<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>BlaCk_Log</title>
    <link>https://black7375.tistory.com/</link>
    <description>호흡이 긴 포스팅을 위주로 하고 있습니다. </description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 06:35:06 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>BlaCk_Void</managingEditor>
    <image>
      <title>BlaCk_Log</title>
      <url>https://tistory1.daumcdn.net/tistory/2773330/attach/abf3b27d80fb4c33a82c5d9f03cbddf4</url>
      <link>https://black7375.tistory.com</link>
    </image>
    <item>
      <title>font-range가 빠르게 서브셋하는 방법</title>
      <link>https://black7375.tistory.com/99</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;본 글은 2023년 12월 30일에 작성되었으며 옮겨진 글입니다.&lt;/i&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;h2 data-ke-size=&quot;size26&quot;&gt;font-range란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 &lt;a href=&quot;https://github.com/black7375/font-range&quot;&gt;fontRange&lt;/a&gt;라는 라이브러리의 저자이며, 폰트 서브셋을 효율적이고 쉽게 할 수 있는 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;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;웹환경에서 서브셋은 &lt;a href=&quot;https://github.com/adobe-type-tools/Adobe-KR#supplement-0adobe-kr-0&quot;&gt;Adobe-KR-0&lt;/a&gt;를 따라 2780자(자모 포함 2831자)를 사용하거나,&lt;br /&gt;&lt;a href=&quot;https://koreantypography.org/wp-content/uploads/2016/02/kst_12_7_2_06.pdf&quot;&gt;노민지, 윤민구 - KS 코드 완성형 한글의 추가 글자 제안&lt;/a&gt;(&lt;a href=&quot;https://github.com/black7375/Readable_Font/blob/cc483dd27d39683b48134d3d13ce1e681b439543/Resource/font/korean2574.txt&quot;&gt;2574자, 리스트&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;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;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range&quot;&gt;&lt;code&gt;unicode-range&lt;/code&gt;&lt;/a&gt;가 바로 그에 대한 대답입니다.&lt;br /&gt;알파벳처럼 문자 셋이 간단할 경우, &lt;a href=&quot;https://fonts.googleapis.com/css2?family=Noto+Sans&amp;amp;display=swap&quot;&gt;Noto Sans&lt;/a&gt;와 같이 키릴문자(&lt;code&gt;cyrillic&lt;/code&gt;), 그리스문자(&lt;code&gt;greek&lt;/code&gt;), 라틴문자(&lt;code&gt;latin&lt;/code&gt;) 등의 범위를 수동으로 지정하면 충분합니다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;/* cyrillic-ext */
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosans/v35/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9X6VLKzA.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosans/v35/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9e6VLKzA.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* devanagari */
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosans/v35/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9b6VLKzA.woff2) format('woff2');
  unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FF;
}
/* greek-ext */
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosans/v35/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9W6VLKzA.woff2) format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosans/v35/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9Z6VLKzA.woff2) format('woff2');
  unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosans/v35/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9V6VLKzA.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosans/v35/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9U6VLKzA.woff2) format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosans/v35/o-0mIpQlx3QUlC5A4PNB6Ryti20_6n1iPHjcz6L1SoM-jCpoiyD9A-9a6VI.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}&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;그러나 CJK(Chinese, Japanese, Korean) 문자의 경우 일본어의 히라가나와 가타카나를 제외하면 명확한 범위를 나누기가 어렵습니다.&lt;br /&gt;우선 한자를 생각해봅시다. 모든 뜻마다 하나의 문자가 존재하죠.&lt;br /&gt;게다가 한중일 한자는 &lt;a href=&quot;https://www.mk.co.kr/news/world/4727410&quot;&gt;모두 조금씩 차이&lt;/a&gt;가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uYOyd/btsLFCfs3lX/k43EaH5ZAYMk4ztSvXVZG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uYOyd/btsLFCfs3lX/k43EaH5ZAYMk4ztSvXVZG0/img.png&quot; data-alt=&quot;한중일 한자 차이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uYOyd/btsLFCfs3lX/k43EaH5ZAYMk4ztSvXVZG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuYOyd%2FbtsLFCfs3lX%2Fk43EaH5ZAYMk4ztSvXVZG0%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;300&quot; height=&quot;420&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;420&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;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;한글의 표현방식은 모든 글자를 각각의 코드에 대응시키는 완성형과 창제 원리대로 초중종성을 합쳐 표현하는 조합형이 있습니다.&lt;br /&gt;유니코드에서는 둘 다 지원하지만, Windows나 Linux는 완성형을 주로 쓰며 MacOS는 조합형을 사용합니다.&lt;br /&gt;MacOS에서 다른 운영체제로 파일을 보내면 &lt;code&gt;ㅍㅏㅇㅣㄹ.txt&lt;/code&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;565&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3BNsU/btsLFRwJMJz/3TAkbTPFus9BoC14KUzzX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3BNsU/btsLFRwJMJz/3TAkbTPFus9BoC14KUzzX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3BNsU/btsLFRwJMJz/3TAkbTPFus9BoC14KUzzX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3BNsU%2FbtsLFRwJMJz%2F3TAkbTPFus9BoC14KUzzX0%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;565&quot; height=&quot;331&quot; data-origin-width=&quot;565&quot; data-origin-height=&quot;331&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://www.morisawa.co.kr/type-center/font-story?article_no=1&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;a href=&quot;https://tapito.tistory.com/529&quot;&gt;조합형/완성형/유니코드의 모든 것&lt;/a&gt;과 &lt;a href=&quot;https://pat.im/1184&quot;&gt;표준이 된 세벌식? - (4) 옛한글을 나타내는 표준 방안이 된 첫가끝 조합형&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;br /&gt;따라서 앞에서 언급한 Adobe-KR-0처럼 자주 쓰이는 글자들(2780자)만 포함하도록 만들어졌던 겁니다.&lt;/p&gt;
&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;&lt;a href=&quot;https://developers.googleblog.com/2018/04/google-fonts-launches-korean-support.html&quot;&gt;한국어&lt;/a&gt;, &lt;a href=&quot;https://developers.googleblog.com/2018/09/google-fonts-launches-japanese-support.html&quot;&gt;일본어&lt;/a&gt;, &lt;a href=&quot;https://web.archive.org/web/20230308014334/https://design.google/news/google-fonts-launches-chinese-support/&quot;&gt;중국어&lt;/a&gt;를 사용 패턴에 따라 서브셋을 자동으로 수행하여 제공합니다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;/* [0] */
@font-face {
  font-family: 'Noto Sans KR';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosanskr/v36/PbyxFmXiEBPT4ITbgNA5Cgms3VYcOA-vvnIzzuoyeLGC5nwuDo-KBTUm6CryotyJROlrnQ.0.woff2) format('woff2');
  unicode-range: U+f9ca-fa0b, U+ff03-ff05, U+ff07, U+ff0a-ff0b, U+ff0d-ff19, U+ff1b, U+ff1d, U+ff20-ff5b, U+ff5d, U+ffe0-ffe3, U+ffe5-ffe6;
}
/* [1] */
@font-face {
  font-family: 'Noto Sans KR';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosanskr/v36/PbyxFmXiEBPT4ITbgNA5Cgms3VYcOA-vvnIzzuoyeLGC5nwuDo-KBTUm6CryotyJROlrnQ.1.woff2) format('woff2');
  unicode-range: U+f92f-f980, U+f982-f9c9;
}
/* [2] */
@font-face {
  font-family: 'Noto Sans KR';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosanskr/v36/PbyxFmXiEBPT4ITbgNA5Cgms3VYcOA-vvnIzzuoyeLGC5nwuDo-KBTUm6CryotyJROlrnQ.2.woff2) format('woff2');
  unicode-range: U+d723-d728, U+d72a-d733, U+d735-d748, U+d74a-d74f, U+d752-d753, U+d755-d757, U+d75a-d75f, U+d762-d764, U+d766-d768, U+d76a-d76b, U+d76d-d76f, U+d771-d787, U+d789-d78b, U+d78d-d78f, U+d791-d797, U+d79a, U+d79c, U+d79e-d7a3, U+f900-f909, U+f90b-f92e;
}
/* ... */
/* [117] */
@font-face {
  font-family: 'Noto Sans KR';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosanskr/v36/PbyxFmXiEBPT4ITbgNA5Cgms3VYcOA-vvnIzzuoyeLGC5nwuDo-KBTUm6CryotyJROlrnQ.117.woff2) format('woff2');
  unicode-range: U+d, U+48, U+7c, U+ac10, U+ac15, U+ac74, U+ac80, U+ac83, U+acc4, U+ad11, U+ad50, U+ad6d, U+adfc, U+ae00, U+ae08, U+ae4c, U+b0a8, U+b124, U+b144, U+b178, U+b274, U+b2a5, U+b2e8, U+b2f9, U+b354, U+b370, U+b418, U+b41c, U+b4f1, U+b514, U+b798, U+b808, U+b824-b825, U+b8cc, U+b978, U+b9d0, U+b9e4, U+baa9, U+bb3c, U+bc18, U+bc1c, U+bc30, U+bc84, U+bcf5, U+bcf8, U+bd84, U+be0c, U+be14, U+c0b0, U+c0c9, U+c0dd, U+c124, U+c2dd, U+c2e4, U+c2ec, U+c54c, U+c57c-c57d, U+c591, U+c5c5-c5c6, U+c5ed, U+c608, U+c640, U+c6b8, U+c6d4, U+c784, U+c7ac, U+c800-c801, U+c9c1, U+c9d1, U+cc28, U+cc98, U+cc9c, U+ccad, U+cd5c, U+cd94, U+cd9c, U+cde8, U+ce68, U+cf54, U+d0dc, U+d14c, U+d1a0, U+d1b5, U+d2f0, U+d30c, U+d310, U+d398, U+d45c, U+d50c, U+d53c, U+d560, U+d568, U+d589, U+d604, U+d6c4, U+d788;
}
/* [118] */
@font-face {
  font-family: 'Noto Sans KR';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosanskr/v36/PbyxFmXiEBPT4ITbgNA5Cgms3VYcOA-vvnIzzuoyeLGC5nwuDo-KBTUm6CryotyJROlrnQ.118.woff2) format('woff2');
  unicode-range: U+39, U+49, U+4d-4e, U+a0, U+ac04, U+ac1c, U+ac70, U+ac8c, U+acbd, U+acf5, U+acfc, U+ad00, U+ad6c, U+adf8, U+b098, U+b0b4, U+b294, U+b2c8, U+b300, U+b3c4, U+b3d9, U+b4dc, U+b4e4, U+b77c, U+b7ec, U+b85d, U+b97c, U+b9c8, U+b9cc, U+ba54, U+ba74, U+ba85, U+baa8, U+bb34, U+bb38, U+bbf8, U+bc14, U+bc29, U+bc88, U+bcf4, U+bd80, U+be44, U+c0c1, U+c11c, U+c120, U+c131, U+c138, U+c18c, U+c218, U+c2b5, U+c2e0, U+c544, U+c548, U+c5b4, U+c5d0, U+c5ec, U+c5f0, U+c601, U+c624, U+c694, U+c6a9, U+c6b0, U+c6b4, U+c6d0, U+c704, U+c720, U+c73c, U+c740, U+c744, U+c74c, U+c758, U+c77c, U+c785, U+c788, U+c790-c791, U+c7a5, U+c804, U+c815, U+c81c, U+c870, U+c8fc, U+c911, U+c9c4, U+ccb4, U+ce58, U+ce74, U+d06c, U+d0c0, U+d130, U+d2b8, U+d3ec, U+d504, U+d55c, U+d569, U+d574, U+d638, U+d654, U+d68c;
}
/* [119] */
@font-face {
  font-family: 'Noto Sans KR';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/notosanskr/v36/PbyxFmXiEBPT4ITbgNA5Cgms3VYcOA-vvnIzzuoyeLGC5nwuDo-KBTUm6CryotyJROlrnQ.119.woff2) format('woff2');
  unicode-range: U+20-22, U+27-2a, U+2c-38, U+3a-3b, U+3f, U+41-47, U+4a-4c, U+4f-5d, U+61-7b, U+7d, U+a1, U+ab, U+ae, U+b7, U+bb, U+bf, U+2013-2014, U+201c-201d, U+2122, U+ac00, U+ace0, U+ae30, U+b2e4, U+b85c, U+b9ac, U+c0ac, U+c2a4, U+c2dc, U+c774, U+c778, U+c9c0, U+d558;
}&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;br /&gt;따라서 CSS의 &lt;code&gt;unicode-range&lt;/code&gt; 부분만을 파싱하여 서브셋해주는 라이브러리를 만들었죠.&lt;br /&gt;&lt;code&gt;font-range&lt;/code&gt;의 탄생배경입니다.&lt;/p&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 파일 경로나 URL을 입력하면 알아서 다운로드 받아 &lt;code&gt;unicode-range&lt;/code&gt;에 따라 서브셋 해줍니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;fontRange(font_path, css_url_or_path);
fontRange(font_path, css_url_or_path, save_dir);       // Option1
fontRange(font_path, css_url_or_path, { ...options }); // Option2&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;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;fontSubset(font_path);
fontSubset(font_path, save_dir);       // Option1
fontSubset(font_path, { ...options }); // Option2&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;한번에 효율적인 서브셋&lt;/b&gt;을 할 필요가 생겨서 만들어진 API가 있으니 &lt;code&gt;fontPipe&lt;/code&gt;입니다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;fontPipe([
  { font_path },                                      // As `fontSubset(font_path)`
  { font_path, option: { text: &quot;abc&quot; } },             // As `fontSubset(font_path, { text: &quot;abc&quot; })`
  { font_path, option: { textFile: file_path } },     // As `fontSubset(font_path, { textFile: file_path })`
  { font_path, option: { cssFile: css_url_or_path } } // As `fontRange(font_path, css_url_or_path)`
]);
fontPipe([{ font_path1 }, { font_path2 }], &quot;&amp;lt;index&amp;gt;/&amp;lt;total&amp;gt;&quot;); // Sharding option use like `1/2`&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;효율적인 서브셋하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;font-range의 &lt;code&gt;fontPipe()&lt;/code&gt;는 얼마나 효율적일까요?&lt;/p&gt;
&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/orioncactus/pretendard/pull/115&quot;&gt;프리텐다드의 고성능 서브셋 시스템&lt;/a&gt;을 보면 그 위력을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmqUzo/btsLHrXSbMM/jJMp21f6B01axEXg0LkxIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmqUzo/btsLHrXSbMM/jJMp21f6B01axEXg0LkxIK/img.png&quot; data-alt=&quot;기존 서브셋&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmqUzo/btsLHrXSbMM/jJMp21f6B01axEXg0LkxIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmqUzo%2FbtsLHrXSbMM%2FjJMp21f6B01axEXg0LkxIK%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;960&quot; height=&quot;463&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;463&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;960&quot; data-origin-height=&quot;850&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7XuxX/btsLGX34h9i/kOIA9hkQ4gbwXK6LjHk270/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7XuxX/btsLGX34h9i/kOIA9hkQ4gbwXK6LjHk270/img.png&quot; data-alt=&quot;고성능 서브셋&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7XuxX/btsLGX34h9i/kOIA9hkQ4gbwXK6LjHk270/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7XuxX%2FbtsLGX34h9i%2FkOIA9hkQ4gbwXK6LjHk270%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;960&quot; height=&quot;850&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;850&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;한시간 동안 걸리던 작업이 겨우 5분으로 줄어들었습니다!!!&lt;br /&gt;수치상 &lt;code&gt;11.14&lt;/code&gt;배가 빨라진거죠.&lt;/p&gt;
&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;h3 data-ke-size=&quot;size23&quot;&gt;쉘 생성 제거&lt;/h3&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;파이썬의 폰트툴즈(fonttools) 패키지를 설치하면 제공되는 &lt;a href=&quot;https://fonttools.readthedocs.io/en/latest/subset/&quot;&gt;&lt;code&gt;pyftsubset&lt;/code&gt;&lt;/a&gt;입니다.&lt;br /&gt;&lt;a href=&quot;https://www.44bits.io/ko/post/optimization_webfont_with_pyftsubnet&quot;&gt;보통 이렇게 Shell 명령어로 사용&lt;/a&gt;합니다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;pyftsubset &quot;NotoSansCJKkr-Regular.otf&quot; \
  --flavor=&quot;woff2&quot; \
  --output-file=&quot;./subset-fonts/NotoSansR.subset.5.woff2&quot; \
  --text-file=&quot;glyphs.txt&quot; \
  --layout-features='*' \
  --glyph-names \
  --symbol-cmap \
  --legacy-cmap \
  --notdef-glyph \
  --notdef-outline \
  --recommended-glyphs \
  --name-legacy \
  --drop-tables= \
  --name-IDs='*' \
  --name-languages='*'&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;Node.JS에는 명령어를 실행하기 위한 방법으로 &lt;a href=&quot;https://www.freecodecamp.org/korean/news/node-js-child-processes-everything-you-need-to-know-e69498fe970a/&quot;&gt;&lt;code&gt;exec&lt;/code&gt;나 &lt;code&gt;spawn&lt;/code&gt;&lt;/a&gt;이 있습니다.&lt;br /&gt;&lt;code&gt;exec&lt;/code&gt;는 bash와 같은 쉘을 이용해 실행하므로 자동적으로 이스케이프 처리가 되어, &lt;code&gt;spawn&lt;/code&gt; 보다 편리합니다.&lt;br /&gt;복잡한 옵션 명령어들을 다루어야 했던 제게 &lt;code&gt;exec&lt;/code&gt;가 가진 이점이 컸습니다.&lt;/p&gt;
&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://www.npmjs.com/package/pretendard-jp&quot;&gt;&lt;code&gt;pretendard-jp&lt;/code&gt;&lt;/a&gt;와 &lt;a href=&quot;https://www.npmjs.com/package/pretendard-std&quot;&gt;&lt;code&gt;pretendard-std&lt;/code&gt;&lt;/a&gt;처럼 새로운 폰트들이 추가되고 &lt;a href=&quot;https://github.com/orioncactus/pretendard/pull/91&quot;&gt;가변폰트의 다이나믹 서브셋&lt;/a&gt;까지 지원하면서 엄청난 양의 서브셋이 만들어지게 됩니다.&lt;br /&gt;용량이 너무 커서 NPM에 올라가지 못해 반쯤 강제로 패키지를 나누어 관리하는 &lt;a href=&quot;https://github.com/orioncactus/pretendard/pull/82&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;폰트 패밀리: &lt;code&gt;pretendard&lt;/code&gt;, &lt;code&gt;pretenard-std&lt;/code&gt;, &lt;code&gt;pretendard-jp&lt;/code&gt;와 최근 추가된 &lt;code&gt;pretendard-gov&lt;/code&gt;처럼 다양한 폰트 바리에이션들&lt;/li&gt;
&lt;li&gt;굵기: 프리텐다드는 9개의 weight를 지원합니다. 모든 굵기가 합쳐져 옵션으로 조정하는 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_fonts/Variable_fonts_guide&quot;&gt;가변폰트&lt;/a&gt;도 있습니다.&lt;/li&gt;
&lt;li&gt;포맷: woff와 woff2 형식으로 나뉩니다.&lt;/li&gt;
&lt;li&gt;서브셋 범위: 전체, &lt;code&gt;Adobe-KR-0&lt;/code&gt;, &lt;code&gt;unicode-range&lt;/code&gt;를 이용한 다이나믹 서브셋&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 다이나믹 서브셋은 각 폰트파일당 90개가 넘게 나뉘어집니다.&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;때문에 Pretendard 스케일에서는 쉘 생성 제거는 효용을 가지게 될만하다 판단해 쉘 생성을 제거해보기로 결정했습니다.&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;그래서 &lt;a href=&quot;https://github.com/sindresorhus/execa#shell-syntax&quot;&gt;execa&lt;/a&gt;라는 라이브러리를 &lt;a href=&quot;https://github.com/black7375/font-range/commit/ca95b54dea9f283f922cd17e19855010ce411462#diff-1245a5bbc4ca0684dff978efcae118b08f62d2afc05812df22d0627985b4273a&quot;&gt;사용&lt;/a&gt;하였습니다.&lt;br /&gt;execa 자체는 esm 모듈을 사용하고 있어 &lt;a href=&quot;https://github.com/esm2cjs/execa&quot;&gt;&lt;code&gt;esm2cjs/execa&lt;/code&gt;&lt;/a&gt;로 설치했고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 벤치마크 결과는 없지만 당시 기억으로 8%정도의 개선이 있었습니다.&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;/h3&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;작업의 속성을 크게 2가지로 나누자면 &lt;a href=&quot;https://elsoc.fandom.com/wiki/Scheduling&quot;&gt;CPU와 I/O&lt;/a&gt; 작업이 있습니다.&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;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p7tzW/btsLFJyTRdY/GOdTDKAIEqKXziKGG8Kmo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p7tzW/btsLFJyTRdY/GOdTDKAIEqKXziKGG8Kmo1/img.png&quot; data-alt=&quot;CPU bound vs I/O bound&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p7tzW/btsLFJyTRdY/GOdTDKAIEqKXziKGG8Kmo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp7tzW%2FbtsLFJyTRdY%2FGOdTDKAIEqKXziKGG8Kmo1%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;235&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CPU bound vs I/O bound&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;만약 CPU 중심 작업이라면 병렬성(parallel), I/O 중심 작업이라면 동시성(concurrent)에 신경을 써야하겠지요.&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;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bS8sB0/btsLFDZNZIq/OvBYb2vqpzO9UZIJH120M1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bS8sB0/btsLFDZNZIq/OvBYb2vqpzO9UZIJH120M1/img.png&quot; data-alt=&quot;동시성 vs 병렬성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bS8sB0/btsLFDZNZIq/OvBYb2vqpzO9UZIJH120M1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbS8sB0%2FbtsLFDZNZIq%2FOvBYb2vqpzO9UZIJH120M1%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;700&quot; height=&quot;250&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;동시성 vs 병렬성&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;br /&gt;파일을 읽고 쓰기는 분명 I/O겠지만, 명령이 실행되는 동안 오랫동안 기다려야 하는 &lt;b&gt;변환작업&lt;/b&gt;은 CPU를 계속 점유해야 가능합니다.&lt;br /&gt;CPU Bound 작업이라는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 자바스크립트는 싱글 스레드 언어이며, Node.JS도 마찬가지의 한계를 가지고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I9vlG/btsLFKEyb0M/t8MGsUuFpqSH2DsOwAHd5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I9vlG/btsLFKEyb0M/t8MGsUuFpqSH2DsOwAHd5K/img.png&quot; data-alt=&quot;싱글쓰레드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I9vlG/btsLFKEyb0M/t8MGsUuFpqSH2DsOwAHd5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI9vlG%2FbtsLFKEyb0M%2Ft8MGsUuFpqSH2DsOwAHd5K%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;982&quot; height=&quot;384&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;384&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;JS의 await는 I/O에는 뛰어나지만, CPU Bound일때는 다른작업들이 차단(block)되어 실행되지 않습니다.&lt;br /&gt;다행히도 &lt;a href=&quot;https://github.com/black7375/font-range/blob/9f2527d360c0aeda036faf0849f9ccdb5dde4876/src/main.ts#L222-L230&quot;&gt;당시 코드&lt;/a&gt;를 &lt;a href=&quot;https://github.com/orioncactus/pretendard/blob/535bbdfd667892831b7785cd307df449c28c9c2f/packages/subset-utils/src/dynamic-subset.ts&quot;&gt;사용&lt;/a&gt;해보면 여러 Promise가 반환되어 &lt;code&gt;Promise.all()&lt;/code&gt;로 처리할 수 있었습니다.&lt;br /&gt;완전히 멈춰있는 최악의 상황은 아니었지요.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;  return ranges.then(eachRanges =&amp;gt; eachRanges.map((unicodes, i) =&amp;gt; {
    const saveOption = &quot;--output-file='&quot; +
      join(dirPath, getName(nameFormat, fontName, i, fontExt)) + &quot;' &quot;;
    const unicodeRanges = unicodes.split(', ').join(',');
    const unicodeOption = &quot;--unicodes='&quot; + unicodeRanges + &quot;' &quot;;

    const options = &quot; '&quot; + fontPath + &quot;' &quot; + saveOption + unicodeOption
      + convertOption + defaultOption + etcOption;
    return execSync(&quot;pyftsubset&quot; + options);
  }));&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;br /&gt;OS는 모든 프로세스를 공평하게 실행시켜줘야 하기 때문에 작업을 전환시킵니다.&lt;/p&gt;
&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsgcbz/btsLGgW5qVh/7l5BmYQ5dljHWwltcJZPG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsgcbz/btsLGgW5qVh/7l5BmYQ5dljHWwltcJZPG0/img.png&quot; data-alt=&quot;컨텍스트 스위칭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsgcbz/btsLGgW5qVh/7l5BmYQ5dljHWwltcJZPG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdsgcbz%2FbtsLGgW5qVh%2F7l5BmYQ5dljHWwltcJZPG0%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&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;br /&gt;해결할 수 있는 방법 중 하나는 CPU 코어 갯수대로만 쓰레드를 만들고 큐 형태로 관리하여 일을 배분해주는 겁니다.&lt;br /&gt;점유가 끝나야 다음 작업을 시작하므로 컨텍스트 스위칭이 최소화됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JNmmI/btsLFyqOvCD/dFvsH9GZW9J4jbT0ANzGaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JNmmI/btsLFyqOvCD/dFvsH9GZW9J4jbT0ANzGaK/img.png&quot; data-alt=&quot;쓰레드 풀&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JNmmI/btsLFyqOvCD/dFvsH9GZW9J4jbT0ANzGaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJNmmI%2FbtsLFyqOvCD%2FdFvsH9GZW9J4jbT0ANzGaK%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;750&quot; height=&quot;416&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;416&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;a href=&quot;https://github.com/piscinajs/piscina&quot;&gt;Piscina&lt;/a&gt;라는 &lt;a href=&quot;https://github.com/black7375/font-range/commit/c7e54d3c997a660b53b5e50522e04e2b32075da8&quot;&gt;워커 풀을 사용&lt;/a&gt;하였습니다.&lt;br /&gt;자바스크립트 세계에서 CPU 바운드 작업은 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Worker&quot;&gt;Worker&lt;/a&gt;를 사용하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1658&quot; data-origin-height=&quot;888&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/epv81L/btsLFEqPhFX/HaL6VgxG9HU1U6iqDVDZTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/epv81L/btsLFEqPhFX/HaL6VgxG9HU1U6iqDVDZTK/img.png&quot; data-alt=&quot;Worker&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/epv81L/btsLFEqPhFX/HaL6VgxG9HU1U6iqDVDZTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fepv81L%2FbtsLFEqPhFX%2FHaL6VgxG9HU1U6iqDVDZTK%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;1658&quot; height=&quot;888&quot; data-origin-width=&quot;1658&quot; data-origin-height=&quot;888&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Worker&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;br /&gt;첫번째로 워커는 일반적으로 다른 script 파일이어야 하므로 &lt;a href=&quot;https://github.com/black7375/font-range/blob/master/src/worker.ts&quot;&gt;&lt;code&gt;worker.ts&lt;/code&gt;&lt;/a&gt;에서 명령이 실행되어야 하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째, 명령 실행을 동기적으로 해야합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;export default function subset({options, log = &quot;&quot;}: SubsetI) {
  if(log !== &quot;&quot;) {
    console.log(log);
  }
  return execaSync(&quot;pyftsubset&quot;, options);
}&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;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;만약 비동기로 실행하게 되면 async를 만나는 순간 프로미스로 반환해버리고, 작업이 끝난 취급을 받아 다음 작업으로 넘어가게 되어 워커풀을 도입하기 전과 동일하게 수많은 프로세스가 생기게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w6wy9/btsLHtg4MdZ/zucSIoTGGHcENhACsuvi01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w6wy9/btsLHtg4MdZ/zucSIoTGGHcENhACsuvi01/img.png&quot; data-alt=&quot;await 실행&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w6wy9/btsLHtg4MdZ/zucSIoTGGHcENhACsuvi01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw6wy9%2FbtsLHtg4MdZ%2FzucSIoTGGHcENhACsuvi01%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;await 실행&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;a href=&quot;https://refactoring.guru/ko/design-patterns/singleton&quot;&gt;싱글턴 패턴&lt;/a&gt;을 &lt;a href=&quot;https://github.com/black7375/font-range/blob/9a8c00aff17871e55386be44cd4a3c0adbb97708/src/main.ts#L13-L28&quot;&gt;사용&lt;/a&gt;하여 워커풀이 처음 한번만 초기화되도록 보장했습니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;type WorkerRT = ReturnType&amp;lt;typeof WorkerFn&amp;gt;;

class Worker {
  private static instance: Piscina;
  private constructor() { }

  public static getInstance(): Piscina {
    if(!Worker.instance) {
      Worker.instance = new Piscina({
        filename: join(__dirname, &quot;../&quot;, &quot;build&quot;, &quot;worker.js&quot;)
      });
    }
    return Worker.instance;
  }
}&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;워커 풀은 약 20%의 성능 개선을 가져왔던 걸로 기억합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;샤딩&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/what-is/database-sharding/&quot;&gt;샤딩(Sharding)&lt;/a&gt;은 주로 DB쪽에서 사용되는 용어로 분산하여 저장하는 프로세스입니다.&lt;/p&gt;
&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/black7375/font-range/commit/212ac0f3816dd6169b49b7ba5703a0b45d15e20e&quot;&gt;구현은 정말 간단&lt;/a&gt;합니다.&lt;br /&gt;예를 들어 10개의 작업이 있을 때 &lt;code&gt;2/5&lt;/code&gt;와 같은 옵션을 주면 &lt;code&gt;2/5&lt;/code&gt;의 양만큼만 처리하므로 &lt;code&gt;3&lt;/code&gt;과 &lt;code&gt;4&lt;/code&gt;만 실행되는 방식입니다.&lt;/p&gt;
&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;첫번째, &quot;1/5&quot;~&quot;5/5&quot;까지 처리한 작업물들을 모아서 합쳐야 합니다.&lt;br /&gt;저는 &lt;a href=&quot;https://github.com/orioncactus/pretendard/commit/7651b75b5b9b81e151cee17bbafea43b7b23ac68&quot;&gt;커밋을 만들어 push하고 rebase&lt;/a&gt;하는 형식으로 처리했습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;runs:
  using: &quot;composite&quot;
  steps:
    - name: Commit Build File
      shell: bash
      run: |
        git config user.name &quot;$(git log -n 1 --pretty=format:%an)&quot;
        git config user.email &quot;$(git log -n 1 --pretty=format:%ae)&quot;
        if [[ &quot;$(git branch -r --contains ${{ inputs.branch }} 2&amp;gt;/dev/null)&quot; ]]; then
          git checkout ${{ inputs.branch }}
        else
          git checkout -b ${{ inputs.branch }}
        fi
        git add --ignore-removal ${{ inputs.file_pattern }}
        if [[ &quot;$(git diff --staged)&quot; != &quot;&quot; ]]; then
          git commit -m &quot;${{ inputs.message }}&quot;
          if [[ &quot;$(git branch -r --contains ${{ inputs.branch }} 2&amp;gt;/dev/null)&quot; ]]; then
            git push origin ${{ inputs.branch }}
          else
            git push -u origin ${{ inputs.branch }}
          fi
        fi&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;br /&gt;깃허브의 경우 &lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration#usage-limits&quot;&gt;동시에 실행가능&lt;/a&gt;한 작업은 20개이며, MacOS는 5개입니다.&lt;br /&gt;Linux는 2코어이지만 MacOS는 현재 &lt;a href=&quot;https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources&quot;&gt;3코어, 4코어&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;당시에는 3코어짜리 MacOS만 존재했는데, 3코어 MacOS 5개 대신 2코어 Linux 8개를 사용하는 성능 특성이 좋아 모두 리눅스 머신을 기준으로 해서 처리하였습니다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;  pretendard-jp:
    runs-on: ubuntu-latest
    if: contains(github.event.head_commit.message, 'release:')
    strategy:
      matrix:
        shard: [&quot;1/8&quot;, &quot;2/8&quot;, &quot;3/8&quot;, &quot;4/8&quot;, &quot;5/8&quot;, &quot;6/8&quot;, &quot;7/8&quot;, &quot;8/8&quot;]
        include:
          - shard: &quot;1/8&quot;
            branch: &quot;jp-1&quot;
          - shard: &quot;2/8&quot;
            branch: &quot;jp-2&quot;
          - shard: &quot;3/8&quot;
            branch: &quot;jp-3&quot;
          - shard: &quot;4/8&quot;
            branch: &quot;jp-4&quot;
          - shard: &quot;5/8&quot;
            branch: &quot;jp-5&quot;
          - shard: &quot;6/8&quot;
            branch: &quot;jp-6&quot;
          - shard: &quot;7/8&quot;
            branch: &quot;jp-7&quot;
          - shard: &quot;8/8&quot;
            branch: &quot;jp-8&quot;
    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: '0'
    - uses: ./.github/actions/setup-pip
    - uses: ./.github/actions/setup-yarn
    - uses: ./.github/actions/subset-push
      with:
        workspace: pretendard-jp
        shard: ${{ matrix.shard }}
        branch: ${{ matrix.branch }}&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;br /&gt;모든 문자를 woff2로 변환해야하는 &lt;code&gt;static&lt;/code&gt; 작업은 문자 집합의 일부분만 변환하면 되는 다이나믹 서브셋의 각 작업보다 느립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;font-range 내부에서는 &lt;code&gt;dynamic&lt;/code&gt;의 &lt;code&gt;unicode-range&lt;/code&gt;들을 각각 작업으로 처리하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 전 오래걸리는 &lt;code&gt;static&lt;/code&gt; 작업끼리 모아놓기보다는 순서를 적당히 섞는 간단한 휴리스틱으로 Normalizing을 했습니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;// 전
subsets(
  // Pretendard
  [&quot;static&quot;,    &quot;woff&quot;,  fontList],
  [&quot;static&quot;,    &quot;woff2&quot;, fontList],
  [&quot;glyph&quot;,     &quot;woff&quot;,  fontList],
  [&quot;glyph&quot;,     &quot;woff2&quot;, fontList],
  [&quot;dynamic&quot;,   &quot;woff&quot;,  fontList],
  [&quot;dynamic&quot;,   &quot;woff2&quot;, fontList],
  // Pretendard Variable
  [&quot;static&quot;,    &quot;woff2&quot;, variable],
  [&quot;dynamic&quot;,   &quot;woff2&quot;, variable]
);

// 후
subsets(
  // Pretendard woff
  [&quot;static&quot;,    &quot;woff&quot;,  fontList],
  [&quot;glyph&quot;,     &quot;woff&quot;,  fontList],
  [&quot;dynamic&quot;,   &quot;woff&quot;,  fontList],

  // Pretendard woff2
  [&quot;static&quot;,    &quot;woff2&quot;, fontList],
  [&quot;glyph&quot;,     &quot;woff2&quot;, fontList],
  [&quot;dynamic&quot;,   &quot;woff2&quot;, fontList],

  // Pretendard Variable
  [&quot;static&quot;,    &quot;woff2&quot;, variable],
  [&quot;dynamic&quot;,   &quot;woff2&quot;, variable]
);&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;a href=&quot;https://www.freecodecamp.org/news/how-to-shuffle-an-array-of-items-using-javascript-or-typescript/&quot;&gt;Shuffle하는 방식&lt;/a&gt;도 생각해보았지만, 결정적이어야하는 Sharding 시스템 특성상 어울리지 않았습니다.&lt;br /&gt;그래서 &lt;a href=&quot;https://frhyme.github.io/python-libs/np_random_get_set_state/&quot;&gt;seed 값&lt;/a&gt;을 사용하는 방안(&lt;a href=&quot;https://github.com/davidbau/seedrandom&quot;&gt;seedrandom&lt;/a&gt;, &lt;a href=&quot;https://github.com/yixizhang/seed-shuffle&quot;&gt;seed-shuffle&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;좋습니다. 그래서 성능은 어떨까요?&lt;br /&gt;10배가 넘는 성능을 만든 1등공신입니다!!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;끝&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 훌륭한 일을 하지만, 놀랍게도 font-range의 소스코드는 &lt;a href=&quot;https://github.com/black7375/font-range/blob/master/src/main.ts&quot;&gt;500라인에 불과&lt;/a&gt;합니다.&lt;br /&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;&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;20만건이 넘는 데이터를 PDF로 변환하기&lt;/b&gt;: 제가 참여하기 전보다 &lt;b&gt;200% 이상&lt;/b&gt;의 성능개선!!&lt;br /&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;a style=&quot;color: #0070d1;&quot; href=&quot;https://pptr.dev/&quot;&gt;Puppeteer&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;또는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.selenium.dev/&quot;&gt;Selenium&lt;/a&gt; 대신 성능/안정화를 위해 패치한 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #0070d1; text-align: start;&quot; href=&quot;https://github.com/jsdom/jsdom&quot;&gt;JSDOM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;역시 성능/안정화를 위해 프로미스 풀&lt;/li&gt;
&lt;li&gt;파일 건너뛰기와 로컬 이미지 사용&lt;/li&gt;
&lt;li&gt;Stream I/O&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일부 엑셀 파일을 PDF로 변환하기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;헤드리스 모드의 LibreOffice에서 출력용 VBA를 적용 후, PDF 생성&lt;/li&gt;
&lt;li&gt;CUPS와 같은 패키지가 추가로 필요할 수도 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;웹사이트에서 PDF 뷰어 제공하기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mozilla/pdf.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PDF.JS&lt;/a&gt;는 생각보다 커스텀하기 까다롭게 되어 있다&lt;/li&gt;
&lt;li&gt;서버의 &lt;a href=&quot;https://github.com/mozilla/pdf.js/issues/3150#issuecomment-17582371&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;헤더를 요구&lt;/a&gt;하거나 .mjs등의 확장자 때문에 추가적인 리소스 허용등의 설정이 필요할 수도.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&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;이 정도가 NDA에서 어긋나지 않는 선에서 공개할 수 있는 내용인듯.&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/99</guid>
      <comments>https://black7375.tistory.com/99#entry99comment</comments>
      <pubDate>Tue, 31 Dec 2024 21:15:34 +0900</pubDate>
    </item>
    <item>
      <title>리스프에서 멋진 3가지.</title>
      <link>https://black7375.tistory.com/98</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 쓰게 된 계기는 Racket 공식 계정의 &lt;a href=&quot;https://x.com/alstjr7375/status/1837054672630333454&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;a href=&quot;https://plwiki.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;plwiki&lt;/a&gt;에 조금 기여해볼까 생각 중.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1125&quot; data-origin-height=&quot;1474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJHmbc/btsKeK64Ug0/oNYrFexmCiuKr9MaKVKK41/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJHmbc/btsKeK64Ug0/oNYrFexmCiuKr9MaKVKK41/img.jpg&quot; data-alt=&quot;여러분은 방금 Racket 언어 사용법의 90%를 익혔습니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJHmbc/btsKeK64Ug0/oNYrFexmCiuKr9MaKVKK41/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJHmbc%2FbtsKeK64Ug0%2FoNYrFexmCiuKr9MaKVKK41%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;1125&quot; height=&quot;1474&quot; data-origin-width=&quot;1125&quot; data-origin-height=&quot;1474&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;여러분은 방금 Racket 언어 사용법의 90%를 익혔습니다.&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;/p&gt;
&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://wiki.c2.com/?DataAndCodeAreTheSameThing=&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Code as data, data as code&lt;/a&gt; 혹은 &lt;a href=&quot;https://en.wikipedia.org/wiki/Homoiconicity&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Homoiconicity&lt;/a&gt;처럼 식상한 것을 제외하고, 알아보도록 합시다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Racket - 매크로: 본디 리스프에서 매크로는 유명하다. 그 중에서도 Racket의 매크로는 조금 특별하다.&lt;/li&gt;
&lt;li&gt;Racket - parameterize: Thread와 함께 사용할 수 있는 동적 바인딩.&lt;/li&gt;
&lt;li&gt;Common Lisp - CLOS: 매우 동적이고 유연한 객체지향 시스템.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 보게되면 제가 가끔씩 Racket 기습찬양하는 이유를 알게될지도 모르겠네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Racket - 가장 강력하고 안전한 매크로&lt;/h2&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;h3 data-ke-size=&quot;size23&quot;&gt;1.1 안전한 매크로&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1.1 C vs Racket: 매크로가 구문이어야 하는 이유&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 안전한 매크로란 무엇인가에 대해 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C와 Racket의 매크로를 간단히 만들어 비교해보면 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729601150720&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

#define MAX(a, b) (a &amp;gt; b ? a : b)
#define DEBUG_PRINT(x) printf(&quot;%s = %d&quot;, #x, x)

// 사용 예
int main() {
    int x = 5, y = 10;
    int max = MAX(x, y);
    DEBUG_PRINT(max);
    return 0;
}&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;Racket의 방식이 전위식이라서 익숙하지 않은 것을 제외하고는 어렵지 않을 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1729601169461&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#lang racket

(define-syntax-rule (max-of a b)
  (if (&amp;gt; a b) a b))

(define-syntax-rule (debug-print x)
  (printf &quot;~a = ~a&quot; 'x x))

;; 사용 예
(let ([x 5] [y 10])
  (let ([max (max-of x y)])
    (debug-print max)))&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;code&gt;max = 10&lt;/code&gt;이라는 출력.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;max라는 심볼과 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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 C의 매크로와 Racket의 매크로에는 근본적인 차이가 있습니다.&lt;/p&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 매크로는 단순한 텍스트 치환에 가까운 반면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Racket의 매크로는 함수를 정의할 때처럼 구문처럼 취급합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 확인하기 위해 변수의 값을 바꿔주는 swap 매크로를 구현해보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1729604074500&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#define SWAP(a, b) \
    typeof(a) temp = a; \
    a = b; \
    b = temp;

// 사용 예
int main() {
    int x = 1, y = 2;
    SWAP(x, y);

    DEBUG_PRINT(x);
    DEBUG_PRINT(y);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1729604104583&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax-rule (swap a b)
  (let ([temp a])
    (set! a b)
    (set! b temp)))

(let ([x 1] [y 2])
  (swap x y)
  (debug-print x)
  (debug-print 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;실행해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;x = 2&lt;/code&gt;이고, &lt;code&gt;y = 1&lt;/code&gt;로 잘 변환됨을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 &lt;code&gt;temp = 3&lt;/code&gt;이라고 추가적인 변수를 미리 선언해놓고 실행해보면 어떨까요?&lt;/p&gt;
&lt;pre id=&quot;code_1729605455963&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main() {
    int x = 1, y = 2, temp = 3;
    SWAP(x, y);

    DEBUG_PRINT(x);
    DEBUG_PRINT(y);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1729605474591&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(let ([x 1] [y 2] [temp 3])
  (swap x y)
  (debug-print x)
  (debug-print 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;Racket과 달리 C에서는 temp가 이미 선언되었다며 에러가 났음을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C는 매크로를 확장할 때 문자열의 치환이므로, 변수 캡쳐나 문법등을 고려하여 조심히 구현해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729605696438&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#define swap(a, b) do { \
    typeof(a) temp = a; \
    a = b; \
    b = temp; \
} while(0)&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;code&gt;do ~ while(0)&lt;/code&gt;을 넣었느냐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 블록을 넣게 되면 다음과 같은 경우에 &lt;code&gt;if (x &amp;gt; y) { swap 내용 }; else 내용&lt;/code&gt;으로 해석되게 되므로,&lt;code&gt; main.c:24:5: error: &amp;lsquo;else&amp;rsquo; without a previous &amp;lsquo;if&amp;rsquo;&lt;/code&gt;와 같은 에러가 나오게 되기 때문입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729607159654&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#define SWAP(a, b) { \
    typeof(a) temp = a; \
    a = b; \
    b = temp; \
}

int main() {
    int x = 1, y = 2, temp = 3;

    if (x &amp;gt; y)
        SWAP(x, y);
    else
       printf(&quot;not SWAP!!\n&quot;);

    DEBUG_PRINT(x);
    DEBUG_PRINT(y);
    return 0;
}&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;C 매크로의 이상한 예를 하나 더 들어봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 10을 곱하는 매크로 정의입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 문자열 치환과 연산자 우선순위에 의해서 각각의 결과가 모두 다릅니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729608620608&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

#define MULTIPLY1(x) x * 10
#define MULTIPLY2(x) (x * 10)
#define MULTIPLY3(x) ((x) * 10)

// 사용 예
int main() {
    printf(&quot;1: %d\n&quot;, MULTIPLY1(1 + 2) * 3); // 1 + 2 * 10 * 3 = 61
    printf(&quot;2: %d\n&quot;, MULTIPLY2(1 + 2) * 3); // (1 + 2 * 10) * 3 = 63
    printf(&quot;3: %d\n&quot;, MULTIPLY3(1 + 2) * 3); // ((1 + 2) * 10) * 3 = 90
    return 0;
}&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;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;이외에도 많은 예상치 못한 에러들이 쏟아질 수도 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 Rakcet의 매크로는 구문이며, 위생적 매크로이기 때문에 문법에러나 변수캡쳐등을 고려할 필요가 없이 안전하게 매크로를 작성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;음.. 그렇다면 다른 Lisp의 매크로와는 어떻게 비교될까요?&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;1.1.2 Common Lisp vs Racket: 위생적 매크로여야 하는 이유&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Common Lisp의 매크로는 구문이지만 '&lt;a href=&quot;https://en.wikipedia.org/wiki/Hygienic_macro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;위생적(Hygienic)&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;바로 예를 들어보죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 Common Lisp 매크로의 결과는 &lt;code&gt;6&lt;/code&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의도치 않게 사용 예의 &lt;code&gt;temp&lt;/code&gt;가 캡쳐되어 &lt;code&gt;(+ temp 1)&lt;/code&gt;의 값으로 &lt;code&gt;setf&lt;/code&gt; 된겁니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729615816661&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(defmacro without-gensym (num &amp;amp;body body)
  `(let ((temp ,num))
     (setf temp (+ temp 1))
     ,@body))

;; 사용 예
(let ((temp 5))
  (without-gensym temp
    (print temp))) ;; 결과: 6&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;&lt;a href=&quot;https://www.lispworks.com/documentation/HyperSpec/Body/f_gensym.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gensym&lt;/a&gt;(generate symbol)을 사용해 고유한 심볼을 생성하도록 해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 매크로 내부의 &lt;code&gt;temp&lt;/code&gt;와 외부의 &lt;code&gt;temp&lt;/code&gt;가 서로 다른 변수로 취급되어 충돌을 방지할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729615920556&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(defmacro with-gensym (num &amp;amp;body body)
  (let ((temp (gensym)))
    `(let ((,temp ,num))
       (setf ,temp (+ ,temp 1))
       ,@body)))

;; 사용 예
(let ((temp 5))
  (with-gensym temp
    (print temp))) ;; 결과: 5&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;반면 Racket은 위생적인 매크로이기 때문에 일반적인 lexical scope처럼 사용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729615847849&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax-rule (without-gensym num body ...)
  (let ([temp num])
    (set! temp (+ temp 1))
    body ...))

;; 사용 예
(let ([temp 5])
  (without-gensym temp
    (print temp))) ;; 결과: 5&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;반대로 Racket에서 Common Lisp처럼 영향을 미치려면 어떻게 해야 할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 param에 대입을 해주면 되겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729643944261&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax-rule (without-gensym num body ...)
  (let ([num (+ num 1)])
    body ...))
 
 ;; 사용 예
(let ([temp 5])
  (without-gensym temp
    (print temp))) ;; 결과: 6&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;Racket의 매크로가 확실히 쉽고 명확한 편이죠?&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;h3 data-ke-size=&quot;size23&quot;&gt;1.2 강력한 매크로&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.racket-lang.org/guide/pattern-macros.html#%28part._define-syntax-rule%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;define-syntax-rule&lt;/code&gt;&lt;/a&gt;을 써보았을때 안전한 매크로구나!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라는 생각은 들었지만 그렇다고 저것만으로 강력한 DSL을 정의할 수 있다는 생각이 들지는 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌면 당연한 것이 &lt;code&gt;define-syntax&lt;/code&gt;에서 제약된 형태 중 일부인데다, 활용법을 모르기 때문입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2.1 바닥부터 톺아보기&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.racket-lang.org/guide/macros.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Racket - Macros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.greghendershott.com/fear-of-macros/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fear&amp;nbsp;of&amp;nbsp;Macros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.racket-lang.org/reference/syntax-model.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Syntax&amp;nbsp;Model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://beautifulracket.com/explainer/syntax-objects.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Syntax Object&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;Babel, SWC와 같은 transform이 예시죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://itchallenger.tistory.com/709&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Babel 플러그인을 만들때처럼&lt;/a&gt;, AST 대신 Syntax Object가 존재하며 input-output 값으로 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;define-syntax&lt;/code&gt;에서 transformer-expression에는 syntax 객체가 input으로 들어오는 callback이며, syntax 객체로 return 해야합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729660314156&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax macro-name
  transformer-expression)&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;먼저 들어오는 syntax 객체는 신경쓰지 않고, 항상 &lt;code&gt;&quot;Hello, world!!&quot;&lt;/code&gt;를 출력하는 매크로를 만들어봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;hello-macro&lt;/code&gt;는 확장되어, 컴파일타임에 &lt;code&gt;&quot;Hello, world!!&quot;&lt;/code&gt; 문자열로 대체됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729660438826&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax hello-macro
  (lambda (stx)
    (syntax &quot;Hello, world!!&quot;)))&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;code&gt;(hello-macro)&lt;/code&gt;로 실행해보면 &lt;code&gt;&quot;Hello, world!!&quot;&lt;/code&gt;가 출력되었을 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다 콜백은 함수정의와 마찬가지로 &lt;code&gt;lambda&lt;/code&gt;는 짧게 줄여서 할당해 간결히 만들어봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;syntax 함수는 &lt;code&gt;#'&lt;/code&gt;로 줄일수 있다. &lt;code&gt;#'&lt;/code&gt;는 Lisp계열에서 함수 심볼이라고 표시하는 용도로 많이 쓰이나, Racket에서는 &lt;a href=&quot;https://docs.racket-lang.org/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._~7e~3f%29%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;syntax 객체를 나타내기&lt;/a&gt; 위해 사용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1729661698408&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (hello-macro stx)
  #'&quot;Hello, world!!&quot;)&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;Racket에서 Macro stepper를 활용해 확장된 모습을 보거나,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;265&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcKseI/btsKgcB6Pqj/nk1bbFae3R7Nk5EHq8Ldh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcKseI/btsKgcB6Pqj/nk1bbFae3R7Nk5EHq8Ldh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcKseI/btsKgcB6Pqj/nk1bbFae3R7Nk5EHq8Ldh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdcKseI%2FbtsKgcB6Pqj%2Fnk1bbFae3R7Nk5EHq8Ldh0%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;1238&quot; height=&quot;265&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;265&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;code&gt;expand&lt;/code&gt;를 이용해 확장된 모습과 정보를 확인해볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1729661462706&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(expand #'hello-macro)&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;1165&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c42bY9/btsKhmXMlQX/whXBzk8ZKTTadM4KSIHfVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c42bY9/btsKhmXMlQX/whXBzk8ZKTTadM4KSIHfVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c42bY9/btsKhmXMlQX/whXBzk8ZKTTadM4KSIHfVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc42bY9%2FbtsKhmXMlQX%2FwhXBzk8ZKTTadM4KSIHfVk%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;1090&quot; height=&quot;1165&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;1165&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;1.2.2 Syntax 객체와 리스트 다루기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 syntax는 뒤에 값들을 아예 평가하지 않고, syntax 객체로 만들기 때문에 의도와 달라질 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &lt;code&gt;(syntax (+ 1 2))&lt;/code&gt;는 &lt;code&gt;'(+ 1 2)'&lt;/code&gt; 자체가 syntax 객체가 되며, 미리 계산이 되지 않지요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수도 마찬가지로 &lt;code&gt;(syntax (+ 1 num))&lt;/code&gt;을 하게되면 변수가 바인딩되지 않고, 평가될때 비로소 바인딩 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729663852774&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define num 2)
(define my-syntax (syntax (+ 1 num)))

;; 사용
(expand my-syntax) ;; (#%app + '1 num) 로 확장됨
(eval my-syntax) ;; 이때 바인딩 및 평가&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;pre id=&quot;code_1729664190527&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(quasisyntax (unsyntax (+ 1 2))) ;; 3으로 평가됨
(quasisyntax (+ 1 (unsyntax num))) ;; (+ 1 2)로 num이 바인딩 됨&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;code&gt;quasisyntax&lt;/code&gt;는 &lt;code&gt;#`&lt;/code&gt;으로, &lt;code&gt;unsyntax&lt;/code&gt;는 &lt;code&gt;#,&lt;/code&gt;으로 &lt;a href=&quot;https://docs.racket-lang.org/reference/reader.html#%28part._parse-quote%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;줄여서 쓸 수&lt;/a&gt; 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729664344345&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#`#,(+ 1 2)
#`(+ 1 #,num)&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;Syntax 객체를 데이터로 바꾸는 것도 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;데이터로의 변환이 아니라 메타 데이터를 가져오고 싶다면 &lt;code&gt;syntax-line&lt;/code&gt;이나 &lt;code&gt;syntax-column&lt;/code&gt;과 같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://docs.racket-lang.org/reference/stxops.html&quot;&gt;연산자&lt;/a&gt;를 활용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터로의 변환이 아니라 syntax를 분해하여 syntax list로 만들고 싶다면 &lt;code&gt;syntax-&amp;gt;list&lt;/code&gt;를 활용하자.&lt;/p&gt;
&lt;pre id=&quot;code_1729664788645&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(syntax-&amp;gt;datum #'(+ 1 2))&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 결과는 &lt;code&gt;'(+ 1 2)&lt;/code&gt;라는 리스트다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;249&quot; data-origin-height=&quot;62&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tVvWU/btsKgupddz1/FejkX5GKbrPWTYwg9SFzc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tVvWU/btsKgupddz1/FejkX5GKbrPWTYwg9SFzc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tVvWU/btsKgupddz1/FejkX5GKbrPWTYwg9SFzc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtVvWU%2FbtsKgupddz1%2FFejkX5GKbrPWTYwg9SFzc1%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;249&quot; height=&quot;62&quot; data-origin-width=&quot;249&quot; data-origin-height=&quot;62&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;여기서 Lisp의 리스트와 조작법에 대해 잠시 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lisp가 LISt Processor의 준말임을 생각하면 리스트와 조작에 대한 이해가 없다면 어려움이 생길 수 있습니다.&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;Lisp의 리스트는 Cons cell라는 2개의 포인터를 이용한 링크드 리스트로 되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &lt;a href=&quot;https://www.slideshare.net/slideshow/lisp-61984538/61984538#20&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;아래 이미지&lt;/a&gt;는 중첩리스트인 &lt;code&gt;(list a (r t) b)&lt;/code&gt;를 나타낸 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막의 &lt;code&gt;nil&lt;/code&gt; 혹은 &lt;code&gt;'()&lt;/code&gt;는 null을 나타낸다. 리스프에서는 비어있는 리스트와 null이 동치인 표현입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2hTBk/btsKhI7vACF/e5DilwlLKNKP3KeTXIEhk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2hTBk/btsKhI7vACF/e5DilwlLKNKP3KeTXIEhk0/img.png&quot; data-alt=&quot;중첩리스트인 '(a (r t) b)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2hTBk/btsKhI7vACF/e5DilwlLKNKP3KeTXIEhk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2hTBk%2FbtsKhI7vACF%2Fe5DilwlLKNKP3KeTXIEhk0%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;1285&quot; height=&quot;964&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중첩리스트인 '(a (r t) b)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 cons cell이 꼭 null로 끝날 필요는 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;(cons 1 2)&lt;/code&gt;를 해보면 1과 2를 가르키는 pair 구조를 만들어 낼 수 있죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;92&quot; data-origin-height=&quot;63&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b10aTe/btsKg6ORf7a/e4ls6x4fRpwnk2fvLfsnH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b10aTe/btsKg6ORf7a/e4ls6x4fRpwnk2fvLfsnH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b10aTe/btsKg6ORf7a/e4ls6x4fRpwnk2fvLfsnH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb10aTe%2FbtsKg6ORf7a%2Fe4ls6x4fRpwnk2fvLfsnH1%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;92&quot; height=&quot;63&quot; data-origin-width=&quot;92&quot; data-origin-height=&quot;63&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;(cons 1 2)&lt;/code&gt;는 &lt;code&gt;'(1 . 2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(cons 1&amp;nbsp; (cons 2 (cons 3 '())))&lt;/code&gt;은 &lt;code&gt;(list 1 2 3)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(list 1 2 3)&lt;/code&gt;은 &lt;code&gt;'(1 2 3)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&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;code&gt;'(1 2 3)&lt;/code&gt;을 어떻게 조작해야 할까요?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;246&quot; data-origin-height=&quot;63&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSK64a/btsKgbDvszf/r2fsknE9N16L8M943ZrSO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSK64a/btsKgbDvszf/r2fsknE9N16L8M943ZrSO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSK64a/btsKgbDvszf/r2fsknE9N16L8M943ZrSO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSK64a%2FbtsKgbDvszf%2Fr2fsknE9N16L8M943ZrSO0%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;246&quot; height=&quot;63&quot; data-origin-width=&quot;246&quot; data-origin-height=&quot;63&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 간단한 것은 &lt;code&gt;car&lt;/code&gt;과 &lt;code&gt;cdr&lt;/code&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;code&gt;(car '(1 2 3))&lt;/code&gt;: 첫번째 참조값인 1을 리턴&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(cdr '(1 2 3))&lt;/code&gt;: 두번째 참조값인 2를 리턴&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(car (cdr '(1 2 3)))&lt;/code&gt;: 2를 리턴.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;축약하여 &lt;code&gt;(cadr '(1 2 3))&lt;/code&gt;처럼 사용할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.racket-lang.org/reference/pairs.html#(part._.Pair_.Accessor_.Shorthands)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;caar, cddr, cddar과 같은 방식&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름이 car, cdr인게 이상해 보일 수 있으나. 나름의 역사적인 이유가 존재합니다.&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;1280&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cC6vJE/btsKgLYOaFs/ARL8qXgkkMHD74RDYCX0bk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cC6vJE/btsKgLYOaFs/ARL8qXgkkMHD74RDYCX0bk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cC6vJE/btsKgLYOaFs/ARL8qXgkkMHD74RDYCX0bk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcC6vJE%2FbtsKgLYOaFs%2FARL8qXgkkMHD74RDYCX0bk%2Fimg.webp&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;1285&quot; height=&quot;964&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;code&gt;(length '(1 2 3))&lt;/code&gt;: 길이인 3&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(list-ref '(1 2 3) 2)&lt;/code&gt;: index에 따른 접근&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(append '(1 2 3) '(4 5))&lt;/code&gt;: 두 리스트를 이어 &lt;code&gt;'(1 2 3 4 5)&lt;/code&gt;를 만듦&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(reverse '(1 2 3))&lt;/code&gt;: 뒤집어 &lt;code&gt;'(3 2 1)&lt;/code&gt;을 출력&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;a href=&quot;https://docs.racket-lang.org/reference/pairs.html#(part._.List_.Iteration)&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;a href=&quot;https://black7375.tistory.com/38&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://black7375.tistory.com/38&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729670213442&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;내 맘대로 프로그램 설계 5. - 리스트와 재귀.&quot; data-og-description=&quot;내 맘대로 하는 프로그램 설계 시리즈.Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비.2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/38&quot; data-og-url=&quot;https://black7375.tistory.com/38&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cfZQBQ/hyXlHPAS9f/c69aSZYMKkqTjLubKbT3E0/img.png?width=800&amp;amp;height=104&amp;amp;face=0_0_800_104,https://scrap.kakaocdn.net/dn/bRzSRD/hyXlVAgnsj/Klrf8pjvdmLwCz45eUnsGK/img.png?width=800&amp;amp;height=104&amp;amp;face=0_0_800_104,https://scrap.kakaocdn.net/dn/csHgSI/hyXlT3yJLL/M7XfPSsXsh0nir4kSTMdXK/img.png?width=871&amp;amp;height=474&amp;amp;face=0_0_871_474&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/38&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/38&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cfZQBQ/hyXlHPAS9f/c69aSZYMKkqTjLubKbT3E0/img.png?width=800&amp;amp;height=104&amp;amp;face=0_0_800_104,https://scrap.kakaocdn.net/dn/bRzSRD/hyXlVAgnsj/Klrf8pjvdmLwCz45eUnsGK/img.png?width=800&amp;amp;height=104&amp;amp;face=0_0_800_104,https://scrap.kakaocdn.net/dn/csHgSI/hyXlT3yJLL/M7XfPSsXsh0nir4kSTMdXK/img.png?width=871&amp;amp;height=474&amp;amp;face=0_0_871_474');&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;내 맘대로 프로그램 설계 5. - 리스트와 재귀.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;내 맘대로 하는 프로그램 설계 시리즈.Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비.2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.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;이제 준비되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적으로 매크로를 다루어봅시다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2.3 define-syntax 사용해보기&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;code&gt;#`&lt;/code&gt;로 평가가 가능한 Syntax 객체로 만들고 &lt;code&gt;#,&lt;/code&gt;로 평가를 진행했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729677112144&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (length-of stx)
  #`#,(length (syntax-&amp;gt;datum stx)))

(legth-of '(1 2 3)) ;; 결과는?&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;결과가 3을 예상하지만..!&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;일단 input으로 들어온 syntax 객체를 프린트 해봅니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729678170853&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (length-of stx)
  (println (syntax-&amp;gt;datum stx))
  #`#,(length (syntax-&amp;gt;datum stx)))&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;code&gt;'(length-of '(1 2 3))&lt;/code&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;560&quot; data-origin-height=&quot;155&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JZgXp/btsKg3SsmlR/eMTd0FMoLH6GOOa4t0LjGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JZgXp/btsKg3SsmlR/eMTd0FMoLH6GOOa4t0LjGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JZgXp/btsKg3SsmlR/eMTd0FMoLH6GOOa4t0LjGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJZgXp%2FbtsKg3SsmlR%2FeMTd0FMoLH6GOOa4t0LjGk%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;560&quot; height=&quot;155&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;155&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림을 보고 침착하게 &lt;code&gt;'(1 2 3)&lt;/code&gt;만 나오도록 추출을 해봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1729678615897&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(car (cdr (car (cdr '(length-of '(1 2 3))))))&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;code&gt;cadadr&lt;/code&gt;이 되겠죠?&lt;/p&gt;
&lt;pre id=&quot;code_1729678752759&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (length-of stx)
  #`#,(length (cadadr (syntax-&amp;gt;datum stx))))
  
 (legth-of '(1 2 3)) ;; 결과: 3&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;
&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;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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 도구 없이 Syntax 객체만 조작하여 만들기 때문에 다소 어렵게 느껴질 수도 있습니다.&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;다른 패러다임 문법 구현으로는 명령형 패러다임의 대표적인 문법인 while문을 만들어봅시다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;(while 조건 ...본문)&lt;/code&gt; 이어야 하므로 최소 3개 이상으로 이루어져 있어야 함&lt;/li&gt;
&lt;li&gt;조건과 본문 부분을 뽑아냄&lt;br /&gt;본문은 여러개의 표현식으로 이루어 질 수 있으므로 javascript에서 spread 연산자를 쓰듯, &lt;code&gt;@&lt;/code&gt;을 추가로 붙여줘야 한다.&lt;/li&gt;
&lt;li&gt;조건이 true일 경우 반복하는 재귀함수&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1729751692690&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (while stx)
  (let ([parts (syntax-&amp;gt;datum stx)])
    (if (&amp;lt; (length parts) 3)
        (raise-syntax-error 'while &quot;올바른 형식이 아닙니다: (while condition body ...)&quot; stx)
        (let ([condition (cadr parts)]
              [body (cddr parts)])
          #`(let loop ()
              (when #,condition
                #,@body
                (loop)))))))

;; 사용
(define counter 0)
(while (&amp;lt; counter 5)
  (println counter)
  (set! counter (+ counter 1)))&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;0, 1, 2, 3, 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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;syntax-&amp;gt;datum&lt;/code&gt;은 모든 syntax 메타 정보를 날려버리기 때문에 글로벌 변수가 아니라 지역변수인 &lt;code&gt;let&lt;/code&gt;을 사용하면 작동하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 syntax 정보를 보존하는 &lt;code&gt;syntax-&amp;gt;list&lt;/code&gt;로 변환하여 사용할 필요가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1729754587319&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (while stx)
  (let ([parts (syntax-&amp;gt;list stx)])
    (if (&amp;lt; (length parts) 3)
        (raise-syntax-error 'while &quot;올바른 형식이 아닙니다: (while condition body ...)&quot; stx)
        (let ([condition (cadr parts)]
              [body (cddr parts)])
          #`(let loop ()
              (when #,condition
                #,@body
                (loop)))))))

;; 사용
(let ([counter 0])
  (while (&amp;lt; counter 5)
    (println counter)
    (set! counter (+ counter 1))))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAFZSX/btsKjkS7ezF/ziBSEhDax5K9vNIc53kZ51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAFZSX/btsKjkS7ezF/ziBSEhDax5K9vNIc53kZ51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAFZSX/btsKjkS7ezF/ziBSEhDax5K9vNIc53kZ51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAFZSX%2FbtsKjkS7ezF%2FziBSEhDax5K9vNIc53kZ51%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;822&quot; height=&quot;375&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;375&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;code&gt;cadr&lt;/code&gt;, &lt;code&gt;cddr&lt;/code&gt; 따위로 각 파트를 분리해내는 것, 바인딩이 말입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바인딩은 &lt;a href=&quot;https://docs.racket-lang.org/guide/with-syntax.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;with-syntax&lt;/code&gt;&lt;/a&gt;를 이용해 보다 간단히 만들 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729758848331&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (while stx)
  (let ([parts (syntax-&amp;gt;list stx)])
    (if (&amp;lt; (length parts) 3)
        (raise-syntax-error 'while &quot;올바른 형식이 아닙니다: (while condition body ...)&quot; stx)
        (let ([condition (cadr parts)]
              [body (cddr parts)])
          (with-syntax ([condition condition]
                        [(body ...) body])
            #'(let loop ()
                (when condition
                  body ...
                  (loop))))))))&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;code&gt;...&lt;/code&gt;는 body를 rest parameter로 인식하도록 합니다.&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;h4 data-ke-size=&quot;size20&quot;&gt;1.2.4 매턴매칭 매크로: 선언적으로 작성하기&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;a href=&quot;https://docs.racket-lang.org/guide/syntax-case.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;syntax-case&lt;/code&gt;&lt;/a&gt;를 이용해서요.&lt;/p&gt;
&lt;pre id=&quot;code_1729757661078&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (while stx)
  (syntax-case stx ()
    [(_ condition body ...)
     #'(let loop ()
         (when condition
           body ...
           (loop)))]
    [_ (raise-syntax-error 'while &quot;올바른 형식이 아닙니다: (while condition body ...)&quot; stx)]))&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;사실 &lt;code&gt;with-syntax&lt;/code&gt;도 패턴 매칭을 할 수 있으므로 사용해도 상관없습니다만, &lt;code&gt;syntax-case&lt;/code&gt;가 더 선언적일거에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, rest parameter는 0개일때도 작동하므로, 반드시 1개이상의 표현식을 가지도록 body와 body-rest를 만들어줍시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 패턴 매칭에 실패하면 알아서 에러를 띄우므로 굳이 에러처리를 해야할 필요도 없습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729758041186&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (while stx)
  (syntax-case stx ()
    [(_ condition body1 body-others ...)
     #'(let loop ()
         (when condition
            body1 body-others ...
           (loop)))]))&lt;/code&gt;&lt;/pre&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;93&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvz5cS/btsKhPG8iNa/MNSna7pGjGKbopfOmHDKpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvz5cS/btsKhPG8iNa/MNSna7pGjGKbopfOmHDKpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvz5cS/btsKhPG8iNa/MNSna7pGjGKbopfOmHDKpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbvz5cS%2FbtsKhPG8iNa%2FMNSna7pGjGKbopfOmHDKpK%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;93&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;93&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;&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://docs.racket-lang.org/guide/pattern-macros.html#%28part._define-syntax_and_syntax-rules%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;syntax-rules&lt;/code&gt;&lt;/a&gt;를 사용하여 해결해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, &lt;code&gt;syntax-rules&lt;/code&gt;는 콜백을 리턴해주니 변수에 정의하도록 바꿉니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729759177631&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax while
  (syntax-rules ()
    [(_ condition body1 body-others ...)
     (let loop ()
       (when condition
         body1 body-others ...
         (loop)))]))&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;code&gt;define-syntax-rule&lt;/code&gt;로 줄여서 사용할 수도 있겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음과 비교해보면 말도 안되게 편리해집니다 ㅋㅋㅋㅋ&lt;/p&gt;
&lt;pre id=&quot;code_1729760695158&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax-rule (while condition body1 body-others ...)
  (let loop ()
    (when condition
      body1 body-others ...
      (loop))))&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;Rust를 이끌던 Dave Herman이 매크로 애호가이며, &lt;a href=&quot;https://brson.github.io/2021/05/02/rusts-most-unrecognized-contributor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rust의 매크로 설계에 Racket이 큰 영향&lt;/a&gt;을 끼치기도 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로&amp;nbsp;&lt;a href=&quot;https://doc.rust-kr.org/ch19-06-macros.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rust 매크로&lt;/a&gt;에서 &lt;code&gt;macro_rules!&lt;/code&gt;는 &lt;code&gt;syntax-rules&lt;/code&gt;와 비슷하고, &lt;code&gt;proc_macro&lt;/code&gt;는 &lt;code&gt;define-syntax&lt;/code&gt;와 비슷합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 &lt;code&gt;set!&lt;/code&gt; 처럼 사이드이펙트가 있는 경우 Racket에서는 !를 마지막에 붙이는 관습이 있는데, Rust에서는 선언적 매크로에 !를 붙이도록 하는 작은 변형도...&lt;/p&gt;
&lt;pre id=&quot;code_1729761109378&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 선언적 매크로
#[macro_export]
macro_rules! vec {
    ( $( $x:expr ),* ) =&amp;gt; {
        {
            let mut temp_vec = Vec::new();
            $(
                temp_vec.push($x);
            )*
            temp_vec
        }
    };
}

// 절차적 매크로
use proc_macro;

#[some_attribute]
pub fn some_name(input: TokenStream) -&amp;gt; TokenStream {
}&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;물론 Rust는 중위식이라 전위식 기반인 Racket보다 훨씬 복잡한데다가 타입등의 이유로 매크로 자체를 짜는 난이도가 높을수밖에 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lisp는 사실상 그 자체로 AST나 다름없다보니... 훨씬 쉬운편이지요.&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;1.2.5 syntax-case vs syntax-rules: 컴파일타임과 런타임&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직은 &lt;code&gt;syntax-case&lt;/code&gt;와 &lt;code&gt;syntax-rules&lt;/code&gt;가 헷갈릴겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 본 차이로는 &lt;code&gt;syntax-case&lt;/code&gt;에서 있던 Syntax 객체 생성 문법인 &lt;code&gt;#'&lt;/code&gt;가 사라진 것, &lt;code&gt;syntax-rules&lt;/code&gt;에는 &lt;code&gt;stx&lt;/code&gt; 매개변수가 없다는 거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;syntax-case&lt;/code&gt;는 기본적으로 컴파일 타임에 실행되고 &lt;code&gt;#'&lt;/code&gt; 내부에 있는 요소들이 런타임에 실행되는 반면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;syntax-rules&lt;/code&gt;는 컴파일 타임(phase 1)에 변환만 일어나고 런타임(phase 0)때 실행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;code&gt;syntax-case&lt;/code&gt;는 컴파일 타임에 Syntax 객체의 메타데이터 활용, 입력값 검증이나 조건부처리, 각종 계산 평가들을 할 수 있는 능력을 갖춘 반면, &lt;code&gt;syntax-rules&lt;/code&gt;는 런타임에 처리해야 하는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;syntax-case&lt;/code&gt;를 잘 활용할 수 있는 예를 하나 더 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 입력값 유효성을 컴파일타임에 검증하여 에러를 발생시킵니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729856158012&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (simple-op stx)
  (syntax-case stx ()
    [(_ op a b)
     (and (number? (syntax-&amp;gt;datum #'a)) (number? (syntax-&amp;gt;datum #'b)))
     (case (syntax-&amp;gt;datum #'op)
       [(add) #'(+ a b)]
       [(sub) #'(- a b)]
       [(mul) #'(* a b)]
       [(div) (if (= 0 (syntax-&amp;gt;datum #'b))
                  (raise-syntax-error 'simple-op &quot;0으로 나눌 수 없습니다&quot; #'b)
                  #'(/ a b))]
       [else (raise-syntax-error  'simple-op &quot;지원하지 않는 연산자&quot; #'op)])]
    [(_ op a b) (raise-syntax-error 'simple-op &quot;숫자만 연산이 가능합니다&quot; stx)]))

;; 사용
(simple-op add 1 2) ;; 결과: 3
(simple-op sub 1 2) ;; 결과: -1
(simple-op mul 1 2) ;; 결과: 2
(simple-op div 1 2) ;; 결과: 0.5
(simple-op div 1 0) ;; 에러: 0으로 나눌 수 없음
(simple-op div 1 &quot;abc&quot;) ;; 에러: 숫자만 연산이 가능
(simple-op other 1 2) ;; 에러: 지원하지 않는 연산자&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;바로 &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;sub&lt;/code&gt;를 다루거나 타입을 검증하는 등 더 복잡한 패턴매칭이 가능할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 &lt;a href=&quot;https://docs.racket-lang.org/syntax/Parsing_Syntax.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;syntax/parse&lt;/code&gt;&lt;/a&gt;라는 내장 라이브러리를 이용하면 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729859991157&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; syntax/parse라는 라이브러리 사용 - 매크로를 import할 경우 for-syntax를 붙여줘야 한다
(require (for-syntax syntax/parse))

(define-syntax (simple-op stx)
  (syntax-parse stx
    [(_ (~literal add) a:number b:number) #'(+ a b)]
    [(_ (~literal sub) a:number b:number) #'(- a b)]
    [(_ (~literal mul) a:number b:number) #'(* a b)]
    [(_ (~literal div) a:number b:number)
     (when (= (syntax-&amp;gt;datum #'b) 0)
       (raise-syntax-error 'simple-op &quot;0으로 나눌 수 없습니다&quot; #'b))
     #'(/ a b)]
    [(_ op:id a:number b:number)
     (raise-syntax-error 'simple-op &quot;지원하지 않는 연산자입니다&quot; #'op)]))&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;한층 Rust의 &lt;code&gt;macro_rules!&lt;/code&gt;와 더 가까워졌죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;body:expr&lt;/code&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;1.2.6 함수와 변수를 정의하는 매크로&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 Racket 매크로의 강점을 알아보고, 튜토리얼을 해보았습니다.&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://docs.racket-lang.org/reference/define-struct.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-struct%29%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;define-struct&lt;/a&gt;라 하여 구조체 관련 함수를 만들어주는 매크로입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729865676903&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-struct posn (x y))

;; 사용
(define p1 (make-posn 1 2))
(posn? p1)
(posn-y p1)&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;code&gt;define-struct&lt;/code&gt;를 이용하여 구조체 모양을 정의하면 3가지 종류의 함수를 자동으로 생성합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;make-[이름]&lt;/code&gt;: 구조체 생성자&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[이름]?&lt;/code&gt;: 구조체의 인스턴스인지 확인&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[이름]-[필드]&lt;/code&gt;: 인스턴스의 필드값을 반환&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현한 매크로는 조금 어려워 보이겠지만ㅠㅠ 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서 &lt;code&gt;format-id&lt;/code&gt;는 컴파일 타임에 실행되어야 하는 함수이기 때문에 &lt;code&gt;begin-for-syntax&lt;/code&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;code&gt;'(구조체_이름 arg1 arg2) &lt;/code&gt;와 같은 리스트로 생성 (실제 Racket struct와는 다르겠지만요)&lt;/li&gt;
&lt;li&gt;술어 함수는 &lt;code&gt;car&lt;/code&gt;로 구조체 이름이 같은지 체크&lt;/li&gt;
&lt;li&gt;접근자 함수는 arg이름과 index에 따라 &lt;code&gt;list-ref&lt;/code&gt;로 참조함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729872375949&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(require (for-syntax syntax/parse))

(begin-for-syntax
  (define (format-id stx format-str . base-ids)
    (datum-&amp;gt;syntax stx
      (string-&amp;gt;symbol
        (apply format format-str
          (map syntax-&amp;gt;datum base-ids))))))

(define-syntax (my-define-struct stx)
  (syntax-parse stx
    [(_ name:id (field:id ...))
     #`(begin
         ; 생성자 함수 정의
         (define (#,(format-id stx &quot;make-~a&quot; #'name) field ...)
           (cons 'name (list field ...)))
 
         ; 술어 함수 정의
         (define (#,(format-id stx &quot;~a?&quot; #'name) x)
           (and (list? x) 
                (not (empty? x)) 
                (eq? (car x) 'name)))

         ; 접근자 함수들 정의
         #,@(for/list ([f (syntax-&amp;gt;list #'(field ...))]
                       [i (in-naturals)])
             #`(define (#,(format-id stx &quot;~a-~a&quot; #'name f) x)
                 (list-ref (cdr x) #,i))))]))

;; 사용
(my-define-struct person (name age))
(define p1 (make-person &quot;이름&quot; 20)) ; '(person &quot;이름&quot; 20) 처럼 저장
(person? p1)         ; #true
(person-name p1)     ; &quot;이름&quot;
(person-age p1)      ; 20&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;본문에 직접 바인딩 되는게 불만이라면 앞서 나오는 &lt;code&gt;with-syntax&lt;/code&gt;를 활용하면 되요.&lt;/p&gt;
&lt;pre id=&quot;code_1729880082373&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (my-define-struct stx)
  (syntax-parse stx
    [(_ name:id (field:id ...))
     (with-syntax ([fields (syntax-&amp;gt;list #'(field ...))]
                   [constructor (format-id stx &quot;make-~a&quot; #'name)]
                   [predicate (format-id stx &quot;~a?&quot; #'name)]
                   [(accessor ...) (for/list ([f (syntax-&amp;gt;list #'(field ...))])
                                   (format-id stx &quot;~a-~a&quot; #'name f))]
                   [(index ...) (for/list ([i (in-range (length (syntax-&amp;gt;list #'(field ...))))])
                                #`#,i)])
       #'(begin
           ; 생성자 함수 정의
           (define (constructor field ...)
             (cons 'name (list field ...)))
           
           ; 술어 함수 정의
           (define (predicate x)
             (and (list? x)
                  (not (empty? x))
                  (eq? (car x) 'name)))
           
           ; 접근자 함수들 정의
           (define (accessor x)
             (list-ref (cdr x) index)) ...))]))&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;code&gt;syntax-parse&lt;/code&gt;에서 제공하는 &lt;code&gt;#:with&lt;/code&gt; 를 사용해 블럭을 한단계 줄이는 것도 방법입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729880182763&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define-syntax (my-define-struct stx)
  (syntax-parse stx
    [(_ name:id (field:id ...))
     #:with constructor (format-id stx &quot;make-~a&quot; #'name)
     #:with predicate (format-id stx &quot;~a?&quot; #'name)

     #:with fields (syntax-&amp;gt;list #'(field ...))
     #:with (accessor ...) (for/list ([f (attribute fields)])
                            (format-id stx &quot;~a-~a&quot; #'name f))
     #:with (index ...) (for/list ([i (in-range (length (attribute fields)))])
                         #`#,i)
     #'(begin
         ; 생성자 함수 정의
         (define (constructor field ...)
           (cons 'name (list field ...)))
         
         ; 술어 함수 정의
         (define (predicate x)
           (and (list? x)
                (not (empty? x))
                (eq? (car x) 'name)))
         
         ; 접근자 함수들 정의
         (define (accessor x)
           (list-ref (cdr x) index)) ...)]))&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막에는 난이도가 좀 있었지만, 접근자처럼 복잡한 대상을 구현해서 그렇습니다. 일반적인 경우는 쉽게 만들 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 강력하고 안전한 Racket 매크로의 멋짐을 다들 알아주셨으면 하면서 매크로 파트를 마치겠습니다 ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Racket - Thread와 함께하는 동적바인딩&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1&amp;nbsp;동적 바인딩이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일전에 lexical scope에서 다루었지만, 다시 한번 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://black7375.tistory.com/62&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729933207619&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.&quot; data-og-description=&quot;내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비. 2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/62&quot; data-og-url=&quot;https://black7375.tistory.com/62&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Xtttv/hyXpwGbvgX/Lx2HQrnXsy5yfp07NT5nVK/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/dcjYXo/hyXlRSMykR/7xmClvWyxnNCHdPwth0RZk/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/edrd2b/hyXlXrWf9R/jjzaOUd09wBZTd7DryrWKk/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/62&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Xtttv/hyXpwGbvgX/Lx2HQrnXsy5yfp07NT5nVK/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/dcjYXo/hyXlRSMykR/7xmClvWyxnNCHdPwth0RZk/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/edrd2b/hyXlXrWf9R/jjzaOUd09wBZTd7DryrWKk/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612');&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;내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비. 2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.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;다음은 Emacs Lisp의 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;setq&lt;/code&gt;는 전역변수, &lt;code&gt;defun&lt;/code&gt;은 함수정의, &lt;code&gt;let&lt;/code&gt;은 앞서 보았던 지역변수라고 할때 최종적으로 출력되는 값은 무엇일까요?&lt;/p&gt;
&lt;pre id=&quot;code_1730018960622&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(setq sample-var 5)
(defun sample-print ()
  (print sample-var))
(let ((sample-var 8))
  (sample-print))&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;lexical scope: 컴파일 타임에 결정이 나므로, &lt;code&gt;5&lt;/code&gt;가 출력&lt;/li&gt;
&lt;li&gt;dynamic scope: 런타임에 결정이 나므로, &lt;code&gt;8&lt;/code&gt;이 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 정답을 굳이 고르자면, Emacs Lisp는 dynamic scope를 기본적으로 사용하므로 &lt;code&gt;8&lt;/code&gt;이 출력됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경험을 해보고 싶다면 lexical-binding에 대한 기본값을 조절할 수 있으므로 쉽게 테스트할 수 있을 것 입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730019446715&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(setq lexical-binding t) ;; 활성화
(setq lexical-binding nil) ;; 비활성화&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bH58Pe/btsKltDoBf8/960sJbGFSiGaQnKJd2JFLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH58Pe/btsKltDoBf8/960sJbGFSiGaQnKJd2JFLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH58Pe/btsKltDoBf8/960sJbGFSiGaQnKJd2JFLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH58Pe%2FbtsKltDoBf8%2F960sJbGFSiGaQnKJd2JFLk%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;749&quot; height=&quot;443&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;443&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;이맥스에서는 보통은 파일단위로 lexical scope를 활성화해서 사용하는 편입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음을 첫번째 라인에 두면 해당 파일은 lexical binding을 사용하는 식.&lt;/p&gt;
&lt;pre id=&quot;code_1730020660954&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;;; -*- lexical-binding: t -*-&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;a href=&quot;https://github.com/doomemacs/doomemacs/blob/master/early-init.el&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Doom Emacs&lt;/a&gt;라던가 다양한 설정파일, 그리고 패키지들을 보면 lexical binding을 사용하기 위해 첫 라인에 두는 것을 볼 수 있어요.&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;2.2 왜 동적 바인딩인가?&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&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;실제로 알려진것처럼 기본값으로 동적바인딩이 안좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 왜 고전적인 Lisp들은 동적 바인딩을 사용하고 있을까요?&lt;/p&gt;
&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://www.emacswiki.org/emacs/NoThreading#h5o-3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;역사적인 이유&lt;/a&gt; 때문입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;실제로 John McCarthy가 50년대에 Alonzo Church의 람다 계산을 이해하지 못했기 때문에 어휘 범위 대신 동적 범위를 구현했다는 것입니다. 그리고 elisp가 만들어지고 나서야 어휘 범위가 Lisp 세계의 표준이 되었습니다. . GNU Emacs가 개발되면서 동적 범위에는 Emacs와 같은 프로그램에 대한 몇 가지 유용한 속성이 있다는 것이 밝혀졌습니다. 비록 대부분의 경우 그것이 잘못된 것이기 때문에 멈춰 있었습니다.&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;h4 data-ke-size=&quot;size20&quot;&gt;2.2.1&amp;nbsp;전역변수: 불필요한&amp;nbsp;전역&amp;nbsp;오염을&amp;nbsp;방지&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;변수의 생명주기가 실행 컨텍스트에 한정&lt;/li&gt;
&lt;li&gt;명시적인 범위 내에서만 변수 접근 가능&lt;/li&gt;
&lt;li&gt;실행 종료 후 자동으로 정리됨&lt;/li&gt;
&lt;/ol&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;pre id=&quot;code_1730052191540&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let baseUrl = &quot;https://api.production.com&quot;;

async function getUser(id) {
  const result = await fetch(`${baseUrl}/user/${id}`);
  return await result.json();
}

describe(&quot;테스트&quot;, () =&amp;gt; {
  const bakupUrl = baseUrl;
  beforeEach(() =&amp;gt; {
    baseUrl = &quot;https://api.test.com&quot;;
  });
  afterEach(() =&amp;gt; {
    baseUrl = backupUrl;
  });

  test(&quot;테스트유져 확인&quot;, async () =&amp;gt; {
    const user1 = await getUser(1);
    expect(user1.name).toBe(&quot;test 유저1&quot;);
  });
  // ...
});&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;만약 let 키워드가 블럭 단위의 동적 바인딩을 제공한다고 가정해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 &lt;code&gt;beforeEach&lt;/code&gt;나 &lt;code&gt;afterEach&lt;/code&gt;와 같은 것을 사용하지 않아도 자동적으로 복원이 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730053108910&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let baseUrl = &quot;https://api.production.com&quot;;

async function getUser(id) {
  const result = await fetch(`${baseUrl}/user/${id}`);
  return await result.json();
}

describe(&quot;테스트&quot;, () =&amp;gt; {
  let baseUrl = &quot;https://api.test.com&quot;;

  test(&quot;테스트유져 확인&quot;, async () =&amp;gt; {
    const user1 = await getUser(1);
    expect(user1.name).toBe(&quot;test 유저1&quot;);
  });
  // ...
});&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;let이 거부감이 느껴진다면 &lt;code&gt;with&lt;/code&gt;문과 해당 블럭이 동적 바인딩을 제공한다고 가정해보자. (키워드가 겹침은 무시합시다)&lt;/p&gt;
&lt;pre id=&quot;code_1730056097997&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let baseUrl = &quot;https://api.production.com&quot;;

async function getUser(id) {
  const result = await fetch(`${baseUrl}/user/${id}`);
  return await result.json();
}

describe(&quot;테스트&quot;, () =&amp;gt; {
  with(baseUrl as &quot;https://api.test.com&quot;) {
    test(&quot;테스트유져 확인&quot;, async () =&amp;gt; {
      const user1 = await getUser(1);
      expect(user1.name).toBe(&quot;test 유저1&quot;);
    });
    // ...
  }
});&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;또 다른 예로 로깅의 컨텍스트에 DEBUG, INFO, WARNING, ERROR, CRITICAL과 같은 로그 레벨을 제공해주는 것도 좋은 생각아닐까.&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;h4 data-ke-size=&quot;size20&quot;&gt;2.2.2 컨텍스트: 불필요한 매개변수 제거&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적 바인딩이 유용한 두번째 경우는 불필요한 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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.react.dev/learn/passing-data-deeply-with-context&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Context를&amp;nbsp;사용해&amp;nbsp;데이터를&amp;nbsp;깊게&amp;nbsp;전달하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;870&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Czr3C/btsKnaDjxY2/jfgvwA5f8oBcxIVsD3pz6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Czr3C/btsKnaDjxY2/jfgvwA5f8oBcxIVsD3pz6k/img.png&quot; data-alt=&quot;하위 컴포넌트까지 전달하려면?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Czr3C/btsKnaDjxY2/jfgvwA5f8oBcxIVsD3pz6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCzr3C%2FbtsKnaDjxY2%2FjfgvwA5f8oBcxIVsD3pz6k%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;608&quot; height=&quot;430&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;870&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;/p&gt;
&lt;pre id=&quot;code_1730093590187&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Page() {
  return (
    &amp;lt;Section&amp;gt;
      &amp;lt;Heading level={1}&amp;gt;Title&amp;lt;/Heading&amp;gt;
      &amp;lt;Section&amp;gt;
        &amp;lt;Heading level={2}&amp;gt;Heading&amp;lt;/Heading&amp;gt;
        &amp;lt;Heading level={2}&amp;gt;Heading&amp;lt;/Heading&amp;gt;
        &amp;lt;Heading level={2}&amp;gt;Heading&amp;lt;/Heading&amp;gt;
        &amp;lt;Section&amp;gt;
          &amp;lt;Heading level={3}&amp;gt;Sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;Heading level={3}&amp;gt;Sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;Heading level={3}&amp;gt;Sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;Section&amp;gt;
            &amp;lt;Heading level={4}&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
            &amp;lt;Heading level={4}&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
            &amp;lt;Heading level={4}&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;/Section&amp;gt;
        &amp;lt;/Section&amp;gt;
      &amp;lt;/Section&amp;gt;
    &amp;lt;/Section&amp;gt;
  );
}

function Section({ children }) {
  return (
    &amp;lt;section className=&quot;section&quot;&amp;gt;
      {children}
    &amp;lt;/section&amp;gt;
  );
}

function Heading({ level, children }) {
  const SizedHeader = `h${ level }`;
  return &amp;lt;SizedHeader&amp;gt;{children}&amp;lt;/SizedHeader&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;code&gt;Heading&lt;/code&gt;에 넘겨주는 &lt;code&gt;level&lt;/code&gt; 값에 따라 크기가 달라지며, 섹션이 한단계 증가할 수록 &lt;code&gt;level&lt;/code&gt;의 값이 커지는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvVSWC/btsKk0oV9gw/8pmCxs8EmtddueU0Gm9Vp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvVSWC/btsKk0oV9gw/8pmCxs8EmtddueU0Gm9Vp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvVSWC/btsKk0oV9gw/8pmCxs8EmtddueU0Gm9Vp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvVSWC%2FbtsKk0oV9gw%2F8pmCxs8EmtddueU0Gm9Vp1%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;528&quot; height=&quot;523&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;523&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;a href=&quot;https://ko.react.dev/reference/react/createContext&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;createContext&lt;/a&gt;와 &lt;a href=&quot;https://ko.react.dev/reference/react/useContext&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;useContext&lt;/a&gt;를 사용하는 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730095450924&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createContext, useContext } from &quot;react&quot;;

function Page() {
  return (
    &amp;lt;Section&amp;gt;
      &amp;lt;Heading&amp;gt;Title&amp;lt;/Heading&amp;gt;
      &amp;lt;Section&amp;gt;
        &amp;lt;Heading&amp;gt;Heading&amp;lt;/Heading&amp;gt;
        &amp;lt;Heading&amp;gt;Heading&amp;lt;/Heading&amp;gt;
        &amp;lt;Heading&amp;gt;Heading&amp;lt;/Heading&amp;gt;
        &amp;lt;Section&amp;gt;
          &amp;lt;Heading&amp;gt;Sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;Heading&amp;gt;Sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;Heading&amp;gt;Sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;Section&amp;gt;
            &amp;lt;Heading&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
            &amp;lt;Heading&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
            &amp;lt;Heading&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;/Section&amp;gt;
        &amp;lt;/Section&amp;gt;
      &amp;lt;/Section&amp;gt;
    &amp;lt;/Section&amp;gt;
  );
}

const LevelContext = createContext(0);

function Section({ children }) {
  const level = useContext(LevelContext);
  return (
    &amp;lt;section className=&quot;section&quot;&amp;gt;
      &amp;lt;LevelContext.Provider value={level + 1}&amp;gt;
        {children}
      &amp;lt;/LevelContext.Provider&amp;gt;
    &amp;lt;/section&amp;gt;
  );
}

function Heading({ children }) {
  const level = useContext(LevelContext);
  const SizedHeader = `h${ level }`;
  return &amp;lt;SizedHeader&amp;gt;{children}&amp;lt;/SizedHeader&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;context 덕분에 매우 깔끔하게 구현해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 보았던 동적 바인딩의 속성과 매우 유사하죠?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;변수의 생명주기가 실행 컨텍스트에 한정&lt;/li&gt;
&lt;li&gt;명시적인 범위 내에서만 변수 접근 가능&lt;/li&gt;
&lt;li&gt;실행 종료 후 자동으로 정리됨&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context 변화에 따른 re-render를 요구하는 것 빼고는 사실상 동적 스코프와 거의 같다시피 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언어 차원에서 동적 스코프를 제공했다면, React 팀이나 기타 프레임워크들에서 해야할 일이 많이 줄어들어들 겁니다.&lt;/p&gt;
&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;방금전에는 최상위에 flat하게 정의되어 있기 좋은 예제를 사용했지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테마처럼 때에 따라서 특정한 값을 계속 하위 컴포넌트로 넘겨주어야 할 수도 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730106481943&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from &quot;react&quot;;

const themes = {
  light: {
    background: &quot;#ffffff&quot;,
    text: &quot;#000000&quot;,
    primary: &quot;#007bff&quot;
  },
  dark: {
    background: &quot;#222222&quot;,
    text: &quot;#ffffff&quot;,
    primary: &quot;#0056b3&quot;
  }
};

function App() {
  const [currentTheme, setCurrentTheme] = useState(&quot;light&quot;);

  const toggleTheme = () =&amp;gt; {
    setCurrentTheme(prevTheme =&amp;gt; prevTheme === &quot;light&quot; ? &quot;dark&quot; : &quot;light&quot;);
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;테마 예제&amp;lt;/h1&amp;gt;
      &amp;lt;ParentComponent
        theme={themes[currentTheme]}
        toggleTheme={toggleTheme}
        currentTheme={currentTheme}
      /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

function ParentComponent({ theme, toggleTheme, currentTheme }) {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;ChildComponent
        theme={theme}
        toggleTheme={toggleTheme}
        currentTheme={currentTheme}
      /&amp;gt;
      &amp;lt;AnotherChildComponent
        theme={theme}
        toggleTheme={toggleTheme}
        currentTheme={currentTheme}
      /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

function ChildComponent({ theme, toggleTheme, currentTheme }) {
  return (
    &amp;lt;div style={{
      background: theme.background,
      color: theme.text,
      padding: &quot;20px&quot;,
      transition: &quot;all 0.3s ease&quot;
    }}&amp;gt;
      &amp;lt;h2&amp;gt;현재 테마: {currentTheme}&amp;lt;/h2&amp;gt;
      &amp;lt;button 
        onClick={toggleTheme}
        style={{
          background: theme.primary,
          color: theme.text,
          padding: &quot;10px 20px&quot;,
          borderRadius: &quot;5px&quot;
        }}
      &amp;gt;
        테마 변경
      &amp;lt;/button&amp;gt;
      &amp;lt;p&amp;gt;이것은 테마가 적용된 컴포넌트입니다.&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

function AnotherChildComponent({ theme }) {
  return (
    &amp;lt;div style={{
      background: theme.background,
      color: theme.text,
      padding: &quot;20px&quot;,
      marginTop: &quot;10px&quot;
    }}&amp;gt;
      &amp;lt;p&amp;gt;다른 자식 컴포넌트&amp;lt;/p&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;이럴때 context를 사용하면 자연스럽게 개선을 할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730105841322&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// == 테마 제공 ===================================================================
import { createContext, useState, useContext } from &quot;react&quot;;

// 테마 정의
const themes = {
  light: {
    background: &quot;#ffffff&quot;,
    text: &quot;#000000&quot;,
    primary: &quot;#007bff&quot;
  },
  dark: {
    background: &quot;#222222&quot;,
    text: &quot;#ffffff&quot;,
    primary: &quot;#0056b3&quot;
  }
};

// Context 생성
const ThemeContext = createContext();

// Provider 컴포넌트
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState(&quot;light&quot;);

  const toggleTheme = () =&amp;gt; {
    setTheme(prevTheme =&amp;gt; prevTheme === &quot;light&quot; ? &quot;dark&quot; : &quot;light&quot;);
  };

  const value = {
    theme: themes[theme],
    toggleTheme,
    currentTheme: theme
  };

  return (
    &amp;lt;ThemeContext.Provider value={value}&amp;gt;
      {children}
    &amp;lt;/ThemeContext.Provider&amp;gt;
  );
}

// 커스텀 훅
function useTheme() {
  const context = useContext(ThemeContext);
  if (context === undefined) {
    throw new Error(&quot;useTheme must be used within a ThemeProvider&quot;);
  }
  return context;
}

// == 테마 사용 ===================================================================
function App() {
  return (
    &amp;lt;ThemeProvider&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;h1&amp;gt;테마 예제&amp;lt;/h1&amp;gt;
        &amp;lt;ParentComponent /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/ThemeProvider&amp;gt;
  );
}

function ParentComponent() {
  return (
    &amp;lt;ChildComponent /&amp;gt;
    &amp;lt;AnotherChildComponent /&amp;gt;
  );
}

function ChildComponent() {
  const { theme, toggleTheme, currentTheme } = useTheme();

  return (
    &amp;lt;div style={{
      background: theme.background,
      color: theme.text,
      padding: &quot;20px&quot;,
      transition: &quot;all 0.3s ease&quot;
    }}&amp;gt;
      &amp;lt;h2&amp;gt;현재 테마: {currentTheme}&amp;lt;/h2&amp;gt;
      &amp;lt;button 
        onClick={toggleTheme}
        style={{
          background: theme.primary,
          color: theme.text,
          padding: &quot;10px 20px&quot;,
          borderRadius: &quot;5px&quot;
        }}
      &amp;gt;
        테마 변경
      &amp;lt;/button&amp;gt;
      &amp;lt;p&amp;gt;이것은 테마가 적용된 컴포넌트입니다.&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

function AnotherChildComponent() {
  const { theme } = useTheme();

  return (
    &amp;lt;div style={{
      background: theme.background,
      color: theme.text,
      padding: &quot;20px&quot;,
      marginTop: &quot;10px&quot;
    }}&amp;gt;
      &amp;lt;p&amp;gt;다른 자식 컴포넌트&amp;lt;/p&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;자, 그렇다면 프론트에만 유용할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.djangoproject.com/en/5.1/ref/request-response/#quick-overview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;첫번째 View 함수 인자로 HttpRequest를 전달&lt;/a&gt;하는 Django와 달리 Flask는 &lt;a href=&quot;https://flask.palletsprojects.com/en/stable/reqcontext/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Request Context&lt;/a&gt;를 통해 각 요청을 처리하며,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날에는 &lt;a href=&quot;https://flask-docs-kr.readthedocs.io/ko/stable/reqcontext.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자체적으로 구현&lt;/a&gt;되어 있었으나 최신에는 Python 3.7에 도입된 &lt;a href=&quot;https://docs.python.org/ko/3/library/contextvars.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;contextvars&lt;/a&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;a href=&quot;https://testdriven.io/blog/flask-contexts-advanced/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Deep&amp;nbsp;Dive&amp;nbsp;into&amp;nbsp;Flask's&amp;nbsp;Application&amp;nbsp;and&amp;nbsp;Request&amp;nbsp;Contexts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spoqa.github.io/2012/05/07/about-flask-request.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Werkzeug와&amp;nbsp;Flask의&amp;nbsp;Request&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1730108785305&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from flask import Flask, request, g
from flask import current_app

app = Flask(__name__)

# 요청 전에 실행되는 before_request 함수
@app.before_request
def before_request_func():
    g.user = None  # g 객체에 사용자 정보 저장
    if &quot;user_id&quot; in request.headers:
        g.user = request.headers[&quot;user_id&quot;]

# 기본 라우트
@app.route(&quot;/&quot;)
def index():
    # request 객체 사용
    user_agent = request.headers.get(&quot;User-Agent&quot;)
    # g 객체 사용
    current_user = g.user or &quot;Anonymous&quot;
    return f&quot;Hello {current_user}! Your browser is: {user_agent}&quot;

# request context를 수동으로 사용하는 예제
def process_request_outside_context():
    with app.test_request_context(&quot;/hello&quot;, method=&quot;POST&quot;):
        # 이제 request context 내부입니다
        assert request.path == &quot;/hello&quot;
        assert request.method == &quot;POST&quot;
        
        # current_app 접근 가능
        assert current_app.name == &quot;app&quot;&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;code&gt;contextvars&lt;/code&gt;는 저도 FastAPI와 SQLModel 환경 구축을 위해 transactional을 구현하는 도중 사용한 경험이 있는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NDA 때문에 직접적인 코드를 보여주지는 못하지만, &lt;a href=&quot;https://dev.to/uponthesky/python-post-reviewhow-to-implement-a-transactional-decorator-in-fastapi-sqlalchemy-ein&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How to implement a transactional decorator in FastAPI + SQLAlchemy&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;위의 Django처럼 첫번째 인자로 context를 넘기는 방향으로 처리해왔습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730109330570&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SQLite
// https://www.sqlite.org/c3ref/prepare.html
int sqlite3_prepare_v2(
    sqlite3 *db,            /* Database handle */
    const char *zSql,       /* SQL statement, UTF-8 encoded */
    int nByte,              /* Maximum length of zSql in bytes. */
    sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
    const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);

// libcurl
// https://curl.se/libcurl/c/curl_easy_setopt.html
CURLcode curl_easy_setopt(
  CURL *handle, // context
  CURLoption option,
  parameter
);

// FFmpeg
// https://ffmpeg.org/doxygen/6.1/group__lavc__decoding.html
int avcodec_default_get_buffer2(
  AVCodecContext *s,
  AVFrame *frame,
  int flags
);&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;이 전통에 따라 Go도 &lt;a href=&quot;https://pkg.go.dev/context&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;context&lt;/a&gt;를 사용할때 첫번째 인자는 항상 context를 넘기도록 되어있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://go.dev/blog/context&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Go&amp;nbsp;Concurrency&amp;nbsp;Patterns:&amp;nbsp;Context&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Go는 에러처리에서도 명시적으로 처리하기 좋아하는 언어라서 그렇다쳐도&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;h4 data-ke-size=&quot;size20&quot;&gt;2.2.3 의존성 주입: 보일러 플레이트 제거&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 주입은 보일러 플레이트가 많기로 유명합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 개념 자체는 생각보다 간단하며, DI 프레임워크들 그리고 언어 자체가 장황한 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;a href=&quot;https://developer.android.com/training/dependency-injection?hl=ko#kotlin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Android의 DI예제&lt;/a&gt;를 살펴보면 Kotlin과 Java의 차이는 상당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 합쳐 코틀린이 43라인인 반면 자바는 59라인입니다(약 1.4배).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d5weVp/btsKmUH1agL/pg5qeWeXBRrpodLRuHW200/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d5weVp/btsKmUH1agL/pg5qeWeXBRrpodLRuHW200/img.png&quot; width=&quot;500&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;302&quot; data-is-animation=&quot;false&quot; style=&quot;width: 63.7169%; margin-right: 10px;&quot; data-widthpercent=&quot;64.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d5weVp/btsKmUH1agL/pg5qeWeXBRrpodLRuHW200/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5weVp%2FbtsKmUH1agL%2Fpg5qeWeXBRrpodLRuHW200%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;576&quot; height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z1IbI/btsKnbCLebd/6RqwHzAtUSQDYiZjO6mbI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z1IbI/btsKnbCLebd/6RqwHzAtUSQDYiZjO6mbI0/img.png&quot; width=&quot;500&quot; data-title=&quot;&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;546&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;35.53&quot; style=&quot;width: 35.1203%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z1IbI/btsKnbCLebd/6RqwHzAtUSQDYiZjO6mbI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ1IbI%2FbtsKnbCLebd%2F6RqwHzAtUSQDYiZjO6mbI0%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;574&quot; height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;DI 전과 후: 결합도가 줄어들었다&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;pre id=&quot;code_1730118255295&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// DI 적용 전
class Car {
    private val engine = Engine()

    fun start() {
        engine.start()
    }
}

fun main(args: Array) {
    val car = Car()
    car.start()
}


// 생성자 삽입 DI
class Car(private val engine: Engine) {
    fun start() {
        engine.start()
    }
}

fun main(args: Array) {
    val engine = Engine()
    val car = Car(engine)
    car.start()
}


// 필드 삽입 DI
class Car {
    lateinit var engine: Engine

    fun start() {
        engine.start()
    }
}

fun main(args: Array) {
    val car = Car()
    car.engine = Engine()
    car.start()
}&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;pre id=&quot;code_1730118310249&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// DI 적용 전
class Car {
    private Engine engine = new Engine();

    public void start() {
        engine.start();
    }
}

class MyApp {
    public static void main(String[] args) {
        Car car = new Car();
        car.start();
    }
}


// 생성자 삽입 DI
class Car {
    private final Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        engine.start();
    }
}

class MyApp {
    public static void main(String[] args) {
        Engine engine = new Engine();
        Car car = new Car(engine);
        car.start();
    }
}


// 필드 삽입 DI
class Car {
    private Engine engine;

    public void setEngine(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        engine.start();
    }
}

class MyApp {
    public static void main(String[] args) {
        Car car = new Car();
        car.setEngine(new Engine());
        car.start();
    }
}&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;예제로 본 DI 개념 자체는 무척이나 간단한게, 외부에서 생성자나 필드로 값을 주입해 제어를 역전하기 입니다.&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://dagger.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dagger&lt;/a&gt;라는 프레임워크를 기준으로 설명하고자 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730119948322&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import javax.inject.Inject
import dagger.Component
import dagger.Module
import dagger.Provides

// 생성자 주입
// 1. 의존성이 필요한 클래스 (@Inject)
class Car @Inject constructor(private val engine: Engine) {
    fun start() {
        engine.start()
    }
}

// 2. 의존성을 제공하는 모듈 (@Module)
@Module
class EngineModule {
    @Provides
    fun provideEngine() = Engine()
}

// 3. 둘을 연결하는 컴포넌트 (@Component)
@Component(modules = [EngineModule::class])
interface CarComponent {
    fun getCar(): Car
}

// 실제 사용
// @Component 사용으로, 앞에 Dagger가 붙은 DaggerCarComponent가 자동생성됨
fun main() {
    val carComponent = DaggerCarComponent.create()
    val car = carComponent.getCar()
    car.start()
}&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;code&gt;@Module&lt;/code&gt;, &lt;code&gt;@Component&lt;/code&gt;이며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;code&gt;DaggerCarComponent.create()&lt;/code&gt;로 의존성&amp;nbsp;주입&amp;nbsp;관리자&amp;nbsp;생성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;carComponent.getCar()&lt;/code&gt;로 객체&amp;nbsp;생성과&amp;nbsp;의존성&amp;nbsp;주입&lt;/li&gt;
&lt;/ul&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;필드 삽입 DI의 예까지만 보고 DI 프레임워크를 사용했을때 장점을 알아봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1730132145402&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 필드 주입
// 1. 의존성이 필요한 클래스 (@Inject)
class Car {
    @Inject
    lateinit var engine: Engine

    fun start() {
        engine.start()
    }
}

// 2. 의존성을 제공하는 모듈 (@Module)
@Module
class CarModule {
    @Provides
    fun provideEngine() = Engine()
}

// 3. 둘을 연결하는 컴포넌트 (@Component)
@Component(modules = [CarModule::class])
interface CarComponent {
    fun inject(car: Car)
}

// 실제 사용
// @Component 사용으로, 앞에 Dagger가 붙은 DaggerCarComponent가 자동생성됨
fun main() {
    val car = Car()
    val carComponent = DaggerCarComponent.create()
    carComponent.inject(car)
    car.start()
}&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;예를 들어 엔진을 구성할때 &lt;code&gt;FuelInjector&lt;/code&gt;, &lt;code&gt;EngineSensor&lt;/code&gt;, &lt;code&gt;EngineLogger&lt;/code&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;pre id=&quot;code_1730134105025&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 센서 및 모니터링 인터페이스 구현
interface EngineSensor {
    fun getCurrentStatus(): EngineStatus
    fun getTemperature(): Float
}

class EngineTemperatureSensor @Inject constructor() : EngineSensor {
    override fun getCurrentStatus(): EngineStatus = EngineStatus.RUNNING
    override fun getTemperature(): Float = 90.0f
}

interface TirePressureSensor {
    fun getCurrentPressure(): Float
}

class StandardTirePressureSensor @Inject constructor() : TirePressureSensor {
    override fun getCurrentPressure(): Float = 32.0f
}

interface EngineLogger {
    fun log(message: String)
}

class ConsoleEngineLogger @Inject constructor() : EngineLogger {
    override fun log(message: String) {
        println(&quot;Engine: $message&quot;)
    }
}

interface CarMonitor {
    fun logEvent(event: CarEvent)
}

class ConsoleCarMonitor @Inject constructor() : CarMonitor {
    override fun logEvent(event: CarEvent) {
        println(&quot;Car Event: $event&quot;)
    }
}

// 2. FuelInjector 구현
class FuelInjector @Inject constructor() {
    fun inject() {
        println(&quot;Fuel injected&quot;)
    }
    
    fun stop() {
        println(&quot;Fuel injection stopped&quot;)
    }
}

// 3. 핵심 컴포넌트 구현
interface Engine {
    fun start()
    fun stop()
    fun getStatus(): EngineStatus
    fun getTemperature(): Float
}

class GasolineEngine @Inject constructor(
    private val fuelInjector: FuelInjector,
    private val engineSensor: EngineSensor,
    private val engineLogger: EngineLogger
) : Engine {
    override fun start() {
        fuelInjector.inject()
        engineLogger.log(&quot;Engine started&quot;)
    }
    
    override fun stop() {
        fuelInjector.stop()
        engineLogger.log(&quot;Engine stopped&quot;)
    }
    
    override fun getStatus(): EngineStatus = engineSensor.getCurrentStatus()
    override fun getTemperature(): Float = engineSensor.getTemperature()
}

interface Wheel {
    fun getPressure(): Float
    fun checkCondition(): WheelCondition
}

class StandardWheel @Inject constructor(
    private val tirePressureSensor: TirePressureSensor
) : Wheel {

    override fun getPressure(): Float = tirePressureSensor.getCurrentPressure()
    override fun checkCondition(): WheelCondition = WheelCondition.GOOD
}

// 4. Car 구현
interface Car {
    fun start()
    fun stop()
    fun drive()
    fun getStatus(): CarStatus
}

class StandardCar @Inject constructor(
    private val engine: Engine,
    @Named(&quot;wheels&quot;) private val wheels: List&amp;lt;Wheel&amp;gt;,
    private val carMonitor: CarMonitor
) : Car {
    override fun start() {
        engine.start()
        carMonitor.logEvent(CarEvent.START)
    }
    
    override fun stop() {
        engine.stop()
        carMonitor.logEvent(CarEvent.STOP)
    }
    
    override fun drive() {
        if (engine.getStatus() == EngineStatus.RUNNING) {
            wheels.forEach { it.rotate() }
            carMonitor.logEvent(CarEvent.DRIVING)
        }
    }
    
    override fun getStatus(): CarStatus = CarStatus(
        engineStatus = engine.getStatus(),
        engineTemperature = engine.getTemperature(),
        wheelsPressure = wheels.map { it.getPressure() }
    )
}

// 5. 데이터 클래스 및 열거형
data class CarStatus(
    val engineStatus: EngineStatus,
    val engineTemperature: Float,
    val wheelsPressure: List&amp;lt;Float&amp;gt;
)

enum class EngineStatus {
    STOPPED, RUNNING, ERROR
}

enum class WheelCondition {
    GOOD, WORN, CRITICAL
}

enum class CarEvent {
    START, STOP, DRIVING
}

// 6. Dagger 모듈 및 컴포넌트
@Module
class CarModule {
    @Provides
    fun provideEngineSensor(sensor: EngineTemperatureSensor): EngineSensor = sensor

    @Provides
    fun provideTirePressureSensor(sensor: StandardTirePressureSensor): TirePressureSensor = sensor

    @Provides
    fun provideEngineLogger(logger: ConsoleEngineLogger): EngineLogger = logger

    @Provides
    fun provideCarMonitor(monitor: ConsoleCarMonitor): CarMonitor = monitor

    @Provides
    fun provideEngine(engine: GasolineEngine): Engine = engine

    @Provides
    @Named(&quot;wheels&quot;)
    fun provideWheels(
        tirePressureSensor: Provider&amp;lt;TirePressureSensor&amp;gt;,
    ): List&amp;lt;Wheel&amp;gt; = List(4) { 
        StandardWheel(tirePressureSensor.get())
    }

    @Provides
    fun provideCar(car: StandardCar): Car = car
}

@Component(modules = [CarModule::class])
interface CarComponent {
    fun getCar(): Car
}

// 7. 실제 사용
fun main() {
    val carComponent = DaggerCarComponent.create()
    val car = carComponent.getCar()
    
    car.start()
    car.drive()
    println(car.getStatus())
    car.stop()
}&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;code&gt;@Module&lt;/code&gt;에서 의존성 제공을 모두 처리해주니 확실히 깔끔해보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dagger는 &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;방금은&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_1730140723457&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum class EngineType {
    GASOLINE,
    ELECTRIC,
    HYBRID
}

@Module
class NetworkModule {
    @Provides
    @Singleton
    fun provideNetworkClient(): NetworkClient {
        return NetworkClientImpl()
    }
}

@Module
class CarModule(private val engineType: EngineType) {
    @Provides
    fun provideEngineSensor(sensor: EngineTemperatureSensor): EngineSensor = sensor

    @Provides
    fun provideTirePressureSensor(sensor: StandardTirePressureSensor): TirePressureSensor = sensor

    @Provides
    fun provideEngineLogger(logger: ConsoleEngineLogger): EngineLogger = logger

    @Provides
    fun provideCarMonitor(monitor: ConsoleCarMonitor): CarMonitor = monitor

    @Provides
    fun provideEngine(
        gasolineEngine: Provider&amp;lt;GasolineEngine&amp;gt;,
        electricEngine: Provider&amp;lt;ElectricEngine&amp;gt;,
        hybridEngine: Provider&amp;lt;HybridEngine&amp;gt;
    ): Engine {
        return when (engineType) {
            EngineType.GASOLINE -&amp;gt; gasolineEngine.get()
            EngineType.ELECTRIC -&amp;gt; electricEngine.get()
            EngineType.HYBRID -&amp;gt; hybridEngine.get()
        }
    }

    @Provides
    @Named(&quot;wheels&quot;)
    fun provideWheels(
        tirePressureSensor: Provider&amp;lt;TirePressureSensor&amp;gt;,
    ): List&amp;lt;Wheel&amp;gt; = List(4) { 
        StandardWheel(tirePressureSensor.get())
    }

    @Provides
    fun provideCar(car: StandardCar): Car = car
}

@Component(modules = [
    CarModule::class,
    NetworkModule::class,
    SecureModule::class
])
interface CarComponent {
    fun getCar(): Car

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun carModule(carModule: CarModule): Builder
        fun networkModule(networkModule: NetworkModule): Builder
        fun build(): CarComponent
    }
}

fun main() {
    val carComponent = DaggerCarComponent.builder()
        .carModule(CarModule(EngineType.HYBRID))
        .networkModule(NetworkModule(baseUrl = &quot;https://car-api.example.com&quot;))
        .build()

    val car = carComponent.getCar()
    
    car.start()
    car.drive()
    println(car.getStatus())
    car.stop()
}&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;의존성이 복잡하게 얽혀있고, 이런저런 커스텀이 필요할때 DI 프레임워크를 사용하면 도움이 되리란 것을 체감할 수 있습니다.&lt;/p&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;그래서 동적 바인딩과는 대체 무슨 상관이지?&quot; 라는 생각이 스물스물 올라오고 있을테지요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DI 프레임워크의 필요성만 설파할 뿐이지, 동적 바인딩에 대해서는 언급하지 않았으니까 말입니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;DynamicParameter&lt;/code&gt;로 초기값을 산정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;currentLogLevel&lt;/code&gt;로 참조&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withDynamicScope&lt;/code&gt;로 블록 내부에서 얻어지는 값이 바뀌게끔함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1730255933228&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val currentLogLevel = DynamicParameter&amp;lt;LogLevel&amp;gt;(LogLevel.INFO)

fun log(level: LogLevel, msg: String) {
    if (level.priority &amp;gt;= currentLogLevel.priority) {
        println(&quot;[$level] $msg&quot;)
    }
}

fun main() {
    log(LogLevel.DEBUG, &quot;Debug message&quot;) // 출력 안됨
    
    withDynamicScope(currentLogLevel to LogLevel.DEBUG) {
        log(LogLevel.DEBUG, &quot;Debug message&quot;) // 출력됨
    }
}&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;앞선 Context도 일종의 의존성 주입이었죠.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20240420234105/https://gulundin.github.io/di-frameworks-are-dynamic-binding/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dynamic&amp;nbsp;scoping&amp;nbsp;is&amp;nbsp;the&amp;nbsp;simplest&amp;nbsp;form&amp;nbsp;of&amp;nbsp;dependency&amp;nbsp;injection&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;code&gt;CarContext&lt;/code&gt;: &lt;code&gt;@Module CarModule&lt;/code&gt;처럼 사용될 동적 변수들 모음&lt;/li&gt;
&lt;li&gt;&lt;code&gt;createCar&lt;/code&gt;: 의존성을 주입하여 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1730220635880&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 사용될 Context 정의
object CarContext {
    val currentEngineSensor = DynamicParameter&amp;lt;EngineSensor&amp;gt;()
    val currentTirePressureSensor = DynamicParameter&amp;lt;TirePressureSensor&amp;gt;()
    val currentEngineLogger = DynamicParameter&amp;lt;EngineLogger&amp;gt;()
    val currentCarMonitor = DynamicParameter&amp;lt;CarMonitor&amp;gt;()
    val currentEngine = DynamicParameter&amp;lt;Engine&amp;gt;()
    val currentWheels = DynamicParameter&amp;lt;List&amp;lt;Wheel&amp;gt;&amp;gt;()
    val currentCar = DynamicParameter&amp;lt;Car&amp;gt;()
}

// 2. Context 사용
class GasolineEngine: Engine {
    private val fuelInjector: FuelInjector = FuelInjector()
    private val engineSensor: EngineSensor get() = CarContext.currentEngineSensor
    private val engineLogger: EngineLogger get() = CarContext.currentEngineLogger

    override fun start() {
        fuelInjector.inject()
        engineLogger.log(&quot;Engine started&quot;)
    }
    
    override fun stop() {
        fuelInjector.stop()
        engineLogger.log(&quot;Engine stopped&quot;)
    }
    
    override fun getStatus(): EngineStatus = engineSensor.getCurrentStatus()
    override fun getTemperature(): Float = engineSensor.getTemperature()
}

class StandardWheel: Wheel {
    private val tirePressureSensor: TirePressureSensor get() = CarContext.currentTirePressureSensor

    override fun getPressure(): Float = tirePressureSensor.getCurrentPressure()
    override fun checkCondition(): WheelCondition = WheelCondition.GOOD
}

class StandardCar : Car {
    private val engine: Engine  get() = CarContext.currentEngine
    private val wheels: List&amp;lt;Wheel&amp;gt;  get() = CarContext.currentWheels
    private val carMonitor: CarMonitor  get() = CarContext.currentCarMonitor

    override fun start() {
        engine.start()
        carMonitor.logEvent(CarEvent.START)
    }
    
    override fun stop() {
        engine.stop()
        carMonitor.logEvent(CarEvent.STOP)
    }
    
    override fun drive() {
        if (engine.getStatus() == EngineStatus.RUNNING) {
            wheels.forEach { it.rotate() }
            carMonitor.logEvent(CarEvent.DRIVING)
        }
    }
    
    override fun getStatus(): CarStatus = CarStatus(
        engineStatus = engine.getStatus(),
        engineTemperature = engine.getTemperature(),
        wheelsPressure = wheels.map { it.getPressure() }
    )
}

// 3. Context 제공
fun createEngine(engineType: EngineType) {
    withDynamicScope(
        CarContext.currentEngineSensor to EngineTemperatureSensor(),
        CarContext.currentEngineLogger to ConsoleEngineLogger(),
        CarContext.currentEngine to when (engineType) {
            EngineType.GASOLINE -&amp;gt; GasolineEngine()
            EngineType.ELECTRIC -&amp;gt; ElectricEngine()
            EngineType.HYBRID -&amp;gt; HybridEngine()
        }
    ) {
        return CarContext.currentEngine
    }
}

fun createCar(
    engineType: EngineType,
    networkModule: NetworkModule,
) {
    withDynamicScope(
        CarContext.currentTirePressureSensor to StandardTirePressureSensor,
        CarContext.currentWheels to List(4) { StandardWheel() },
        CarContext.currentEngine to createEngine(engineType),
        CarContext.currentCar to StandardCar()
        NetworkContext.currentNetworkModule to networkModule,
        SecureContext.currentSecureModule to createSecure()
    ) {
        return CarContext.currentCar
    }
}

// 4. 실제 사용
fun main() {
    val car = createCar(
        engineType=EngineType.HYBRID,
        networkModule=createNetwork(baseUrl = &quot;https://car-api.example.com&quot;)
    )

    car.start()
    car.drive()
    println(car.getStatus())
    car.stop()

    withDynamicScope(
        CarComponents.currentEngineSensor to MockEngineSensor(),
        CarComponents.currentCarMonitor to MockCarMonitor()
    ) {
        car.start()
        car.drive()
        println(car.getStatus())
        car.stop()
    }
}&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;분명 처음보는 문법임에도, Dagger를 사용했을때보다 간결해보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 의심되는 부분이 있습니다. Dagger처럼 의존성이 제공이 컴파일 타임에 체크가 가능한가입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일타임에 &lt;b&gt;의존성 체크&lt;/b&gt;만 성공적으로 이루어진다면 의존성을 제공하는 부분은 간결하게 &lt;code&gt;createCar&lt;/code&gt;과 같은 함수만 만들면 되기 때문에 무척 쉬워지죠.&lt;/p&gt;
&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;컴파일러의 Null Safety의 확장으로서 생각하기.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수를 호출하거나, 생성자를 호출하는 곳 기준 Null 안전성을 갖춰야 한다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 본문이나 클래스 정의에서는 의존성을 갖추었는지를 알 방법이 없으므로, 호출하는 곳이 기준점이어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;초기값을 모두 가지고 있다면 안전하게 함수나 생성자 호출 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withDynamicScope&lt;/code&gt;로 모든 동적 바인딩 변수나 프로퍼티가 제공되었다면 함수나 생성자 호출 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1730258838268&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun useCar() {
    // 동적 바인딩을 사용하는 함수 본문이나 클래스 프로퍼티에서는 알 수 없고,
    // 호출지점에서 Scope가 있는지 결정나므로 생성자가 실행되는 지점에서 에러체크
    val car1 = StandardCar() // 에러: currentEngine, currentWheels, currentCarMonitor의 초기값이 없음
 
    withDynamicScope(
        CarContext.currentTirePressureSensor to StandardTirePressureSensor,
        CarContext.currentEngineLogger to ConsoleEngineLogger(),
        CarContext.currentCarMonitor to ConsoleCarMonitor(),
        CarContext.currentEngine to GasolineEngine(),
        CarContext.currentWheels to List(4) { StandardWheel() },
    ) {
        val car2 = StandardCar() // 에러: GasolineEngine에서 사용되는 currentEngineSensor가 제공되지 않음
    }

    withDynamicScope(
        CarContext.currentEngineSensor to EngineTemperatureSensor(),
        CarContext.currentTirePressureSensor to StandardTirePressureSensor,
        CarContext.currentEngineLogger to ConsoleEngineLogger(),
        CarContext.currentCarMonitor to ConsoleCarMonitor(),
        CarContext.currentEngine to GasolineEngine(),
        CarContext.currentWheels to List(4) { StandardWheel() },
    ) {
        val car3 = StandardCar() // 성공
    }
}&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;함께 제공하는 Context 묶음에 대해 Dagger처럼 의존성 그래프가 만족하는지 체크할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730259360617&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 마치 Dagger의 @Module처럼 의존성이 모두 만족하는지 체크
@Context
object CarContext {
    val currentEngineSensor = DynamicParameter&amp;lt;EngineSensor&amp;gt;()
    val currentTirePressureSensor = DynamicParameter&amp;lt;TirePressureSensor&amp;gt;()
    val currentEngineLogger = DynamicParameter&amp;lt;EngineLogger&amp;gt;()
    val currentCarMonitor = DynamicParameter&amp;lt;CarMonitor&amp;gt;()
    val currentEngine = DynamicParameter&amp;lt;Engine&amp;gt;()
    val currentWheels = DynamicParameter&amp;lt;List&amp;lt;Wheel&amp;gt;&amp;gt;()
    val currentCar = DynamicParameter&amp;lt;Car&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;물론 복잡한 케이스에서&amp;nbsp;&lt;a href=&quot;https://github.com/saasquatch/bunshi&quot;&gt;Bunshi&lt;/a&gt;나&amp;nbsp;&lt;a href=&quot;https://github.com/disjukr/bunja&quot;&gt;Bunja&lt;/a&gt;와 같은 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;2.3 Thread 안전한 동적 바인딩&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Racket에는 &lt;a href=&quot;https://docs.racket-lang.org/mzscheme/Old_Syntactic_Forms.html#%28form._%28%28lib._mzscheme%2Fmain..rkt%29._fluid-let%29%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fluid-let&lt;/a&gt;과 &lt;a href=&quot;https://docs.racket-lang.org/reference/parameters.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;parameterize&lt;/a&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;code&gt;fluid-let&lt;/code&gt;: 일반 변수를 동적 스코프처럼 쓸 수 있게 해줌&lt;/li&gt;
&lt;li&gt;&lt;code&gt;parameterize&lt;/code&gt;: &lt;code&gt;make-parameter&lt;/code&gt;와 쌍으로 쓰이며, 쓰레드 안전함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1730394736344&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; fluid-let 예제
(define x 10)
(fluid-let ([x 20])
  (print x))  ; 20 출력
(print x)     ; 10 출력

;; parameterize 예제
(define current-x (make-parameter 10))
(parameterize ([current-x 20])
  (print (current-x)))  ; 20 출력
(print (current-x))     ; 10 출력&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;code&gt;parameterize&lt;/code&gt;가 현재 Racket의 표준입니다.&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;Racket의 문서를 읽어보면 짐작할 수 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;쓰레드 및 컨티뉴에이션 친화적인 방식으로 코드를 매개변수화하려면 parameterize를 사용하세요. parameterize 형식은 본문 표현의 동적 범위를 위해 새로운 쓰레드 셀을 도입합니다.&lt;br /&gt;새로운 쓰레드가 생성될 때, 새 쓰레드의 초기 컨티뉴에이션에 대한 매개변수화는 생성자 쓰레드의 매개변수화를 따릅니다. 각 매개변수의 쓰레드 셀이 보존되므로, 새 쓰레드는 이를 생성한 스레드의 매개변수 값들을 &quot;상속&quot;받게 됩니다. 컨티뉴에이션이 한 쓰레드에서 다른 쓰레드로 이동할 때, parameterize를 통해 도입된 설정들은 쓰레드과 함께 효과적으로 이동합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Racket에는 Thread local storage의 프리미티브 형태인 쓰레드 셀(Thread cell)이 있음&lt;/li&gt;
&lt;li&gt;새로운 쓰레드가 생기면 현재 매개변수 값들(make-parameter 값들)을 상속받음&lt;/li&gt;
&lt;li&gt;컨티뉴에이션이 다른 쓰레드로 이동할때도 현재 매개변수 값들이 이동&lt;/li&gt;
&lt;/ol&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://jeapostrophe.github.io/2012-07-16-cont-mar-post.html&quot;&gt;Continuation&amp;nbsp;Marks,&amp;nbsp;part&amp;nbsp;I:&amp;nbsp;Dynamic&amp;nbsp;Wind&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://jeapostrophe.github.io/2012-07-25-cont-mar-post.html&quot;&gt;Continuation&amp;nbsp;Marks,&amp;nbsp;part&amp;nbsp;II:&amp;nbsp;Parameters&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://jeapostrophe.github.io/2012-07-30-cont-mar-post.html&quot;&gt;Continuation&amp;nbsp;Marks,&amp;nbsp;part&amp;nbsp;III:&amp;nbsp;Marks&amp;nbsp;themselves&lt;/a&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언어적으로 다이나믹 바인딩을 지원하면 전역변수, 컨텍스트, DI등 다양한 방면에서 커다란 도움이 되는 해법이라 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람들의 편견하에 지나치게 기피되고 있는 기능이 아닐까..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 명시적으로 다이나믹 바인딩을 위한 명시적인 플레이스홀더를 정의하고, Thread safe, 컴파일타임 의존성 체크가 가능하다면 분명 유용하게 쓰일수 있을거라 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든것을 함수의 인수로 명시적으로 넘기자는 주장도 있을 수 있지만,&amp;nbsp;더 이상 리엑트 hooks와 context처럼 쓰이는게 안티패턴은 아니잖아요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Common Lisp - 유연하고 확장가능한 객체지향 시스템&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* Common Lisp의 구현체는 다양하나, 이 글은 &lt;a href=&quot;https://www.sbcl.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SBCL&lt;/a&gt;을 기준으로 하고 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 다양한 객체지향 구현&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;a href=&quot;https://black7375.tistory.com/86&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://black7375.tistory.com/86&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730454602538&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;객체지향 시스템과 패러다임 그리고 철학&quot; data-og-description=&quot;자바스크립트는 왜 프로토타입을 선택했을까 라는 글을 읽고 떠오르는 내용들을 덧붙이거나 정리 해보았습니다. 원글과는 접근법이 좀 다르며, 기획이 아닌 급하게 쓴 글이라 의식의 흐름 사이&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/86&quot; data-og-url=&quot;https://black7375.tistory.com/86&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Sc0Cp/hyXpCBbl6H/Ce6JQXLwy4jd2kMNr1orN0/img.png?width=270&amp;amp;height=177&amp;amp;face=0_0_270_177,https://scrap.kakaocdn.net/dn/pRN6F/hyXpCgQ2sJ/SN3GvchK8ORljXkfRlqFW0/img.png?width=270&amp;amp;height=177&amp;amp;face=0_0_270_177,https://scrap.kakaocdn.net/dn/b5nCKj/hyXpoCX2tz/8n2FDskG3zsnrFV2i648kk/img.jpg?width=1280&amp;amp;height=1807&amp;amp;face=0_0_1280_1807&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/86&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/86&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Sc0Cp/hyXpCBbl6H/Ce6JQXLwy4jd2kMNr1orN0/img.png?width=270&amp;amp;height=177&amp;amp;face=0_0_270_177,https://scrap.kakaocdn.net/dn/pRN6F/hyXpCgQ2sJ/SN3GvchK8ORljXkfRlqFW0/img.png?width=270&amp;amp;height=177&amp;amp;face=0_0_270_177,https://scrap.kakaocdn.net/dn/b5nCKj/hyXpoCX2tz/8n2FDskG3zsnrFV2i648kk/img.jpg?width=1280&amp;amp;height=1807&amp;amp;face=0_0_1280_1807');&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;객체지향 시스템과 패러다임 그리고 철학&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트는 왜 프로토타입을 선택했을까 라는 글을 읽고 떠오르는 내용들을 덧붙이거나 정리 해보았습니다. 원글과는 접근법이 좀 다르며, 기획이 아닌 급하게 쓴 글이라 의식의 흐름 사이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.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;이외에도 interface, trait, protocol, mixin 등의 개념이 객체지향 구현을 위해 쓰입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 미세한 차이는 이 글이 지나치게 길어질테니 간략한 차이만을 다루고, 추후 따로 다룰 수 있도록 하겠습니다. (언젠가?)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Interface: 구현해야 하는 메서드들의 명세&lt;/li&gt;
&lt;li&gt;Trait: 메서드를 재사용할 수 있게 해주는 수평적 재사용 매커니즘 (메서드 명세와 메서드 기본 구현)&lt;/li&gt;
&lt;li&gt;Protocol: 객체가 따라야하는 메서드와 프로퍼티를 정의하는 규약(프로퍼티와 메서드 명세, 메서드 기본 구현)&lt;/li&gt;
&lt;li&gt;Mixin: 재사용 가능한 메서드와 프로퍼티을 정의하는 수평적 재사용(프로퍼티와 메서드 구현)&lt;/li&gt;
&lt;li&gt;Class: 객체를 생성하기 위한 템플릿으로, 프로퍼티와 메서드를 캡슐화(Mixin과 달리 수직적 재사용인 상속 가능)&lt;/li&gt;
&lt;li&gt;Prototype: 객체를 복제하여 새로운 객체를 생성하는 방식의 상속 방식&lt;/li&gt;
&lt;li&gt;CLOS: 다중&amp;nbsp;디스패치와&amp;nbsp;메서드&amp;nbsp;조합을&amp;nbsp;지원하는&amp;nbsp;동적&amp;nbsp;객체&amp;nbsp;시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 아래로 올수록 구체적이고, 동적인 객체지향 구현방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 CLOS(Common Lisp Object System)을 함께 살펴보도록 합시다.&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;3.2 유연한 메서드 시스템&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2.1 확장 가능한 메서드: 클래스 정의를 수정하지 않고 추가&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 간단한 클래스를 만들어 봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1730466202488&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 클래스 구조
(defclass 클래스명 (부모클래스들)
  ((슬롯명1
    :옵션키워드1 값1
    :옵션키워드2 값2
    ...)
   (슬롯명2
    :옵션키워드1 값1
    ...))
 
;; 옵션 키워드
:initarg      ; 초기화 시 사용할 키워드
:accessor     ; getter/setter 함수 자동 생성
:reader       ; getter 함수만 생성
:writer       ; setter 함수만 생성
:initform     ; 초기값 설정
:type         ; 타입 지정
:allocation   ; :class(클래스 변수) 또는 :instance(인스턴스 변수)

;; 메서드 구조
(defmethod 메소드이름 ((변수명 클래스명)) 
  ; 메서드 본문
)&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;pre id=&quot;code_1730466636625&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 클래스 정의
(defclass person ()
  ((name
    :initarg :name
    :accessor person-name)
   (age
    :initarg :age
    :accessor person-age)))

;; 메서드 정의 - 포맷 방식
;; ~A: (Aesthetic) 읽기 좋은 형태로 출력
;; ~D: (Decimal) 십진수로 출력
;; ~%: 줄바꿈
(defmethod display-info ((p person))
  (format t &quot;이름: ~A, 나이: ~D~%&quot; 
          (person-name p) 
          (person-age p)))

;; 사용
(let ((person1 (make-instance 'person :name &quot;John&quot; :age 20)))
  (display-info person1))&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;저 이후에도 메서드를 추가할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730467424674&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(defmethod increase-age ((p person))
  (setf (person-age p) (+ 1 (person-age p))))

;; 다시 사용해보기
(let ((person1 (make-instance 'person :name &quot;John&quot; :age 20)))
  (display-info person1)
  (increase-age person1)
  (display-info person1))&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;클래스를 정의할 때만 메서드를 정의할 수 있는 Java, C++과 달리 그 이후 자유롭게 &lt;b&gt;확장에 열려있다&lt;/b&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;3.2.2 다중 디스패치: 런타임 객체 타입에 따른 함수 사용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 다중 디스패치를 해봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1730479348674&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 클래스 (Person 상속)
(defclass student (person)
  ((grade :initarg :grade :accessor student-grade)))

(defclass teacher (person)
  ((subject :initarg :subject :accessor teacher-subject)))

;; 제네릭 메서드
(defgeneric greet (person1 person2))

;; 다중 디스패치
(defmethod greet ((person1 person) (person2 person))
  (format t &quot;person이 person에게 인사&quot;))
 
(defmethod greet ((person1 teacher) (person2 student))
  (format t &quot;teacher가 student에게 인사&quot;))

 ;; 사용
 (let ((p1 (make-instance 'teacher :name &quot;John&quot; :age 20 :subject &quot;math&quot;))
       (p2 (make-instance 'student :name &quot;Jane&quot; :age 21 :grade 100)))
   (greet p1 p2)) ;; &quot;teacher가 student에게 인사&quot;&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;메서드 오버로딩과 비슷해 보이지만 약간의 차이가 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730480422778&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
	public static void greet(Person a, Person b) {
        System.out.println(&quot;Person이 Person에게 인사&quot;);
    }
    public static void greet(Teacher a, Student b) {
        System.out.println(&quot;Teacher가 Student에게 인사&quot;);
    }

    public static void main(String[] args) {
        Person teacher = new Teacher();
        Person student = new Student();
        greet(teacher, student); // Person이 Person에게 인사
    }
}

class Person {}
class Student extends Person {}
class Teacher extends Person {}&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;다중 디스패치: 런타임의 객체 타입에 따라 결정&lt;/li&gt;
&lt;li&gt;오버로딩: 컴파일 타임의 객체 타입에 따라 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떨때 다중 디스패치가 유용할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &lt;code&gt;student&lt;/code&gt;와 &lt;code&gt;teacher&lt;/code&gt;가 랜덤으로 섞인 리스트에서 각각의 정보들을 앞서 정의한 &lt;code&gt;display-info&lt;/code&gt;로 출력해줄때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;student&lt;/code&gt;는 &lt;code&gt;grade&lt;/code&gt;도 출력을 해주고, &lt;code&gt;teacher&lt;/code&gt;는 &lt;code&gt;subject&lt;/code&gt;를 추가로 출력해주는 것은 어떨까요?&lt;/p&gt;
&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;code&gt;Shape&lt;/code&gt; 객체에 대한 구역 구하기가 쉬워지겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 수치해석쪽은 정수/부동소수이냐, SparseVector/DenseVector이냐등 타입을 판별하는데 드는 시간보다 수행하는 최적화가 크기 때문에 Julia와 같은 언어는 다중 디스패치를 사용한다고 알려져있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730485763740&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 클래스 정의
(defclass circle ()
  ((radius :initarg :radius :accessor circle-radius)))

(defclass rectangle ()
  ((width :initarg :width :accessor rectangle-width)
   (height :initarg :height :accessor rectangle-height)))

(defclass triangle ()
  ((base :initarg :base :accessor triangle-base)
   (height :initarg :height :accessor triangle-height)))

;; 다중 디스패치가 없을경우 (일반함수 조건문)
(defun calculate-area (shape)
  (cond
    ((typep shape 'circle)
     (* pi (expt (circle-radius shape) 2)))
    
    ((typep shape 'rectangle)
     (* (rectangle-width shape)
        (rectangle-height shape)))
    
    ((typep shape 'triangle)
     (/ (* (triangle-base shape)
           (triangle-height shape))
        2))
    
    (t (error &quot;지원하지 않는 도형입니다.&quot;))))


;; 다중 디스패치가 있을경우
(defgeneric calculate-area (shape)
  (:documentation &quot;도형의 면적을 계산합니다.&quot;))

; 각 도형별 메소드 구현
(defmethod calculate-area ((shape circle))
  (* pi (expt (circle-radius shape) 2)))

(defmethod calculate-area ((shape rectangle))
  (* (rectangle-width shape)
     (rectangle-height shape)))

(defmethod calculate-area ((shape triangle))
  (/ (* (triangle-base shape)
        (triangle-height shape))
     2))


;;; 사용 예제
(defun print-areas (shapes)
  (format t &quot;도형 면적 계산 결과:~%&quot;)
  (format t &quot;==================~%&quot;)
  (loop for shape in shapes
        for i from 1
        do (format t &quot;~A. ~A의 면적: ~,2f~%&quot; 
                   i
                   (class-name (class-of shape))
                   (calculate-area shape)))
  (format t &quot;==================~%&quot;))

(print-areas(list
             (make-instance 'circle :radius 5)
             (make-instance 'rectangle :width 4 :height 6)
             (make-instance 'triangle :base 3 :height 4)
             (make-instance 'circle :radius 3)
             (make-instance 'rectangle :width 2 :height 8)))
;;; 결과
; 도형 면적 계산 결과:
; ==================
; 1. CIRCLE의 면적: 78.54
; 2. RECTANGLE의 면적: 24.00
; 3. TRIANGLE의 면적: 6.00
; 4. CIRCLE의 면적: 28.27
; 5. RECTANGLE의 면적: 16.00
; ==================&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;다음 형태라 생각해보세요.&lt;/p&gt;
&lt;pre id=&quot;code_1730484156563&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 다중 디스패치가 없을경우
type Shape = 
  | { kind: &quot;circle&quot;; radius: number }
  | { kind: &quot;rectangle&quot;; width: number; height: number }
  | { kind: &quot;triangle&quot;; base: number; height: number };

function calculateArea(shape: Shape): number {
  switch (shape.kind) {
    case &quot;circle&quot;:
      return Math.PI * shape.radius ** 2;
    case &quot;rectangle&quot;:
      return shape.width * shape.height;
    case &quot;triangle&quot;:
      return (shape.base * shape.height) / 2;
  }
}

// 다중 디스패치가 있을경우
type Shape = Circle | Rectange | Triangle;
type Circle = { radius: number };
type Rectangle = { width: number; height: number };
type Triangle = { base: number; height: number };

function calculateArea(shape: Circle): number {
  return Math.PI * shape.radius ** 2;
}
function calculateArea(shape: Rectange): number {
  return shape.width * shape.height;
}
function calculateArea(shape: Triangle): number {
  return (shape.base * shape.height) / 2;
}&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;혼동이 올수도 있으므로 가능하다면 Switch나 패턴매칭을 우선적으로 사용하는게 좋을테지만,&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;h4 data-ke-size=&quot;size20&quot;&gt;3.2.3 메서드 조합: 횡단 관심사 제어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드 조합(Method combination)은 &lt;a href=&quot;https://en.wikipedia.org/wiki/Aspect-oriented_programming&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AOP(Aspect-oriented programing)&lt;/a&gt;에서 쓰이던 before, after, around가 메서드에 적용되는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/twatA/btsKuWkmpMW/P3s2Aj5fD42Ws5SOcPRIFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/twatA/btsKuWkmpMW/P3s2Aj5fD42Ws5SOcPRIFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/twatA/btsKuWkmpMW/P3s2Aj5fD42Ws5SOcPRIFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtwatA%2FbtsKuWkmpMW%2FP3s2Aj5fD42Ws5SOcPRIFK%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;600&quot; height=&quot;463&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;463&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;예를 들어 다음 코드는 &quot;계산 중...&quot;의 앞 뒤로 시작과 완료 메세지가 뜨게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1730488115407&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 메소드 결합
(defmethod calculate-area :before ((shape t))
  (format t &quot;면적 계산을 시작합니다.~%&quot;))

(defmethod calculate-area :after ((shape t))
  (format t &quot;면적 계산이 완료되었습니다.~%&quot;))

;; 메소드 재정의
(defmethod calculate-area ((shape circle))
  (format t &quot;계산 중...~%&quot;)
  (* pi (expt (circle-radius shape) 2)))

;; 사용
(calculate-area (make-instance 'circle :radius 5))&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;AOP와 마찬가지로 &lt;b&gt;횡단 관심사(Cross-cutting concerns)&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;3.3 동적인 객체&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 장점이라 보기에는 힘들지만, 프로토타입과 마찬가지로 인터프리터 언어의 특성이라고도 생각할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 프로토타입 언어도 메서드를 CLOS처럼 동적으로 추가가능하며, 프로퍼티나 생성자 역시 동적으로 추가/변경할 수 있죠.&lt;/p&gt;
&lt;pre id=&quot;code_1730469428118&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 프로토타입 생성자
function Person(name, age) {
  this.name = name;
  this.age = age;
}

// 프로토타입에 메서드 추가
Person.prototype.greet = function() {
  console.log(`Hello, ${this.name}!`);
};

// 인스턴스 생성
const person1 = new Person(&quot;John&quot;, 30);
const person2 = new Person(&quot;Jane&quot;, 25);

// 2. 동적 속성 추가 방법들
// 2.1 특정 인스턴스에만 속성 추가
person1.address = &quot;Seoul&quot;;
console.log(person1.address); // &quot;Seoul&quot;
console.log(person2.address); // undefined

// 2.2 프로토타입에 속성 추가 (모든 인스턴스에 영향)
Person.prototype.address = &quot;Default Address&quot;;
const person3 = new Person(&quot;Bob&quot;, 35);
console.log(person2.address); // &quot;Default Address&quot;
console.log(person3.address); // &quot;Default Address&quot;

// 2.3 생성자 함수 수정
function Person(name, age, address) {
  this.name = name;
  this.age = age;
  this.address = address;
}

// 새로운 인스턴스는 수정된 생성자 사용
const person4 = new Person(&quot;Alice&quot;, 28, &quot;Busan&quot;);&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;CLOS 역시 앞선 Javascript처럼 프로퍼티(슬롯)을 추가 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 엄연히 객체에 기반한 프로토타입 체인을 수정하는 자바스크립트에 비해 정의 자체를 재정의할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1730471757898&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(defvar person1 (make-instance 'person :name &quot;John&quot; :age 20))

;; 클래스 재정의
(defclass person ()
  ((name :initarg :name
         :accessor person-name)
   (age :initarg :age
        :accessor person-age)
   (address :initarg :address
            :accessor person-address
            :initform &quot;Default Address&quot;)))

;; 메서드 재정의
(defmethod display-info ((p person))
  (format t &quot;이름: ~A, 나이: ~D, 주소: ~A~%&quot; 
          (person-name p) 
          (person-age p)
          (person-address p)))

(person-address person1) ;; Default Address
(display-info person1)&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;code&gt;address&lt;/code&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;어찌되었건 CLOS는 클래스의 확장이기 때문에, 이미 인스턴스의 프로퍼티가 초기화되어 이전에 있던 값을 반환합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730521317992&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; address의 기본 값을 변경
(defclass person ()
  ((name :initarg :name
         :accessor person-name)
   (age :initarg :age
        :accessor person-age)
   (address :initarg :address
            :accessor person-address
            :initform &quot;Other Default Address&quot;)))

(person-address person1) ;; 하지만 &quot;Default Address&quot;&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;마이그레이션&lt;/b&gt;을 해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 사용하던 &lt;code&gt;&quot;Default Address&quot;&lt;/code&gt;만 새로운 것으로 변경해봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1730522396924&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 인스턴스 마이그레이션
(defmethod update-instance-for-redefined-class :after
    ((instance person) 
     added-slots 
     discarded-slots 
     property-list
     &amp;amp;rest initargs)
  (when (equal (person-address instance) &quot;Default Address&quot;)
    (setf (person-address instance) &quot;Other Default Address&quot;)))

(make-instances-obsolete 'person)

;; 체크해보기
(person-address person1)
(display-info person1)&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;&lt;code&gt;fmakunbound&lt;/code&gt;를 통해 일괄적으로 제거할 수도 있고, &lt;code&gt;remove-method&lt;/code&gt;를 통해 특정 메서드만 선택해 제거할 수도 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730523443869&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 모든 메서드 일괄 삭제
(fmakunbound 'display-info)

;; calculate-area의 :after로 나오는 로그 메서드 제거
(remove-method #'calculate-area
              (find-method #'calculate-area '(:after) (list (find-class 't))))

;; calculate-area의 circle 메서드 제거
(remove-method #'calculate-area
              (find-method #'calculate-area '() (list (find-class 'circle))))&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;3.4 MOP(Meta-Object Protocol)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Metaobject#Metaobject_protocol&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MOP&lt;/a&gt;는 객체&amp;nbsp;지향&amp;nbsp;시스템의&amp;nbsp;구현을&amp;nbsp;사용자가&amp;nbsp;확장할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;해주는&amp;nbsp;인터페이스입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python의 metaclass와 비슷하지만 더 강력합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 metaclass가 생성 시점의 동작에 대해서 제어를 한다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MOP는 클래스&amp;nbsp;정의,&amp;nbsp;슬롯&amp;nbsp;접근,&amp;nbsp;메소드&amp;nbsp;디스패치&amp;nbsp;등&amp;nbsp;거의&amp;nbsp;모든&amp;nbsp;부분에서 확장&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;code&gt;standard-class&lt;/code&gt; 입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730529953084&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(class-of person1) ;; #&amp;lt;STANDARD-CLASS #:PERSON&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;/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;h4 data-ke-size=&quot;size20&quot;&gt;3.4.1 인스턴스 카운터: 생성시 상태제어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스가 생길때 &lt;code&gt;counter&lt;/code&gt;가 증가하도록 만들어봤어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 기능은 로그를 남길때 딱이겠죠?&lt;/p&gt;
&lt;pre id=&quot;code_1730531067186&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 1. 에러를 피하기 위해서..
;; MOP 관련 패키지를 import함 - 추후 sb-mop:validate-superclass 와 같이 네임스페이스를 지정하지 않기위해
; https://koji-kojiro.github.io/sb-docs/build/html/sb-mop/
(use-package :sb-mop)

;; Meta class를 변경하기 위한 class의 symbol 제거
; https://stackoverflow.com/questions/38811931/how-to-change-classs-metaclass#38812140
(unintern 'person)

;; 2. 메타 클래스 정의
(defclass counted-class (standard-class)
  ((counter :initform 0)))

(defmethod make-instance :after ((class counted-class) &amp;amp;rest initargs)
  (declare (ignore initargs))
  (incf (slot-value class 'counter)))

(defmethod get-instance-count ((class counted-class))
  (slot-value class 'counter))

; 메타 클래스끼리 호환이 되는지 여부 - 필수로 구현요구
; true면 상속, false면 상속 금지
(defmethod validate-superclass ((class counted-class)
                                (superclass standard-class))
  t)

;; 3. 클래스 재정의
(defclass person ()
  ((name :initarg :name
         :accessor person-name)
   (age :initarg :age
        :accessor person-age)
   (address :initarg :address
            :accessor person-address
            :initform &quot;Default Address&quot;))
  (:metaclass counted-class))

;; 4. 사용
(get-instance-count (find-class 'person)) ;; 0
(make-instance 'person :name &quot;Jane&quot; :age 21)
(get-instance-count (find-class 'person)) ;; 1&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;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.4.2 타입 검사기: 기존 기능 확장&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Common Lisp에는 분명 타입 선언을 할 수 있지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 타입힌트처럼 런타임에서 무시하고 실행됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730536126289&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 재정의
(unintern 'person)

(defclass person ()
  ((name :type string
         :initarg :name
         :accessor person-name)
   (age :type integer
        :initarg :age
        :accessor person-age)))

;; 실행
(make-instance 'person :name 1 :age &quot;John&quot;) ;; 잘못된 타입이지만 성공적으로 실행됨&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;369&quot; data-origin-height=&quot;172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biEYJW/btsKuRjlHkc/ngc9kQwwdsHPvF8aoOKjZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biEYJW/btsKuRjlHkc/ngc9kQwwdsHPvF8aoOKjZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biEYJW/btsKuRjlHkc/ngc9kQwwdsHPvF8aoOKjZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiEYJW%2FbtsKuRjlHkc%2Fngc9kQwwdsHPvF8aoOKjZk%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;369&quot; height=&quot;172&quot; data-origin-width=&quot;369&quot; data-origin-height=&quot;172&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;Common Lisp의 타입명시는 최적화를 위해서 존재하기 때문이다. (Python은 IDE와 문서화 역할이 더 큼)&lt;/p&gt;
&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;메타 클래스를 이용해서 set 하기 전에 검사를 하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730536572141&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 메타 클래스 정의
(defclass type-checking-class (standard-class)
  ())

(defmethod validate-superclass ((class type-checking-class)
                              (superclass standard-class))
  t)

(defmethod (setf slot-value-using-class) :before
           (new-value
            (class type-checking-class)
            instance
            slot)
  (let ((type (slot-definition-type slot)))
    (when type  ; type이 지정된 경우에만 검증
      (unless (typep new-value type)
        (error &quot;Value ~S is not of type ~S&quot; new-value type)))))


;; 클래스 재정의
(unintern 'person)
(defclass person ()
  ((name :type string
         :initarg :name
         :accessor person-name)
   (age :type integer
        :initarg :age
        :accessor person-age))
  (:metaclass type-checking-class))

;; 실행
(make-instance 'person :name 1 :age &quot;John&quot;) ;; 에러!!
(defvar person1 (make-instance 'person :name &quot;John&quot; :age 20)) ;; 성공
(setf (person-age person1) 21) ;; 성공
(setf (person-age person1) &quot;22&quot;) ;; 에러!!&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;560&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtZ8wO/btsKuzb9Rnh/8NLEM3rjxy1jBzK6VTriOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtZ8wO/btsKuzb9Rnh/8NLEM3rjxy1jBzK6VTriOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtZ8wO/btsKuzb9Rnh/8NLEM3rjxy1jBzK6VTriOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtZ8wO%2FbtsKuzb9Rnh%2F8NLEM3rjxy1jBzK6VTriOk%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;614&quot; height=&quot;560&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;560&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://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Proxy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Proxy&lt;/a&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;3.4.3 값 검증하기: 클래스 정의시 키워드 추가&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 타입을 넘어 defclass를 할때 검증하는 함수를 넣어봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;:validator&lt;/code&gt; 에 함수를 사용해 검증할 수 있도록 할거에요.&lt;/p&gt;
&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;code&gt;direct-slot&lt;/code&gt;이라 부르고요,&lt;/p&gt;
&lt;pre id=&quot;code_1730545617653&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(defclass person ()
  ((name :initarg :name)    ; 직접 슬롯
   (age :initarg :age)))    ; 직접 슬롯&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;code&gt;effective-slot&lt;/code&gt;이라 불러요.&lt;/p&gt;
&lt;pre id=&quot;code_1730545705899&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(defclass animal ()
  ((name :initarg :name)))

(defclass dog (animal)
  ((breed :initarg :breed)))

;; dog 클래스의 유효 슬롯:
;; - name (animal로부터 상속)
;; - breed (직접 정의)&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도는 흑마법이라 어쩔수가 없어요 ㅠㅠ&lt;/p&gt;
&lt;pre id=&quot;code_1730544575901&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 클래스 정의
(defclass validated-class (standard-class)
  ())

(defclass validated-slot-definition (standard-slot-definition)
  ((validator :initarg :validator :initform nil 
              :accessor slot-validator)))

(defclass validated-direct-slot-definition 
  (validated-slot-definition standard-direct-slot-definition) ())

(defclass validated-effective-slot-definition 
  (validated-slot-definition standard-effective-slot-definition) ())

;; 검증 함수
(defun validate-slot (value validator slot-name)
  (when (and validator 
             (not (funcall (if (functionp validator)
                               validator
                               (coerce validator 'function))
                           value)))
    (error &quot;Validation failed for slot ~A with value ~A&quot; slot-name value)))

;; 메타클래스 메소드들
(defmethod validate-superclass ((class validated-class)
                                (superclass standard-class))
  t)

(defmethod direct-slot-definition-class ((class validated-class) &amp;amp;rest initargs)
  (declare (ignore initargs))
  (find-class 'validated-direct-slot-definition))

(defmethod effective-slot-definition-class ((class validated-class) &amp;amp;rest args)
  (declare (ignore args))
  (find-class 'validated-effective-slot-definition))

(defmethod compute-effective-slot-definition ((class validated-class) name direct-slots)
  (let* ((effective-slot (call-next-method))
         (validator (and (first direct-slots)
                         (slot-validator (first direct-slots)))))
    (when validator
      (setf (slot-validator effective-slot) validator))
    effective-slot))

(defmethod (setf slot-value-using-class) :before
  (new-value (class validated-class) object (slot validated-effective-slot-definition))
  (validate-slot new-value 
                 (slot-validator slot)
                 (slot-definition-name slot)))

(defmethod shared-initialize :after ((instance standard-object) slot-names &amp;amp;rest args)
  (declare (ignore args slot-names))
  (when (typep (class-of instance) 'validated-class)
    (dolist (slot (class-slots (class-of instance)))
            (when (slot-boundp instance (slot-definition-name slot))
              (validate-slot (slot-value instance (slot-definition-name slot))
                             (slot-validator slot)
                             (slot-definition-name slot))))))

;; 클래스 재정의
(unintern 'person)
(defclass person ()
  ((name :initarg :name
         :accessor person-name
         :validator (lambda (x) (and (stringp x) (&amp;gt; (length x) 5))))
   (age :initarg :age
        :accessor person-age
        :validator (lambda (x) (and (numberp x) (&amp;gt; x 5)))))
  (:metaclass validated-class))

;; 실행
(make-instance 'person :name &quot;John Doe&quot; :age 20) ;; 성공
(make-instance 'person :name &quot;John&quot; :age 20) ;; 실패
(make-instance 'person :name &quot;John Doe&quot; :age 3) ;; 실패&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;
&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;:validator에 있는 검증 로직이 줄어들 것 같네요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;구현은 간단하게 다중 상속을 하면 해결됩니다?!&lt;/p&gt;
&lt;pre id=&quot;code_1730564297318&quot; class=&quot;hy&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;;; 결합된 메타클래스 정의
(defclass type-and-validated-class (type-checking-class validated-class)
  ())

;; 상위클래스 검증
(defmethod validate-superclass ((class type-and-validated-class)
                              (superclass standard-class))
  t)

;; 클래스 재정의
(unintern 'person)
(defclass person ()
  ((name :type string
         :initarg :name
         :accessor person-name
         :validator (lambda (x) (&amp;gt; (length x) 5)))
   (age :type integer
        :initarg :age
        :accessor person-age
        :validator (lambda (x) (&amp;gt; x 5))))
  (:metaclass type-and-validated-class))&lt;/code&gt;&lt;/pre&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 data-ke-size=&quot;size16&quot;&gt;이외에도 MOP를 잘 활용하면 각종 로깅, 캐싱은 물론 완전한 AOP 구현에도 쓰일수 있겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MOP는 단순한 리플렉션을 넘어 &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;3.5 다중상속&lt;/h3&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;사실 이런 문제들 때문에 저는 Trait이나 Protocol 방식을 좋아하나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 만약 Java나 C++과 같은 Class 방식을 써야 한다면 차라리 CLOS방식이 낫지 않나..&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;span style=&quot;letter-spacing: 0px;&quot;&gt;3.5.1 C++의 다중상속 문제&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;C++의 다중상속은 엉망이기로 유명합니다.&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;예를 들어 유명한 다이아몬드 상속을 생각해봅시다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730567836933&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {};
class B: public A {};
class C: public A {};
class D: public B, public C {};

int main()
{
    D d{};
    return 0;
}&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;letter-spacing: 0px;&quot;&gt;우리는 다이어몬드 모양으로 상속이 될거라 생각하지만, 실제모양은 오른쪽과 같습니다. [&lt;a href=&quot;https://velog.io/@soongle/c-%EB%8B%A4%EC%9D%B4%EC%95%84%EB%AA%AC%EB%93%9C-%EC%83%81%EC%86%8Ddiamond-inheritance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;그림출처&lt;/a&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;1280&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MtJo4/btsKuPMH7zb/GHxrRoGElRlIzkhKR0Epc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MtJo4/btsKuPMH7zb/GHxrRoGElRlIzkhKR0Epc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MtJo4/btsKuPMH7zb/GHxrRoGElRlIzkhKR0Epc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMtJo4%2FbtsKuPMH7zb%2FGHxrRoGElRlIzkhKR0Epc0%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;1280&quot; height=&quot;644&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;644&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;pre id=&quot;code_1730571533744&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

class A {
public:
    A() { std::cout &amp;lt;&amp;lt; &quot;A constructor&quot; &amp;lt;&amp;lt; std::endl; }
};

class B : public A {
public:
    B() { std::cout &amp;lt;&amp;lt; &quot;B constructor&quot; &amp;lt;&amp;lt; std::endl; }
};

class C : public A {
public:
    C() { std::cout &amp;lt;&amp;lt; &quot;C constructor&quot; &amp;lt;&amp;lt; std::endl; }
};

class D : public B, public C {
public:
    D() { std::cout &amp;lt;&amp;lt; &quot;D constructor&quot; &amp;lt;&amp;lt; std::endl; }
};

int main() {
    D d{};
    return 0;
}

/* 결과
A constructor
B constructor
A constructor
C constructor
D constructor
*/&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;letter-spacing: 0px;&quot;&gt;그래서 앞선 코드는 컴파일이 되었겠지만 실제로 메서드를 사용해보면,&lt;/span&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;span style=&quot;letter-spacing: 0px;&quot;&gt;보다 쉽게 문제를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730568882798&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

class A {
public:
    void foo() { std::cout &amp;lt;&amp;lt; &quot;Message&quot; &amp;lt;&amp;lt; std::endl; }
};
class B: public A {};
class C: public A {};
class D: public B, public C {};

int main()
{
    D d{};
    d.foo(); // 에러: request for member &amp;lsquo;foo&amp;rsquo; is ambiguous
    d.A::foo(); // 에러: &amp;lsquo;A&amp;rsquo; is an ambiguous base of &amp;lsquo;D&amp;rsquo;
    d.B::foo(); // 가능
    d.C::foo(); // 가능
    return 0;
}&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;letter-spacing: 0px;&quot;&gt;이는 &lt;code&gt;A&lt;/code&gt;의 인스턴스를 하나만 쓰게 하면 해결됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;code&gt;B&lt;/code&gt;와 &lt;code&gt;C&lt;/code&gt;에서 &lt;code&gt;A&lt;/code&gt;를 가상 상속하게 되면 말이지요.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730569696381&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {
public:
    void foo() { std::cout &amp;lt;&amp;lt; &quot;Message&quot; &amp;lt;&amp;lt; std::endl; }
};
class B: virtual public A {};
class C: virtual public A {};
class D: public B, public C {};


int main()
{
    D d{};
    d.foo();
    d.A::foo();
    d.B::foo();
    d.C::foo();
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 예제에 &lt;code&gt;virtual&lt;/code&gt;을 붙여 테스트해보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;A&lt;/code&gt; 클래스가 한번만 생성될 겁니다.&lt;/p&gt;
&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;이게 끝이었다면 말을 꺼내지 않았을 겁니다.&lt;/span&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;pre id=&quot;code_1730570152019&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {
public:
    void foo() { std::cout &amp;lt;&amp;lt; &quot;Message1&quot; &amp;lt;&amp;lt; std::endl; }
};
class B: virtual public A {
public:
    void foo() { std::cout &amp;lt;&amp;lt; &quot;Message2&quot; &amp;lt;&amp;lt; std::endl; }
};
class C: virtual public A {
public:
    void foo() { std::cout &amp;lt;&amp;lt; &quot;Message3&quot; &amp;lt;&amp;lt; std::endl; }
};
class D: public B, public C {};


int main()
{
    D d{};
    d.foo(); // 에러!!
    d.A::foo(); // Message1 출력
    d.B::foo(); // Message2 출력
    d.C::foo(); // Message3 출력
    return 0;
}&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;pre id=&quot;code_1730570651296&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class D: public B, public C {
public:
    void foo() { B::foo(); }
};&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;이외에도 C++에서 다중상속은 초기화 및 생성자/소멸자 순서 같은 관리의 모호함과 메모리 레이아웃, 가상상속 오버헤드등의 성능 문제들이 일어나기로 유명합니다.&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;span style=&quot;letter-spacing: 0px;&quot;&gt;3.5.2 CPL(Class Precedence List) 규칙&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히도 Common Lisp에서는 CPL(Class Precedence List)이란 규칙을 사용해 &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;그래서 MOP에서는 타입과 검증을 함께 적용할 수 있었죠.&lt;/p&gt;
&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;code&gt;type-and-validated-class&lt;/code&gt; -&amp;gt; &lt;code&gt;type-checking-class&lt;/code&gt; -&amp;gt; &lt;code&gt;validated-class&lt;/code&gt; ...순으로 적용된 것을 볼 수 있지요.&lt;/p&gt;
&lt;pre id=&quot;code_1730571077008&quot; class=&quot;stata&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;(compute-class-precedence-list (find-class 'type-and-validated-class))

;; 결과
(#&amp;lt;STANDARD-CLASS COMMON-LISP-USER::TYPE-AND-VALIDATED-CLASS&amp;gt;
 #&amp;lt;STANDARD-CLASS COMMON-LISP-USER::TYPE-CHECKING-CLASS&amp;gt;
 #&amp;lt;STANDARD-CLASS COMMON-LISP-USER::VALIDATED-CLASS&amp;gt;
 #&amp;lt;STANDARD-CLASS COMMON-LISP:STANDARD-CLASS&amp;gt;
 #&amp;lt;STANDARD-CLASS SB-PCL::STD-CLASS&amp;gt; #&amp;lt;STANDARD-CLASS SB-PCL::SLOT-CLASS&amp;gt;
 #&amp;lt;STANDARD-CLASS SB-PCL::PCL-CLASS&amp;gt; #&amp;lt;STANDARD-CLASS COMMON-LISP:CLASS&amp;gt;
 #&amp;lt;STANDARD-CLASS SB-PCL::DEPENDENT-UPDATE-MIXIN&amp;gt;
 #&amp;lt;STANDARD-CLASS SB-PCL::PLIST-MIXIN&amp;gt;
 #&amp;lt;STANDARD-CLASS SB-PCL::DEFINITION-SOURCE-MIXIN&amp;gt;
 #&amp;lt;STANDARD-CLASS SB-PCL::STANDARD-SPECIALIZER&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;CPL 규칙은&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/C3_linearization&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;C3 선형화&lt;/a&gt; 알고리즘이므로 파이썬의 MRO(Method Resolution Order)와 거의 동일합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;nbsp;클래스 자신이 가장 먼저&lt;/li&gt;
&lt;li&gt;왼쪽에서 오른쪽으로 선언된 부모 순서&lt;/li&gt;
&lt;li&gt;공통 조상은 한 번만 나타남 [&lt;a href=&quot;https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node274.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;위상 정렬(Topological&amp;nbsp;Sorting)&lt;/a&gt;을 사용함]&lt;/li&gt;
&lt;li&gt;&lt;code&gt;standard-object&lt;/code&gt;와 &lt;code&gt;t&lt;/code&gt;는 항상 마지막 [메타 클래스가 아닌 일반 클래스 기준]&lt;/li&gt;
&lt;/ol&gt;
&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_1730548845970&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 리스트대로 보여주기
(defun print-cpl (class-name)
  (format t &quot;CPL for ~A: ~A~%&quot; 
          class-name 
          (mapcar #'class-name 
                  (compute-class-precedence-list
                   (find-class class-name)))))

;; 다이아몬드 상속
(defclass A () ())
(defclass B (A) ())
(defclass C (A) ())
(defclass D (B C) ())

;; 결과
(print-cpl 'D)
; CPL for D: (D B C A STANDARD-OBJECT SLOT-OBJECT T)&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;CPL 대로라면 메서드를 선언했을때 &lt;code&gt;D&lt;/code&gt;에 없을 경우 &lt;code&gt;B&lt;/code&gt;의 메서드가 실행될테죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한번 실험해봅시다!!&lt;/p&gt;
&lt;pre id=&quot;code_1730572966062&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 메소드 선언
(defgeneric foo (obj))

(defmethod foo ((obj A))
  (format t &quot;Message1~%&quot;))
(defmethod foo ((obj B))
  (format t &quot;Message2~%&quot;))
(defmethod foo ((obj C))
  (format t &quot;Message3~%&quot;))

;; 예시
(let ((d1 (make-instance 'D)))
  (foo d1)                    ; Message2
  (foo (change-class d1 'A))  ; Message1
  (foo (change-class d1 'B))  ; Message2
  (foo (change-class d1 'C))) ; Message3&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;그리고 CPL로 더 복잡한 경우도 잘 다루는 모습도 확인 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1730549638631&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(defclass A () ())
(defclass B () ())
(defclass C () ())
(defclass D (A B) ())
(defclass E (B C) ())
(defclass F (D E) ())

; 결과
(print-cpl 'F)
; CPL for F: (F D A E B C STANDARD-OBJECT SLOT-OBJECT T)&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;pre id=&quot;code_1730550004752&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;;; 교차 상속
(defclass A () ())
(defclass B () ())
(defclass C (A B) ()) ; C는 A &amp;gt; B 순서를 요구
(defclass D (B A) ()) ; D는 B &amp;gt; A 순서를 요구
(defclass E (C D) ()) ; 모순 발생!


;; 에러
;  While computing the class precedence list of the class named COMMON-LISP-USER::E.
; It is not possible to compute the class precedence list because
; there is a circularity in the local precedence relations.
; This arises because:
;   The class named COMMON-LISP-USER::A follows the class named COMMON-LISP-USER::B in the supers of the class named COMMON-LISP-USER::D.
;   The class named COMMON-LISP-USER::B follows the class named COMMON-LISP-USER::A in the supers of the class named COMMON-LISP-USER::C..


;; 시각화
; E
; ├─ C
; │  ├─ A ──┐
; │  └─ B &amp;lt;─┤
; └─ D      │
;    ├─ B ──┤
;    └─ A &amp;lt;─┘
;
; 순환 발생: A &amp;gt; B &amp;gt; A&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLOS의 상속 시스템이 완전히 마음에 드는 것은 아니지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다중 상속이 필요하다면 적어도 C++의 다중 상속방식보다 나은 것으로 보입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Lisp가 강력하다는 의미를 체감했으리라 믿는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Homoiconicity말고도 안전하면서 쉬운 패턴매칭 매크로, 다양한 용도를 제공하는 동적 스코프, 객체지향 시스템 자체를 확장하는 CLOS 모두 메타적이고, 동적이고, 유연하게 만들어주는 리스프 특징을 잘 보여준다고 생각한다.&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;CLOS는 상당히 호불호가 갈릴수 있겠지만 나머지는 안전하면서도 다양한 활용법을 제공해주기 때문에 다른 언어들에서도 많이 참고했으면.&lt;/p&gt;</description>
      <category>프로그래밍/설계</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/98</guid>
      <comments>https://black7375.tistory.com/98#entry98comment</comments>
      <pubDate>Sun, 3 Nov 2024 13:32:20 +0900</pubDate>
    </item>
    <item>
      <title>프롬프트, 프로그래밍처럼 생각하기</title>
      <link>https://black7375.tistory.com/97</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;최근 2주간 프롬프트 엔지니어링을 하면서 얻은 인사이트를 공유해보자 한다.&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;내 결론은 프롬프트 엔지니어링은 프로그래밍처럼 접근 가능하다이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 언어&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM은 자연어를 기반으로 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;937&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/elFJwe/btsEEKSAwxV/PeaeGDVGPSiYvB3qzIYm6k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/elFJwe/btsEEKSAwxV/PeaeGDVGPSiYvB3qzIYm6k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/elFJwe/btsEEKSAwxV/PeaeGDVGPSiYvB3qzIYm6k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FelFJwe%2FbtsEEKSAwxV%2FPeaeGDVGPSiYvB3qzIYm6k%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;1200&quot; height=&quot;878&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;937&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;직관적이고 풍부한 표현과 어휘를 모두 활용할 수 있지만, 상대적으로 모호한 편.&lt;/p&gt;
&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;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;나중에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #0070d1; text-align: left;&quot; href=&quot;https://ko.wikipedia.org/wiki/%EB%A1%9C%EC%A7%80%EB%B0%98&quot;&gt;로지반&lt;/a&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 AI 전용 언어가 등장해도 재밌지 않을까 싶긴하다 ㅋㅋ&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 컴퓨터 구조 / OS&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수많은 언어를 알아들으며 마치 Babel Fish 같은 LLM!!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwXEX1/btsEE1GvCkD/OAfwwj77CMREptbWwPzsp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwXEX1/btsEE1GvCkD/OAfwwj77CMREptbWwPzsp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwXEX1/btsEE1GvCkD/OAfwwj77CMREptbWwPzsp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwXEX1%2FbtsEE1GvCkD%2FOAfwwj77CMREptbWwPzsp1%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;1000&quot; height=&quot;750&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;750&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hitchhikersguidetoearth.fandom.com/wiki/Babel_Fish&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Babel Fish&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;각종 하이퍼파라미터나 파인튜닝을 다룰려면 LLM이나 Transformer 구조에 대해 기본적인 이해를 하고 있으면 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TYxbx/btsEEDTAxxv/oAcKvzbii36Xow3sBpqjjK/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TYxbx/btsEEDTAxxv/oAcKvzbii36Xow3sBpqjjK/tfile.svg&quot; data-origin-width=&quot;1790&quot; data-origin-height=&quot;686&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.143%; margin-right: 10px;&quot; data-widthpercent=&quot;53.77&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TYxbx/btsEEDTAxxv/oAcKvzbii36Xow3sBpqjjK/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTYxbx%2FbtsEEDTAxxv%2FoAcKvzbii36Xow3sBpqjjK%2Ftfile.svg&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;1790&quot; height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v8WMK/btsEFd06aFg/in3qVXJhKauGPK1qkWseX0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v8WMK/btsEFd06aFg/in3qVXJhKauGPK1qkWseX0/img.jpg&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;312&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.6942%;&quot; data-widthpercent=&quot;46.23&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v8WMK/btsEFd06aFg/in3qVXJhKauGPK1qkWseX0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv8WMK%2FbtsEFd06aFg%2Fin3qVXJhKauGPK1qkWseX0%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;700&quot; height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://huggingface.co/learn/nlp-course/ko/chapter1/4?fw=pt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;트랜스포머는 어떻게 동작하나요?&lt;/a&gt; / &lt;a href=&quot;https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS1555203008&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;챗GPT는&amp;nbsp;어떻게&amp;nbsp;사람이&amp;nbsp;쓴&amp;nbsp;듯한&amp;nbsp;글을&amp;nbsp;자동으로&amp;nbsp;생성해낼까요?&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;예를 들어 Temperature는 출력 분포에 대한 것이며, TopP나 TopK는 조건을 만족하는 상위 N개에서 고르는 식으로 작동한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czTFfd/btsEHp7m9xF/fsoajzmsL99htZtHXq5Kq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czTFfd/btsEHp7m9xF/fsoajzmsL99htZtHXq5Kq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czTFfd/btsEHp7m9xF/fsoajzmsL99htZtHXq5Kq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczTFfd%2FbtsEHp7m9xF%2FfsoajzmsL99htZtHXq5Kq1%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;941&quot; height=&quot;200&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://huggingface.co/blog/how-to-generate#sampling&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;to&amp;nbsp;generate&amp;nbsp;text:&amp;nbsp;using&amp;nbsp;different&amp;nbsp;decoding&amp;nbsp;methods&amp;nbsp;for&amp;nbsp;language&amp;nbsp;generation&amp;nbsp;with&amp;nbsp;Transformers&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;컴퓨터에서 1 Word가 데이터 처리의 크기라면, LLM은 &lt;a href=&quot;https://platform.openai.com/tokenizer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;토큰 단위&lt;/a&gt;이며, &lt;a href=&quot;https://openai.com/pricing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;과금&lt;/a&gt;도 input과 output 토큰 단위로 이루어진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pADXO/btsEMYH19HG/Rio6Bk7T1RqBaKWKkSxcTK/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pADXO/btsEMYH19HG/Rio6Bk7T1RqBaKWKkSxcTK/tfile.svg&quot; data-origin-width=&quot;1816&quot; data-origin-height=&quot;1135&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.8572%; margin-right: 10px;&quot; data-widthpercent=&quot;49.43&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pADXO/btsEMYH19HG/Rio6Bk7T1RqBaKWKkSxcTK/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpADXO%2FbtsEMYH19HG%2FRio6Bk7T1RqBaKWKkSxcTK%2Ftfile.svg&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;1816&quot; height=&quot;1135&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p2pXQ/btsEFey6Cvi/wrvNcEjRr4V2HrVWwPX1Sk/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p2pXQ/btsEFey6Cvi/wrvNcEjRr4V2HrVWwPX1Sk/tfile.svg&quot; data-origin-width=&quot;1825&quot; data-origin-height=&quot;1115&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.98%;&quot; data-widthpercent=&quot;50.57&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p2pXQ/btsEFey6Cvi/wrvNcEjRr4V2HrVWwPX1Sk/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp2pXQ%2FbtsEFey6Cvi%2FwrvNcEjRr4V2HrVWwPX1Sk%2Ftfile.svg&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;1825&quot; height=&quot;1115&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;RAM과 같이 작업 메모리에 한계가 존재하며, 보통 컨텍스트 윈도우(Context Window)라고 부른다.&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;700&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHmSpu/btsEFj1nSXo/dNpeP8kjepaKoXM0DToSKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHmSpu/btsEFj1nSXo/dNpeP8kjepaKoXM0DToSKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHmSpu/btsEFj1nSXo/dNpeP8kjepaKoXM0DToSKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHmSpu%2FbtsEFj1nSXo%2FdNpeP8kjepaKoXM0DToSKk%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;700&quot; height=&quot;450&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;449&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ai.plainenglish.io/context-window-size-and-language-model-performance-balancing-act-2ae2964e3ec1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Context&amp;nbsp;Window&amp;nbsp;Size&amp;nbsp;and&amp;nbsp;Language&amp;nbsp;Model&amp;nbsp;Performance:&amp;nbsp;Balancing&amp;nbsp;Act&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;a href=&quot;https://python.langchain.com/docs/modules/memory/types/summary_buffer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;대화요약&lt;/a&gt;, &lt;a href=&quot;https://python.langchain.com/docs/modules/data_connection/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RAG&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;마지막으로 리눅스와 윈도우 같은 OS들이 C로 짜여져 C API가 기본이듯, 학습데이터에서 양과 질이 가장 좋은 언어인 영어를 기본으로 사용하면 좋다.&lt;br /&gt;토큰도 아껴지는 것은 덤.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 프롬프트 엔지니어링&lt;/h2&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;일반적인 가이드는 이 4가지 공식 가이드에서 대부분 얻을 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.promptingguide.ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Prompt&amp;nbsp;Engineering&amp;nbsp;Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://platform.openai.com/docs/guides/prompt-engineering&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OpenAI: Six&amp;nbsp;strategies&amp;nbsp;for&amp;nbsp;getting&amp;nbsp;better&amp;nbsp;results&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/prompt-engineering&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Microsoft: Introduction&amp;nbsp;to&amp;nbsp;prompt&amp;nbsp;engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/vertex-ai/docs/generative-ai/learn/introduction-prompt-design&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Google: Introduction&amp;nbsp;to&amp;nbsp;prompt&amp;nbsp;design&lt;/a&gt;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://aman.ai/primers/ai/prompt-engineering/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Primers&amp;nbsp;&amp;bull;&amp;nbsp;Prompt&amp;nbsp;Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@jelkhoury880/some-methodologies-in-prompt-engineering-fa1a0e1a9edb&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Explained&amp;nbsp;Methodologies&amp;nbsp;and&amp;nbsp;frameworks&amp;nbsp;in&amp;nbsp;Prompt&amp;nbsp;Engineering&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외의 자료들은 &lt;a href=&quot;https://github.com/promptslab/Awesome-Prompt-Engineering&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Awesome Prompt Engineering&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;3.1 Input - Output&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 프로그래밍의 기초는 함수다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;input -&amp;gt; ouput&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM도 다르지 않다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;자연어 -&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;/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;input의 다음에 나타날 내용을 예측한 것이 output&lt;br /&gt;이라는 점이다.&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;구조적인 output을 만들 수는 있으나 자연어 생성기라 생각하는 것이 낫다.&lt;br /&gt;사람이 리스트나 JSON을 만든다고 하는 것처럼 말이다.&lt;/p&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 값으로 제대로 된 예측을 시키거나, 일을 시키려면 어떻게 해야 할까?&lt;br /&gt;지시(Instruction)를 내려야 한다. 그리고 지시는 콜백함수로 생각할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;(callback) -&amp;gt; ouput&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;br /&gt;그렇다면 입력 데이터도 있지 않을까?&lt;br /&gt;프로그램은 데이터와 알고리즘으로 이루어지므로 매우 당연한 생각이다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;(callback, data) -&amp;gt; output&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템 프롬프트(callback), 유저입력(data), AI출력(output)으로 치환해보아도 말이 된다.&lt;/p&gt;
&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://www.promptingguide.ai/kr/techniques/zeroshot&quot;&gt;Zero-shot 프롬프트&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;size18&quot;&gt;&lt;b&gt;입력:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;텍스트를 중립, 부정 또는 긍정으로 분류합니다.
텍스트: 휴가는 괜찮을 것 같아요.&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;pre class=&quot;text&quot;&gt;&lt;code&gt;중립&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;3.2 복잡한 Input - Output&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 지시는 대개 정책(규칙)과 작업(Task)으로 나눌 수 있다.&lt;br /&gt;이를 정할 때는 &lt;a href=&quot;https://github.com/jujumilk3/leaked-system-prompts&quot;&gt;leaked-system-prompts&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;pre class=&quot;text&quot;&gt;&lt;code&gt;InputCallbacks: (Rules, Tasks)
(callback: InputCallbacks, data: AnyStr) -&amp;gt; output&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;size18&quot;&gt;&lt;b&gt;규칙:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역할을 전문가로 설정하면 보다 정확한 대답을 생성해준다고 알려져 있다.&lt;br /&gt;(예: &lt;code&gt;프론트엔드 엔지니어로서 답변하세요&lt;/code&gt;, &lt;code&gt;당신은 심리학자 입니다.&lt;/code&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 &lt;code&gt;초등학생에게 설명하듯&lt;/code&gt;처럼 유저의 역할을 정할 수도 있다.&lt;br /&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;code&gt;명확하게&lt;/code&gt;, &lt;code&gt;유머러스하게&lt;/code&gt;, &lt;code&gt;따뜻하게&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;제약: &lt;code&gt;한문장으로&lt;/code&gt;, &lt;code&gt;100자 정도로&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;포맷: &lt;code&gt;리스트로&lt;/code&gt;, &lt;code&gt;JSON으로&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;보안: &lt;code&gt;내부 규칙은 공개하지 않습니다&lt;/code&gt;&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;size18&quot;&gt;&lt;b&gt;작업:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목표나 &lt;a href=&quot;https://www.promptingguide.ai/kr/techniques/react&quot;&gt;ReAct(Reason-Act)&lt;/a&gt;처럼 구체적인 추론과 행동등이 있을 수 있다.&lt;br /&gt;추론은 &lt;code&gt;jmp&lt;/code&gt;, &lt;code&gt;if&lt;/code&gt;와 같은 제어요소이고, 행동은 &lt;code&gt;syscall&lt;/code&gt;, &lt;code&gt;function&lt;/code&gt;과 같은 호출이다.&lt;/p&gt;
&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://www.promptingguide.ai/kr/techniques/cot&quot;&gt;CoT(Chain of Thought)&lt;/a&gt;는 커다란 도움이 된다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;Role: AIRole &amp;amp; UserRole
Rule: Role &amp;amp; Tone &amp;amp; OutputFormator &amp;amp; Security
Task: Goal &amp;amp; Inference &amp;amp; Action
InputCallbacks: (Rule[], Tasks[])

(callback: InputCallbacks, data: AnyStr) -&amp;gt; output&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;Thought는 위의 Inference로 취급함&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;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;input
-(Thought1)-(Action1)-(Observe1)
-(Thought2)-(Action2)-(Observe2)
-(Thought3)-(Action3)-
-&amp;gt; output&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;이렇게 생각해보면 OutputFormator는 Rule보다는 마지막에 실행하는 Action에 가까우니 Task로 취급해도 될 것 같다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;Role: AIRole &amp;amp; UserRole
Rule: Role &amp;amp; Tone &amp;amp; Security
Task: Goal &amp;amp; Inference &amp;amp; Action
InputCallbacks: (Rule[], Tasks[])

(callback: InputCallbacks, data: AnyStr) -&amp;gt; output&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;3.3 Sub-function&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면밀히 생각해보면 Subtask, 즉 sub-function은 자체적인 규칙과 추론단계를 포함할 수 있다.&lt;br /&gt;그리고 Subtask도 가지고 있을수도 있으리라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Task인 OutputFormator는 리스트나 JSON Schema와 같은 규칙을 가지고 있다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;Role: AIRole &amp;amp; UserRole
Rule: Role &amp;amp; Tone &amp;amp; Security
Task: Goal &amp;amp; Rule &amp;amp; Inference &amp;amp; Action &amp;amp; Task
InputCallbacks: (Rule[], Tasks[])

(callback: InputCallbacks, data: AnyStr) -&amp;gt; output&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;나는 subtask 대신 한단계의 Task 정의로 끝내고 필요하면 Thought-Act 로 표현하는 방식을 사용한다.&lt;/p&gt;
&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://www.promptingguide.ai/techniques/prompt_chaining&quot;&gt;프롬프트 체이닝&lt;/a&gt; 경우, 커링으로 생각할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;input -&amp;gt; ouput1 -&amp;gt; ouput2 -&amp;gt; output3&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;a href=&quot;https://www.promptingguide.ai/kr/techniques/react&quot;&gt;ReAct(Reason-Act)&lt;/a&gt; 방식으로 생각하면 다음과 같은 것이다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;input -(Thought1)-(Action1)&amp;gt; Observe1
-(Thought2)-(Action2)&amp;gt; Observe2
-(Thought3)-(Action3)&amp;gt; output&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;3.4 Context / Dependency Injection&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 프로그램을 할 때 단순히 input 데이터만 사용하지 않는다.&lt;br /&gt;의존성을 주입하거나, 중간에 I/O등으로 인한 Effect가 존재하기도 한다.&lt;/p&gt;
&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;참고할 만한 문맥(Context)나 정보(Knowledge)를 넣을 수 있다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;아래 문맥을 고려해서 질문에 답변해 줘. 답변은 짧고 간결하게 해 줘. 답변이 정확하지 않다면, 「확실치 않은 대답」이라고 응답해 줘.

문맥: Teplizumab은 Ortho Pharmaceutical이라는 뉴저지의 제약 회사에서 유래했다. 그곳에서, 과학자들은 OKT3라는 항체의 초기 버전을 만들어 냈다. 원래 쥐에서 유래된 이 분자는 T 세포의 표면에 결합하여 세포를 죽이는 잠재력을 제한할 수 있다. 1986년, 신장 이식 후 장기 거부 반응 예방을 위해 승인되어 인간이 사용할 수 있는 최초의 치료용 항체가 되었다.
질문: OKT3는 어디서 유래했는가?
답변:&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;pre class=&quot;text&quot;&gt;&lt;code&gt;Role: AIRole &amp;amp; UserRole
Rule: Role &amp;amp; Tone &amp;amp; Security
Task: Goal &amp;amp; Rule &amp;amp; Inference &amp;amp; Action &amp;amp; Task
InputCallbacks: (Rule[], Tasks[])
InputData: (Knowledge, Data | Question)

(callback: InputCallbacks, data: InputData) -&amp;gt; output&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Tasks: 아래 문맥을 고려해서 질문에 답변해 줘.&lt;/li&gt;
&lt;li&gt;Rules: 답변은 짧고 간결하게 해 줘. 답변이 정확하지 않다면, 「확실치 않은 대답」이라고 응답해 줘.&lt;/li&gt;
&lt;li&gt;Knowledge: 문맥&lt;/li&gt;
&lt;li&gt;Data: 질문&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;a href=&quot;https://www.promptingguide.ai/kr/techniques/dsp&quot;&gt;Directional Stimulus Prompting&lt;/a&gt; 처럼 힌트를 추가해도 도움이 될 것이다.&lt;br /&gt;특히 요약같은 경우 &lt;a href=&quot;https://lovit.github.io/nlp/2018/04/16/krwordrank/&quot;&gt;WordRank&lt;/a&gt;나 기존 NLP등을 보조로 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;Role: AIRole &amp;amp; UserRole
Rule: Role &amp;amp; Tone &amp;amp; Security
Task: Goal &amp;amp; Rule &amp;amp; Inference &amp;amp; Action &amp;amp; Task
Context: Knowledge &amp;amp; Hints

InputCallbacks: (Rule[], Tasks[])
InputData: (Contexts[], data: Data | Question)

(callback: InputCallbacks, data: InputData) -&amp;gt; output&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;3.5 Effect&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM이 자체적으로 중간에 외부 툴링과 상호작용할 수도 있다.&lt;/p&gt;
&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://www.promptingguide.ai/kr/techniques/pal&quot;&gt;코드 인터프리터(Program-Aided Language Models)&lt;/a&gt;, &lt;a href=&quot;https://www.promptingguide.ai/kr/techniques/rag&quot;&gt;RAG(Retrieval Augmented Generation)&lt;/a&gt;이 해당 개념이다.&lt;br /&gt;PAL은 프로그램을 실행해주며, RAG는 지식을 주입받을 수 있다.&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;Role: AIRole &amp;amp; UserRole
Rule: Role &amp;amp; Tone &amp;amp; Security
Task: Goal &amp;amp; Rule &amp;amp; Inference &amp;amp; Action &amp;amp; Task
Context: Knowledge &amp;amp; Hints

InputCallbacks: (Rule[], Tasks[])
InputData: (Context[], Data | Question)
Effects: PAL | RAG

(callback: InputCallbacks, data: InputData) -[ Effects ]-&amp;gt; output&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;그런데.. LLM은 항상 같은 결과를 내는가?&lt;br /&gt;아니다. 따라서 내부에서 사용되는 Inference, Action이든 Function call이든 모두 Effect를 가졌다고 생각해도 무방하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, PAL, RAG등은 모두 Action 개념으로 통일해버리자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.6 Tests&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 프로그래밍에서는 Test를 작성하여 안정성을 높힐 수 있다.&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;하지만 머신러닝 세계에서는 input - Output 예를 Input으로 집어넣어 성능을 향상 시킬 수 있다.&lt;br /&gt;이는 일반적인 프로그램에서 가질 수 없는 특성이며, 알파이자 오메가다.&lt;br /&gt;재귀함수를 Loop unrolling된 형태로 최적화해주는 컴파일러가 생각나기도 하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.promptingguide.ai/kr/techniques/fewshot&quot;&gt;Few-shot&lt;/a&gt;: Zero-shot의 예를 사용&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.promptingguide.ai/kr/techniques/consistency&quot;&gt;Self-Consistency&lt;/a&gt;: CoT의 예를 사용&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.promptingguide.ai/kr/techniques/react&quot;&gt;ReAct&lt;/a&gt;: 프롬프트 체이닝을 예로 사용&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;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;Role: AIRole &amp;amp; UserRole
Rule: Role &amp;amp; Tone &amp;amp; Security
Task: Goal &amp;amp; Rule &amp;amp; Inference &amp;amp; Action &amp;amp; Task
Context: Knowledge &amp;amp; Hints

InputCallbacks: (Rule[], Tasks[])
InputData: (Context[], Data | Question, (Example&amp;lt;Prompt&amp;gt;)[])

Prompt: (callback: InputCallbacks, data: InputData) -&amp;gt; output&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;TDD는 LLM을 이용시 오히려 특화된 개발 방법론 아닐까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM 특성상 편향을 가질 수 있기 때문에 되도록 다양한 예를 넣어주는 것을 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 템플릿&lt;/h2&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;먼저, 창의적이기보다는 일정한 규칙을 꼭 지켜야하는 빡빡한 Output이 나와야 하는 환경에 맞추어 작성하였음을 알았으면 한다.&lt;br /&gt;또한 세부적인 프롬프트를 공개하기에는 보안상 조금 어려움이 있으니 양해바란다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Rules: 전반적으로 지켜야 하는 것들&lt;/li&gt;
&lt;li&gt;Tasks: 액션 리스트와 설명, 여기에 FunctionCall(코드 인터프리터, RAG등)과 OutputFormator도 포함된다&lt;/li&gt;
&lt;li&gt;Task Steps: 메인함수처럼 각 태스크를 ReAct 방식으로 표현. 복잡하지 않으면 리스트로만 작성해도 상관없다&lt;/li&gt;
&lt;li&gt;Examples: input-output 예시들, 정말 명시적으로 하고 싶을 때는 CoT나 ReAct방식대로 추론과정을 펼쳐서 작성한다.&lt;/li&gt;
&lt;li&gt;Start: 유저나 API가 입력하기 직전에 넣을 내용들&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1707661179762&quot; class=&quot;text&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;### Rules ###
Description
1. Rule 1..
2. Rule 2..
3. ...


### Tasks ###
Description

(1) Task1[input]: Description
- Task rule 1
- Task rule 2
- ...

(2) Task2[input]: Description
- Task rule 1
- Task rule 2
- ...


### Task Steps ###
Description

Question: [User message]
Thought1: infer description
Act1: Task1[1nput]
Obs: {result1}
Thought2: infer description
Act2: Task2[1nput]


### Examples ###
Description

- Context: Data
Input: example1 input
Ouput: example1 output
Input: example2 input
Ouput: example2 ouput

- Context: Data
Input: example1 input
Ouput: ...

### Start ###
Description&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;br /&gt;코볼이 &lt;a href=&quot;https://en.wikipedia.org/wiki/COBOL#Syntax&quot;&gt;identification, environment, data, procedure&lt;/a&gt; DIVISION으로 나뉘거나 Pascal/Delphi가 program, uses, label, const 등으로 섹션을 나누는 것과 비슷하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HYKhP/btsEE0U7tvQ/ePRfCYOhlZ4EvZQmhN4zlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HYKhP/btsEE0U7tvQ/ePRfCYOhlZ4EvZQmhN4zlK/img.png&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;991&quot; data-is-animation=&quot;false&quot; style=&quot;width: 12.5902%; margin-right: 10px;&quot; data-widthpercent=&quot;12.89&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HYKhP/btsEE0U7tvQ/ePRfCYOhlZ4EvZQmhN4zlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHYKhP%2FbtsEE0U7tvQ%2FePRfCYOhlZ4EvZQmhN4zlK%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;374&quot; height=&quot;991&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E4Z4N/btsEIPkpzkL/zpI4Qb98CnwJ5QCEeYN990/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E4Z4N/btsEIPkpzkL/zpI4Qb98CnwJ5QCEeYN990/img.png&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;549&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.9604%; margin-right: 10px;&quot; data-widthpercent=&quot;55.25&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E4Z4N/btsEIPkpzkL/zpI4Qb98CnwJ5QCEeYN990/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE4Z4N%2FbtsEIPkpzkL%2FzpI4Qb98CnwJ5QCEeYN990%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;888&quot; height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nbUXO/btsEEKZnntt/13LLyNjP1oGmEkzZKJISR0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nbUXO/btsEEKZnntt/13LLyNjP1oGmEkzZKJISR0/img.jpg&quot; data-origin-width=&quot;487&quot; data-origin-height=&quot;522&quot; data-is-animation=&quot;false&quot; style=&quot;width: 31.1238%;&quot; data-widthpercent=&quot;31.86&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nbUXO/btsEEKZnntt/13LLyNjP1oGmEkzZKJISR0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnbUXO%2FbtsEEKZnntt%2F13LLyNjP1oGmEkzZKJISR0%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;487&quot; height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ibmiskills.com/structural-hierarchy-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cobol Structural Hierarchy&lt;/a&gt; / &lt;a href=&quot;https://www.mainframestechhelp.com/tutorials/cobol/program-structure.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cobol Program Structure&lt;/a&gt; / &lt;a href=&quot;https://www.bestprog.net/en/2021/08/25/pascal-delphi-lazarus-the-structure-of-a-pascal-program-in-the-delphi-and-lazarus/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The structure of a Pascal program in the Delphi and Lazarus programming systems. Console application&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;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;최대한 선형적이며 분기없으면서 안정적으로 작업을 시키려 Task Step에 적용해보려고 시도하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDaWaA/btsEFQqYQg2/JRld3wyKljGg6tavBPzBw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDaWaA/btsEFQqYQg2/JRld3wyKljGg6tavBPzBw0/img.png&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;556&quot; data-is-animation=&quot;false&quot; style=&quot;width: 29.6417%; margin-right: 10px;&quot; data-widthpercent=&quot;30.35&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDaWaA/btsEFQqYQg2/JRld3wyKljGg6tavBPzBw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDaWaA%2FbtsEFQqYQg2%2FJRld3wyKljGg6tavBPzBw0%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;850&quot; height=&quot;556&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O6TkD/btsEHHNBAF2/mzcWntxqBkgqOWrNUxjYv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O6TkD/btsEHHNBAF2/mzcWntxqBkgqOWrNUxjYv0/img.png&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;486&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.9111%; margin-right: 10px;&quot; data-widthpercent=&quot;34.72&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O6TkD/btsEHHNBAF2/mzcWntxqBkgqOWrNUxjYv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO6TkD%2FbtsEHHNBAF2%2FmzcWntxqBkgqOWrNUxjYv0%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;850&quot; height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6dL99/btsEJderP6V/Mpiyt8P6jgUCFpEiJ5RUp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6dL99/btsEJderP6V/Mpiyt8P6jgUCFpEiJ5RUp1/img.png&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;483&quot; data-is-animation=&quot;false&quot; style=&quot;width: 34.1217%;&quot; data-widthpercent=&quot;34.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6dL99/btsEJderP6V/Mpiyt8P6jgUCFpEiJ5RUp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6dL99%2FbtsEJderP6V%2FMpiyt8P6jgUCFpEiJ5RUp1%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;850&quot; height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.researchgate.net/publication/336512408_The_Effect_of_Locus_of_Control_on_Organizational_Learning_Situation_Awareness_and_Safety_Culture&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Effect&amp;nbsp;of&amp;nbsp;Locus&amp;nbsp;of&amp;nbsp;Control&amp;nbsp;on&amp;nbsp;Organizational&amp;nbsp;Learning,&amp;nbsp;Situation&amp;nbsp;Awareness&amp;nbsp;and&amp;nbsp;Safety&amp;nbsp;Culture&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;LogiCoT만으로 애매한 부분들을 채워줄 수 있을 것으로 보인다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. IDE&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡해져서 전용 IDE로 관리하면 좋겠다는 생각이 스물스물 들고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://promptmetheus.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PROMPT Metheus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://x.ai/prompt-ide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;xAI PromptIDE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bigscience-workshop/promptsource&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Prompt Source&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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://en.wikipedia.org/wiki/Oberon_(operating_system)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oberon&lt;/a&gt;이나 &lt;a href=&quot;https://en.wikipedia.org/wiki/Archy_(software)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Archy&lt;/a&gt;처럼 텍스트가 곧 명령처럼 사용할 수 있는 UI도 만들어지지 않을까.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;325&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m61C4/btsEI9JR03j/CuQne4Kr5e8EdJu0j2kncK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m61C4/btsEI9JR03j/CuQne4Kr5e8EdJu0j2kncK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m61C4/btsEI9JR03j/CuQne4Kr5e8EdJu0j2kncK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm61C4%2FbtsEI9JR03j%2FCuQne4Kr5e8EdJu0j2kncK%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;310&quot; data-origin-width=&quot;325&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ignorethecode.net/blog/2009/04/22/oberon/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oberon&lt;/a&gt;(&lt;a href=&quot;https://schierlm.github.io/OberonEmulator/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;에뮬레이터&lt;/a&gt;)&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;형태는 조금 다르겠지만 말이다.&lt;/p&gt;</description>
      <category>프로그래밍/기타</category>
      <category>설계</category>
      <category>인공지능</category>
      <category>프롬프트</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/97</guid>
      <comments>https://black7375.tistory.com/97#entry97comment</comments>
      <pubDate>Sat, 10 Feb 2024 00:32:15 +0900</pubDate>
    </item>
    <item>
      <title>상품과 기호: 들뢰즈-가타리를 중심으로</title>
      <link>https://black7375.tistory.com/95</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;개발자분들이 의외로 &lt;a href=&quot;https://twitter.com/alstjr7375/status/1667481649725194240&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;원 글은 3페이지라는 제약 내에서 쓰여져서 짧긴하나, &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;압축적이라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;기본적으로 요구하는 지식이 있으며&amp;nbsp; 평소에 제가 쓰는 다른 글과 달리 조금.. 어려울 수도 있습니다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 상품과 제품&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책에서 가장 인상 깊은 점은 역시 제목인 &quot;소비자는 좋은 제품을 선택하지 않는다&quot;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책의 &quot;제품이 부품의 결합체지만 상품은 상징적 의미의 더미&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;상품은 제품/서비스란 실체를 가르키는 일종의 기호다. 그렇다면 &quot;기호와 지시대상은 과연 다르게 받아들여질 수 있는가?&quot;, &quot;그리고 그 관계와 영향이란 무엇인가?&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;금성은 태양계의 2 번째 내행성이다. 그러나 샛별[새벽 동쪽하늘에서의 금성]과 개밥바라기[저녁 서쪽하늘에서의&amp;nbsp;금성]라는&amp;nbsp;이름&amp;nbsp;또한&amp;nbsp;가지고&amp;nbsp;있으며&amp;nbsp;의미를&amp;nbsp;다르게&amp;nbsp;받아들인다.&lt;br /&gt;이는&amp;nbsp;기호와&amp;nbsp;지시대상이&amp;nbsp;1:1&amp;nbsp;관계를&amp;nbsp;가지지&amp;nbsp;않는다는&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;또한 샛별은 &quot;샛별&quot;이라는 문자임과 동시에 /ˈsʰɛ̝ːt̚p͈jʌ̹ɭ/ ~ /ˈsʰɛ̝ːp͈jʌ̹ɭ/ɭ 샏:뼐/새:뼐]&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_1&quot; id=&quot;footnote_link_95_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 1)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt;로 발음하는 표현이다. 그러나 샛별이라는 기호 자체의 표현과 의미도 1:1 관계를 가지지 않는다. 영어로는 Evening star 라고 불리는 표현의 반례 때문이다. 방금의 예와 같이 기표와 기의는 우연성에 의해 중계되지만 샛별이란 표현에서 대부분의 한국인들이 '새벽 동쪽하늘에서의 금성'을 떠올리는 것은 한국어-한글이란 체계 속에서 규약적 필연&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_2&quot; id=&quot;footnote_link_95_2&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 2)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 2)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;2&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&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;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_3&quot; id=&quot;footnote_link_95_3&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 3)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 3)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;3&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;태양계 2 번째 행성에서 나온 새로운 정보[발생적 성분]로서의 &quot;금성&quot;은 다른 기호체제인 영어로는 Venus 로 번역 가능한데[변형적 성분], 한국어는 오행(五行)의 금(金)을 영어는 그리스신화의 미의 여신인 아프로디테로 세부적인 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 확장해 변환 중 의미소실 사례를 알아보자. 금성사는 한자인 金星으로 변형 후 다시 영어인 GoldStar 로 번역되어 금성(Venus)이라는 발생적 성분이 없어졌기에&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;br /&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;이렇듯 순수 생산물로서의 제품이 상품으로 편입되는 순간 기존 기호적 체제와의 상호작용에 의해 해석이 달라질 수 있다. 의미가 축소/확장되거나 때로는 바코드 번호처럼 반기표적 기호의 성질을 띄기도 한다. 하지만 무엇보다 중요한 점은 상대적으로 달라진다는 점이다. 상품을 만들 때는 표현과&amp;nbsp;내용에&amp;nbsp;있어&amp;nbsp;다양한&amp;nbsp;차이를&amp;nbsp;고려하고&amp;nbsp;어떠한&amp;nbsp;의미로&amp;nbsp;받아들여질지&amp;nbsp;고려해야&amp;nbsp;할&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;2. 상품과 상품&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상품과&amp;nbsp;제품에서&amp;nbsp;이야기했듯이&amp;nbsp;기호는&amp;nbsp;그&amp;nbsp;자체로&amp;nbsp;다의성을&amp;nbsp;띌&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;사과(Apple)라고 하면 먹는 사과를 떠올릴 수 있겠지만 뉴턴의 만유인력, 세잔의 정물화, 잡스의 Apple Inc. 등을 떠올리기도 한다는 것 이다.&lt;/p&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;nbsp;띄지만&amp;nbsp;시대나&amp;nbsp;사용하는&amp;nbsp;사례에&amp;nbsp;따라&amp;nbsp;인식하는&amp;nbsp;강도는&amp;nbsp;물론&amp;nbsp;의미까지&amp;nbsp;달라진다.&lt;br /&gt;비트겐슈타인이 &quot;언어를 말하는 일이 어떤 활동의 일부, 또는 삶의 형식의 일부&quot;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_4&quot; id=&quot;footnote_link_95_4&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 4)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 4)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;4&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt;라고 했던 것처럼 말이다. 똑같이 먹는 사과에서 비롯되었지만, 이제 IT 산업에서 사과를 이야기하면 Apple Inc.만 떠올리지 먹는 사과로서의 인식은 한입 베어먹은 로고를 제외하면 남아있지 않다. 더 극적인 예를 들어보자면 '혜자스럽다'와 '창렬스럽다'&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_5&quot; id=&quot;footnote_link_95_5&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 5)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 5)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;5&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&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;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_6&quot; id=&quot;footnote_link_95_6&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 6)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 6)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;6&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt; &lt;/span&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_7&quot; id=&quot;footnote_link_95_7&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 7)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 7)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;7&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt; &lt;/span&gt;보드리야르&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_8&quot; id=&quot;footnote_link_95_8&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 8)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 8)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;8&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt;식으로는 파생실재를 모델을 가지고 산출하는 작업이다.&lt;br /&gt;원래 'Apple'에는 회사의 이미지가 없으며 '혜자'와 '창렬' 역시 식품의 가성비와 관련된 이미지가 없다는 점에서 'Apple Inc.', '혜자스럽다', '창렬스럽다'의 이미지는 모두 &quot;실제로는 존재하지 않는 대상을 존재하는 것처럼 만들어놓은&quot; 원본 없는 이미지인 시뮬라크르였지만 실제보다 실제가 되어버린&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;존재하지&amp;nbsp;않던&amp;nbsp;것이&amp;nbsp;원본을&amp;nbsp;대체한다니,&amp;nbsp;과연&amp;nbsp;나쁜&amp;nbsp;것일까?&lt;br /&gt;'창렬스럽다'처럼 '김창렬'이라는 개인 내지는 가족에게 불이익을 준 사례&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_9&quot; id=&quot;footnote_link_95_9&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 9)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 9)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;9&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt;가 있으므로 안 좋게 볼 수도 있겠지만, 'Apple'과 '혜자스럽다'는 그렇다고 단언하기 힘들다. 오히려 원본으로 대체 불가능한 독특한 가치를 가지고 있다. 만약 시뮬라크르가 나쁜 것이라면 'Apple Inc.'가 이루어낸 많은 혁신들이 부정되며, 이제는 초코파이의 대명사가 되버린 오리온 초코파이 정(情) 또한 안 좋은 것이 되고야 만다. 그리고 이에 대해 들뢰즈는 &quot;존재는 생성을 통해, 동일성은 차이 나는 것을 통해, 일자는 다자를 통해 자신을 언명한다&quot;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_10&quot; id=&quot;footnote_link_95_10&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 10)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 10)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;10&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&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;h3 data-ke-size=&quot;size23&quot;&gt;3. 상품과 욕망&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책에서 가장 아쉬웠던 점은 소비행동을 단순히 &quot;소비자 자신의 욕구를 충족하기 위한 수단&quot;으로 정의했다는 점 이다. &quot;제품의 가치를 소진하는 과정&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 data-ke-size=&quot;size16&quot;&gt;이를 단지 결핍되었다고 설명하기란 어렵다. 매슬로우의 단계 욕구이론에서도 자아실현은 특별히 따로 구분하고 있으며, 말년의 매슬로우는 자신의 욕구이론을 비판&lt;span&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_11&quot; id=&quot;footnote_link_95_11&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 11)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 11)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;11&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_12&quot; id=&quot;footnote_link_95_12&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 12)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 12)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;12&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&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;앞서 단순 결핍의 반례로 설명한 사례는 자아실현을 위한 시도[자기초월의 과정]로 니체적 힘(Kraft)에의 의지에 가깝다고 할 수 있다. 이제 욕구와는 구분되는 단어, 욕망(Desire)이 필요하다. 들뢰즈-가타리는 욕망을 무의식의 자기생산이라 이야기한다. 여기서 생산이란 구성, 조립, 배치등을 통한 유물론적 변형으로 여겨지며 욕망은 마르크스적 의미의 하부구조, 기계들로서 작동한다.&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_13&quot; id=&quot;footnote_link_95_13&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 13)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 13)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;13&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&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;결핍은&amp;nbsp;어찌하여&amp;nbsp;생기고&amp;nbsp;작동하는&amp;nbsp;걸까?&lt;br /&gt;들뢰즈-가타리는 억압적 재현작용과 억압된 대표, 욕망이 억압된 대표에 사로잡혔다고 여기게 되는 위조된 이미지를 주는 재현내용으로 구성되며, 억압이 작용하려면 &quot;기꺼이 벌 받으려는 후속욕망&quot;이 억압의 대상인 선행욕망을 대신 해야한다고 말한다.&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_14&quot; id=&quot;footnote_link_95_14&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 14)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 14)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;14&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를테면 거식증&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_15&quot; id=&quot;footnote_link_95_15&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 15)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 15)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;15&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt;은 체중에 대한 반복적 사회적 압박[재현작용], 음식 섭취[억압된 대표], '멋져보이는' 모델/연예인들과의 비교[위조된 이미지의 재현내용]에 의해 일어나며 체중 감소라는 후속욕망이 음식 섭취라는 선행욕망을 대신하기 때문일테며, 처음 언급한 프로이트의 핵심인 오이디푸스콤플렉스는&amp;nbsp;제국주의가&amp;nbsp;사회적&amp;nbsp;욕망을&amp;nbsp;가족&amp;nbsp;내의&amp;nbsp;욕망으로&amp;nbsp;이전시킨&amp;nbsp;관점에서&amp;nbsp;이해할&amp;nbsp;수&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;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_16&quot; id=&quot;footnote_link_95_16&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 16)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 16)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;16&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/span&gt;이 있다. 억압이 없는 한 계속하여 흐르게하고 흐르고 절단하는 욕망이&amp;nbsp;자연스레&amp;nbsp;각&amp;nbsp;유저별로&amp;nbsp;차이를&amp;nbsp;생산하게&amp;nbsp;구성되어&amp;nbsp;특별하게&amp;nbsp;만든다는&amp;nbsp;점에서&amp;nbsp;좋은&amp;nbsp;서비스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이제 억압보다 차이를 긍정하며, 사회에 내적 동기의 중요성&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_95_17&quot; id=&quot;footnote_link_95_17&quot; onmouseover=&quot;tistoryFootnote.show(this, 95, 17)&quot; onmouseout=&quot;tistoryFootnote.hide(95, 17)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;17&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&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;최근에 Claude 3.5를 이용해 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;사용한&amp;nbsp;프롬프트는&amp;nbsp;다음과&amp;nbsp;같습니다.&lt;br /&gt;1.&amp;nbsp;다음&amp;nbsp;글의&amp;nbsp;내용을&amp;nbsp;이해하고,&amp;nbsp;요약하시오.&amp;nbsp;(위&amp;nbsp;글&amp;nbsp;내용&amp;nbsp;첨부)&lt;br /&gt;2.&amp;nbsp;푸코의&amp;nbsp;담론&amp;nbsp;이야기까지&amp;nbsp;쭉&amp;nbsp;전개해&amp;nbsp;&quot;상품과&amp;nbsp;권력&quot;을&amp;nbsp;작성하여,&amp;nbsp;&quot;좋은&amp;nbsp;제품&quot;에&amp;nbsp;대한&amp;nbsp;수미상관으로&amp;nbsp;마무리하시오.&lt;br /&gt;원본&amp;nbsp;글의&amp;nbsp;전개방식,&amp;nbsp;논리구조,&amp;nbsp;어조등을&amp;nbsp;그대로&amp;nbsp;유지해야&amp;nbsp;합니다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;4. 상품과 권력&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 우리는 상품이 기호로서 작동하며, 그 의미가 맥락에 따라 변화하고 때로는 실재를 대체하는 시뮬라크르가 될 수 있음을 살펴보았다. 이제 우리는 한 걸음 더 나아가 상품과 권력의 관계를 살펴보고자 한다. 과연 &quot;좋은 제품&quot;이란 무엇인가? 이는 단순히 기능적 우수성만을 의미하는가, 아니면 그 이상의 무언가를 내포하고 있는가?&lt;br /&gt;&lt;br /&gt;푸코의&amp;nbsp;관점에서&amp;nbsp;보면,&amp;nbsp;&quot;좋은&amp;nbsp;제품&quot;이라는&amp;nbsp;개념은&amp;nbsp;하나의&amp;nbsp;담론(discourse)으로&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;작용한다.&lt;br /&gt;&lt;br /&gt;&quot;좋은&amp;nbsp;제품&quot;이라는&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;&quot;좋은&amp;nbsp;제품&quot;으로&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;결과이다.&lt;br /&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;&quot;좋은&amp;nbsp;제품&quot;에&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;&quot;규율&amp;nbsp;권력&quot;과&amp;nbsp;유사하게&amp;nbsp;작동한다.&amp;nbsp;소비자들은&amp;nbsp;&quot;좋은&amp;nbsp;제품&quot;이라는&amp;nbsp;담론에&amp;nbsp;의해&amp;nbsp;자신의&amp;nbsp;소비&amp;nbsp;행위를&amp;nbsp;규율하게&amp;nbsp;되는&amp;nbsp;것이다.&lt;br /&gt;&lt;br /&gt;그러나&amp;nbsp;담론의&amp;nbsp;형성이&amp;nbsp;일방적인&amp;nbsp;것은&amp;nbsp;아니다.&amp;nbsp;소비자들&amp;nbsp;역시&amp;nbsp;SNS나&amp;nbsp;리뷰&amp;nbsp;플랫폼을&amp;nbsp;통해&amp;nbsp;제품에&amp;nbsp;대한&amp;nbsp;자신의&amp;nbsp;의견을&amp;nbsp;표현하고,&amp;nbsp;이는&amp;nbsp;다시&amp;nbsp;&quot;좋은&amp;nbsp;제품&quot;에&amp;nbsp;대한&amp;nbsp;담론을&amp;nbsp;재구성하는&amp;nbsp;데&amp;nbsp;영향을&amp;nbsp;미친다.&amp;nbsp;이는&amp;nbsp;푸코가&amp;nbsp;말한&amp;nbsp;&quot;권력의&amp;nbsp;미시물리학&quot;과&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;br /&gt;&lt;br /&gt;더&amp;nbsp;나아가,&amp;nbsp;&quot;좋은&amp;nbsp;제품&quot;이라는&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;&quot;좋은&amp;nbsp;제품&quot;으로&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;&quot;생명정치(biopolitics)&quot;의&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;br /&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;&quot;좋은&amp;nbsp;제품&quot;에&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;&quot;좋은&amp;nbsp;제품&quot;으로&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;br /&gt;&lt;br /&gt;이제&amp;nbsp;다시&amp;nbsp;처음의&amp;nbsp;질문으로&amp;nbsp;돌아가&amp;nbsp;보자.&amp;nbsp;&quot;소비자는&amp;nbsp;좋은&amp;nbsp;제품을&amp;nbsp;선택하지&amp;nbsp;않는다&quot;는&amp;nbsp;명제는&amp;nbsp;어떤&amp;nbsp;의미를&amp;nbsp;갖는가?&amp;nbsp;이는&amp;nbsp;단순히&amp;nbsp;소비자의&amp;nbsp;비합리성을&amp;nbsp;지적하는&amp;nbsp;것이&amp;nbsp;아니라,&amp;nbsp;&quot;좋은&amp;nbsp;제품&quot;이라는&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;&quot;좋은&amp;nbsp;제품&quot;의&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;br /&gt;&lt;br /&gt;결국,&amp;nbsp;&quot;좋은&amp;nbsp;제품&quot;이란&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;&quot;좋은&amp;nbsp;제품&quot;에&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;br /&gt;&lt;br /&gt;Citations:&amp;nbsp;&lt;br /&gt;18.&amp;nbsp;Michel&amp;nbsp;Foucault,&amp;nbsp;The&amp;nbsp;Archaeology&amp;nbsp;of&amp;nbsp;Knowledge,&amp;nbsp;Routledge,&amp;nbsp;2002&lt;br /&gt;19.&amp;nbsp;Michel&amp;nbsp;Foucault,&amp;nbsp;Discipline&amp;nbsp;and&amp;nbsp;Punish:&amp;nbsp;The&amp;nbsp;Birth&amp;nbsp;of&amp;nbsp;the&amp;nbsp;Prison,&amp;nbsp;Vintage&amp;nbsp;Books,&amp;nbsp;1995&lt;br /&gt;20.&amp;nbsp;Michel&amp;nbsp;Foucault,&amp;nbsp;The&amp;nbsp;History&amp;nbsp;of&amp;nbsp;Sexuality:&amp;nbsp;An&amp;nbsp;Introduction,&amp;nbsp;Volume&amp;nbsp;I,&amp;nbsp;Vintage&amp;nbsp;Books,&amp;nbsp;1990&lt;/p&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 배경지식&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8UXuz/btsk9PY3r8W/sk3kqNDD8Up5QY1TeEsJV0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8UXuz/btsk9PY3r8W/sk3kqNDD8Up5QY1TeEsJV0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8UXuz/btsk9PY3r8W/sk3kqNDD8Up5QY1TeEsJV0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8UXuz%2Fbtsk9PY3r8W%2Fsk3kqNDD8Up5QY1TeEsJV0%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;초반에 차근차근 설명하다가 후반으로 갈수록 3페이지 제한 내에 쓸만한 주제가 아니라 설명에 실패했어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 계획은 푸코의 담론 이야기까지 쭉 전개해 &quot;상품과 권력&quot;까지도 쓸려고 했으나 쳐내고, &quot;좋은 제품&quot;에 대한 수미상관으로 마무리만 했습니다만, 그럼에도 요하는 배경지식이 너무 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(권력에 대한 이론은 마케팅으로 접목할 수 있겠죠 :D)&lt;/p&gt;
&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;span&gt;들뢰즈&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;가타리의 철학을 위해서는 크게 세가지의 계파를 이해하면 좋습니다&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFZ6Ud/btsk9cArXeD/msB2tyFOnsOKsGbRk7AATk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFZ6Ud/btsk9cArXeD/msB2tyFOnsOKsGbRk7AATk/img.jpg&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;599&quot; data-is-animation=&quot;false&quot; style=&quot;width: 31.3728%; margin-right: 10px;&quot; data-widthpercent=&quot;32.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFZ6Ud/btsk9cArXeD/msB2tyFOnsOKsGbRk7AATk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFZ6Ud%2Fbtsk9cArXeD%2FmsB2tyFOnsOKsGbRk7AATk%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;449&quot; height=&quot;599&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DDiAG/btslcCYoP8i/3WxONy5hOEoHsJgWDg6wc0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DDiAG/btslcCYoP8i/3WxONy5hOEoHsJgWDg6wc0/img.jpg&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;338&quot; data-is-animation=&quot;false&quot; style=&quot;width: 35.91%; margin-right: 10px;&quot; data-widthpercent=&quot;36.76&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DDiAG/btslcCYoP8i/3WxONy5hOEoHsJgWDg6wc0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDDiAG%2FbtslcCYoP8i%2F3WxONy5hOEoHsJgWDg6wc0%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;290&quot; height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wsa0e/btsk85uCSVp/ONfrH7K7S4qKNef2HJuXBk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wsa0e/btsk85uCSVp/ONfrH7K7S4qKNef2HJuXBk/img.jpg&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;482&quot; data-is-animation=&quot;false&quot; style=&quot;width: 30.3917%;&quot; data-widthpercent=&quot;31.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wsa0e/btsk85uCSVp/ONfrH7K7S4qKNef2HJuXBk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWsa0e%2Fbtsk85uCSVp%2FONfrH7K7S4qKNef2HJuXBk%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;350&quot; height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;의심의 대가들&lt;/figcaption&gt;
&lt;/figure&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;span&gt;스피노자&lt;/span&gt;-&lt;span&gt;니체&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;헤겔&lt;/span&gt;-&lt;span&gt;마르크스&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;프로이트&lt;/span&gt;-&lt;span&gt;라캉&lt;/span&gt;&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&gt;니체적 힘에의 의지는 극복하려는 의지로 이데아를 위해 욕망을 부정하는 플라톤주의나 정신분석학에서 결핍으로보는 프로이트&lt;/span&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;제가 썼던 글도 마찬가지 입니다.&lt;/p&gt;
&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;a href=&quot;https://product.kyobobook.co.kr/detail/S000000959143&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;들뢰즈 개념어 사전&lt;/a&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;a href=&quot;https://jiwoonism.tistory.com/215&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;들뢰즈&amp;nbsp;가타리&amp;nbsp;용어&amp;nbsp;설명&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;p data-ke-size=&quot;size16&quot;&gt;옐름슬레우 관련은 연결이 됩니다만, 아예 다른 내용이라 생각해도 좋습니다. &lt;s&gt;그냥 글 나누기가 귀찮아서 그래요..&lt;/s&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 기호론과 LLM&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;a href=&quot;https://twitter.com/alstjr7375/status/1656923181712809984&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;트윗&lt;/a&gt;에 있듯 &quot;왜 언어(기호)의 해석에 비용이 많이 드는가&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.semanticscholar.org/paper/Hjelmslev's-semiotic-model-of-language%3A-An-exegesis-Taverniers/aea82d14a5887daa4f1d647ae5387d4e71543e86&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hjelmslev's semiotic model of language: An exegesis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://s-space.snu.ac.kr/bitstream/10371/85443/1/3.%202236729.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;On&amp;nbsp;Saussure&amp;nbsp;and&amp;nbsp;Hjelmslev,&amp;nbsp;their&amp;nbsp;Structural&amp;nbsp;Viewpoints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kci.go.kr/kciportal/ci/sereArticleSearch/ciSereArtiView.kci?sereArticleSearchBean.artiId=ART002834984&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;옐름슬레우의&amp;nbsp;&amp;lsquo;언어의&amp;nbsp;지층화&amp;rsquo;&amp;nbsp;이론이&amp;nbsp;들뢰즈와&amp;nbsp;과타리의&amp;nbsp;&amp;lsquo;도덕의&amp;nbsp;지질학&amp;rsquo;에&amp;nbsp;수용된&amp;nbsp;과정&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;h4 data-ke-size=&quot;size20&quot;&gt;소쉬르의 기호학&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소쉬르에 대해 설명하기 위해서는 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%9E%91%EA%B7%B8%EC%99%80_%ED%8C%8C%EB%A1%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;랑그(Langue)와 파롤(Parole)&lt;/a&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p6NQR/btslatagLTX/OlX8JCQa1ymUOdr2uPwVx0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p6NQR/btslatagLTX/OlX8JCQa1ymUOdr2uPwVx0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p6NQR/btslatagLTX/OlX8JCQa1ymUOdr2uPwVx0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp6NQR%2FbtslatagLTX%2FOlX8JCQa1ymUOdr2uPwVx0%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;550&quot; height=&quot;172&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;172&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.koya-culture.com/news/article.html?no=97510&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;김슬옹&amp;nbsp;교수,&amp;nbsp;&amp;ldquo;세종과&amp;nbsp;들뢰즈의&amp;nbsp;언어관&amp;rdquo;&amp;nbsp;발표&amp;nbsp;주목받아&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;소쉬르는 사회적인 측면인 &quot;랑그&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;앞서 배운 기표(Signifiant), 기의(signifi&amp;eacute;), 지시대상(R&amp;eacute;f&amp;eacute;rent)이 나오게 되죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B8%B0%ED%91%9C%EC%99%80_%EA%B8%B0%EC%9D%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;기표와 기의&lt;/a&gt;는 사회계약에 의한, 자의성을 띈다고 생각하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhg61B/btslbnAAsEy/42HWG5M9tfAjNokm1Jdayk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhg61B/btslbnAAsEy/42HWG5M9tfAjNokm1Jdayk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhg61B/btslbnAAsEy/42HWG5M9tfAjNokm1Jdayk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbhg61B%2FbtslbnAAsEy%2F42HWG5M9tfAjNokm1Jdayk%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;350&quot; height=&quot;210&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.le-gout-de-la-psychanalyse.fr/psychanalyse/la-linguisterie-inventee-par-lacan/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;La&amp;nbsp;linguisterie&amp;nbsp;invent&amp;eacute;e&amp;nbsp;par&amp;nbsp;Lacan&amp;nbsp;&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결합관계(Syntagme): 연관되어 결합 할 수 있는 관계 (And)&lt;/li&gt;
&lt;li&gt;계열관계(Paradigme): 대체되어도 결합관계가 성립되는 관계 (Or)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCvW0j/btsk83p6nlt/OsZaSKabHKgkYUvUDuno00/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCvW0j/btsk83p6nlt/OsZaSKabHKgkYUvUDuno00/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCvW0j/btsk83p6nlt/OsZaSKabHKgkYUvUDuno00/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCvW0j%2Fbtsk83p6nlt%2FOsZaSKabHKgkYUvUDuno00%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;560&quot; height=&quot;250&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.epicurus.kr/Humanitas/386926&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[철학사40]&amp;nbsp;소쉬르(Saussure)&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;h4 data-ke-size=&quot;size20&quot;&gt;퍼스의 기호학&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;퍼스의 기호학은 표현체(Representamen), 해석체(Interpretant), 대상(Object)으로 이루어져 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpv7id/btsk84P2JGT/xZTIgRLfkpWYU47kE4S28k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpv7id/btsk84P2JGT/xZTIgRLfkpWYU47kE4S28k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpv7id/btsk84P2JGT/xZTIgRLfkpWYU47kE4S28k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdpv7id%2Fbtsk84P2JGT%2FxZTIgRLfkpWYU47kE4S28k%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;598&quot; height=&quot;406&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.semanticscholar.org/paper/Sign-Object-Interpretant-Symbol-Reference-(-)-(-)-%E2%80%9C-Taniguchi-Ugur/b0dd9509895e44dd3c0696e4afbb3ece6bd949ed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sign&amp;nbsp;Object&amp;nbsp;Interpretant&amp;nbsp;Symbol&amp;nbsp;Reference&amp;nbsp;(&amp;nbsp;Signifier&amp;nbsp;)&amp;nbsp;Referent&amp;nbsp;(&amp;nbsp;Signified&amp;nbsp;)&amp;nbsp;&amp;ldquo;&amp;nbsp;Apple&amp;nbsp;&amp;rdquo;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(원본 이미지에서 Signifiant, signifi&amp;eacute;를 자른 이유는 소쉬르의 signifi&amp;eacute;는 Interpretant에 더 가깝기 때문에&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;또한 기호는 도상(Icon), 지표(Index), 상징(Symbol)로 구분되죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;기호-02.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lBCR9/btsk9kygbp7/hbQLziVgc226KKCEEUdm50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lBCR9/btsk9kygbp7/hbQLziVgc226KKCEEUdm50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lBCR9/btsk9kygbp7/hbQLziVgc226KKCEEUdm50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlBCR9%2Fbtsk9kygbp7%2FhbQLziVgc226KKCEEUdm50%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;1280&quot; height=&quot;720&quot; data-filename=&quot;기호-02.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://brunch.co.kr/@jmlee9762/26&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;아이콘,&amp;nbsp;지표&amp;nbsp;그리고&amp;nbsp;심볼.&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;표현, 대상, 해석에 의해 기호작용(Semiosis, 세미오시스)이 일어나는 방법은 다음과 같구요,&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;1196&quot; data-origin-height=&quot;612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egV0aO/btsk816V4xC/u5vk7iSg7yGUfs0b3rGQfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egV0aO/btsk816V4xC/u5vk7iSg7yGUfs0b3rGQfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egV0aO/btsk816V4xC/u5vk7iSg7yGUfs0b3rGQfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FegV0aO%2Fbtsk816V4xC%2Fu5vk7iSg7yGUfs0b3rGQfK%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;450&quot; height=&quot;228&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;612&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://interaction.tistory.com/9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;시각 도상의 언어적 속성에 대한 연구&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eUlqET/btslb5fhlBR/IyUY91kkrpzMZ07wDumTd0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eUlqET/btslb5fhlBR/IyUY91kkrpzMZ07wDumTd0/img.jpg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;223&quot; data-is-animation=&quot;false&quot; style=&quot;width: 58.2466%; margin-right: 10px;&quot; data-widthpercent=&quot;58.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eUlqET/btslb5fhlBR/IyUY91kkrpzMZ07wDumTd0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeUlqET%2Fbtslb5fhlBR%2FIyUY91kkrpzMZ07wDumTd0%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;400&quot; height=&quot;223&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHaWcc/btslbn1JzZq/mNsP4BOheqQtczB5qae5M1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHaWcc/btslbn1JzZq/mNsP4BOheqQtczB5qae5M1/img.jpg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;320&quot; data-is-animation=&quot;false&quot; style=&quot;width: 40.5906%;&quot; data-widthpercent=&quot;41.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHaWcc/btslbn1JzZq/mNsP4BOheqQtczB5qae5M1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHaWcc%2Fbtslbn1JzZq%2FmNsP4BOheqQtczB5qae5M1%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;400&quot; height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://aodr.org/_common/do.php?a=full&amp;amp;b=&amp;amp;bidx=23&amp;amp;aidx=371&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;서사적 상호작용 공간에서의 모달리티&lt;/span&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;아이콘, 인덱스, 심볼은 각각 이렇게 생각하시면 됩니다.&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;모양을 닮은 아이콘: 사과 아이콘은 사과 모양을 띄고 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;기호-03.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLCQz1/btsk80Aboy3/IFyPqBT5yqW9ov62I8drk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLCQz1/btsk80Aboy3/IFyPqBT5yqW9ov62I8drk1/img.png&quot; data-alt=&quot;모양을 기반으로 한 아이콘&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLCQz1/btsk80Aboy3/IFyPqBT5yqW9ov62I8drk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLCQz1%2Fbtsk80Aboy3%2FIFyPqBT5yqW9ov62I8drk1%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;1280&quot; height=&quot;720&quot; data-filename=&quot;기호-03.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;모양을 기반으로 한 아이콘&lt;/figcaption&gt;
&lt;/figure&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;기호-04.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Crnp/btslaf4gCJr/7bPrCQv9JLfKCVRDvkgAu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Crnp/btslaf4gCJr/7bPrCQv9JLfKCVRDvkgAu0/img.png&quot; data-alt=&quot;인접/인과를 기반으로 한 인덱스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Crnp/btslaf4gCJr/7bPrCQv9JLfKCVRDvkgAu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Crnp%2Fbtslaf4gCJr%2F7bPrCQv9JLfKCVRDvkgAu0%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;1280&quot; height=&quot;720&quot; data-filename=&quot;기호-04.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;관습에 의한 심볼: 알파벳은 유사성과 인과관계보다는 약속이나 관습에 기반한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;기호-05.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2WIZR/btsk8J6osxi/2pnu2LlAMN55y7AvtLqXk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2WIZR/btsk8J6osxi/2pnu2LlAMN55y7AvtLqXk0/img.png&quot; data-alt=&quot;관습/자의성을 기반으로 한 심볼&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2WIZR/btsk8J6osxi/2pnu2LlAMN55y7AvtLqXk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2WIZR%2Fbtsk8J6osxi%2F2pnu2LlAMN55y7AvtLqXk0%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;1280&quot; height=&quot;720&quot; data-filename=&quot;기호-05.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;내용과 표현&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 글에서 소쉬르의&lt;span&gt;&amp;nbsp;&lt;/span&gt;기표(signifiant)와 기의(signifi&amp;eacute;)를 차용해 설명한 이유는 쉽기 때문입니다. (단, 1:1 관계가 아니다를 설명하기 위해서와 기호체계 마다 다르다에 한정하여 사용했습니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옐름슬레우의 경우 명시적으로 표현(Expression)-내용(Content)을 정의하지 않았기 때문도 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그는 대신 기호함수(Sign function)을 중요시 여겼습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf0BPx/btsk9jGzvTR/2ZL85q96fTKdYXW7yO98Y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf0BPx/btsk9jGzvTR/2ZL85q96fTKdYXW7yO98Y1/img.png&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;317&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.2494%; margin-right: 10px;&quot; data-widthpercent=&quot;52.86&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf0BPx/btsk9jGzvTR/2ZL85q96fTKdYXW7yO98Y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf0BPx%2Fbtsk9jGzvTR%2F2ZL85q96fTKdYXW7yO98Y1%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;612&quot; height=&quot;317&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbrqnQ/btslat2VBsi/j5qOe4X9hbeC7WPNTU51hK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbrqnQ/btslat2VBsi/j5qOe4X9hbeC7WPNTU51hK/img.png&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;341&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.5878%;&quot; data-widthpercent=&quot;47.14&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbrqnQ/btslat2VBsi/j5qOe4X9hbeC7WPNTU51hK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbrqnQ%2Fbtslat2VBsi%2Fj5qOe4X9hbeC7WPNTU51hK%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;341&quot;/&gt;&lt;/span&gt;&lt;/div&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'말'과 '글'은 표현이고, '설득'과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;'사과'&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XvLg5/btsldOLaCOv/PARBQs6hKIshRK2AQmepJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XvLg5/btsldOLaCOv/PARBQs6hKIshRK2AQmepJ0/img.png&quot; data-alt=&quot;언어마다 포함하는 의미가 다른 예&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XvLg5/btsldOLaCOv/PARBQs6hKIshRK2AQmepJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXvLg5%2FbtsldOLaCOv%2FPARBQs6hKIshRK2AQmepJ0%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;700&quot; height=&quot;255&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;255&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&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;구분하기 어렵다&lt;/b&gt;는 점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'표현 없는 내용'과 '내용 없는 표현'은 존재할 수 없다는 거죠. (상호의존성)&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;함수적 정의에 따르면, 둘 중 어느 하나를 반드시 표현이라고 부르고다른 하나를 반드시&amp;nbsp;내용이라고&amp;nbsp;불러야&amp;nbsp;할&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;HTML-CSS-Javascript는 각자 담고자 하는 내용에 따라 표현이 정해진 예입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML을 Javacript에서 적절히 표혀하기 위해 JSX처럼 확장하기도 하고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저수준/컴파일 언어인 C, Rust의 표현과 고수준/인터프린터 언어인 Javascript, Python의 표현도 달라질 수밖에 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 측면에서 DSL의 부상도 이해할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://news.hada.io/topic?id=8009&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;작은&amp;nbsp;언어는&amp;nbsp;프로그래밍의&amp;nbsp;미래입니다&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jetbrains.com/ko-kr/mps/concepts/domain-specific-languages/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;도메인 특화 언어 (DSL: Domain-Specific Languages)에 관한 설명&lt;/a&gt;&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;/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;866&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfV9R4/btslaRoqhYO/wtlmDKYsLhUXi7JrxEHgE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfV9R4/btslaRoqhYO/wtlmDKYsLhUXi7JrxEHgE0/img.png&quot; data-alt=&quot;함축적/메타적 기호학, 외연(외시, Denotation)/내연(공시, Connotation)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfV9R4/btslaRoqhYO/wtlmDKYsLhUXi7JrxEHgE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfV9R4%2FbtslaRoqhYO%2FwtlmDKYsLhUXi7JrxEHgE0%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;866&quot; height=&quot;350&quot; data-origin-width=&quot;866&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;함축적/메타적 기호학, 외연(외시, Denotation)/내연(공시, Connotation)&lt;/figcaption&gt;
&lt;/figure&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b35WxK/btsla0ZRuQ8/kM0f1uynqQ2zEkSMloeBG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b35WxK/btsla0ZRuQ8/kM0f1uynqQ2zEkSMloeBG0/img.png&quot; data-alt=&quot;함축적 기호학의 내용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b35WxK/btsla0ZRuQ8/kM0f1uynqQ2zEkSMloeBG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb35WxK%2Fbtsla0ZRuQ8%2FkM0f1uynqQ2zEkSMloeBG0%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;864&quot; height=&quot;600&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;600&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;어째서 'speech', 'writing'처럼 표현으로 보이는 것이 내용에 나오냐고요?&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차적 의미, 2차적 의미로 말합니다.&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://ko.wikipedia.org/wiki/%EC%9D%B4%EB%85%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이데올로기&lt;/a&gt;를 포함하구요. (여기서 또 마르크스가..)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfG4Tz/btslaIZriGW/7F7TAOqHxVKNgYM5Yf3M2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfG4Tz/btslaIZriGW/7F7TAOqHxVKNgYM5Yf3M2K/img.png&quot; style=&quot;width: 31.5954%; margin-right: 10px;&quot; data-test-id=&quot;figure-image&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;394&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;31.97&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfG4Tz/btslaIZriGW/7F7TAOqHxVKNgYM5Yf3M2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfG4Tz%2FbtslaIZriGW%2F7F7TAOqHxVKNgYM5Yf3M2K%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;440&quot; height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsJwK4/btslaQXmZm9/gnT7kw3xV2ea9F3McatG21/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsJwK4/btslaQXmZm9/gnT7kw3xV2ea9F3McatG21/img.jpg&quot; style=&quot;width: 67.2418%;&quot; width=&quot;530&quot; height=&quot;223&quot; data-font-image=&quot;false&quot; data-title=&quot;〈표 1〉 신화적 의미 작용&quot; data-seq=&quot;2&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;223&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;68.03&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsJwK4/btslaQXmZm9/gnT7kw3xV2ea9F3McatG21/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsJwK4%2FbtslaQXmZm9%2FgnT7kw3xV2ea9F3McatG21%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;530&quot; height=&quot;223&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://terms.naver.com/entry.naver?docId=1691664&amp;amp;cid=42219&amp;amp;categoryId=42221&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;롤랑&amp;nbsp;바르트&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;늠름하게 경례하는 프랑스 흑인 청년에서 확장되어 피부색 차별없이 프랑스 국기 하에서 봉사하며, 이는 제국주의와 식민주의를 옹호하기 위해 사용됩니다. (+1950년대 임을 상기합시다)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czO4FZ/btsk8ZOUREt/sgbUa1oCjfUOjotC6H9Gq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czO4FZ/btsk8ZOUREt/sgbUa1oCjfUOjotC6H9Gq1/img.png&quot; style=&quot;width: 60.5538%; margin-right: 10px;&quot; width=&quot;1710&quot; height=&quot;962&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;61.27&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czO4FZ/btsk8ZOUREt/sgbUa1oCjfUOjotC6H9Gq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczO4FZ%2Fbtsk8ZOUREt%2FsgbUa1oCjfUOjotC6H9Gq1%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;1280&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ltzce/btsla0r1kQ0/3cBxH5F7zJDX8be9YgxDQ1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ltzce/btsla0r1kQ0/3cBxH5F7zJDX8be9YgxDQ1/img.jpg&quot; style=&quot;width: 38.2834%;&quot; data-origin-width=&quot;535&quot; data-origin-height=&quot;476&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;38.73&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ltzce/btsla0r1kQ0/3cBxH5F7zJDX8be9YgxDQ1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLtzce%2Fbtsla0r1kQ0%2F3cBxH5F7zJDX8be9YgxDQ1%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;535&quot; height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://brunch.co.kr/@jmswsb123/83&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;번외_'롤랑 바르트'는 누구인가&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;/ &amp;nbsp;&lt;a href=&quot;https://m.blog.naver.com/syo0116/130032176927&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;롤랑바르트&amp;nbsp;'의미작용'&lt;/a&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠시 샛길로 갔습니다만 다시 돌아와봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 위 롤랑바르트 이론에서 외연[2차적 기표]은 형식(Form), 내연[2차적 기의]은 개념(Concept)으로 사용되고 있습니다.&lt;/p&gt;
&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;롤랑바르트가 다양한 상황에서 2차적 의미와의 관계에서 기호에 초점을 맞추는 반면, 옐름슬레우는 언어이론과 형식에 관심을 가졌다.&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;이 챕터의 형식(Form)-실체(Substance)-요지(Purport)입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 그에 따르면 &lt;b&gt;기호함수(Sign function)&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;형식: 함수의 값이 정해지는 표명(manifestation)에서 상수적 역할을 함, (Schema)&lt;/li&gt;
&lt;li&gt;실체: 형식에 의해서만 존재할 수 있으며, 표명에서 변수적 역할을 함&lt;/li&gt;
&lt;li&gt;요지: 공통된 요인(factor)이나 함수에 의해서만 정의되고 형식화되지 않은 무형의 사고 덩어리 (질료)&lt;/li&gt;
&lt;/ul&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;864&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSghcJ/btsk84JbAlv/Y4GgNjZcDYC0RYXsTcXDUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSghcJ/btsk84JbAlv/Y4GgNjZcDYC0RYXsTcXDUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSghcJ/btsk84JbAlv/Y4GgNjZcDYC0RYXsTcXDUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSghcJ%2Fbtsk84JbAlv%2FY4GgNjZcDYC0RYXsTcXDUK%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;864&quot; height=&quot;480&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;866&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bafYuW/btsldOK42xg/TBRsNPho1J1OsWDlFjxY50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bafYuW/btsldOK42xg/TBRsNPho1J1OsWDlFjxY50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bafYuW/btsldOK42xg/TBRsNPho1J1OsWDlFjxY50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbafYuW%2FbtsldOK42xg%2FTBRsNPho1J1OsWDlFjxY50%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;866&quot; height=&quot;546&quot; data-origin-width=&quot;866&quot; data-origin-height=&quot;546&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;a href=&quot;https://black7375.tistory.com/86&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;객체지향 시스템과 패러다임 그리고 철학&lt;/a&gt;에서 &quot;&lt;b&gt;없다면&amp;nbsp;실체를&amp;nbsp;생각할&amp;nbsp;수&amp;nbsp;없는&amp;nbsp;것&lt;/b&gt;&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&gt;&lt;span&gt;&lt;span&gt;프로그래밍에 적용해도 비슷하겠습니다&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;.&lt;/span&gt;&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;&lt;span&gt;&lt;span&gt;&lt;span&gt;내용-요지: 만들고자 하는 프로그램에 대한 잠재적 사고&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;표현-요지: 형식화 되지 않은 잠재적 프로그래밍 언어&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;내용-형식: 적절한 형식의 내용인 자료구조와 알고리즘&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;표현-형식: &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;표현방식인 프로그래밍 언어의 문법&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;내용-실체: 해당되는 로직구현&lt;br /&gt;표현-실체: 프로그래밍 언어로의 표현&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;좋다. 그렇다면 2차적 의미가 어떠한 식으로 적용되는가?&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;864&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxLc4d/btslcDpxWDT/0FdhNKikhof2T2q80TNLI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxLc4d/btslcDpxWDT/0FdhNKikhof2T2q80TNLI1/img.png&quot; data-alt=&quot;위와 같다고 한다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxLc4d/btslcDpxWDT/0FdhNKikhof2T2q80TNLI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxLc4d%2FbtslcDpxWDT%2F0FdhNKikhof2T2q80TNLI1%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;864&quot; height=&quot;356&quot; data-origin-width=&quot;864&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;프로그래밍으로 동작하는 서비스도 2차적 의미를 가지고 있겠죠?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EC9CR/btslaZG4Pj1/YIKLGFKNo4KAsRPPLHVT00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EC9CR/btslaZG4Pj1/YIKLGFKNo4KAsRPPLHVT00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EC9CR/btslaZG4Pj1/YIKLGFKNo4KAsRPPLHVT00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEC9CR%2FbtslaZG4Pj1%2FYIKLGFKNo4KAsRPPLHVT00%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;750&quot; height=&quot;422&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;422&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://news.kbs.co.kr/news/view.do?ncd=3097844&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lsquo;기쁨&amp;nbsp;강박증&amp;rsquo;&amp;nbsp;스트레스&amp;hellip;SNS에선&amp;nbsp;모두가&amp;nbsp;행복?&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;s&gt;무서워요&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzD0KG/btsk9Dkff0u/EsAUpkVB0mPI3mo8MS8ccK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzD0KG/btsk9Dkff0u/EsAUpkVB0mPI3mo8MS8ccK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzD0KG/btsk9Dkff0u/EsAUpkVB0mPI3mo8MS8ccK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bzD0KG/btsk9Dkff0u/EsAUpkVB0mPI3mo8MS8ccK/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;477&quot; height=&quot;540&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.signosemio.com/hjelmslev/semiotic-hierarchy.asp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Semiotic&amp;nbsp;Hierarchy&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rh7tk/btslt1xVyQC/vHl1BDmar2G3qxWuRPHmcK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rh7tk/btslt1xVyQC/vHl1BDmar2G3qxWuRPHmcK/img.jpg&quot; data-lazy-src=&quot;&quot; data-width=&quot;600&quot; data-height=&quot;249&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;249&quot; data-is-animation=&quot;false&quot; style=&quot;width: 54.9716%; margin-right: 10px;&quot; data-widthpercent=&quot;55.62&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rh7tk/btslt1xVyQC/vHl1BDmar2G3qxWuRPHmcK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frh7tk%2Fbtslt1xVyQC%2FvHl1BDmar2G3qxWuRPHmcK%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;600&quot; height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/34RPA/btsltVK3OFm/569H5x6JItKpXexqcjTK9K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/34RPA/btsltVK3OFm/569H5x6JItKpXexqcjTK9K/img.gif&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;298&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.8656%;&quot; data-widthpercent=&quot;44.38&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/34RPA/btsltVK3OFm/569H5x6JItKpXexqcjTK9K/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F34RPA%2FbtsltVK3OFm%2F569H5x6JItKpXexqcjTK9K%2Fimg.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;573&quot; height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdOQxB/btslvAsMTKH/GXK2BKS4arFuADYFBOb3Zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdOQxB/btslvAsMTKH/GXK2BKS4arFuADYFBOb3Zk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdOQxB/btslvAsMTKH/GXK2BKS4arFuADYFBOb3Zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdOQxB%2FbtslvAsMTKH%2FGXK2BKS4arFuADYFBOb3Zk%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;1350&quot; height=&quot;479&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.naver.com/zzangdol57/221522787522&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;언어의 구성 요소 (feat. 음운론, 형태론, 통사론, 의미론, 화용론)&lt;/a&gt;, &lt;a href=&quot;https://www.korean.go.kr/nkview/nklife/1988_1/12_7.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;바람직한 언어 교육&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://skyjwoo.tistory.com/entry/%EC%96%B8%EC%96%B4%ED%95%99-%ED%99%94%EC%9A%A9%EB%A1%A0-%ED%99%94%EC%9A%A9%EB%A1%A0%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;화용론이란&amp;nbsp;무엇인가&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; &amp;lsquo;도덕의 지질학&amp;rsquo;에 수용된 과정에 잘 설명되어있으니 생략합니다.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 언어해석과 생성에서 최첨단을 달리는 LLM(Large Language Model)은 엄청난 크기와 비용을 필요로 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://brunch.co.kr/@brunchgpjz/49&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;거대언어모델(LLM)의 현주소&lt;/a&gt;(&lt;a href=&quot;https://velog.io/@kameleon43/%EB%85%BC%EB%AC%B8%EB%A6%AC%EB%B7%B0-A-Survey-of-Large-Language-Models&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;또 다른 요약&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://crossroads.apctp.org/cop/bbs/000000000000/selectArticleDetail.do?nttId=3973&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Scale entanglement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jmagazine.joins.com/forbes/view/337649&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;또 진화한 GPT-4의 위력과 핵심기술&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;767&quot; data-origin-height=&quot;855&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJCdeN/btslbxjhuhv/aNLEickPsCUBKTdTnje39K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJCdeN/btslbxjhuhv/aNLEickPsCUBKTdTnje39K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJCdeN/btslbxjhuhv/aNLEickPsCUBKTdTnje39K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJCdeN%2Fbtslbxjhuhv%2FaNLEickPsCUBKTdTnje39K%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;767&quot; height=&quot;855&quot; data-origin-width=&quot;767&quot; data-origin-height=&quot;855&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2018년에 거대한 사이즈였던 BERT(3억 4천만), GPT(1억 1천만)도 지금은 피라미에 불과합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2023년 기준 PaLM-e(5600억), 작아도 LLaMA(65억 파라미터) 스케일이기 때문입니다.&lt;/p&gt;
&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://arxiv.org/abs/2306.00802&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: #333333; text-align: start;&quot;&gt;상식은 네트워크 넓이, 추론은 네트워크 깊이의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://arxiv.org/abs/2305.07759&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;영향을 받는다&lt;/a&gt;하고 좋은 품질의 데이터를 사용하면 &lt;a href=&quot;https://arxiv.org/abs/2306.11644&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;적은 파라미터로도 좋은 결과&lt;/a&gt;를 낸다고는 합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1000억&amp;nbsp;파라미터를&amp;nbsp;전후하여&amp;nbsp;무엇인가가&amp;nbsp;일어났다.&amp;nbsp;모델의&amp;nbsp;구조와는&amp;nbsp;상관없이,&amp;nbsp;1천억&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;(in-context&amp;nbsp;learning)이라고&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적은 파라미터라고는 하지만 BERT 급만해도 모바일이나 노트북에서 돌리기 어렵습니다.&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;2232&quot; data-origin-height=&quot;1171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O02O7/btslagWRKy5/oiFsP2MIlnmHQEKk5XGsL0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O02O7/btslagWRKy5/oiFsP2MIlnmHQEKk5XGsL0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O02O7/btslagWRKy5/oiFsP2MIlnmHQEKk5XGsL0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO02O7%2FbtslagWRKy5%2FoiFsP2MIlnmHQEKk5XGsL0%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;1833&quot; height=&quot;962&quot; data-origin-width=&quot;2232&quot; data-origin-height=&quot;1171&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/many-tribes-artificial-intelligence-ai-carlos-e-perez&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Many&amp;nbsp;Tribes&amp;nbsp;of&amp;nbsp;Artificial&amp;nbsp;Intelligence&amp;nbsp;(AI)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhz8Si/btsljgOjv24/3MeX3nu2O4Qtia7j7E4b00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhz8Si/btsljgOjv24/3MeX3nu2O4Qtia7j7E4b00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUtaT8%2FbtqMeEXH7oM%2FqJvVRBqxE3UmKz27kOMqmK%2Fimg.png&quot; width=&quot;640&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;610&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-is-animation=&quot;false&quot; style=&quot;width: 61.5095%; margin-right: 10px;&quot; data-widthpercent=&quot;62.23&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhz8Si/btsljgOjv24/3MeX3nu2O4Qtia7j7E4b00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbhz8Si%2FbtsljgOjv24%2F3MeX3nu2O4Qtia7j7E4b00%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;752&quot; height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dyZ4bo/btslat9KxEK/rLpm2oifWUpBrxozUoHXCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dyZ4bo/btslat9KxEK/rLpm2oifWUpBrxozUoHXCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbt7mfi%2FbtqMdFbYiry%2FskgaaI95UZ1XVw0p3KiLsk%2Fimg.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;802&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-is-animation=&quot;false&quot; style=&quot;width: 37.3277%;&quot; data-widthpercent=&quot;37.77&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dyZ4bo/btslat9KxEK/rLpm2oifWUpBrxozUoHXCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdyZ4bo%2Fbtslat9KxEK%2FrLpm2oifWUpBrxozUoHXCK%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;600&quot; height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dbrang.tistory.com/1529&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;이 중에서 가장 대표적인 2개가 고전적인 기호주의와 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;현 LLM 모델의 철학적 기반인 연결주의&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;491&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CKsHx/btslbotiSti/X0LSxFiyt2glQFTfOFC3H0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CKsHx/btslbotiSti/X0LSxFiyt2glQFTfOFC3H0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CKsHx/btslbotiSti/X0LSxFiyt2glQFTfOFC3H0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCKsHx%2FbtslbotiSti%2FX0LSxFiyt2glQFTfOFC3H0%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;491&quot; height=&quot;162&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://wangjieshu.com/2017/12/23/symbol-vs-connectionism-a-closing-gap-in-artificial-intelligence/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Symbolism&amp;nbsp;vs.&amp;nbsp;Connectionism:&amp;nbsp;A&amp;nbsp;Closing&amp;nbsp;Gap&amp;nbsp;in&amp;nbsp;Artificial&amp;nbsp;Intelligence&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;기호주의는 계산주의(Computationalism)라고도 불리는데 저는 계산주의라는 용어를 선호합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 관계를 나타내기 위한 명시적인 룰을 기반으로 하기 때문에 그렇습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEblw7/btslaIyNBtD/4dnUIjPXPc8e2b264bnOw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEblw7/btslaIyNBtD/4dnUIjPXPc8e2b264bnOw0/img.png&quot; width=&quot;584&quot; height=&quot;314&quot; data-recalc-dims=&quot;1&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;314&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.0645%; margin-right: 10px;&quot; data-widthpercent=&quot;55.71&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEblw7/btslaIyNBtD/4dnUIjPXPc8e2b264bnOw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEblw7%2FbtslaIyNBtD%2F4dnUIjPXPc8e2b264bnOw0%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;584&quot; height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GvFYH/btslaSOVbVd/ZJjV3m8D9gCVKYlwOxKqDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GvFYH/btslaSOVbVd/ZJjV3m8D9gCVKYlwOxKqDK/img.png&quot; width=&quot;584&quot; height=&quot;395&quot; data-recalc-dims=&quot;1&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;395&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.7728%;&quot; data-widthpercent=&quot;44.29&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GvFYH/btslaSOVbVd/ZJjV3m8D9gCVKYlwOxKqDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGvFYH%2FbtslaSOVbVd%2FZJjV3m8D9gCVKYlwOxKqDK%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;584&quot; height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Existential Graph와&amp;nbsp; 시맨틱&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;그렇지 않습니다. 때문에 기호주의라기보다는 계산주의라 부르는게 합당하다는 거죠.&lt;/p&gt;
&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VkaMZ/btslbnOIoBX/qS1EiFIEktkMbpgIVKL5Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VkaMZ/btslbnOIoBX/qS1EiFIEktkMbpgIVKL5Fk/img.png&quot; data-alt=&quot;뉴럴 네트워크&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VkaMZ/btslbnOIoBX/qS1EiFIEktkMbpgIVKL5Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVkaMZ%2FbtslbnOIoBX%2FqS1EiFIEktkMbpgIVKL5Fk%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;584&quot; height=&quot;310&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;뉴럴 네트워크&lt;/figcaption&gt;
&lt;/figure&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;li&gt;기호를 해석할 때, 외연(1차적)-내연(2차적)이 합쳐져 의미가 작용할 수 있음&lt;/li&gt;
&lt;li&gt;함축적&amp;nbsp;기호학과&amp;nbsp;메타적&amp;nbsp;기호학으로&amp;nbsp;나뉠&amp;nbsp;수&amp;nbsp;있음&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MBK7a/btslbQC6IXE/sggK1rRaNLGVd5p5egRx2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MBK7a/btslbQC6IXE/sggK1rRaNLGVd5p5egRx2k/img.png&quot; data-origin-width=&quot;1175&quot; data-origin-height=&quot;518&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;65.32&quot; style=&quot;width: 64.5562%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MBK7a/btslbQC6IXE/sggK1rRaNLGVd5p5egRx2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMBK7a%2FbtslbQC6IXE%2FsggK1rRaNLGVd5p5egRx2k%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;1175&quot; height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LaBDd/btslgiFFqFu/ZmbORZO0kJdjzpL5WhhqHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LaBDd/btslgiFFqFu/ZmbORZO0kJdjzpL5WhhqHK/img.png&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;880&quot; data-is-animation=&quot;false&quot; style=&quot;width: 34.281%;&quot; data-widthpercent=&quot;34.68&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LaBDd/btslgiFFqFu/ZmbORZO0kJdjzpL5WhhqHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLaBDd%2FbtslgiFFqFu%2FZmbORZO0kJdjzpL5WhhqHK%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;1060&quot; height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@naem1023/GPT-%EC%96%B8%EC%96%B4-%EB%AA%A8%EB%8D%B8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GPT 언어 모델&lt;/a&gt;, &lt;a href=&quot;https://news.sktelecom.com/178491&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;에이닷에&amp;nbsp;적용된&amp;nbsp;거대언어모델&amp;nbsp;GPT-3가&amp;nbsp;무엇일까?&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; &quot;요지&quot;와 같이 비형식적 부분, 각종 중의적/은유적 표현과 말장난, 농담까지 모두 룰베이스로 처리하기 어렵다고 생각합니다. 제게는 마치 컴파일 타임에 모든 것을 해결하려는 것처럼 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보다 네이티브하게 다룰 수 있을 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%B9%84%EA%B2%B0%EC%A0%95%EB%A1%A0%EC%A0%81_%ED%8A%9C%EB%A7%81_%EA%B8%B0%EA%B3%84&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;h4 data-ke-size=&quot;size20&quot;&gt;몇가지 잡생각들&lt;/h4&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;그렇다고 LLM이 모든 것을 잘 해줄거야는 또 이치에 맞지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스마트폰보다도 느린 프로세서에 1GB램도 안달린 공학용 계산기의 solve() 기능을 현재 LLM이 더 빠르게/정확하게/전력 효율적이게 처리해줄 수 있을까요?&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://en.wikipedia.org/wiki/Elaboration_likelihood_model&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ELM(Elaboration likelihood model)&lt;/a&gt;과&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Heuristic-systematic_model_of_information_processing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HSM(Heuristic-systematic model of information processing)&lt;/a&gt;이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ELM은 관여도에 따른 중심-주변경로, HSM은 휴리스틱에 따른 시스템1-시스템2로 나뉘어집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중 구글은 HSM에 영감을 받아 &lt;a href=&quot;https://news.hada.io/topic?id=9362&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;수학/코딩/논리/추론이 더 좋아졌다&lt;/a&gt;고 합니다.&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;940&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r12m8/btsk9DLP5SU/7XavPMv3lU9unKbRBsvQz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r12m8/btsk9DLP5SU/7XavPMv3lU9unKbRBsvQz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r12m8/btsk9DLP5SU/7XavPMv3lU9unKbRBsvQz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr12m8%2Fbtsk9DLP5SU%2F7XavPMv3lU9unKbRBsvQz0%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;700&quot; height=&quot;940&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;940&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@uxdaysseoul/2%EA%B0%80%EC%A7%80%EC%9D%98-%EC%82%AC%EA%B3%A0-%EB%AA%A8%EB%93%9C-%EC%8B%9C%EC%8A%A4%ED%85%9C-1-%EC%8B%9C%EC%8A%A4%ED%85%9C-2-b22a752163ef&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2가지의&amp;nbsp;사고&amp;nbsp;모드&amp;nbsp;(시스템&amp;nbsp;1,&amp;nbsp;시스템&amp;nbsp;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;근데 이상하죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;추론&quot;과 &quot;계산&quot; 과정은 비용이 더 들어가야 하는데, 계산기는 추론시 비용이 적습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빠르고 무의식적인 시스템1, 제어적이고 규칙기반인 시스템2가 섞여 있는듯이 보이네요?&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;대규모&amp;nbsp;언어&amp;nbsp;모델(LLM)은&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;LLM&amp;nbsp;출력에만&amp;nbsp;의존하는&amp;nbsp;것만으로는&amp;nbsp;충분하지&amp;nbsp;않습니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;이 비유에서 LLM은 순전히 시스템 1에서 작동하는 것으로 생각할 수 있습니다. 텍스트를 빠르게 생성하지만 깊은 생각은 하지 않습니다. 이것은 몇 가지 놀라운 기능으로 이어지지만 몇 가지 놀라운 면에서 부족할 수 있습니다. (시스템 1만 사용하여 수학 문제를 풀려고 한다고 상상해 보십시오. 중단하고 산술을 할 수 없습니다. 마음에 떠오르는 첫 번째 답을 뱉어내면 됩니다.) 전통적인 계산은 시스템 2 사고와 밀접하게 일치합니다. 융통성이 없지만 올바른 단계의 순서는 긴 나눗셈에 대한 솔루션과 같은 인상적인 결과를 생성할 수 있습니다. &lt;br /&gt;&lt;br /&gt;이 최신 업데이트에서는 LLM(시스템 1)과 기존 코드(시스템 2)의 기능을 결합하여 Bard 응답의 정확성을 개선했습니다. 암시적 코드 실행을 통해 Bard는 논리적 코드의 이점을 얻을 수 있는 프롬프트를 식별하고 &quot;내부적으로&quot; 작성하고 실행한 후 그 결과를 사용하여 보다 정확한 응답을 생성합니다. 지금까지 우리는 이 방법이 내부 챌린지 데이터 세트의 계산 기반 단어 및 수학 문제에 대한 Bard의 응답 정확도를 약 30% 향상시키는 것을 확인했습니다.&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;우리가 구구단이나 공식을 외우고서는 계산이 빨라지듯, 기계 입장에서도 규칙적 -&amp;gt; 자동적으로 시스템1 영역인 것 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그치만 단순한 계산이나 코드 실행처럼 딱 정해진 도메인에 대한 판단은 기존 LLM의 영역보다 더 빠르며 다른 특성을 가지고 있습니다.&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;제가 생각한 것은 &quot;경험적 종합 판단&quot;영역에서 &quot;선험적 종합 판단&quot;영역으로 Pre-Training한 무언가 일 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://forum.owlofsogang.com/t/topic/1617/4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://forum.owlofsogang.com/t/topic/1617/4&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1687641726071&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;&amp;quot;직관들에 의한 선험적 종합 인식&amp;quot; 이 무엇인지 모르겠습니다&quot; data-og-description=&quot;제가 비전공자라 확실하게 이해하고 있는지는 모르겠습니다만, 백종현님이 작성하셨던 다른책을 읽어본 경험을 말미암아 이해할때 다음과 같았습니다. 틀린 부분이나 보충할 내용이 있다면 해&quot; data-og-host=&quot;forum.owlofsogang.com&quot; data-og-source-url=&quot;https://forum.owlofsogang.com/t/topic/1617/4&quot; data-og-url=&quot;https://forum.owlofsogang.com/t/topic/1617/4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/MdGJv/hyS6xW5CUI/pqXlk2AJ6v1bUDwfVqc7z1/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/W3oBU/hyS6AsJ2Uq/l64wWWxSkzB1wpzGqLsYA1/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://forum.owlofsogang.com/t/topic/1617/4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://forum.owlofsogang.com/t/topic/1617/4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/MdGJv/hyS6xW5CUI/pqXlk2AJ6v1bUDwfVqc7z1/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/W3oBU/hyS6AsJ2Uq/l64wWWxSkzB1wpzGqLsYA1/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; data-ke-size=&quot;size16&quot;&gt;&quot;직관들에 의한 선험적 종합 인식&quot; 이 무엇인지 모르겠습니다&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;제가 비전공자라 확실하게 이해하고 있는지는 모르겠습니다만, 백종현님이 작성하셨던 다른책을 읽어본 경험을 말미암아 이해할때 다음과 같았습니다. 틀린 부분이나 보충할 내용이 있다면 해&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;forum.owlofsogang.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;System2를 기반한 추론으로 선험적 계산 엔진 생성&lt;/li&gt;
&lt;li&gt;System1의 프롬프트를 학습시킬 때, 계산 엔진을 Literal로 이용할 수 있도록 함&lt;/li&gt;
&lt;li&gt;System1에서 추가적으로 추론이 필요한 경우 System2를 이용하도록 함&lt;/li&gt;
&lt;/ol&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;b&gt;외적탐색&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;경험적(System 1): 직관적 언어 사용&lt;/li&gt;
&lt;li&gt;경험적(System 2): 추론적인 사고&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;하지만&amp;nbsp;내적탐색으로&amp;nbsp;정보가&amp;nbsp;안나오거나&amp;nbsp;실시간&amp;nbsp;정보를&amp;nbsp;반영하려면&amp;nbsp;BingChat처럼&amp;nbsp;외적탐색이&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;899&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yoH5b/btslbyoX59x/7qT7D87XRTASOGSuvivzb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yoH5b/btslbyoX59x/7qT7D87XRTASOGSuvivzb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yoH5b/btslbyoX59x/7qT7D87XRTASOGSuvivzb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyoH5b%2FbtslbyoX59x%2F7qT7D87XRTASOGSuvivzb1%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;899&quot; height=&quot;506&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://thejaehoon.tistory.com/6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;소비자행동론.&amp;nbsp;핵심은&amp;nbsp;관여도와&amp;nbsp;준거집단&amp;nbsp;&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;BingChat 레퍼런스 기능은 정말 좋은데 현재 아쉬운 점은 검색된 정보에 너무 의존한다 느껴진다는 것입니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;현재 페이지나 PDF를 기반으로 알려주는 내용들은 요약 정도&lt;/li&gt;
&lt;li&gt;검색해서 알려주는 내용도 검색에 대한 요약 느낌&lt;/li&gt;
&lt;li&gt;ChatGPT와 비교해 전반적으로 스스로 생각하여 정보를 준다는 느낌이 적음&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 ChatGPT도 오픈 도메인 엑세스를 잘 하던 &lt;a href=&quot;https://en.wikipedia.org/wiki/IBM_Watson&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Watson&lt;/a&gt;을 본받았으면 합니다. [&lt;a href=&quot;http://kibme.org/resources/journal/20180802153415717.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IBM Watson 작동방식에 대한 이해 및 사례 소개&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Watson은 검색엔진말고도 다양한 분야의 지식에 접근하여 활용가능 했었거든요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cl6OyZ/btslaeycvZI/lrj8XfGOCkU1KIAzZFFUNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cl6OyZ/btslaeycvZI/lrj8XfGOCkU1KIAzZFFUNK/img.png&quot; width=&quot;620&quot; height=&quot;415&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;830&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;40.08&quot; data-filename=&quot;blob&quot; style=&quot;width: 39.1466%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cl6OyZ/btslaeycvZI/lrj8XfGOCkU1KIAzZFFUNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcl6OyZ%2FbtslaeycvZI%2Flrj8XfGOCkU1KIAzZFFUNK%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;663&quot; height=&quot;830&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPsSMN/btslcCR7TJn/JYz0oIAeKqXncQ3VzSEJB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPsSMN/btslcCR7TJn/JYz0oIAeKqXncQ3VzSEJB1/img.png&quot; width=&quot;620&quot; height=&quot;415&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;830&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;33.07&quot; data-filename=&quot;blob&quot; style=&quot;width: 32.2974%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPsSMN/btslcCR7TJn/JYz0oIAeKqXncQ3VzSEJB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPsSMN%2FbtslcCR7TJn%2FJYz0oIAeKqXncQ3VzSEJB1%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;547&quot; height=&quot;830&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T9SpJ/btslaJR2hRr/OUyO8tLyEHXP2tzijUGP1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T9SpJ/btslaJR2hRr/OUyO8tLyEHXP2tzijUGP1k/img.png&quot; data-origin-width=&quot;281&quot; data-origin-height=&quot;525&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;26.85&quot; data-filename=&quot;blob&quot; style=&quot;width: 26.2304%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T9SpJ/btslaJR2hRr/OUyO8tLyEHXP2tzijUGP1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT9SpJ%2FbtslaJR2hRr%2FOUyO8tLyEHXP2tzijUGP1k%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;281&quot; height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://writings.stephenwolfram.com/2023/01/wolframalpha-as-the-way-to-bring-computational-knowledge-superpowers-to-chatgpt/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wolfram|Alpha&amp;nbsp;as&amp;nbsp;the&amp;nbsp;Way&amp;nbsp;to&amp;nbsp;Bring&amp;nbsp;Computational&amp;nbsp;Knowledge&amp;nbsp;Superpowers&amp;nbsp;to&amp;nbsp;ChatGPT&lt;/a&gt;, &lt;a href=&quot;https://writings.stephenwolfram.com/2011/01/jeopardy-ibm-and-wolframalpha/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Jeopardy,&amp;nbsp;IBM,&amp;nbsp;and&amp;nbsp;Wolfram|Alpha&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;그래서 정리해보면 근미래에 출연할 LLM 서비스의 모습은 다음과 같이 구성되지 않을까 싶습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;System 1: 시스템이 이용할 선험적 기능들&lt;/li&gt;
&lt;li&gt;System 1: 직관적 언어모델&lt;/li&gt;
&lt;li&gt;System 2: 추론적 사고 모델&lt;/li&gt;
&lt;li&gt;System 2: 외적 탐색 모델&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;284&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQe9oc/btslhdRPLD8/gRhPY0nPL9HoBQa84tjq61/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQe9oc/btslhdRPLD8/gRhPY0nPL9HoBQa84tjq61/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQe9oc/btslhdRPLD8/gRhPY0nPL9HoBQa84tjq61/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQe9oc%2FbtslhdRPLD8%2FgRhPY0nPL9HoBQa84tjq61%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;284&quot; height=&quot;492&quot; data-origin-width=&quot;284&quot; data-origin-height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://m.blog.naver.com/swings81/221008719966&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;논어&amp;nbsp;위정편&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;혹시 이해가 안됐다면 &quot;아~ 완벽히 이해했어!&quot;라고 하는걸로. &lt;s&gt;사실 저도 아무 생각이 없습니다&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8UXuz/btsk9PY3r8W/sk3kqNDD8Up5QY1TeEsJV0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8UXuz/btsk9PY3r8W/sk3kqNDD8Up5QY1TeEsJV0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8UXuz/btsk9PY3r8W/sk3kqNDD8Up5QY1TeEsJV0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8UXuz%2Fbtsk9PY3r8W%2Fsk3kqNDD8Up5QY1TeEsJV0%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;div class=&quot;footnotes&quot;&gt;
  &lt;ol class=&quot;footnotes&quot;&gt;
    &lt;li id=&quot;footnote_95_1&quot;&gt;&lt;a href=&quot;https://ko.wiktionary.org/wiki/%EC%83%9B%EB%B3%84&quot;&gt;샛별&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;위키낱말사전&lt;span&gt;, 2020 &lt;a href=&quot;#footnote_link_95_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_2&quot;&gt;페르디낭 드 소쉬르&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000200470749&quot;&gt;일반언어학 강의&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;김현권 역&lt;span&gt;, &lt;/span&gt;철학의 정원&lt;span&gt;, 2022 &lt;a href=&quot;#footnote_link_95_2&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_3&quot;&gt;질 드뢰즈 &amp;amp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;펠릭스 가타리&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000001396596&quot;&gt;천개의 고원&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;김재인 역&lt;span&gt;, &lt;/span&gt;새물결&lt;span&gt;, 2003 &lt;a href=&quot;#footnote_link_95_3&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_4&quot;&gt;루트비히 비트겐슈타인&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000000848164&quot;&gt;철학적 탐구&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;이승종 역&lt;span&gt;, &lt;/span&gt;아카넷&lt;span&gt;, 2020 &lt;a href=&quot;#footnote_link_95_4&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_5&quot;&gt;정순영&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://www.ajunews.com/view/20150520182238270&quot;&gt;김창렬 &lt;span&gt;H&lt;/span&gt;푸드&amp;rsquo;에 손배소 &amp;ldquo;&lt;span&gt;'&lt;/span&gt;창렬스럽다&lt;span&gt;'&lt;/span&gt;는 &lt;span&gt;'&lt;/span&gt;혜자스럽다&lt;span&gt;'&lt;/span&gt;의 반대 뜻&lt;span&gt;?&amp;rdquo;&lt;/span&gt;&lt;/a&gt;, 아주경제&lt;span&gt;, 2015 &lt;a href=&quot;#footnote_link_95_5&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_6&quot;&gt;이승아&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://jobsn.chosun.com/site/data/html_dir/2021/05/04/2021050401722.html&quot;&gt;잎사귀만 봐도 거품 무는 &lt;span&gt;'&lt;/span&gt;애플&lt;span&gt;'... &lt;/span&gt;세상 사과가 다 제 것인가&lt;span&gt;?&lt;/span&gt;&lt;/a&gt;, 조선일보&lt;span&gt;, 2021 &lt;a href=&quot;#footnote_link_95_6&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_7&quot;&gt;김가영&lt;span&gt;, &lt;a href=&quot;https://www.donga.com/news/Entertainment/article/all/20170810/85774561/2&quot;&gt;&amp;lsquo;&lt;/a&gt;&lt;/span&gt;&lt;a href=&quot;https://www.donga.com/news/Entertainment/article/all/20170810/85774561/2&quot;&gt;혜자롭다&amp;rsquo;&lt;span&gt;X&amp;lsquo;&lt;/span&gt;창렬하다&amp;rsquo; 뭉쳤다&amp;hellip; 누리꾼 &amp;ldquo;신선한 조합&amp;rdquo;&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;동아일보&lt;span&gt;, 2017 &lt;a href=&quot;#footnote_link_95_7&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_8&quot;&gt;장 보드리야르&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://www.yes24.com/Product/Goods/183902&quot;&gt;시뮬라시옹&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;하태환 역&lt;span&gt;, &lt;/span&gt;민음사&lt;span&gt;, 2001 &lt;a href=&quot;#footnote_link_95_8&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_9&quot;&gt;김소정&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://www.chosun.com/national/national_general/2022/05/07/NRQX2TNME5ADNED7Z5U7HVS5RU/&quot;&gt;아무렇지 않게 쓴 &amp;lsquo;창렬하다&amp;rsquo;&amp;hellip;김창열 가족들은 &lt;span&gt;13&lt;/span&gt;년째 &amp;lsquo;속앓이&amp;rsquo;&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;조선일보&lt;span&gt;, 2022 &lt;a href=&quot;#footnote_link_95_9&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_10&quot;&gt;질 들뢰즈&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000000618701&quot;&gt;차이와 반복&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;김상환 역&lt;span&gt;, &lt;/span&gt;민음사&lt;span&gt;, 2004 &lt;a href=&quot;#footnote_link_95_10&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_11&quot;&gt;Maslow, Abraham H, &lt;a href=&quot;https://onlinelibrary.wiley.com/doi/abs/10.1002/j.2164-4683.1991.tb00010.x&quot;&gt;Critique of self-actualization theory&lt;/a&gt;, Thousand Oaks, 1996 &lt;a href=&quot;#footnote_link_95_11&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_12&quot;&gt;Maslow, Abraham H, &lt;a href=&quot;https://www.amazon.com/Farther-Reaches-Human-Nature/dp/0140194703&quot;&gt;The farther reaches of human nature&lt;/a&gt;, New York: The Viking Press, 1971 &lt;a href=&quot;#footnote_link_95_12&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_13&quot;&gt;김재인&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://s-space.snu.ac.kr/handle/10371/121586&quot;&gt;들뢰즈의 비인간주의 존재론&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;서울대학교 대학원&lt;span&gt;, 2013 &lt;a href=&quot;#footnote_link_95_13&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_14&quot;&gt;질 드뢰즈 &amp;amp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;펠릭스 가타리&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000000618682&quot;&gt;안티 오이디푸스&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;김재인 역&lt;span&gt;, &lt;/span&gt;민음사&lt;span&gt;, 2014 &lt;a href=&quot;#footnote_link_95_14&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_15&quot;&gt;보건복지부 국립정신건강센터 &amp;amp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;대한신경정신의학회&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://www.mentalhealth.go.kr/portal/disease/diseaseDetail.do?dissId=73&quot;&gt;거식증&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;국가정신건강정보포털&lt;span&gt;, 2021 &lt;a href=&quot;#footnote_link_95_15&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_16&quot;&gt;西川善司&lt;span&gt;, &lt;/span&gt;&lt;a href=&quot;https://www.4gamer.net/games/341/G034168/20170901120/&quot;&gt;「ゼルダの伝説&lt;span&gt;BotW&lt;/span&gt;」の完璧なゲーム世界は，任天堂の開発スタイルが変わったからこそ生まれた&lt;/a&gt;&lt;span&gt;, 4Gamer.net, 2017 &lt;a href=&quot;#footnote_link_95_16&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_95_17&quot;&gt;김경일&lt;span&gt;, &lt;a href=&quot;https://dbr.donga.com/article/view/1201/article_no/9044/ac/magazine&quot;&gt;&amp;ldquo;&lt;/a&gt;&lt;/span&gt;&lt;a href=&quot;https://dbr.donga.com/article/view/1201/article_no/9044/ac/magazine&quot;&gt;조언해달라&amp;rdquo;는 말로 회의 시작해 보라 평범했던 직원의 잠재력이 터진다&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;동아비지니스리뷰&lt;span&gt;, 2019 &lt;a href=&quot;#footnote_link_95_17&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description>
      <category>개인적인 생각들.</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/95</guid>
      <comments>https://black7375.tistory.com/95#entry95comment</comments>
      <pubDate>Sun, 25 Jun 2023 07:40:36 +0900</pubDate>
    </item>
    <item>
      <title>대략적인 금융 계획.</title>
      <link>https://black7375.tistory.com/94</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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;0. 포인트&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;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;830&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdBxi9/btrXLq8PY8l/gtLMNkCknBkurqEo7afKFK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdBxi9/btrXLq8PY8l/gtLMNkCknBkurqEo7afKFK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdBxi9/btrXLq8PY8l/gtLMNkCknBkurqEo7afKFK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdBxi9%2FbtrXLq8PY8l%2FgtLMNkCknBkurqEo7afKFK%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;830&quot; height=&quot;500&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&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;a href=&quot;https://brunch.co.kr/@dighty/138&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022년&amp;nbsp;간편결제&amp;nbsp;앱&amp;nbsp;18종&amp;nbsp;순위&amp;nbsp;분석&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.card-gorilla.com/contents/detail/1758&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;간편결제의 성장은 신용카드의 종말일까&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 카드&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;신용 vs 체크&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://post.naver.com/viewer/postView.naver?volumeNo=32003036&amp;amp;memberNo=45722825&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;체크카드 vs 신용카드, 나에게 딱 맞는 카드는 무엇일까?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://thisthatbase.com/checkcard-creditcard-difference/&quot;&gt;체크카드&amp;nbsp;신용카드&amp;nbsp;차이&amp;nbsp;및&amp;nbsp;장단점&amp;nbsp;8가지&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.banksalad.com/articles/%EC%8B%A0%EC%9A%A9%EC%B9%B4%EB%93%9C%EC%9D%98-%EC%9E%A5%EC%A0%90%EA%B3%BC-%EB%B0%9C%EA%B8%89%EA%B8%B0%EC%A4%80-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EB%B0%9C%EA%B8%89%EB%B0%A9%EB%B2%95%EA%B9%8C%EC%A7%80-%ED%95%9C%EB%B2%88%EC%97%90-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;신용카드의 장점과 발급기준 그리고 발급방법까지 한번에 알아보자&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://opengov.seoul.go.kr/mediahub/22105909&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;'연말정산&amp;nbsp;꿀팁'&amp;nbsp;신용카드vs체크카드&amp;nbsp;황금비율은?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;784&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkoNKm/btrXJWNHx9S/htZKMMa3rr1hbXjEiR0pvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkoNKm/btrXJWNHx9S/htZKMMa3rr1hbXjEiR0pvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkoNKm/btrXJWNHx9S/htZKMMa3rr1hbXjEiR0pvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkoNKm%2FbtrXJWNHx9S%2FhtZKMMa3rr1hbXjEiR0pvk%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;700&quot; height=&quot;784&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;784&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;그렇다면 관건은 다음과 같을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&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;총 급여 25%가 넘을 시 소득공제 비율이 높음&lt;br /&gt;(체크카드와 현금영수증: 30%, 신용카드: 15%)&lt;/li&gt;
&lt;li&gt;연회비 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&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;각종 혜택&lt;/li&gt;
&lt;li&gt;할부 가능&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 급여 25%가 넘어 소득 공제를 받을 수 있는가와 카드 혜택이 주요 쟁점이다.&lt;/p&gt;
&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;h4 data-ke-size=&quot;size20&quot;&gt;카드 혜택&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ribosome.tistory.com/36&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;현대카드 제로 할인형 vs 포인트형, 뭐가 나을까&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.card-gorilla.com/contents/detail/901&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;적립&amp;nbsp;vs&amp;nbsp;할인,&amp;nbsp;결정장애들을&amp;nbsp;위한&amp;nbsp;알짜카드&amp;nbsp;'KB국민&amp;nbsp;The&amp;nbsp;Easy'&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;또한 포인트 유효기간은 보통 5년이며 사용할 수 있는 곳도 제한되는걸로 알려져 있다.&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;2. 세금&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;연말정산&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.korea.kr/news/reporterView.do?newsId=148898087&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;연말정산을 100% 이해하고 싶다면?!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.ibk.co.kr/2748&quot;&gt;연말정산 대비는 평소에! '소득 공제' 최대로 받는 방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kakaobank.com/bank-story/12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;연말정산 초보자를 위한 필수 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.koreatax.org/tax/taxpayers/work/turn13.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;소득&amp;middot;세액공제 해설&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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://txsi.hometax.go.kr/docs/customer/dictionary/wordList.jsp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;용어사전&lt;/a&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;/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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcItmr/btrXWKSEBIT/vX03Ktp3NK3HkIusRrfod1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcItmr/btrXWKSEBIT/vX03Ktp3NK3HkIusRrfod1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcItmr/btrXWKSEBIT/vX03Ktp3NK3HkIusRrfod1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcItmr%2FbtrXWKSEBIT%2FvX03Ktp3NK3HkIusRrfod1%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;678&quot; height=&quot;480&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;연말정산은 세금을 부과하는 총급여액을 기준으로 계산하므로,&amp;nbsp;&lt;a href=&quot;https://www.nts.go.kr/nts/cm/cntnts/cntntsView.do?mi=6588&amp;amp;cntntsId=7867&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비과세 근로소득&lt;/a&gt;을 제외 [&lt;a href=&quot;https://guide.taxmedicenter.com/32/?q=YToyOntzOjEyOiJrZXl3b3JkX3R5cGUiO3M6MzoiYWxsIjtzOjQ6InBhZ2UiO2k6NDt9&amp;amp;bmode=view&amp;amp;idx=6835851&amp;amp;t=board&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비과세&amp;nbsp;급여에는&amp;nbsp;어떤&amp;nbsp;것이&amp;nbsp;있고,&amp;nbsp;소득자에게&amp;nbsp;어떤&amp;nbsp;영향을&amp;nbsp;주나요?&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;총급여액에서 &lt;a href=&quot;https://www.nts.go.kr/nts/cm/cntnts/cntntsView.do?mi=6592&amp;amp;cntntsId=7871&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;근로소득공제&lt;/a&gt;를 차감&lt;/li&gt;
&lt;li&gt;근로소득금액에서 종합소득공제를 차감 [&lt;a href=&quot;https://help.3o3.co.kr/hc/ko/sections/15029722409369-%EC%86%8C%EB%93%9D%EA%B3%B5%EC%A0%9C-%EA%B8%B0%EC%B4%88-&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;소득공제&amp;nbsp;기초&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;과세표준에서 세액공제를 차감 [&lt;a href=&quot;https://help.3o3.co.kr/hc/ko/sections/15029737545241-%EC%84%B8%EC%95%A1%EA%B3%B5%EC%A0%9C-%EA%B8%B0%EC%B4%88-&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;세액공제 기초&lt;/a&gt;, &lt;a href=&quot;https://www.nts.go.kr/nts/cm/cntnts/cntntsView.do?mi=6596&amp;amp;cntntsId=7875&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;세액공제&lt;/a&gt;, &lt;a href=&quot;https://www.nts.go.kr/nts/cm/cntnts/cntntsView.do?mi=6595&amp;amp;cntntsId=7874&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;특별세액공제&lt;/a&gt;]&lt;/li&gt;
&lt;/ol&gt;
&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2y3et/btrXVx7qE3H/60ux01L9PvXZESOZeKew7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2y3et/btrXVx7qE3H/60ux01L9PvXZESOZeKew7K/img.png&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;480&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2y3et/btrXVx7qE3H/60ux01L9PvXZESOZeKew7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2y3et%2FbtrXVx7qE3H%2F60ux01L9PvXZESOZeKew7K%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;678&quot; height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9eiEV/btrXTQNCO8j/7skfZr2xBRk3wdQxUpHrn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9eiEV/btrXTQNCO8j/7skfZr2xBRk3wdQxUpHrn1/img.png&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;480&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9eiEV/btrXTQNCO8j/7skfZr2xBRk3wdQxUpHrn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9eiEV%2FbtrXTQNCO8j%2F7skfZr2xBRk3wdQxUpHrn1%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;678&quot; height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/div&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;/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;난 식대 월 20만원 정도만 혜택받을 수 있을 듯.&lt;/p&gt;
&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;투자에 가까운 주택청약종합저축, 개인연금저축은 뒤에서 다룰 예정이고, 카드사용에서 살짝 언급되었던 사용금액 공제에 대해 집중적으로 살펴보도록 하자. [&lt;a href=&quot;https://www.koreatax.org/tax/taxpayers/work/turn49.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;신용카드&amp;nbsp;등사&amp;nbsp;용액&amp;nbsp;소득공제&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfQzrg/btrXXzclTJK/z61QVijPxnTNvWBOarQRS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfQzrg/btrXXzclTJK/z61QVijPxnTNvWBOarQRS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfQzrg/btrXXzclTJK/z61QVijPxnTNvWBOarQRS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfQzrg%2FbtrXXzclTJK%2Fz61QVijPxnTNvWBOarQRS0%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;896&quot; height=&quot;432&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;공제금액: (전통시장사용분+대중교통이용분+현금영수증, 직불ㆍ선불카드등사용분+신용카드사용분) - 최저사용금액&lt;/li&gt;
&lt;li&gt;&amp;nbsp;공제순서 : 신용카드사용분 &amp;rarr; 현금영수증, 직불ㆍ선불카드사용분 &amp;rarr; 도서&amp;middot;공연&amp;middot;박물관&amp;middot;미술관 사용분(총급여 7천만원 이하자만 해당) &amp;rarr; 전통시장사용분, 대중교통이용분 &amp;rarr; 소비증가분&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;a href=&quot;https://www.kakaobank.com/bank-story/11&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;꼭&amp;nbsp;알아야&amp;nbsp;할&amp;nbsp;연말정산&amp;nbsp;절세&amp;nbsp;꿀팁&amp;nbsp;7가지&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfVaOH/btrXUWfJeRJ/Th77ah9HN9chwORidqLCi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfVaOH/btrXUWfJeRJ/Th77ah9HN9chwORidqLCi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfVaOH/btrXUWfJeRJ/Th77ah9HN9chwORidqLCi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfVaOH%2FbtrXUWfJeRJ%2FTh77ah9HN9chwORidqLCi1%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;678&quot; height=&quot;480&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;480&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;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;/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;보험료: 12% (한도: 연 100만원)&lt;/li&gt;
&lt;li&gt;의료비: 15% (총급여액의 3% 초과시)&lt;/li&gt;
&lt;li&gt;기부금&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coY9Dl/btrXVhKOjjv/ytVAXyk5zXFINaBy7O7fvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coY9Dl/btrXVhKOjjv/ytVAXyk5zXFINaBy7O7fvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coY9Dl/btrXVhKOjjv/ytVAXyk5zXFINaBy7O7fvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoY9Dl%2FbtrXVhKOjjv%2FytVAXyk5zXFINaBy7O7fvk%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;1034&quot; height=&quot;236&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;236&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youthcenter.go.kr/youngPlcyUnif/youngPlcyUnifList.do?pageUnit=60&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;청년정책 통합검색&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youth.seoul.go.kr/site/main/home&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;청년몽땅정보통&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hrd.go.kr/hrdp/gi/pgiao/PGIAO0302D.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;국민내일배움카드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kua.go.kr/uaptm010/selectMain.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;국민취업지원제도&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nts.go.kr/nts/na/ntt/selectNttInfo.do?mi=2207&amp;amp;nttSn=38033&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;청년&amp;nbsp;중소기업&amp;nbsp;취업자&amp;nbsp;소득세&amp;nbsp;감면&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sbcplan.or.kr/intro.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;청년내일채움공제 / 내일채움공제 / 청년재직자 내일채움공제&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kinfa.or.kr/financialSupport/youthHopeSavings.do#none&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;청년희망적금&lt;/a&gt;(종료), &lt;a href=&quot;https://blog.toss.im/article/high-interest-03&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;청년도약계좌&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;취업지원제도의 경우 취업장려금 50만원을 6개월에 걸쳐주며, 취업성공시 최대 150만원을 추가로 주므로 가능하다면 해보는 것도 좋을듯하다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;751&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q5EsF/btrX2pNZBuX/gZKOxVgjF7Sn80OSn8cYqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q5EsF/btrX2pNZBuX/gZKOxVgjF7Sn80OSn8cYqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q5EsF/btrX2pNZBuX/gZKOxVgjF7Sn80OSn8cYqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ5EsF%2FbtrX2pNZBuX%2FgZKOxVgjF7Sn80OSn8cYqk%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;951&quot; height=&quot;751&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;751&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://tom.yesclub21.net/sub01/01.asp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;내일채움공제와 청년내일채움공제 간단 비교&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LtdZS/btrX0K0hGpK/HDgqZBB0kgoruCITaWS0I1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LtdZS/btrX0K0hGpK/HDgqZBB0kgoruCITaWS0I1/img.jpg&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;560&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LtdZS/btrX0K0hGpK/HDgqZBB0kgoruCITaWS0I1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLtdZS%2FbtrX0K0hGpK%2FHDgqZBB0kgoruCITaWS0I1%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;560&quot; height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPEyca/btrX1AbOg5y/tWakKahEyp9bivTjJ673ek/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPEyca/btrX1AbOg5y/tWakKahEyp9bivTjJ673ek/img.jpg&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;560&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPEyca/btrX1AbOg5y/tWakKahEyp9bivTjJ673ek/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPEyca%2FbtrX1AbOg5y%2FtWakKahEyp9bivTjJ673ek%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;560&quot; height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.korea.kr/news/visualNewsView.do?newsId=148910624&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023년&amp;nbsp;달라지는&amp;nbsp;청년내일채움공제&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;혜택이 다소 적지만 청년도약계좌는 월 70만원씩 5년간 납입하여 4200만원을 만들면 정부가 최대 6% 매칭지원금을 주고, 이자와 배당에 대한 소득을 과세하지 않는다. [&lt;a href=&quot;https://www.yna.co.kr/view/AKR20230128019300002&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;청년도약계좌,&amp;nbsp;소득&amp;nbsp;7천500만원&amp;nbsp;이하면&amp;nbsp;이자&amp;middot;배당&amp;nbsp;비과세&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 출시가 되지 않아서 변경의 여지는 있지만 추후에 나올 ISA(개인종합자산관리) 계좌의 상위호환에 가깝다.&lt;/p&gt;
&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://youth.seoul.go.kr/site/main/content/hd_youth_passbok_intro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;희망두배 청년통장&lt;/a&gt; /&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://youth.seoul.go.kr/site/main/content/hd_youth_passbook_saving&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;청년저축계좌&lt;/a&gt; / &lt;a href=&quot;https://youth.seoul.go.kr/site/main/content/hd_youth_passbook_Passbook&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;청년희망키움통장&lt;/a&gt;등도 있지만 기본적으로 저소득층이 대상이라 가입조건이 매우 까다롭다. [&lt;a href=&quot;https://technicalneers.com/Blog_archives/3128&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2021년&amp;nbsp;희망키움통장1,2,내일키움통장,청년&amp;nbsp;희망키움통장,청년&amp;nbsp;저축계좌&amp;nbsp;비교&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8czez/btrX1yLLea3/uIkSzRHHZSZUo352sarfjk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8czez/btrX1yLLea3/uIkSzRHHZSZUo352sarfjk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8czez/btrX1yLLea3/uIkSzRHHZSZUo352sarfjk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8czez%2FbtrX1yLLea3%2FuIkSzRHHZSZUo352sarfjk%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;906&quot; height=&quot;408&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXKIf3/btrX1wUIotP/pLLgogf8JkLaykKcAzR5OK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXKIf3/btrX1wUIotP/pLLgogf8JkLaykKcAzR5OK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXKIf3/btrX1wUIotP/pLLgogf8JkLaykKcAzR5OK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXKIf3%2FbtrX1wUIotP%2FpLLgogf8JkLaykKcAzR5OK%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;906&quot; height=&quot;506&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;506&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;3. 주택&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;a href=&quot;https://www.kbfg.com/kbresearch/report/reportView.do?reportId=2000360&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022 한국 부자보고서&lt;/a&gt;에 따르면 부동산으로 수익을 얻은 10이상의 금융자산가들이 많다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b30xdH/btrXVkm3KaD/H0n31oNAS3pHd9xMms2ZOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b30xdH/btrXVkm3KaD/H0n31oNAS3pHd9xMms2ZOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b30xdH/btrXVkm3KaD/H0n31oNAS3pHd9xMms2ZOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb30xdH%2FbtrXVkm3KaD%2FH0n31oNAS3pHd9xMms2ZOk%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;799&quot; height=&quot;360&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;360&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;월세액 &amp;amp; 대출&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;a href=&quot;https://www.taxwatch.co.kr/article/tax/2021/01/14/0001&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;'월세액&amp;nbsp;세액공제'의&amp;nbsp;모든&amp;nbsp;것&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;12% (최대 90만원)&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;a href=&quot;https://nhuf.molit.go.kr/FP/FP05/FP0502/FP05020301.jsp&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연 1.5~2.1% (최대 2억원)&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;a href=&quot;https://nhuf.molit.go.kr/FP/FP05/FP0503/FP05030101.jsp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;내집마련디딤돌대출&lt;/a&gt;을 사용할 수 있다. [&lt;a href=&quot;https://blog.toss.im/article/theyoung-loan&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;버팀목대출과&amp;nbsp;디딤돌대출&amp;nbsp;100%&amp;nbsp;활용&amp;nbsp;방법&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인트는 고정금리와 변동금리 선택이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연 2.15~3% (일반 2.5억원)&lt;/li&gt;
&lt;/ul&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;집을 구매할때 이용할 제도는 모두가 아는 &lt;a href=&quot;https://oland.kbstar.com/quics?page=ohsubs#loading&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;주택청약&lt;/a&gt;이다. [&lt;a href=&quot;https://www.ajunews.com/view/20210118192913773&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[주택청약&amp;nbsp;길라잡이]①&amp;nbsp;'주택청약&amp;nbsp;1순위'&amp;nbsp;되기&amp;nbsp;위한&amp;nbsp;기본&amp;nbsp;조건은?&amp;nbsp;&lt;/a&gt;, &lt;a href=&quot;https://www.cardif.co.kr/life-stage/safe-start/cmsContents.do?cmsPath=/cmsHtml/life-stage/LSSAF002M/D001/life_stage_content.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;주택청약,&amp;nbsp;매&amp;nbsp;달&amp;nbsp;얼마씩&amp;nbsp;넣어야할까?&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;여기서도 &lt;a href=&quot;https://oland.kbstar.com/quics?page=C066786&amp;amp;cc=b030657:b029684&amp;amp;isNew=N&amp;amp;prcode=DP01000935#loading&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;최대 연 3.6%에 소득공제(연 240만원 한도)가 주어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 고금리 시대라 청약 순위를 위해서 넣겠지만, 0.5~1%밖에 안되었던 때는 매우 매력적이었다.&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;4. 예적금&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속 한 말이지만 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%95%9C%EA%B5%AD%EC%9D%80%ED%96%89_%EA%B8%B0%EC%A4%80%EA%B8%88%EB%A6%AC&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://glaw.scourt.go.kr/wsjo/lawod/sjo192.do?lawodNm=%EC%A1%B0%EC%84%B8%EA%B0%90%EB%A9%B4%EA%B7%9C%EC%A0%9C%EB%B2%95%EC%8B%9C%ED%96%89%EB%A0%B9&amp;amp;jomunNo=83&amp;amp;jomunGajiNo=&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;세금우대종합저축&lt;/a&gt;을 활용해 3000만원까지는 농어촌특별세 1.4%만 내자. [&lt;a href=&quot;https://www.secbank.co.kr/deposit/taxavoidance.jsp?Pcode=A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;예금절세가이드&lt;/a&gt;, &amp;nbsp;&lt;a href=&quot;https://www.mk.co.kr/news/economy/10465914&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;올해가 마지막 기회&amp;hellip;돈 넣어만 두면 年 7% 이자 준다는데&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 경우 2000만원 이하 금액에는 15.4%(지방소득세 포함), 초과분은 최대 49.5%까지도 세율이 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%83%81%ED%98%B8%EA%B8%88%EC%9C%B5&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;h3 data-ke-size=&quot;size23&quot;&gt;5. 연금저축 vs IRP vs ISA&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.chosun.com/economy/economy_general/2022/04/25/WGZJLAGAOBCY7MFQF4KHRNN334/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;작년말&amp;nbsp;허겁지겁&amp;nbsp;넣으셨죠?&amp;nbsp;봄맞이&amp;nbsp;&amp;lsquo;연금&amp;nbsp;점검&amp;rsquo;&amp;nbsp;꿀팁&amp;nbsp;5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sedaily.com/NewsView/269ZZWEQ0R&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[머니트렌드]절세통장 &quot;연금저축&amp;middot;IRP&amp;middot;ISA 순으로 투자하세요&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.mt.co.kr/mtview.php?no=2021102916362549223&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[부꾸미]무조건&amp;nbsp;연&amp;nbsp;16.5%&amp;nbsp;버는&amp;nbsp;법&amp;hellip;연금계좌&amp;nbsp;활용&amp;nbsp;'꿀팁'&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.hanabank.com/1559&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;1억&amp;nbsp;벌어도&amp;nbsp;세금&amp;nbsp;0원?&amp;nbsp;ISA로&amp;nbsp;주식해야&amp;nbsp;하는&amp;nbsp;이유&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://newsis.com/view/?id=NISX20210730_0001532948&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[국민계좌 부활하나②] 일반 증권계좌와 ISA, 세금 차이는&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://investrabbit.tistory.com/entry/%EC%97%B0%EA%B8%88%EC%A0%80%EC%B6%95-IRP-ISA-%EC%B0%A8%EC%9D%B4%EC%A0%903%EA%B0%80%EC%A7%80-%EC%9E%A5%EB%8B%A8%EC%A0%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;연금저축&amp;nbsp;vs&amp;nbsp;IRP&amp;nbsp;vs&amp;nbsp;ISA&amp;nbsp;차이점3가지&amp;nbsp;및&amp;nbsp;장단점은?&lt;/a&gt;&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;정석대로라면 연금저축 -&amp;gt; IRP -&amp;gt; ISA순으로 투자하라는 말이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 연금저축, IRP는 만 55세까지 유지해야만 한다는 엄청난 단점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주택, 차등 때문에 몫돈이 필요할 수 있는 상황에서 4~5년도 아니라 20년 넘게 기다리기에는 현금 유동성에서 손해가 크다.&lt;/p&gt;
&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;616&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvkyI1/btrX3qtksHJ/eT1xJNsTfPByjlUyUVVYe0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvkyI1/btrX3qtksHJ/eT1xJNsTfPByjlUyUVVYe0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvkyI1/btrX3qtksHJ/eT1xJNsTfPByjlUyUVVYe0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvkyI1%2FbtrX3qtksHJ%2FeT1xJNsTfPByjlUyUVVYe0%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;616&quot; height=&quot;633&quot; data-origin-width=&quot;616&quot; data-origin-height=&quot;634&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;따라서 나는 ISA를 우선시하는게 낫다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주식매매차익 5000만원 이상일때 비과세며, 배당/이자도 200만원 초과시에 9.9%로 엄청난 절세효과가 있다. (보통의 경우 넘기기 쉽지 않다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 만기후 IRP 계좌로 이체하더라도 10%(300만원 한도)를 세액공제받을 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZdGzM/btrX41fi5IE/kkzqGuoHyI7M8EsCNG8Ki1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZdGzM/btrX41fi5IE/kkzqGuoHyI7M8EsCNG8Ki1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0LtqB%2FbtreT3n2zVk%2F9UkUOrzdNAn3nOgPnmgoKk%2Fimg.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;720&quot; data-filename=&quot;인덱스 이미지_01.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZdGzM/btrX41fi5IE/kkzqGuoHyI7M8EsCNG8Ki1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZdGzM%2FbtrX41fi5IE%2FkkzqGuoHyI7M8EsCNG8Ki1%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;720&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHArzz/btrX2opeWhH/7YU72044kMLHTlIdOZ7Fzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHArzz/btrX2opeWhH/7YU72044kMLHTlIdOZ7Fzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTqync%2FbtreWIYd27x%2FfqwQUTPKYKHOsR3FKaEhyK%2Fimg.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;720&quot; data-filename=&quot;인덱스 이미지_02.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHArzz/btrX2opeWhH/7YU72044kMLHTlIdOZ7Fzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHArzz%2FbtrX2opeWhH%2F7YU72044kMLHTlIdOZ7Fzk%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;720&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mTgpZ/btrX3sLvOer/M8tlWaBa2ElIyLXtK5pW71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mTgpZ/btrX3sLvOer/M8tlWaBa2ElIyLXtK5pW71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2eETj%2FbtreMD49YMt%2FkgorIvBnbhKFFjQwm63FE1%2Fimg.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;720&quot; data-filename=&quot;인덱스 이미지_03.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mTgpZ/btrX3sLvOer/M8tlWaBa2ElIyLXtK5pW71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmTgpZ%2FbtrX3sLvOer%2FM8tlWaBa2ElIyLXtK5pW71%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;720&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/div&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o6iMZ/btrX2phrHn9/bodsVyVNuWDkMLmtksuKK0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o6iMZ/btrX2phrHn9/bodsVyVNuWDkMLmtksuKK0/img.jpg&quot; width=&quot;560&quot; data-src=&quot;https://pds.joongang.co.kr/news/component/htmlphoto_mmdata/202009/11/f8b33714-2a56-4bc7-aa23-49a777d05ba0.jpg&quot; data-type=&quot;article&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;812&quot; data-is-animation=&quot;false&quot; style=&quot;width: 27.6513%; margin-right: 10px;&quot; data-widthpercent=&quot;27.98&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o6iMZ/btrX2phrHn9/bodsVyVNuWDkMLmtksuKK0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo6iMZ%2FbtrX2phrHn9%2FbodsVyVNuWDkMLmtksuKK0%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;560&quot; height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sDCeX/btrX2paF7X4/45PtLgXEMKKLpcMzOfW3eK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sDCeX/btrX2paF7X4/45PtLgXEMKKLpcMzOfW3eK/img.jpg&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;383&quot; data-is-animation=&quot;false&quot; style=&quot;width: 71.1859%;&quot; data-widthpercent=&quot;72.02&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sDCeX/btrX2paF7X4/45PtLgXEMKKLpcMzOfW3eK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsDCeX%2FbtrX2paF7X4%2F45PtLgXEMKKLpcMzOfW3eK%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;680&quot; height=&quot;383&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;IRP: 투자가능상품이 비교적 자유로우나 70%까지만 위험자산에 투자가능&lt;/li&gt;
&lt;li&gt;ISA: 투자가능상품이 해외주식을 제외하면 대부분 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 주식, 채권&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주식 vs 채권&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;a href=&quot;https://www.hanwhawm.com/main/finance/guide/TG440_3wt.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;채권과 주식의 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://better-tomorrow.co.kr/skilltip/1514&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;주식과&amp;nbsp;채권&amp;nbsp;어떻게&amp;nbsp;다를까?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;1024&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyGlHp/btrX4lLUkgF/MpZbdqrvjDvVhiQlH4iah1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyGlHp/btrX4lLUkgF/MpZbdqrvjDvVhiQlH4iah1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyGlHp/btrX4lLUkgF/MpZbdqrvjDvVhiQlH4iah1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyGlHp%2FbtrX4lLUkgF%2FMpZbdqrvjDvVhiQlH4iah1%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;960&quot; height=&quot;425&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/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;/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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kookje.co.kr/news2011/asp/newsbody.asp?code=2500&amp;amp;key=20200326.99099010790&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[차호중의 재테크 칼럼]ETN 투자 시 유의점&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://m.blog.naver.com/hoonjaek/221469949318&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;미국 ETF &amp;amp; ETN 상품의 이해&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://post.naver.com/viewer/postView.nhn?volumeNo=24111898&amp;amp;memberNo=40258112&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;'ELS, DLS'가 뭔가요?..안전 자산이라고 믿었던 독일채권의 배신&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://woogie-db.tistory.com/39&quot;&gt;[경제생활]&amp;nbsp;ETF,&amp;nbsp;ELS,&amp;nbsp;ELT,&amp;nbsp;ELF&amp;nbsp;설명&amp;nbsp;및&amp;nbsp;차이점&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://money2.creontrade.com/E5/WTS/Html/fnmall/CW_elsUnderstand.aspx?p=2808&amp;amp;v=2321&amp;amp;m=2084&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ELS 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.iprovest.com/financial/elsdls/elsdlsintro.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ELS/DLS란?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.intn.co.kr/news/articleView.html?idxno=2013379&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;선물(Futures), 증거금 납부하고 매일 종가기준 일일정산&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://m.blog.naver.com/sinjeongcc/221849147064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;선물과 옵션의 차이&lt;/a&gt;&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;뭉그러뜨렸을때 유명한 파생상품으로는 ETF(상장지수펀드, Exchange Traded Fund)와 ETN(상장지수증권, Exchange Traded Note)일 것이다.&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;600&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pfF4G/btrZPT8gZLt/GYVzK2JcpNMsYw4nkfx4tk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pfF4G/btrZPT8gZLt/GYVzK2JcpNMsYw4nkfx4tk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pfF4G/btrZPT8gZLt/GYVzK2JcpNMsYw4nkfx4tk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpfF4G%2FbtrZPT8gZLt%2FGYVzK2JcpNMsYw4nkfx4tk%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;600&quot; height=&quot;319&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E3Iqu/btrZKp1jSXs/WSdo7zV7YKX7zCuk5NRhKk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E3Iqu/btrZKp1jSXs/WSdo7zV7YKX7zCuk5NRhKk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E3Iqu/btrZKp1jSXs/WSdo7zV7YKX7zCuk5NRhKk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE3Iqu%2FbtrZKp1jSXs%2FWSdo7zV7YKX7zCuk5NRhKk%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;800&quot; height=&quot;315&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ETF: 일종의 상장된 펀드로, 포트폴리오대로 지수추종을 가능하게 만들어준다. [추적오차: 고객 부담]&lt;/li&gt;
&lt;li&gt;ETN: 일종의 상장된 채권으로, 기초지수의 수익률을 그대로 지급하는 것을 약속한다. [추적오차: 증권사가 부담]&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;자동적 분산투자와 공매도에 상대적으로 제한적인 개인의 입장에서 가격이 떨어짐에 배팅할 수 있는 인버스가 있다는 점에서 꽤 매력적이다. (기관은 상환기간 무제한에다가 2023년임에도 공매도를 수기로 관리하는 곳이 있다는게 참 ㅋㅋ...)&lt;/p&gt;
&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;a href=&quot;https://blog.toss.im/article/leverage-etf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;레버리지&lt;/a&gt;, &lt;a href=&quot;https://www.kcie.or.kr/guide/3/18/web_view?series_idx=&amp;amp;content_idx=876&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;괴리율&lt;/a&gt;, &lt;a href=&quot;https://m.post.naver.com/viewer/postView.naver?volumeNo=29295875&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ELS(주가연계증권, Equity Linked Securities)과 DLS(파생결합증권, Derivative Linked Securities)도 주목할만한 하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceF6U7/btrZ0KCExrT/dDktYLCI47Ip10hyKuNMl0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceF6U7/btrZ0KCExrT/dDktYLCI47Ip10hyKuNMl0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceF6U7/btrZ0KCExrT/dDktYLCI47Ip10hyKuNMl0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/ceF6U7/btrZ0KCExrT/dDktYLCI47Ip10hyKuNMl0/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;960&quot; height=&quot;264&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ELS: 개별 주식이나 주가 지수에 따라서 수익률이 결정되는 유가증권&lt;/li&gt;
&lt;li&gt;DLS: 이자율, 통화, 실물자산(금, 원유 등), 금리 등 주가 지수가 아닌 다른 걸 기초자산으로 수익률이 결정되는 유가증권&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;ELS가 ETF와 비슷해보이지만 다른 점은 장외 거래 상품이며, ETN과 같이 만기가 있다.&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;700&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b93Nk1/btrZQcNzxGH/jXPs0JJgpB9kIUpj7VQrm1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b93Nk1/btrZQcNzxGH/jXPs0JJgpB9kIUpj7VQrm1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b93Nk1/btrZQcNzxGH/jXPs0JJgpB9kIUpj7VQrm1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb93Nk1%2FbtrZQcNzxGH%2FjXPs0JJgpB9kIUpj7VQrm1%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;700&quot; height=&quot;224&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색해보면 이름이 많이 나와서 헷갈리죠? [ELS, ELB, DLS, DLB]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주식/주가지수와 연계(Linked)가 되면 E(Equity), 나머지(이자율, 통화, 실물자산등)와 연계되면 D(Derivate)가 앞에 붙는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원금이 보장되지 않으면 S(Securities), 보장되면 B(Bond)가 끝에 붙는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원금 보장형(ELB/DLB)은 채권으로&lt;span&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfDPJ4/btrZ0JYfYUg/FpciKPiL8bQtAA5jErdKkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfDPJ4/btrZ0JYfYUg/FpciKPiL8bQtAA5jErdKkK/img.png&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;304&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.5309%; margin-right: 10px;&quot; data-widthpercent=&quot;51.13&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfDPJ4/btrZ0JYfYUg/FpciKPiL8bQtAA5jErdKkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfDPJ4%2FbtrZ0JYfYUg%2FFpciKPiL8bQtAA5jErdKkK%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;609&quot; height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btmr4I/btrZ4bNH6fx/0CJK2P9pemQuBocYDpW0xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btmr4I/btrZ4bNH6fx/0CJK2P9pemQuBocYDpW0xk/img.png&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;318&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.3063%;&quot; data-widthpercent=&quot;48.87&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btmr4I/btrZ4bNH6fx/0CJK2P9pemQuBocYDpW0xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtmr4I%2FbtrZ4bNH6fx%2F0CJK2P9pemQuBocYDpW0xk%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;609&quot; height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;상승 낙아웃 형, 하이파이브형&lt;/figcaption&gt;
&lt;/figure&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만기에&amp;nbsp;주가가&amp;nbsp;하락해도&amp;nbsp;원금보존추구(A)&lt;/li&gt;
&lt;li&gt;최초기준가격과 만기평가가격을 비교하여 참여율에 따라 지급금액 결정(B)&lt;/li&gt;
&lt;li&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;확정(C)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하이파이브(오토콜)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만기 3년, 매 6개월마다 기초자산이 배리어가격 이상이면 원금과 수익을 지급하고 조기상환(A)&lt;/li&gt;
&lt;li&gt;만기평가일까지 상환 조건 미달성 시, 투자기간 동안 한계가격 미만으로 하락한 적이 없으면 원금과 수익지급(B)&lt;/li&gt;
&lt;li&gt;투자기간 동안 한계가격 미만으로 하락 한 적이 있고 만기상환 조건 미 충족 시 만기에 원금 지급(C)&lt;/li&gt;
&lt;/ul&gt;
&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctNslL/btrZJVNhjXx/kShq5gQJZOK3pObm17JXu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctNslL/btrZJVNhjXx/kShq5gQJZOK3pObm17JXu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctNslL/btrZJVNhjXx/kShq5gQJZOK3pObm17JXu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctNslL%2FbtrZJVNhjXx%2FkShq5gQJZOK3pObm17JXu1%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;386&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스텝다운형:&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만기&amp;nbsp;3년,&amp;nbsp;매&amp;nbsp;6개월마다&amp;nbsp;기초자산이&amp;nbsp;배리어가격&amp;nbsp;이상이면&amp;nbsp;원금과&amp;nbsp;수익을&amp;nbsp;지급하고&amp;nbsp;조기상환(A)&lt;/li&gt;
&lt;li&gt;만기평가일까지 상환 조건 미달성 시, 투자기간 동안 한계가격 미만으로 하락한 적이 없으면 원금과 수익지급(B)&lt;/li&gt;
&lt;li&gt;투자기간 동안 한계가격 미만으로 하락 한 적이 있고 만기상환 조건 미 충족 시 만기 손실(C)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XjYZz/btrZNuOPTvt/QdCgvDvS4jhYEZ8ukK1nxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XjYZz/btrZNuOPTvt/QdCgvDvS4jhYEZ8ukK1nxK/img.png&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;294&quot; data-is-animation=&quot;false&quot; style=&quot;width: 54.5413%; margin-right: 10px;&quot; data-widthpercent=&quot;55.18&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XjYZz/btrZNuOPTvt/QdCgvDvS4jhYEZ8ukK1nxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXjYZz%2FbtrZNuOPTvt%2FQdCgvDvS4jhYEZ8ukK1nxK%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;607&quot; height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CBtik/btrZNLbRYCs/v8DgVgGABkPmZKUIQls6kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CBtik/btrZNLbRYCs/v8DgVgGABkPmZKUIQls6kK/img.png&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;362&quot; data-is-animation=&quot;false&quot; style=&quot;width: 44.2959%;&quot; data-widthpercent=&quot;44.82&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CBtik/btrZNLbRYCs/v8DgVgGABkPmZKUIQls6kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCBtik%2FbtrZNLbRYCs%2Fv8DgVgGABkPmZKUIQls6kK%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;607&quot; height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;일일손익 원금부분보장형
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;투자기간 동안 기초자산 주가를 매일 관찰해 주가가 배리어 가격 이상의 날에 대해 절대수익률을 제공하고 배리어 미만 구간에 대해서도 만기 주가에 따라 최대손실률은 제한하면서 주가 상승 이익을 100% 향유함으로써 수익성을 제고시킨 상품&lt;/li&gt;
&lt;/ul&gt;
&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIDoXi/btrZK0tOpc7/9a83bv0rK5BLKkzeaaJXxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIDoXi/btrZK0tOpc7/9a83bv0rK5BLKkzeaaJXxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIDoXi/btrZK0tOpc7/9a83bv0rK5BLKkzeaaJXxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIDoXi%2FbtrZK0tOpc7%2F9a83bv0rK5BLKkzeaaJXxk%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;960&quot; height=&quot;536&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;536&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;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;/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;/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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hankyung.com/finance/article/2021072856161&quot;&gt;&quot;40대부터 안전자산 늘려야&quot; vs &quot;나이 상관말고 주식 비중 70%&quot;&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dndn.io/blog/1187&quot;&gt;주식과 채권을 포트폴리오에 어떤 비중으로 담아야 할까?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;620&quot; data-origin-height=&quot;625&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl6VO6/btrX2VNVFsC/ctiKfHsNj6ZOGDupnitwGK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl6VO6/btrX2VNVFsC/ctiKfHsNj6ZOGDupnitwGK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl6VO6/btrX2VNVFsC/ctiKfHsNj6ZOGDupnitwGK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl6VO6%2FbtrX2VNVFsC%2FctiKfHsNj6ZOGDupnitwGK%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;620&quot; height=&quot;625&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;625&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://www.joongang.co.kr/article/2668087&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크 정석 ① 72의 법칙&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2674066&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재태크 정석 ② 100 - 나이의 법칙&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2681312&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크 정석 ③ 부자지수의 법칙&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2688638&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크 정석 ④ 2080법칙&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2696481&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크&amp;nbsp;정석&amp;nbsp;⑤&amp;nbsp;레버리지&amp;nbsp;효과&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2703846&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크&amp;nbsp;정석&amp;nbsp;⑥정액분할투자&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2719574&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크 정석 ⑦ 비정상적일 땐 즉시 베팅하라&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2734279&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크 정석 ⑧ 손실 많이 봤따면 손절매 과감히&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2735263&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크&amp;nbsp;정석&amp;nbsp;⑨&amp;nbsp;만족&amp;nbsp;지연&amp;nbsp;법칙&amp;nbsp;-&amp;nbsp;당장의&amp;nbsp;수익에&amp;nbsp;연연하지&amp;nbsp;말라&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2741660&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크 정석 ⑩ 풍선효과 활용&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2749522&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크 정석 ⑪ -50=+100의 법칙&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2756451&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크 정석 ⑫ 고위험 고수익 - 돈이 동반되면 위험이 따르기 마련?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2765258&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크&amp;nbsp;정석&amp;nbsp;⑬&amp;nbsp;포트폴리오의&amp;nbsp;중요성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/2771268&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재테크&amp;nbsp;정석&amp;nbsp;⑭&amp;nbsp;적절한&amp;nbsp;보험&amp;nbsp;설계&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안전하게 장기투자를 할 예정이라면 레이달리오의 포트폴리오를 확인해보아도 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FbfN2/btrZSSVX71I/11aCS1bcKWoRH08rSuuHhk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FbfN2/btrZSSVX71I/11aCS1bcKWoRH08rSuuHhk/img.jpg&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;359&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.8101%; margin-right: 10px;&quot; data-widthpercent=&quot;48.37&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FbfN2/btrZSSVX71I/11aCS1bcKWoRH08rSuuHhk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFbfN2%2FbtrZSSVX71I%2F11aCS1bcKWoRH08rSuuHhk%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;632&quot; height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmMCVc/btrZNuhlFIY/kmLnjEi5URnukUySJfpx3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmMCVc/btrZNuhlFIY/kmLnjEi5URnukUySJfpx3K/img.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;545&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.0271%;&quot; data-widthpercent=&quot;51.63&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmMCVc/btrZNuhlFIY/kmLnjEi5URnukUySJfpx3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmMCVc%2FbtrZNuhlFIY%2FkmLnjEi5URnukUySJfpx3K%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;1024&quot; height=&quot;545&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://m.blog.naver.com/ojm3637/220659775164&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코스톨라니 달걀모형으로 보는 거시경제&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://blog.toss.im/article/asset-allocation-etf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;레이달리오처럼&amp;nbsp;투자하기,&amp;nbsp;ETF로&amp;nbsp;하는&amp;nbsp;법&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://finance.naver.com/sise/sise_group.naver?type=upjong&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;업종&lt;/a&gt;/&lt;a href=&quot;https://finance.naver.com/sise/theme.naver&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;a href=&quot;https://www.wiseindex.com/About/WICS&quot;&gt;WICS(Wise Industry Classification Standard)&lt;/a&gt;가 업종을 구분하는 보편적 방법으로 알려져 있으니 확인해보길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미국의 섹터별 유명 기업은 &lt;a href=&quot;https://finviz.com/map.ashx&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;finviz&lt;/a&gt;에서 한눈에 볼 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://kr.investing.com/&quot;&gt;인베스팅&lt;/a&gt;이나&amp;nbsp;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.financialjuice.com/home&quot;&gt;Financial Juice&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;금리&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://m.blog.naver.com/reductionist101/221318829378&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;금리와 환율의 관계 쉽게 이해하기 (+통화량, 화폐가치, 물가)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.toss.im/article/what-is-interest-rate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이자율이&amp;nbsp;뭐지?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.fidelity.co.kr/insight-and-learning/bond-investing-made-simple/how-interest-rates-affect-bonds&quot;&gt;금리가 채권에 미치는 영향&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eiec.kdi.re.kr/material/clickView.do?click_yymm=201512&amp;amp;cidx=1099&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;채권&amp;nbsp;수익률은&amp;nbsp;어떻게&amp;nbsp;결정될까?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;620&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bturkY/btrZ78xvQoo/RGAkWsgjG8G0KssuzCfs21/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bturkY/btrZ78xvQoo/RGAkWsgjG8G0KssuzCfs21/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bturkY/btrZ78xvQoo/RGAkWsgjG8G0KssuzCfs21/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbturkY%2FbtrZ78xvQoo%2FRGAkWsgjG8G0KssuzCfs21%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;620&quot; height=&quot;387&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://v.daum.net/v/20220418172402997&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;'돈의&amp;nbsp;가격'&amp;nbsp;금리&amp;hellip;올리면&amp;nbsp;정말&amp;nbsp;물가&amp;middot;집값이&amp;nbsp;잡힐까&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;그러나 나라마다 상대적으로 매겨지기 때문에 절대적이지 않다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3ESrp/btrZ72RyYgr/Pkexyvri8Cp12CwkA7VhkK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3ESrp/btrZ72RyYgr/Pkexyvri8Cp12CwkA7VhkK/img.jpg&quot; data-lazy-src=&quot;&quot; data-width=&quot;693&quot; data-height=&quot;210&quot; data-top=&quot;1689.9666748046875&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;235&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.1438%; margin-right: 10px;&quot; data-widthpercent=&quot;50.73&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3ESrp/btrZ72RyYgr/Pkexyvri8Cp12CwkA7VhkK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3ESrp%2FbtrZ72RyYgr%2FPkexyvri8Cp12CwkA7VhkK%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;773&quot; height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qRbFt/btr0aVjQBD3/1PEIUPdl3AQgEUUYfr90u0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qRbFt/btr0aVjQBD3/1PEIUPdl3AQgEUUYfr90u0/img.jpg&quot; data-lazy-src=&quot;&quot; data-width=&quot;693&quot; data-height=&quot;216&quot; data-top=&quot;2139&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;242&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.6934%;&quot; data-widthpercent=&quot;49.27&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qRbFt/btr0aVjQBD3/1PEIUPdl3AQgEUUYfr90u0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqRbFt%2Fbtr0aVjQBD3%2F1PEIUPdl3AQgEUUYfr90u0%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;773&quot; height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/div&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;&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;h4 data-ke-size=&quot;size20&quot;&gt;재무재표와 지수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&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;&lt;a href=&quot;https://blog.naver.com/jhpark3310/222792572329&quot;&gt;주식 매수 타이밍을 확인하는 지수 (PER / Shiller / 버핏 지수)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.fidelity.co.kr/insight-and-learning/learn-about-investing/what-is-volatility/volatility-index&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;VIX변동성&amp;nbsp;지수에&amp;nbsp;대하여&amp;nbsp;투자자가&amp;nbsp;알아야&amp;nbsp;할&amp;nbsp;것들&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주식시장이 과열인지 저평가인지를 확인하는 주된 방법들입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버핏지수: 시가총액 / GDP로 7~80%면 저평가이며 100~125%면 적절하다고 판단 [&lt;a href=&quot;https://www.gurufocus.com/global-market-valuation.php&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;버핏지수 확인&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;CAPE(쉴러 PE): 아래 나올 PER과 비슷하며 미국의 경우 20~30 정도가 적절한 값으로 판단 [&lt;a href=&quot;https://www.multpl.com/shiller-pe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CAPE 지수 확인&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;VIX 지수: 시카고 옵션거래소 변동성 지수로 20 미만이면 안정적, 30이상이면 공포로 인한 변동성이 크다 판단&amp;nbsp; [&lt;a href=&quot;https://www.barchart.com/stocks/quotes/$VIX&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VIX 지수 확인&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Fear&amp;amp;Greed 지수: VIX + a로 만들었으며 공포와 탐욕이 직관적으로 표시되어 있음 [&lt;a href=&quot;https://edition.cnn.com/markets/fear-and-greed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fear&amp;amp;Greed 지수 확인&lt;/a&gt;]&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;b&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;&lt;a href=&quot;https://blog.hanabank.com/1645&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;투자를&amp;nbsp;위한&amp;nbsp;필수&amp;nbsp;지식!&amp;nbsp;재무제표&amp;nbsp;보는&amp;nbsp;방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sirius-library.oopy.io/series/financial_statements&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재무제표&amp;nbsp;기초&lt;/a&gt;&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;b&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;&lt;a href=&quot;https://www.mk.co.kr/premium/special-report/view/2021/05/30208/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;주식투자하면서&amp;nbsp;PER&amp;nbsp;PBR&amp;nbsp;ROE도&amp;nbsp;모른다고?&amp;nbsp;[7화]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gangsanilee.tistory.com/2603&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[주식용어]&amp;nbsp;ROE,&amp;nbsp;PBR,PER&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.waytoliah.com/1532&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[주식 종목 분석] 'PER, PBR, EPS, BPS, ROE' 의미 해석과 계산 방법&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://post.naver.com/viewer/postView.nhn?volumeNo=31010729&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;저PER주라고&amp;nbsp;사니?&amp;nbsp;나는&amp;nbsp;다&amp;nbsp;따져보고&amp;nbsp;산다.&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PER, PBR, ROE를 통해 가치가 과장되었는가를 생각해볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-23.png&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGrkCk/btrX32Mz3QY/PnqxKxVWsqgkV4qZpAoWx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGrkCk/btrX32Mz3QY/PnqxKxVWsqgkV4qZpAoWx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGrkCk/btrX32Mz3QY/PnqxKxVWsqgkV4qZpAoWx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGrkCk%2FbtrX32Mz3QY%2FPnqxKxVWsqgkV4qZpAoWx1%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;573&quot; height=&quot;390&quot; data-filename=&quot;image-23.png&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;557&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PER: 주가 수익 비율로, 1주당 수익이 몇 배가 되는지 [낮다면 저평가]&lt;/li&gt;
&lt;li&gt;PBR: 주가 순자산비율로, 자산 대비 1주당 주가가 몇 배인지 [낮다면 장부가치보다 주가가 낮음]&lt;/li&gt;
&lt;li&gt;ROE:&amp;nbsp; 자기 자본 이익룰로, 자본 대비 얼마나 이익을 냈는지 [높다면 마진을 많이 남김]&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;680&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccSy0L/btrZ7Fif7Mz/JcNYlt3I4Cm4ZKhKIgAzJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccSy0L/btrZ7Fif7Mz/JcNYlt3I4Cm4ZKhKIgAzJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccSy0L/btrZ7Fif7Mz/JcNYlt3I4Cm4ZKhKIgAzJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccSy0L%2FbtrZ7Fif7Mz%2FJcNYlt3I4Cm4ZKhKIgAzJ0%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;876&quot; height=&quot;680&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;680&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;b&gt;기술적 지표&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://black7375.tumblr.com/post/169475967045/%EC%B4%88%EA%B0%84%EB%8B%A8-%EC%A3%BC%EC%8B%9D%EC%B0%A8%ED%8A%B8-%EB%B3%B4%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;초간단 주식차트보기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hi-ib.com/systemtrade/st020901.jsp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;기술적&amp;nbsp;분석이란?&lt;/a&gt;&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;a href=&quot;https://kr.investing.com/&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;h4 data-ke-size=&quot;size20&quot;&gt;해외주식&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hankyung.com/economy/article/2022071082121&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;해외주식 250만원 넘게 벌었다면&amp;hellip;'손실 종목' 팔고 다시 사라&amp;nbsp;&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경험적으로든 데이터든 수익률 차이가 크기 때문이다. [&lt;a href=&quot;https://www.hankyung.com/finance/article/2023021973231&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&quot;코스피,&amp;nbsp;장투할&amp;nbsp;이유가&amp;nbsp;없다&quot;&amp;hellip;10년&amp;nbsp;수익률&amp;nbsp;글로벌&amp;nbsp;'꼴찌'&amp;nbsp;&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;&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;해외주식 양도세 기준은 연간 250만원이상의 순수익을 얻었을때다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지방소득세까지 합해 22%나되는 세금이 붙는데, 만약 마이너스인 종목을 매도해 250만원 이하로 내려가도록 상쇄할 수 있다면 양도세를 안낼 수 있다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://newsmt.co.kr/mtview.php?no=2020062517344662675&quot;&gt;새로운&amp;nbsp;세금,&amp;nbsp;금융투자소득세가&amp;nbsp;온다&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.mt.co.kr/mtview.php?no=2022072115110530514&quot;&gt;&quot;주식&amp;middot;코인&amp;nbsp;소득세&amp;nbsp;모두&amp;nbsp;2년&amp;nbsp;연기&quot;...2024년&amp;nbsp;총선&amp;nbsp;이후로&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joongang.co.kr/article/25011854&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;매달 200만원 따박따박 받으려면&amp;hellip;배당금 종잣돈 얼마&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 배당주들을 원하는 사람들이 늘어나고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 은행, 통신주, 소비재가 대표적인 배당주고 지수추종에는 SCHD, JEPI, JEPQ, SPHD정도가 유명한 것 같다.&lt;/p&gt;
&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 data-ke-size=&quot;size23&quot;&gt;7. 보험&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://eiec.kdi.re.kr/material/clickView.do?click_yymm=201512&amp;amp;cidx=1024&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;보험의&amp;nbsp;종류&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.medibloc.org/timeline/content/insurance/9968&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;생명보험&amp;nbsp;vs&amp;nbsp;손해보험,&amp;nbsp;뭐가&amp;nbsp;달라요?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cidermics.com/contents/detail/1502&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;'실비보험' 올해부터 달라지는 것 3가지! [2018]&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생명보험 vs 손해보험 vs 제 3보험&lt;/h4&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;1024&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IJu6q/btr0r6NuxLc/HVcnK7XeROrwuWYoCnlqJK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IJu6q/btr0r6NuxLc/HVcnK7XeROrwuWYoCnlqJK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IJu6q/btr0r6NuxLc/HVcnK7XeROrwuWYoCnlqJK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIJu6q%2Fbtr0r6NuxLc%2FHVcnK7XeROrwuWYoCnlqJK%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;1024&quot; height=&quot;576&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&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;br /&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;보장: 약속된 목돈&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;예:&amp;nbsp;암,&amp;nbsp;종신,&amp;nbsp;건강보험&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;제 3보험
&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;/ul&gt;
&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;/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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생명보험 &amp;gt; 손해보험&lt;/li&gt;
&lt;li&gt;종합실비 &amp;gt; 단독실비&lt;/li&gt;
&lt;li&gt;저축형 &amp;gt; 보장형&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;/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;만약 손해보험을 들었는데 매달 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;&lt;br /&gt;저축형은 만기가 되면 돌려주는데 중간에 보험사가 운용을 하고 이자를 추가로 넣어 돌려준다.&lt;br /&gt;개인적으로 이자 몇 푼 받으려 보험료를 더 내기보다는 컴팩트한게 좋다.&lt;br /&gt;&quot;투자&quot;를&amp;nbsp;하려면&amp;nbsp;주식,&amp;nbsp;채권,&amp;nbsp;예금,&amp;nbsp;적금을&amp;nbsp;하는게..&lt;/p&gt;</description>
      <category>기타 정보</category>
      <category>투자</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/94</guid>
      <comments>https://black7375.tistory.com/94#entry94comment</comments>
      <pubDate>Mon, 30 Jan 2023 11:34:31 +0900</pubDate>
    </item>
    <item>
      <title>더 나은 Git 워크플로우를 향해서</title>
      <link>https://black7375.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 몇개월간 Git 활용이 일진보한듯 하여 몇글자 적어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 레포구조&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/ko/v2/%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-%EB%B2%84%EC%A0%84-%EA%B4%80%EB%A6%AC%EB%9E%80%3F&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;시작하기 - 버전 관리란?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/ko/v2/%EB%B6%84%EC%82%B0-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C%EC%9D%98-Git-%EB%B6%84%EC%82%B0-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C%EC%9D%98-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;분산&amp;nbsp;환경에서의&amp;nbsp;Git&amp;nbsp;-&amp;nbsp;분산&amp;nbsp;환경에서의&amp;nbsp;워크플로&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃은 분산 버전 관리 시스템(Distributed Version Control Systems)이기 때문에 각 컴퓨터마다 레포지토리를 가질 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7n5x5/btsdc78cZEj/OrRHJe2CdkvX5jZOT5M5Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7n5x5/btsdc78cZEj/OrRHJe2CdkvX5jZOT5M5Kk/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;683&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.2079%; margin-right: 10px;&quot; data-widthpercent=&quot;34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7n5x5/btsdc78cZEj/OrRHJe2CdkvX5jZOT5M5Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7n5x5%2Fbtsdc78cZEj%2FOrRHJe2CdkvX5jZOT5M5Kk%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;800&quot; height=&quot;683&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TsqcN/btsddThldkC/Zg54zQ1MtvZdtxHk9phEa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TsqcN/btsddThldkC/Zg54zQ1MtvZdtxHk9phEa0/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;556&quot; data-is-animation=&quot;false&quot; style=&quot;width: 40.7932%; margin-right: 10px;&quot; data-widthpercent=&quot;41.76&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TsqcN/btsddThldkC/Zg54zQ1MtvZdtxHk9phEa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTsqcN%2FbtsddThldkC%2FZg54zQ1MtvZdtxHk9phEa0%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;800&quot; height=&quot;556&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHuQsb/btsddtQHEST/B3QuklM8m8gyGs5wv3SLk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHuQsb/btsddtQHEST/B3QuklM8m8gyGs5wv3SLk0/img.png&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;800&quot; data-is-animation=&quot;false&quot; style=&quot;width: 23.6733%;&quot; data-widthpercent=&quot;24.24&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHuQsb/btsddtQHEST/B3QuklM8m8gyGs5wv3SLk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHuQsb%2FbtsddtQHEST%2FB3QuklM8m8gyGs5wv3SLk0%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;668&quot; height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/div&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE0BwJ/btsdhy4vO8Y/pgZBAhVYbKSCbChXykSwbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE0BwJ/btsdhy4vO8Y/pgZBAhVYbKSCbChXykSwbK/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;345&quot; data-is-animation=&quot;false&quot; style=&quot;width: 31.2107%; margin-right: 10px;&quot; data-widthpercent=&quot;31.95&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE0BwJ/btsdhy4vO8Y/pgZBAhVYbKSCbChXykSwbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE0BwJ%2Fbtsdhy4vO8Y%2FpgZBAhVYbKSCbChXykSwbK%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;800&quot; height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SJUOL/btsddkfmBR7/iLQ6ck4HmXXkUN79bhjRdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SJUOL/btsddkfmBR7/iLQ6ck4HmXXkUN79bhjRdk/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;267&quot; data-is-animation=&quot;false&quot; style=&quot;width: 40.3285%; margin-right: 10px;&quot; data-widthpercent=&quot;41.29&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SJUOL/btsddkfmBR7/iLQ6ck4HmXXkUN79bhjRdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSJUOL%2FbtsddkfmBR7%2FiLQ6ck4HmXXkUN79bhjRdk%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;800&quot; height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPTAa2/btsdi3b72fK/EMZ9ALKY9TN101nHrIx1HK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPTAa2/btsdi3b72fK/EMZ9ALKY9TN101nHrIx1HK/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;412&quot; data-is-animation=&quot;false&quot; style=&quot;width: 26.1352%;&quot; data-widthpercent=&quot;26.76&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPTAa2/btsdi3b72fK/EMZ9ALKY9TN101nHrIx1HK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPTAa2%2Fbtsdi3b72fK%2FEMZ9ALKY9TN101nHrIx1HK%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;800&quot; height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/div&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;메인테이너 밑의 관리자가 각자 분야의 기여를 받고, 최종적으로 메인테이너가 관리자 레포를 merge하는 식으로 운용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 다양한 방식으로 구성할 수 있다는 점은 DVCS의 커다란 매력이다.&lt;/p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://z.github.io/whygitisbetter/#easy-to-learn&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Why&amp;nbsp;Git&amp;nbsp;is&amp;nbsp;Better&amp;nbsp;than&amp;nbsp;X&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 브랜치 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브랜치(분기) 전략은 Git의 처음과 끝이다.&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;1600&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhXUH3/btrWml0SlW7/r30j881KZFckLprzYVr9e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhXUH3/btrWml0SlW7/r30j881KZFckLprzYVr9e0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhXUH3/btrWml0SlW7/r30j881KZFckLprzYVr9e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhXUH3%2FbtrWml0SlW7%2Fr30j881KZFckLprzYVr9e0%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;771&quot; height=&quot;724&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://articles.alfa1.com/hello-serverless-goodbye-git-flow&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hello&amp;nbsp;Serverless,&amp;nbsp;Goodbye&amp;nbsp;Git&amp;nbsp;Flow&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;추후 나올 Master, Main, Mainline, Trunk는 모두 동일하게 쓰인다.&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;GitHub Flow&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 개발자들이 가장 쉽게 익힐만한 방식, &lt;a href=&quot;https://docs.github.com/en/get-started/quickstart/github-flow&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Github flow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8sGsX/btrWcLtSytZ/KECGevC2FDDaxdSKrj5Qs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8sGsX/btrWcLtSytZ/KECGevC2FDDaxdSKrj5Qs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8sGsX/btrWcLtSytZ/KECGevC2FDDaxdSKrj5Qs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8sGsX%2FbtrWcLtSytZ%2FKECGevC2FDDaxdSKrj5Qs1%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;900&quot; height=&quot;506&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://build5nines.com/introduction-to-git-version-control-workflow/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introduction&amp;nbsp;to&amp;nbsp;Git&amp;nbsp;Version&amp;nbsp;Control&amp;nbsp;Workflow&lt;/a&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;기능이나 버그 브랜치 만들기&lt;/li&gt;
&lt;li&gt;풀리퀘스트 생성&lt;/li&gt;
&lt;li&gt;피드백 받아 고치기&lt;/li&gt;
&lt;li&gt;병합&lt;/li&gt;
&lt;/ol&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;583&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBTvli/btrWmmerCO7/6wj2Kkdo9pCnenDDS5Aoh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBTvli/btrWmmerCO7/6wj2Kkdo9pCnenDDS5Aoh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBTvli/btrWmmerCO7/6wj2Kkdo9pCnenDDS5Aoh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBTvli%2FbtrWmmerCO7%2F6wj2Kkdo9pCnenDDS5Aoh1%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;583&quot; height=&quot;276&quot; data-origin-width=&quot;583&quot; data-origin-height=&quot;276&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.programster.org/git-workflows&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git&amp;nbsp;Workflows&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;h3 data-ke-size=&quot;size23&quot;&gt;Git Flow&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 사람들이 들어봤을 Git flow다. [&lt;a href=&quot;https://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;A&amp;nbsp;successful&amp;nbsp;Git&amp;nbsp;branching&amp;nbsp;model&lt;/a&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3Sxms/btrWmnRWzme/tKbq20Qhax3y6f6E16KUnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3Sxms/btrWmnRWzme/tKbq20Qhax3y6f6E16KUnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3Sxms/btrWmnRWzme/tKbq20Qhax3y6f6E16KUnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3Sxms%2FbtrWmnRWzme%2FtKbq20Qhax3y6f6E16KUnK%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;781&quot; height=&quot;410&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Feature 브랜치에서 개발해 Develop 브랜치에 병합&lt;/li&gt;
&lt;li&gt;Develope 브랜치가 충분히 성숙하면 Release(Stage) 생성&lt;/li&gt;
&lt;li&gt;Release 브랜치에서는 버그 수정만&lt;/li&gt;
&lt;li&gt;Release가 준비되면 Master에 병합하고, 릴리즈!!&lt;/li&gt;
&lt;li&gt;릴리즈 후, 핫픽스가 생기면 다시 릴리즈하고 Develope 브랜치에도 적용&lt;/li&gt;
&lt;/ol&gt;
&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;h3 data-ke-size=&quot;size23&quot;&gt;Gitlab Flow와 Perforce Stream&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GUI에서 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Glossary/MVC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MVC&lt;/a&gt; -&amp;gt; &lt;a href=&quot;https://facebook.github.io/flux/docs/in-depth-overview/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Flux 아키텍쳐&lt;/a&gt;처럼 선형적으로 넘어가는 것처럼 흐름을 보다 단순히 만들어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Develop, Stage, Master는 장기적으로 유지되고, Feature, Bug, Hotfix는 단기적으로 유지하는 건 어떨까?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lbscO/btrWeXG3lG7/SUZKNBD8WiJCylTmYCqpX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lbscO/btrWeXG3lG7/SUZKNBD8WiJCylTmYCqpX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lbscO/btrWeXG3lG7/SUZKNBD8WiJCylTmYCqpX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlbscO%2FbtrWeXG3lG7%2FSUZKNBD8WiJCylTmYCqpX1%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;700&quot; height=&quot;394&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;보통 &lt;a href=&quot;https://docs.gitlab.com/ee/topics/gitlab_flow.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gitlab flow&lt;/a&gt;라고 부른다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;415&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AVgYO/btrWc23mcK8/kkAk3BOFHiZJIfjibF1nhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AVgYO/btrWc23mcK8/kkAk3BOFHiZJIfjibF1nhK/img.png&quot; data-alt=&quot;Gitlab flow&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AVgYO/btrWc23mcK8/kkAk3BOFHiZJIfjibF1nhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAVgYO%2FbtrWc23mcK8%2FkkAk3BOFHiZJIfjibF1nhK%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;802&quot; height=&quot;415&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;415&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Gitlab flow&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Hotfix를 Develop, Stage, Master에 모두 병합하는 대신 양옆의 2개에만 하기&lt;/li&gt;
&lt;li&gt;Github Flow처럼 Develop을 Master로 하기 (경우에 따라 Staging을 Master로 할 수 도?)&lt;/li&gt;
&lt;/ol&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 워크플로우에 한층 가깝게 만든다면 Perforce의 Stream도 좋은 예다.&amp;nbsp;[&lt;a href=&quot;https://www.perforce.com/solutions/version-control/branching-brains&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What&amp;nbsp;Is&amp;nbsp;Perforce&amp;nbsp;Streams?&lt;/a&gt;, &lt;a href=&quot;https://www.perforce.com/video-tutorials/vcs/codelines-and-streams&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Codelines&amp;nbsp;and&amp;nbsp;Streams&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Github 워크플로우와 차이라면 명확한 역할이 정해져 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/celeHB/btrWllmAkAP/UeuzM3hhEWfMWeIlTqByWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/celeHB/btrWllmAkAP/UeuzM3hhEWfMWeIlTqByWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/celeHB/btrWllmAkAP/UeuzM3hhEWfMWeIlTqByWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceleHB%2FbtrWllmAkAP%2FUeuzM3hhEWfMWeIlTqByWk%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;681&quot; height=&quot;254&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Release, Main(master), Develop으로 구성&lt;/li&gt;
&lt;li&gt;Release에서는 버그를 고쳐 Main 방향으로 전파 (Merge Down)&lt;/li&gt;
&lt;li&gt;Main도 Develop으로 전파, 기능이 만들어지면 충돌을 없애고 Main에 반영&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Trunk 기반&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Trunk 기반 개발은 Main(Master)를 보다 효율적으로 사용하기위한 방법이다. [&lt;a href=&quot;https://launchdarkly.com/blog/git-branching-strategies-vs-trunk-based-development/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git&amp;nbsp;Branching&amp;nbsp;Strategies&amp;nbsp;vs.&amp;nbsp;Trunk-Based&amp;nbsp;Development&lt;/a&gt;, &amp;nbsp;&lt;a href=&quot;https://trunkbaseddevelopment.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Trunk Based Development&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Main 브랜치만 오래 유지해 충돌이 줄이는데, 구글과 페이스북 규모에서 많이 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ygUDY/btrWpZXHBO0/YKIFMWP31pZTN48IciPwok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ygUDY/btrWpZXHBO0/YKIFMWP31pZTN48IciPwok/img.png&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;183&quot; data-is-animation=&quot;false&quot; style=&quot;width: 63.0046%; margin-right: 10px;&quot; data-widthpercent=&quot;63.75&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ygUDY/btrWpZXHBO0/YKIFMWP31pZTN48IciPwok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FygUDY%2FbtrWpZXHBO0%2FYKIFMWP31pZTN48IciPwok%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;712&quot; height=&quot;183&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJr8yu/btrWoqBfoN1/hgFnLdhEWcE5GG0MD4nBOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJr8yu/btrWoqBfoN1/hgFnLdhEWcE5GG0MD4nBOK/img.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;329&quot; data-is-animation=&quot;false&quot; style=&quot;width: 35.8326%;&quot; data-widthpercent=&quot;36.25&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJr8yu/btrWoqBfoN1/hgFnLdhEWcE5GG0MD4nBOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJr8yu%2FbtrWoqBfoN1%2FhgFnLdhEWcE5GG0MD4nBOK%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;728&quot; height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfVeo8/btrWjkO6HLf/RocMJ8yJjQlFp4Dj0LjAp0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfVeo8/btrWjkO6HLf/RocMJ8yJjQlFp4Dj0LjAp0/img.jpg&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;1081&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfVeo8/btrWjkO6HLf/RocMJ8yJjQlFp4Dj0LjAp0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfVeo8%2FbtrWjkO6HLf%2FRocMJ8yJjQlFp4Dj0LjAp0%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;1921&quot; height=&quot;1081&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbYAR2/btrWnowHdFQ/XzBKUcLONshPpfSBuU8j80/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbYAR2/btrWnowHdFQ/XzBKUcLONshPpfSBuU8j80/img.jpg&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;1081&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbYAR2/btrWnowHdFQ/XzBKUcLONshPpfSBuU8j80/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbYAR2%2FbtrWnowHdFQ%2FXzBKUcLONshPpfSBuU8j80%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;1921&quot; height=&quot;1081&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Main만 장기유지 Branch로 사용&lt;/li&gt;
&lt;li&gt;다른 Branch들은 짧게 유지&lt;/li&gt;
&lt;li&gt;기능은 플래그를 사용해 Off 상태로 병합해 항상 최신 코드 유지&lt;/li&gt;
&lt;li&gt;CI/CD를 적극적으로 활용&lt;/li&gt;
&lt;/ol&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Staging 과정이 필요하면 Gitlab flow, 아니라면 Trunk 기반이 합리적으로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 커밋&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨벤션&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://www.conventionalcommits.org/ko/v1.0.0/&quot;&gt;Conventional&amp;nbsp;Commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ec.europa.eu/component-library/v1.15.0/eu/docs/conventions/git/&quot;&gt;Git Commit Guidelines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 타입에 fix:[버그수정]와 feat:[기능추가]을 사용하며, 앵귤러 컨벤션을 따라 docs:[문서수정] style:[포매팅] refactor:[리펙토링] perf:[성능향상] test:[테스트] chore:[툴링], bump:[패키지 버전업] 등을 사용하는 경우가 일반적이다.&lt;/p&gt;
&lt;pre id=&quot;code_1673855251786&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.25091578610560883&quot;&gt;&lt;code&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입에 이모지 사용: 개인적으로 터미널에서 입력하기 까다로워 불호이나 &lt;a href=&quot;https://github.com/carloscuesta/gitmoji&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gitmoji&lt;/a&gt; 툴을 써볼 수 있다&lt;/li&gt;
&lt;li&gt;개인적으로 &quot;feat(api): send email to the customer&quot;보다 &quot;Feat: API - Send email to the customer&quot;처럼 대문자로 위계를 주고, 적용범위는 대시를 사용하는 방식를 좋아한다&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;279&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l09MS/btrWqQtssGw/kePHCxVhOc6QDewEKjuRFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l09MS/btrWqQtssGw/kePHCxVhOc6QDewEKjuRFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l09MS/btrWqQtssGw/kePHCxVhOc6QDewEKjuRFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl09MS%2FbtrWqQtssGw%2FkePHCxVhOc6QDewEKjuRFk%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;1090&quot; height=&quot;279&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;279&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단위&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 커밋은 최소 단위별로 되어야 한다. [&lt;a href=&quot;https://tech.10000lab.xyz/git/git-commit-discipline.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;깃(Git)&amp;nbsp;커밋&amp;nbsp;가이드&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;사실 이 글을 적게된 원인..&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커밋을 rebase로&amp;nbsp;합치기는 쉽지만, 나누기는 어려움&lt;/li&gt;
&lt;li&gt;패키지 Bump, 오타수정처럼 사소한 커밋도 이미 존재&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;a href=&quot;https://youngjinmo.github.io/2020/01/git-add-p/&quot;&gt;Git에서&amp;nbsp;변경사항&amp;nbsp;단위(Hunk)로&amp;nbsp;스테이징하기&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 툴에서&amp;nbsp;&lt;a href=&quot;https://github.com/dandavison/delta&quot;&gt;delta&lt;/a&gt;&lt;span&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;1090&quot; data-origin-height=&quot;1165&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lNNWh/btrWqQ8lKMH/aAn3EMAQmbtXqmw3PWukV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lNNWh/btrWqQ8lKMH/aAn3EMAQmbtXqmw3PWukV1/img.png&quot; data-alt=&quot;변경단위별로 스테이징, 변경 Delta 추적&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lNNWh/btrWqQ8lKMH/aAn3EMAQmbtXqmw3PWukV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlNNWh%2FbtrWqQ8lKMH%2FaAn3EMAQmbtXqmw3PWukV1%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;1090&quot; height=&quot;1165&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;1165&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;변경단위별로 스테이징, 변경 Delta 추적&lt;/figcaption&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 그럼 얼마나 자주할 것인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 나중에 PR을 열기 전이든, 병합하기 전이든 추후 적절히 보이기만 하면 상관없다는 마인드라 저장이 필요하다 싶을 때마다 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어 컴파일이나 린트를 안되는 상태에서도.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Stash 후 바로 pop할 상황이 아니라면 일단 스냅샷으로 만듦&lt;/li&gt;
&lt;li&gt;작업 중 다른 방법이 생각나 테스트 해볼 때&lt;/li&gt;
&lt;li&gt;다음 작업하기 전 Save가 필요할 때&lt;/li&gt;
&lt;li&gt;그냥 Remote에 백업이 필요할 때&lt;/li&gt;
&lt;/ol&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;깃은 DVCS라 바로 main에 반영되지 않게 또는 본인 레포의 리모트에 푸시가 가능하며, 앞서 말했듯 &quot;&lt;b&gt;잘 정리하면&lt;/b&gt;&quot; 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://news.hada.io/topic?id=6970&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git-Branchless - 브랜치를 사용하지 않는 Git 워크플로우 지원 도구 모음&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/arxanas/git-branchless&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git-branchless&lt;/a&gt;라는 CLI 툴.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Branchless라는 이름답게 마구마구 분기를 양산해도 선형적으로 유지할 수 있다&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Command:-git-smartlog&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git sl 또는 git smartlog&lt;/a&gt;를 사용하면 직관적인 그래프로 추적가능&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Command:-git-next,-git-prev&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git prev와 git next&lt;/a&gt;로 쉬운 checkout&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Command:-git-sync&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git sync&lt;/a&gt;를 통한 자동적인 rebase, &lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Command:-git-move&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git move&lt;/a&gt;를 통한 커밋 옮기기&lt;/li&gt;
&lt;li&gt;prev 커밋에서 리베이스로 재작성 후 git next로 움직이고 싶다면 &lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Command:-git-restack&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git restack&lt;/a&gt;으로 고쳐주기&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Command:-git-undo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git undo&lt;/a&gt;로 언제든지 되돌리기!!&lt;/li&gt;
&lt;li&gt;git &lt;a href=&quot;https://git-scm.com/book/ko/v2/Git-%EB%8F%84%EA%B5%AC-%EB%A6%AC%EB%B9%84%EC%A0%84-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;revision&lt;/a&gt;보다 강력한 &lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Reference:-Revsets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;revset&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&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;h4 data-ke-size=&quot;size20&quot;&gt;초기화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 초기화를 하고 일반적인 분기를 생성 해볼겁니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;git init과 git branchless init으로 초기화&lt;/li&gt;
&lt;li&gt;commit0 ~ commit2 이후에 featA라는 분기를 만들어 commit3, commit4 진행&lt;/li&gt;
&lt;li&gt;main으로 돌아오기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1673871761293&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.27912257556359243&quot;&gt;&lt;code&gt;git init --initial-branch=main
git branchless init --main-branch=main

touch commit0
git add commit0
git commit -m &quot;Add: commit0&quot;

touch commit1
git add commit1
git commit -m &quot;Add: commit1&quot;

touch commit2
git add commit2
git commit -m &quot;Add: commit2&quot;

git switch -c featA
touch commit3
git add commit3
git commit -m &quot;Add: commit3&quot;

touch commit4
git add commit4
git commit -m &quot;Add: commit4&quot;

git switch 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;로그를 보면 알겠지만 git hook을 통해 구동된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czu2Yk/btrWsiXUBWM/jUGtkRFdko23Q4WRRKINwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czu2Yk/btrWsiXUBWM/jUGtkRFdko23Q4WRRKINwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czu2Yk/btrWsiXUBWM/jUGtkRFdko23Q4WRRKINwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fczu2Yk%2FbtrWsiXUBWM%2FjUGtkRFdko23Q4WRRKINwK%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;1090&quot; height=&quot;374&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;367&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oVYDg/btrWlmtMlhU/pSjt4bo6x4Cg1ZcLTk8fjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oVYDg/btrWlmtMlhU/pSjt4bo6x4Cg1ZcLTk8fjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oVYDg/btrWlmtMlhU/pSjt4bo6x4Cg1ZcLTk8fjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoVYDg%2FbtrWlmtMlhU%2FpSjt4bo6x4Cg1ZcLTk8fjk%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;1090&quot; height=&quot;367&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;367&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;pre id=&quot;code_1682691753417&quot; class=&quot;shell&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.17578339531182863&quot;&gt;&lt;code&gt;git log --graph --oneline --all --decorate --color --topo-order --branches -10 | tac&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCcAyf/btsddSV5ydx/CTyZsJChMq5M0cPSA5qBXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCcAyf/btsddSV5ydx/CTyZsJChMq5M0cPSA5qBXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCcAyf/btsddSV5ydx/CTyZsJChMq5M0cPSA5qBXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCcAyf%2FbtsddSV5ydx%2FCTyZsJChMq5M0cPSA5qBXK%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;922&quot; height=&quot;287&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git sl(git smartlog)로도 확인을 해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 명령어로 정보를 더 보기 편하게 보여준다.&lt;/p&gt;
&lt;pre id=&quot;code_1682691753422&quot; class=&quot;shell&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.02619460053530176&quot;&gt;&lt;code&gt;git sl&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;303&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/demfHM/btsddZARa0i/8lCWsegyjVUioZfQYXzyU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/demfHM/btsddZARa0i/8lCWsegyjVUioZfQYXzyU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/demfHM/btsddZARa0i/8lCWsegyjVUioZfQYXzyU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdemfHM%2FbtsddZARa0i%2F8lCWsegyjVUioZfQYXzyU0%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;922&quot; height=&quot;303&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;303&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;pre id=&quot;code_1682691820718&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8497138023501838&quot;&gt;&lt;code&gt;touch commit5
git add commit5
git commit -m &quot;Add: commit5&quot;

git switch --detach

touch commit6
git add commit6
git commit -m &quot;Add: commit6&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bX0jrK/btsdcJ6HeCo/Jic1QrXoHH0ECGYSrwbXPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bX0jrK/btsdcJ6HeCo/Jic1QrXoHH0ECGYSrwbXPK/img.png&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;335&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 51.9385%; margin-right: 10px;&quot; data-widthpercent=&quot;52.55&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bX0jrK/btsdcJ6HeCo/Jic1QrXoHH0ECGYSrwbXPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbX0jrK%2FbtsdcJ6HeCo%2FJic1QrXoHH0ECGYSrwbXPK%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;922&quot; height=&quot;335&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vxw5f/btsddjUbi07/EXAPeeziC3vXVZ0yrpKwyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vxw5f/btsddjUbi07/EXAPeeziC3vXVZ0yrpKwyk/img.png&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;371&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 46.8987%;&quot; data-widthpercent=&quot;47.45&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vxw5f/btsddjUbi07/EXAPeeziC3vXVZ0yrpKwyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVxw5f%2FbtsddjUbi07%2FEXAPeeziC3vXVZ0yrpKwyk%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;922&quot; height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;바로 전&lt;/b&gt; 커밋인 main으로 다시 돌아가고 싶다고 해보자. 어떻게 해야 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 git이었다면 git swith main이라 했겠지만 여기서는 전 커밋으로 전환하는 git prev 명령어로 충분하다.&lt;/p&gt;
&lt;pre id=&quot;code_1682745016196&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.02679174416780772&quot;&gt;&lt;code&gt;git prev&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAIlva/btsdax0jpLW/EWFwpvKqx6koEnXRys7871/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAIlva/btsdax0jpLW/EWFwpvKqx6koEnXRys7871/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAIlva/btsdax0jpLW/EWFwpvKqx6koEnXRys7871/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAIlva%2Fbtsdax0jpLW%2FEWFwpvKqx6koEnXRys7871%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;922&quot; height=&quot;453&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;453&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;반대로 다음 커밋으로 이동할 때도 next로 전환하기만 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자를 넣어 prev 3 하면 3 커밋전으로 전환하는 식이라 간편하다.&lt;/p&gt;
&lt;pre id=&quot;code_1682745491231&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.1787431277402115&quot;&gt;&lt;code&gt;git next
git prev 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pMS4V/btsdaYJ26oT/rVtkEOuWIEzkk8neR9unxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pMS4V/btsdaYJ26oT/rVtkEOuWIEzkk8neR9unxk/img.png&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;455&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 51.4994%; margin-right: 10px;&quot; data-widthpercent=&quot;52.11&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pMS4V/btsdaYJ26oT/rVtkEOuWIEzkk8neR9unxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpMS4V%2FbtsdaYJ26oT%2FrVtkEOuWIEzkk8neR9unxk%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;922&quot; height=&quot;455&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HfCTU/btsdazqfznI/gJI2NY9HtvOLlvtNbVZGWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HfCTU/btsdazqfznI/gJI2NY9HtvOLlvtNbVZGWK/img.png&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;495&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 47.3378%;&quot; data-widthpercent=&quot;47.89&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HfCTU/btsdazqfznI/gJI2NY9HtvOLlvtNbVZGWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHfCTU%2FbtsdazqfznI%2FgJI2NY9HtvOLlvtNbVZGWK%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;922&quot; height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/div&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 main 다음이 commit6이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 commit 3과 4가 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 data-ke-size=&quot;size16&quot;&gt;git-branchless 툴을 사용하면 commit3으로 이동한뒤 git sync라고 하면 main을 기준으로 리베이스가 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1682696518688&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.33191469682648433&quot;&gt;&lt;code&gt;git next 2 -o # 오래된 커밋쪽으로 이동, 새로운 커밋쪽은 -n
git sync&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;698&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfUTj9/btsddkyOvW9/gOEd9INdp7InbaksC3LOB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfUTj9/btsddkyOvW9/gOEd9INdp7InbaksC3LOB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfUTj9/btsddkyOvW9/gOEd9INdp7InbaksC3LOB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfUTj9%2FbtsddkyOvW9%2FgOEd9INdp7InbaksC3LOB0%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;922&quot; height=&quot;698&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;698&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;326&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mNG5D/btsdd0NizME/ffVoAAyxtNAfTL5UV0OZa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mNG5D/btsdd0NizME/ffVoAAyxtNAfTL5UV0OZa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mNG5D/btsdd0NizME/ffVoAAyxtNAfTL5UV0OZa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmNG5D%2Fbtsdd0NizME%2FffVoAAyxtNAfTL5UV0OZa1%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;922&quot; height=&quot;326&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;326&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;마법의 무기 git undo로 되돌려버릴 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1682701721993&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.1876604272288409&quot;&gt;&lt;code&gt;git undo&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;1012&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brQL4b/btsddGuPKce/jUEdHkqBtIqG9kpkoEPQ7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brQL4b/btsddGuPKce/jUEdHkqBtIqG9kpkoEPQ7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brQL4b/btsddGuPKce/jUEdHkqBtIqG9kpkoEPQ7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrQL4b%2FbtsddGuPKce%2FjUEdHkqBtIqG9kpkoEPQ7K%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;922&quot; height=&quot;1012&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;1012&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 git sl의 장점이 하나 더 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 의미있는 익명분기만 똑똑하게 추적해 준다는 점!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 스크린샷 찍기를 깜박해서 이미 한번 git undo로 되돌린 상태인데요,&amp;nbsp; git log 그래프를 보면 상당히 더럽습니다. (commit3과 4가 3번이나 표시)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;421&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/etJa0Z/btsdaz4RQJL/rNOghxqS0Wdu6mtD0BsfM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/etJa0Z/btsdaz4RQJL/rNOghxqS0Wdu6mtD0BsfM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/etJa0Z/btsdaz4RQJL/rNOghxqS0Wdu6mtD0BsfM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FetJa0Z%2Fbtsdaz4RQJL%2FrNOghxqS0Wdu6mtD0BsfM1%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;922&quot; height=&quot;421&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;421&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 commit6을 commit4 뒤로 옮겨봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1682697810760&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.07611421592689072&quot;&gt;&lt;code&gt;git move -s 7de4f31 -d d4b489a&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;undo후 featA 브랜치인 commit3과 commit4를 commit6 뒤로 옮겨볼 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1682697934756&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.12881602659481184&quot;&gt;&lt;code&gt;git undo
git move -b featA -d 7de4f31 # 같은 분기에 속한 -b 413c2f2 또는 -b d4b489a 를 해도 상관없음&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;595&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAiu1Y/btsddSV5Ek3/2893n8q1QQe2k5EN2WcbO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAiu1Y/btsddSV5Ek3/2893n8q1QQe2k5EN2WcbO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAiu1Y/btsddSV5Ek3/2893n8q1QQe2k5EN2WcbO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAiu1Y%2FbtsddSV5Ek3%2F2893n8q1QQe2k5EN2WcbO0%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;922&quot; height=&quot;595&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;595&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;하지만 Feature&amp;nbsp; 브랜치를 병합하기 전이라던가 제한적으로 쓸때도 편하다고 생각한다.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;짜잔~ 커밋 그래프를 선형적으로 유지하기가 이렇게나 쉽습니다?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 생각해보니 commit6과 commit3을 rebase하고 싶어졌습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1682700448785&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5041372596379045&quot;&gt;&lt;code&gt;git rebase -i HEAD~2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;843&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qQvIJ/btsdc8LRFFv/reZ8lE9kd97DEvNOjOp7ZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qQvIJ/btsdc8LRFFv/reZ8lE9kd97DEvNOjOp7ZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qQvIJ/btsdc8LRFFv/reZ8lE9kd97DEvNOjOp7ZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqQvIJ%2Fbtsdc8LRFFv%2FreZ8lE9kd97DEvNOjOp7ZK%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;922&quot; height=&quot;843&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;843&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;다행히 안내가 뜨는대로 git restack 명령어로 깔끔히 해결되니 걱정마십시오.&lt;/p&gt;
&lt;pre id=&quot;code_1682700639059&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.22330732721953883&quot;&gt;&lt;code&gt;git restack&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9o4ER/btsdazqfKWF/Q9P24Nvhw0kHfJkVshKNh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9o4ER/btsdazqfKWF/Q9P24Nvhw0kHfJkVshKNh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9o4ER/btsdazqfKWF/Q9P24Nvhw0kHfJkVshKNh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9o4ER%2FbtsdazqfKWF%2FQ9P24Nvhw0kHfJkVshKNh1%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;922&quot; height=&quot;437&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;437&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://github.com/arxanas/git-branchless/wiki/Workflow:-divergent-development&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;투기적&amp;nbsp;커밋 후 리베이스&lt;/a&gt;하는&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방식으로&amp;nbsp; 할 수 있다.&lt;/span&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;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 관심있다면 &lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Command:-git-record&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git record&lt;/a&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Command:-git-amend&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git amend&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 restack은 rebase뿐만 아니라 git commit --amend 일 때도 모두 적용이 가능하다!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sync나 move시 conflict가 생길 경우 명시적으로 --merge 옵션을 추가하도록 실패하며, 설사 merge를 시도하다 안되겠다 싶으면 언제든지 git undo로 되돌릴 수 있다.&lt;/p&gt;
&lt;p 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;이제부터 더 간단해보이는 커밋 그래프와 두려움 없는 git 명령어들을 누려보세요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;참고로 HEAD~같이 단순한&amp;nbsp;&lt;a href=&quot;https://git-scm.com/docs/revisions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;revision&lt;/a&gt;보다 강력하고 쉬운 &lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Reference:-Revsets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;revset&lt;/a&gt;이 있으니 선택자가 필요하다면 확인해보길 바란다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;익명분기 추적, revset 모두 Mercurial(hg)의 훌륭한 자산이었던 것들이다.&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;git branchless 개발자가 메타 출신 엔지니어라서 그런지 메타의 VCS인 &lt;a href=&quot;https://engineering.fb.com/2022/11/15/open-source/sapling-source-control-scalable/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sapling&lt;/a&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;h2 data-ke-size=&quot;size26&quot;&gt;3. 병합&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&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;4~5000라인? 아니 1000라인 정도만 되도 &lt;b&gt;&quot;다른사람이 작성한&quot;&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;패치 스택(Patch Stack)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해 나온 방식이 바로 Patch stack이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.michaelagreiler.com/stacked-pull-requests/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;Stacked pull requests: make code reviews faster, easier, and more effective&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://timothya.com/blog/git-stack/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;A&amp;nbsp;Better&amp;nbsp;Model&amp;nbsp;for&amp;nbsp;Stacked&amp;nbsp;(GitHub)&amp;nbsp;Pull&amp;nbsp;Requests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능[1/3], 기능[2/3], 기능[3/3]처럼 쪼개서 리뷰 후 병합하면 체크해야할 양이 현저히 줄기 때문에 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리뷰할 때는 기능[1/3], 기능[2/3], 기능[3/3] 순으로 하여 커밋이 필요하면 추가하고, 병합할 때는 기능[3/3], 기능[2/3], 기능[1/3] 순으로 병합하기 때문에 Patch Stack이라 불린다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZhrHE/btsdcJ6H4mC/TLkaRCaoDYVpDpR9ownK70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZhrHE/btsdcJ6H4mC/TLkaRCaoDYVpDpR9ownK70/img.png&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;273&quot; data-is-animation=&quot;false&quot; style=&quot;width: 54.994%; margin-right: 10px;&quot; data-widthpercent=&quot;55.64&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZhrHE/btsdcJ6H4mC/TLkaRCaoDYVpDpR9ownK70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZhrHE%2FbtsdcJ6H4mC%2FTLkaRCaoDYVpDpR9ownK70%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;678&quot; height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beWjN0/btsdduBbcEe/m9kkyoGR62zzzwrPu7m12k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beWjN0/btsdduBbcEe/m9kkyoGR62zzzwrPu7m12k/img.jpg&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;399&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.8432%;&quot; data-widthpercent=&quot;44.36&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beWjN0/btsdduBbcEe/m9kkyoGR62zzzwrPu7m12k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeWjN0%2FbtsdduBbcEe%2Fm9kkyoGR62zzzwrPu7m12k%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;790&quot; height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;일반 분기 vs 패치 스택&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;git-branchless의 경우 &lt;a href=&quot;https://github.com/arxanas/git-branchless/wiki/Command:-git-submit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git submit&lt;/a&gt;이라는 명령어를 통해 branch들을 push하는 형태이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적인 툴로 &lt;a href=&quot;https://graphite.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Graphite&lt;/a&gt;가 존재한다. (&lt;a href=&quot;https://secure.phabricator.com/book/phabricator/article/introduction/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Phabricator&lt;/a&gt;나 &lt;a href=&quot;https://gerrit.googlesource.com/gerrit/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gerrit&lt;/a&gt;도 참고해볼만하나 phabricator는 메타가 버렸고, gerrit은 구글 전용 느낌이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾아보니 메타의 경우 &lt;a href=&quot;https://reviewstack.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ReviewStack&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rI8VP/btsdc68mR7D/Si3QrMWXBlb0A3XDX2urBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rI8VP/btsdc68mR7D/Si3QrMWXBlb0A3XDX2urBK/img.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;400&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rI8VP/btsdc68mR7D/Si3QrMWXBlb0A3XDX2urBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrI8VP%2Fbtsdc68mR7D%2FSi3QrMWXBlb0A3XDX2urBK%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;798&quot; height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPK65X/btsdaYcaaKn/69PqAtqlHUEPkBmJmakkBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPK65X/btsdaYcaaKn/69PqAtqlHUEPkBmJmakkBK/img.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;400&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPK65X/btsdaYcaaKn/69PqAtqlHUEPkBmJmakkBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPK65X%2FbtsdaYcaaKn%2F69PqAtqlHUEPkBmJmakkBK%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;798&quot; height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;병합 커밋 vs 선형적&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 선형적으로 관리를 하면 보기 좋은 것은 물론 &lt;a href=&quot;https://blog.gangnamunni.com/post/understanding_git_bisect/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git bisect를 이용해 문제있는 커밋 식별&lt;/a&gt;하기도 쉬워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무언가 자동적으로 식별한 후 고치고 싶다면 git-branchless의 &lt;a href=&quot;https://github.com/arxanas/git-branchless/discussions/803&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git test&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;병합 큐(Merge Queue)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병합에 있어 또 다른 문제는 다양한 이슈에서 생기는 풀리퀘스트를 병합할 때 문제가 생길 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 Patch 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;예를 들어, 잘 작동하는 feature1과 feature2라는 풀리퀘스트가 있다고 가정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 병합할때는 괜찮지만, 두개가 모두 병합될때는 충돌이 생길수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0DgUu/btsnF3Uc7ta/ktKB6Gx1IQ11OkQGsKGyt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0DgUu/btsnF3Uc7ta/ktKB6Gx1IQ11OkQGsKGyt1/img.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0DgUu/btsnF3Uc7ta/ktKB6Gx1IQ11OkQGsKGyt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0DgUu%2FbtsnF3Uc7ta%2FktKB6Gx1IQ11OkQGsKGyt1%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;1200&quot; height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqoYw8/btsnEodYbOo/aqcu40zfjSkZi02BYhpxM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqoYw8/btsnEodYbOo/aqcu40zfjSkZi02BYhpxM0/img.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqoYw8/btsnEodYbOo/aqcu40zfjSkZi02BYhpxM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqoYw8%2FbtsnEodYbOo%2Faqcu40zfjSkZi02BYhpxM0%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;1200&quot; height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.runway.team/blog/merge-queues-intro-for-mobile-engineers&quot;&gt;Merge&amp;nbsp;queues:&amp;nbsp;An&amp;nbsp;intro&amp;nbsp;for&amp;nbsp;mobile&amp;nbsp;engineers&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의 stage 영역의 개념처럼 Merge ready 상태를 도입한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;풀리퀘스트를 바로 병합하는 대신 Merge queue에 추가함&lt;/li&gt;
&lt;li&gt;Merge queue에 존재하는 분기의 상태로 풀리퀘스트를 업데이트&lt;/li&gt;
&lt;li&gt;다시 CI 검사를 실행함&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LxF1J/btsnGkIndN9/PAb4N2LXnXmCWu8QABEGKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LxF1J/btsnGkIndN9/PAb4N2LXnXmCWu8QABEGKK/img.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;562&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.9442%; margin-right: 10px;&quot; data-widthpercent=&quot;56.6&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LxF1J/btsnGkIndN9/PAb4N2LXnXmCWu8QABEGKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLxF1J%2FbtsnGkIndN9%2FPAb4N2LXnXmCWu8QABEGKK%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;1200&quot; height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XMVT6/btsnE9m5B0i/NnThJWM6kQ4YrJBx7IZqm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XMVT6/btsnE9m5B0i/NnThJWM6kQ4YrJBx7IZqm0/img.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;733&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.8931%;&quot; data-widthpercent=&quot;43.4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XMVT6/btsnE9m5B0i/NnThJWM6kQ4YrJBx7IZqm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXMVT6%2FbtsnE9m5B0i%2FNnThJWM6kQ4YrJBx7IZqm0%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;1200&quot; height=&quot;733&quot;/&gt;&lt;/span&gt;&lt;/div&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;내가 아는한 Shopify가 도입한 기능으로,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://shopify.engineering/introducing-the-merge-queue&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introducing&amp;nbsp;the&amp;nbsp;Merge&amp;nbsp;Queue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://shopify.engineering/successfully-merging-work-1000-developers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Successfully&amp;nbsp;Merging&amp;nbsp;the&amp;nbsp;Work&amp;nbsp;of&amp;nbsp;1000+&amp;nbsp;Developers&lt;/a&gt;&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;깃랩은 merge train, 깃허브에서는 merge queue라 부른다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.gitlab.com/ee/ci/pipelines/merge_trains.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Merge trains&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://about.gitlab.com/blog/2020/01/30/all-aboard-merge-trains/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;starting&amp;nbsp;merge&amp;nbsp;trains&amp;nbsp;improve&amp;nbsp;efficiency&amp;nbsp;for&amp;nbsp;DevOps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://about.gitlab.com/blog/2020/12/14/merge-trains-explained/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How to use merge train pipelines with GitLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gitlab.com/gitlab-org/gitlab-foss/-/issues/4176&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Merge&amp;nbsp;train/Release&amp;nbsp;train/Merge&amp;nbsp;when&amp;nbsp;master&amp;nbsp;succeeds:&amp;nbsp;run&amp;nbsp;build&amp;nbsp;on&amp;nbsp;merged&amp;nbsp;code&amp;nbsp;before&amp;nbsp;merging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/2023-07-12-github-merge-queue-is-generally-available/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitHub&amp;nbsp;merge&amp;nbsp;queue&amp;nbsp;is&amp;nbsp;generally&amp;nbsp;available&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이슈 관리에 있어서도 종속성을 다룰 수 있었으면 한다. [&lt;a href=&quot;https://yoric.github.io/post/about-blockers/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;about:Mozilla's&amp;nbsp;blockers&amp;nbsp;and&amp;nbsp;needinfos&lt;/a&gt;, &lt;a href=&quot;https://wiki.documentfoundation.org/QA/Bugzilla/Fields/Status&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;QA/Bugzilla/Fields/Status&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버그질라에는 blocker와 needinfos라는 이슈 종속성 시스템이 존재한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;blocker: A이슈로 인해 B이슈가 해결될 수 없다면, A이슈는 B의 blocker이다.&lt;/li&gt;
&lt;li&gt;needinfo: 더 많은 정보가 제공될 때까지 재현 및 수정될 수 없는 버그&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2016&quot; data-origin-height=&quot;1458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HkHUD/btsnEokETc3/eNT3JKfHXpvWhlffHqNgok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HkHUD/btsnEokETc3/eNT3JKfHXpvWhlffHqNgok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HkHUD/btsnEokETc3/eNT3JKfHXpvWhlffHqNgok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHkHUD%2FbtsnEokETc3%2FeNT3JKfHXpvWhlffHqNgok%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;2016&quot; height=&quot;1458&quot; data-origin-width=&quot;2016&quot; data-origin-height=&quot;1458&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;충돌 - 일급 충돌 및 3 Way diff&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Git에 없어서 아쉽지만, Jujutsu, Pijul에는 &lt;a href=&quot;https://github.com/martinvonz/jj/blob/main/docs/conflicts.md&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/martinvonz/jj&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Jujutsu&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;a href=&quot;https://git-scm.com/docs/git-notes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git note&lt;/a&gt;에 메타데이터를 저장하는 &lt;a href=&quot;https://github.com/arxanas/git-branchless/discussions/126#discussioncomment-4659309&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;그리고 Jujutsu의 3-way diff방식은 매우 보기 편하다.&lt;/p&gt;
&lt;pre id=&quot;code_1682706262139&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8500549773428256&quot;&gt;&lt;code&gt;# Git 방식
  &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; left
  apple
  grapefruit
  orange
  ======= base
  apple
  grape
  orange
  ||||||| right
  APPLE
  GRAPE
  ORANGE
  &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;

# Jujutsu 방식
  &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;
  %%%%%%%
   apple
  -grape
  +grapefruit
   orange
  +++++++
  APPLE
  GRAPE
  ORANGE
  &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&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;Jujutsu의 3way diff 방식은 깃에도 들어갔으면 하는 바램이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 위 방식이 기존 IDE, 에디터의 문법강조와 호환이 안될 가능성이 높고, 2개의 Diff등을 원할 수 있기 때문에 &lt;a href=&quot;https://github.com/arxanas/git-branchless/discussions/923&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Better conflict marker 제안&lt;/a&gt;을 해보는 중.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 Jujutsu쪽에 다시 글을 올리게 될 것 같다.&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Git이 충돌날때 고질적인 단점 중에 하나는 바이너리의 처리다.&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;1139&quot; data-origin-height=&quot;1075&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bb9du/btsddtCtpNA/I2Fvzvi8ZmkZRygjvBeie0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bb9du/btsddtCtpNA/I2Fvzvi8ZmkZRygjvBeie0/img.png&quot; data-alt=&quot;일단 충돌이 생겼다는데 어떻게 하라는 건지..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bb9du/btsddtCtpNA/I2Fvzvi8ZmkZRygjvBeie0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBb9du%2FbtsddtCtpNA%2FI2Fvzvi8ZmkZRygjvBeie0%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;1139&quot; height=&quot;1075&quot; data-origin-width=&quot;1139&quot; data-origin-height=&quot;1075&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;학교에 돌아가면 PDF라던가 바이너리 파일을 다룰일이 많으므로 러스트로 간단히 바이너리 충돌동작 개선안을 만들어봤다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/black7375/binary-conflict&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Binary conflict&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1139&quot; data-origin-height=&quot;1075&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crfvF0/btsdbPsxfXW/71M11pogs5kJUpvJ7cnXPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crfvF0/btsdbPsxfXW/71M11pogs5kJUpvJ7cnXPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crfvF0/btsdbPsxfXW/71M11pogs5kJUpvJ7cnXPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrfvF0%2FbtsdbPsxfXW%2F71M11pogs5kJUpvJ7cnXPK%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;1139&quot; height=&quot;1075&quot; data-origin-width=&quot;1139&quot; data-origin-height=&quot;1075&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보다시피 3개의 파일을 볼 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;base: 분기의 시작인 파일&lt;/li&gt;
&lt;li&gt;그냥: 충돌 나기 전에 병합된 현재 보여지는 파일&lt;/li&gt;
&lt;li&gt;their: 병합을 시도하는 새로운 파일&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;이렇게 3개의 파일을 동시에 보여주게 되면 필요한 파일이면 추가, 필요없으면 제거를 함은 물론 워드나 프리젠테이션 파일이면 열어서 직접 비교한 후 병합할 수 있다.&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;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/ko/v2/%EB%B6%84%EC%82%B0-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C%EC%9D%98-Git-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-%EA%B8%B0%EC%97%AC%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;분산&amp;nbsp;환경에서의&amp;nbsp;Git&amp;nbsp;-&amp;nbsp;프로젝트에&amp;nbsp;기여하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/ko/v2/%EB%B6%84%EC%82%B0-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C%EC%9D%98-Git-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;분산&amp;nbsp;환경에서의&amp;nbsp;Git&amp;nbsp;-&amp;nbsp;프로젝트&amp;nbsp;관리하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-send-email.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Learn to use email with git!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;최근 깃 사용에서 다른 사람의 변경사항을 반영하는 방법은 Pull Request를 생성 후 병합(Merge)하는 방식일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 Pull request인가 하면 옛날에 깃허브에서 프로젝트에 기여를 하기 위해 요청하면 기여자의 리포트 레포에서 git pull을 하라는 메일이 갔기 때문이며 &lt;a href=&quot;https://git-scm.com/docs/git-request-pull&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git request-pull&lt;/a&gt; 이라는 명령도 존재한다.&amp;nbsp; [&lt;a href=&quot;https://github.blog/2011-09-09-better-pull-request-emails/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Better&amp;nbsp;Pull&amp;nbsp;Request&amp;nbsp;Emails&lt;/a&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKEhMy/btsdd0G0WpE/Q0mOcCeQGrE1WAJLz7AQkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKEhMy/btsdd0G0WpE/Q0mOcCeQGrE1WAJLz7AQkK/img.png&quot; data-alt=&quot;pull 요청 메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKEhMy/btsdd0G0WpE/Q0mOcCeQGrE1WAJLz7AQkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKEhMy%2Fbtsdd0G0WpE%2FQ0mOcCeQGrE1WAJLz7AQkK%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;800&quot; height=&quot;539&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pull 요청 메일&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;a href=&quot;https://elixir.free-electrons.com/linux/latest/source/Documentation/process/submitting-patches.rst&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;리눅스&lt;/a&gt;나&amp;nbsp;&lt;a href=&quot;https://orgmode.org/worg/org-contribute.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;org mode&lt;/a&gt;같은 전통있는 오픈소스들이 애용하는걸로 알려져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Free desktop에서 &lt;a href=&quot;https://www.freedesktop.org/wiki/Software/PulseAudio/HowToUseGitSendEmail/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;제공하는 예제&lt;/a&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1682765350711&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3932469649558942&quot;&gt;&lt;code&gt;# == 설정 ==
# 본인 정보
git config --global user.name &quot;My Name&quot;
git config --global user.email &quot;myemail@example.com&quot;

# 본인의 메일 서버 연동
git config --global sendemail.smtpencryption tls
git config --global sendemail.smtpserver mail.messagingengine.com
git config --global sendemail.smtpuser tanuk@fastmail.fm
git config --global sendemail.smtpserverport 587
git config --global sendemail.smtppass hackme

# 메일 받을 대상 설정
git config sendemail.to pulseaudio-discuss@lists.freedesktop.org

# == 보내기 ==
# 패치 전송
git send-email HEAD^

# 패치 버전2 전송
git send-email -v2 HEAD^

# 패치 생성 후 보내기
git format-path origin/master # 이메일용 패치 생성
git send-mail *.patch

# == 적용하기 ==
# 패치 적용
git am filename.mbox

# 리눅스의 경우
b4 am -o- &amp;lt;url&amp;gt; | git am&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;a href=&quot;https://sourcehut.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SourceHut&lt;/a&gt;이라고 &lt;a href=&quot;https://git-scm.com/docs/git-format-patch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git send-email&lt;/a&gt;과 &lt;a href=&quot;https://lists.sr.ht/~sircmpwn/email-test-drive&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;a href=&quot;https://github.com/mricon/b4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;b4&lt;/a&gt;라는 툴을 직접 만들어 사용하는 모양이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이 방식을 사용할 것이라면 이메일과 관련된 &lt;a href=&quot;https://git-scm.com/book/ko/v2/%EB%B6%80%EB%A1%9D-C%3A-Git-%EB%AA%85%EB%A0%B9%EC%96%B4-Email&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git 명령어들&lt;/a&gt; 모음도 확인 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 기타 관리 방법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기능개발과 버그 수정을 동시에 - Worktree&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ryanking13.github.io/2021/05/10/git-worktree.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git&amp;nbsp;worktree&amp;nbsp;소개&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-worktree&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git-worktree - Manage multiple working trees&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.invidelabs.com/git-worktree-to-make-daily-git-workflow-better/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Get&amp;nbsp;your&amp;nbsp;git&amp;nbsp;game&amp;nbsp;up&amp;nbsp;with&amp;nbsp;git&amp;nbsp;worktrees&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git worktree 기능을 사용하면&amp;nbsp; git history는 공유된 채로 작업파일들만 여러곳에 체크아웃하여 작업들을 동시에 진행할 수 있다.&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;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4YSqu/btsdbPTDx8v/9BOskz2CLy7h9Da98DLkAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4YSqu/btsdbPTDx8v/9BOskz2CLy7h9Da98DLkAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4YSqu/btsdbPTDx8v/9BOskz2CLy7h9Da98DLkAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4YSqu%2FbtsdbPTDx8v%2F9BOskz2CLy7h9Da98DLkAK%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;681&quot; height=&quot;633&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;633&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;stash나 커밋 후 branch 전환후 작업하거나 clone을 새로 받을 필요가 없다.&lt;/p&gt;
&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_1682709697452&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5609032515058973&quot;&gt;&lt;code&gt;git worktree add [path]        # 워크트리 추가
git worktree remove [worktree] # 워크트리 제거
git worktree list              # 등록된 워크트리들을 보여줌&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;위 설명을 들으면 마치 SVN의 분기를 떠오르게 하는 방식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;160&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKc5kV/btsddjUczcp/eNOSKTwqKxKKpJCEadJGq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKc5kV/btsddjUczcp/eNOSKTwqKxKKpJCEadJGq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKc5kV/btsddjUczcp/eNOSKTwqKxKKpJCEadJGq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKc5kV%2FbtsddjUczcp%2FeNOSKTwqKxKKpJCEadJGq1%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;160&quot; height=&quot;300&quot; data-origin-width=&quot;160&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://wiki.kldp.org/wiki.php/SubversionBook/BranchingAndMerging&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SVN 브랜치(branch)와 merge&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;대용량 파일 - Git LFS&lt;/h3&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;a href=&quot;https://black7375.tistory.com/82#5.7-ci/cd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CI/CD 성능&lt;/a&gt; 관련해 적었을 때 소개한 적이 있을 것 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중 첫번째는 대용량 파일로 &lt;a href=&quot;https://docs.github.com/ko/repositories/working-with-files/managing-large-files/about-large-files-on-github&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;깃허브의 경우&lt;/a&gt;, 50MB 파일은 경고 100MB 이상 파일은 차단하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 경우 &lt;a href=&quot;https://git-lfs.github.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git LFS&lt;/a&gt;로 해결할 수 있지만 여전히 &lt;a href=&quot;https://docs.github.com/ko/repositories/working-with-files/managing-large-files/about-git-large-file-storage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;최대 파일 크기&lt;/a&gt;가 제약되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnA7Q5/btsdegbwiov/QrcE8Ax5wme2H2J1k0XuX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnA7Q5/btsdegbwiov/QrcE8Ax5wme2H2J1k0XuX0/img.png&quot; data-alt=&quot;Git LFS&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnA7Q5/btsdegbwiov/QrcE8Ax5wme2H2J1k0XuX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnA7Q5%2Fbtsdegbwiov%2FQrcE8Ax5wme2H2J1k0XuX0%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;1200&quot; height=&quot;630&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Git LFS&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dvc.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DVC&lt;/a&gt;: &lt;a href=&quot;https://bag.org.tr/proje/help/workflow/git_annex.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git Annex&lt;/a&gt;와 비슷하나 머신러닝 데이터처럼 더 커다란 파일과 클라우드에서 공유 &lt;a href=&quot;https://github.com/iterative/dvc/issues/211&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#211&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비슷하게 Git과 호환되는 &lt;a href=&quot;https://about.xethub.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;xetdata&lt;/a&gt;, &lt;a href=&quot;https://www.diversion.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;diversion&lt;/a&gt;이 있는 것 같다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://snowtrack.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Snowtrack&lt;/a&gt;: 2D/3D 디자인 리소스들 관리에 최적화, 관심있다면 &lt;a href=&quot;https://github.com/snowtrack/snowfs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SnowFS&lt;/a&gt;도 확인하자&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/elfshaker/elfshaker&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;elfshaker&lt;/a&gt;: 바이너리 압축이 고도로 가능&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jamsync.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JamSync&lt;/a&gt;: Rsync에 기반하여 항상 최신으로 유지&lt;/li&gt;
&lt;/ul&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;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Get&amp;nbsp;up&amp;nbsp;to&amp;nbsp;speed&amp;nbsp;with&amp;nbsp;partial&amp;nbsp;clone&amp;nbsp;and&amp;nbsp;shallow&amp;nbsp;clone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bring&amp;nbsp;your&amp;nbsp;monorepo&amp;nbsp;down&amp;nbsp;to&amp;nbsp;size&amp;nbsp;with&amp;nbsp;sparse-checkout&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;.git(bare git)의 내용을 &lt;a href=&quot;https://git-scm.com/docs/partial-clone&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;부분복제(Partial clone)&lt;/a&gt;하기와 작업파일 &lt;a href=&quot;https://www.git-scm.com/docs/git-sparse-checkout&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;부분 체크아웃(Sparse checkout)&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;먼저 부분복제로 다운로드하는 시간을 줄여보면 clone시 파일(--filter=blob:none), 디렉토리(--filter=tree:0), 커밋기록(--depth=1) 등을 제한 시킬 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HaGqV/btsddsKmEYS/JL44jMn9kdJ0COPOKRZV4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HaGqV/btsddsKmEYS/JL44jMn9kdJ0COPOKRZV4K/img.png&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;414&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.531%; margin-right: 10px;&quot; data-widthpercent=&quot;33.31&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HaGqV/btsddsKmEYS/JL44jMn9kdJ0COPOKRZV4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHaGqV%2FbtsddsKmEYS%2FJL44jMn9kdJ0COPOKRZV4K%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;799&quot; height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZSlb4/btsddUNlZOw/Gx3JO8JzgFLv1IdqgZ7GC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZSlb4/btsddUNlZOw/Gx3JO8JzgFLv1IdqgZ7GC0/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;414&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5717%; margin-right: 10px;&quot; data-widthpercent=&quot;33.35&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZSlb4/btsddUNlZOw/Gx3JO8JzgFLv1IdqgZ7GC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZSlb4%2FbtsddUNlZOw%2FGx3JO8JzgFLv1IdqgZ7GC0%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;800&quot; height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RD1S1/btsdcKEKZGg/LoADxk65Duj4zMi68fNgA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RD1S1/btsdcKEKZGg/LoADxk65Duj4zMi68fNgA1/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;414&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5717%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RD1S1/btsdcKEKZGg/LoADxk65Duj4zMi68fNgA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRD1S1%2FbtsdcKEKZGg%2FLoADxk65Duj4zMi68fNgA1%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;800&quot; height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;파일, 디렉토리, 커밋 기록 제외&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git이 clone되고 나면 실제 작업파일들을 보여줘야 한다.&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;800&quot; data-origin-height=&quot;585&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgSo6i/btsdeZm3Sic/1L82k7sJArmQs5fV3km491/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgSo6i/btsdeZm3Sic/1L82k7sJArmQs5fV3km491/img.png&quot; data-alt=&quot;사용하는 작업 디렉토리만 보여주기!!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgSo6i/btsdeZm3Sic/1L82k7sJArmQs5fV3km491/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgSo6i%2FbtsdeZm3Sic%2F1L82k7sJArmQs5fV3km491%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;800&quot; height=&quot;585&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;585&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;20분이나 걸리던 작업이..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9KprH/btsdc0Oo4s5/5lcoGgafr6LxKIDNcewlbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9KprH/btsdc0Oo4s5/5lcoGgafr6LxKIDNcewlbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9KprH/btsdc0Oo4s5/5lcoGgafr6LxKIDNcewlbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9KprH%2Fbtsdc0Oo4s5%2F5lcoGgafr6LxKIDNcewlbk%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;922&quot; height=&quot;340&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;340&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;겨우 1분만에 다운로드 받아진 것을 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1682739543297&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5439930401415718&quot;&gt;&lt;code&gt;git clone --depth=1 --sparse https://github.com/torvalds/linux&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;307&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwXtlP/btsdc1Gv6nv/2jKTx4iL3QMT3mpeID5hK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwXtlP/btsdc1Gv6nv/2jKTx4iL3QMT3mpeID5hK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwXtlP/btsdc1Gv6nv/2jKTx4iL3QMT3mpeID5hK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwXtlP%2Fbtsdc1Gv6nv%2F2jKTx4iL3QMT3mpeID5hK1%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;922&quot; height=&quot;307&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;307&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나 같은 경우 sparse-checkout은 github action이나 문서처럼 의존성이 적은 작업의 커밋이 필요할때 유용하게 쓰고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정한 폴더만 받는 기능도 SVN의 킬러 기능이었으나 모두 대체 가능해지면서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃허브는 2024년 1월 8일에 &lt;a href=&quot;https://github.blog/2023-01-20-sunsetting-subversion-support/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SVN 지원을 제거하게&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;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/2022-10-13-the-story-of-scalar/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Story&amp;nbsp;of&amp;nbsp;Scalar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/devops/introducing-scalar/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introducing&amp;nbsp;Scalar:&amp;nbsp;Git&amp;nbsp;at&amp;nbsp;scale&amp;nbsp;for&amp;nbsp;everyone&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기능에는 마소의 눈물겨운 노력이 깃들어있다..ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우 소스코드가 너무 커서 다운로드에 12시간, 체크아웃에 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;sparse checkout이 기본은 물론, GVFS라는 프로토콜로 빠르게 다운로드가 가능하다고 한다(Azure devops만 현재 지원).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjkegG/btsdhypfqeO/4g8fkIDlY4Q9DkYZoXjh5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjkegG/btsdhypfqeO/4g8fkIDlY4Q9DkYZoXjh5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjkegG/btsdhypfqeO/4g8fkIDlY4Q9DkYZoXjh5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjkegG%2FbtsdhypfqeO%2F4g8fkIDlY4Q9DkYZoXjh5k%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;800&quot; height=&quot;263&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;263&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빌드 결과물을 소스와 분리하기 위해 clone시&amp;lt;project_name&amp;gt;/src에 소스코드가 위치&lt;/li&gt;
&lt;li&gt;인덱스와 수정된 크기 추적 및 압축&lt;/li&gt;
&lt;li&gt;백그라운드에서 fetch, 커밋그래프 작성, 팩 파일 정리 및 색인 생성 작업을 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 depth=1을 하면 커밋기록이 사라지는 것과 달리 기록이 보존되면서 파일들이 필요하게 되면 적절히 다운로드를 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대형 레포를 가지고 있는 곳이라면 시도해볼만 하겠다.&lt;/p&gt;</description>
      <category>프로그래밍/기타</category>
      <category>Git</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/92</guid>
      <comments>https://black7375.tistory.com/92#entry92comment</comments>
      <pubDate>Sun, 15 Jan 2023 20:43:42 +0900</pubDate>
    </item>
    <item>
      <title>HTML과 CSS 전처리, 템플릿의 표현력</title>
      <link>https://black7375.tistory.com/91</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;별다른건 아니고, 예전에 찾았었던 자료들 정리나 하려고 쓰는 글.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 굳이 쓰게된 동기를 찾는다면 JSX와 CSS In 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;PHP를 사용하던 페이스북이 &lt;a href=&quot;https://en.wikipedia.org/wiki/XHP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;XHP&lt;/a&gt;(&lt;a href=&quot;https://github.com/facebookarchive/xhp-php5-extension&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;xhp-php5-extension&lt;/a&gt;, &lt;a href=&quot;https://docs.hhvm.com/hack/XHP/introduction&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;XHP: Introduction&lt;/a&gt;)를 만들고, 대체할 제품으로 &lt;a href=&quot;https://en.wikipedia.org/wiki/React_(software)#History&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React&lt;/a&gt;와 &lt;a href=&quot;https://en.wikipedia.org/wiki/JSX_(JavaScript)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JSX&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/CSS-in-JS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS-In-JS&lt;/a&gt;(&lt;a href=&quot;https://speakerdeck.com/vjeux/react-css-in-js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;슬라이드&lt;/a&gt;)를 소개하더니, 종국에는 &lt;a href=&quot;https://react.dev/blog/2020/12/21/data-fetching-with-react-server-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;서버 컴포넌트&lt;/a&gt;까지 만들어 내면서 PHP를 대체 가능하게 만들어버렸다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://taegon.kim/archives/5097&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;ReactJS 둘러보기 - XHP부터 React Native까지&lt;/a&gt;&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;/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;h2 data-ke-size=&quot;size26&quot;&gt;전처리, 템플릿 엔진&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Preprocessor&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;a href=&quot;https://en.wikipedia.org/wiki/Template_processor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;템플릿 엔진&lt;/a&gt;은 결과 문서를 생성하기 위해 데이터 모델과 템플릿을 결합하는 프로그램이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;396&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMInft/btsrkPD7y7B/OWJCpkltbcdPUxp5dTsw80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMInft/btsrkPD7y7B/OWJCpkltbcdPUxp5dTsw80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMInft/btsrkPD7y7B/OWJCpkltbcdPUxp5dTsw80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMInft%2FbtsrkPD7y7B%2FOWJCpkltbcdPUxp5dTsw80%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;883&quot; height=&quot;396&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;396&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@hi_potato/Template-Engine-Template-Engine&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;템플릿&amp;nbsp;엔진이란?&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HTML&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HTML 템플릿 엔진들&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;템플릿 엔진 비교&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 HTML부터 시작하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/comparing-html-preprocessor-features/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Comparing&amp;nbsp;HTML&amp;nbsp;Preprocessor&amp;nbsp;Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/alexmercedcoder/express-templating-cheatsheet-pug-ejs-handlebars-mustache-liquid-50f1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Express Templating Cheatsheet (Pug, EJS, Handlebars, Mustache, Liquid)&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1760&quot; data-origin-height=&quot;1638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/95sn6/btsq2PfcirQ/kfLCQuvYJ9YCy3AObn7yN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/95sn6/btsq2PfcirQ/kfLCQuvYJ9YCy3AObn7yN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/95sn6/btsq2PfcirQ/kfLCQuvYJ9YCy3AObn7yN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F95sn6%2Fbtsq2PfcirQ%2FkfLCQuvYJ9YCy3AObn7yN1%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;1760&quot; height=&quot;1638&quot; data-origin-width=&quot;1760&quot; data-origin-height=&quot;1638&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;size18&quot;&gt;&lt;b&gt;Markdown 및 마크업 종류&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://commonmark.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;일부 문법은 아쉽지만 &lt;a href=&quot;https://orgmode.org/features.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Org Mode&lt;/a&gt;, &lt;a href=&quot;https://namu.wiki/w/%EB%82%98%EB%AC%B4%EC%9C%84%ED%82%A4:%EB%AC%B8%EB%B2%95%20%EB%8F%84%EC%9B%80%EB%A7%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모니위키&lt;/a&gt;, &lt;a href=&quot;https://librewiki.net/wiki/%EB%8F%84%EC%9B%80%EB%A7%90:%EC%9C%84%ED%82%A4_%EB%AC%B8%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;미디어위키&lt;/a&gt;, &lt;a href=&quot;https://asciidoc.org/#compare&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AsciiDoc&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;단점으로 뽑자면 Includes와 같은 전처리기의 필수 기능이 없다.&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;b&gt;Pug 류&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/pugjs/pug&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pug&lt;/a&gt;, &lt;a href=&quot;https://github.com/haml/haml&quot;&gt;Haml&lt;/a&gt;, &lt;a href=&quot;https://github.com/slim-template/slim&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Slim&lt;/a&gt;류는 XML 문법의 흔적을 제거하고 파이썬 내지는 &lt;a href=&quot;https://emmet.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Emmet&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;size18&quot;&gt;&lt;b&gt;PHP, ERB 류&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 &lt;a href=&quot;https://github.com/ruby/erb&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ERB&lt;/a&gt;, &lt;a href=&quot;https://shopify.github.io/liquid/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Liquid&lt;/a&gt;, &lt;a href=&quot;https://github.com/mozilla/nunjucks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nunjucks&lt;/a&gt;등은 HTML에 상대적으로 가깝게 만들어져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/handlebars-lang/handlebars.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Handlebars&lt;/a&gt;나 &lt;a href=&quot;https://github.com/mustache/mustache&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mustache&lt;/a&gt;의 {{# start}}{{/ end}}보다 {% start %}{% end %}가 보기 좋은 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전반적인 문법은 Nunjucks가 가장 깔끔해보이는 듯.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러고보니 Nunjucks도 모질라 작품이네;;&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://github.com/thymeleaf/thymeleaf&quot;&gt;Thymeleaf&lt;/a&gt;, &lt;a href=&quot;https://github.com/noirbizarre/jinja2&quot;&gt;Jinja2&lt;/a&gt;, &lt;a href=&quot;https://velocity.apache.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Velocity&lt;/a&gt;, &lt;a href=&quot;https://freemarker.apache.org/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Freemarker&lt;/a&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;JSX와의 비교&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난 SFC도 매력적이지만 &lt;a href=&quot;https://dev.to/ryansolid/why-i-m-not-a-fan-of-single-file-components-3bfl&quot;&gt;Ryan Carniato와 동일한 이유&lt;/a&gt;로 JSX 방식을 선호한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSX는 자바스크립트 스펙을 사용하기 때문에 Local variables, Filters, Math에서는 완벽한 우위라 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Templating과 Includes는 {변수} 혹은 {JSX.Element}처럼 &lt;a href=&quot;https://react.dev/learn/javascript-in-jsx-with-curly-braces&quot;&gt;Curly brace&lt;/a&gt;로 사용이 가능하고, Slot쪽은 Props와 HOC 패턴으로 그럭저럭 대체 가능하다. [&lt;a href=&quot;https://www.radix-ui.com/primitives/docs/utilities/slot&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RadixUI Slot&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@srph/react-imitating-vue-slots-eab8393f96fd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue Slots in React&lt;/a&gt;, &lt;a href=&quot;https://github.com/dschnare/react-slot&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React&amp;nbsp;Slot&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;head&amp;gt;쪽도 JSX의 특성상 사용하지는 못하지만 &lt;a href=&quot;https://github.com/staylor/react-helmet-async&quot;&gt;react-helmet-async&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;JSX의 가장 커다란 아쉬움은 Logic과 Loops라 할 수 있겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삼항/비트 연산자와 map()으로 가능하긴 하나 중첩된 삼항 연산자가 나타나는등 복잡한 조건이라면, 읽기 쉽지 않은 것이 사실이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SolidJS는 &lt;a href=&quot;https://www.solidjs.com/docs/latest/api#control-flow&quot;&gt;Control Flow&lt;/a&gt;라 하여 지원하고 있으며, 컴포넌트이기 때문에 리엑트도 하려면 &lt;a href=&quot;https://github.com/romac/react-if&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React If&lt;/a&gt;처럼 가능하긴 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SolidJS의 제어 컴포넌트들을 보면 상당히 직관적이고 유연하다.&lt;/p&gt;
&lt;pre id=&quot;code_1692298594373&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.18058660629998435&quot;&gt;&lt;code&gt;// 일반적인 If-Else 조건
&amp;lt;Show when={state.count &amp;gt; 0} fallback={&amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}&amp;gt;
  &amp;lt;div&amp;gt;My Content&amp;lt;/div&amp;gt;
&amp;lt;/Show&amp;gt;

// state.user 값이 변경될때만 실행하며, state.user 값을 받아서 사용할 수 있음
&amp;lt;Show when={state.user} fallback={&amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}&amp;gt;
  {(user) =&amp;gt; &amp;lt;div&amp;gt;{user.firstName}&amp;lt;/div&amp;gt;}
&amp;lt;/Show&amp;gt;

// 여러가지 조건이 필요할 때
&amp;lt;Switch fallback={&amp;lt;div&amp;gt;Not Found&amp;lt;/div&amp;gt;}&amp;gt;
  &amp;lt;Match when={state.route === &quot;home&quot;}&amp;gt;
    &amp;lt;Home /&amp;gt;
  &amp;lt;/Match&amp;gt;
  &amp;lt;Match when={state.route === &quot;settings&quot;}&amp;gt;
    &amp;lt;Settings /&amp;gt;
  &amp;lt;/Match&amp;gt;
&amp;lt;/Switch

// 변경된 항목만 효율적으로 업데이트하는 참조 키 루프
&amp;lt;For each={state.list} fallback={&amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}&amp;gt;
  {(item, index) =&amp;gt; (
    &amp;lt;div&amp;gt;
      #{index()} {item}
    &amp;lt;/div&amp;gt;
  )}
&amp;lt;/For&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;이는 앵귤러JS에서 &lt;a href=&quot;https://docs.angularjs.org/api/ng/directive/ngIf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ng-if&lt;/a&gt;와 &lt;a href=&quot;https://docs.angularjs.org/api/ng/directive/ngRepeat&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ng-repeat&lt;/a&gt;이라 하여 &lt;a href=&quot;https://docs.angularjs.org/guide/directive&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;디렉티브(Directive)&lt;/a&gt;라는 이름으로 더 간결하게 제공하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후속제품인 &lt;a href=&quot;https://angular.io/api/core/Directive&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앵귤러&lt;/a&gt;와 &lt;a href=&quot;https://vuejs.org/api/built-in-directives.html#v-text&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue&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;다음 케이스의 대부분은 Control Flow 컴포넌트와 겹치는 것 같지만, 라인수가 줄어들어서 선호하는 사람이 있을 수도.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.solidjs.com/docs/latest/api#use___&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SolidJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yandex/jsx-directives&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;jsx-directives&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/baeyun/directive-x&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Directive-X&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/damianc/babel-plugin-react-jsx-directives&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;babel-plugin-react-jsx-directives&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/peakchen90/babel-plugin-react-directives&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;babel-plugin-react-directives&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 SolidJS의 방식이 꽤 좋은데, 리엑트에 익숙할 독자들을 위해 리엑트가 디렉티브를 지원한다 가정해 약간 변형해보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1692298769424&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9569226555501668&quot;&gt;&lt;code&gt;function model(el, value) {
  const [field, setField] = value;
  useEffect(() =&amp;gt; el.value = field, [el, field]);
  el.addEventListener(&quot;input&quot;, (e) =&amp;gt; setField(e.target.value));
}

function Input() {
  const [name, setName] = setState(&quot;&quot;);
  return &amp;lt;input type=&quot;text&quot; use:model={[name, setName]} /&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;디렉티브에서 주목할 것은 useRef(null)을 쓸일이 줄어들 수 있다는 점. (디렉티브는 ref에 대한 문법 설탕에 가깝다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역 디렉티브는 JSX 네임스페이스에 추가해야할 필요가 있으므로, 익명 디렉티브도 보고싶다.&lt;/p&gt;
&lt;pre id=&quot;code_1692284215882&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.035249307227825044&quot;&gt;&lt;code&gt;function Input() {
  const focus = (el) =&amp;gt; {
    el.focus();
  }

  return &amp;lt;input type=&quot;text&quot; use={focus} /&amp;gt;;
}&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;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;XSLT와 Xquery&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/XSLT&quot;&gt;XSLT(Extensible Stylesheet Language Transformations)&lt;/a&gt;는 XML을 다른 형식으로 변환할 수 있도록 만든 포맷이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/XSLT&quot;&gt;XSLT 문서&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;a href=&quot;https://ko.wikipedia.org/wiki/XQuery&quot;&gt;XQuery&lt;/a&gt;는 이거.. JSX아냐? 라는 생각이 들만큼 비슷하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문법의 하위집합인 &lt;a href=&quot;https://ko.wikipedia.org/wiki/XPath&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;XPATH&lt;/a&gt;는 XML 노드들을 참조하는 방법으로 우리에게 익숙한 파일 경로방식을 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1692457758120&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9934418236256176&quot;&gt;&lt;code&gt; &amp;lt;html&amp;gt;&amp;lt;body&amp;gt;
 {
   for $act in doc(&quot;hamlet.xml&quot;)//ACT
   let $speakers := distinct-values($act//SPEAKER)
   return
     &amp;lt;div&amp;gt;
       &amp;lt;h1&amp;gt;{ string($act/TITLE) }&amp;lt;/h1&amp;gt;
       &amp;lt;ul&amp;gt;
       {
         for $speaker in $speakers
         return &amp;lt;li&amp;gt;{ $speaker }&amp;lt;/li&amp;gt;
       }
       &amp;lt;/ul&amp;gt;
     &amp;lt;/div&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.saxonica.com/saxon-js/index.xml&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SaonicaJS&lt;/a&gt;가 &lt;a href=&quot;https://www.linkedin.com/pulse/why-xslt-xquery-coming-back-kurt-cagle&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;XSLT와 XPATH를 지원&lt;/a&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;JSP&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/jspt.html&quot;&gt;JSP&lt;/a&gt;는 PHP와 거의 유사한데 &lt;a href=&quot;https://www.geeksforgeeks.org/jsp-scriptlettag/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Scriptlet&lt;/a&gt;, &lt;a href=&quot;https://www.geeksforgeeks.org/jsp-declaration-tag/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Declaration&lt;/a&gt;, &lt;a href=&quot;https://www.geeksforgeeks.org/jsp-expression-tag/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Expression&lt;/a&gt;으로 나뉘어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 스크립팅이나 정의는 Return 보다는 함수 본문에 있는게 맞다고 생각하기에 Scriptlet이나 Declatation이 굳이 JSX에 필요하다 생각하지는 않는다.&lt;/p&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의 문제 중 하나는 WAS를 사용해 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9E%90%EB%B0%94_%EC%84%9C%EB%B8%94%EB%A6%BF&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;서블렛&lt;/a&gt;으로 변환하는 과정이 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2843&quot; data-origin-height=&quot;850&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KnXIs/btsrrTgsvaw/obIdBwAY8OSX4HwRfJfta0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KnXIs/btsrrTgsvaw/obIdBwAY8OSX4HwRfJfta0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KnXIs/btsrrTgsvaw/obIdBwAY8OSX4HwRfJfta0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKnXIs%2FbtsrrTgsvaw%2FobIdBwAY8OSX4HwRfJfta0%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;2843&quot; height=&quot;850&quot; data-origin-width=&quot;2843&quot; data-origin-height=&quot;850&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web&amp;nbsp;Server와&amp;nbsp;WAS의&amp;nbsp;차이와&amp;nbsp;웹&amp;nbsp;서비스&amp;nbsp;구조&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;h4 data-ke-size=&quot;size20&quot;&gt;Marko&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/marko-js/marko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Marko&lt;/a&gt;는 HTML 확장의 끝판왕인 템플릿 엔진이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서나온 Pug, PHP 종류 &lt;a href=&quot;https://markojs.com/docs/syntax/&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;/p&gt;
&lt;pre id=&quot;code_1692300121478&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.38526191726740655&quot;&gt;&lt;code&gt;// Emmet과 비슷
&amp;lt;div.count/&amp;gt; // &amp;lt;div class=&quot;count&quot;/&amp;gt;
&amp;lt;span#my-id/&amp;gt; // &amp;lt;span id=&quot;my-id&quot;/&amp;gt;

// 자바스크립트의 값들을 바로 사용가능
&amp;lt;div class=myClassName/&amp;gt;
&amp;lt;input type=&quot;checkbox&quot; checked=isChecked /&amp;gt;
&amp;lt;custom-tag string=&quot;Hello&quot;/&amp;gt;
&amp;lt;custom-tag number=1/&amp;gt;
&amp;lt;custom-tag template-string=`Hello ${name}`/&amp;gt;
&amp;lt;custom-tag boolean=true/&amp;gt;
&amp;lt;custom-tag array=[1, 2, 3]/&amp;gt;
&amp;lt;custom-tag object={ hello: &quot;world&quot; }/&amp;gt;
&amp;lt;custom-tag variable=name/&amp;gt;
&amp;lt;custom-tag function-call=user.getName()/&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;a href=&quot;https://markojs.com/docs/conditionals-and-lists/&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;if문은 default argmument, for문은 children callback을 네이티브하게 지원해주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{% start %}{% end %}보다도 깔끔하게 설계 되었고, For문에 있어 Fallback기능이 없어 아쉬울뿐 자바스크립트의 문법을 모두 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;${}의 보간방식도 자바스크립트의 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Template literal&lt;/a&gt;과 일관성이 있어 호감.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue의 &lt;a href=&quot;https://vuejs.org/guide/components/slots.html#named-slots&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;명명된 슬롯&lt;/a&gt;과 비슷한 attribute tag도 제공한다.&lt;/p&gt;
&lt;pre id=&quot;code_1692298132836&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.36257697081243667&quot;&gt;&lt;code&gt;// 조건문
&amp;lt;if(user.loggedOut)&amp;gt;
  &amp;lt;a href=&quot;/login&quot;&amp;gt;Log in&amp;lt;/a&amp;gt;
&amp;lt;/if&amp;gt;
&amp;lt;else-if(!user.trappedForever)&amp;gt;
  &amp;lt;a href=&quot;/logout&quot;&amp;gt;Log out&amp;lt;/a&amp;gt;
&amp;lt;/else-if&amp;gt;
&amp;lt;else&amp;gt;
  Hey ${user.name}!
&amp;lt;/else&amp;gt;

// For 문
// 배열: &amp;lt;for|item, index, array| of=array&amp;gt;
// 객체: &amp;lt;for|key, value| in=object&amp;gt;
// for문: &amp;lt;for|value| from=first to=last step=increment&amp;gt;
&amp;lt;ul&amp;gt;
  &amp;lt;for|color, index| of=colors&amp;gt;
    &amp;lt;li&amp;gt;${index}: ${color}&amp;lt;/li&amp;gt;
  &amp;lt;/for&amp;gt;
&amp;lt;/ul&amp;gt;

// @는 attribute 태그
&amp;lt;my-select&amp;gt;
  &amp;lt;@option&amp;gt;A&amp;lt;/@option&amp;gt;
  &amp;lt;@option&amp;gt;B&amp;lt;/@option&amp;gt;
&amp;lt;/my-select&amp;gt;
// 사용법
&amp;lt;my-select
  option=[
    { renderBody: &quot;A&quot; },
    { renderBody: &quot;B&quot; }
  ]
/&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;/p&gt;
&lt;pre id=&quot;code_1692299788781&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.18992652891623718&quot;&gt;&lt;code&gt;// 이벤트
&amp;lt;button on-click(() =&amp;gt; alert(&quot;Clicked!  &quot;))&amp;gt;
  Celebrate click
&amp;lt;/button&amp;gt;

// 컨텍스트
&amp;lt;context coupon=input.coupon on-buy(handleBuy)&amp;gt;
  &amp;lt;!-- Somewhere nested in the container will be the buy button --&amp;gt;
  &amp;lt;fancy-container/&amp;gt;
&amp;lt;/context&amp;gt;
&amp;lt;context|{ coupon }, emit| from=&quot;fancy-form&quot;&amp;gt;
  Coupon: ${coupon}.
  &amp;lt;button on-click(emit, &quot;buy&quot;)&amp;gt;Buy&amp;lt;/button&amp;gt;
&amp;lt;/context&amp;gt;

// 비동기
&amp;lt;await(searchResultsPromise)&amp;gt;
  &amp;lt;@then|person|&amp;gt;
    Hello ${person.name}!
  &amp;lt;/@then&amp;gt;
  &amp;lt;@catch|err|&amp;gt;
    The error was: ${err.message}.
  &amp;lt;/@catch&amp;gt;
&amp;lt;/await&amp;gt;

// 태그 이름 보간
&amp;lt;${input.renderBody} number=1337 /&amp;gt;

// 재사용
&amp;lt;macro|{ name }| name=&quot;welcome-message&quot;&amp;gt;
  &amp;lt;h1&amp;gt;Hello ${name}!&amp;lt;/h1&amp;gt;
&amp;lt;/macro&amp;gt;
&amp;lt;welcome-message name=&quot;Patrick&quot;/&amp;gt;
&amp;lt;welcome-message name=&quot;Austin&quot;/&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;이는 XML과 거의 흡사한 JSX 스펙보다는 HTML에 가깝고 유연하게 만들어져서 가능했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깔끔한 제어구문들은 2021년에 소개된 &lt;a href=&quot;https://dev.to/ryansolid/introducing-the-marko-tags-api-preview-37o4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Marko Tags API&lt;/a&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;HTMX&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://htmx.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTMX&lt;/a&gt;는 HTML 속성들을 확장해 AJAX, CSS Transition, Websocket등을 사용가능하게 만든다.&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;HTMX기준 &lt;a href=&quot;https://htmx.org/attributes/hx-encoding/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;인코딩&lt;/a&gt;은 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/POST&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;application/x-www-form-urlencoded&lt;/a&gt;를 사용하는 것 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1692302341750&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.2549138765198884&quot;&gt;&lt;code&gt;function MyComponent() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div id=&quot;response-div&quot; /&amp;gt;
      &amp;lt;button
        use:post=&quot;/register&quot;
        use:target=&quot;#response-div&quot; // 또는 useRef 값
        use:swap={&amp;lt;CancleButton /&amp;gt;}
      &amp;gt;
          Register!
      &amp;lt;/button&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;size18&quot;&gt;HLisp와 Hiccup&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트가 함수라면 tag들도 함수로 나타낼 수 있지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 속성들은 &lt;a href=&quot;https://clojure.org/guides/destructuring#_keyword_arguments&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;a href=&quot;https://hoplon.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hoplon&lt;/a&gt;이라는 클로져 스크립트 라이브러리가 &lt;a href=&quot;https://github.com/hoplon/hoplon/wiki/HLisp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HLisp문법&lt;/a&gt;을 사용해 이 방식으로 동작한다.&lt;/p&gt;
&lt;pre id=&quot;code_1692471785221&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3615740114649775&quot;&gt;&lt;code&gt;function Counter() {
  const [count, setCount] = useState(0);
  return div([
    h1(count, class=&quot;header&quot;, style={ fontSize: &quot;12px&quot; }),
    button(&quot;+1&quot;, onClick=(() =&amp;gt; setCount(count + 1))),
    button(&quot;-1&quot;, onClick=(() =&amp;gt; setCount(count - 1)))
  ]);
}&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;물론 리엑트에서 위와 같이 작성한다면 매번 호출되며 Hooks가 작동하지 않는 사소한(?) 단점이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://francodalessio.com/never-call-a-react-function-component/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Never&amp;nbsp;call&amp;nbsp;a&amp;nbsp;React&amp;nbsp;function&amp;nbsp;component&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kentcdodds.com/blog/dont-call-a-react-function-component&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Don't&amp;nbsp;call&amp;nbsp;a&amp;nbsp;React&amp;nbsp;function&amp;nbsp;component&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/igor_bykov/react-calling-functional-components-as-functions-1d3l&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React: Calling functional components as functions&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저의 세계에서는 &lt;a href=&quot;https://clojure.org/reference/data_structures#Keywords&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;키워드&lt;/a&gt;가 &lt;a href=&quot;https://stackoverflow.com/questions/45080469/clojure-convert-persistentvector-of-strings-to-persistentvector-of-keywords&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;벡터에 들어갈 수 &lt;/a&gt;&amp;nbsp;있으므로 각 태그들은 키워드를 사용하고, 컴포넌트 함수들도 벡터에 넣음으로서 정적인 구조를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;속성들이야 Map을 사용하면 되고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://reagent-project.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reagent&lt;/a&gt;의 &lt;a href=&quot;https://github.com/weavejester/hiccup&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hiccup&lt;/a&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSX 자체는 충분히 훌륭하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XML에 가까운 적은 문법의 추가만으로 직관적인 HTML 표현을 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 Marko의 구문이 더 깔끔하며, 가지 않은 길임에는 틀림없어 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Marko 구문을 쓸 수 있다면 Best이겠지만 Babel, 에디터 지원등 전체적인 생태계를 갈아엎어야 하기 때문에 현실적으로 힘들다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 Control 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;/p&gt;
&lt;pre id=&quot;code_1692463193814&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.4399545431402947&quot;&gt;&lt;code&gt;function Counter() {
  const [count, setCount] = useState(0);
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;+1&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count - 1)}&amp;gt;-1&amp;lt;/button&amp;gt;
      &amp;lt;Header count={count} /&amp;gt;
      &amp;lt;Lists count={count}&amp;gt;
        {
          (i) =&amp;gt; &amp;lt;li key={i}&amp;gt;{i}&amp;lt;/li&amp;gt;
        }
      &amp;lt;/Lists&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

function Header({ count }) {
  if(count &amp;gt; 5) {
    return &amp;lt;p&amp;gt;{count}&amp;lt;/p&amp;gt;;
  }
  const SizedHeader = `h${ count &amp;gt; 0 ? count : 1 }`;
  return &amp;lt;SizedHeader&amp;gt;{count}&amp;lt;/SizedHeader&amp;gt;;
}

function Lists({ count, children }) {
  const list = Array.from(
    {length: count },
    (_, i) =&amp;gt; children(i)
  );
  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;Control Flow 컴포넌트들을 제공하고, 디렉티브를 지원하면 이렇게 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Array.from( { length: count }, () =&amp;gt; {})같은 이상한 구문을 생각해야하는 오버헤드가 줄어들고 코드는 선언적으로 변한다.&lt;/p&gt;
&lt;pre id=&quot;code_1692463382520&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8097932480238536&quot;&gt;&lt;code&gt;function Counter() {
  const [count, setCount] = useState(0);
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;+1&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count - 1)}&amp;gt;-1&amp;lt;/button&amp;gt;
      &amp;lt;Header count={count} /&amp;gt;
      &amp;lt;Lists count={count}&amp;gt;
        {
          (i) =&amp;gt; &amp;lt;li key={i}&amp;gt;{i}&amp;lt;/li&amp;gt;
        }
      &amp;lt;/Lists&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

function Header({ count }) {
  const SizedHeader = `h${ count &amp;gt; 0 ? count : 1 }`;
  return (
    &amp;lt;If condition={count &amp;gt; 5}&amp;gt;
      &amp;lt;Then&amp;gt;
        &amp;lt;p&amp;gt;{count}&amp;lt;/p&amp;gt;
      &amp;lt;/Then&amp;gt;
      &amp;lt;Else&amp;gt;
        &amp;lt;SizedHeader&amp;gt;{count}&amp;lt;/SizedHeader&amp;gt;
      &amp;lt;/Else&amp;gt;
    &amp;lt;/If&amp;gt;
  );
}

function Lists({ count, children }) {
  return (
    &amp;lt;ul use:each={count}&amp;gt;
      {
        (_, i) =&amp;gt; children(i)
      }
    &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;그리고 JSX를 더욱 확장해 Marko 방식과 결합하면 더욱 간결하게 만들 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hackmd.io/@markojs/S1gXsc1v3&quot;&gt;Marko Tags API 레퍼런스&lt;/a&gt;와 비교했을때 엄밀하게는 차이가 있는데,&amp;nbsp; JSX와 보다유사하게 만든 의사코드일 뿐이므로 양해바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 몇가지 원칙하에 작성했으니 적당한(?) 트랜스파일러가 있다면 변환 가능하지 않을까&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JSX의 슈퍼셋&lt;/li&gt;
&lt;li&gt;태그 선언 내에서 보간은 ${}로 함&lt;/li&gt;
&lt;li&gt;Marko와 비슷하지만, JSX처럼 {}를 사용하므로 태그내에서 Object는 ({ key: value })처럼 사용해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1692463203950&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6689676962775722&quot;&gt;&lt;code&gt;function Counter() {
  const [count, setCount] = useState(0);
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick() { setCount(count + 1); }&amp;gt;+1&amp;lt;/button&amp;gt;
      &amp;lt;button onClick() { setCount(count - 1); }&amp;gt;-1&amp;lt;/button&amp;gt;
      &amp;lt;Header(count) /&amp;gt;
      &amp;lt;Lists|i| count={count}&amp;gt;
        &amp;lt;li key={i}&amp;gt;{i}&amp;lt;/li&amp;gt;
      &amp;lt;/Lists&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

function Header(_, count) {
  return (
    &amp;lt;If(count &amp;gt; 5)&amp;gt;
      &amp;lt;p&amp;gt;{count}&amp;lt;/p&amp;gt;;
    &amp;lt;/If&amp;gt;
    &amp;lt;Else&amp;gt;
      &amp;lt;h${count &amp;gt; 0 ? count : 1}&amp;gt;{count}&amp;lt;/&amp;gt;
    &amp;lt;/Else&amp;gt;
  );
}

function Lists({ count, children }) {
  return (
    &amp;lt;ul use:for|i| use:in(count)&amp;gt;
      {children(i)}
    &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;h2 data-ke-size=&quot;size26&quot;&gt;CSS&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CSS 관리와 표현의 문제들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS의 표현력에 관해서는 &lt;a href=&quot;https://twitter.com/alstjr7375/status/1675687003751587840?s=20&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;트위터&lt;/a&gt;와 &lt;a href=&quot;https://gall.dcinside.com/mgallery/board/view/?id=github&amp;amp;no=47883&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@teo/css-history-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;역사로&amp;nbsp;알아보는&amp;nbsp;CSS가&amp;nbsp;어려워진&amp;nbsp;이유&lt;/a&gt;와 &lt;a href=&quot;https://velog.io/@teo/CSS%EC%B1%85-%EC%B6%9C%ED%8C%90%EC%A0%9C%EC%9D%98%EB%A5%BC-%EB%B0%9B%EA%B3%A0-%EC%9E%91%EC%84%B1%ED%96%88%EB%8D%98-%EC%9B%90%EA%B3%A0%EB%93%A4-%EA%B3%B5%EC%9C%A0...-%EC%A7%80%EA%B8%88%EC%9D%80-%EB%B6%80%EB%9F%AC%EC%A1%8C%EC%96%B4%EC%9A%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;원고&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://andreipfeiffer.dev/blog/2022/scalable-css-evolution&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;evolution&amp;nbsp;of&amp;nbsp;scalable&amp;nbsp;CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/andreipfeiffer/css-in-js-&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;thorough&amp;nbsp;analysis&amp;nbsp;of&amp;nbsp;CSS-in-TS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://so-so.dev/web/css-in-js-whats-the-defference/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS-in-JS,&amp;nbsp;무엇이&amp;nbsp;다른가요?&lt;/a&gt;&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;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Global namespace: 모든 스타일이 전역적으로 선언되어 중복되지 않는 class 이름을 적용해야 하는 문제&lt;/li&gt;
&lt;li&gt;Dependencies: CSS와 JS간의 의존관계를 관리하기 힘든 문제&lt;/li&gt;
&lt;li&gt;Dead&amp;nbsp;Code&amp;nbsp;Elimination:&amp;nbsp;기능&amp;nbsp;추가,&amp;nbsp;변경,&amp;nbsp;삭제&amp;nbsp;과정에서&amp;nbsp;불필요한&amp;nbsp;CSS를&amp;nbsp;제거하기&amp;nbsp;어려운&amp;nbsp;문제&lt;/li&gt;
&lt;li&gt;Minification:&amp;nbsp;클래스&amp;nbsp;이름의&amp;nbsp;최소화&amp;nbsp;문제&lt;/li&gt;
&lt;li&gt;Sharing&amp;nbsp;Constants:&amp;nbsp;JS&amp;nbsp;코드와&amp;nbsp;상태&amp;nbsp;값을&amp;nbsp;공유할&amp;nbsp;수&amp;nbsp;없는&amp;nbsp;문제&lt;/li&gt;
&lt;li&gt;Non-deterministic&amp;nbsp;Resolution:&amp;nbsp;CSS&amp;nbsp;로드&amp;nbsp;순서에&amp;nbsp;따라&amp;nbsp;스타일&amp;nbsp;우선&amp;nbsp;순위가&amp;nbsp;달라지는&amp;nbsp;문제&lt;/li&gt;
&lt;li&gt;Breaking&amp;nbsp;Isolation:&amp;nbsp;CSS의&amp;nbsp;외부&amp;nbsp;수정을&amp;nbsp;관리하기&amp;nbsp;어려운&amp;nbsp;문제(캡슐화)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 트위터에서 지적되었던 문제들도 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;조합적 폭발: 고대비, 다크모드, 모바일-태블릿-데스크톱-TV를 다루려면 16가지에 대응이 되야하며 OS, RTL등등을 지원하려면 더 많은 조합들이 $2^n$으로 발생한다&lt;/li&gt;
&lt;li&gt;다차원적 위계: CSS의 시각적 위계와 HTML의 정보구조 위계&lt;/li&gt;
&lt;li&gt;디자인 일관성: 디자인적 규칙을 일관적으로 관리할 수 있어야 함&lt;/li&gt;
&lt;/ol&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;올바르게&quot; 구성하기에는 많은 어려움이 따른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 유지관리하고 있는 프로젝트의 탭 바의 레이아웃 구성을 만드는 코드(&lt;a href=&quot;https://github.com/black7375/Firefox-UI-Fix/tree/master/src/tabbar/layout&quot;&gt;정의&lt;/a&gt;, &lt;a href=&quot;https://github.com/black7375/Firefox-UI-Fix/blob/bf37686eb3bb18e62442502f44828c4724b3087c/css/leptonChrome.css#L4510-L5961&quot;&gt;컴파일 결과&lt;/a&gt;)를 보고와보자 ㅋㅋㅋㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저 버전, OS, 활성화 가능한 창 버튼, 전체화면 여부, One liner나 숨기기와 같은 레이아웃 종류등등 많은 것을 모두 고려해야 했다.&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;/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;size18&quot;&gt;&lt;b&gt;CSS와 JS 통신&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 CSS In JS를 사용함으로서 매우 쉽게 해결이 가능한 문제들이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JS 만으로 CSS를 관리하면 상태 값 공유는 JS에 있는 값을 사용하면 되고, 의존 관계 역시 JS의 값이 우선되므로 해결이 가능하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Sharing&amp;nbsp;Constants:&amp;nbsp;JS&amp;nbsp;코드와&amp;nbsp;상태&amp;nbsp;값을&amp;nbsp;공유&lt;/li&gt;
&lt;li&gt;Dependencies: CSS와 JS간의 의존관계를 관리&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;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/var&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS var&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;size18&quot;&gt;&lt;b&gt;Class 이름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class 이름의 많은 것은 CSS module이 해결해 줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 핵심은 &lt;a href=&quot;https://en.wikipedia.org/wiki/Variable_shadowing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;쉐도잉&lt;/a&gt; 지원으로, Scoped CSS의 긍정적인 면이라 할 수 있다.&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;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6ifpE/btsrtctjW76/vzVywA1kzFcEZnrTSVAkoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6ifpE/btsrtctjW76/vzVywA1kzFcEZnrTSVAkoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6ifpE/btsrtctjW76/vzVywA1kzFcEZnrTSVAkoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6ifpE%2FbtsrtctjW76%2FvzVywA1kzFcEZnrTSVAkoK%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;700&quot; height=&quot;700&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.javascriptstuff.com/what-are-css-modules/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What&amp;nbsp;are&amp;nbsp;CSS&amp;nbsp;Modules?&amp;nbsp;A&amp;nbsp;visual&amp;nbsp;introduction&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Global namespace: 해시값을 추가적으로 적용하면 전역적으로 고유해짐&lt;/li&gt;
&lt;li&gt;Minification: 해시값만 남기면 클래스 이름을 축소하기가 쉬움&lt;/li&gt;
&lt;li&gt;Non-deterministic Resolution(일부): BEM 방법론처럼 Specificity를 하나로 관리하도록 만들어 일부 해결&lt;/li&gt;
&lt;li&gt;Breaking Isolation(일부): 이름이 겹치지 않으므로(무책임하지만ㅠㅠ) Scoped class를 하나 더 만들어 확장하기&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;트위터 불평글에서 Scoped CSS에 관해 내가 공감한다는 부분이 바로 Non-deterministic Resolution과 Breaking Isolation이다.&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;b&gt;논리와 반복적 표현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 일부 해결이 가능한 문제가 더 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조합적 폭발(일부): 전처리기나 CSS In JS에서 논리와 반복적 표현이 가능해짐으로 인해 &quot;잘 작성하면&quot; 해결 가능&lt;/li&gt;
&lt;/ul&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;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&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;Dead Code Elimination: AST를 만들고 번들러를 이용해 추적해야 하며, Split된 CSS는 런타임시 &lt;a href=&quot;https://blog.cometkim.kr/posts/css-optimization-in-jamstack/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;어떻게 불러와야 할지&lt;/a&gt;에 대한 문제가 생긴다.&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;size18&quot;&gt;&lt;b&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;조합적 폭발: 조합을 쉽고 버그없이 할 수 있어야 한다&lt;/li&gt;
&lt;li&gt;다차원적 위계: 시각적 위계와 의미론적 위계를 결국 모두 다룰 수 있어야 한다&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;size18&quot;&gt;&lt;b&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;Non-deterministic Resolution: 스타일 우선 순위를 개발자가 쉽게 정할 수 있도록 해야 한다&lt;/li&gt;
&lt;li&gt;Breaking Isolation: 확장 대상의 CSS를 명시적으로 알 수 있으며, Override와 Emit이 쉬워야 한다&lt;/li&gt;
&lt;li&gt;디자인 일관성: 중앙에서 관리할 필요가 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전처리기와 CSS In JS: 리터럴 구문&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://webdesign.tutsplus.com/sass-vs-less-vs-stylus-preprocessor-shootout--net-24320t&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sass&amp;nbsp;vs.&amp;nbsp;LESS&amp;nbsp;vs.&amp;nbsp;Stylus:&amp;nbsp;Preprocessor&amp;nbsp;Shootout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raygun.com/blog/css-preprocessors-examples/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Popular&amp;nbsp;CSS&amp;nbsp;preprocessors&amp;nbsp;with&amp;nbsp;examples:&amp;nbsp;Sass,&amp;nbsp;Less,&amp;nbsp;Stylus&amp;nbsp;and&amp;nbsp;more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ui-workarounds.com/sass-vs-less-vs-stylus-and-the-winner-is/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SASS&amp;nbsp;vs&amp;nbsp;LESS&amp;nbsp;vs&amp;nbsp;Stylus&amp;nbsp;&amp;ndash;&amp;nbsp;and&amp;nbsp;the&amp;nbsp;winner&amp;nbsp;is?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 CSS In JS를 먼저 살펴보지 않은 이유는 전처리기가 일반 CSS와 비슷하기 때문이다.&lt;/p&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 In JS 라이브러리가 있다는 가정하에 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 CSS In JS 라이브러리에 대한 제안이 될 수도 있겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;올해 말쯤에 프로젝트들이 정리되면 만들어보고 싶긴한데...&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제작하려는 목적으로 설계하는 것처럼 진행하느라 조금 늘어짐은 감안바란다. (일종의 RFC 느낌)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 정적 CSS 추출등의 최적화를 감안하지 않은 API들이 있다.&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;Template String vs Object Style&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://oleg008.medium.com/template-strings-vs-objects-in-cssinjs-4028ecc420b2&quot;&gt;Template&amp;nbsp;Strings&amp;nbsp;vs.&amp;nbsp;Objects&amp;nbsp;in&amp;nbsp;CSSinJS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS In JS 세계에서 CSS를 표현할 때는 두가지 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Template string과 Object style이다.&lt;/p&gt;
&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;CSS 속성과 문법을 그대로 사용가능하기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TGfQx/btsrxnJfr1P/h7d1u5NKop0M2Kugdj9ZH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TGfQx/btsrxnJfr1P/h7d1u5NKop0M2Kugdj9ZH1/img.png&quot; style=&quot;width: 50.3099%; margin-right: 10px;&quot; width=&quot;700&quot; height=&quot;246&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;245&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50.9&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TGfQx/btsrxnJfr1P/h7d1u5NKop0M2Kugdj9ZH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTGfQx%2FbtsrxnJfr1P%2Fh7d1u5NKop0M2Kugdj9ZH1%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;700&quot; height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HSdUJ/btsrEq5h8nH/FjK9N9xfUnffz7cQJKgnpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HSdUJ/btsrEq5h8nH/FjK9N9xfUnffz7cQJKgnpk/img.png&quot; style=&quot;width: 48.5273%;&quot; width=&quot;700&quot; height=&quot;255&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;254&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.1&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HSdUJ/btsrEq5h8nH/FjK9N9xfUnffz7cQJKgnpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHSdUJ%2FbtsrEq5h8nH%2FFjK9N9xfUnffz7cQJKgnpk%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;700&quot; height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;템플릿 문자열 vs 객체 스타일&lt;/p&gt;
&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://developer.mozilla.org/en-US/docs/Web/API/CSSStyleRule/style&quot;&gt;CSSOM&lt;/a&gt;과 동일한 표현방식이고 많은 보간이 필요할 때 나은 방식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J4hTc/btsrwX460L2/KaStkduppVQYLcgD5kDYk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J4hTc/btsrwX460L2/KaStkduppVQYLcgD5kDYk0/img.png&quot; style=&quot;width: 50.5732%; margin-right: 10px;&quot; width=&quot;700&quot; height=&quot;209&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;209&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;51.17&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J4hTc/btsrwX460L2/KaStkduppVQYLcgD5kDYk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ4hTc%2FbtsrwX460L2%2FKaStkduppVQYLcgD5kDYk0%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;700&quot; height=&quot;209&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1e44U/btsrB4hRmQv/wCIU0ew1q62Jc88CRdJId1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1e44U/btsrB4hRmQv/wCIU0ew1q62Jc88CRdJId1/img.png&quot; style=&quot;width: 48.264%;&quot; width=&quot;700&quot; height=&quot;219&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;219&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;48.83&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1e44U/btsrB4hRmQv/wCIU0ew1q62Jc88CRdJId1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1e44U%2FbtsrB4hRmQv%2FwCIU0ew1q62Jc88CRdJId1%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;700&quot; height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;/div&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;CSS In JS를 사용하는 이유는 기본적으로 많은 규칙을 다루고, JS와의 상호작용을 위해 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때문에 CSS In JS을 사용한다면 Object 스타일을 기본으로 두어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디자인 규칙이 적고 JS와의 상호작용이 불필요하다면 CSS 전처리기를 사용함이 더 낫다.&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;CSS In JS의 근본적 한계&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Object Style을 기본적으로 사용한다 가정하고 단점들을 파보도록 하자.&lt;/p&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 In JS의 근본적 한계라 하면, CSS 문법이 리터럴이 아니라는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때문에 컬러코드는 기본적으로 에디터에서 picker등이 동작하지 않으며, CSS 유닛(&quot;px&quot;, &quot;rem&quot;, &quot;vw&quot;등)과 값들(&quot;visible&quot;, &quot;space-between&quot; 등)을 String으로 취급하지 않고는 사용할 수가 없다.&lt;/p&gt;
&lt;pre id=&quot;code_1692401663129&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.4860273320182469&quot;&gt;&lt;code&gt;// 이하 css()를 클래스이름을 생성하는 임의의 CSS In JS 함수로 취급한다
const sample = css({
  // 색상
  color: &quot;red&quot;,
  background: &quot;#EEEEEE&quot;,

  // 단위
  fontSize: &quot;16px&quot;,
  fontSize: &quot;1rem&quot;,

  // 값
  visibility: &quot;visible&quot;,
  justifyContent: &quot;space-between&quot;
});&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;a href=&quot;https://marketplace.visualstudio.com/items?itemName=AntiAntiSepticeye.vscode-color-picker&quot;&gt;VS Code&lt;/a&gt;, &lt;a href=&quot;https://jblevins.org/log/rainbow-mode&quot;&gt;Emacs&lt;/a&gt;) 덕분에 어느정도 해결이 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blmohF/btsrxm20wjt/kKz0cD6AkSdsg6oz7xP2EK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blmohF/btsrxm20wjt/kKz0cD6AkSdsg6oz7xP2EK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blmohF/btsrxm20wjt/kKz0cD6AkSdsg6oz7xP2EK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblmohF%2Fbtsrxm20wjt%2FkKz0cD6AkSdsg6oz7xP2EK%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;864&quot; height=&quot;345&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;345&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;단위 기능을 CSS가 아닌 범용 언어에서 구현이 가능하냐고 묻는다면 &lt;a href=&quot;https://black7375.tistory.com/85#4.-%ED%8E%B8%EC%9D%98%EC%84%B1%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8B%A4%EC%96%91%ED%95%9C-%EA%B8%B0%EB%8A%A5%EB%93%A4&quot;&gt;러스트글&lt;/a&gt;에도 적었지만 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;F#은 구현&lt;/a&gt;해두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입시스템과 언어 구문의 지원이 필요하지만 &lt;b&gt;진지하게&lt;/b&gt; UI와 스타일링을 다루려면 필요한 기능이라 생각된다.&lt;/p&gt;
&lt;pre id=&quot;code_1692401729779&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.08478045534577472&quot;&gt;&lt;code&gt;let dpiValue = 150.0&amp;lt;dpi&amp;gt;
let inchValue = 8.0&amp;lt;inch&amp;gt;
let pxValue = 1200.0&amp;lt;px&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS의 각 단위에 대한 변환은 &lt;a href=&quot;https://github.com/black7375/sass-unitconverter&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;px과 같이 일반적인 값을 받는 속성이라면, JSS의 &lt;a href=&quot;https://cssinjs.org/jss-plugin-default-unit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;default-unit&lt;/a&gt;이나&amp;nbsp; Vanilla Extract의 &lt;a href=&quot;https://vanilla-extract.style/documentation/styling/#unitless-properties&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;unitless property&lt;/a&gt;처럼 정의 할 수는 있겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1692403623924&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3606106573234855&quot;&gt;&lt;code&gt;const sample = css({
  // cast to pixels
  padding: 10,
  marginTop: 25,

  // unitless properties
  flexGrow: 1,
  opacity: 0.5
});&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;파싱 문제로 인해 특수기호 중 '$'와 '_'만이 사용가능하고 &quot;::before&quot;이나 &quot;.my-selector&quot;처럼 다른 특수기호가 들어갈 경우에는 &quot;로 감싸줘야 동작한다.&lt;/p&gt;
&lt;pre id=&quot;code_1692468020408&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.2962439667122503&quot;&gt;&lt;code&gt;const sample = {
  $name$: &quot;$ is literal&quot;,
  _name_: &quot;_ is literal&quot;,
  &quot;::before&quot;: &quot;is not literal&quot;,
  &quot;.my-selector&quot;: &quot;is not literal&quot;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SCSS와 중첩구문&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sass-lang.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SCSS&lt;/a&gt;가 선도한 부분은 중첩구문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길다란 font-size, font-weight &lt;a href=&quot;https://sass-lang.com/documentation/style-rules/declarations/#nesting&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;속성을 중첩&lt;/a&gt; 가능하도록 만들고, &amp;amp;를 이용해 직관적인 &lt;a href=&quot;https://sass-lang.com/documentation/style-rules/parent-selector/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;셀렉터 중첩&lt;/a&gt;도 지원한다.&lt;/p&gt;
&lt;pre id=&quot;code_1692321108473&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3913782449917599&quot;&gt;&lt;code&gt;.sample {
  width: 200px;
  font: {
    /* 속성중첩 */
    size: 10px;
    weight: bold;
  }

  /* 셀렉터 중첩 */
  p {
    color: red;
  }
  &amp;amp;:hover p {
    background: blue;
  }
  a &amp;amp; {
    background: grey;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 컴파일된 결과.&lt;/p&gt;
&lt;pre id=&quot;code_1692321137445&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6029395422738729&quot;&gt;&lt;code&gt;.sample {
  width: 200px;
  font-size: 10px;
  font-weight: bold;
}
.sample p {
  color: red;
}
.sample:hover p {
  background: blue;
}
a .sample {
  background: grey;
}&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;CSS In JS에서는 다음과 같이 할 수 있을 것 이다.&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;값이 객체 형식일때, 속성에 &quot;&amp;amp;&quot;이 포함되면 셀렉터로 취급&lt;br /&gt;&lt;a href=&quot;https://emotion.sh/docs/object-styles#child-selectors&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Emotion의 방식&lt;/a&gt;이며, Vanilla Extract의 &lt;a href=&quot;https://vanilla-extract.style/documentation/styling/#complex-selectors&quot;&gt;complex selector 방식&lt;/a&gt;은 중첩을 강요해 별로라고 생각한다&lt;/li&gt;
&lt;li&gt;값이 객체 형식일때, 속성에 &quot;&amp;amp;&quot;이 포함되지 않으면 중첩 프로퍼티로 취급&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1692403118330&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8816974789349742&quot;&gt;&lt;code&gt;const sample = css({
  width: 200,
  font: {
    size: 10,
    weight: &quot;bold&quot;
  },

  &quot;&amp;amp; p&quot;: {
    color: &quot;red&quot;
  },
  &quot;&amp;amp;:hover p&quot;: {
    background: &quot;blue&quot;
  },
  &quot;a &amp;amp;&quot;: {
    background: &quot;grey&quot;
  }
});&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;Default unit의 예처럼 무언가 간단하게 만들 수 있지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vanilla Extract에서는 &lt;a href=&quot;https://vanilla-extract.style/documentation/styling/#simple-pseudo-selectors&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Simple pseudo selectors&lt;/a&gt;라 하여 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pseudo-classes&lt;/a&gt;와 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pseudo-elements&lt;/a&gt;는 &quot;&amp;amp;&quot; 표시가 없어도 되게 만들었다. (자식 선택자 &quot;&amp;gt;&quot;나 &quot;[attribute]&quot;에도 적용될 수 있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;:hover나 ::before는 대부분의 경우 부모요소를 사용하므로 더 나은 기본값이라 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 파싱 문제 때문에&amp;nbsp; &quot;로 감싸는 구문을 강요한다는 문제가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692407326131&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6124359503547759&quot;&gt;&lt;code&gt;const sample = css({
  &quot;:hover&quot;: {
    background: &quot;blue&quot;
  },
  &quot;::before&quot;: {
    background: &quot;grey&quot;
  }
});&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;Panda CSS는 _로 시작하는 &lt;a href=&quot;https://panda-css.com/docs/concepts/conditional-styles&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Conditional Styles&lt;/a&gt;을 가지고 있다. ('_'과 '$'만이 속성이름으로 자유롭게 사용할 수 있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 조건 스타일때 base 속성은 원본에 적용되도록 하여 관심사를 모을 수 있는 Property based condition 중첩구문을 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Panda CSS 접근법의 문제라면 _dark가 &amp;amp;.dark, .dark &amp;amp;를 의미하는 것처럼 임의의 클래스를 삽입하는 Adhoc스러움이다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값이 객체 형식일때, 속성의 시작이 &quot;_&quot;과 &quot;__&quot;일 경우 각각 &quot;:&quot;과 &quot;::&quot;로 대체&lt;/li&gt;
&lt;li&gt;값이 객체 형식일때, 속성의 시작이 &quot;:&quot;일 경우 &quot;&amp;amp;:&quot;로 컴파일&lt;/li&gt;
&lt;li&gt;값이 객체 형식일때, base나 presudo 셀렉터를 적용가능&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1692408600516&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.24268264460549815&quot;&gt;&lt;code&gt;const sample = css({
  background: &quot;#EEEEEE&quot;,
  _hover: {
    background: &quot;blue&quot;
  },
  __before: {
    background: &quot;grey&quot;
  },

  // 또는
  background: {
    base: &quot;#EEEEEE&quot;,
    _hover: &quot;blue&quot;,
    __before: &quot;grey&quot;
  }
});&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;속성 중첩과 조건 중첩이 충돌할 수 있다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 &quot;base&quot;와 동일한 이름을 가지는 속성이 없으므로 충돌하지 않는다.&lt;/p&gt;
&lt;pre id=&quot;code_1692410057642&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9833346792637535&quot;&gt;&lt;code&gt;const sample = css({
  width: 200,
  margin: {
    // 속성 중첩
    base: &quot;5% 0&quot;,
    block: &quot;0.5rem&quot;,
    inline: &quot;3%&quot;,

    // 조건 중첩
    _hover: &quot;6% 0&quot;,
    __before: {
      base: &quot;2rem 3rem&quot;,
      block: &quot;2rem&quot;,
      inline: &quot;3rem&quot;
    }
  },
});&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;pre id=&quot;code_1692410890812&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.19962080945082772&quot;&gt;&lt;code&gt;const sample = css({
  width: 200,
  margin$: {
    block: &quot;0.5rem&quot;,
    inline: &quot;3%&quot;,
    __before: {
      block: &quot;2rem&quot;,
      inline: &quot;3rem&quot;
    }
  },

  margin: {
    base: &quot;5% 0&quot;,
    _hover: &quot;6% 0&quot;,
    __before: base: &quot;2rem 3rem&quot;
  }
});&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;,&quot;가 있을 때를 감지해 split하면 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값이 객체 형식일때, 속성에 &quot;,&quot;이 포함되어 있으면 여러 셀렉터가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1692564960553&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.059366520831360736&quot;&gt;&lt;code&gt;const sample = css({
  &quot;_hover, _active&quot;: {
    color: &quot;red&quot;
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Less와 속성 병합&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://lesscss.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Less&lt;/a&gt;의 가장 큰 특징은 &lt;a href=&quot;https://lesscss.org/features/#variables-feature-lazy-evaluation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lazy&lt;/a&gt;하다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 자바스크립트는 strict함이 기본이기에 좋지 않은 방식이라 CSS In JS에 적용하기에는 좋지 않은 방식이라 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://lesscss.org/features/#import-atrules-feature&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;import하는 방식&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;a href=&quot;https://lesscss.org/features/#variables-feature-variable-variables&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;window[&quot;VAR_NAME&quot;] 또는 this[&quot;VAR_NAME&quot;]처럼 참조할 수는 있지만, 너무 비직관적이고 실수를 조장한다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C언어의 포인터에서 헷갈리는 사람들이 많음을 감안해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1692413068085&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5116164261419202&quot;&gt;&lt;code&gt;/* 일관성을 위해 SCSS 구문처럼 사용 */
$primary: green;
.section {
  $color: primary;

  .element {
    color: $$color; /* green */
  }
}&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;a href=&quot;https://lesscss.org/features/#merge-feature&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Merge properties&lt;/a&gt;은 꽤 유용해보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;box-shadow&lt;/a&gt;나 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;transform&lt;/a&gt;처럼 길다란 속성들은 한줄로 작성하기가 어려웠기 때문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692413338067&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.93032219811057&quot;&gt;&lt;code&gt;.sample {
  /* Merge with Comma */
  box-shadow+: inset 0 0 10px #555;
  box-shadow+: 0 0 20px black;

  /* Merge with Space */
  transform+_: scale(2);
  transform+_: rotate(15deg);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692413406992&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7603582628036413&quot;&gt;&lt;code&gt;.sample {
  box-shadow: inset 0 0 10px #555, 0 0 20px black;
  transform: scale(2) rotate(15deg);
}&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;스페이스는 _과 비슷하므로 콤마에는 $을 붙이는게 좋을듯 하다.&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;/ul&gt;
&lt;pre id=&quot;code_1692413831031&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.062182816566016985&quot;&gt;&lt;code&gt;const sample = css({
  /* Merge with Comma */
  boxShadow$: &quot;inset 0 0 10px #555&quot;,
  boxShadow$: &quot;0 0 20px black&quot;,

  /* Merge with Space */
  transform_: &quot;scale(2)&quot;,
  transform_: &quot;rotate(15deg)&quot;
});&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;CSS In JS 세계(&lt;a href=&quot;https://emotion.sh/docs/object-styles#fallbacks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Emotion&lt;/a&gt;, &lt;a href=&quot;https://vanilla-extract.style/documentation/styling/#fallback-styles&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vanilla Extract&lt;/a&gt;)에서는 속성 값의 Fallback을 위한 고유한 접근법도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692565884678&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7729655630248937&quot;&gt;&lt;code&gt;const sample = css({
  // In Firefox and IE the &quot;overflow: overlay&quot; will be
  // ignored and the &quot;overflow: auto&quot; will be applied
  overflow: ['auto', 'overlay']
});&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692565928039&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8610522730568609&quot;&gt;&lt;code&gt;.sample {
  overflow: auto;
  overflow: overlay;
}&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값이 배열일 때 일반적인 경우면 Fallback으로 취급&lt;/li&gt;
&lt;li&gt;$로 끝나면 ','로 이으며, _으로 끝나면 공백으로 이음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1692566224107&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.19865044858182823&quot;&gt;&lt;code&gt;const sample = css({
  overflow: [&quot;auto&quot;, &quot;overlay&quot;],
  boxShadow$: [&quot;inset 0 0 10px #555&quot;, &quot;0 0 20px black&quot;],
  transform_: [&quot;scale(2)&quot;, &quot;rotate(15deg)&quot;]
});&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;또는 griffel의 &lt;a href=&quot;https://griffel.js.org/react/api/shorthands&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;shorthands&lt;/a&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;Stylus와 참조&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stylus-lang.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Stylus&lt;/a&gt;는 &lt;a href=&quot;https://stylus-lang.com/docs/selectors.html#partial-reference&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참조&lt;/a&gt;에 대한 아이디어가 재미있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692417641739&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.32577388698577203&quot;&gt;&lt;code&gt;/* 역시 SCSS 구문처럼 수정됨 */
.sample {
  &amp;amp;_level1 {
    &amp;amp;_level2 {
      /* 루트 */
      ^[0]:hover {
        width: 0px;
      }

      /* 정방향 */
      ^[1]:hover {
        width: 1px;
      }
      ^[2]:hover {
        width: 2px;
      }
      

      /* 역방향 */
      ^[-1]:hover {
        width: -1px;
      }
      ^[-2]:hover {
        width: -1px;
      }
    }
  }
}&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;그러나 깊이를 숫자로 표현하면 Less의 변수 이름기반 참조처럼 혼동이 올 여지가 커보인다.&lt;/p&gt;
&lt;pre id=&quot;code_1692417886355&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8591219681108052&quot;&gt;&lt;code&gt;.sample:hover {
  width: 0px;
}

.sample_level1:hover {
  width: 1px;
}
.sample_level1_level2:hover {
  width: 2px;
}

.sample_level1:hover {
  width: -1px;
}
.sample:hover {
  width: -2px;
}&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;대신 XPath와 비슷한 &lt;a href=&quot;https://stylus-lang.com/docs/selectors.html#initial-reference&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;경로 기반 참조&lt;/a&gt;는 사용하기 좋아보인다. (CSS In JS에 적합하지 않다고 생각하지만..)&lt;/p&gt;
&lt;pre id=&quot;code_1692476064356&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8279499922506649&quot;&gt;&lt;code&gt;.sample
  &amp;amp;_level1 {
    &amp;amp;_level2 {
      /* 항상 루트 참조 */
      /:hover {
        width: 0px;
      }

      /* 항상 첫번째 참조 */
      ~/:hover {
        width: 1px;
      }

      /* 상대 참조 */
      ../:hover {
        width: 2px;
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692477066986&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3751039503846467&quot;&gt;&lt;code&gt;:hover {
  width: 0px;
}
.sample:hover {
  width: 1px;
}
.sample_level1:hover {
  width: 2px;
}&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;다른 라이브러리중에서는 JSS의 &lt;a href=&quot;https://cssinjs.org/jss-plugin-nested?v=v10.10.0#use-rulename-to-reference-a-local-rule-within-the-same-style-sheet&quot;&gt;셀렉터 참조&lt;/a&gt;의 아이디어도 좋아보인다.&lt;/p&gt;
&lt;pre id=&quot;code_1692477224840&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.37667230016538045&quot;&gt;&lt;code&gt;const styles = {
  container: {
    // Reference the local rule &quot;button&quot;.
    '&amp;amp; $button': {
      padding: '10px'
    },
  },
  button: {
    color: 'grey'
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692477246649&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9968060218907511&quot;&gt;&lt;code&gt;.container-0:focus .button-1 {
  color: blue;
}
.button-1 {
  color: grey;
}&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;&amp;amp;&quot;이 포함되야 셀렉터로 취급한다고 정의했기 때문이다.&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;답은 Vanilla Extract의 &lt;a href=&quot;https://vanilla-extract.style/documentation/styling/#circular-selectors&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;셀렉터 참조&lt;/a&gt; 방식이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692478585355&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3342020704120936&quot;&gt;&lt;code&gt;const parent = css({
  width: &quot;1px&quot;
});

const child = css({
  [`${parent} &amp;amp;`]: {
    width: &quot;2px&quot;
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692478983460&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6812278423537654&quot;&gt;&lt;code&gt;.parent {
  width: 1px;
}
.parent .child {
  width: 2px;
}&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;문제는 Vanilla Extract가 그렇듯 상호 참조가 일어날때는 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/get&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;접근자&lt;/a&gt;를 사용해야 할 필요가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692478888704&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.18513260904922402&quot;&gt;&lt;code&gt;const parent = css({
  [`&amp;amp;:hover ${child}`]: {
    width: &quot;1px&quot;
  }
});
const child = css({
  get [`${parent} &amp;amp;`]() {
    return {
      width: &quot;2px&quot;
    }
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692479421283&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5485272766249248&quot;&gt;&lt;code&gt;.parent:hover .child {
  width: 1px;
}
.parent .child {
  width: 2px;
}&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;이럴때는 JSS의 방식으로 돌아가보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스가 첫번째 레벨에만 있다고 가정한다면 (Vanilla extract의 &lt;a href=&quot;https://vanilla-extract.style/documentation/api/style-variants/&quot;&gt;styleVariants,&lt;/a&gt; Griffel의 &lt;a href=&quot;https://griffel.js.org/react/api/make-styles&quot;&gt;makeStyles&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSS와 같이 로컬 규칙에서 명시적으로 참조할 수 있지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 다루어주는 함수를 하나 추가하자.&lt;/p&gt;
&lt;pre id=&quot;code_1692479921197&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.2564779777392633&quot;&gt;&lt;code&gt;const classes = cssVariants({
  parent: {
    &quot;:hover $child&quot;: {
      width: &quot;1px&quot;
    }
  },
  child: {
    &quot;$parent &amp;amp;&quot;: {
      width: &quot;2px&quot;
    }
  }
});&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;selector 참조기능에 대한 탐색을 충분히 한 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stylus-lang.com/docs/variables.html#property-lookup&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;속성값 참조&lt;/a&gt;는 어떨까? stylus에서 완성도 있게 제공하고 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692418136979&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8903308406726421&quot;&gt;&lt;code&gt;.sample {
  width: 100px;
  margin-left: @width;
  margin-top: -(@width / 2);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692480230381&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9136277744687712&quot;&gt;&lt;code&gt;.sample {
  width: 100px;
  margin-left: 100px;
  margin-top: -50px;
}&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;CSS In JS에서는 어떻게 기능을 제공할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 참조할 때는 Stylus와 똑같이 해도 되겠지만, 계산이 필요한 경우에는&amp;nbsp; 명시적인 계산을 하도록 해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1692480434104&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5615074576309853&quot;&gt;&lt;code&gt;const sample = css({
  width: 100,
  marginLeft: &quot;@width&quot;,
  marginTop: &quot;calc(-(@width / 2))&quot;
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일 되기 전 중간 형식은 역시 접근자를 활용하면 쉽게 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692490206938&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.40063095668917226&quot;&gt;&lt;code&gt;const sample = css({
  width: 100,
  get marginLeft() {
    return this.width;
  }
  get marginTop() {
    return -(this.width / 2);
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PostCSS와 CSS 확장&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3대 CSS 전처리기를 살펴보았는데, 뒤따라 항상 언급되는 존재가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 CSS계의 Babel인 &lt;a href=&quot;https://github.com/postcss/postcss&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PostCSS&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;a href=&quot;https://github.com/csstools/postcss-plugins/tree/main/plugin-packs/postcss-preset-env&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;postcss-preset-env&lt;/a&gt;는 기본값으로 다양한 문법을 확장해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 간편한 &lt;a href=&quot;https://preset-env.cssdb.org/features/#media-query-ranges&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;미디어쿼리 범위&lt;/a&gt;가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692482232419&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.280457737840611&quot;&gt;&lt;code&gt;@media (480px &amp;lt;= width &amp;lt; 768px) {
  .sample {
    font-family: system-ui;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692482244723&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8981799787606747&quot;&gt;&lt;code&gt;@media (min-width: 480px) and (max-width: 767.98px) {
  .sample {
      font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
  }
}&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;벤더 prefix도 적절히 잘 해주니, 기본값으로 설정 후 세부적인 룰은 유저들에게 맡기면 될 것 같다.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋다. 이제 (가상)CSS In JS의 리터럴 구문이 탄생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해를 돕기위한 예일 뿐이므로, 보통은 다음처럼 길게 중첩될일이 없을 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692485209512&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.609953282894087&quot;&gt;&lt;code&gt;const sample = cssVariants({
  parent: {
    width: 200, // Unitless
    margin: {
      // 속성 중첩
      base: &quot;5% 0&quot;,
      block: &quot;0.5rem&quot;,
      inline: {
        base: &quot;3%&quot;,
        &quot;h1 &amp;amp;, &amp;amp; div&quot;: &quot;4%&quot; // 셀렉터 중첩
      },

      // 조건 중첩
      _hover: &quot;6% 0&quot;,
      __before: {
        block: &quot;2rem&quot;,
        inline: &quot;calc(@block / 2)&quot; // 속성 참조
      }
    }
  },
  child: {
    // 셀렉터 참조
    &quot;$parent &amp;amp;&quot;: {
        overflow: [&quot;auto&quot;, &quot;overlay&quot;],  // Fallback
        boxShadow$: [&quot;inset 0 0 10px #555&quot;, &quot;0 0 20px black&quot;], // 콤마로 속성 병합
        transform_: [&quot;scale(2)&quot;, &quot;rotate(15deg)&quot;]  // 공백으로 속성 병합
    },
    // PostCSS 연계
    &quot;@media&quot;: {
      &quot;width &amp;lt; 480px&quot;: {
        font-family: system-ui
      },
      &quot;480px &amp;lt;= width &amp;lt; 768px&quot;: {
        color: color-mix(in lch, purple 50%, plum 50%)
      }
    }
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692485638115&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9590311851705697&quot;&gt;&lt;code&gt;.parent {
  width: 200px;
  margin: 5% 0;
  margin-block: 0.5rem;
  margin-inline: 3%;
}
h1 .parent,
.parent div {
  margin-inline: 4%;
}

.parent:hover {
  margin: 6% 0;
}
.parent::before {
  margin-block: 2rem;
  margin-inline: 1rem;
}

.parent .child {
  overflow: auto;
  overflow: overlay;
  box-shadow: inset 0 0 10px #555, 0 0 20px black;
  transform: scale(2) rotate(15deg);
}

@media (max-width: 479.98px) {
  .child {
    font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
  }
}
@media (min-width: 480px) and (max-width: 767.98px) {
  .child {
    color: rgb(175, 92, 174);
  }
}&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;&lt;a href=&quot;https://github.com/activeguild/css-to-vanilla-extract&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS-to-vanilla-extract&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;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;합성(Composition)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 전 리터럴 구문은 사실상 CSS 클래스 1개일때를 위한 문법이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692566900758&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3250159484457903&quot;&gt;&lt;code&gt;function Sample() {
  return &amp;lt;div className={css({ color: &quot;red&quot;, padding: 3 })}&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;현실적으로는 여러가지 클래스가 사용되기 마련이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692567040440&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5400326973376304&quot;&gt;&lt;code&gt;function Sample() {
  const activate = useState(true);
  return &amp;lt;div className={`class1 class2 ${activate &amp;amp;&amp;amp; &quot;class3&quot;}`}&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;이럴때 필요한 방식이 합성이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://emotion.sh/docs/object-styles#composition&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Emotion&lt;/a&gt;, &lt;a href=&quot;https://vanilla-extract.style/documentation/style-composition/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vanilla Extract&lt;/a&gt;등에서 사용되어 검증된 방법.&lt;/p&gt;
&lt;pre id=&quot;code_1692569143017&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6781032858929809&quot;&gt;&lt;code&gt;function Sample() {
  const activate = useState(true);
  return &amp;lt;div className={css([&quot;class1&quot;, &quot;class2&quot;, activate &amp;amp;&amp;amp; &quot;class3&quot;])}&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;API Wrapper로만 만들면 상관없겠지만..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 부분을 직접 구현하려면, Vanilla Extract가 언급하듯 단일 클래스로 컴파일 되어야 특이도 문제가 생기지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://weser.io/blog/the-shorthand-longhand-problem-in-atomic-css&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Shorthand-Longhand Problem in Atomic CSS&lt;/a&gt;라는 글도 읽어봄직하다.&lt;/p&gt;
&lt;pre id=&quot;code_1692569739911&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.4984168525019138&quot;&gt;&lt;code&gt;const base = css({ padding: 12 });
const primary = css([base, { background: &quot;blue&quot;, &quot;p &amp;amp;&quot;: { color: &quot;red&quot; } }]);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692569798866&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.15318260039293563&quot;&gt;&lt;code&gt;.base {
  padding: 12px;
}
.primary {
  background: blue;
}
p .primary {
  color: red;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;UI = f( State )&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리엑트와 Flutter가 주장하듯 UI는 함수라고 생각할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vyP7O/btsrCnIuxgM/mT6fD5NTPWKXr9R3LcjCvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vyP7O/btsrCnIuxgM/mT6fD5NTPWKXr9R3LcjCvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vyP7O/btsrCnIuxgM/mT6fD5NTPWKXr9R3LcjCvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvyP7O%2FbtsrCnIuxgM%2FmT6fD5NTPWKXr9R3LcjCvK%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;762&quot; height=&quot;276&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;276&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.flutter.dev/data-and-backend/state-mgmt/declarative&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;그렇다면 Style이 함수가 아닐 이유가 있는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://fela.js.org/docs/latest/intro/principles&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fela의 접근법&lt;/a&gt;과 동일하며, 이 철학에 따라 Flutter는 &lt;a href=&quot;https://api.flutter.dev/flutter/widgets/Padding-class.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Padding&lt;/a&gt;도 위젯으로 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692572790204&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.25920242505985736&quot;&gt;&lt;code&gt;const sample = css((props) =&amp;gt; ({
  color: &quot;red&quot;,
  background: props.bgColor
}));

function Sample() {
  return &amp;lt;div className={sample({ bgColor: &quot;blue&quot; })}&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;평가된 CSS는 다음과 같아야 할 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692575079455&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8172949271605938&quot;&gt;&lt;code&gt;.sample {
  color: red;
}
.sample_background_wnefh {
  background: blue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만들어두면 다양한 케이스에 대응 가능할 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sample({ bgColor: &quot;#fff&quot; })처럼 다른 색상이 사용되면 새로운 클래스 생성&lt;/li&gt;
&lt;li&gt;sample()처럼 값이 들어있지 않은 경우에 .sample만 평가되어 사용&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;a href=&quot;https://github.com/One-Nexus/Lucid&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lucid&lt;/a&gt;도 재미있지만 이 방식이 더 깔끔하다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 property가 함수일때는 함수를 평가하는 방식을 지원하는 방법은 좋을 수도?&lt;/p&gt;
&lt;pre id=&quot;code_1692573851885&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.01552104802573584&quot;&gt;&lt;code&gt;const sample = css({
  color: &quot;red&quot;,
  background: (props) =&amp;gt; props.bgColor
});

function Sample() {
  return &amp;lt;div className={sample({ bgColor: &quot;blue&quot; })}&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;한가지 문제는 return 타입 추론이 어려워진다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때문에 이렇게 다이나믹한 경우는 항상 함수로 return하는 함수로 분리를 할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692580995837&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.4731530394591592&quot;&gt;&lt;code&gt;// 함수가 인수이므로 타입추론 가능
const sample1 = css(({ color }) =&amp;gt; ({
  color
}));

// 속성이 함수면???
const sample2 = css({
  color: ({color}) =&amp;gt; color
});&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;pre id=&quot;code_1692582227416&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.40572083766482336&quot;&gt;&lt;code&gt;// string(class이름) 반환
const static = css({
  color: &quot;red&quot;,
});

// function 반환
const dynamic = rules(({ color }) =&amp;gt; ({
  color,
  background: ({ bg } = { bg: &quot;blue&quot; }) =&amp;gt; bg
}));

function Sample() {
  return &amp;lt;&amp;gt;
    &amp;lt;div className={
  // 항상 sting 반환
  css([
    static,
    dynamic,  // background: blue로 자동평가
    dynamic({ // background: #222로 class 생성
      bg: &quot;#222&quot;
    }),
    dynamic({ // color: white, background: blue
      color: &quot;white&quot;
    })
  ])
  }&amp;gt;내용&amp;lt;/div&amp;gt;&amp;lt;/&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;이제 Mixin이 하는 일의 상당부분도 커버할 수 있게 되었다!!&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;인라인 CSS: 시각적 위계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@teo/adorableCSS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;세상&amp;nbsp;귀여운&amp;nbsp;on-demand&amp;nbsp;Atomic&amp;nbsp;CSS:&amp;nbsp;AdorableCSS를&amp;nbsp;소개합니다.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tech.kakao.com/2022/05/20/on-demand-atomic-css-library/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;내가 하면 더 잘 만들 것 같아서 만들어 본 세상 귀여운 on-demand Atomic CSS Library. -Part.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tech.kakao.com/2022/05/24/on-demand-atomic-css-library-2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;내가 하면 더 잘 만들 것 같아서 만들어 본 세상 귀여운 on-demand Atomic CSS Library. -Part.2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인라인과 AtomicCSS의 장단점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시대를 거슬러 올라가 인라인 스타일을 사용하던 시대를 상상해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1692488143903&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8043968682484753&quot;&gt;&lt;code&gt;&amp;lt;p&amp;gt;일반 텍스트&amp;lt;span style=&quot;color: red; text-decoration: underline&quot;&amp;gt;빨간색과 밑줄&amp;lt;/span&amp;gt;&amp;lt;/p&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIl5ce/btsrH6yHma8/UgKZAn3MKVOpLOpQdC1zk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIl5ce/btsrH6yHma8/UgKZAn3MKVOpLOpQdC1zk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIl5ce/btsrH6yHma8/UgKZAn3MKVOpLOpQdC1zk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIl5ce%2FbtsrH6yHma8%2FUgKZAn3MKVOpLOpQdC1zk1%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;2578&quot; height=&quot;1616&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;미디어 쿼리, 선택자, 의사요소, 애니메이션등의 기능제한&lt;/li&gt;
&lt;li&gt;반복적으로 작성해야 하며, 문서의 사이즈도 커짐&lt;/li&gt;
&lt;li&gt;컨텐츠와 서식의 분리가 불가능&lt;/li&gt;
&lt;li&gt;길어져서 읽기가 힘듦&lt;/li&gt;
&lt;li&gt;의미의 구분이 어려움&lt;/li&gt;
&lt;/ol&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번 문제는 Atomic CSS(또는 Utility first)기반의 프레임워크들(&lt;a href=&quot;https://github.com/tailwindlabs/tailwindcss&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tailwind&lt;/a&gt;, &lt;a href=&quot;https://github.com/windicss/windicss&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Windi CSS&lt;/a&gt;, &lt;a href=&quot;https://github.com/unocss/unocss&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Uno CSS&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;a href=&quot;https://tailwindcss.com/docs/hover-focus-and-other-states&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;클래스로 만들어 버리는 것&lt;/a&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lT26s/btsrCTNGMio/uDeglP4a7EKiE9rmavjC21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lT26s/btsrCTNGMio/uDeglP4a7EKiE9rmavjC21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lT26s/btsrCTNGMio/uDeglP4a7EKiE9rmavjC21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlT26s%2FbtsrCTNGMio%2FuDeglP4a7EKiE9rmavjC21%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;1280&quot; height=&quot;800&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&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;게다가 Atomic CSS 고유의 장점이 생겼으니, 클래스이기 때문에 다음에서 &quot;text-red-600&quot;처럼 동일한 시각적인 요소를 가질경우 한번만 정의가 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1692490610420&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.46326103655798545&quot;&gt;&lt;code&gt;&amp;lt;p&amp;gt;일반 텍스트&amp;lt;span class=&quot;text-red-600 decoration-solid&quot;&amp;gt;빨간색과 밑줄&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;div class=&quot;text-red-600 bg-white&quot;&amp;gt;요소 1&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;때문에 장기적으로 CSS 파일의 크기가 줄어들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkl3jT/btsrB0sYAZv/HS81UKMQcb6Oaj0NjhhB6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkl3jT/btsrB0sYAZv/HS81UKMQcb6Oaj0NjhhB6k/img.png&quot; width=&quot;3840&quot; height=&quot;1702&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;567&quot; data-is-animation=&quot;false&quot; title=&quot;&quot; style=&quot;width: 58.3288%; margin-right: 10px;&quot; data-widthpercent=&quot;59.01&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkl3jT/btsrB0sYAZv/HS81UKMQcb6Oaj0NjhhB6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbkl3jT%2FbtsrB0sYAZv%2FHS81UKMQcb6Oaj0NjhhB6k%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;1280&quot; height=&quot;567&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Km6w/btsrSLu5fZP/QzPGGNvZVrH0ruUkGds7sK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Km6w/btsrSLu5fZP/QzPGGNvZVrH0ruUkGds7sK/img.jpg&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;354&quot; data-is-animation=&quot;false&quot; style=&quot;width: 40.5084%;&quot; data-widthpercent=&quot;40.99&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Km6w/btsrSLu5fZP/QzPGGNvZVrH0ruUkGds7sK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Km6w%2FbtsrSLu5fZP%2FQzPGGNvZVrH0ruUkGds7sK%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;555&quot; height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;/div&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;CSS 자체와는 디커플링이 되므로 text-red-600이 &lt;a href=&quot;https://m2.material.io/design/color/the-color-system.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;머터리얼 컬러시스템&lt;/a&gt;의 빨간색에서 &lt;a href=&quot;https://getbootstrap.kr/docs/5.3/customize/color/&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;또한 TailwindCSS처럼 체계적으로 스타일들을 미리 만들어두면 개발자는 값을 가져다가 쓰기만 하면 그만이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복되는 표현? tailwind의 &lt;a href=&quot;https://tailwindcss.com/docs/functions-and-directives#apply&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@apply&lt;/a&gt; 같은게 있다면 해결할 수 있으며, 의미론적인 표현도 어느정도 달성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692491419407&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6586684524411491&quot;&gt;&lt;code&gt;.select2-dropdown {
  @apply rounded-b-lg shadow-md;
}
.select2-search {
  @apply border border-gray-300 rounded;
}
.select2-results__group {
  @apply text-lg font-bold text-gray-900;
}&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;한편으로는 Atomic CSS 고유의 단점들도 생긴다.&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;독단적인 문법이므로 타입시스템 활용이나 코드 하이라이팅도 상대적으로 어렵다.&lt;/p&gt;
&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;장점&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;다양한 CSS 기능 사용 가능&lt;/li&gt;
&lt;li&gt;타이핑을 줄이고, 편리한 문법 사용 가능&lt;/li&gt;
&lt;li&gt;CSS의 시각적 값들을 중앙에서 조정 가능&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&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;커스텀과 임의의 CSS 작성이 어려움&lt;/li&gt;
&lt;li&gt;CSS에서 알던 속성들과 지식 활용이 어려운 독단적 문법&lt;/li&gt;
&lt;li&gt;타입시스템과 하이라이팅 활용이 어려움&lt;/li&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;AtomicCSS 개념분해와 역할&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 여러가지 이슈가 혼재함을 알 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;자체적 문법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 다양한 CSS 기능을 사용 가능하게 하고, 구문을 짧게 줄여 편리&lt;/li&gt;
&lt;li&gt;단점: CSS에서 알던 문법과 다르고, 타입시스템과 하이라이팅 활용이 어려움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;속성의 이름과 값
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 타이핑을 줄이며, CSS의 시각적 값들을 중앙에서 조정 가능&lt;/li&gt;
&lt;li&gt;단점: CSS에서 알던 속성과 값을 활용하기 어려움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&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;다양한 CSS 기능을 사용 가능&quot;이 장점이 될 수 있는가?&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;b&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;u&gt;버려야만 한다.&lt;/u&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;!important -&amp;gt; !처럼 간단한 문법은 CSS In JS 컴파일 과정이나 PostCSS Plugin으로 제공해 충분히 해줄수 있다.&lt;/p&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;결국 AtomicCSS가 존재하는 목적은 인라인 CSS와 같은 &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;앞서 @apply를 통해 의미론적으로 만들수는 있다고 했지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미론적인 방법을 제대로 사용하려면&amp;nbsp; &lt;a href=&quot;https://daisyui.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;daisyUI&lt;/a&gt;처럼 프레임워크를 새로 재창조하는 수준을 거쳐야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1692495536016&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.956337326297907&quot;&gt;&lt;code&gt;&amp;lt;button class=&quot;bg-indigo-600 px-4 py-3 text-center text-sm font-semibold inline-block text-white cursor-pointer uppercase transition duration-200 ease-in-out rounded-md hover:bg-indigo-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-600 focus-visible:ring-offset-2 active:scale-95&quot;&amp;gt;
  Tailwind Button
&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692495550532&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8095265792003663&quot;&gt;&lt;code&gt;&amp;lt;button class=&quot;btn btn-primary&quot;&amp;gt;
  daisyUI Button
&amp;lt;/button&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;따라서 AtomicCSS에서 @apply같은 합성구문은 시각적 요소를 결합되는 용도로 사용해야지,&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;라이트모드와 다크모드까지 고려했을 때 4가지의 클래스를 하나로 묶어취급함은 괜찮지 않은가?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;text-black bg-white&lt;/li&gt;
&lt;li&gt;dark:text-white dark:bg-gray-900&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;/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;AtomicCSS 프레임워크와 테마&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시각적 표현을 위한 좋은 프레임워크의 조건은 무엇이 있을까?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;색, 폰트, 간격, 레이아웃, 반응형등 다양한 시각적 요소를 다룸&lt;/li&gt;
&lt;li&gt;시각적 요소들의 구성이 체계적이어야 함&lt;/li&gt;
&lt;li&gt;특정 까다롭거나 반복적인 패턴들은 묶어서 제공&lt;/li&gt;
&lt;li&gt;관용적인 프리셋 값들&lt;/li&gt;
&lt;/ol&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;b&gt;시각적 요소와 구성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중에서 1번과 2번은 기본적으로 스타일가이드 이야기에 가까우므로 프로그래머 관점에서 다루는 글의 범위를 넘어선다. &lt;s&gt;하고픈 이야기는 있지만..&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 알아두어야 할 점은 구성에 있어 각종 스펙과 룰을 정한다는 것은 기본적으로 top-down 형태의 일이라는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 스펙으로는 &lt;a href=&quot;https://tr.designtokens.org/format/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;W3C 디자인토큰&lt;/a&gt;, &lt;a href=&quot;https://github.com/system-ui/theme-specification&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Styeld System&lt;/a&gt;과 &lt;a href=&quot;https://theme-ui.com/theme-spec&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ThemeUI&lt;/a&gt;를 들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 다음과 같은 스펙이 있다고 가정해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1692555293667&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9098800766168287&quot;&gt;&lt;code&gt;const theme = {
  spaces: [0, 4, 8, 16, 32, 64],
  colors: {
    text: &quot;#000&quot;,
    background: &quot;#fff&quot;,
    primary: &quot;#07c&quot;
  }
};&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;space와 colors는 Theme key라 할 수 있다.&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;Styled System 기준으로 사용되는 프로퍼티 규약을 적용했을 때 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;space는 margin,&amp;nbsp;&amp;nbsp;padding, gird-gap 등에 사용&lt;/li&gt;
&lt;li&gt;colors는 color, background-color, border-color에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예컨대 background-color: &quot;primary&quot;와 border-color: &quot;primary&quot;는 &quot;#07c&quot;라는 색상을 사용하게 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 테마쪽은 Vanilla Extract가 너무나도 작업을 잘해놓았기 때문에 소소한 개선만 필요할뿐, 특별한 불만이 없다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://vanilla-extract.style/documentation/theming/&quot;&gt;Theme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vanilla-extract.style/documentation/api/create-theme/&quot;&gt;createTheme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vanilla-extract.style/documentation/api/create-theme-contract/&quot;&gt;createThemeContract&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 단일값, 배열, 중첩등을 테마가 충분히 다룰 수 있기 때문에 우선 확장했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 직접 값을 다루기 위해 values를 추가했다.&lt;/p&gt;
&lt;pre id=&quot;code_1692598697930&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6478360014823229&quot;&gt;&lt;code&gt;const { className: themeClass, vars, values } = theme({
  // 단일
  rootSize: &quot;10px&quot;,

  // 배열
  spaces: [0, 4, 8],

  // 중첩
  colors: {
    text: &quot;#000&quot;,
    background: &quot;#fff&quot;,
    indigo: {
      600: &quot;#4f46e5&quot;,
      700: &quot;#4338ca&quot;
    }
  }
});

const { className: otherThemeClass } = theme(vars, {
  rootSize: &quot;1rem&quot;,
  spaces: [0, 2, 4],
  colors: {
    // text는 그대로 활용
    background: &quot;blue&quot;,
    indigo: {
      600: &quot;#5a46e5&quot;,
      700: &quot;#4338ca&quot;
    }
  }
});&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;위의 JS와 CSS는 각각 다음 모습과 같을 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692601186801&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.90831290700241&quot;&gt;&lt;code&gt;const themeClass = &quot;themeClass&quot;;
const otherThemeClass = &quot;otherThemeClass&quot;;

const themeClassValues = {
  rootSize: &quot;var(--rootSize)&quot;,
  spaces: [&quot;var(--spaces-0)&quot;, &quot;var(--spaces-1)&quot;, &quot;var(--spaces-2)&quot;],
  colors: {
    text: &quot;var(--colors-text)&quot;,
    background: &quot;var(--colors-background)&quot;,
    indigo: {
      600: &quot;var(--colors-indigo-600)&quot;,
      700: &quot;var(--colors-indigo-700)&quot;
    }
  }
};

const themeClassValues = {
  rootSize: &quot;10px&quot;,
  spaces: [0, 4, 8],
  colors: {
    text: &quot;#000&quot;,
    background: &quot;#fff&quot;,
    indigo: {
      600: &quot;#4f46e5&quot;,
      700: &quot;#4338ca&quot;
    }
  }
};

const otherThemeClassValues = {
  rootSize: &quot;1rem&quot;,
  spaces: [0, 2, 4],
  colors: {
    text: &quot;#000&quot;,
    background: &quot;blue&quot;,
    indigo: {
      600: &quot;#5a46e5&quot;,
      700: &quot;#4338ca&quot;
    }
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692599725103&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.06416715796264072&quot;&gt;&lt;code&gt;.themeClass {
  --rootSize: 10px;

  /* 자동적 변환이 안됨!! */
  --spaces-0: 0;
  --spaces-1: 4;
  --spaces-2: 8;

  /* 중첩은 속성이 이어써짐 */
  --colors-text: #000;
  --colors-background: #fff;
  --colors-indigo-600: &quot;#4f46e5&quot;;
  --colors-indigo-700: &quot;#4338ca&quot;;
}

.otherThemeClass {
  --rootSize: 1rem;

  --spaces-0: 0;
  --spaces-1: 2;
  --spaces-2: 4;

  --colors-text: #000; /* 재활용된 text */
  --colors-background: blue;
  --colors-indigo-600: &quot;#5a46e5&quot;;
  --colors-indigo-700: &quot;#4338ca&quot;;
}&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;CSS 결과물을 상상해보는 과정에서 한가지 문제를 발견했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동 변환이 작동하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌면 당연한게 현재 상태로 적용될 property를 알 수 없기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 언급했던 W3C 스펙을 가지고 계약에 의한 토큰 설계를 할 수 있을 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692602348697&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.007450042792546574&quot;&gt;&lt;code&gt;const { className: themeClass, contracts } = theme({
  spaces: tokenConstract({
    $type: &quot;dimension&quot;,
    $value: [0, 4, 8]
  }),
  colors: tokenConstract({
    $type: &quot;color&quot;,
    $value: {
      text: &quot;#000&quot;
    }
  })
});

const myContracted = themeContract({
  spaces: {
    $type: &quot;dimension&quot;
  },
  colors: {
    text: {
      $type: &quot;color&quot;
    }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692659224387&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8125838842676938&quot;&gt;&lt;code&gt;// contracts나 myContracted 사용, 이제 자동 변환이 수행된다
const { className: newThemeClass } = theme(contracts, {
  spaces: [3, 6, 9],
  colors: {
    text: &quot;#888&quot;
  }
});&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;하지만 설계를 크게 바꾸어야 할 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조를 하고 싶을 때는 어떻게 해야 하지?&lt;/p&gt;
&lt;pre id=&quot;code_1692603687951&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3225298420148869&quot;&gt;&lt;code&gt;const { vars } = theme({
  rootSize: &quot;10px&quot;,
  get newSize() { return this.rootSize },

  spaces: [0, 4, 8],
  spaces: {
    small: &amp;amp;spaces[0],
    medium: &amp;amp;spaces[1],
    large: &amp;amp;spaces[2]
  },
});&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;newSize는 rootSize와 똑같은 기본값을 가지는 새로운 값을 만들고 있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째 space는 답이 없어보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 다음과 같이 할 수 있긴 하다 ㅋㅋ&lt;/p&gt;
&lt;pre id=&quot;code_1692598620750&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9400554203406092&quot;&gt;&lt;code&gt;const { vars } = theme({
  spaces: defineProperty([0, 4, 8], {
    small: (arr) =&amp;gt; arr[0],
    medium: (arr) =&amp;gt; arr[1],
    large: (arr) =&amp;gt; arr[2]
  }),
});

function defineProperty(arr, properties) {
  const customProperties = Object.keys(properties).reduce((acc, key) =&amp;gt; {
    acc[key] = {
      get: function () {
        return properties[key](this);
      }
    };
    return acc;
  }, {});

  return Object.defineProperties(arr, customProperties);
}&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;따라서 라이브러리가 자동적으로 수행하도록 theme()를 변경해야 할 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 내가 새로 제안하는 Theme 함수 제안이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;consts: 규약되고 JS에서 값은 존재하나, var()로 사용되지 않는 값들&lt;/li&gt;
&lt;li&gt;values: 규약되고, var()로 나타나는 값들&lt;/li&gt;
&lt;li&gt;alias: 새로운 var가 생기지 않고, 자바스크립트 상에서만 참조함&lt;/li&gt;
&lt;li&gt;fallbacks: values에 있는 값들을 참조할 때&lt;/li&gt;
&lt;li&gt;clones: values와 기본값만 같고, 런타임에 상호변경 여지가 있을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1692604441075&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5594097875076942&quot;&gt;&lt;code&gt;const { vars } = theme({
  // 상수
  consts: {
    constSize: &quot;50%&quot;
  },

  // 메인 값들
  values: {
    rootSize: &quot;10px&quot;,
    spaces: tokenConstract({
      $type: &quot;dimension&quot;,
      $value: [0, 4, 8]
    })
  },

  // 기존 var()를 사용하고 자바스크립트 상에서만 참조
  alias: ({ spaces }) =&amp;gt; ({
    spaces: {
      // 구조는 동일해야 vars.spaces.small 처럼 사용가능
      small: spaces[0],
      medium: spaces[1],
      large: ({ spaces }) =&amp;gt; spaces[2] // 각 속성마다 할 수도
    }
  }),

  // 새로운 var을 생성하지만 참조함
  fallbacks: ({ rootSize }) =&amp;gt; ({
    sameSize: rootSize,
    otherSize: [rootSize, &quot;1rem&quot;]
  }),

  // 기본 값만 같은 하드포크
  clones: ({ rootSize }) =&amp;gt; ({
    newSize: rootSize
  })
});&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692606265469&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.31831477586602097&quot;&gt;&lt;code&gt;.themeClass {
  /* Consts는 자바스크립트에서만 접근 가능 */

  --rootSize: 10px;

  /* tokenConstract에 의한 기본값 변환!! */
  --spaces-0: 0px;
  --spaces-1: 4px;
  --spaces-2: 8px;

  /* Alias는 자바스크립트에서만 접근 가능 */

  /* Fallback */
  --sameSize: var(--rootSize);
  --otherSize: var(--rootSize, 1rem);

  /* 기본값만 같음 */
  --newSize: 10px;
}&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;css var() 값을 런타임 중에 바꾸는 가장 쉬운 방법 중 하나는 Vanilla Extract의 &lt;a href=&quot;https://vanilla-extract.style/documentation/packages/dynamic/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dynamic&lt;/a&gt;이라는 패키지를 사용하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 플랫폼으로 export가 필요할 경우는 아마존의 &lt;a href=&quot;https://github.com/amzn/style-dictionary&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;style-dictionary&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;size18&quot;&gt;&lt;b&gt;까다롭거나 반복적인 패턴&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SASS, Less, Stylus 같은 전처리들이 가지고 있는 각종 빌트인 함수들이 맨땅의 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;a href=&quot;https://github.com/styled-components/polished&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;polished&lt;/a&gt;라는 매우 준수한 라이브러리가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에 &lt;a href=&quot;https://developer-1px.github.io/adorable-css/docs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AdorableCSS&lt;/a&gt;는 까다로운 Flexbox를 대체하기 위해 Autolayout와 Hbox, 까다로운 포지션 문제를 다루기 위해 &lt;a href=&quot;https://github.com/layoutBox/PinLayout&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PinLayout&lt;/a&gt;과 비슷한 Position Layer를 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PandaCSS 마찬가지로 Container,&amp;nbsp;Stack,&amp;nbsp;Wrap,&amp;nbsp;Aspect&amp;nbsp;Ratio등을&amp;nbsp;위한 많은 &lt;a href=&quot;https://panda-css.com/docs/concepts/patterns&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;a href=&quot;https://github.com/Brew-Brew/css-in-js-media&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;css-in-js-media&lt;/a&gt;, &lt;a href=&quot;https://github.com/dev-uly/vanilla-syrup&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;vanilla-syrup&lt;/a&gt;, &lt;a href=&quot;https://github.com/sass-mq/sass-mq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sass MQ&lt;/a&gt;등처럼 편리하게 다룰 수 있는 것들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Keyframe도 마찬가지(&lt;a href=&quot;https://vanilla-extract.style/documentation/api/keyframes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vanilla Extract&lt;/a&gt;, &lt;a href=&quot;https://fela.js.org/docs/latest/basics/keyframes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fela&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;a href=&quot;https://github.com/TheMightyPenguin/dessert-box&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Box처럼&lt;/a&gt; 반복적인 패턴의 컴포넌트나 &lt;a href=&quot;https://github.com/csstools/sanitize.css&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sanitize.css&lt;/a&gt;같은 &lt;a href=&quot;https://github.com/troxler/awesome-css-frameworks#base--reset--normalize&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;reset&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;size18&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;w = width&amp;nbsp;&amp;nbsp; h = height&amp;nbsp;&amp;nbsp; m = margin &amp;nbsp; p = padding &amp;nbsp; b = border&amp;nbsp;&amp;nbsp; r = border-radius&lt;/li&gt;
&lt;li&gt;z = z-index &amp;nbsp; bg = background&amp;nbsp;&amp;nbsp; c = color&amp;nbsp;&amp;nbsp; mt = margin-top &amp;nbsp; pr = padding-right&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;둘째, mastercss의 &lt;a href=&quot;https://css.master.co/docs/breakpoints&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;반응형 디자인 기준&lt;/a&gt;처럼 다양한 상황을 다룰 수 있어야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@3xs = 360px, iPhone 6, 7, 8, X, 11, 12 / Galaxy S8 / HTC One&amp;hellip;&lt;/li&gt;
&lt;li&gt;@2xs = 480px, Blackberry Passport / Amazon Kindle Fire HD 7 &amp;hellip;&lt;/li&gt;
&lt;li&gt;@xs = 600px, LG G Pad 8.3 / Amazon Kindle Fire &amp;hellip;&lt;/li&gt;
&lt;li&gt;@sm = 768px, Microsoft Surface / iPad Pro 9.7 / iPad Mini &amp;hellip;&lt;/li&gt;
&lt;li&gt;@md = 1024px, iPad Pro 12.9 / Microsoft Surface Pro 3 &amp;hellip;&lt;/li&gt;
&lt;li&gt;@lg = 1280px, Google Chromebook Pixel / Samsung Chromebook &amp;hellip;&lt;/li&gt;
&lt;li&gt;@xl = 1440px, Macbook Air 2020 M1 / MacBook Pro 15 &amp;hellip;&lt;/li&gt;
&lt;li&gt;@2xl = 1600px, Dell Inspiron 14 series &amp;hellip;&lt;/li&gt;
&lt;li&gt;@3xl = 1920px, Dell UltraSharp U2412M / Dell S2340M / Apple iMac 21.5-inch &amp;hellip;&lt;/li&gt;
&lt;li&gt;@4xl = 2560px, Dell UltraSharp U2711 / Apple iMac 27-inch &amp;hellip;&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;마지막으로 normalize.css에 reset.css의 더 나은 값을 사용하는 sanitize.css처럼 합리적이고 기본적인 값의 커버리지가 넓어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 AtomicCSS 메타-프레임워크 툴링을 구상해볼 차례다.&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;AtomicCSS 문법 쪼개기&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;AtomicCSS 프레임워크가 제공하는 문법과 기능들을 보고 구현이 가능하도록 만들어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자체문법은 포기한다고 하지 않았나요?라고 묻는다면, AtomicCSS 프레임워크들이 제공하는 class 문법을 포기하자는 말이었지,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Javacript 문법을 기반으로 하여 재구성하지 않겠다는 의미는 아니었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AtomicCSS 프레임워크의 문법을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 위에서 나왔던Tailwind&amp;nbsp; 버튼의 예시다.&lt;/p&gt;
&lt;pre id=&quot;code_1692558575974&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9868370587070985&quot;&gt;&lt;code&gt;&amp;lt;button class=&quot;bg-indigo-600 px-4 py-3 text-center text-sm font-semibold inline-block text-white cursor-pointer uppercase transition duration-200 ease-in-out rounded-md hover:bg-indigo-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-600 focus-visible:ring-offset-2 active:scale-95&quot;&amp;gt;
  Tailwind Button
&amp;lt;/button&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;총 4가지의 종류가 있음을 알 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;hover:bg-indigo-700&lt;/li&gt;
&lt;li&gt;bg-indigo-600&lt;/li&gt;
&lt;li&gt;px-4&lt;/li&gt;
&lt;li&gt;uppercase&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 제외하면 &lt;a href=&quot;https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;임의의 값&lt;/a&gt;과 mastercss의 &lt;a href=&quot;https://css.master.co/docs/syntax-tutorial#group-styles&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;먼저 가장 간단한 uppercase는 &quot;uppercase&quot; 혹은 { uppercase: true }정도로 사용할 수 있으면 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;px-4는 { px: 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;그럼 bg-indigo-600은?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 속성인 bg와 값인 indigo-600으로 나누어 { bg: &quot;indigo-600&quot; }가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 indigo-600은 위에서 언급했던 테마의 색상으로 생각할 수 있으며, 타입시스템이 작용하도록 수정해야 할 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{ bg: indigo[600] }이나 { bg: { indigo: 600 }}처럼 나타낼 수 있겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hover:bg-indigo-700에서 특이점은 hover일텐데, 우리가 앞서 정의했던 리터럴 구문을 활용하면 쉽게 정의할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{ _hover: { bg: indigo[700] } }&lt;/p&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 값과의 합성을 하거나 Fallback을 할 수 있다.&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_1692563093534&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.03825391335331052&quot;&gt;&lt;code&gt;// 리터럴과 같은 이름 - 사용법도 같음
const { css } = defineRules({
  // 무언가 규칙정의
  // Value의 fallback 허용 활성화 가정
});
const sample = css({
  uppercase: true,
  px: 4,
  bg: indigo[600],
  _hover: {
    bg: indigo[700]
  },

  color: &quot;#000&quot;, // Fallback 될 임의의 값
  &quot;_hover, _active&quot;: {
    color: &quot;red&quot; // 중첩되어 그룹화된 값
  }
});&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;겉보기로는 간단해 보이긴 하나, 합성이 없어 아쉽고 indigo는 대체 어디서 생겨난 값인지 알 수 가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 숨겨진 복잡성이 예상외로 커 &lt;a href=&quot;https://github.com/tw-in-js/twind&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;twind&lt;/a&gt;, &lt;a href=&quot;https://github.com/ben-rogerson/twin.macro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;twin.macro&lt;/a&gt;, &lt;a href=&quot;https://vanilla-extract.style/documentation/packages/sprinkles/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sprinkles&lt;/a&gt;등 수많은 Atomic CSS in 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;pre id=&quot;code_1692574298980&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7968115308753585&quot;&gt;&lt;code&gt;const { css } = defineRules({
  // ...
});
const sample = css([
  &quot;uppercase&quot;,
  ({ indigo }) =&amp;gt; ({
    px: 4,
    bg: indigo[600],
    _hover: {
      bg: indigo[700]
    },

    color: &quot;#000&quot;,
    &quot;_hover, _active&quot;: {
      color: &quot;red&quot;
    }
  })
]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&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;&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;직접 context를 노출해 주었다면 어떨까요?&lt;/p&gt;
&lt;pre id=&quot;code_1692584310957&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8391792138397187&quot;&gt;&lt;code&gt;const { vars: themeVars } = theme({
  // ...
  colors: {
    indigo: {
      600: &quot;#4f46e5&quot;,
      700: &quot;#4338ca&quot;
    }
  }
});

const { css } = defineRules({
  contexts: {
    indigo: themeVars.colors.indigo
  }
  // ...
});&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;rules가 첫번째에 context, 두번째에 유저 인수를 받는 구조라면 말이 된다!!&lt;/p&gt;
&lt;pre id=&quot;code_1692585341184&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.4695163258693419&quot;&gt;&lt;code&gt;const { css, rules } = defineRules({ /* ... */ });

// 정적
const static1 = css([
  &quot;uppercase&quot;,
  {
    px: 4,
  }
]);

// 여전히 정적임
const sample2 = css([
  &quot;uppercase&quot;,
  ({ indigo }) =&amp;gt; ({
    bg: indigo[600],
    border: ({ indigo }) =&amp;gt; indigo[700]
  })
]);

// 동적
const dynamic = rules([
  &quot;uppercase&quot;,
  ({ indigo }, ({ size })) =&amp;gt; {
    px: size,
    bg: (_, { bgColor }) =&amp;gt; bgColor,
    
    color: indigo[600]
  }
]);

function Sample() {
  return (
    &amp;lt;div
      className={css([
        static1,
        static2,
        dynamic, // color: indigo[600]으로 자동평가
        dynamic({
          // color: indigo[600], px: 6
          size: 6
        }),

        // 함수 - indigo[600], bg: indigo[700]
        dynamic(({ indigo }) =&amp;gt; {
          bgColor: indigo[700];
        })
      ])}
    &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;h4 data-ke-size=&quot;size20&quot;&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;지금까지 살펴본 옵션은 2가지였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fallback을 가능하게 해서 color: &quot;#000&quot;처럼 기본 CSS 값들을 쓸 수 있게 만들지(Strict mode 여부)와 context 제공.&lt;/p&gt;
&lt;pre id=&quot;code_1692586217470&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.09926657771718628&quot;&gt;&lt;code&gt;// css, rules, variants등 함수 제공
const { css } = defineRules({
  strict: false, // 기본 CSS 문법들을 쓸 수 있게 strict 모드 해제
  contexts: {
    spaces: themeVars.spaces,
    indigo: themeVars.colors.indigo
  }
});&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;바로 padding-inline인 px와 background인 bg로 매핑하는 능력이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692586744156&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.16631013814730844&quot;&gt;&lt;code&gt;const { css } = defineRules({
  // rules에서 쓰였던 기능은 모두 사용 가능
  rules: {
    px: (value) =&amp;gt; ({ paddingInline: theme.spaces[value] }),
    bg: {
      background: (value) =&amp;gt; value
    },

    // 두번째 인수는 context
    px: (value, { spaces }) =&amp;gt; ({ paddingInline: spaces[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;px의 경우 theme.spaces에서만 가능한 값으로 제한이 되어있는 모습을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 css값에도 할 수 있을까? 이는 Vanilla Extract의 &lt;a href=&quot;https://vanilla-extract.style/documentation/packages/sprinkles/&quot;&gt;sprinkles&lt;/a&gt;가 잘 해주고 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692589957770&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.47961581160595623&quot;&gt;&lt;code&gt;const { css } = defineRules({
  // CSS에서 사용가능한 기능 제약
  properties: {
    // 배열에 있는 값만 허용
    display: [&quot;none&quot;, &quot;inline&quot;],
    paddingLeft: theme.spaces,

    // 속성 전체
    color: true,   // strict: true 일때도 속성이 허용됨
    border: false, // strict: false 일때도 속성이 거부됨
  }
});&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;px는 padding-left, padding-right라고 생각할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일전에 나온 griffel의 &lt;a href=&quot;https://griffel.js.org/react/api/shorthands&quot;&gt;shorthands&lt;/a&gt; 상황처럼 제약이 있을 경우 paddingLeft, paddingRight 값을 연결해주어야 할 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692588390591&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7577824581487512&quot;&gt;&lt;code&gt;const { css } = defineRules({
  shortcuts: {
    pl: &quot;paddingLeft&quot;,
    pr: &quot;paddingRight&quot;,
    px: [&quot;paddingLeft&quot;, &quot;paddingRight&quot;],
  }
});&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;shortcuts에서 매핑한 속성을 활용하고 싶을수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 활용시 동적인 요소가 필요할 수 도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692589186926&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.26195105390755047&quot;&gt;&lt;code&gt;const { css } = defineRules({
  shortcuts: {
    px: [&quot;paddingLeft&quot;, &quot;paddingRight&quot;],
    py: [&quot;paddingTop&quot;, &quot;paddingBottom&quot;],

    p: [&quot;px&quot;, &quot;py&quot;], // 생성되며 계산
    get p() { return [this.px, this.py]; }, // 순수 문법 활용

    p: (useY) =&amp;gt; [&quot;px&quot;, useY &amp;amp;&amp;amp; &quot;py&quot;] // 함수
  }
});&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;이제 지나치게 정적인 Vanilla Extract나 무서운 &lt;a href=&quot;https://unocss.dev/config/rules&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;규식이를 쓰는 uno&lt;/a&gt;보다 작성하기 편해보이지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무심코 빼먹은게 2개나 된다ㅠㅠ&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 값: 계속 쓰여왔던 uppercase등 AdorableCSS에서 언급했던 유니크한 값들&lt;/li&gt;
&lt;li&gt;조건부 스타일: Vanilla Extract sprinkles에 있는 그것, PandaCSS에서 리터럴로 있기에는 Ad-Hoc 하다며 &lt;a href=&quot;https://panda-css.com/docs/concepts/conditional-styles&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비판했던 물건&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 원래 css 리터럴과 비슷하되, rules처럼 context 정도는 받아서 작업할 수 있다면 좋겠죠?&lt;/p&gt;
&lt;pre id=&quot;code_1692593963430&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5203294313442705&quot;&gt;&lt;code&gt;const { css } = defineRules({
  values: {
    uppercase: {
      textTransform: &quot;uppercase&quot;
    },
    indigoBG: ({ indigo }) =&amp;gt; ({
      background: indigo[600]
    })
  }
});&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;단일 셀렉터부터 Mixin과 비슷한 스타일까지 모두 가능하도록 구성했다.&lt;/p&gt;
&lt;pre id=&quot;code_1692596419014&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5349650435740299&quot;&gt;&lt;code&gt;const { css } = defineRules({
  defaultCondition: &quot;light&quot;,
  conditions: {
    // 단일
    light: &quot;&quot;,
    dark: &quot;&amp;amp;.dark, .dark &amp;amp;&quot;,
    
    // 여럿
    dark: [&quot;&amp;amp;.dark&quot;, &quot;.dark &amp;amp;&quot;],

    // 중첩
    osLight: {},
    osDark: { &quot;@media&quot;: &quot;(prefers-color-scheme: dark)&quot; },

    // 함수
    hovAct: (children) =&amp;gt; ({
      _hover: {
        base: {
          ...children
        },
        _active: {
          ...children
        }
      }
    })
  }
});&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의 설계가 일부 잘못된게 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;conditions를 그룹으로 묶었을 때, 3가지로 나타난다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;light-dark&lt;/li&gt;
&lt;li&gt;osLight-osDark&lt;/li&gt;
&lt;li&gt;hovAct&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;이때 light와 osLight가 동시에 기본값이 될 수는 없는 걸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 배열로 표시하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1692619829187&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3899030794201398&quot;&gt;&lt;code&gt;const { css } = defineRules({
  defaultCondition: [&quot;light&quot;, &quot;osLight&quot;],
  conditions: { /* ... */ }
});&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;하지만 관리의 문제는 아직 해결하지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 방식대로라면 One big rules 파일이 되어 제어가 어렵기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vanilla extract는 여기서 좋은 아이디어를 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 여러 룰을 만든 후 &lt;a href=&quot;https://vanilla-extract.style/documentation/packages/sprinkles/#createsprinkles&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;Theme 정의를 할때처럼 규약들을 export하고 합치는 방법은 어떨까?&lt;/p&gt;
&lt;pre id=&quot;code_1692658712607&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9066746978120901&quot;&gt;&lt;code&gt;const { contracts: responsiveContracts } = defineRules({ /* ... */ });
const { contracts: colorContracts } = defineRules({ /* ... */ });

const { css, rules } = combineRules(responsiveContracts, colorContracts);&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;다른 세부적인 유틸과 기능이 필요할 수도 있겠지만, 이 글은 큰 그림을 위주로 다루기에 이만 끝을 내도록 하자.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AtomicCSS는&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적으로&amp;nbsp;color:&amp;nbsp;rgb(220&amp;nbsp;38&amp;nbsp;38);라는&amp;nbsp;값을&amp;nbsp;tailwind에서는&amp;nbsp;text-red-600만으로&amp;nbsp;표현해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는&amp;nbsp;시각적&amp;nbsp;위계의&amp;nbsp;결합도가&amp;nbsp;줄어드는&amp;nbsp;추상화라&amp;nbsp;할&amp;nbsp;수&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;.text-red-600가&amp;nbsp;rgb(220&amp;nbsp;38&amp;nbsp;38)일&amp;nbsp;수&amp;nbsp;있겠지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디자이너의&amp;nbsp;필요에&amp;nbsp;의해&amp;nbsp;rgb(250,&amp;nbsp;40,&amp;nbsp;40)과&amp;nbsp;같은&amp;nbsp;값으로&amp;nbsp;조정하면&amp;nbsp;전체&amp;nbsp;시스템에&amp;nbsp;바로&amp;nbsp;적용된다는&amp;nbsp;것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;파생하였다.&lt;/p&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;nbsp;기존의&amp;nbsp;지식을&amp;nbsp;활용할&amp;nbsp;수&amp;nbsp;없이&amp;nbsp;배움을&amp;nbsp;강요하고,&amp;nbsp;타입시스템과&amp;nbsp;하이라이팅&amp;nbsp;활용이&amp;nbsp;어려웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한&amp;nbsp;이미&amp;nbsp;만들어진&amp;nbsp;시스템에&amp;nbsp;가까워&amp;nbsp;커스텀과&amp;nbsp;임의의&amp;nbsp;CSS&amp;nbsp;작성이&amp;nbsp;상대적으로&amp;nbsp;어려웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로&amp;nbsp;중앙&amp;nbsp;집중형&amp;nbsp;시스템이지만,&amp;nbsp;효과적으로&amp;nbsp;제어해주는&amp;nbsp;시스템이&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;문법&amp;nbsp;문제는&amp;nbsp;타입스크립트를&amp;nbsp;활용하는&amp;nbsp;CSS&amp;nbsp;In&amp;nbsp;JS로&amp;nbsp;해결할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;defineRuels는 기존의 커스텀이 어려웠던 시스템에서 벗어나, 도메인마다 bottom-up으로 정의하여 개별의 팀들이 사용할 수 있는 Meta Atomic Util이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 커다란 규칙을 만들때는 어려움이 있으므로, combineRules를 통해 결합할 수 있도록 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 라이트모드와 다크모드 시스템의 전환이나 Accent 색의 변경을 한번에 수행하려면 어떻게 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 필요한게 중앙화된 규약의 존재며, Theme 정의가 빛을 발하는 지점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말해 일반적으로 defineRules는 key 수준에서 동작하며, Theme는 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;자, 새로운 Theme API를 정의했고, 디자인 토큰 매핑과 사용까지 총 3가지에 대한 재정의를 했다.&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;Variants - 의미론적 위계&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;들어서기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tailwind와 daisyUI의 사용을 다시 한번 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1692660418479&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.4930067158046545&quot;&gt;&lt;code&gt;&amp;lt;button class=&quot;bg-indigo-600 px-4 py-3 text-center text-sm font-semibold inline-block text-white cursor-pointer uppercase transition duration-200 ease-in-out rounded-md hover:bg-indigo-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-600 focus-visible:ring-offset-2 active:scale-95&quot;&amp;gt;
  Tailwind Button
&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692660418483&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9510752910586555&quot;&gt;&lt;code&gt;&amp;lt;button class=&quot;btn btn-primary&quot;&amp;gt;
  daisyUI Button
&amp;lt;/button&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;Tailwind 문법을 우리가 정의한 가상의 AtomicCSS 라이브러리로 순진하게 옮기면 대략 다음과 같이 표현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692660860547&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.2985933636432584&quot;&gt;&lt;code&gt;const { css } = defineRules({ /* ... */ });
const buttonStyle = css([
  &quot;uppercase&quot;,
  &quot;transition&quot;,

  ({ indigo }) =&amp;gt; ({
    bg: indigo[600],
    px: 4,
    py: 3,
    text: [&quot;center&quot;, &quot;sm&quot;],
    font: &quot;semibold&quot;,
    inline: &quot;block&quot;,
    text: &quot;white&quot;,
    cursor: &quot;pointer&quot;,
    duration: 200,
    ease: &quot;in-out&quot;,
    rounded: &quot;md&quot;,
    _hover: {
      bg: indigo[700]
    },
    _focusVisible: {
      outline: &quot;none&quot;,
      ring: {
        base: 2,
        color: indigo[600],
        offset: 2
      }
    },
    _active: {
      scale: 95
    }
  })
]);&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;그렇다면 daisyUI는 이렇게 표현할 수 없는걸까?&lt;/p&gt;
&lt;pre id=&quot;code_1692661873419&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.1412673846776873&quot;&gt;&lt;code&gt;const button = Something({ /* ... */ });
const buttonStyle = button(&quot;primary&quot;);&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;a href=&quot;https://getbem.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BEM&lt;/a&gt;의 Element와 Modifier를 이렇게 표현할 수는 없는걸까?&lt;/p&gt;
&lt;pre id=&quot;code_1692668609988&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3954937184977124&quot;&gt;&lt;code&gt;&amp;lt;form class=&quot;form form--theme-xmas form--simple&quot;&amp;gt;
  &amp;lt;input class=&quot;form__input&quot; type=&quot;text&quot; /&amp;gt;
  &amp;lt;input
    class=&quot;form__submit form__submit--disabled&quot;
    type=&quot;submit&quot; /&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692668893435&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9714735039439991&quot;&gt;&lt;code&gt;&amp;lt;form class={ form([&quot;base&quot;, &quot;simple&quot;, { theme: &quot;xmas&quot; }]) }&amp;gt;
  &amp;lt;input class={ form(&quot;input&quot;) } type=&quot;text&quot; /&amp;gt;
  &amp;lt;input
    class={ form({ sumit: &quot;disabled&quot; }) }
    type=&quot;submit&quot; /&amp;gt;
&amp;lt;/form&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;클래스가 1개와 매핑되던 의미론을 넘어서, 응집력을 갖추게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 &quot;simple&quot;과 theme: &quot;xmas&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;기본기능&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 약간은 동적으로 보일 수 있는 Variants라는 기능을 만든적이 있었다.&lt;/p&gt;
&lt;pre id=&quot;code_1692583573496&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7830804200694764&quot;&gt;&lt;code&gt;const classes = cssVariants({
  parent: {
    &quot;:hover $child&quot;: {
      width: &quot;1px&quot;
    }
  },
  child: {
    &quot;$parent &amp;amp;&quot;: {
      width: &quot;2px&quot;
    }
  }
});&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;pre id=&quot;code_1692583573497&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.2746488724193533&quot;&gt;&lt;code&gt;function Sample() {
  return (
    &amp;lt;div className={classes.parent}&amp;gt;
      &amp;lt;div&amp;gt; className={classes[&quot;child&quot;]}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합성과 함수를 사용하는 모습도 보일 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692583573497&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.25681744561840947&quot;&gt;&lt;code&gt;const base = css({ padding: 12 });
const classes = variants({
  parent: [base, {
    width: &quot;1px&quot;
  }],
  child: ({width}) =&amp;gt; ({
    width
  })
});

function Sample() {
  return (
    &amp;lt;div className={classes.parent}&amp;gt;
      &amp;lt;div&amp;gt; className={classes.child(5)}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 Vanilla Extract는 &lt;a href=&quot;https://vanilla-extract.style/documentation/api/style-variants/#mapping-variants&quot;&gt;mapping&lt;/a&gt;하여 여러 Variants를 찍어내는 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 classes[&quot;small&quot;]과 classes[&quot;large&quot;]를 만들어낸다.&lt;/p&gt;
&lt;pre id=&quot;code_1692583573498&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7412351282438081&quot;&gt;&lt;code&gt;const base = css({ padding: 12 });
const classes = cssVariants(
  {
    small: &quot;1rem&quot;,
    large: &quot;10rem&quot;
  },
  (size) =&amp;gt; [base, { width: size }]
);&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;앞선 작업들을 하려면 로직을 하나씩 작업해줘야 할 것 같다.&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;동적 Variants&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Variants로 유명한 &lt;a href=&quot;https://stitches.dev/&quot;&gt;stitches&lt;/a&gt;는 일반 룰 정의하는 함수 내부에서 variants를 설정할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQM9RC/btsrUnUCbGE/Hiv6CLJGwLpWCeJ1o67ti1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQM9RC/btsrUnUCbGE/Hiv6CLJGwLpWCeJ1o67ti1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQM9RC/btsrUnUCbGE/Hiv6CLJGwLpWCeJ1o67ti1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQM9RC%2FbtsrUnUCbGE%2FHiv6CLJGwLpWCeJ1o67ti1%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;1012&quot; height=&quot;506&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;506&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;우리의 가상 라이브러리는 함수를 반환하는 rules에서 수행할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692583573499&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.1179538822210705&quot;&gt;&lt;code&gt;const sample = rules({
  color: &quot;red&quot;,
  variants: {
    color: {
      white: {
        color: &quot;white&quot;,
        background: {
          base: &quot;black&quot;,
          _hover: &quot;gray&quot;
        }
      }
    },
    outlined: {
      true: {
        borderColor: &quot;blue&quot;
      }
    }
  }
});

function Sample() {
  return (
    &amp;lt;div className={sample({ color: &quot;white&quot;, outlined: true })}&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;그러나 사용법이 우리가 정의했던 방법에 비해서 약간 아쉽다. 개선해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;outlined의 경우 defineRules의 values처럼 toggleVariants블럭으로 옮긴 후, 호출시 배열을 활용해 직관적으로 만들 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692612486932&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.4216991546275364&quot;&gt;&lt;code&gt;const sample = rules({
  color: &quot;red&quot;,
  toggleVariants: {
    outlined: {
      borderColor: &quot;blue&quot;
    }
  },
  variants: { /* ... */ }
});

function Sample() {
  return (
    &amp;lt;div className={sample([&quot;outlined&quot;, { color: &quot;white&quot; }])}&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;variants 구현에 있어 기존 함수형 프로퍼티를 사용해보는건 어떨까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 말했듯 안타깝게도 variant 자체는 이미 switch-match 조건이 포함된 것과 다름 없기에 개선되기가 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 함수형 프로퍼티를 사용하면 컨텍스트의 값을 받아서 처리할 수 있어서 서로 보완적이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692613011874&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.18244292222959668&quot;&gt;&lt;code&gt;// 똑같은 동작
const sample1 = rules((props) =&amp;gt; {
  if(&quot;color&quot; in props) {
    if(props.color == &quot;white&quot;) {
      return ({
        color: &quot;white&quot;,
        background: props.bgColor
      });
    }
  }
});

const sample2 = rules({
  variants: {
    color: {
      white: {
        color: &quot;white&quot;,
        background: ({ bgColor }) =&amp;gt; bgColor
      }
    }
  }
});&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;Stitches에 있는 Variant는 이게 끝이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 Variants를 설정할 수 있음은 당연하고,&lt;/p&gt;
&lt;pre id=&quot;code_1692667477572&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6270279255723924&quot;&gt;&lt;code&gt;const sample = rules({
  // 기본값
  defaultsVariants: [&quot;outlined&quot;, {
    color: &quot;white&quot;,
  }],

  // Variants 들
  toggleVariants: {
    outlined: { /* ... */ }
  },
  variants: {
    color: {
      white: { /*... */ },
      gray: { /*... */ },
    }
    size: {
      small: { /* ... */ },
      big: { /* ... */ }
    }
  }
});&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;적용로직을 선언적&lt;/b&gt;으로 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 호출하면 컴파일 타임에 정적으로 클래스 이름이 생성된다.&lt;/p&gt;
&lt;pre id=&quot;code_1692664396673&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7830343230355507&quot;&gt;&lt;code&gt;const sample = rules({
  /* 위와 같음 */

  // 패턴 패칭 후 적용
  compoundVariants: [
    [&quot;outlined&quot;, { color: &quot;white&quot;, css: { /* YOUR_STYLE */ } ],
    {
      color: gray,
      size: small,
      css: { /* YOUR_STYLE */ }
    }
  ]
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 케이스는 기본 Variants의 이름 참조를 통해서도 가능할 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692672159411&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6278598704909506&quot;&gt;&lt;code&gt;const sample = rules({
  variants: {
    color: {
      white: { /*... */ },
      gray: { /*... */ },
    }
    size: {
      small: { /* ... */ },
      big: {
        $white: {
          // CSS
        }
      }
    }
  }
});&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;아까 AtomicCSS에서도 적용 가능하지 않을까?&lt;/p&gt;
&lt;pre id=&quot;code_1692666396151&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.853377379774622&quot;&gt;&lt;code&gt;const { css } = defineRules({
  defaultCondition: &quot;light&quot;,
  conditions: {
    light: &quot;&quot;,
    dark: [&quot;&amp;amp;.dark&quot;, &quot;.dark &amp;amp;&quot;],
    osLight: {},
    osDark: { &quot;@media&quot;: &quot;(prefers-color-scheme: dark)&quot; },
    hovAct: (children) =&amp;gt; ({
      _hover: {
        base: {
          ...children
        },
        _active: {
          ...children
        }
      }
    })
  },
  compoundConditions: [
    {
      when: [&quot;light&quot;, &quot;osLight&quot;],
      condition: &quot;&amp;amp;.pureLight&quot;
    },
    {
      when: [&quot;light&quot;, &quot;hovAct&quot;],
      condition: (children) =&amp;gt; ({ /* Something */ })
    }
  ]
});&lt;/code&gt;&lt;/pre&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stylable라는 CSS 전처리기의 &lt;a href=&quot;https://stylable.io/docs/references/pseudo-classes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pseudo class&lt;/a&gt;를 보면 st-state라는 이름으로 흥미로운 기능을 제공한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Boolean 타입, Enum 타입, String과 Number 타입으로 나뉨&lt;/li&gt;
&lt;li&gt;Enum은 특정한 문자열 인수만 가능하며, 기본값 정의 가능&lt;/li&gt;
&lt;li&gt;String/Number 타입은 각각의 타입 인수에 관한 validation 함수들을 설정 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1692617769559&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6280535629669486&quot;&gt;&lt;code&gt;.sample {
  -st-states:
    /* Boolean 타입 */
    toggled,
    loading,

    /* Enum 타입 */
    size(enum(small, medium, large)),
    color(enum(red, green, blue)) green, /* green이 기본값 */

    /* String - Number 타입 */
    category(string),
    ranking(number),
    category(string(regex('^user'), minLength(5))), /* 유효성 검사들 */
    x(number(min(2), max(6), multipleOf(2)));
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692655795029&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6087718196993983&quot;&gt;&lt;code&gt;/* 상태 1개 */
.sample:toggled {}

/* 상태 2개 */
.sample:toggled:loading {}

/* size에 medium이 포함되어 있음 */
.sample:size(medium) {}

/* size에 huge가 없음 */
.sample:size(huge) {}

/* green이 기본값으로 사용 */
.sample:color {}

/* 유효성 검사를 거친 Stirng과 Number */
.sample:category(kitchen) {}
.sample:x(4) {}&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;1, 2번은 boolean과 일반 Variant이며, 3번은 함수형 프로퍼티와도 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;런타임에서 사용법도 비슷하다.&lt;/p&gt;
&lt;pre id=&quot;code_1692618307187&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8241456502392412&quot;&gt;&lt;code&gt;import { st, classes } from './sheet.st.css'; 

// active states
st(classes.part, {
  isOn: true,      // boolean
  size: 'small'    // string or enum
  place: 1         // number state
});

// un-active states - only 'part' class
st(classes.part, {
  isFirst: false,  // boolean
  size: undefined  // string or enum
  place: undefined // number
});&lt;/code&gt;&lt;/pre&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stitches의 놀라운 작업 덕분에 API 일관성을 갖추기 빼고는 할 일이 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AtomicCSS의 토큰을 Variants에서 쓰기 또한 그저 defineRules의 리턴값에서 함수를 할당받기 외에는 할 일이 없다.&lt;/p&gt;
&lt;pre id=&quot;code_1692671339168&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.42649136368409235&quot;&gt;&lt;code&gt;const { cssVariants, rules } = defineRules({ /* ... */ });

const sample1 = cssVariants({
  parent: {
    &quot;:hover $child&quot;: {
      w: &quot;1rem&quot;
    }
  },
  child: {
    &quot;$parent &amp;amp;&quot;: {
      w: 2
    }
  }
});

// 함수의 첫번째는 입력 값, 두번째는 Context이다.
const sample2 = ruels({
  c: &quot;red&quot;,
  bg: &quot;primary&quot;,
  variants: {
    color: {
      indigo: {
        bg: (_, {indigo}) =&amp;gt; indigo[600]
      },
      custom: ({ color }) =&amp;gt; ({
        bg: color.custom
      })
    }
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HTML &amp;amp; CSS &amp;amp; JS&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Styled Component&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 HTML + JS 그리고 CSS + JS를 다루었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 HTML과 CSS 조합을 인간친화적으로 만들면 어떨까?&lt;/p&gt;
&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://styled-components.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Styled Components&lt;/a&gt; 되시겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLLqRD/btsrH5no8Ex/EmqP8XDDdN1P1elQulgEEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLLqRD/btsrH5no8Ex/EmqP8XDDdN1P1elQulgEEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLLqRD/btsrH5no8Ex/EmqP8XDDdN1P1elQulgEEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLLqRD%2FbtsrH5no8Ex%2FEmqP8XDDdN1P1elQulgEEk%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;318&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1692674965750&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.011983253781393644&quot;&gt;&lt;code&gt;function Sample() {
  return &amp;lt;div&amp;gt;
    &amp;lt;Button&amp;gt;Normal Button&amp;lt;/Button&amp;gt;
    &amp;lt;Button primary&amp;gt;Primary Button&amp;lt;/Button&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;WindiCSS의 &lt;a href=&quot;https://windicss.org/features/attributify.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Attributify Mode&lt;/a&gt;도 살펴보라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 얼마나 훌륭한 생각인가?&lt;/p&gt;
&lt;pre id=&quot;code_1692663856880&quot; class=&quot;armasm&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7564576241698401&quot;&gt;&lt;code&gt;&amp;lt;button 
  bg=&quot;blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600&quot;
  text=&quot;sm white&quot;
  font=&quot;mono light&quot;
  p=&quot;y-2 x-4&quot;
  border=&quot;2 rounded blue-200&quot;
&amp;gt;
  Button
&amp;lt;/button&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;컴포넌트에 대한 attributify mode까지 작동되면 처음부터 끝까지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구문의 동형성을 달성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1692663823788&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.42467943696639&quot;&gt;&lt;code&gt;// 리터럴 구문
const base = css({ color: &quot;#444&quot; });
const smaple1 = rules({ color }) =&amp;gt; ({ background: color }));
const sample2 = css([&quot;pure-class-name&quot;, base, sample1({ color: &quot;red&quot; }), { width: 10 }]);

// Atomic 구문
const { css: atomic } = defineRules({
  // ...
});
const sample3 = atomic([&quot;uppercase&quot;, { px: 4, _hover: { bg: &quot;red&quot; } }]);

// variants 구문
const variants = rules({
  variants: {
    // ...
  }
});
const sample4 = variants([&quot;outlined&quot;, { accent: &quot;pink&quot; }]);

// styled 구문
const Sample5 = styled(&quot;button&quot;, { /* Something like rules() */ });
const element1 = &amp;lt;Sample5 outlined accent=&quot;pink&quot;&amp;gt;Button&amp;lt;/Sample5&amp;gt;;

// Atomic Styled 구문
const { styled: atomicStyled } = defineRules({
  // ...
});
const Sample6 = atomicStyled(&quot;div&quot;, { /* Something like atomic rules() */ });
const element2 = &amp;lt;Sample6 px={4} bg={({ indigo }) =&amp;gt; indigo[600]} /&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;이 글에서 제안한 함수는 10개도 되지 않지만 꽤나 강력합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;핵심: css(), rules(),&amp;nbsp; defineRules(), styled()&lt;/li&gt;
&lt;li&gt;테마: theme()&amp;nbsp;&amp;nbsp;tokenConstract(), themeConstract()&lt;/li&gt;
&lt;li&gt;기타: cssVariants(), combineRules()&lt;/li&gt;
&lt;/ul&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 인프라의 핵심은 편의성과 성능이라 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Marko like JSX구문이 아니라 스타일을 다루는데도 컴파일러 인프라는 편의성을 제공해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vanilla Extract의 경우 스타일과 컴포넌트 코드를 함께 둘 수(co-location) &lt;a href=&quot;https://github.com/vanilla-extract-css/vanilla-extract/discussions/500&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;Stylelint도 &lt;a href=&quot;https://github.com/vanilla-extract-css/vanilla-extract/discussions/858&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;a href=&quot;https://github.com/callstack/linaria&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Linaria&lt;/a&gt;와 &lt;a href=&quot;https://github.com/macaron-css/macaron&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;macaron&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;a href=&quot;https://github.com/linkedin/css-blocks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Blocks&lt;/a&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://jbee.io/react/headless-concept/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Headless&amp;nbsp;UI&amp;nbsp;Library란?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;원래 HTML - CSS - JS가 그러했고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Literal - Theme - Atomic - Variants - Styled Component 순으로 쌓아 올린 가상의 CSS In JS 라이브러리 또한 CSS 관리를 각단계로 훌륭히 나눌 수 있음을 보여줬다.&lt;/p&gt;
&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://react-spectrum.adobe.com/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Spectrum Libraries&lt;/a&gt;는 상태 - 동작 - 컴포넌트의 분리를 수행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;282&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oMOpC/btsrIabBugY/Ph0baY4KyhxJakK5KVcB40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oMOpC/btsrIabBugY/Ph0baY4KyhxJakK5KVcB40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oMOpC/btsrIabBugY/Ph0baY4KyhxJakK5KVcB40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoMOpC%2FbtsrIabBugY%2FPh0baY4KyhxJakK5KVcB40%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;282&quot; height=&quot;246&quot; data-origin-width=&quot;282&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://react-spectrum.adobe.com/architecture.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;아키텍처&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;State: 뷰에 대한 가정없이 상태만 관리&lt;/li&gt;
&lt;li&gt;Behavior: 플랫폼에 따른 이벤트, 접근성, 국제화를 고려한 동작&lt;/li&gt;
&lt;li&gt;Component:&amp;nbsp; State와 Behavior를 사용하고, 디자인 시스템과 함께 제공&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;a href=&quot;https://github.com/tailwindlabs/headlessui&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Headless UI&lt;/a&gt;, &lt;a href=&quot;https://github.com/radix-ui/primitives&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Radix Primitives&lt;/a&gt;, &lt;a href=&quot;https://ark-ui.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ark-UI&lt;/a&gt;, &lt;a href=&quot;https://zagjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Zag&lt;/a&gt;처럼 좋은 State, Behavior Components들을 제공하는 라이브러리가 늘어나고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타일에서도 &lt;a href=&quot;https://www.kuma-ui.com/docs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kuma UI&lt;/a&gt;처럼 스타일에 관한 Headless UI도 나오고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 &lt;a href=&quot;https://github.com/shadcn-ui/ui&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;shadcn/ui&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;a href=&quot;https://open-ui.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OpenUI&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선언적이고 작성 / 관리하기 쉬운 구문과 라이브러리 API를 가상이지만 만들어보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 그 결과가 깔끔하고 마음에 드는데 배경에는 몇가지 원칙이 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로직을 나열하기보다는 선언적일 것&lt;/li&gt;
&lt;li&gt;각 레이어의 API는 동형적으로 만들어져야 함&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/95#내용과-표현&quot;&gt;표현과 내용은 서로를 전제&lt;/a&gt;하므로 고려해야함&lt;/li&gt;
&lt;li&gt;위계가(관점이) 다르면 &lt;a href=&quot;https://black7375.tistory.com/34#2.4-%EC%A1%B0%EA%B1%B4-%ED%95%A8%EC%88%98.&quot;&gt;배중률이 적용&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&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;size18&quot;&gt;&lt;b&gt;HTML&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;JSX의 제어와 참조는 컴포넌트와 디렉티브를 만들어 개선할 수 있다&lt;/li&gt;
&lt;li&gt;class와 ID는 emmet 구문을 사용해 직관적으로 표현할 수 있다&lt;/li&gt;
&lt;li&gt;프로퍼티에서 자바스크립트 구문을 그대로 사용할 수 있다&lt;/li&gt;
&lt;li&gt;Default argmument과 Children callback관련 문법을 제공할 수 있다&lt;/li&gt;
&lt;li&gt;태그 이름을 직접 보간할 수도 있다&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;size18&quot;&gt;&lt;b&gt;CSS&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;Atomic CSS는 시각적인 위계를 다루고 디자인 토큰을 매핑하기 쉬워야 함&lt;/li&gt;
&lt;li&gt;Atomic CSS를 잘 쓰기 위해서는 Theme에 대한 지원이 필요&lt;/li&gt;
&lt;li&gt;Theme는 규약을 정할 수 있으며, CSS 컴파일 결과와 JS에서 사용을 고려해야 함&lt;/li&gt;
&lt;li&gt;중앙화된 프레임워크는 충분한 유틸리티와 관용적인 프리셋을 가져야 함&lt;/li&gt;
&lt;li&gt;Variants는 의미론적 위계를 다루며, Atomic CSS의 활용도 충분히 가능&lt;/li&gt;
&lt;li&gt;리터럴부터 Styled 컴포넌트까지 거의 동일한 문법으로 사용가능&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;notranslate&quot; style=&quot;all: initial;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝.&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <category>언어</category>
      <category>웹</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/91</guid>
      <comments>https://black7375.tistory.com/91#entry91comment</comments>
      <pubDate>Sun, 11 Sep 2022 01:55:20 +0900</pubDate>
    </item>
    <item>
      <title>동시성, 병렬, 비동기, 논블럭킹과 컨셉들</title>
      <link>https://black7375.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;/p&gt;
&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;h3 data-ke-size=&quot;size23&quot;&gt;1. 용어&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;동시성 / 병렬&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9ufuK/btrMNcGT95i/5t5KiBY4NmkZu5LbxSpIcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9ufuK/btrMNcGT95i/5t5KiBY4NmkZu5LbxSpIcK/img.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;250&quot; data-is-animation=&quot;false&quot; style=&quot;width: 72.9301%; margin-right: 10px;&quot; data-widthpercent=&quot;73.79&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9ufuK/btrMNcGT95i/5t5KiBY4NmkZu5LbxSpIcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9ufuK%2FbtrMNcGT95i%2F5t5KiBY4NmkZu5LbxSpIcK%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;700&quot; height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oI7Dw/btrML9DEUab/rBc7DqAMd1pilaZbMIcAI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oI7Dw/btrML9DEUab/rBc7DqAMd1pilaZbMIcAI0/img.png&quot; data-origin-width=&quot;372&quot; data-origin-height=&quot;374&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;26.21&quot; style=&quot;width: 25.9072%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oI7Dw/btrML9DEUab/rBc7DqAMd1pilaZbMIcAI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoI7Dw%2FbtrML9DEUab%2FrBc7DqAMd1pilaZbMIcAI0%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;372&quot; height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJHmLS/btrMKlq4g17/qD6K7ORunDvhimCmk6sexK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJHmLS/btrMKlq4g17/qD6K7ORunDvhimCmk6sexK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJHmLS/btrMKlq4g17/qD6K7ORunDvhimCmk6sexK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJHmLS%2FbtrMKlq4g17%2FqD6K7ORunDvhimCmk6sexK%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;874&quot; height=&quot;250&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 싱글코어에서 &lt;a href=&quot;https://en.wikipedia.org/wiki/Single_instruction,_multiple_data&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SIMD&lt;/a&gt;를 이용하면 병렬로 작업을 실행할 수 있다.&amp;nbsp; [&lt;a href=&quot;https://blog.naver.com/fs0608/221650925743&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SIMD&amp;nbsp;(Single&amp;nbsp;Instruction&amp;nbsp;Multiple&amp;nbsp;Data)에&amp;nbsp;대한&amp;nbsp;집중탐구!&lt;/a&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;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AALri/btrMRGICOEg/MkMGKTbQHgVqWZSuPJVt9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AALri/btrMRGICOEg/MkMGKTbQHgVqWZSuPJVt9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AALri/btrMRGICOEg/MkMGKTbQHgVqWZSuPJVt9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAALri%2FbtrMRGICOEg%2FMkMGKTbQHgVqWZSuPJVt9K%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;1280&quot; height=&quot;960&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;/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;/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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;939&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzRPyi/btrU44F7anE/hDttEMCKq1vnjEa7mxl5vK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzRPyi/btrU44F7anE/hDttEMCKq1vnjEa7mxl5vK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzRPyi/btrU44F7anE/hDttEMCKq1vnjEa7mxl5vK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzRPyi%2FbtrU44F7anE%2FhDttEMCKq1vnjEa7mxl5vK%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;960&quot; height=&quot;704&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;939&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.ee.surrey.ac.uk/Projects/CAL/seq-switching/synchronous_and_asynchronous_cir.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Synchronous&amp;nbsp;and&amp;nbsp;Asynchronous&amp;nbsp;Circuits&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;소프트웨어 API에서 비동기는 &lt;b&gt;콜백등에 의해 트리거&lt;/b&gt;되는 형태라 생각하자. [&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Synchronous and asynchronous requests&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;br /&gt;(약간의 오버헤드가 있으며 순서를 보장하지 않음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블럭킹/논블럭킹은 &lt;b&gt;작업이 완료될 때까지 기다려야 하는가&lt;/b&gt;의 여부로 생각하면 적절하다. [&lt;a href=&quot;https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Overview&amp;nbsp;of&amp;nbsp;Blocking&amp;nbsp;vs&amp;nbsp;Non-Blocking&lt;/a&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;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4qFtp/btrMUSPpkF3/lYOgahZzlOKbnVHYRaWAG0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4qFtp/btrMUSPpkF3/lYOgahZzlOKbnVHYRaWAG0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4qFtp/btrMUSPpkF3/lYOgahZzlOKbnVHYRaWAG0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4qFtp%2FbtrMUSPpkF3%2FlYOgahZzlOKbnVHYRaWAG0%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;500&quot; height=&quot;302&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xmMvf/btrMWeYKraV/lDgLYqTVgr3kz9awiwMnN0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xmMvf/btrMWeYKraV/lDgLYqTVgr3kz9awiwMnN0/img.jpg&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;428&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.7056%; margin-right: 10px;&quot; data-widthpercent=&quot;50.29&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xmMvf/btrMWeYKraV/lDgLYqTVgr3kz9awiwMnN0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxmMvf%2FbtrMWeYKraV%2FlDgLYqTVgr3kz9awiwMnN0%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;773&quot; height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r5518/btrM0nNUU1U/SMOx6ElvGSA7tP6aC7I5D1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r5518/btrM0nNUU1U/SMOx6ElvGSA7tP6aC7I5D1/img.jpg&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;433&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.71&quot; style=&quot;width: 49.1316%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r5518/btrM0nNUU1U/SMOx6ElvGSA7tP6aC7I5D1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr5518%2FbtrM0nNUU1U%2FSMOx6ElvGSA7tP6aC7I5D1%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;773&quot; height=&quot;433&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;선점형과 비선점형&lt;/figcaption&gt;
&lt;/figure&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;/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;선점형은 Non-Blocking, 비선점형은 Bloking의 일종이라 볼 수 있다.&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;2. 운영체제와 프로세서&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;다른 프로세스에는 직접 엑세스할 수 없으므로 데이터를 주고 받으려면&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Inter-process_communication&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IPC&lt;/a&gt;등을 이용해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;611&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mP5YN/btrMUSU4sLV/eGqMultKRlIHKdQy4aoFF1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mP5YN/btrMUSU4sLV/eGqMultKRlIHKdQy4aoFF1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mP5YN/btrMUSU4sLV/eGqMultKRlIHKdQy4aoFF1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmP5YN%2FbtrMUSU4sLV%2FeGqMultKRlIHKdQy4aoFF1%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;961&quot; height=&quot;611&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;611&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;OS나 언어등의 환경마다 조금씩 다를 수 있지만.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSuKAe/btrMWdK352m/WiZSn7jtq0PaI90jpNFKz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSuKAe/btrMWdK352m/WiZSn7jtq0PaI90jpNFKz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSuKAe/btrMWdK352m/WiZSn7jtq0PaI90jpNFKz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSuKAe%2FbtrMWdK352m%2FWiZSn7jtq0PaI90jpNFKz1%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;951&quot; height=&quot;648&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://xvirt.ink/2018/11/16/memory-layout/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Memory&amp;nbsp;Layout&amp;nbsp;of&amp;nbsp;C&amp;nbsp;Programs&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;/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;695&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xbNn3/btrMUk5CZxn/EoJWCgcrMKUmKiKDSyipC1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xbNn3/btrMUk5CZxn/EoJWCgcrMKUmKiKDSyipC1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xbNn3/btrMUk5CZxn/EoJWCgcrMKUmKiKDSyipC1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxbNn3%2FbtrMUk5CZxn%2FEoJWCgcrMKUmKiKDSyipC1%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;695&quot; height=&quot;428&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;428&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;프로세스와 달리 Heap, Data 영역을 공유하여 IPC가 필요없고&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;1536&quot; data-origin-height=&quot;943&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzPVLw/btrMUxjp6Us/m6rLgu1AaANRFmb4dLWsh1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzPVLw/btrMUxjp6Us/m6rLgu1AaANRFmb4dLWsh1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzPVLw/btrMUxjp6Us/m6rLgu1AaANRFmb4dLWsh1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bzPVLw/btrMUxjp6Us/m6rLgu1AaANRFmb4dLWsh1/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;1536&quot; height=&quot;943&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;943&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.cs.miami.edu/home/wuchtys/CSC322-21S/Content/UNIXProgramming/UNIXThreads.shtml&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;UNIX&amp;nbsp;Threads&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DqTEN/btrO9DhkyOJ/6wZRsp2XKqY0tfjG5pPUKk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DqTEN/btrO9DhkyOJ/6wZRsp2XKqY0tfjG5pPUKk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DqTEN/btrO9DhkyOJ/6wZRsp2XKqY0tfjG5pPUKk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/DqTEN/btrO9DhkyOJ/6wZRsp2XKqY0tfjG5pPUKk/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;679&quot; height=&quot;482&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.fmc-modeling.org/category/projects/apache/amp/A_1_Unix_Processes.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Unix Processes&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;a href=&quot;https://www.microsoftpressstore.com/articles/article.aspx?p=2233328&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Processes, Threads, and Jobs in the Windows Operating System&lt;/a&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;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;675&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hlu4R/btrMUTzGGdD/JRfC9wjhAsWCw4qXKmC1Lk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hlu4R/btrMUTzGGdD/JRfC9wjhAsWCw4qXKmC1Lk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hlu4R/btrMUTzGGdD/JRfC9wjhAsWCw4qXKmC1Lk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHlu4R%2FbtrMUTzGGdD%2FJRfC9wjhAsWCw4qXKmC1Lk%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;2048&quot; height=&quot;1080&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;675&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;675&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzgP2L/btrMTr5tskv/LKQJ57hpjbzL3fDrqnRENk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzgP2L/btrMTr5tskv/LKQJ57hpjbzL3fDrqnRENk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzgP2L/btrMTr5tskv/LKQJ57hpjbzL3fDrqnRENk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzgP2L%2FbtrMTr5tskv%2FLKQJ57hpjbzL3fDrqnRENk%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;2048&quot; height=&quot;1080&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;675&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;물리: CPU에 들어간 실제 코어&lt;/li&gt;
&lt;li&gt;논리: 작업부하를 공유하며 동시에 스케쥴링&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리해보자면 다음과 같다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpgFED/btrMWQ93kOU/zBer0tMzGXKUkM1QdM9Kv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpgFED/btrMWQ93kOU/zBer0tMzGXKUkM1QdM9Kv1/img.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;484&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.7112%; margin-right: 10px;&quot; data-widthpercent=&quot;51.31&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpgFED/btrMWQ93kOU/zBer0tMzGXKUkM1QdM9Kv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpgFED%2FbtrMWQ93kOU%2FzBer0tMzGXKUkM1QdM9Kv1%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;500&quot; height=&quot;484&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G4qjd/btrMVuzvRq7/TSFImQnoyTvwqKTojgNy7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G4qjd/btrMVuzvRq7/TSFImQnoyTvwqKTojgNy7K/img.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;510&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.126%;&quot; data-widthpercent=&quot;48.69&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G4qjd/btrMVuzvRq7/TSFImQnoyTvwqKTojgNy7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG4qjd%2FbtrMVuzvRq7%2FTSFImQnoyTvwqKTojgNy7K%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;500&quot; height=&quot;510&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://beyondthegeek.com/2017/09/29/multi-core-vs-hyper-threading/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Multi&amp;nbsp;Core&amp;nbsp;vs.&amp;nbsp;Hyper-threading&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;/p&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfPLZ8/btrTRexe0qN/O3YDhUNLOaWaysL3BVrMu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfPLZ8/btrTRexe0qN/O3YDhUNLOaWaysL3BVrMu0/img.png&quot; width=&quot;960&quot; height=&quot;617&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;658&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.4616%; margin-right: 10px;&quot; data-widthpercent=&quot;49.03&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfPLZ8/btrTRexe0qN/O3YDhUNLOaWaysL3BVrMu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfPLZ8%2FbtrTRexe0qN%2FO3YDhUNLOaWaysL3BVrMu0%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;1024&quot; height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u72Wn/btrTRCLnTUf/9vVuLXn7JpCgfL6ldLN8ik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u72Wn/btrTRCLnTUf/9vVuLXn7JpCgfL6ldLN8ik/img.png&quot; width=&quot;960&quot; height=&quot;592&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;633&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.3756%;&quot; data-widthpercent=&quot;50.97&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u72Wn/btrTRCLnTUf/9vVuLXn7JpCgfL6ldLN8ik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu72Wn%2FbtrTRCLnTUf%2F9vVuLXn7JpCgfL6ldLN8ik%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;1024&quot; height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;SMP와 NUMA&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 프로세서가 공유된 메모리를 사용하는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Symmetric_multiprocessing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SMP(Symmetric Multi Processing, 대칭형 다중 처리)&lt;/a&gt;와 로컬메모리와 외부 메모리를 분리해 사용하는&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Non-uniform_memory_access&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NUMA(Non-uniform Memory Access, 불균일 기억장치 접근)&lt;/a&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.redhat.com/en/blog/architecting-containers-part-1-why-understanding-user-space-vs-kernel-space-matters&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Architecting&amp;nbsp;Containers&amp;nbsp;Part&amp;nbsp;1:&amp;nbsp;Why&amp;nbsp;Understanding&amp;nbsp;User&amp;nbsp;Space&amp;nbsp;vs.&amp;nbsp;Kernel&amp;nbsp;Space&amp;nbsp;Matters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/hackinbits/linux-kernel-is-the-core-of-any-linux-operating-system-77f229dafb6b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Linux&amp;nbsp;Kernel&amp;nbsp;Explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ebpf.io/what-is-ebpf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What&amp;nbsp;is&amp;nbsp;eBPF?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제는 일반적으로 메모리와 하드웨어를 보호하기 위해 &lt;a href=&quot;https://en.wikipedia.org/wiki/User_space_and_kernel_space&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;사용자 공간(User space)과 커널 공간(Kernel space)&lt;/a&gt;을 나눈다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cC4YSs/btrVAurnyre/fznj0kk4LQoJcOCui91wKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cC4YSs/btrVAurnyre/fznj0kk4LQoJcOCui91wKK/img.png&quot; width=&quot;760&quot; height=&quot;300&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;300&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.1092%; margin-right: 10px;&quot; data-widthpercent=&quot;48.68&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cC4YSs/btrVAurnyre/fznj0kk4LQoJcOCui91wKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcC4YSs%2FbtrVAurnyre%2Ffznj0kk4LQoJcOCui91wKK%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;760&quot; height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSd2Dl/btrVzzAcPlZ/5WwgRU3XqVGAK7ipK02Ms0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSd2Dl/btrVzzAcPlZ/5WwgRU3XqVGAK7ipK02Ms0/img.png&quot; width=&quot;1170&quot; height=&quot;438&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;438&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.728%;&quot; data-widthpercent=&quot;51.32&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSd2Dl/btrVzzAcPlZ/5WwgRU3XqVGAK7ipK02Ms0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSd2Dl%2FbtrVzzAcPlZ%2F5WwgRU3XqVGAK7ipK02Ms0%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;1170&quot; height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/div&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;커널에서는 모든 시스템 기능(VFS, IPC, 스케쥴링, 드라이버 등)을 커널 공간에서 실행하는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Monolithic_kernel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모놀리식&lt;/a&gt;, 최소한만 실행하는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Microkernel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;마이크로&lt;/a&gt;, 중간 방식인 &lt;a href=&quot;https://en.wikipedia.org/wiki/Hybrid_kernel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;하이브리드&lt;/a&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUqidw/btrVzKVLvgy/g8iPKmlYCJHhkhR6ZD2tK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUqidw/btrVzKVLvgy/g8iPKmlYCJHhkhR6ZD2tK1/img.png&quot; width=&quot;400&quot; height=&quot;369&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;369&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;21.69&quot; style=&quot;width: 21.4351%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUqidw/btrVzKVLvgy/g8iPKmlYCJHhkhR6ZD2tK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUqidw%2FbtrVzKVLvgy%2Fg8iPKmlYCJHhkhR6ZD2tK1%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;400&quot; height=&quot;369&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oyp5c/btrVAK8FZFZ/BwDXKKPiLIeZmqW9yI0jJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oyp5c/btrVAK8FZFZ/BwDXKKPiLIeZmqW9yI0jJ0/img.png&quot; width=&quot;960&quot; height=&quot;245&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;327&quot; data-is-animation=&quot;false&quot; style=&quot;width: 77.4022%;&quot; data-widthpercent=&quot;78.31&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oyp5c/btrVAK8FZFZ/BwDXKKPiLIeZmqW9yI0jJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foyp5c%2FbtrVAK8FZFZ%2FBwDXKKPiLIeZmqW9yI0jJ0%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;1280&quot; height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;시스템콜과 커널의 유형&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스(모놀리식), 푸크시아(마이크로), 윈도우 NT(하이브리드)가 대표적인 예.&lt;/p&gt;
&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;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIhTTy/btrPjj32YtG/kqOZt2OpUmj4x3pyha6kpk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIhTTy/btrPjj32YtG/kqOZt2OpUmj4x3pyha6kpk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIhTTy/btrPjj32YtG/kqOZt2OpUmj4x3pyha6kpk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIhTTy%2FbtrPjj32YtG%2FkqOZt2OpUmj4x3pyha6kpk%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://forum.huawei.com/enterprise/en/context-switch-everything-you-need-to-know/thread/685119-895&quot;&gt;Context&amp;nbsp;switch-Everything&amp;nbsp;you&amp;nbsp;need&amp;nbsp;to&amp;nbsp;Know&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;a href=&quot;https://en.wikipedia.org/wiki/Loadable_kernel_module&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;a href=&quot;https://en.wikipedia.org/wiki/EBPF&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;eBPF&lt;/a&gt;를 통해 안전하면서도 커널공간에서 프로그램을 실행하는 방법이 생겼다!!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;659&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFwLjV/btrVzushXqV/eKMDIULhAHQ3pKYBZVEr21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFwLjV/btrVzushXqV/eKMDIULhAHQ3pKYBZVEr21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFwLjV/btrVzushXqV/eKMDIULhAHQ3pKYBZVEr21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFwLjV%2FbtrVzushXqV%2FeKMDIULhAHQ3pKYBZVEr21%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;1280&quot; height=&quot;659&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;659&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;669&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rsuhu/btrVzVCTy6l/VCkZkaCK3hkom1f7cnSWbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rsuhu/btrVzVCTy6l/VCkZkaCK3hkom1f7cnSWbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rsuhu/btrVzVCTy6l/VCkZkaCK3hkom1f7cnSWbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frsuhu%2FbtrVzVCTy6l%2FVCkZkaCK3hkom1f7cnSWbK%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;1280&quot; height=&quot;669&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;669&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;eBPF를 사용한 예로 &lt;a href=&quot;https://en.wikipedia.org/wiki/Express_Data_Path&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;XDP(eXpress Data Path)&lt;/a&gt;가 있으며, 반대로 유저스페이스를 최대한 활용하려는 시도인 &lt;a href=&quot;https://en.wikipedia.org/wiki/Data_Plane_Development_Kit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DPDK(Data Plane Development Kit)&lt;/a&gt;도 주목할만 하다. [&lt;a href=&quot;https://www.minzkn.com/moniwiki/wiki.php/XDP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;XDP(eXpress Data Path)&lt;/a&gt;, &lt;a href=&quot;https://deview.kr/data/deview/session/attach/1000_T3_%EC%86%A1%EC%9D%B8%EC%A3%BC_Kubernetes%20%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EC%97%90%EC%84%9C%EC%9D%98%20%EA%B3%A0%EC%84%B1%EB%8A%A5&amp;amp;%EA%B3%A0%EA%B0%80%EC%9A%A9%EC%84%B1%20NAT%20Networking%20%EC%8B%9C%EC%8A%A4%ED%85%9C.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;K8s&amp;nbsp;에서의&amp;nbsp;eBPF/XDP&amp;nbsp;기반&amp;nbsp;고성능&amp;nbsp;&amp;amp;&amp;nbsp;고가용성&amp;nbsp;NAT&amp;nbsp;시스템&lt;/a&gt;, &lt;a href=&quot;https://www.packetcoders.io/what-is-dpdk/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What&amp;nbsp;is&amp;nbsp;DPDK?&lt;/a&gt;, &lt;a href=&quot;https://www.dpdk.org/wp-content/uploads/sites/35/2018/10/pm-07-DPDK-BPFu6.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DPDK+eBPF&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;3. 코루틴과 파이버&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파이버&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FJdyV/btrMUNAKNfD/CkPD5CswIfgotuY317atH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FJdyV/btrMUNAKNfD/CkPD5CswIfgotuY317atH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FJdyV/btrMUNAKNfD/CkPD5CswIfgotuY317atH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFJdyV%2FbtrMUNAKNfD%2FCkPD5CswIfgotuY317atH0%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;620&quot; height=&quot;494&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;494&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;예외적인 케이스로 DragonFly BSD의 &lt;a href=&quot;https://en.wikipedia.org/wiki/Light_Weight_Kernel_Threads&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LWKT(Light Weight Kernel Threads)&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코루틴&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P9CnW/btrNeHryXl5/LkmDAjUkj88Z1KFbAaT8bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P9CnW/btrNeHryXl5/LkmDAjUkj88Z1KFbAaT8bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P9CnW/btrNeHryXl5/LkmDAjUkj88Z1KFbAaT8bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP9CnW%2FbtrNeHryXl5%2FLkmDAjUkj88Z1KFbAaT8bk%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;500&quot; height=&quot;268&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코루틴은 일시중단(suspend)했다가 재개(resume)할 수 있는 제어요소다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이버와 코루틴은 쓰레드/함수 관계와 비슷하며, 유저수준에서 가장 큰 차이는 코루틴은 서브 루틴처럼 Caller-Callee 사이에서 전환되지만, 파이버는 스케쥴러에 의해 순서가 정해질 수 있다.&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;&lt;a href=&quot;https://medium.com/@jooyunghan/%EC%BD%94%EB%A3%A8%ED%8B%B4-%EC%86%8C%EA%B0%9C-504cecc89407&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코루틴&amp;nbsp;소개&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@jooyunghan/%EC%BD%94%EB%A3%A8%ED%8B%B4%EC%9D%84-%EA%B5%AC%EB%B6%84%ED%95%B4%EB%B3%B4%EC%9E%90-98428c491ace&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코루틴을&amp;nbsp;구분해보자&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@jooyunghan/%EC%BD%94%EB%A3%A8%ED%8B%B4%EA%B3%BC-%ED%8C%8C%EC%9D%B4%EB%B2%84-9e93c12bce30&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코루틴과 파이버&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@jooyunghan/knock-knock-%EC%BD%94%EB%A3%A8%ED%8B%B4-c4ccc17a5d66&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Knock!Knock!&amp;nbsp;코루틴&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@jooyunghan/stackful-stackless-%EC%BD%94%EB%A3%A8%ED%8B%B4-4da83b8dd03e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Stackful/Stackless&amp;nbsp;코루틴&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@jooyunghan/knock-knock-%EC%BD%94%EB%A3%A8%ED%8B%B4-2-e5d26678e021&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Knock!Knock!&amp;nbsp;코루틴&amp;nbsp;#2&lt;/a&gt;&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;코루틴에서 주목할만한 것은 Stackful, Stackless 코루틴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Protothread&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;프로토 쓰레드(Protothread)&lt;/a&gt;라 불리는 것도 스택리스 코루틴의 일종이라 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfM9ML/btrO6NQ2VLx/NRI5Qsh1OdCkLXNYPXbk1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfM9ML/btrO6NQ2VLx/NRI5Qsh1OdCkLXNYPXbk1k/img.png&quot; data-alt=&quot;Stackful 코루틴&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfM9ML/btrO6NQ2VLx/NRI5Qsh1OdCkLXNYPXbk1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfM9ML%2FbtrO6NQ2VLx%2FNRI5Qsh1OdCkLXNYPXbk1k%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Stackful 코루틴&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stackless 코루틴은 피호출자(Callee) 중지(suspend)가 되면 호출자(Caller)로 돌아오지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stackful 코루틴은 sub function에서도 호출자로 돌아올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 Stack 정보를 저장해야 하므로 메모리를 더 소모한다.&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;4. 제네레이터, Async/Await, 컨티뉴에이션&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;제네레이터&lt;/h4&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;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwhvCv/btrO6MR9XSF/auFDGY35VkkYcI0E48Y240/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwhvCv/btrO6MR9XSF/auFDGY35VkkYcI0E48Y240/img.png&quot; data-alt=&quot;제네레이터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwhvCv/btrO6MR9XSF/auFDGY35VkkYcI0E48Y240/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwhvCv%2FbtrO6MR9XSF%2FauFDGY35VkkYcI0E48Y240%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;제네레이터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Generator&amp;nbsp;코루틴은&amp;nbsp;suspend(즉&amp;nbsp;yield)할&amp;nbsp;때&amp;nbsp;제어권을&amp;nbsp;따로&amp;nbsp;지정하지&amp;nbsp;않으며,&amp;nbsp;자동으로&amp;nbsp;Caller에게&amp;nbsp;넘어간다.&amp;nbsp;이러한&amp;nbsp;코루틴을&amp;nbsp;Semi-coroutine&amp;nbsp;혹은&amp;nbsp;Asymmetric&amp;nbsp;코루틴이라고&amp;nbsp;한다.&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;반대의&amp;nbsp;개념,&amp;nbsp;Symmetric&amp;nbsp;코루틴도&amp;nbsp;있다.&amp;nbsp;Caller/Callee의&amp;nbsp;관계가&amp;nbsp;성립하지&amp;nbsp;않으며&amp;nbsp;A&amp;nbsp;코루틴이&amp;nbsp;B&amp;nbsp;코루틴으로&amp;nbsp;제어권을&amp;nbsp;넘겨서&amp;nbsp;B가&amp;nbsp;resume되면(A는&amp;nbsp;제어권을&amp;nbsp;넘기면서&amp;nbsp;suspend),&amp;nbsp;B는&amp;nbsp;그&amp;nbsp;제어권을&amp;nbsp;꼭&amp;nbsp;A에게&amp;nbsp;넘길&amp;nbsp;필요가&amp;nbsp;없다.&amp;nbsp;또다른&amp;nbsp;코루틴&amp;nbsp;C에게&amp;nbsp;제어권을&amp;nbsp;전달하면서&amp;nbsp;suspend할&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;따라서&amp;nbsp;Symmetric&amp;nbsp;코루틴은&amp;nbsp;suspend할&amp;nbsp;때&amp;nbsp;제어권을&amp;nbsp;넘겨받을&amp;nbsp;코루틴을&amp;nbsp;지정하여야&amp;nbsp;한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Async / Await&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GSIAC/btrOQGS79EA/wXqbeYAMaO51yvhMTOd6S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GSIAC/btrOQGS79EA/wXqbeYAMaO51yvhMTOd6S1/img.png&quot; data-alt=&quot;일반적인 Async/Await, 결과를 반환하는 Async/Awiait&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GSIAC/btrOQGS79EA/wXqbeYAMaO51yvhMTOd6S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGSIAC%2FbtrOQGS79EA%2FwXqbeYAMaO51yvhMTOd6S1%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;일반적인 Async/Await, 결과를 반환하는 Async/Awiait&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Async/Await는 언어나 런타임에 따라 동작이 상이할 수 있으나 자바스크립트의 경우 await가 생기면 비동기 함수의 실행을 일시적으로 중단하고, 메인 프로세스를 진행한다.&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;다른 쓰레드(일반적으로 I/O)가 프로미스의 동작을 실행하고 완료되면, 중단(await)지점으로 재개되어 실행한다.&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PkgTN/btrO3FgsPG1/yEKCEZJa1ADUKJzr2YBcnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PkgTN/btrO3FgsPG1/yEKCEZJa1ADUKJzr2YBcnk/img.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PkgTN/btrO3FgsPG1/yEKCEZJa1ADUKJzr2YBcnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPkgTN%2FbtrO3FgsPG1%2FyEKCEZJa1ADUKJzr2YBcnk%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;1024&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boBHHf/btrO4tlPoe1/JhH5qfKbPUWO3gwPuGZis1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boBHHf/btrO4tlPoe1/JhH5qfKbPUWO3gwPuGZis1/img.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boBHHf/btrO4tlPoe1/JhH5qfKbPUWO3gwPuGZis1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboBHHf%2FbtrO4tlPoe1%2FJhH5qfKbPUWO3gwPuGZis1%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;1024&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Return을 하는 Async/Await&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답은 async 함수를 프로미스로 취급한다.&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;h4 data-ke-size=&quot;size20&quot;&gt;컨티뉴에이션&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Continuation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;컨티뉴에이션(Continuation)&lt;/a&gt;은 Coroutine처럼 제어흐름(Control flow)의 일종이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Call-with-current-continuation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;call-with-current-continuation(call/cc)&lt;/a&gt;를 이용하면 다음 이미지와 같이 마치 GOTO문처럼 사용할 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b75bZq/btrO4g75rJv/bbE6CmktyJf9nMy1xVl6B0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b75bZq/btrO4g75rJv/bbE6CmktyJf9nMy1xVl6B0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b75bZq/btrO4g75rJv/bbE6CmktyJf9nMy1xVl6B0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb75bZq%2FbtrO4g75rJv%2FbbE6CmktyJf9nMy1xVl6B0%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&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;a href=&quot;https://www.slideshare.net/openbala/continuations&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Continuations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://guruma.github.io/posts/2018-11-18-Continuation-Concept/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;후속문(Continuation)&amp;nbsp;:&amp;nbsp;제1부.&amp;nbsp;개념과&amp;nbsp;call/cc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cms2.ks.ac.kr/riet/contents/20190304/%ED%95%A8%EC%88%98%ED%98%95%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98%20Continuation%EC%9D%84%20%EC%9D%B4%EC%9A%A9%ED%95%9C%20%ED%9D%90%EB%A6%84%EC%A0%9C%EC%96%B4.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;함수형&amp;nbsp;프로그래밍의&amp;nbsp;Continuation을&amp;nbsp;이용한&amp;nbsp;흐름제어&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/black7375/ReadabilityDocs/tree/master/%EC%BB%B4%ED%93%A8%ED%8C%85%20%EA%B8%B0%EC%88%A0%EC%9D%98%20%EC%9B%90%ED%98%95%ED%83%90%ED%97%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;컴퓨팅 기술의 원형 탐험&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스텝 디버거를 개발하면서 나온&amp;nbsp;&lt;a href=&quot;https://archive.jlongster.com/Whats-in-a-Continuation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What&amp;rsquo;s in a Continuation&lt;/a&gt;와 F#을 이용한 &lt;a href=&quot;https://fsharpforfunandprofit.com/posts/computation-expressions-continuations/&quot;&gt;Understanding&amp;nbsp;continuations&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;s&gt;대신 모든 함수형 프로그래밍이 으레 그렇듯 초반에는 쉽다가 급격히 러닝커브가 올라가는?&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;787&quot; data-origin-height=&quot;409&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u7arM/btrO4tsCrDO/7oxYaCeZY8HkqpdAVgpKm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u7arM/btrO4tsCrDO/7oxYaCeZY8HkqpdAVgpKm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u7arM/btrO4tsCrDO/7oxYaCeZY8HkqpdAVgpKm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu7arM%2FbtrO4tsCrDO%2F7oxYaCeZY8HkqpdAVgpKm1%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;787&quot; height=&quot;409&quot; data-origin-width=&quot;787&quot; data-origin-height=&quot;409&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;787&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbaujH/btrO5tS9DZ9/ixa9WhmtSEc0lHG2UiOFMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbaujH/btrO5tS9DZ9/ixa9WhmtSEc0lHG2UiOFMk/img.png&quot; data-alt=&quot;일반 / 컨티뉴에이션 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbaujH/btrO5tS9DZ9/ixa9WhmtSEc0lHG2UiOFMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbaujH%2FbtrO5tS9DZ9%2Fixa9WhmtSEc0lHG2UiOFMk%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;787&quot; height=&quot;520&quot; data-origin-width=&quot;787&quot; data-origin-height=&quot;520&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;그럼 처음 나왔던 call/cc 함수를 이용하는 예제를 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEUx0T/btrO4tlS6TH/WIs3W6YLu6W4faC7t6fiY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEUx0T/btrO4tlS6TH/WIs3W6YLu6W4faC7t6fiY1/img.png&quot; data-alt=&quot;call/cc&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEUx0T/btrO4tlS6TH/WIs3W6YLu6W4faC7t6fiY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEUx0T%2FbtrO4tlS6TH%2FWIs3W6YLu6W4faC7t6fiY1%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;1468&quot; height=&quot;310&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;call/cc&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;다음 코드를 실행시키면 첫번째 console.log가 실행된 후, cont(5)에서 x의 값이 5로 할당되며 두번째 console.log는 실행되지 않는다.&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;900&quot; data-origin-height=&quot;303&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mgPys/btrO6hdzLKi/KEIANBExyiXXt1SR7QxvK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mgPys/btrO6hdzLKi/KEIANBExyiXXt1SR7QxvK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mgPys/btrO6hdzLKi/KEIANBExyiXXt1SR7QxvK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmgPys%2FbtrO6hdzLKi%2FKEIANBExyiXXt1SR7QxvK0%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;900&quot; height=&quot;303&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;303&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 다음의 예제에서도 두번째 배열 값에서 cont(true)가 실행되어 멈추고 x에 true가 할당된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zuAFN/btrO5f1m5up/roiMObjIbeAUUEKu6nW3nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zuAFN/btrO5f1m5up/roiMObjIbeAUUEKu6nW3nK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zuAFN/btrO5f1m5up/roiMObjIbeAUUEKu6nW3nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzuAFN%2FbtrO5f1m5up%2FroiMObjIbeAUUEKu6nW3nK%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;900&quot; height=&quot;370&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;370&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;그렇다면 GOTO는 어떤 방식으로 나타나는가를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 아이디어는 내부가 아닌 외부에서 컨티뉴에이션 사용이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;value에 callCC의 컨티뉴에이션을 할당 &lt;b&gt;[GOTO의 Label과 같은 역할]&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;value는 함수니 &quot;got a continuation!&quot;이 출력&lt;/li&gt;
&lt;li&gt;value(x * 2) 실행 &lt;b&gt;[GOTO 실행!!]&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;value로 다시 돌아감, value에는 5 * 2로 10이 할당되어 있음&lt;/li&gt;
&lt;li&gt;value는 일반 값이므로 &quot;computation finished 10&quot;을 출력&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0qqWq/btrOGo6o9Ng/qU9nQ8fCD97ptIFA96KrW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0qqWq/btrOGo6o9Ng/qU9nQ8fCD97ptIFA96KrW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0qqWq/btrOGo6o9Ng/qU9nQ8fCD97ptIFA96KrW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0qqWq%2FbtrOGo6o9Ng%2FqU9nQ8fCD97ptIFA96KrW1%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;900&quot; height=&quot;422&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;422&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;423&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KPTTR/btrO5sUiFsj/hkmUDkNu5t5Wyl5n5HkZn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KPTTR/btrO5sUiFsj/hkmUDkNu5t5Wyl5n5HkZn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KPTTR/btrO5sUiFsj/hkmUDkNu5t5Wyl5n5HkZn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKPTTR%2FbtrO5sUiFsj%2FhkmUDkNu5t5Wyl5n5HkZn1%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;900&quot; height=&quot;423&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;423&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;GOTO문의 일종으로 취급될 수 있기 때문에 각종 제어흐름을 구현하는게 가능하다.&lt;/p&gt;
&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://en.wikipedia.org/wiki/Continuation-passing_style&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Continuation Passing Style&lt;/a&gt;에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Continuation Passing Style은 &lt;a href=&quot;https://tech.devsisters.com/posts/crunchy-concurrency-kotlin/&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;a href=&quot;https://gall.dcinside.com/mgallery/board/view/?id=github&amp;amp;no=35622&quot;&gt;Continuation Passing Style (CPS) 를 알아보자&lt;/a&gt;라는 글이 잘 설명되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPS는 꼬리재귀와 상당히 유사하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1273&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rcdH5/btrOQtGna0x/AAgBxUepG47ez5faI6GxQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rcdH5/btrOQtGna0x/AAgBxUepG47ez5faI6GxQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rcdH5/btrOQtGna0x/AAgBxUepG47ez5faI6GxQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrcdH5%2FbtrOQtGna0x%2FAAgBxUepG47ez5faI6GxQ0%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;1273&quot; height=&quot;708&quot; data-origin-width=&quot;1273&quot; data-origin-height=&quot;708&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;a href=&quot;https://black7375.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://black7375.tistory.com/62&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1666232952062&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.&quot; data-og-description=&quot;내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비. 2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/62&quot; data-og-url=&quot;https://black7375.tistory.com/62&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/yuIFR/hyQbCGJrO7/ucdo07WXaqbmyBveyY6Xc0/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/EvxBP/hyQbAWrERB/JL9fbPL62glJDRmyhHXOGk/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/u9kkj/hyQapudEPJ/3Rr5ct4gLZKZ2gWwKQR36K/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612&quot; data-tc-id=&quot;w-0.07976674517244065&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/62&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/yuIFR/hyQbCGJrO7/ucdo07WXaqbmyBveyY6Xc0/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/EvxBP/hyQbAWrERB/JL9fbPL62glJDRmyhHXOGk/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/u9kkj/hyQapudEPJ/3Rr5ct4gLZKZ2gWwKQR36K/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612');&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;내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비. 2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.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;다만, 1, 2, 6, 24처럼 누산값(accumulator)을 전달하는 대신 컨티뉴에이션을 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pow(제곱)함수를 컨티뉴에이션으로 반환하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DEu0a/btrOQo55VMe/1JejB5a31Hk1pKWH7cDHQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DEu0a/btrOQo55VMe/1JejB5a31Hk1pKWH7cDHQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DEu0a/btrOQo55VMe/1JejB5a31Hk1pKWH7cDHQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDEu0a%2FbtrOQo55VMe%2F1JejB5a31Hk1pKWH7cDHQK%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;603&quot; height=&quot;80&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;80&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;그래서 만약 다음 메인함수를 CPS 스타일로 변환한다면?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJaNDN/btrOQx23kQj/PYvpkOEQKeUmTfwQ5LrYcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJaNDN/btrOQx23kQj/PYvpkOEQKeUmTfwQ5LrYcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJaNDN/btrOQx23kQj/PYvpkOEQKeUmTfwQ5LrYcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJaNDN%2FbtrOQx23kQj%2FPYvpkOEQKeUmTfwQ5LrYcK%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;494&quot; height=&quot;80&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;80&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;pow를 분리하여 순서를 맞추고, CPS로 변환하면 끝.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RITDA/btrOQqCOHln/znuhD53TaZek3xObqXlxbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RITDA/btrOQqCOHln/znuhD53TaZek3xObqXlxbk/img.png&quot; data-orgext=&quot;1&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;125&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.2599%; margin-right: 10px;&quot; data-widthpercent=&quot;49.84&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RITDA/btrOQqCOHln/znuhD53TaZek3xObqXlxbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRITDA%2FbtrOQqCOHln%2FznuhD53TaZek3xObqXlxbk%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;454&quot; height=&quot;125&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOyyU8/btrO78AQeZ2/ip6KSUBB7KeGojaNB0tIKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOyyU8/btrO78AQeZ2/ip6KSUBB7KeGojaNB0tIKK/img.png&quot; data-orgext=&quot;1&quot; data-origin-width=&quot;541&quot; data-origin-height=&quot;148&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50.16&quot; style=&quot;width: 49.5773%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOyyU8/btrO78AQeZ2/ip6KSUBB7KeGojaNB0tIKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOyyU8%2FbtrO78AQeZ2%2Fip6KSUBB7KeGojaNB0tIKK%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;541&quot; height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MQqlD/btrO35TmQ0j/5IOB2Z9yGAeZcZSZYamaEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MQqlD/btrO35TmQ0j/5IOB2Z9yGAeZcZSZYamaEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MQqlD/btrO35TmQ0j/5IOB2Z9yGAeZcZSZYamaEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMQqlD%2FbtrO35TmQ0j%2F5IOB2Z9yGAeZcZSZYamaEK%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;617&quot; height=&quot;171&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;171&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;다음 자료에 앞선 그림자료와 예제코드까지 잘 설명되어있으니 참고바란다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dmitrykandalov.com/coroutines-as-threads&quot;&gt;Coroutines&amp;nbsp;As&amp;nbsp;Threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dmitrykandalov.com/yielding-generators&quot;&gt;Yielding&amp;nbsp;Generators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dmitrykandalov.com/async-await&quot;&gt;Async&amp;nbsp;Await&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dmitrykandalov.com/call-with-current-continuation&quot;&gt;Call&amp;nbsp;With&amp;nbsp;Current&amp;nbsp;Continuation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. Promise와 Future, 스트림, 메세징&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Promise / Future&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://dist-prog-book.com/chapter/2/futures.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Futures&amp;nbsp;and&amp;nbsp;Promises&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://speakerdeck.com/heathermiller/futures-and-promises-in-scala-2-dot-10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Futures and Promises in Scala 2.10&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.labviewcraftsmen.com/blog/futures-promises-and-continuations-oh-my&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;Futures,&amp;nbsp;Promises&amp;nbsp;and&amp;nbsp;Continuations,&amp;nbsp;Oh&amp;nbsp;My!&lt;/a&gt;&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;Promise(약속)과 Future(미래, &lt;s&gt;선물&lt;/s&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lm50j/btrO9OQndNl/FKzKkCMbBNB9GrNgWai5Hk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lm50j/btrO9OQndNl/FKzKkCMbBNB9GrNgWai5Hk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lm50j/btrO9OQndNl/FKzKkCMbBNB9GrNgWai5Hk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLm50j%2FbtrO9OQndNl%2FFKzKkCMbBNB9GrNgWai5Hk%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&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;프로미스: 퓨처가 참조하는 한번 결과를 할당 가능한 가능한 값이며,&amp;nbsp; CompletableFuture나 Completer로도 불리기도 한다.&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wWKZX/btrO5gGHAK4/WOHB2zEjbTK2TclcNyWGpK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wWKZX/btrO5gGHAK4/WOHB2zEjbTK2TclcNyWGpK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wWKZX/btrO5gGHAK4/WOHB2zEjbTK2TclcNyWGpK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwWKZX%2FbtrO5gGHAK4%2FWOHB2zEjbTK2TclcNyWGpK%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&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;참고로 MPSC(Multi-producer, single-consumer)와 같은 용어를 본 적이 있을 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;M은 멀티, S는 Single&lt;/li&gt;
&lt;li&gt;P는 생산자, C는 소비자&lt;/li&gt;
&lt;/ul&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;h4 data-ke-size=&quot;size20&quot;&gt;Stream / Buffer&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.infoq.com/articles/Async-Streams/&quot;&gt;Async Streams in C# 8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 커다랗거나 연속된 데이터를 다룬다고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통으로 처리하거나 전달하기보다 덩어리(Chunk) 단위로 다루기를 원할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림(Stream)은 연속적인 데이터 흐름이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G6x4J/btrVkXGVLF7/QqK3YD6isVMQL8anOGvil0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G6x4J/btrVkXGVLF7/QqK3YD6isVMQL8anOGvil0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G6x4J/btrVkXGVLF7/QqK3YD6isVMQL8anOGvil0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG6x4J%2FbtrVkXGVLF7%2FQqK3YD6isVMQL8anOGvil0%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;1024&quot; height=&quot;354&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://codemacaw.com/2019/11/29/introduction-of-nodejs-streams/&quot;&gt;Introduction&amp;nbsp;to&amp;nbsp;NodeJS&amp;nbsp;Streams&lt;/a&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;/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;그럼 임시적으로 데이터를 담아놓는 버퍼(Buffer)가 왜 필요할까?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전달이 빠름: 데이터를 바로 처리할 수 없기 때문에 저장&lt;br /&gt;(비디오 다운로드가 보는 속도보다 빠를때 미리 저장해둠)&lt;/li&gt;
&lt;li&gt;전달이 느림: 처리할 크기가 될 때까지 저장&lt;br /&gt;(연결이 느릴때 0.1초 단위로 비디오를 보여주기보다 1~2초단위로 보여주기 위해 저장)&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;/p&gt;
&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceMex0/btrVme9uIsd/HGmeg8b19ZbLaEUDaC6aT0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceMex0/btrVme9uIsd/HGmeg8b19ZbLaEUDaC6aT0/img.jpg&quot; style=&quot;width: 25.0627%; margin-right: 10px;&quot; data-src=&quot;articles/Async-Streams/en/resources/18-Synchronous-Data-Pull-resized-2-1535723140308.jpg&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;556&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;25.66&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceMex0/btrVme9uIsd/HGmeg8b19ZbLaEUDaC6aT0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceMex0%2FbtrVme9uIsd%2FHGmeg8b19ZbLaEUDaC6aT0%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;407&quot; height=&quot;556&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZcKur/btrVjRf3iEr/LrYYBl4CHnAPhwKKC5Tc61/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZcKur/btrVjRf3iEr/LrYYBl4CHnAPhwKKC5Tc61/img.jpg&quot; style=&quot;width: 31.2639%; margin-right: 10px;&quot; data-src=&quot;articles/Async-Streams/en/resources/19-Asynchronous-Data-Pull-resized-1535722901107.jpg&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;472&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;32.01&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZcKur/btrVjRf3iEr/LrYYBl4CHnAPhwKKC5Tc61/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZcKur%2FbtrVjRf3iEr%2FLrYYBl4CHnAPhwKKC5Tc61%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;431&quot; height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xRwXb/btrVk5ESTn2/Kpr9eKXSx4tMwtskVoyer1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xRwXb/btrVk5ESTn2/Kpr9eKXSx4tMwtskVoyer1/img.jpg&quot; style=&quot;width: 41.3479%;&quot; data-src=&quot;articles/Async-Streams/en/resources/110-Asynchronous-Sequence-Data-Pull-small-1535721009722.jpg&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;496&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;42.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xRwXb/btrVk5ESTn2/Kpr9eKXSx4tMwtskVoyer1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxRwXb%2FbtrVk5ESTn2%2FKpr9eKXSx4tMwtskVoyer1%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;599&quot; height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Stream은 전체 데이터를 나눠서 처리할 수 있음&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;h4 data-ke-size=&quot;size20&quot;&gt;Push / Pull&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://easylive.io/en/support/knowledge-base/version-V14/core-concepts/push-vs-pull/&quot;&gt;What's&amp;nbsp;the&amp;nbsp;difference&amp;nbsp;between&amp;nbsp;push&amp;nbsp;and&amp;nbsp;pull&amp;nbsp;protocols?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://iximiuz.com/en/posts/nodejs-readable-streams-distilled/&quot;&gt;Node.js Readable streams distilled&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dotnetcurry.com/csharp/async-streams&quot;&gt;Async streams in C# &amp;ndash; Deep Dive&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림처럼 연속된 데이터를 주고 받을때 필요한 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pull과 Push는 생산자와 소비자의 통신방식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBMwxa/btrVjhF86Au/P3gJKY6kc8kamQHUgnFwYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBMwxa/btrVjhF86Au/P3gJKY6kc8kamQHUgnFwYK/img.png&quot; style=&quot;width: 49.1259%; margin-right: 10px;&quot; data-origin-width=&quot;501&quot; data-origin-height=&quot;314&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.7&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBMwxa/btrVjhF86Au/P3gJKY6kc8kamQHUgnFwYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBMwxa%2FbtrVjhF86Au%2FP3gJKY6kc8kamQHUgnFwYK%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;314&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H9Tue/btrVkWVxJko/IWdrFwpjQnBQMGWZKUhkDK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H9Tue/btrVkWVxJko/IWdrFwpjQnBQMGWZKUhkDK/img.jpg&quot; style=&quot;width: 49.7113%;&quot; data-src=&quot;articles/Async-Streams/en/resources/11-Pull-Programming-Model-vs-Push-Programming-Model-small-1535721010263.jpg&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;371&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50.3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H9Tue/btrVkWVxJko/IWdrFwpjQnBQMGWZKUhkDK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH9Tue%2FbtrVkWVxJko%2FIWdrFwpjQnBQMGWZKUhkDK%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;599&quot; height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;pull / push&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pull: 소비자가 요청하면 데이터를 줌&lt;/li&gt;
&lt;li&gt;Push: 생산자가 데이터를 주면 받아서 씀&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;Pull은 동기, Push는 비동기에 가깝다고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 서로 유리한 지점이 다르다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cy3zgQ/btrVeWbXUH8/Wmgww7jRkpo0ZS3SnG7yuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cy3zgQ/btrVeWbXUH8/Wmgww7jRkpo0ZS3SnG7yuK/img.png&quot; style=&quot;width: 57.2081%; margin-right: 10px;&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;908&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;57.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cy3zgQ/btrVeWbXUH8/Wmgww7jRkpo0ZS3SnG7yuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcy3zgQ%2FbtrVeWbXUH8%2FWmgww7jRkpo0ZS3SnG7yuK%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;1136&quot; height=&quot;908&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3OwP8/btrVgh7E6DW/Ep8Bvt5KzCytvtivMr6cv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3OwP8/btrVgh7E6DW/Ep8Bvt5KzCytvtivMr6cv0/img.png&quot; style=&quot;width: 41.6291%;&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;1250&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;42.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3OwP8/btrVgh7E6DW/Ep8Bvt5KzCytvtivMr6cv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3OwP8%2FbtrVgh7E6DW%2FEp8Bvt5KzCytvtivMr6cv0%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;1138&quot; height=&quot;1250&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Pull/ Push&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pull: 요청이 들어오면 바로 데이터를 제공해야 하므로 빠른 생산자가 있을 때 유리&lt;/li&gt;
&lt;li&gt;Push: 데이터를 주면 바로 소비할 수 있는 빠른 소비자가 있을 때 유리&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;Push의 대표적인 예는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promise&lt;/a&gt;와&amp;nbsp;&lt;a href=&quot;https://rxjs.dev/guide/observable&quot;&gt;Observable&lt;/a&gt;가 있다. [&lt;a href=&quot;https://www.howdy-mj.me/rxjs/reactive-programming-and-rxjs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;반응형&amp;nbsp;프로그래밍과&amp;nbsp;RxJS&lt;/a&gt;, &lt;a href=&quot;https://obaranovskyi.medium.com/the-ultimate-guide-to-observables-and-vs-promises-rxjs7-296877376668&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The ultimate guide to Observables and/vs Promises (+RxJS7)&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;305&quot; data-origin-height=&quot;183&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ejym5b/btrVjR8cm4u/MRQJBxow3CKQVk7k67iF91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ejym5b/btrVjR8cm4u/MRQJBxow3CKQVk7k67iF91/img.png&quot; data-alt=&quot;Observable은 여러 값의 지연 푸시 컬렉션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ejym5b/btrVjR8cm4u/MRQJBxow3CKQVk7k67iF91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fejym5b%2FbtrVjR8cm4u%2FMRQJBxow3CKQVk7k67iF91%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;305&quot; height=&quot;183&quot; data-origin-width=&quot;305&quot; data-origin-height=&quot;183&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Observable은 여러 값의 지연 푸시 컬렉션&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 스트림에 나온 Asynchronous Sequence Data Pull은 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Async Iterator&lt;/a&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;Sub / Pub&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 생산자나 소비자가 여러개일 때 직접이 아닌 간접적으로 연결하고 싶다면 어떻게 될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ZeroMQ의 문서가 아주 잘 되어 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://zeromq.org/socket-api/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Socket&amp;nbsp;API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zguide.zeromq.org/docs/chapter2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sockets&amp;nbsp;and&amp;nbsp;Patterns&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lrHVo/btsl5jD3V2P/F16WJwSkkpCoZEMrB9XDX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lrHVo/btsl5jD3V2P/F16WJwSkkpCoZEMrB9XDX0/img.png&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;304&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.7811%; margin-right: 10px;&quot; data-widthpercent=&quot;56.44&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lrHVo/btsl5jD3V2P/F16WJwSkkpCoZEMrB9XDX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlrHVo%2Fbtsl5jD3V2P%2FF16WJwSkkpCoZEMrB9XDX0%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;432&quot; height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBou1e/btsl6NY8S0s/9E50PcAuvkkgTcD4RzR2iK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBou1e/btsl6NY8S0s/9E50PcAuvkkgTcD4RzR2iK/img.png&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;320&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.0561%;&quot; data-widthpercent=&quot;43.56&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBou1e/btsl6NY8S0s/9E50PcAuvkkgTcD4RzR2iK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBou1e%2Fbtsl6NY8S0s%2F9E50PcAuvkkgTcD4RzR2iK%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;351&quot; height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Pub&amp;nbsp; / Sub&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;직접 연결인 Observer 패턴과 비교해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pi8ES/btsl9u57qL6/wYWq0PqjGLxC6O592zEIck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pi8ES/btsl9u57qL6/wYWq0PqjGLxC6O592zEIck/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.7874%; margin-right: 10px;&quot; data-widthpercent=&quot;52.4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pi8ES/btsl9u57qL6/wYWq0PqjGLxC6O592zEIck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpi8ES%2Fbtsl9u57qL6%2FwYWq0PqjGLxC6O592zEIck%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;1280&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br0FkN/btsl3iSVr7r/Ykzvkk1eeUwGN3Wfnm4jLK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br0FkN/btsl3iSVr7r/Ykzvkk1eeUwGN3Wfnm4jLK/img.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;634&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.0498%;&quot; data-widthpercent=&quot;47.6&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br0FkN/btsl3iSVr7r/Ykzvkk1eeUwGN3Wfnm4jLK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr0FkN%2Fbtsl3iSVr7r%2FYkzvkk1eeUwGN3Wfnm4jLK%2Fimg.webp&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;1024&quot; height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.agilecaterpillar.com/blog/observer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Observer&amp;nbsp;vs&amp;nbsp;Publisher-Subscriber&amp;nbsp;Pattern&lt;/a&gt;, &lt;a href=&quot;https://www.aiplusinfo.com/blog/observer-vs-pub-sub-pattern-what-is-the-difference/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Observer vs. Pub-Sub Pattern: What is the Difference&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;ZeroMQ의 특이한점은 메세지 브로커 대신 소켓의 Wrapper로 해결하려 한다는 점.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;387&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDm2Bo/btsl3jxyOyr/sgah4TXpqHExWxyqb7z7Q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDm2Bo/btsl3jxyOyr/sgah4TXpqHExWxyqb7z7Q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDm2Bo/btsl3jxyOyr/sgah4TXpqHExWxyqb7z7Q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDm2Bo%2Fbtsl3jxyOyr%2Fsgah4TXpqHExWxyqb7z7Q1%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;387&quot; height=&quot;256&quot; data-origin-width=&quot;387&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;a href=&quot;https://www.zkoss.org/wiki/ZK_Developer%27s_Reference/Event_Handling/Event_Queues&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Event&amp;nbsp;Queues&lt;/a&gt;, &lt;a href=&quot;https://medium.com/elixirlabs/event-bus-implementation-s-d2854a9fafd5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Event Bus Implementation(s)&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://cloudramblings.me/2015/03/31/event-driven-architecture-the-basics/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Event Driven Architecture &amp;ndash; The Basics&lt;/a&gt;, &amp;nbsp;&lt;a href=&quot;https://www.codeproject.com/Articles/30066/EventBroker-a-notification-component-for-synchrono&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;EventBroker:&amp;nbsp;a&amp;nbsp;notification&amp;nbsp;component&amp;nbsp;for&amp;nbsp;synchronous&amp;nbsp;and&amp;nbsp;asynchronous,&amp;nbsp;loosly&amp;nbsp;coupled&amp;nbsp;event&amp;nbsp;handling&lt;/a&gt;, &lt;a href=&quot;https://medium.com/swlh/the-engineers-guide-to-event-driven-architectures-benefits-and-challenges-3e96ded8568b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Engineers&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;Event-Driven&amp;nbsp;Architectures:&amp;nbsp;Benefits&amp;nbsp;and&amp;nbsp;Challenges&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCQnTS/btsl1fQv6Go/0UrppfsovdiswpfvbHksK0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCQnTS/btsl1fQv6Go/0UrppfsovdiswpfvbHksK0/img.jpg&quot; width=&quot;626&quot; height=&quot;160&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;160&quot; data-is-animation=&quot;false&quot; style=&quot;width: 75.0665%; margin-right: 10px;&quot; data-widthpercent=&quot;75.95&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCQnTS/btsl1fQv6Go/0UrppfsovdiswpfvbHksK0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCQnTS%2Fbtsl1fQv6Go%2F0UrppfsovdiswpfvbHksK0%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;626&quot; height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/elItD2/btsl6L76W50/cK1PkqKKN9OgiuA1ZawbdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/elItD2/btsl6L76W50/cK1PkqKKN9OgiuA1ZawbdK/img.png&quot; width=&quot;700&quot; height=&quot;565&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;565&quot; data-is-animation=&quot;false&quot; style=&quot;width: 23.7707%;&quot; data-widthpercent=&quot;24.05&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/elItD2/btsl6L76W50/cK1PkqKKN9OgiuA1ZawbdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FelItD2%2Fbtsl6L76W50%2FcK1PkqKKN9OgiuA1ZawbdK%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;700&quot; height=&quot;565&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPcc5S/btsl2KWuEui/7oXDL2mX5RxUljrJAjohwK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPcc5S/btsl2KWuEui/7oXDL2mX5RxUljrJAjohwK/img.jpg&quot; width=&quot;960&quot; height=&quot;720&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;810&quot; data-is-animation=&quot;false&quot; style=&quot;width: 23.0364%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;23.58&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPcc5S/btsl2KWuEui/7oXDL2mX5RxUljrJAjohwK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPcc5S%2Fbtsl2KWuEui%2F7oXDL2mX5RxUljrJAjohwK%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;1080&quot; height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YWB0R/btsl5jYosjd/bJ4zXa5pSRKO4XFGhd4QP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YWB0R/btsl5jYosjd/bJ4zXa5pSRKO4XFGhd4QP0/img.png&quot; data-origin-width=&quot;492&quot; data-origin-height=&quot;246&quot; data-is-animation=&quot;false&quot; style=&quot;width: 34.5546%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;35.38&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YWB0R/btsl5jYosjd/bJ4zXa5pSRKO4XFGhd4QP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYWB0R%2Fbtsl5jYosjd%2FbJ4zXa5pSRKO4XFGhd4QP0%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;492&quot; height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwmtEq/btsl1znAy7E/Cc0OkzLCKVlvwK6b5kHUZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwmtEq/btsl1znAy7E/Cc0OkzLCKVlvwK6b5kHUZ1/img.png&quot; width=&quot;638&quot; height=&quot;275&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;275&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;41.04&quot; style=&quot;width: 40.0834%; margin-top: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwmtEq/btsl1znAy7E/Cc0OkzLCKVlvwK6b5kHUZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwmtEq%2Fbtsl1znAy7E%2FCc0OkzLCKVlvwK6b5kHUZ1%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;638&quot; height=&quot;275&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;큐: 선입선출(FIFO)이 보장됨&lt;/li&gt;
&lt;li&gt;버스: 여러 생산자가 있을 경우, 모든 내용은 공유됨, FIFO를 보장하지 않을 수도 있음&lt;/li&gt;
&lt;li&gt;브로커: 일종의 허브로서 라우터 역할을 함&lt;/li&gt;
&lt;/ul&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;/h4&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://learn.microsoft.com/en-us/azure/service-bus-messaging/compare-messaging-services&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Azure에 따르면&lt;/a&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;/ul&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;일반적으로 메세지 중심의 경우 메세지가 중간에 사라지지 않고 처리하기를 기대하기 때문에 Pull에 가깝고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 중심은 알림을 보낸 후 처리를 신경쓰지 않으므로&amp;nbsp; Push에 가깝다.&lt;/p&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~5가지 유형으로 나누기도 한다. [&lt;a href=&quot;https://thehonestcoder.com/types-of-messages-in-message-driven-systems/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Types&amp;nbsp;of&amp;nbsp;Messages&amp;nbsp;in&amp;nbsp;Message-Driven&amp;nbsp;Systems&lt;/a&gt;, &lt;a href=&quot;https://developer.lightbend.com/docs/akka-guide/concepts/message-driven-event-driven.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Message&amp;nbsp;Driven&amp;nbsp;vs&amp;nbsp;Event&amp;nbsp;Driven&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zv0ST/btsl1fQvj7p/Qq89SSRqimygT6cDbJthOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zv0ST/btsl1fQvj7p/Qq89SSRqimygT6cDbJthOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zv0ST/btsl1fQvj7p/Qq89SSRqimygT6cDbJthOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZv0ST%2Fbtsl1fQvj7p%2FQq89SSRqimygT6cDbJthOK%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;512&quot; height=&quot;450&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;쿼리: 정보를 얻기 위해 보내는 메세지&lt;/li&gt;
&lt;li&gt;회신: 명령 혹은 쿼리의 응답 메세지 [엄격하게 해석하면 쿼리에 대한 응답만 치는 경우도]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외 궁금한 점이 있다면 &lt;a href=&quot;https://www.enterpriseintegrationpatterns.com/patterns/messaging/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Messaging Patterns&lt;/a&gt; 사이트를 참고해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rTwen/btsl2Tlkbp3/WU3AsPuuPAB0vSjXs29840/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rTwen/btsl2Tlkbp3/WU3AsPuuPAB0vSjXs29840/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rTwen/btsl2Tlkbp3/WU3AsPuuPAB0vSjXs29840/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrTwen%2Fbtsl2Tlkbp3%2FWU3AsPuuPAB0vSjXs29840%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;768&quot; height=&quot;474&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;474&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로덕션 제품들은 여러가지 개념들을 섞거나 보완하기 마련이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종류가 많지만 유명한건 Kafka, RabbitMQ, ActiveMQ, ZeroMQ일 것이다. [&lt;a href=&quot;https://digitalvarys.com/kafka-vs-activemq-vs-rabbitmq-vs-zeromq/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kafka&amp;nbsp;vs&amp;nbsp;ActiveMQ&amp;nbsp;vs&amp;nbsp;RabbitMQ&amp;nbsp;vs&amp;nbsp;ZeroMQ&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RwbQO/btsl5jYp9BQ/Jd2TFOOGN3WXc3vUIintYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RwbQO/btsl5jYp9BQ/Jd2TFOOGN3WXc3vUIintYK/img.png&quot; width=&quot;641&quot; height=&quot;356&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;356&quot; data-is-animation=&quot;false&quot; style=&quot;width: 61.3012%; margin-right: 10px;&quot; data-widthpercent=&quot;62.02&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RwbQO/btsl5jYp9BQ/Jd2TFOOGN3WXc3vUIintYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRwbQO%2Fbtsl5jYp9BQ%2FJd2TFOOGN3WXc3vUIintYK%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;641&quot; height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgVF63/btsl2nGYuss/jkty2Hi8yOATAmjKKHsypk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgVF63/btsl2nGYuss/jkty2Hi8yOATAmjKKHsypk/img.png&quot; width=&quot;699&quot; height=&quot;634&quot; data-origin-width=&quot;699&quot; data-origin-height=&quot;634&quot; data-is-animation=&quot;false&quot; style=&quot;width: 37.5361%;&quot; data-widthpercent=&quot;37.98&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgVF63/btsl2nGYuss/jkty2Hi8yOATAmjKKHsypk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgVF63%2Fbtsl2nGYuss%2Fjkty2Hi8yOATAmjKKHsypk%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;699&quot; height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bH3Yoh/btsl5kiIjXt/coHrlRCfyzjnqDdkVKZNLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH3Yoh/btsl5kiIjXt/coHrlRCfyzjnqDdkVKZNLk/img.png&quot; data-origin-width=&quot;748&quot; data-origin-height=&quot;480&quot; data-widthpercent=&quot;56.29&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.6359%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH3Yoh/btsl5kiIjXt/coHrlRCfyzjnqDdkVKZNLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH3Yoh%2Fbtsl5kiIjXt%2FcoHrlRCfyzjnqDdkVKZNLk%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;748&quot; height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb3exR/btsl9LGM6in/s9ZXbgg7AxTiFCJkUsgdI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb3exR/btsl9LGM6in/s9ZXbgg7AxTiFCJkUsgdI0/img.png&quot; width=&quot;699&quot; height=&quot;634&quot; data-recalc-dims=&quot;1&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;438&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;43.71&quot; style=&quot;width: 43.2013%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb3exR/btsl9LGM6in/s9ZXbgg7AxTiFCJkUsgdI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb3exR%2Fbtsl9LGM6in%2Fs9ZXbgg7AxTiFCJkUsgdI0%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;530&quot; height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/div&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;size18&quot;&gt;&lt;b&gt;Kafka&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kafka에는 토픽으로 나뉘어 저장된다. [&lt;a href=&quot;https://kafka.apache.org/documentation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kafka&lt;/a&gt;, &lt;a href=&quot;https://www.cloudkarafka.com/blog/part1-kafka-for-beginners-what-is-apache-kafka.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Part 1: Apache Kafka for beginners - What is Apache Kafka?&lt;/a&gt; ]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;754&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OU0uS/btsl1Wv41xu/oTrkrkBmyCctAGZp2L7LEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OU0uS/btsl1Wv41xu/oTrkrkBmyCctAGZp2L7LEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OU0uS/btsl1Wv41xu/oTrkrkBmyCctAGZp2L7LEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOU0uS%2Fbtsl1Wv41xu%2FoTrkrkBmyCctAGZp2L7LEK%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;1456&quot; height=&quot;754&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;754&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ziuwB/btsl1zgPn8t/3zOdIL3dL5bqob7cEjr2X0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ziuwB/btsl1zgPn8t/3zOdIL3dL5bqob7cEjr2X0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ziuwB/btsl1zgPn8t/3zOdIL3dL5bqob7cEjr2X0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FziuwB%2Fbtsl1zgPn8t%2F3zOdIL3dL5bqob7cEjr2X0%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;592&quot; height=&quot;399&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;399&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;size18&quot;&gt;&lt;b&gt;RabbitMQ&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RabbitMQ의 브로커는 교환과 큐로 이루어져 있다. [&lt;a href=&quot;https://www.cloudamqp.com/blog/part1-rabbitmq-for-beginners-what-is-rabbitmq.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Part&amp;nbsp;1:&amp;nbsp;RabbitMQ&amp;nbsp;for&amp;nbsp;beginners&amp;nbsp;-&amp;nbsp;What&amp;nbsp;is&amp;nbsp;RabbitMQ?&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;736&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/de58YQ/btsl0WXGxL8/Cp0ETDkePwo8bgshdjatC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/de58YQ/btsl0WXGxL8/Cp0ETDkePwo8bgshdjatC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/de58YQ/btsl0WXGxL8/Cp0ETDkePwo8bgshdjatC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fde58YQ%2Fbtsl0WXGxL8%2FCp0ETDkePwo8bgshdjatC0%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;1206&quot; height=&quot;736&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;736&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;size18&quot;&gt;&lt;b&gt;ZeroMQ&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 나왔듯, ZeroMQ는 Socket의 Wrapper로 작동한다. [&lt;a href=&quot;https://www.educba.com/zeromq-vs-kafka/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ZeroMQ&amp;nbsp;vs&amp;nbsp;Kafka&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZYCvG/btsl9vxfiAz/BdIV8bNclB6KSqrIoAB27k/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZYCvG/btsl9vxfiAz/BdIV8bNclB6KSqrIoAB27k/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZYCvG/btsl9vxfiAz/BdIV8bNclB6KSqrIoAB27k/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZYCvG%2Fbtsl9vxfiAz%2FBdIV8bNclB6KSqrIoAB27k%2Fimg.webp&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;465&quot; height=&quot;380&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;380&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;6. I/O 멀티플렉싱&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;멀티플렉싱&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czzHU2/btrPbuRCAXG/p0D88yzqlWFSLVdQjNukI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czzHU2/btrPbuRCAXG/p0D88yzqlWFSLVdQjNukI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czzHU2/btrPbuRCAXG/p0D88yzqlWFSLVdQjNukI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczzHU2%2FbtrPbuRCAXG%2Fp0D88yzqlWFSLVdQjNukI0%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;1200&quot; height=&quot;516&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.techtarget.com/searchnetworking/definition/multiplexing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;multiplexing&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Multiplexing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;멀티플렉싱(Multiplexing, 다중화)&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;439&quot; data-origin-height=&quot;131&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1ZfOx/btrPbtE9kTz/MAwkXB0HBGK93hqsRYaK5K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1ZfOx/btrPbtE9kTz/MAwkXB0HBGK93hqsRYaK5K/img.gif&quot; data-alt=&quot;시분할&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1ZfOx/btrPbtE9kTz/MAwkXB0HBGK93hqsRYaK5K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/d1ZfOx/btrPbtE9kTz/MAwkXB0HBGK93hqsRYaK5K/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;439&quot; height=&quot;131&quot; data-origin-width=&quot;439&quot; data-origin-height=&quot;131&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; 컴퓨터 통신에서는 HTTP2.0이 대표적인 예.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1501&quot; data-origin-height=&quot;1614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cy5q5J/btrO91v3ngs/kh7BrTs1ExdSzH2ZoJaK40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cy5q5J/btrO91v3ngs/kh7BrTs1ExdSzH2ZoJaK40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cy5q5J/btrO91v3ngs/kh7BrTs1ExdSzH2ZoJaK40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcy5q5J%2FbtrO91v3ngs%2Fkh7BrTs1ExdSzH2ZoJaK40%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;1501&quot; height=&quot;1614&quot; data-origin-width=&quot;1501&quot; data-origin-height=&quot;1614&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.upwork.com/resources/what-is-http2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What&amp;nbsp;is&amp;nbsp;the&amp;nbsp;HTTP/2&amp;nbsp;Protocol?&amp;nbsp;Overview&amp;nbsp;and&amp;nbsp;Examples&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;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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 커넥션 생성시 비용은 멀티프로세스 &amp;gt; 멀티쓰레드 &amp;gt; 멀티플렉싱 순이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfx2aI/btrPbtrDjK8/wcvDgihkVeQdxZuItxWILk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfx2aI/btrPbtrDjK8/wcvDgihkVeQdxZuItxWILk/img.gif&quot; width=&quot;472&quot; height=&quot;459&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;678&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfx2aI/btrPbtrDjK8/wcvDgihkVeQdxZuItxWILk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcfx2aI%2FbtrPbtrDjK8%2FwcvDgihkVeQdxZuItxWILk%2Fimg.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;612&quot; height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1qaSq/btrO4pEomLl/ZnLzRdRxsDiKxb0odPZPkk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1qaSq/btrO4pEomLl/ZnLzRdRxsDiKxb0odPZPkk/img.gif&quot; width=&quot;472&quot; height=&quot;459&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;678&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1qaSq/btrO4pEomLl/ZnLzRdRxsDiKxb0odPZPkk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1qaSq%2FbtrO4pEomLl%2FZnLzRdRxsDiKxb0odPZPkk%2Fimg.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;612&quot; height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djEn9k/btrO6gAb7d2/7ocQGsYqBLj5KVCGHKhkG1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djEn9k/btrO6gAb7d2/7ocQGsYqBLj5KVCGHKhkG1/img.gif&quot; width=&quot;472&quot; height=&quot;459&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;678&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djEn9k/btrO6gAb7d2/7ocQGsYqBLj5KVCGHKhkG1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjEn9k%2FbtrO6gAb7d2%2F7ocQGsYqBLj5KVCGHKhkG1%2Fimg.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;612&quot; height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.usenix.org/legacy/publications/library/proceedings/osdi99/full_papers/banga/banga_html/node3.html&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;소켓&lt;/h4&gt;
&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;700&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bohGxb/btrO4pEo0h1/KFXKywdeUbBPkaMOrj6k30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bohGxb/btrO4pEo0h1/KFXKywdeUbBPkaMOrj6k30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bohGxb/btrO4pEo0h1/KFXKywdeUbBPkaMOrj6k30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbohGxb%2FbtrO4pEo0h1%2FKFXKywdeUbBPkaMOrj6k30%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;700&quot; height=&quot;240&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/swlh/getting-started-with-unix-domain-sockets-4472c0db4eb1&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;인터넷 접속 시 사용되는 네트워크 소켓과 프로세스간 IPC를 위한 유닉스 도메인 소켓으로 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doBgU5/btrO9BRhll3/dKcC4PeBzTkC7K9LvGCBx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doBgU5/btrO9BRhll3/dKcC4PeBzTkC7K9LvGCBx0/img.png&quot; width=&quot;700&quot; height=&quot;422&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;421&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.0999%; margin-right: 10px;&quot; data-widthpercent=&quot;48.67&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doBgU5/btrO9BRhll3/dKcC4PeBzTkC7K9LvGCBx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoBgU5%2FbtrO9BRhll3%2FdKcC4PeBzTkC7K9LvGCBx0%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;700&quot; height=&quot;421&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xGNzb/btrO9z089xT/kSoiBMbn02S9cf3bn8uUE0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xGNzb/btrO9z089xT/kSoiBMbn02S9cf3bn8uUE0/img.jpg&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;451&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;51.33&quot; style=&quot;width: 50.7374%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xGNzb/btrO9z089xT/kSoiBMbn02S9cf3bn8uUE0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxGNzb%2FbtrO9z089xT%2FkSoiBMbn02S9cf3bn8uUE0%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;791&quot; height=&quot;451&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inside.java/2021/02/03/jep380-unix-domain-sockets-channels/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JEP-380:&amp;nbsp;Unix&amp;nbsp;domain&amp;nbsp;socket&amp;nbsp;channels&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;서버와 클라이언트 소켓은 다음과 같은 생명주기를 가진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1047&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eep6Vd/btrPaI3UgYZ/I6FOJ8xFtXxULUKIZjXFgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eep6Vd/btrPaI3UgYZ/I6FOJ8xFtXxULUKIZjXFgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eep6Vd/btrPaI3UgYZ/I6FOJ8xFtXxULUKIZjXFgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feep6Vd%2FbtrPaI3UgYZ%2FI6FOJ8xFtXxULUKIZjXFgk%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;661&quot; height=&quot;962&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1047&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;유닉스는 파일과 소켓 조작을 동일하게 간주하며, fd(File Descriptor)로 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(윈도우는 소켓 API가 따로 존재)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EdsjK/btrO9DuNWwE/aDrfTHW5MeInDpDLtA02H1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EdsjK/btrO9DuNWwE/aDrfTHW5MeInDpDLtA02H1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EdsjK/btrO9DuNWwE/aDrfTHW5MeInDpDLtA02H1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/EdsjK/btrO9DuNWwE/aDrfTHW5MeInDpDLtA02H1/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;871&quot; height=&quot;448&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://users.cs.jmu.edu/bernstdh/web/common/lectures/summary_unix_file-descriptors.php&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;UNIX&amp;nbsp;File&amp;nbsp;Descriptors&amp;nbsp;An&amp;nbsp;Introduction&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;파일 디스크립터는 0(임력), 1(출력), 2(에러)로 정해져 있으므로 3번부터 실제 파일이 시작된다.&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;I/O 모델들&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.naver.com/n_cloudplatform/222189669084&quot;&gt;IO Multiplexing (IO 멀티플렉싱) 기본 개념부터 심화&lt;/a&gt;&lt;span&gt;까지와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://medium.com/@devAsterisk/i-o-model-1b3851f6a816&quot;&gt;I/O Model&lt;/a&gt;이라는 글이 잘 설명해주고 있다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7utIx/btrO9zUpR2J/u4NzYvj1aAmDOFOePo7cGK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7utIx/btrO9zUpR2J/u4NzYvj1aAmDOFOePo7cGK/img.gif&quot; data-lazy-src=&quot;&quot; data-width=&quot;550&quot; data-height=&quot;347&quot; data-origin-width=&quot;538&quot; data-origin-height=&quot;340&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.5439%; margin-right: 10px;&quot; data-widthpercent=&quot;53.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7utIx/btrO9zUpR2J/u4NzYvj1aAmDOFOePo7cGK/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7utIx%2FbtrO9zUpR2J%2Fu4NzYvj1aAmDOFOePo7cGK%2Fimg.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;538&quot; height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LOneg/btrPaIJAdtE/5PW4hsXNfByAGnXf8L9uvk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LOneg/btrPaIJAdtE/5PW4hsXNfByAGnXf8L9uvk/img.gif&quot; data-lazy-src=&quot;&quot; data-width=&quot;550&quot; data-height=&quot;394&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;340&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.2933%;&quot; data-widthpercent=&quot;46.84&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LOneg/btrPaIJAdtE/5PW4hsXNfByAGnXf8L9uvk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLOneg%2FbtrPaIJAdtE%2F5PW4hsXNfByAGnXf8L9uvk%2Fimg.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;474&quot; height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qpyD5/btrPbbxKad1/3b0BAuiP66c0KtPQhhee11/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qpyD5/btrPbbxKad1/3b0BAuiP66c0KtPQhhee11/img.gif&quot; width=&quot;541&quot; height=&quot;340&quot; data-origin-width=&quot;541&quot; data-origin-height=&quot;340&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.3199%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;52.94&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qpyD5/btrPbbxKad1/3b0BAuiP66c0KtPQhhee11/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqpyD5%2FbtrPbbxKad1%2F3b0BAuiP66c0KtPQhhee11%2Fimg.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;541&quot; height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4S13Q/btrTFWCZyO0/aKdmrzGteeS1PQXidTwkJk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4S13Q/btrTFWCZyO0/aKdmrzGteeS1PQXidTwkJk/img.gif&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;340&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.5173%; margin-top: 10px;&quot; data-widthpercent=&quot;47.06&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4S13Q/btrTFWCZyO0/aKdmrzGteeS1PQXidTwkJk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4S13Q%2FbtrTFWCZyO0%2FaKdmrzGteeS1PQXidTwkJk%2Fimg.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;481&quot; height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;동기-블럭킹 / 동기-논블럭킹 / 비동기-블럭킹 / 비동기-논블럭킹&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널이 메세지를 반환해야지만 처리할 수 있는 동기 블럭킹&amp;nbsp; I/O&lt;/li&gt;
&lt;li&gt;system call을 통해 반복적으로 확인(폴링)해야해 컨텍스트 스위칭 오버헤드가 있는 동기 논블럭킹 I/O&lt;/li&gt;
&lt;li&gt;한번에 많은 fd를 처리할 수 있지만 select와 read로 두번의 시스템 콜이 발생하고 비동기 블럭킹 I/O&lt;/li&gt;
&lt;li&gt;결과를 마치 이벤트처럼 전달받을 수 있는 비동기 논블럭킹 I/O&lt;br /&gt;그러나 리눅스에서는 동기 I/O가 충분히 빠르고 &lt;a href=&quot;https://cor3ntin.github.io/posts/iouring/&quot;&gt;AIO시 지연&lt;/a&gt; 때문에 Epoll을 주로 사용&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;select가 대표적인 멀티플렉싱 I/O 모델로 3번째인 비동기 블럭킹 I/O다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체크할 파일 디스크립터 목록을 배열로 만들어놓고, &lt;span&gt;select에서 반환되면&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;1390&quot; data-origin-height=&quot;459&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D8P0n/btrO9PW0Jxy/z7IOZgkVt0ZS9beAklHLNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D8P0n/btrO9PW0Jxy/z7IOZgkVt0ZS9beAklHLNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D8P0n/btrO9PW0Jxy/z7IOZgkVt0ZS9beAklHLNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD8P0n%2FbtrO9PW0Jxy%2Fz7IOZgkVt0ZS9beAklHLNk%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;1390&quot; height=&quot;459&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;459&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jongmin92.github.io/2019/02/28/Java/java-with-non-blocking-io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;멀티플렉싱&amp;nbsp;기반의&amp;nbsp;다중&amp;nbsp;접속&amp;nbsp;서버로&amp;nbsp;가기까지&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;Epoll(리눅스), Kqueue(BSD), IOCP(Windows)가 더 발전된 방법이다.&lt;/p&gt;
&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://en.wikipedia.org/wiki/Epoll&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Epoll&lt;/a&gt;은 유저 스페이스 단이 아닌 커널 단에서 멀티플렉싱을 지원하고 변경된 목록을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 상태가 변경되었는지 매번 디스크립터 목록을 순회할 필요가 없으며, 커널에서 상태 정보를 유지하므로 관찰할 파일의 정보를 매번 전달할 필요가 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvHMIW/btrO9Ppa2kW/KjP5Rf2GY9pfOBfSfLGr3K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvHMIW/btrO9Ppa2kW/KjP5Rf2GY9pfOBfSfLGr3K/img.jpg&quot; width=&quot;700&quot; height=&quot;525&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;524&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4355%; margin-right: 10px;&quot; data-widthpercent=&quot;50.02&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvHMIW/btrO9Ppa2kW/KjP5Rf2GY9pfOBfSfLGr3K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvHMIW%2FbtrO9Ppa2kW%2FKjP5Rf2GY9pfOBfSfLGr3K%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;700&quot; height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfxQYp/btrO9kb707R/mdhiYmx5BrBzqAKfjFxAi0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfxQYp/btrO9kb707R/mdhiYmx5BrBzqAKfjFxAi0/img.jpg&quot; width=&quot;546&quot; height=&quot;409&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;409&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4017%;&quot; data-widthpercent=&quot;49.98&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfxQYp/btrO9kb707R/mdhiYmx5BrBzqAKfjFxAi0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfxQYp%2FbtrO9kb707R%2FmdhiYmx5BrBzqAKfjFxAi0%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;546&quot; height=&quot;409&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://copyconstruct.medium.com/the-method-to-epolls-madness-d9d2d6378642&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;method&amp;nbsp;to&amp;nbsp;epoll&amp;rsquo;s&amp;nbsp;madness&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;a href=&quot;https://en.wikipedia.org/wiki/Kqueue&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kqueue&lt;/a&gt;는 FreeBSD에서 사용되며 kevent를 담은 kqueue를 사용한다. [&lt;a href=&quot;https://people.freebsd.org/~jlemon/papers/kqueue.pdf&quot;&gt;Kqueue: A generic and scalable event notification facility&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.zhaolongli.com/2019/03/01/kqueue-and-FSEvents.html&quot;&gt;kqueue和FSEvents&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=3028687&quot;&gt;HN&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://long-zhou.github.io/2012/12/21/epoll-vs-kqueue.html&quot;&gt;Scalable&amp;nbsp;Event&amp;nbsp;Multiplexing:&amp;nbsp;epoll&amp;nbsp;vs.&amp;nbsp;kqueue&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Epoll과 비교하자면 소켓과 파이프I/O만 지원하는 Epoll과 달리 signal, timer등 다양한 타입들을 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 kevent()는 단일 시스템 콜로 여러개의 업데이트를 한번에 수행할 수 있다.(Epoll은 매번 epoll_ctl()을 사용해야 함)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cf2tRR/btrPddomw73/wL18oGMJKjttg6y8vzWag0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cf2tRR/btrPddomw73/wL18oGMJKjttg6y8vzWag0/img.png&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;494&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.73%; margin-right: 10px;&quot; data-widthpercent=&quot;46.27&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cf2tRR/btrPddomw73/wL18oGMJKjttg6y8vzWag0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcf2tRR%2FbtrPddomw73%2FwL18oGMJKjttg6y8vzWag0%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;915&quot; height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YPFVI/btrO9kwq4lr/NTkzFMRt4pVKtjkzc6zyw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YPFVI/btrO9kwq4lr/NTkzFMRt4pVKtjkzc6zyw0/img.png&quot; data-origin-width=&quot;1880&quot; data-origin-height=&quot;874&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.1072%;&quot; data-widthpercent=&quot;53.73&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YPFVI/btrO9kwq4lr/NTkzFMRt4pVKtjkzc6zyw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYPFVI%2FbtrO9kwq4lr%2FNTkzFMRt4pVKtjkzc6zyw0%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;1880&quot; height=&quot;874&quot;/&gt;&lt;/span&gt;&lt;/div&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://learn.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports?redirectedfrom=MSDN&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; IOCP(I/O Completion Ports)&lt;/a&gt;는 멀티쓰레드로 동작하며 4번 비동기-논블럭킹 모델이다. [&lt;a href=&quot;https://www.slideshare.net/namhyeonuk90/iocp&quot;&gt;Iocp 기본 구조 이해&lt;/a&gt;, &lt;a href=&quot;https://www.slideshare.net/sm9kr/iocp-vs-epoll-perfor&quot;&gt;Windows IOCP vs Linux EPOLL Performance Comparison&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.slideshare.net/sm9kr/windows-registered-io-rio&quot;&gt;Windows Registered I/O (RIO) vs IOCP&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4VzmL/btrO9Qn8Utd/KmoWVMzdYS5DqEe8yDksk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4VzmL/btrO9Qn8Utd/KmoWVMzdYS5DqEe8yDksk1/img.png&quot; data-alt=&quot;IOCP&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4VzmL/btrO9Qn8Utd/KmoWVMzdYS5DqEe8yDksk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4VzmL%2FbtrO9Qn8Utd%2FKmoWVMzdYS5DqEe8yDksk1%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;832&quot; height=&quot;624&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;624&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;IOCP&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우 RIO(Registered I/O)는 한번 더 나아가, 고정 크기의 버퍼를 등록해 컨텍스트 스위칭을 낮출 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 코딩은 어려워짐을 감안해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnl2AZ/btsl5ikTMaI/r90KN2voql9kR3AMadTJU1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnl2AZ/btsl5ikTMaI/r90KN2voql9kR3AMadTJU1/img.webp&quot; width=&quot;1282&quot; height=&quot;962&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnl2AZ/btsl5ikTMaI/r90KN2voql9kR3AMadTJU1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbnl2AZ%2Fbtsl5ikTMaI%2Fr90KN2voql9kR3AMadTJU1%2Fimg.webp&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;1280&quot; height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnBRFe/btsl3iem782/YIRzDTkibi5LA67ozG0Bak/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnBRFe/btsl3iem782/YIRzDTkibi5LA67ozG0Bak/img.webp&quot; width=&quot;1282&quot; height=&quot;962&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnBRFe/btsl3iem782/YIRzDTkibi5LA67ozG0Bak/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnBRFe%2Fbtsl3iem782%2FYIRzDTkibi5LA67ozG0Bak%2Fimg.webp&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;1280&quot; height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/div&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;h3 data-ke-size=&quot;size23&quot;&gt;7. 링버퍼, 최신 I/O 모델, LMAX Distruptor&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;링버퍼&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Circular_buffer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링버퍼&lt;/a&gt;는 성능 저하없이 배열을 dequeue처럼 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDwcgz/btrO8zffgtZ/nbROWEyaHEs6CmF3kzJAC0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDwcgz/btrO8zffgtZ/nbROWEyaHEs6CmF3kzJAC0/img.gif&quot; data-alt=&quot;링버퍼&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDwcgz/btrO8zffgtZ/nbROWEyaHEs6CmF3kzJAC0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bDwcgz/btrO8zffgtZ/nbROWEyaHEs6CmF3kzJAC0/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;800&quot; height=&quot;600&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;링버퍼&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;최신 I/O 모델&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스(io_uring)와 윈도우(IoRing) 모두 차세대 I/O모델로 택하고 있다. [&lt;a href=&quot;https://windows-internals.com/ioring-vs-io_uring-a-comparison-of-windows-and-linux-implementations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IoRing&amp;nbsp;vs.&amp;nbsp;io_uring:&amp;nbsp;a&amp;nbsp;comparison&amp;nbsp;of&amp;nbsp;Windows&amp;nbsp;and&amp;nbsp;Linux&amp;nbsp;implementations&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IYYlb/btrPbuqCooH/YhWrkksl5IfHpabKZaFzBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IYYlb/btrPbuqCooH/YhWrkksl5IfHpabKZaFzBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IYYlb/btrPbuqCooH/YhWrkksl5IfHpabKZaFzBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIYYlb%2FbtrPbuqCooH%2FYhWrkksl5IfHpabKZaFzBK%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;610&quot; height=&quot;272&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developers.mattermost.com/blog/hands-on-iouring-go/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;Getting&amp;nbsp;Hands&amp;nbsp;on&amp;nbsp;with&amp;nbsp;io_uring&amp;nbsp;using&amp;nbsp;Go&amp;nbsp;&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;SQ(submission queue) 버퍼에는 유저 스페이스에서만 쓰기가 가능하고, CQ(completion queue)에서는 커널 스페이스에서만 쓰기가 가능하다.&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;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfkd9R/btrO9lPGSN3/oX6oXkhKjPYcP4brM9W9e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfkd9R/btrO9lPGSN3/oX6oXkhKjPYcP4brM9W9e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfkd9R/btrO9lPGSN3/oX6oXkhKjPYcP4brM9W9e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbfkd9R%2FbtrO9lPGSN3%2FoX6oXkhKjPYcP4brM9W9e1%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;700&quot; height=&quot;352&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/nttlabs/rust-async-with-io-uring-db3fa2642dd4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ソケットAPIが遅すぎる？新たなio_uringを試す！&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;525&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MwosP/btrO8yOc14z/f4qy2NMCBlXSKyCI61cYak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MwosP/btrO8yOc14z/f4qy2NMCBlXSKyCI61cYak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MwosP/btrO8yOc14z/f4qy2NMCBlXSKyCI61cYak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMwosP%2FbtrO8yOc14z%2Ff4qy2NMCBlXSKyCI61cYak%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;1280&quot; height=&quot;525&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.cloudflare.com/missing-manuals-io_uring-worker-pool/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Missing&amp;nbsp;Manuals&amp;nbsp;-&amp;nbsp;io_uring&amp;nbsp;worker&amp;nbsp;pool&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;h4 data-ke-size=&quot;size20&quot;&gt;LMAX Disruptor&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://lmax-exchange.github.io/disruptor/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LMAX Disruptor&lt;/a&gt;는 데이터를 전달 시 큐를 이용할때 지연시간을 줄이기 위해서 만들어졌다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxOO8o/btrPd13ETEo/3xSYUskd6NBJaK022TMYsK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxOO8o/btrPd13ETEo/3xSYUskd6NBJaK022TMYsK/img.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxOO8o/btrPd13ETEo/3xSYUskd6NBJaK022TMYsK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxOO8o%2FbtrPd13ETEo%2F3xSYUskd6NBJaK022TMYsK%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;1024&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rwwJF/btrPehrVI9Z/pnGkS1P3ls7Pt9mJOzQY80/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rwwJF/btrPehrVI9Z/pnGkS1P3ls7Pt9mJOzQY80/img.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rwwJF/btrPehrVI9Z/pnGkS1P3ls7Pt9mJOzQY80/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrwwJF%2FbtrPehrVI9Z%2FpnGkS1P3ls7Pt9mJOzQY80%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;1024&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/div&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;전반적인 아이디어는 IO Uring과 일치한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNyLtO/btrPcdi2PqL/ZgynrDpqfuKLXbbGY6voWk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNyLtO/btrPcdi2PqL/ZgynrDpqfuKLXbbGY6voWk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNyLtO/btrPcdi2PqL/ZgynrDpqfuKLXbbGY6voWk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNyLtO%2FbtrPcdi2PqL%2FZgynrDpqfuKLXbbGY6voWk%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nh5Kd/btrPezeARzL/cDqKAeoRCEGFC3GlWx1Ld1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nh5Kd/btrPezeARzL/cDqKAeoRCEGFC3GlWx1Ld1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nh5Kd/btrPezeARzL/cDqKAeoRCEGFC3GlWx1Ld1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnh5Kd%2FbtrPezeARzL%2FcDqKAeoRCEGFC3GlWx1Ld1%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&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;각 필드는 캐시라인을 고려해 64byte, 링버퍼의 크기는 2의 n 제곱, 배치 프로세싱등의 세부적인 최적화 사항이 있지만 더 자세한 내용들은 다음을 참고해보기 바란다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.slideshare.net/Stephan.Schmidt/lmax-architecture-jax-conference&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;LMAX Architecture(프리젠테이션)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinfowler.com/articles/lmax.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The LMAX Architecture(마틴 파울러 블로그)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.slideshare.net/trishagee/introduction-to-the-disruptor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;Introduction to the Disruptor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lmax-exchange.github.io/disruptor/disruptor.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LMAX&amp;nbsp;Disruptor:&amp;nbsp;High&amp;nbsp;performance&amp;nbsp;alternative&amp;nbsp;to&amp;nbsp;bounded&amp;nbsp;queues&amp;nbsp;for&amp;nbsp;exchanging&amp;nbsp;data&amp;nbsp;between&amp;nbsp;concurrent&amp;nbsp;threads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. 동기화 프리미티브&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;필요성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰레드가 공유 변수에 접근하게 되면 경쟁조건(Race Condition)이 생기게 된다. [바로 위의 링버퍼를 사용하면 효율적으로 접근을 할 수가 있었다.]&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;1037&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b23cBU/btrPfm1XAK9/U7Xc21F8I4tVMI752mmmaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b23cBU/btrPfm1XAK9/U7Xc21F8I4tVMI752mmmaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b23cBU/btrPfm1XAK9/U7Xc21F8I4tVMI752mmmaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb23cBU%2FbtrPfm1XAK9%2FU7Xc21F8I4tVMI752mmmaK%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;1037&quot; height=&quot;551&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cloudxlab.com/blog/race-condition-and-deadlock/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;Race&amp;nbsp;Condition&amp;nbsp;and&amp;nbsp;Deadlock&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;b&gt;막는것&lt;/b&gt;(잠금, Lock)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 다음과 같이 임계구역(Critical section)을 설정해 쓰레드간 동기화를 할 수있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhaclC/btrPfXUZ7Dy/xAdwfrZ8GaA7ZF0sSRLqBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhaclC/btrPfXUZ7Dy/xAdwfrZ8GaA7ZF0sSRLqBk/img.png&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;438&quot; data-is-animation=&quot;false&quot; style=&quot;width: 31.7128%; margin-right: 10px;&quot; data-widthpercent=&quot;32.09&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhaclC/btrPfXUZ7Dy/xAdwfrZ8GaA7ZF0sSRLqBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhaclC%2FbtrPfXUZ7Dy%2FxAdwfrZ8GaA7ZF0sSRLqBk%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;252&quot; height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oZECJ/btrPfW9zvuJ/4j9o5cISLzaVFrImryXaxk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oZECJ/btrPfW9zvuJ/4j9o5cISLzaVFrImryXaxk/img.gif&quot; width=&quot;252&quot; height=&quot;438&quot; data-origin-width=&quot;397&quot; data-origin-height=&quot;326&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;67.91&quot; style=&quot;width: 67.1244%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oZECJ/btrPfW9zvuJ/4j9o5cISLzaVFrImryXaxk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoZECJ%2FbtrPfW9zvuJ%2F4j9o5cISLzaVFrImryXaxk%2Fimg.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;397&quot; height=&quot;326&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.gatevidyalay.com/critical-section-critical-section-problem/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Critical Section | Critical Section Problem&lt;/a&gt;, &lt;a href=&quot;https://blog.naver.com/earthenware/130110491945&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mutex&amp;nbsp;lock과&amp;nbsp;condition을&amp;nbsp;사용한&amp;nbsp;생산자&amp;nbsp;소비자&amp;nbsp;문제의&amp;nbsp;구현&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;그러나 락을 잘못 사용하게되면 서로가 서로를 기다리는 교착상태(Deadlock)이 생길 수도 있으니 조심해야한다. [&lt;a href=&quot;https://www.baeldung.com/cs/deadlock-livelock-starvation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Deadlock,&amp;nbsp;Livelock&amp;nbsp;and&amp;nbsp;Starvation&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 서로 넘겨주느라 일을 못하는 Livelock 상태도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1140&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zTNaz/btrPfNLZIuA/ARQnV5QOIc9Ov7s7UNKk6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zTNaz/btrPfNLZIuA/ARQnV5QOIc9Ov7s7UNKk6k/img.png&quot; data-alt=&quot;데드락&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zTNaz/btrPfNLZIuA/ARQnV5QOIc9Ov7s7UNKk6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzTNaz%2FbtrPfNLZIuA%2FARQnV5QOIc9Ov7s7UNKk6k%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;1140&quot; height=&quot;688&quot; data-origin-width=&quot;1140&quot; data-origin-height=&quot;688&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;h4 data-ke-size=&quot;size20&quot;&gt;스레드 안전&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 스레드가 동시 실행될 때 코드가 올바르게 작동하면 &lt;a href=&quot;https://en.wikipedia.org/wiki/Thread_safety&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스레드 안전(Thread safe)&lt;/a&gt;하다고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;&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;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;공유상태를 피할 수 없다면 다음과 같은 방법을 사용할 수 있다.&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;/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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 장벽(Memory Barriers)은 임계구역의 일종으로 메모리의 작업이 올바른 순서대로 일어나도록 보장한다. [&lt;a href=&quot;https://afana.me/archive/2015/07/10/memory-barriers-in-dot-net.aspx/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Memory&amp;nbsp;Barriers&amp;nbsp;in&amp;nbsp;.NET&lt;/a&gt;, &lt;a href=&quot;https://lwn.net/Articles/573436/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;User-space&amp;nbsp;RCU:&amp;nbsp;Memory-barrier&amp;nbsp;menagerie&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjIjnz/btrTYDwmXvB/2MZBUdMCkFxRFetOlPsOaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjIjnz/btrTYDwmXvB/2MZBUdMCkFxRFetOlPsOaK/img.png&quot; data-alt=&quot;메모리 장벽&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjIjnz/btrTYDwmXvB/2MZBUdMCkFxRFetOlPsOaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjIjnz%2FbtrTYDwmXvB%2F2MZBUdMCkFxRFetOlPsOaK%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;350&quot; height=&quot;357&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;357&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&gt;앞서 나온&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Future/Promise&lt;/b&gt;&lt;span&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;예를 들어 메세지 전달의 채널 방식은 값을 복사하거나 옮겨 스레드 지역 저장소의 방식의 일종이다.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스핀락(Spin lock)은 가장 간단한 동기화 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lock 상태에 접근하면 Lock이 풀릴 때까지 반복적으로 뺑뺑이돌며(Spin) 확인하다가 풀리면 접근하는 방식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhIv3L/btrPgfnzGR0/mIsCpKfskeRDLbn2ZRUWYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhIv3L/btrPgfnzGR0/mIsCpKfskeRDLbn2ZRUWYk/img.png&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;180&quot; data-is-animation=&quot;false&quot; style=&quot;width: 39.8441%; margin-right: 10px;&quot; data-widthpercent=&quot;40.31&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhIv3L/btrPgfnzGR0/mIsCpKfskeRDLbn2ZRUWYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhIv3L%2FbtrPgfnzGR0%2FmIsCpKfskeRDLbn2ZRUWYk%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;300&quot; height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbQa79/btrPjkOOCSp/dKvS0JCOUyUKiCnjkE4Jqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbQa79/btrPjkOOCSp/dKvS0JCOUyUKiCnjkE4Jqk/img.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;201&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;59.69&quot; style=&quot;width: 58.9931%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbQa79/btrPjkOOCSp/dKvS0JCOUyUKiCnjkE4Jqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbQa79%2FbtrPjkOOCSp%2FdKvS0JCOUyUKiCnjkE4Jqk%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;496&quot; height=&quot;201&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://techaccess.in/2021/05/16/spinlock/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;spinlock&lt;/a&gt;, &lt;a href=&quot;https://medium.com/geekculture/the-linux-kernel-locking-api-and-shared-objects-1169c2ae88ff&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Linux&amp;nbsp;Kernel&amp;nbsp;Locking&amp;nbsp;API&amp;nbsp;and&amp;nbsp;Shared&amp;nbsp;Objects&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;뮤텍스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뮤텍스(Mutex)는 운영체제를 통해 락을 걸어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 락이 풀릴 때까지 계속 확인하는게 아닌 대기하는 상태가 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWp11r/btrPfW2RO1T/PY0BGYMzphd95ULlOsBYQ0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWp11r/btrPfW2RO1T/PY0BGYMzphd95ULlOsBYQ0/img.jpg&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;298&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;39.92&quot; style=&quot;width: 39.4601%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWp11r/btrPfW2RO1T/PY0BGYMzphd95ULlOsBYQ0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWp11r%2FbtrPfW2RO1T%2FPY0BGYMzphd95ULlOsBYQ0%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;458&quot; height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFongT/btrPfYzCPSK/c3nei33Nq2zUry1vtjBgTK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFongT/btrPfYzCPSK/c3nei33Nq2zUry1vtjBgTK/img.jpg&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;403&quot; data-is-animation=&quot;false&quot; style=&quot;width: 59.3772%;&quot; data-widthpercent=&quot;60.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFongT/btrPfYzCPSK/c3nei33Nq2zUry1vtjBgTK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFongT%2FbtrPfYzCPSK%2Fc3nei33Nq2zUry1vtjBgTK%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;932&quot; height=&quot;403&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://open4tech.com/rtos-mutex-and-semaphore-basics/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RTOS:&amp;nbsp;Mutex&amp;nbsp;and&amp;nbsp;Semaphore&amp;nbsp;Basics&lt;/a&gt;, &lt;a href=&quot;https://www.geeksforgeeks.org/mutex-lock-for-linux-thread-synchronization/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mutex&amp;nbsp;lock&amp;nbsp;for&amp;nbsp;Linux&amp;nbsp;Thread&amp;nbsp;Synchronization&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;세마포어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세마포어(Semaphore)는 배열처럼 여러 값에 접근할 때 사용한다.&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;691&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buT4bd/btrPgLUb0iP/IeLAcfGFSxnBYcdPdhX2s1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buT4bd/btrPgLUb0iP/IeLAcfGFSxnBYcdPdhX2s1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buT4bd/btrPgLUb0iP/IeLAcfGFSxnBYcdPdhX2s1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuT4bd%2FbtrPgLUb0iP%2FIeLAcfGFSxnBYcdPdhX2s1%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;691&quot; height=&quot;342&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;342&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdqJ7A/btrPfDoZTam/I9Igu3QIsrnzAzWHpJwST0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdqJ7A/btrPfDoZTam/I9Igu3QIsrnzAzWHpJwST0/img.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;164&quot; data-is-animation=&quot;false&quot; style=&quot;width: 61.0465%; margin-right: 10px;&quot; data-widthpercent=&quot;61.76&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdqJ7A/btrPfDoZTam/I9Igu3QIsrnzAzWHpJwST0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdqJ7A%2FbtrPfDoZTam%2FI9Igu3QIsrnzAzWHpJwST0%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;600&quot; height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wswu9/btrPk90sTB0/rk63Njl8ygZ0RK5kSmNri0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wswu9/btrPk90sTB0/rk63Njl8ygZ0RK5kSmNri0/img.png&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;287&quot; data-is-animation=&quot;false&quot; style=&quot;width: 37.7907%;&quot; data-widthpercent=&quot;38.24&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wswu9/btrPk90sTB0/rk63Njl8ygZ0RK5kSmNri0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwswu9%2FbtrPk90sTB0%2Frk63Njl8ygZ0RK5kSmNri0%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;650&quot; height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crrjkm/btrPgCCPaR6/3aKWHSVTY7RkoYPV4iWBd1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crrjkm/btrPgCCPaR6/3aKWHSVTY7RkoYPV4iWBd1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crrjkm/btrPgCCPaR6/3aKWHSVTY7RkoYPV4iWBd1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcrrjkm%2FbtrPgCCPaR6%2F3aKWHSVTY7RkoYPV4iWBd1%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;500&quot; height=&quot;310&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.javatpoint.com/mutex-vs-semaphore&quot;&gt;Mutex vs Semaphore&lt;/a&gt;, &lt;a href=&quot;https://scrutinybykhimaanshu.blogspot.com/2019/08/all-about-java-semaphore.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Java&amp;nbsp;Thread&amp;nbsp;Interview&amp;nbsp;Questions&amp;nbsp;&amp;amp;&amp;nbsp;Answers&amp;nbsp;(All&amp;nbsp;About&amp;nbsp;Java&amp;nbsp;Semaphore&amp;nbsp;and&amp;nbsp;Mutex)&lt;/a&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;STM&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠금/잠금해제 작업이 상당히 머리 아프기에 변수가 알아서(?) 관리해주면 좋겠다고 생각한적이 있다면, 그 답은 소프트웨어 트랜잭션 메모리(STM, Software Transaction Memory)다.&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;바로 DB에서 사용하는 방법이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;583&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cejAim/btrPhojUW2p/Wr6Qk9RmqO5zu1hGYyiIw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cejAim/btrPhojUW2p/Wr6Qk9RmqO5zu1hGYyiIw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cejAim/btrPhojUW2p/Wr6Qk9RmqO5zu1hGYyiIw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcejAim%2FbtrPhojUW2p%2FWr6Qk9RmqO5zu1hGYyiIw0%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;583&quot; height=&quot;239&quot; data-origin-width=&quot;583&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cstaleem.com/transaction-states&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Transaction&amp;nbsp;States&amp;nbsp;in&amp;nbsp;DBMS&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vA45a/btrPiuD245E/MUqkqVmXbmqgn1rScRRDGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vA45a/btrPiuD245E/MUqkqVmXbmqgn1rScRRDGk/img.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;720&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.4786%; margin-right: 10px;&quot; data-widthpercent=&quot;49.05&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vA45a/btrPiuD245E/MUqkqVmXbmqgn1rScRRDGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvA45a%2FbtrPiuD245E%2FMUqkqVmXbmqgn1rScRRDGk%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;960&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5TS67/btrPfEBrtBF/kJTJpTM5UGtMibAkkDiFqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5TS67/btrPfEBrtBF/kJTJpTM5UGtMibAkkDiFqk/img.png&quot; data-selenium-selector=&quot;figure-image&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;722&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.3586%;&quot; data-widthpercent=&quot;50.95&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5TS67/btrPfEBrtBF/kJTJpTM5UGtMibAkkDiFqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5TS67%2FbtrPfEBrtBF%2FkJTJpTM5UGtMibAkkDiFqk%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;1000&quot; height=&quot;722&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sw1nn.com/blog/2012/04/11/clojure-stm-what-why-how/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Clojure STM - What? Why? How?&lt;/a&gt;, &lt;a href=&quot;https://www.semanticscholar.org/paper/A-Qualitative-Survey-of-Modern-Software-Memory-Marathe-Scott/8ecb601968457196f4f454284e1c1547481747bb/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Qualitative&amp;nbsp;Survey&amp;nbsp;of&amp;nbsp;Modern&amp;nbsp;Software&amp;nbsp;Transactional&amp;nbsp;Memory&amp;nbsp;Systems&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjlEPT/btrPgf2aSEV/VAQGngwWnWkXPFhiFGkBe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjlEPT/btrPgf2aSEV/VAQGngwWnWkXPFhiFGkBe1/img.png&quot; data-selenium-selector=&quot;figure-image&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;390&quot; data-is-animation=&quot;false&quot; style=&quot;width: 54.2592%; margin-right: 10px;&quot; data-widthpercent=&quot;54.9&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjlEPT/btrPgf2aSEV/VAQGngwWnWkXPFhiFGkBe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjlEPT%2FbtrPgf2aSEV%2FVAQGngwWnWkXPFhiFGkBe1%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;814&quot; height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqNyS9/btrPk9GaZQ9/f6N9ydnVUkWU8JunRDPPT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqNyS9/btrPk9GaZQ9/f6N9ydnVUkWU8JunRDPPT1/img.png&quot; data-selenium-selector=&quot;figure-image&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;582&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;45.1&quot; style=&quot;width: 44.578%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqNyS9/btrPk9GaZQ9/f6N9ydnVUkWU8JunRDPPT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqNyS9%2FbtrPk9GaZQ9%2Ff6N9ydnVUkWU8JunRDPPT1%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;998&quot; height=&quot;582&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.semanticscholar.org/paper/Software-Transactional-Memory-Should-Not-Be-Ennals/1a16975d1630756772b7d16e220236fe9a2830d3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Software&amp;nbsp;Transactional&amp;nbsp;Memory&amp;nbsp;Should&amp;nbsp;Not&amp;nbsp;Be&amp;nbsp;Obstruction-Free&lt;/a&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;GIL&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;까다로운 동기화 문제 때문에 파이썬의 경우 GIL(Global Interpreter Lock, 전역 인터프리터 잠금)로 해결을 한다.&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;각설하고 파이썬이 GIL을 사용하게 된 계기를 알아보자.&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;&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yuyzE/btrPgqJToXw/kNA1SrnN8zs5xXogprX7CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yuyzE/btrPgqJToXw/kNA1SrnN8zs5xXogprX7CK/img.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;720&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yuyzE/btrPgqJToXw/kNA1SrnN8zs5xXogprX7CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyuyzE%2FbtrPgqJToXw%2FkNA1SrnN8zs5xXogprX7CK%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;960&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI4ms9/btrPk9NgbXu/b0AE3N0LDrrrLx8w1cu9kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI4ms9/btrPk9NgbXu/b0AE3N0LDrrrLx8w1cu9kK/img.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;720&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI4ms9/btrPk9NgbXu/b0AE3N0LDrrrLx8w1cu9kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI4ms9%2FbtrPk9NgbXu%2Fb0AE3N0LDrrrLx8w1cu9kK%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;960&quot; height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.fulcircle.io/posts/the-python-gil/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Python&amp;nbsp;Global&amp;nbsp;Interpreter&amp;nbsp;Lock&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;981&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X3MBv/btrPivDgwbj/ZBJWYS0U9pApI6VCvvx321/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X3MBv/btrPivDgwbj/ZBJWYS0U9pApI6VCvvx321/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X3MBv/btrPivDgwbj/ZBJWYS0U9pApI6VCvvx321/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX3MBv%2FbtrPivDgwbj%2FZBJWYS0U9pApI6VCvvx321%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;981&quot; height=&quot;349&quot; data-origin-width=&quot;981&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.datacamp.com/tutorial/python-global-interpreter-lock&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Python&amp;nbsp;Global&amp;nbsp;Interpreter&amp;nbsp;Lock&amp;nbsp;Tutorial&amp;nbsp;Python&amp;nbsp;Global&amp;nbsp;Interpreter&amp;nbsp;Lock&amp;nbsp;Tutorial&amp;nbsp;&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;쓰레드를 코루틴처럼 만들어 버리다니 I/O에서는 괜찮을 수 있겠지만 CPU 바운드 작업에서는 상당한 문제가 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때문에 파이썬은 C라이브러리들과의 바인딩을 통해 해결하며, 다음 챕터에서 다른 스크립트 언어의 접근법을, 그 다음 챕터에서 더 나은 모델을 알아보자.&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;9. 다른 스크립트 언어의 접근법과&amp;nbsp; Reactor/Proactor 패턴&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Ractor (루비)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루비에는 한때 Guild라고 불렸던 Ractor가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루비에 있던 GIL에서 벗어나면서도 호환성이 있는 동작을 목표로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길드는 파이버를 하나 이상 가진 쓰레드로 구성되며, 한 길드에서는 GGL(Giant Guild Lock)로 다른 쓰레드가 실행될 수 없게 보장된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9XYAG/btrPlHQJRdY/4MwZuwn4KKI8y57JK7LeN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9XYAG/btrPlHQJRdY/4MwZuwn4KKI8y57JK7LeN0/img.png&quot; style=&quot;width: 44.8744%; margin-right: 10px;&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;285&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;45.4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9XYAG/btrPlHQJRdY/4MwZuwn4KKI8y57JK7LeN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9XYAG%2FbtrPlHQJRdY%2F4MwZuwn4KKI8y57JK7LeN0%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;675&quot; height=&quot;285&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lQZip/btrPgLAk94T/ViSQYsbKGjdIIkt0hkvZD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lQZip/btrPgLAk94T/ViSQYsbKGjdIIkt0hkvZD0/img.png&quot; style=&quot;width: 53.9628%;&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;237&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;54.6&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lQZip/btrPgLAk94T/ViSQYsbKGjdIIkt0hkvZD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlQZip%2FbtrPgLAk94T%2FViSQYsbKGjdIIkt0hkvZD0%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;675&quot; height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://olivierlacan.com/posts/concurrency-in-ruby-3-with-guilds/&quot;&gt;Concurrency&amp;nbsp;in&amp;nbsp;Ruby&amp;nbsp;3&amp;nbsp;with&amp;nbsp;Guilds&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKcDtB/btrPfYz3AvL/75ppoIB8Q50TFuWud65dyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKcDtB/btrPfYz3AvL/75ppoIB8Q50TFuWud65dyK/img.png&quot; style=&quot;width: 50.1932%; margin-right: 10px;&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;314&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50.78&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKcDtB/btrPfYz3AvL/75ppoIB8Q50TFuWud65dyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKcDtB%2FbtrPfYz3AvL%2F75ppoIB8Q50TFuWud65dyK%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;675&quot; height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mq8hd/btrPlGqMG8r/TXuUzQ3XfxZlPCkQBfkOo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mq8hd/btrPlGqMG8r/TXuUzQ3XfxZlPCkQBfkOo1/img.png&quot; style=&quot;width: 48.644%;&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;324&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.22&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mq8hd/btrPlGqMG8r/TXuUzQ3XfxZlPCkQBfkOo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMq8hd%2FbtrPlGqMG8r%2FTXuUzQ3XfxZlPCkQBfkOo1%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;675&quot; height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ractor에 관심이 있다면 다음 글들도 읽어보기를 바란다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.atdot.net/~ko1/activities/2016_rubykaigi.pdf&quot;&gt;A&amp;nbsp;proposal&amp;nbsp;of&amp;nbsp;new&amp;nbsp;concurrency&amp;nbsp;model&amp;nbsp;for&amp;nbsp;Ruby&amp;nbsp;3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scoutapm.com/blog/ruby-ractor&quot;&gt;Ractor:&amp;nbsp;Ruby&amp;rsquo;s&amp;nbsp;Version&amp;nbsp;of&amp;nbsp;the&amp;nbsp;Actor&amp;nbsp;Model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering.universe.com/introduction-to-concurrency-models-with-ruby-part-ii-c39c7e612bed&quot;&gt;Introduction&amp;nbsp;to&amp;nbsp;Concurrency&amp;nbsp;Models&amp;nbsp;with&amp;nbsp;Ruby.&amp;nbsp;Part&amp;nbsp;II&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;No GIL (파이썬)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬도 가만히 있지 않고 &lt;a href=&quot;https://news.hada.io/topic?id=7442&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;그렇다면 파이썬의 GIL에 대한 해결책은 무엇인가하면 두가지 방식이 경쟁중인 상황!!&lt;/p&gt;
&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://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python_11.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;No GIL&lt;/a&gt;과 &lt;a href=&quot;https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-per.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sub-interpreter&lt;/a&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sub-interpreter의 접근방식은 &lt;a href=&quot;https://lwn.net/Articles/754162/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LWN에 나오듯&lt;/a&gt; 후에 나올 자바스크립트의 Worker와 비슷하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 No Gil의 방법을 살펴보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.backblaze.com/blog/the-python-gil-past-present-and-future/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Python GIL: Past, Present, and Future&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=7ih7LbK6ODo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;Talks&amp;nbsp;-&amp;nbsp;Cheuk&amp;nbsp;Ting&amp;nbsp;Ho:&amp;nbsp;Trying&amp;nbsp;No&amp;nbsp;GIL&amp;nbsp;on&amp;nbsp;Scientific&amp;nbsp;Programming&amp;nbsp;&lt;/a&gt;&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;다음은 현재 GIL 동작, GIL이 없을때 생기는 문제를 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GIL이 없을 경우 동기화 프리미티브 소개에 경쟁조건이라 나왔던 현상이 나타난다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;938&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TsAt2/btsl1I5TqL2/crtwZSDwP5kO1ez05fLKc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TsAt2/btsl1I5TqL2/crtwZSDwP5kO1ez05fLKc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TsAt2/btsl1I5TqL2/crtwZSDwP5kO1ez05fLKc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTsAt2%2Fbtsl1I5TqL2%2FcrtwZSDwP5kO1ez05fLKc0%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;1280&quot; height=&quot;938&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;938&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GIL을 없애려는 시도는 총 3가지로 나타나는데, 첫번째는 앞서 스레딩을 하려 했으나 느렸다는 것(1999년).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째 2015년의 시도는 STM처럼 atomic하게 만들자 아이디어로 일명 Gilectomy라 부른다..&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;1280&quot; data-origin-height=&quot;1026&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlki7k/btsl2c6JCIf/w3ceW0sTBbctd7HKyLsZvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlki7k/btsl2c6JCIf/w3ceW0sTBbctd7HKyLsZvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlki7k/btsl2c6JCIf/w3ceW0sTBbctd7HKyLsZvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdlki7k%2Fbtsl2c6JCIf%2Fw3ceW0sTBbctd7HKyLsZvK%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;1440&quot; height=&quot;1155&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1026&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 마지막, 현재 No GIL.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;955&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQl1B7/btsl1Ix4qJO/pI6kTYA070kEZGszZIkD1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQl1B7/btsl1Ix4qJO/pI6kTYA070kEZGszZIkD1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQl1B7/btsl1Ix4qJO/pI6kTYA070kEZGszZIkD1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQl1B7%2Fbtsl1Ix4qJO%2FpI6kTYA070kEZGszZIkD1K%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;1440&quot; height=&quot;1075&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;955&quot;/&gt;&lt;/span&gt;&lt;/figure&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;항상 참조횟수가 0 이상을 유지되는 True, False, None등은 recount 매크로가 작동하지 않도록해 경쟁조건 회피&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;다른 쓰레드가 접근할때만 Atomic하게 업데이트&lt;br /&gt;&lt;/span&gt;대부분의 객체 엑세스는 소유 스레드의 로컬일때 일어나므로 효율적임&lt;/li&gt;
&lt;li&gt;컬렉션의 lock을 위한 효율적인 알고리즘&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Worker (자바스크립트)&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;a style=&quot;color: #0070d1;&quot; href=&quot;https://nodesource.com/blog/worker-threads-nodejs/&quot;&gt;Understanding&amp;nbsp;Worker&amp;nbsp;Threads&amp;nbsp;in&amp;nbsp;Node.js&lt;/a&gt;]&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;그럼 싱글 쓰레드를 유지하며 멀티코어를 이용할 방법은 없을까?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기 쉬운 방법이 있다. 바로 shell scirpt에서 sub shell 만들 듯 띄워버리면 그만이다 ㅋㅋ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NCfiy/btsl4lu3xyv/BG30vQYMzNsdyYzgbgFf51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NCfiy/btsl4lu3xyv/BG30vQYMzNsdyYzgbgFf51/img.png&quot; width=&quot;502&quot; height=&quot;292&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;292&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.2308%; margin-right: 10px;&quot; data-widthpercent=&quot;52.85&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NCfiy/btsl4lu3xyv/BG30vQYMzNsdyYzgbgFf51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNCfiy%2Fbtsl4lu3xyv%2FBG30vQYMzNsdyYzgbgFf51%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;292&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5Vegj/btsl2dq3rMO/fQSORkBkEEC1ninfoJbfC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5Vegj/btsl2dq3rMO/fQSORkBkEEC1ninfoJbfC1/img.png&quot; data-origin-width=&quot;428&quot; data-origin-height=&quot;279&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.6064%;&quot; data-widthpercent=&quot;47.15&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5Vegj/btsl2dq3rMO/fQSORkBkEEC1ninfoJbfC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5Vegj%2Fbtsl2dq3rMO%2FfQSORkBkEEC1ninfoJbfC1%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;428&quot; height=&quot;279&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/learning-the-bash/1565923472/ch04.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Basic Shell Programming&lt;/a&gt;, &lt;a href=&quot;https://velog.io/@markyang92/shell-script-%EC%9E%91%EC%84%B1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;./&amp;nbsp;,bash&amp;nbsp;,bash&amp;nbsp;-c&amp;nbsp;&quot;&quot;,&amp;nbsp;source,&amp;nbsp;subshell&amp;nbsp;vs&amp;nbsp;childprocess&lt;/a&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;이게 서브 인터프린터의 기본 개념이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;워커 자체는 여전히 싱글 스레드로 실행되며, shell과는 달리 sleep 없이 동시에 실행가능해야 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;postMessage()&lt;/a&gt;를 통해 데이터를 주고 받는 형태를 띄고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1wgyn/btsl9uE2ejV/La3qdVuBxxC5Kzq9MXoKO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1wgyn/btsl9uE2ejV/La3qdVuBxxC5Kzq9MXoKO1/img.png&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;362&quot; data-is-animation=&quot;false&quot; style=&quot;width: 59.2769%; margin-right: 10px;&quot; data-widthpercent=&quot;59.97&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1wgyn/btsl9uE2ejV/La3qdVuBxxC5Kzq9MXoKO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1wgyn%2Fbtsl9uE2ejV%2FLa3qdVuBxxC5Kzq9MXoKO1%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;885&quot; height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qFaEK/btsl9uZlyAK/xSGEI1fTqv3WkGlKemLs20/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qFaEK/btsl9uZlyAK/xSGEI1fTqv3WkGlKemLs20/img.jpg&quot; data-origin-width=&quot;434&quot; data-origin-height=&quot;266&quot; data-is-animation=&quot;false&quot; style=&quot;width: 39.5603%;&quot; data-widthpercent=&quot;40.03&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qFaEK/btsl9uZlyAK/xSGEI1fTqv3WkGlKemLs20/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqFaEK%2Fbtsl9uZlyAK%2FxSGEI1fTqv3WkGlKemLs20%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;434&quot; height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.carbonfive.com/the-javascript-event-loop-explained/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;JavaScript&amp;nbsp;Event&amp;nbsp;Loop:&amp;nbsp;Explained&lt;/a&gt;, &lt;a href=&quot;https://www.sitepoint.com/developing-faster-javascript-apps-the-ultimate-guide-to-web-workers/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Ultimate Guide to Web Workers&lt;/a&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;물론 오버헤드와 API 제한은 있다. [&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://blog.sessionstack.com/how-javascript-works-the-building-blocks-of-web-workers-5-cases-when-you-should-use-them-a547c0757f6a&quot;&gt;How&amp;nbsp;JavaScript&amp;nbsp;works:&amp;nbsp;The&amp;nbsp;building&amp;nbsp;blocks&amp;nbsp;of&amp;nbsp;Web&amp;nbsp;Workers&amp;nbsp;+&amp;nbsp;5&amp;nbsp;cases&amp;nbsp;when&amp;nbsp;you&amp;nbsp;should&amp;nbsp;use&amp;nbsp;them&lt;/a&gt;]&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;ArrayBuffer를 사용하지 않는 이상 직렬화-복사-역직렬화 과정이 일어나며,&amp;nbsp; window나 documnet 등의 객체에는 접근할 수가 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dw5oof/btrS60MjLKV/txSywk2QmSkjYR1nAwJgUK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dw5oof/btrS60MjLKV/txSywk2QmSkjYR1nAwJgUK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dw5oof/btrS60MjLKV/txSywk2QmSkjYR1nAwJgUK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdw5oof%2FbtrS60MjLKV%2FtxSywk2QmSkjYR1nAwJgUK%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;960&quot; height=&quot;960&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://surma.dev/things/is-postmessage-slow/&quot;&gt;&amp;nbsp;Is&amp;nbsp;postMessage&amp;nbsp;slow?&amp;nbsp;&lt;/a&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Node.js (Reactor 패턴)&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/preezma/node-js-event-loop-architecture-go-deeper-node-core-c96b4cec7aa4&quot;&gt;Node.js event loop architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What you should know to really understand the Node.js Event Loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.korecmblog.com/node-js-event-loop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Node.js 이벤트 루프(Event Loop) 샅샅이 분석하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sCJfs/btrS09K0RDT/9Dk4ykiR5PiCBqRJ50Q3n0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sCJfs/btrS09K0RDT/9Dk4ykiR5PiCBqRJ50Q3n0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sCJfs/btrS09K0RDT/9Dk4ykiR5PiCBqRJ50Q3n0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsCJfs%2FbtrS09K0RDT%2F9Dk4ykiR5PiCBqRJ50Q3n0%2Fimg.webp&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;982&quot; height=&quot;384&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2845&quot; data-origin-height=&quot;1075&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k6Oiz/btrS0FjkH9N/kr4BpaCp6J8aLyHAaLaGFk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k6Oiz/btrS0FjkH9N/kr4BpaCp6J8aLyHAaLaGFk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k6Oiz/btrS0FjkH9N/kr4BpaCp6J8aLyHAaLaGFk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk6Oiz%2FbtrS0FjkH9N%2Fkr4BpaCp6J8aLyHAaLaGFk%2Fimg.webp&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;1919&quot; height=&quot;725&quot; data-origin-width=&quot;2845&quot; data-origin-height=&quot;1075&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Node.js 아키텍처와 I/O 루프&lt;/p&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의 백그라운드에서 멀티 쓰레드로 일부 동작한다. (Reactor 패턴)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.libuv.org/en/v1.x/threadpool.html#threadpool&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;기본적으로 4개&lt;/a&gt;인걸로 알려져있으며 동작은&amp;nbsp;&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;704&quot; data-origin-height=&quot;307&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvvcNx/btrS5xYaZvJ/eGBJQD9H8vcrwMgQnRgkw0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvvcNx/btrS5xYaZvJ/eGBJQD9H8vcrwMgQnRgkw0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvvcNx/btrS5xYaZvJ/eGBJQD9H8vcrwMgQnRgkw0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvvcNx%2FbtrS5xYaZvJ%2FeGBJQD9H8vcrwMgQnRgkw0%2Fimg.webp&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;704&quot; height=&quot;307&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;307&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;493&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SV0LW/btrS0LKrj4Q/F1W36sIKz2kEguWTIkllKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SV0LW/btrS0LKrj4Q/F1W36sIKz2kEguWTIkllKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SV0LW/btrS0LKrj4Q/F1W36sIKz2kEguWTIkllKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSV0LW%2FbtrS0LKrj4Q%2FF1W36sIKz2kEguWTIkllKK%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;1020&quot; height=&quot;493&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;493&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.libuv.org/en/v1.x/design.html&quot;&gt;libuv&amp;nbsp;-Design&amp;nbsp;overview&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 스레드지만 운영체제의 Epoll, kqueue 등을 활용: 네트워크(TCP/UDP), TTY, 파이프&lt;/li&gt;
&lt;li&gt;쓰레드 풀에서 실행: 파일 I/O, DNS, 사용자 지정 코드&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;/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;710&quot; data-origin-height=&quot;749&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHkKGs/btrS5M8Ii94/aeK14OMxfgteG2LAwrEeB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHkKGs/btrS5M8Ii94/aeK14OMxfgteG2LAwrEeB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHkKGs/btrS5M8Ii94/aeK14OMxfgteG2LAwrEeB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHkKGs%2FbtrS5M8Ii94%2FaeK14OMxfgteG2LAwrEeB1%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;710&quot; height=&quot;749&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;749&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.risingstack.com/node-js-at-scale-understanding-node-js-event-loop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Understanding&amp;nbsp;the&amp;nbsp;Node.js&amp;nbsp;Event&amp;nbsp;Loop&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EmwUw/btrS0Fp4OKI/IVDIKcuGFFPJazELQV8gsK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EmwUw/btrS0Fp4OKI/IVDIKcuGFFPJazELQV8gsK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EmwUw/btrS0Fp4OKI/IVDIKcuGFFPJazELQV8gsK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/EmwUw/btrS0Fp4OKI/IVDIKcuGFFPJazELQV8gsK/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;880&quot; height=&quot;495&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript&amp;nbsp;Visualized:&amp;nbsp;Promises&amp;nbsp;&amp;amp;&amp;nbsp;Async/Await&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;위의 Worker와 함께 실행되는 모습을 상상해보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1658&quot; data-origin-height=&quot;888&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zNakZ/btrS5gbGzcb/TmWaRPZpYtvkkgYrTX5Mck/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zNakZ/btrS5gbGzcb/TmWaRPZpYtvkkgYrTX5Mck/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zNakZ/btrS5gbGzcb/TmWaRPZpYtvkkgYrTX5Mck/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzNakZ%2FbtrS5gbGzcb%2FTmWaRPZpYtvkkgYrTX5Mck%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;1658&quot; height=&quot;888&quot; data-origin-width=&quot;1658&quot; data-origin-height=&quot;888&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&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://twitter.com/nearform/status/1260963144278704131&quot;&gt;트위터&lt;/a&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Proactor 패턴&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 노드 JS는 Reactor 패턴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reactor, Proactor 패턴은 이벤트 핸들러의 논블럭킹을 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reactor는 동기적, Proactor는 비동기적이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LJhIC/btrS4ZBpzYu/HaCC2q77H4qhcxSbiq34Q1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LJhIC/btrS4ZBpzYu/HaCC2q77H4qhcxSbiq34Q1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LJhIC/btrS4ZBpzYu/HaCC2q77H4qhcxSbiq34Q1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLJhIC%2FbtrS4ZBpzYu%2FHaCC2q77H4qhcxSbiq34Q1%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Vm5l8zH4hOE&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Proactor&amp;nbsp;and&amp;nbsp;Reactor&amp;nbsp;Design&amp;nbsp;Patterns&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;다음 Reactor 패턴 그림을 보면 동기적이며, Node.js 이벤트 루프와 비슷하다는 것을 단번에 알아챌 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AaqP6/btrS3FQHe3b/qkw1FgFfqKO1yOIQE00Ah0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AaqP6/btrS3FQHe3b/qkw1FgFfqKO1yOIQE00Ah0/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1034&quot; data-is-animation=&quot;false&quot; style=&quot;width: 36.2148%; margin-right: 10px;&quot; data-widthpercent=&quot;37.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AaqP6/btrS3FQHe3b/qkw1FgFfqKO1yOIQE00Ah0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAaqP6%2FbtrS3FQHe3b%2Fqkw1FgFfqKO1yOIQE00Ah0%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;1280&quot; height=&quot;1034&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nupiB/btrS60MvCh5/K5f4ep06o1Mea5IafPEjBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nupiB/btrS60MvCh5/K5f4ep06o1Mea5IafPEjBK/img.png&quot; data-origin-width=&quot;1298&quot; data-origin-height=&quot;1130&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.6042%; margin-right: 10px;&quot; data-widthpercent=&quot;34.4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nupiB/btrS60MvCh5/K5f4ep06o1Mea5IafPEjBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnupiB%2FbtrS60MvCh5%2FK5f4ep06o1Mea5IafPEjBK%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;1298&quot; height=&quot;1130&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhl7BX/btrS5Aui5de/sQap0zyBJITFvzkWL8pFV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhl7BX/btrS5Aui5de/sQap0zyBJITFvzkWL8pFV0/img.png&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;1338&quot; data-is-animation=&quot;false&quot; style=&quot;width: 27.8554%;&quot; data-widthpercent=&quot;28.52&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhl7BX/btrS5Aui5de/sQap0zyBJITFvzkWL8pFV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbhl7BX%2FbtrS5Aui5de%2FsQap0zyBJITFvzkWL8pFV0%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;1274&quot; height=&quot;1338&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;기본, 멀티 쓰레드 핸들러, 멀티 리엑터 - 멀티 쓰레드 핸들러&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 JS는 첫번째 싱글 쓰레드 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 복잡한 형태인 멀티 리엑터 - 멀티 쓰레드의 예는 &lt;a href=&quot;https://vertx.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vert.x&lt;/a&gt;가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beaX2p/btrS1ezg5ur/svE68iI0Ma3HvKX2HH0sQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beaX2p/btrS1ezg5ur/svE68iI0Ma3HvKX2HH0sQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beaX2p/btrS1ezg5ur/svE68iI0Ma3HvKX2HH0sQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeaX2p%2FbtrS1ezg5ur%2FsvE68iI0Ma3HvKX2HH0sQK%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;756&quot; height=&quot;408&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.knoldus.com/what-is-vert-x/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;What&amp;nbsp;is&amp;nbsp;Vert.x&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vert.x에서는 &lt;a href=&quot;https://github.com/vert-x3/vertx-guide-for-java-devs/blob/3.8/intro/README.adoc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;한 쓰레드당 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;Proactor는 비동기답게 통지해주는 방식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1590&quot; data-origin-height=&quot;844&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNTYPA/btrS3o2vVeO/Daa9faxLUOUnaxPlrvY4Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNTYPA/btrS3o2vVeO/Daa9faxLUOUnaxPlrvY4Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNTYPA/btrS3o2vVeO/Daa9faxLUOUnaxPlrvY4Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNTYPA%2FbtrS3o2vVeO%2FDaa9faxLUOUnaxPlrvY4Kk%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;1590&quot; height=&quot;844&quot; data-origin-width=&quot;1590&quot; data-origin-height=&quot;844&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proactor가 비동기라고 무조건 좋은것은 아니라 구현의 복잡도와 오버헤드가 존재하기 때문에 적절한 상황에서 쓰는게 좋다. (앞서 리눅스 AIO도 오버헤드 때문에 느렸다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부스트 &lt;a href=&quot;https://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/async.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Asio&lt;/a&gt;와 &lt;a href=&quot;https://quarkus.io/guides/quarkus-reactive-architecture&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Quarkus&lt;/a&gt;가 대표적인 Proactor 패턴의 예이다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://didawiki.cli.di.unipi.it/lib/exe/fetch.php/magistraleinformatica/tdp/tpd_reactor_proactor.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reactor&amp;nbsp;and&amp;nbsp;Proactor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://simyy.cn/2019/12/16/re-pro-actor/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reactor &amp;amp; Proactor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bbs.huaweicloud.com/blogs/266248&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;高性能网络框架：Reactor&amp;nbsp;和&amp;nbsp;Proactor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://segmentfault.com/a/1190000002715832&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IO设计模式：Reactor和Proactor对比&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. CSP와 액터&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시성을 위해 이런저런 방식이 있지만 최근 가장 인기있는것은 CSP(순차 프로세스 통신, Communication Sequential Process)와 액터(Actor)다.&lt;/p&gt;
&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;h4 data-ke-size=&quot;size20&quot;&gt;CSP&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7hAa0/btrPgEHMr8r/z8JeB75lSa8cMQKJhOtKdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7hAa0/btrPgEHMr8r/z8JeB75lSa8cMQKJhOtKdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7hAa0/btrPgEHMr8r/z8JeB75lSa8cMQKJhOtKdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7hAa0%2FbtrPgEHMr8r%2Fz8JeB75lSa8cMQKJhOtKdk%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;880&quot; height=&quot;474&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://dev.to/karanpratapsingh/csp-vs-actor-model-for-concurrency-1cpg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSP vs Actor model for concurrency&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSP는 채널을 통해서 통신한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1132&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zMJsz/btrPfXHTxOV/BwkR3n8GDHFCFf0xIEBWrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zMJsz/btrPfXHTxOV/BwkR3n8GDHFCFf0xIEBWrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zMJsz/btrPfXHTxOV/BwkR3n8GDHFCFf0xIEBWrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzMJsz%2FbtrPfXHTxOV%2FBwkR3n8GDHFCFf0xIEBWrk%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;1132&quot; height=&quot;289&quot; data-origin-width=&quot;1132&quot; data-origin-height=&quot;289&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://arild.github.io/csp-presentation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Communicating Sequential Processes (CSP) An alternative to the actor model&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq7MEu/btrPit6BRUr/FAkOtEZuKPFnjXYVHuv0Vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq7MEu/btrPit6BRUr/FAkOtEZuKPFnjXYVHuv0Vk/img.png&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;562&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq7MEu/btrPit6BRUr/FAkOtEZuKPFnjXYVHuv0Vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq7MEu%2FbtrPit6BRUr%2FFAkOtEZuKPFnjXYVHuv0Vk%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;750&quot; height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmeOrN/btrPgWBrsmW/ZF509IkxYEZoyvt7Oi0M51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmeOrN/btrPgWBrsmW/ZF509IkxYEZoyvt7Oi0M51/img.png&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;562&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmeOrN/btrPgWBrsmW/ZF509IkxYEZoyvt7Oi0M51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmeOrN%2FbtrPgWBrsmW%2FZF509IkxYEZoyvt7Oi0M51%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;750&quot; height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.slideserve.com/cato/communicating-sequential-processes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Communicating&amp;nbsp;Sequential&amp;nbsp;Processes&lt;/a&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;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kzotK/btrPmFkSBTW/mBntk4yi6WSyHbL7HRadA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kzotK/btrPmFkSBTW/mBntk4yi6WSyHbL7HRadA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kzotK/btrPmFkSBTW/mBntk4yi6WSyHbL7HRadA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkzotK%2FbtrPmFkSBTW%2FmBntk4yi6WSyHbL7HRadA1%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;880&quot; height=&quot;491&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;491&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcEY5C/btrPjkIt4BN/ieqAY4kr7eDLxkt7pfQXhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcEY5C/btrPjkIt4BN/ieqAY4kr7eDLxkt7pfQXhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcEY5C/btrPjkIt4BN/ieqAY4kr7eDLxkt7pfQXhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcEY5C%2FbtrPjkIt4BN%2FieqAY4kr7eDLxkt7pfQXhK%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;733&quot; height=&quot;100&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;100&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1IxMu/btrPnfTWRPI/sbWcFkPNGGM8trzQDRKgEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1IxMu/btrPnfTWRPI/sbWcFkPNGGM8trzQDRKgEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1IxMu/btrPnfTWRPI/sbWcFkPNGGM8trzQDRKgEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1IxMu%2FbtrPnfTWRPI%2FsbWcFkPNGGM8trzQDRKgEK%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;437&quot; height=&quot;333&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;333&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rntlqvnf.github.io/lecture%20notes/os-4th-2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[OS]&amp;nbsp;Synchronization&amp;nbsp;(2)&amp;nbsp;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내용만 보면 상당히 비슷하다만 보통 &lt;a href=&quot;https://en.wikipedia.org/wiki/Actor_model_and_process_calculi_history#Early_work&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음과 같은 차이&lt;/a&gt;를 가지고 있다고 설명한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSP의 프로세스는 익명, 액터는 ID를 가지고 있음&lt;/li&gt;
&lt;li&gt;CSP의 메세지는 동기화된 입출력으로 보낸 순서대로 도착한다&lt;/li&gt;
&lt;li&gt;액터의 메세지는 단방향이며 비동기적이다&lt;/li&gt;
&lt;li&gt;액터는 메세지에는 액터의 주소가 포함될 수 있다&lt;/li&gt;
&lt;li&gt;CSP는 경계 비결정론적이지만, 액터는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Unbounded_nondeterminism&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;무한 비결정론&lt;/a&gt;적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11. 그린 쓰레드, 고루틴 그리고 최신 비동기 런타임 기술들&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;그린 쓰레드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Green_thread&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;그린 쓰레드&lt;/a&gt;는 커널이 아닌 유저 스페이스에서 관리하는 쓰레드다. [&lt;a href=&quot;https://softwareengineering.stackexchange.com/questions/222642/are-go-langs-goroutine-pools-just-green-threads&quot;&gt;Are&amp;nbsp;go-langs&amp;nbsp;goroutine&amp;nbsp;pools&amp;nbsp;just&amp;nbsp;green&amp;nbsp;threads?&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM에서 시도해서 실패했지만(1:N 모델로 Stackful 코루틴과 차이가 크지 않았음) 최근 여러 구현체가 나오고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인게 OpenJDK의 프로젝트 룸(Project Loom)이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/danBBv/btrUM41WdPM/bjOYaOenKGp4u1zP64P04k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/danBBv/btrUM41WdPM/bjOYaOenKGp4u1zP64P04k/img.png&quot; data-origin-width=&quot;328&quot; data-origin-height=&quot;473&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5646%; margin-right: 10px;&quot; data-widthpercent=&quot;50.15&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/danBBv/btrUM41WdPM/bjOYaOenKGp4u1zP64P04k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdanBBv%2FbtrUM41WdPM%2FbjOYaOenKGp4u1zP64P04k%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;328&quot; height=&quot;473&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBbx70/btrURTZbX80/q6QLZCBH1Qch1JWZQdJ1Q0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBbx70/btrURTZbX80/q6QLZCBH1Qch1JWZQdJ1Q0/img.jpg&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;470&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.85&quot; style=&quot;width: 49.2726%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBbx70/btrURTZbX80/q6QLZCBH1Qch1JWZQdJ1Q0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBbx70%2FbtrURTZbX80%2Fq6QLZCBH1Qch1JWZQdJ1Q0%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;324&quot; height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;그린 쓰레드 vs 프로젝트 룸&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.devkr.info/posts/211112_project_loom/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;프로젝트 룸(Project Loom)이란 무엇인가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gunsdevlog.blogspot.com/2020/09/java-project-loom-reactive-streams.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;Java의&amp;nbsp;동시성&amp;nbsp;개선을&amp;nbsp;위한&amp;nbsp;Project&amp;nbsp;Loom은&amp;nbsp;reactive&amp;nbsp;streams를&amp;nbsp;대체할&amp;nbsp;것인가?&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cr.openjdk.java.net/~rpressler/loom/Loom-Proposal.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Project&amp;nbsp;Loom:&amp;nbsp;Fibers&amp;nbsp;and&amp;nbsp;Continuations&amp;nbsp;for&amp;nbsp;the&amp;nbsp;Java&amp;nbsp;Virtual&amp;nbsp;Machine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lukstei.com/382cd48c69f12f72086b11b1f5c18dc7/async-await-talk.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sexy&amp;nbsp;async&amp;nbsp;code&amp;nbsp;without&amp;nbsp;await?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lukstei.com/2020-07-25-a-first-look-into-the-project-loom-in-java/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;first&amp;nbsp;look&amp;nbsp;into&amp;nbsp;the&amp;nbsp;Project&amp;nbsp;Loom&amp;nbsp;in&amp;nbsp;Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blogs.oracle.com/javamagazine/post/going-inside-javas-project-loom-and-virtual-threads&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Going&amp;nbsp;inside&amp;nbsp;Java&amp;rsquo;s&amp;nbsp;Project&amp;nbsp;Loom&amp;nbsp;and&amp;nbsp;virtual&amp;nbsp;threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.softwaremill.com/will-project-loom-obliterate-java-futures-fb1a28508232&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Will&amp;nbsp;Project&amp;nbsp;Loom&amp;nbsp;obliterate&amp;nbsp;Java&amp;nbsp;Futures?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;최신 CSP 런타임&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;a href=&quot;https://go.dev/tour/concurrency/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;고루틴&lt;/a&gt;과 &lt;a href=&quot;https://tokio.rs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tokio&lt;/a&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;a href=&quot;https://morsmachine.dk/go-scheduler&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Go&amp;nbsp;scheduler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://betterprogramming.pub/deep-dive-into-concurrency-of-go-93002344d37b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Deep&amp;nbsp;Dive&amp;nbsp;Into&amp;nbsp;Go&amp;nbsp;Concurrency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://levelup.gitconnected.com/how-does-golang-channel-works-6d66acd54753&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How Does Golang Channel Works&lt;/a&gt;(&lt;a href=&quot;https://velog.io/@moonyoung/Deep-Dive-to-Golang-Channel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Deep&amp;nbsp;Dive&amp;nbsp;to&amp;nbsp;Golang&amp;nbsp;Channel, 한글&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tokio.rs/blog/2019-10-scheduler&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Making the Tokio scheduler 10x faster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tokio.rs/blog/2020-04-preemption&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reducing&amp;nbsp;tail&amp;nbsp;latencies&amp;nbsp;with&amp;nbsp;automatic&amp;nbsp;cooperative&amp;nbsp;task&amp;nbsp;yielding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cafbit.com/post/tokio_internals/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tokio internals: Understanding Rust's asynchronous I/O framework from the bottom up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@genchilu/if-a-goroutine-call-a-new-goroutine-which-one-would-scheduler-pick-up-first-890002dc54f8&quot;&gt;If&amp;nbsp;a&amp;nbsp;goroutine&amp;nbsp;create&amp;nbsp;a&amp;nbsp;new&amp;nbsp;goroutine,&amp;nbsp;which&amp;nbsp;one&amp;nbsp;would&amp;nbsp;scheduler&amp;nbsp;pick&amp;nbsp;up&amp;nbsp;first?&lt;/a&gt;&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;/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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1623&quot; data-origin-height=&quot;927&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mkKJ0/btrPjHKpnHy/1QDMvoTOO0RzGmWWzK9dI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mkKJ0/btrPjHKpnHy/1QDMvoTOO0RzGmWWzK9dI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mkKJ0/btrPjHKpnHy/1QDMvoTOO0RzGmWWzK9dI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmkKJ0%2FbtrPjHKpnHy%2F1QDMvoTOO0RzGmWWzK9dI0%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;1623&quot; height=&quot;927&quot; data-origin-width=&quot;1623&quot; data-origin-height=&quot;927&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;먼저 하나의 OS 쓰레드 1개와만 매핑되던 오리지널 그린쓰레드와 다르게 여러개를 사용한다. [위에서는 P(Virtual Processor)의 갯수]&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;a href=&quot;https://pkg.go.dev/runtime#GOMAXPROCS&quot;&gt;Goroutine&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://docs.rs/tokio/latest/tokio/runtime/struct.Builder.html#method.worker_threads&quot;&gt;Tokio&lt;/a&gt;의 모두 논리코어(OS에서 인식하는 코어 수)의 갯수대로 생성&lt;/li&gt;
&lt;li&gt;논리코어보다 많으면 컨텍스트 스위칭의 오버헤드가 추가되며, 적은 수의 스레드가 항상 활성화 상태일 때가 더 바람직함&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 말단은 여러 코루틴(고의 고루틴, Tokio의 &lt;a href=&quot;https://docs.rs/tokio/latest/tokio/task/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;태스크&lt;/a&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/golang/go/blob/5b606a9d2b7649532fe25794fa6b99bd24e7697c/src/runtime/proc.go#L3475&quot;&gt;컨티뉴에이션을 이용&lt;/a&gt;해 컨텍스트 스위칭을 최소화함&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tokio.rs/blog/2019-10-scheduler#reducing-allocations&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Task 구조&lt;/a&gt;도 Hot 데이터(header)와 Cold 데이터 (Trailer)를 나누어 캐시라인에 최적화 (고루틴의 경우 2kb)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Tokio의 경우 작업이 끝났다는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://doc.rust-lang.org/std/task/struct.RawWaker.html&quot;&gt;알림&lt;/a&gt;&lt;span&gt;을 캐시라인 크기에 맞추어 복사 가능하게 만들고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://rinthel.github.io/rust-lang-book-ko/ch16-03-shared-state.html#atomic-reference-counting-with-arct&quot;&gt;레퍼런스 카운팅(Arc)&lt;/a&gt;&lt;span&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://tokio.rs/blog/2019-10-scheduler#reducing-atomic-reference-counting&quot;&gt;줄임&lt;/a&gt;&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;- 큐와 작업 훔치기(Work stealing)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc8YzY/btrPgpLilju/XZkD8eP6dBm5ISje4ynYr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc8YzY/btrPgpLilju/XZkD8eP6dBm5ISje4ynYr1/img.png&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;357&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.1784%; margin-right: 10px;&quot; data-widthpercent=&quot;49.76&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc8YzY/btrPgpLilju/XZkD8eP6dBm5ISje4ynYr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc8YzY%2FbtrPgpLilju%2FXZkD8eP6dBm5ISje4ynYr1%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;510&quot; height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2wcHC/btrPh7W6Y4W/Ege6w0i0VApGcSzoFgDam0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2wcHC/btrPh7W6Y4W/Ege6w0i0VApGcSzoFgDam0/img.png&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;348&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.6588%;&quot; data-widthpercent=&quot;50.24&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2wcHC/btrPh7W6Y4W/Ege6w0i0VApGcSzoFgDam0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2wcHC%2FbtrPh7W6Y4W%2FEge6w0i0VApGcSzoFgDam0%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;348&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 큐가 하나(GRQ, Global run queue)만 있다면 대기열에서 경합이 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 여러개(LRQ, Local run 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;따라서 방법은 둘 다!! + 다른 큐의 작업 훔쳐오기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FrzNO/btrPitTfxf1/dpOq20cZqAkQTOLNCqj5nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FrzNO/btrPitTfxf1/dpOq20cZqAkQTOLNCqj5nK/img.png&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;574&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;28.91&quot; style=&quot;width: 28.5738%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FrzNO/btrPitTfxf1/dpOq20cZqAkQTOLNCqj5nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFrzNO%2FbtrPitTfxf1%2FdpOq20cZqAkQTOLNCqj5nK%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;548&quot; height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAR5q3/btrPgXHjZBZ/MNLK4sdCrKBKDf2HzNRwd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAR5q3/btrPgXHjZBZ/MNLK4sdCrKBKDf2HzNRwd1/img.png&quot; width=&quot;600px&quot; data-origin-width=&quot;1587&quot; data-origin-height=&quot;676&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;71.09&quot; style=&quot;width: 70.2634%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAR5q3/btrPgXHjZBZ/MNLK4sdCrKBKDf2HzNRwd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAR5q3%2FbtrPgXHjZBZ%2FMNLK4sdCrKBKDf2HzNRwd1%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;1587&quot; height=&quot;676&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LRQ는 워크 스틸링과정의 오버헤드를 줄이기 위해 M이 아닌 P당 1개씩 할당&lt;/li&gt;
&lt;li&gt;LRQ는 FIFO큐와 1개의 LIFO(Next Job) 큐로 구성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로 생성한 작업이 Next Job일 때 프로세서에 남아있는 캐시를 최대한 이용할 수 있음((LRU 캐시를 생각해보자)&lt;/li&gt;
&lt;li&gt;짧게 반복하는 작업이 오랫동안 LIFO를 점유할 수 있기 때문에 점유시간을 제한 (공평한 스케쥴링, 고루틴에서는 10ms)&lt;/li&gt;
&lt;li&gt;FIFO큐의 경우 원형큐로 단일 생산자(현재 프로세서), 다중소비자(Front는 현재 P, Back은 작업을 훔쳐갈 P) 구조 [SPMC]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;nbsp;GRQ는 LRQ에 할당되지 못한 작업들로 구성된 큐
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LRQ가 가득찬 경우&lt;/li&gt;
&lt;li&gt;쓰레드에서 일정기간 작업 실행 후 timeout된 작업 (오래 걸릴거라 예상되는 작업을 공평한 스케쥴링을 위해서 선점, 역시 고루틴에서는 10ms)&lt;br /&gt;&lt;span&gt;Tokio의 경우 선점하지는 않지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://tokio.rs/blog/2020-04-preemption&quot;&gt;작업 예산&lt;/a&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;개념이 있어 양보할 수는 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;자신의 LRQ - 다른 LRQ - GRQ 순으로 작업을 가져옴
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캐시의 지역성을 위해 특정한 기간동안 못가져가도록 제한할 수 있음 (고루틴의 경우 3ms)&lt;/li&gt;
&lt;li&gt;특정 횟수마다 GRQ에서 작업을 가져옴(역시 공평한 스케쥴링을 위해서, 고루틴과 Tokio 모두 61번째)&lt;/li&gt;
&lt;li&gt;GRQ에도 작업이 없으면 네트워크 풀링을 하여 일이 있나 검사를 한다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;작업을 가져올 때 경합과 오버헤드를 줄여야함&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(epoll 작업으로 여러 소켓이 멀티플렉싱되어 동시에 끝나므로 경합하는&amp;nbsp;&lt;/span&gt;경향이 큼)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무작위로 무작위로 훔치려는 형제 LRQ를 선택하여 경합을 줄임&lt;/li&gt;
&lt;li&gt;훔칠 수 있는 작업을 수행하는 P의 갯수를 제한 (일종의 스로틀링, Tokio에서는 P의 절반값)&lt;/li&gt;
&lt;li&gt;검색 상태가 끝나야 알림을 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;블럭킹 작업
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업이 오래걸리는 블러킹 작업이나 CPU 바운드 작업은 전용 워커에서 실행해야 함&lt;/li&gt;
&lt;li&gt;CPU 바운드의 경우 고정된 크기의 쓰레드풀이 따로 있는게 효율적&lt;/li&gt;
&lt;li&gt;고루틴의 경우 네트워크 비동기 작업들을 Net poller라는 배경 쓰레드가 처리후 해당 이벤트가 필요한 P의 LRQ에 넣어줌&lt;/li&gt;
&lt;/ul&gt;
&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;/p&gt;
&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://velog.io/@moonyoung/Deep-Dive-to-Golang-Channel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Deep Dive to Golang Channel&lt;/a&gt; 에서 잘 다루어주고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;886&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CGP2K/btrTFaBEd4M/Vgft3yqdtY3h3LOfvACrDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CGP2K/btrTFaBEd4M/Vgft3yqdtY3h3LOfvACrDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CGP2K/btrTFaBEd4M/Vgft3yqdtY3h3LOfvACrDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCGP2K%2FbtrTFaBEd4M%2FVgft3yqdtY3h3LOfvACrDK%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;1280&quot; height=&quot;886&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;886&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;buf: 링버퍼이며 데이터를 덮어써도 되기 때문에 유용하다&amp;nbsp;&lt;/li&gt;
&lt;li&gt;sendx:전달할 데이터의 인덱스&lt;/li&gt;
&lt;li&gt;recvx: 받을 데이터의 인덱스&amp;nbsp;&lt;/li&gt;
&lt;li&gt;mutex: 주고( send) 받는(recv) 작업을 할 때 락을 걸어 쓰레드 안전하게 만든다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhMpCw/btrTBKqsrvw/zUZk8Y3rkbAb1kP0U5tnkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhMpCw/btrTBKqsrvw/zUZk8Y3rkbAb1kP0U5tnkK/img.png&quot; width=&quot;1421&quot; height=&quot;961&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;866&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;35.66&quot; style=&quot;width: 34.8319%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhMpCw/btrTBKqsrvw/zUZk8Y3rkbAb1kP0U5tnkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhMpCw%2FbtrTBKqsrvw%2FzUZk8Y3rkbAb1kP0U5tnkK%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;1280&quot; height=&quot;866&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TR95q/btrTBjT3Z1V/lywd1K1Bd3AdNyQbQ5MeDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TR95q/btrTBjT3Z1V/lywd1K1Bd3AdNyQbQ5MeDk/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot; data-is-animation=&quot;false&quot; style=&quot;width: 31.4213%; margin-right: 10px;&quot; data-widthpercent=&quot;32.17&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TR95q/btrTBjT3Z1V/lywd1K1Bd3AdNyQbQ5MeDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTR95q%2FbtrTBjT3Z1V%2Flywd1K1Bd3AdNyQbQ5MeDk%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;1280&quot; height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uw5L1/btrTFb8qEnL/9mE3bHzSWS4v4kKXbif5R1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uw5L1/btrTFb8qEnL/9mE3bHzSWS4v4kKXbif5R1/img.png&quot; width=&quot;1282&quot; height=&quot;962&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot; data-is-animation=&quot;false&quot; style=&quot;width: 31.4213%;&quot; data-widthpercent=&quot;32.17&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uw5L1/btrTFb8qEnL/9mE3bHzSWS4v4kKXbif5R1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fuw5L1%2FbtrTFb8qEnL%2F9mE3bHzSWS4v4kKXbif5R1%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;1280&quot; height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1개가 전달되어 sendx의 인덱스가 증가&lt;/li&gt;
&lt;li&gt;버퍼가 꽉 차도록 전달되어 sendx의 인덱스가 다시 처음으로 돌아옴&lt;/li&gt;
&lt;li&gt;데이터 한 개를 소비하여 recvx의 인덱스가 증가함&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;a href=&quot;https://github.com/crossbeam-rs/crossbeam&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Crossbeam&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://github.com/zesterer/flume&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Flume&lt;/a&gt;과 &lt;a href=&quot;https://github.com/fereidani/kanal&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kanal&lt;/a&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;액터 런타임으로 유명한 것은 Erlang의 &lt;a href=&quot;https://blog.stenmans.org/theBeamBook/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BEAM&lt;/a&gt;과 스칼라의 &lt;a href=&quot;https://akka.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AKKA&lt;/a&gt;가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Go와 Tokio에 비하면 상대적으로 오래된 런타임이긴 하지만 엑터도 보여줘야하지 않겠는가.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.thegreatcodeadventure.com/elixir-and-the-beam-how-concurrency-really-works/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Elixir&amp;nbsp;and&amp;nbsp;The&amp;nbsp;Beam:&amp;nbsp;How&amp;nbsp;Concurrency&amp;nbsp;Really&amp;nbsp;Works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.infoq.com/presentations/resilience-beam-erlang-otp/&quot;&gt;Unique&amp;nbsp;Resiliency&amp;nbsp;of&amp;nbsp;the&amp;nbsp;Erlang&amp;nbsp;VM,&amp;nbsp;the&amp;nbsp;BEAM&amp;nbsp;and&amp;nbsp;Erlang&amp;nbsp;OTP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.slideshare.net/hamidreza-s/beam-erlang-vm-as-a-soft-realtime-platform&quot;&gt;BEAM (Erlang VM) as a Soft Real-time Platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/AlexanderKaraberov/Erlang-BEAM-Links&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Erlang-Internals-Info&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.riak.com/riak/kv/latest/using/performance/erlang/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Erlang&amp;nbsp;VM&amp;nbsp;Tuning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Erlang의 VM의 &lt;a href=&quot;https://blog.stenmans.org/theBeamBook/#CH-Scheduling&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스케쥴링&lt;/a&gt;은 C수준에서 협력적이며, Erlang 수준에서는 선점적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언어 수준에서 재귀를 제외하고는 루프구조가 없으며 Tokio처럼 주어진 예산이 모두 감소(Reduction)하면 양보하는 형태다.&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;최대한 많은 스레드를 로드하려하는 compaction과 부하를 분산하는 balancing 모델이 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8YWFd/btrTQd6UgYX/N4FNJoSIi9TH4HaKkKO6YK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8YWFd/btrTQd6UgYX/N4FNJoSIi9TH4HaKkKO6YK/img.jpg&quot; width=&quot;1282&quot; height=&quot;962&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot; data-is-animation=&quot;false&quot; style=&quot;width: 63.4956%; margin-right: 10px;&quot; data-widthpercent=&quot;64.24&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8YWFd/btrTQd6UgYX/N4FNJoSIi9TH4HaKkKO6YK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8YWFd%2FbtrTQd6UgYX%2FN4FNJoSIi9TH4HaKkKO6YK%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;1280&quot; height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8j1UN/btrTR8Xv1xd/i2KmTNmJcGGxUSm7olGRqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8j1UN/btrTR8Xv1xd/i2KmTNmJcGGxUSm7olGRqk/img.png&quot; width=&quot;713&quot; height=&quot;961&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;1303&quot; data-is-animation=&quot;false&quot; style=&quot;width: 35.3416%;&quot; data-widthpercent=&quot;35.76&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8j1UN/btrTR8Xv1xd/i2KmTNmJcGGxUSm7olGRqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8j1UN%2FbtrTR8Xv1xd%2Fi2KmTNmJcGGxUSm7olGRqk%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;967&quot; height=&quot;1303&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://appunite.com/blog/concurrency-and-parallelism-with-elixir-and-beam&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Concurrency&amp;nbsp;and&amp;nbsp;parallelism&amp;nbsp;with&amp;nbsp;Elixir&amp;nbsp;and&amp;nbsp;BEAM&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;Erlang VM의 각 프로세스(Tokio의 태스크)는 격리된 자체적인 메모리 모델을 가지고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J9Ge8/btrTRGmBteM/3fR8IZMu3faJx2upjELQq0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J9Ge8/btrTRGmBteM/3fR8IZMu3faJx2upjELQq0/img.jpg&quot; width=&quot;1282&quot; height=&quot;962&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J9Ge8/btrTRGmBteM/3fR8IZMu3faJx2upjELQq0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ9Ge8%2FbtrTRGmBteM%2F3fR8IZMu3faJx2upjELQq0%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;1280&quot; height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCuKc3/btrTRfbPthZ/UHgm7WDrefdPaK3xcnZzsK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCuKc3/btrTRfbPthZ/UHgm7WDrefdPaK3xcnZzsK/img.jpg&quot; width=&quot;1282&quot; height=&quot;962&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCuKc3/btrTRfbPthZ/UHgm7WDrefdPaK3xcnZzsK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCuKc3%2FbtrTRfbPthZ%2FUHgm7WDrefdPaK3xcnZzsK%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;1280&quot; height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PCB(Process Control Block)는 정적&lt;/li&gt;
&lt;li&gt;Stack은 아래로, Heap은 위쪽 메모리 주소 방향으로 할당됨&lt;/li&gt;
&lt;li&gt;Stack과 Heap이 &lt;a href=&quot;https://github.com/erlang/otp/blob/master/erts/emulator/internal_doc/GarbageCollection.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;만나면 GC가 발생&lt;/a&gt;하며 충분한 메모리가 회수되지 않으면 커질 수 있음&lt;/li&gt;
&lt;li&gt;초기 메모리 주소는 233워드(64bit 기준 1.864kb)으로 매우 저렴함&lt;/li&gt;
&lt;li&gt;격리되어 있으므로 Stop the world 걱정에서 해방됨&lt;/li&gt;
&lt;li&gt;격리되어 있으므로 무한루프가 걸렸을 때 태스크를 kill 하기 쉬움&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;위와 같은 이유로 Erlang VM은 장애가 생겼을때도 고가용성을 제공하며 Soft Realtime 플랫폼으로 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스코드의 &lt;a href=&quot;https://discord.com/blog/how-discord-scaled-elixir-to-5-000-000-concurrent-users&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;Akka의 성능에 대한 게시물은 거의 찾아보기가 어려웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://scalac.io/blog/improving-akka-dispatchers/&quot;&gt;Improving&amp;nbsp;Akka&amp;nbsp;dispatchers&lt;/a&gt;&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;a href=&quot;https://blog.acolyer.org/2014/12/12/scala-actors-unifying-thread-based-and-event-based-programming/&quot;&gt;Scala&amp;nbsp;Actors:&amp;nbsp;Unifying&amp;nbsp;thread-based&amp;nbsp;and&amp;nbsp;event-based&amp;nbsp;programming&lt;/a&gt;, &amp;nbsp;&lt;a href=&quot;https://deepakpol.wordpress.com/2015/09/29/event-driven-and-reactive-architecture/&quot;&gt;Event&amp;nbsp;Driven&amp;nbsp;and&amp;nbsp;Reactive&amp;nbsp;Architecture&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Akka의 액터 시스템은 이벤트 루프와 비교했을때 다음과 같이 작동한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mGRxZ/btrTFKCHBK9/9nR9Phr3gwYzMWyjtFkkQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mGRxZ/btrTFKCHBK9/9nR9Phr3gwYzMWyjtFkkQk/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mGRxZ/btrTFKCHBK9/9nR9Phr3gwYzMWyjtFkkQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmGRxZ%2FbtrTFKCHBK9%2F9nR9Phr3gwYzMWyjtFkkQk%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;960&quot; height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jf15c/btrTDmiICTx/zyapmUXin1UaY37chu4qd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jf15c/btrTDmiICTx/zyapmUXin1UaY37chu4qd1/img.png&quot; style=&quot;width: 49.4186%;&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jf15c/btrTDmiICTx/zyapmUXin1UaY37chu4qd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJf15c%2FbtrTDmiICTx%2FzyapmUXin1UaY37chu4qd1%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;960&quot; height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;이벤트 vs 액터&lt;/figcaption&gt;
&lt;/figure&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;501&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bog2H1/btrTRexfspT/d3UR6mAK3aH3AT398mUK4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bog2H1/btrTRexfspT/d3UR6mAK3aH3AT398mUK4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bog2H1/btrTRexfspT/d3UR6mAK3aH3AT398mUK4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbog2H1%2FbtrTRexfspT%2Fd3UR6mAK3aH3AT398mUK4k%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;648&quot; height=&quot;501&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;501&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Sender는 Actor Ref에 메세지를 전달 (Actor자체는 격리되어 있어 접근할 수 없음)&lt;/li&gt;
&lt;li&gt;메세지 큐(메일박스)에 들어감&lt;/li&gt;
&lt;li&gt;메세지 디스패처가 스케쥴링에 따라 실행함&lt;/li&gt;
&lt;/ol&gt;
&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;Akka의 디스패처는 3종류,&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;고정: 각 액터가 자체 스레드 풀이 있는 CPU 바운드 작업용&lt;/li&gt;
&lt;li&gt;스레드: 한 스레드에서만 호출을 실행하며, 동시성을 제거해야할 때 사용&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 CPU 캐시를 최대한 이용하기 위해 으레 그랬듯 각 스레드에 대해 별도의 대기열을 만들고, 일관된 메일박스를 유지하기 위해 메일박스가 예약되면 전 실행과 동일한 스레드에서 실행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgLJOM/btrTQBl21Pb/fmiHWaTKeVL43AKbiMWkBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgLJOM/btrTQBl21Pb/fmiHWaTKeVL43AKbiMWkBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgLJOM/btrTQBl21Pb/fmiHWaTKeVL43AKbiMWkBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgLJOM%2FbtrTQBl21Pb%2FfmiHWaTKeVL43AKbiMWkBK%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;793&quot; height=&quot;422&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;422&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;Lock Free를 유지하기 위해 &lt;a href=&quot;https://en.wikipedia.org/wiki/Compare-and-swap&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CAS(Compare-and-swap)&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;Akka의 진정한 장점이라면 액터를 기반으로 엄청나게 많은 기능을 제공한다는 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.akka.io/docs/akka/current/typed/fsm.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FSM (Finite State Machine, 유한상태기계)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.akka.io/docs/akka/current/typed/fault-tolerance.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;결함허용&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.akka.io/docs/akka/current/typed/routers.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;라우팅&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.akka.io/docs/akka/current/stream/operators/PubSub/sink.html#pubsub-sink&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pub/Sub&lt;/a&gt;, &lt;a href=&quot;https://doc.akka.io/docs/akka/current/event-bus.html#classic-event-bus&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Event Bus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.akka.io/docs/akka/current/typed/index-persistence.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이벤트 소싱&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.akka.io/docs/akka/current/stream/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스트림&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.akka.io/docs/akka/current/typed/index-cluster.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cluster&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12. 병렬&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SIMD와 파이프라이닝&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SIMD(Single Instruction Multiple Data)는 SISD(Single Instruction Single Data)와 달리 1번의 명령어로 여러 개의 값을 동시에 계산할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csd1Kc/btrTQ00eQgQ/E7QA23MYNf4kVIBGr8DSs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csd1Kc/btrTQ00eQgQ/E7QA23MYNf4kVIBGr8DSs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csd1Kc/btrTQ00eQgQ/E7QA23MYNf4kVIBGr8DSs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcsd1Kc%2FbtrTQ00eQgQ%2FE7QA23MYNf4kVIBGr8DSs0%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;782&quot; height=&quot;398&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.naver.com/fs0608/221650925743&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SIMD&amp;nbsp;(Single&amp;nbsp;Instruction&amp;nbsp;Multiple&amp;nbsp;Data)에&amp;nbsp;대한&amp;nbsp;집중탐구!&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU에 있는 파이프라인과 분기예측을 최대한 이용할 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK5EBr/btrTPU7JQvb/c8QdUChhzZS8bjKKXVykWK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK5EBr/btrTPU7JQvb/c8QdUChhzZS8bjKKXVykWK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK5EBr/btrTPU7JQvb/c8QdUChhzZS8bjKKXVykWK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK5EBr%2FbtrTPU7JQvb%2Fc8QdUChhzZS8bjKKXVykWK%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;960&quot; height=&quot;720&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://slideplayer.com/slide/2406323/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Instruction-Level&amp;nbsp;Parallelism&amp;nbsp;and&amp;nbsp;Superscalar&amp;nbsp;Processors&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 최대한 이용한 라이브러리 &lt;a href=&quot;https://www.pola.rs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Polars&lt;/a&gt;의&amp;nbsp;&lt;a href=&quot;https://www.ritchievink.com/blog/2021/02/28/i-wrote-one-of-the-fastest-dataframe-libraries/&quot;&gt;I wrote one of the fastest DataFrame libraries&lt;/a&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;OpenMP &amp;amp; MPI&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ipcc.cs.uoregon.edu/lectures/lecture-5-patterns.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Parallel&amp;nbsp;Programming&amp;nbsp;Patterns&amp;nbsp;Overview&amp;nbsp;and&amp;nbsp;Map&amp;nbsp;Pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ipcc.cs.uoregon.edu/lectures/lecture-9-fork-join.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fork-Join&amp;nbsp;Pattern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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://www.openmp.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OpenMP&lt;/a&gt;가 대표적인 예이며 for 루프의 부하를 map-reduce 방식으로 적절히 계산해준다고 생각하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;899&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKybaE/btrPmDnqdC7/Jgd9jKhG3kJA4tHwKwWylK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKybaE/btrPmDnqdC7/Jgd9jKhG3kJA4tHwKwWylK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKybaE/btrPmDnqdC7/Jgd9jKhG3kJA4tHwKwWylK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKybaE%2FbtrPmDnqdC7%2FJgd9jKhG3kJA4tHwKwWylK%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;1200&quot; height=&quot;899&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;899&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://princetonuniversity.github.io/PUbootcamp/sessions/parallel-programming/Intro_PP_bootcamp_2018.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introduction&amp;nbsp;to&amp;nbsp;Parallel&amp;nbsp;Programming&amp;nbsp;with&amp;nbsp;MPI&amp;nbsp;and&amp;nbsp;OpenMP&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;반대로 메세지 패싱 스타일인 MPI도 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8hzgV/btrTR06oemO/gG0YBwmYDWYAhYl1Zya8ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8hzgV/btrTR06oemO/gG0YBwmYDWYAhYl1Zya8ck/img.png&quot; width=&quot;480&quot; height=&quot;480&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;306&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.9348%; margin-right: 10px;&quot; data-widthpercent=&quot;46.48&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8hzgV/btrTR06oemO/gG0YBwmYDWYAhYl1Zya8ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8hzgV%2FbtrTR06oemO%2FgG0YBwmYDWYAhYl1Zya8ck%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;676&quot; height=&quot;306&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGrcFu/btrTRBZ6kkk/3NozAQTMUZKINaeKh4z9MK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGrcFu/btrTRBZ6kkk/3NozAQTMUZKINaeKh4z9MK/img.png&quot; width=&quot;480&quot; height=&quot;480&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;226&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.9024%;&quot; data-widthpercent=&quot;53.52&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGrcFu/btrTRBZ6kkk/3NozAQTMUZKINaeKh4z9MK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGrcFu%2FbtrTRBZ6kkk%2F3NozAQTMUZKINaeKh4z9MK%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;575&quot; height=&quot;226&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hpc.nmsu.edu/discovery/mpi/introduction/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Message&amp;nbsp;Passing&amp;nbsp;Interface&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;공유메모리인 OpenMP, 분산된 스타일인 MPI 둘의 장점을 모두 이용하기 위해 다음과 같이 하이브리드 방식으로 사용하기도 한다. (NUMA의 관점에서도 생각해볼 수 있을 듯)&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIy29J/btrTP3DmQj5/HTwUmMhnUUnAxiIWrcLI71/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIy29J/btrTP3DmQj5/HTwUmMhnUUnAxiIWrcLI71/img.gif&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;388&quot; data-is-animation=&quot;false&quot; style=&quot;width: 23.8579%; margin-right: 10px;&quot; data-widthpercent=&quot;24.14&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIy29J/btrTP3DmQj5/HTwUmMhnUUnAxiIWrcLI71/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIy29J%2FbtrTP3DmQj5%2FHTwUmMhnUUnAxiIWrcLI71%2Fimg.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;495&quot; height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eajxOP/btrTP4PQ2jN/VhTDLDWZ9VUKylNAY0otYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eajxOP/btrTP4PQ2jN/VhTDLDWZ9VUKylNAY0otYK/img.png&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;212&quot; data-is-animation=&quot;false&quot; style=&quot;width: 74.9793%;&quot; data-widthpercent=&quot;75.86&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eajxOP/btrTP4PQ2jN/VhTDLDWZ9VUKylNAY0otYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeajxOP%2FbtrTP4PQ2jN%2FVhTDLDWZ9VUKylNAY0otYK%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;850&quot; height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.tezu.ernet.in/dcompsc/facility/HPCC/hypack/hypack13-mode01-multicore-mpi-openmp.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;hyPACK-2013 Mode-1 : Mixed Mode of Programming MPI- OpenMP&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://www.researchgate.net/figure/Hybrid-parallelization-of-the-solver-MPI-message-passing-interface_fig5_327534000&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Parallel&amp;nbsp;multibody&amp;nbsp;separation&amp;nbsp;simulation&amp;nbsp;using&amp;nbsp;MPI&amp;nbsp;and&amp;nbsp;OpenMP&amp;nbsp;with&amp;nbsp;communication&amp;nbsp;optimization&lt;/a&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Cilk&quot;&gt;Cilk&lt;/a&gt;는 for 루프뿐만 아니라 spawn 시에도 적절히 병렬화가 되도록 만들어준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O65hF/btrTR8JYe7f/nfKHglG474OpNBt0hJ00A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O65hF/btrTR8JYe7f/nfKHglG474OpNBt0hJ00A0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O65hF/btrTR8JYe7f/nfKHglG474OpNBt0hJ00A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO65hF%2FbtrTR8JYe7f%2FnfKHglG474OpNBt0hJ00A0%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;1200&quot; height=&quot;674&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ucbrise.github.io/cs262a-spring2018/notes/20-Cilk-OpenMP.pdf&quot;&gt;Cilk&amp;nbsp;and&amp;nbsp;OpenMP&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;a href=&quot;https://en.wikipedia.org/wiki/Parent_pointer_tree&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cactus Stack&lt;/a&gt;의 스택포인터가 부모에서 자식으로만 전달된다는 점을 이용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sBo4K/btrTR9oAHke/0vVv4lXL1byhkKVjJkkXr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sBo4K/btrTR9oAHke/0vVv4lXL1byhkKVjJkkXr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sBo4K/btrTR9oAHke/0vVv4lXL1byhkKVjJkkXr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsBo4K%2FbtrTR9oAHke%2F0vVv4lXL1byhkKVjJkkXr0%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;1200&quot; height=&quot;674&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;674&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;또한 Cilk는 워크스틸링을 지원한다는 점이 특징이라면 특징.&lt;/p&gt;
&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://www4.cs.fau.de/~flow/papers/schmaus2021nowa.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nowa&lt;/a&gt;(&lt;a href=&quot;https://github.com/black7375/nowa&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;소스코드&lt;/a&gt;)는 Wait-Free를 달성하기 위해 컨티뉴에션 스틸링(Continuation Stealing)을 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJHpSn/btrTR0ed8Hi/OzArnV8uVaVoDLKckqdpU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJHpSn/btrTR0ed8Hi/OzArnV8uVaVoDLKckqdpU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJHpSn/btrTR0ed8Hi/OzArnV8uVaVoDLKckqdpU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJHpSn%2FbtrTR0ed8Hi%2FOzArnV8uVaVoDLKckqdpU1%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;952&quot; height=&quot;350&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;350&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;459&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RvVMl/btrTT8bFfYa/oo6ExJLkleKQDcoCWuPGpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RvVMl/btrTT8bFfYa/oo6ExJLkleKQDcoCWuPGpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RvVMl/btrTT8bFfYa/oo6ExJLkleKQDcoCWuPGpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRvVMl%2FbtrTT8bFfYa%2Foo6ExJLkleKQDcoCWuPGpK%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;1280&quot; height=&quot;459&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;459&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://www4.cs.fau.de/~flow/papers/schmaus2021modern.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Emper&lt;/a&gt;(&lt;a href=&quot;https://gitlab.cs.fau.de/i4/manycore/emper&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;소스코드&lt;/a&gt;)는 지금까지 나온 방법 대부분이 거의 사용되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KTfir/btrTQBzClDh/cc8Gu9vNQICurclmDrOn11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KTfir/btrTQBzClDh/cc8Gu9vNQICurclmDrOn11/img.png&quot; data-origin-width=&quot;699&quot; data-origin-height=&quot;691&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.2458%; margin-right: 10px;&quot; data-widthpercent=&quot;49.83&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KTfir/btrTQBzClDh/cc8Gu9vNQICurclmDrOn11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKTfir%2FbtrTQBzClDh%2Fcc8Gu9vNQICurclmDrOn11%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;699&quot; height=&quot;691&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwjflm/btrTQQXJDBX/OFM8ep2OgOd1CjRZC0ENUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwjflm/btrTQQXJDBX/OFM8ep2OgOd1CjRZC0ENUK/img.png&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;696&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50.17&quot; style=&quot;width: 49.5914%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwjflm/btrTQQXJDBX/OFM8ep2OgOd1CjRZC0ENUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbwjflm%2FbtrTQQXJDBX%2FOFM8ep2OgOd1CjRZC0ENUK%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;709&quot; height=&quot;696&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IO Uring&lt;/li&gt;
&lt;li&gt;컨티뉴에이션 스틸링&lt;/li&gt;
&lt;li&gt;Local, Global 스케쥴링&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www4.cs.fau.de/~flow/papers/pfeiffer2020cactus.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wait-free Cactus Stack&lt;/a&gt;&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;a href=&quot;https://github.com/rayon-rs/rayon&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rayon&lt;/a&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;a href=&quot;https://developers.redhat.com/blog/2021/04/30/how-rust-makes-rayons-data-parallelism-magical&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;Rust&amp;nbsp;makes&amp;nbsp;Rayon's&amp;nbsp;data&amp;nbsp;parallelism&amp;nbsp;magical&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://smallcultfollowing.com/babysteps/blog/2015/12/18/rayon-data-parallelism-in-rust/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rayon:&amp;nbsp;data&amp;nbsp;parallelism&amp;nbsp;in&amp;nbsp;Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://morestina.net/blog/1432/parallel-stream-processing-with-rayon&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Parallel&amp;nbsp;stream&amp;nbsp;processing&amp;nbsp;with&amp;nbsp;Rayon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 넓은 범위, 아키텍처 레벨에서 병렬에 특화된 구조도 존재한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다(Lambda) 아키텍처&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvh3UQ/btrTP4bgVlw/WdOmJgznnFjFQbCnxiVsg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvh3UQ/btrTP4bgVlw/WdOmJgznnFjFQbCnxiVsg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvh3UQ/btrTP4bgVlw/WdOmJgznnFjFQbCnxiVsg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdvh3UQ%2FbtrTP4bgVlw%2FWdOmJgznnFjFQbCnxiVsg1%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;670&quot; height=&quot;277&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://blog.skby.net/%EB%9E%8C%EB%8B%A4-%EC%B9%B4%ED%8C%8C-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;람다,&amp;nbsp;카파&amp;nbsp;아키텍처&lt;/a&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;서빙 레이어: 배치와 스피드 레이어의 정보를 조합한다.&amp;nbsp;&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;카파(Kappa) 아키텍처는 보다 단순하게 스피드 레이어를 통과해 배치 계층에 저장되는 형태다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDH5cL/btrTPRQL1Tz/nmkm5819KEIZACJY5xgIDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDH5cL/btrTPRQL1Tz/nmkm5819KEIZACJY5xgIDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDH5cL/btrTPRQL1Tz/nmkm5819KEIZACJY5xgIDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDH5cL%2FbtrTPRQL1Tz%2Fnmkm5819KEIZACJY5xgIDk%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;816&quot; height=&quot;182&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;182&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://blog.jetbrains.com/blog/2021/05/27/big-data-world-part-4-architecture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Big Data World, Part 4: Architecture&lt;/a&gt;나 마이크로소프트의 &lt;a href=&quot;https://learn.microsoft.com/ko-kr/azure/architecture/data-guide/big-data/&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;h3 data-ke-size=&quot;size23&quot;&gt;13. GPU&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파이프라인과 쉐이더&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://fgiesen.wordpress.com/2011/07/09/a-trip-through-the-graphics-pipeline-2011-index/&quot;&gt;A&amp;nbsp;trip&amp;nbsp;through&amp;nbsp;the&amp;nbsp;Graphics&amp;nbsp;Pipeline&amp;nbsp;2011:&amp;nbsp;Index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.nvidia.com/gpugems/gpugems/part-v-performance-and-practicalities/chapter-28-graphics-pipeline-performance&quot;&gt;Graphics&amp;nbsp;Pipeline&amp;nbsp;Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://slideplayer.com/slide/17356723/&quot;&gt;Balancing&amp;nbsp;the&amp;nbsp;Graphics&amp;nbsp;Pipeline&amp;nbsp;for&amp;nbsp;Optimal&amp;nbsp;Performance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 처리의 또 다른 핫한 분야는 GPU일 것이다.&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;723&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWaARc/btrTSLnvWYA/dGL7HKpvukBeKXKypCgqQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWaARc/btrTSLnvWYA/dGL7HKpvukBeKXKypCgqQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWaARc/btrTSLnvWYA/dGL7HKpvukBeKXKypCgqQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWaARc%2FbtrTSLnvWYA%2FdGL7HKpvukBeKXKypCgqQ1%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;723&quot; height=&quot;270&quot; data-origin-width=&quot;723&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://graphicscompendium.com/intro/01-graphics-pipeline&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Graphics&amp;nbsp;Pipeline&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;825&quot; data-origin-height=&quot;465&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mC9Yh/btrTVhgfVUJ/WHMTdG09CoMCP944GRcPp0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mC9Yh/btrTVhgfVUJ/WHMTdG09CoMCP944GRcPp0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mC9Yh/btrTVhgfVUJ/WHMTdG09CoMCP944GRcPp0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmC9Yh%2FbtrTVhgfVUJ%2FWHMTdG09CoMCP944GRcPp0%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;825&quot; height=&quot;465&quot; data-origin-width=&quot;825&quot; data-origin-height=&quot;465&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.siggraph.org/2021/04/mesh-shaders-release-the-intrinsic-power-of-a-gpu.html/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mesh&amp;nbsp;Shaders&amp;nbsp;Release&amp;nbsp;the&amp;nbsp;Intrinsic&amp;nbsp;Power&amp;nbsp;of&amp;nbsp;a&amp;nbsp;GPU&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Introduction&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vulkan 튜토리얼&lt;/a&gt;, &lt;a href=&quot;https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OpenGL 위키&lt;/a&gt;나 Direct3D(&lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/win32/direct3d11/overviews-direct3d-11-graphics-pipeline&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;11&lt;/a&gt;, &lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/win32/direct3d12/pipelines-and-shaders-with-directx-12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;12&lt;/a&gt;) 문서에 보다 자세히 나와있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;입력 어셈블러(Input Assembler): 인덱스 버퍼를 통해 중복되는 꼭지점(Vertex)를 제거&lt;/li&gt;
&lt;li&gt;꼭지점 쉐이더(Vertex Shader): 모든 정점(Vertex)에 대해 실행되며, 변환(Transformation)이나 모핑(Morphing) 같은 작업을 한다&lt;/li&gt;
&lt;li&gt;테셀레이션(Tessellation): 특정 규칙에 따라 표면 세부 정보(subdivide geometry)를 그려 메시 품질을 높힘&lt;/li&gt;
&lt;li&gt;기하 도형 쉐이더(Geometry Shader): 모든 프리미티브(삼각형, 선, 점)에서 실행되며, 이를 버리거나 더 많은 프리미티브를 출력할 수 있음.&lt;/li&gt;
&lt;li&gt;래스터화(Rasterization): 프리미티브의 벡터 정보를 래스터 이미지(픽셀)로 만듦&lt;br /&gt;조각(Fragment)으로 구성되고 화면 밖 조각들은 모두 버려지며, 꼭지점 쉐이더가 출력한 속성들은 보간됨&lt;br /&gt;다른 조각의 뒤(z-index, depth)에 있는 조각들 또한 버려질 수 있음&lt;/li&gt;
&lt;li&gt;프레그먼트 쉐이더(Fragment Shader): 살아남은 모든 조각들에 대해 호출되며, 기록될 프레임 버퍼와 색상 및 깊이 값을 결정함&lt;br /&gt;텍스쳐(Texture) 좌표나 조명의 법선(normals for lighting)등도 포함될 수 있음&lt;/li&gt;
&lt;li&gt;컬러 블렌딩(Color Blending): 프레임 버퍼의 동일한 픽셀에 매핑되는 다른 조각을 혼합함&lt;br /&gt;투명도에 따라 덮어쓰거나 추가, 혼합될 수 있음&lt;/li&gt;
&lt;li&gt;프레임 버퍼(Frame Buffer): 다음 화면에 그려질 정보를 담는 메모리로 출력의 목적지&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 어셈블러/레스터화/컬러 블랜딩은 작업방식이 정해져 있으나 쉐이더를 활용할 수 있는 Vertex, Tessellation, Geometry, Fragment 단계는 코드를 GPU에 업로드해 프로그래머가 원하는 작업 방식을 정의할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://blog.hybrid3d.dev/2020-12-21-reason-for-slow-of-if-statement-in-shader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;쉐이더에서&amp;nbsp;IF&amp;nbsp;문이&amp;nbsp;느린&amp;nbsp;이유&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://xdpixel.com/how-to-avoid-branching-on-the-gpu/&quot;&gt;How&amp;nbsp;to&amp;nbsp;Avoid&amp;nbsp;Branching&amp;nbsp;on&amp;nbsp;the&amp;nbsp;GPU&lt;/a&gt;&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;a href=&quot;https://www.khronos.org/opengl/wiki/Compute_Shader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;컴퓨트 쉐이더&lt;/a&gt;는 그래픽 파이프라인에서 벗어나 GPGPU로 활용할 수 있게 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nvidia의 &lt;a href=&quot;https://developer.nvidia.com/blog/introduction-turing-mesh-shaders/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mesh 쉐이더&lt;/a&gt;가 활용 예. [AMD는 프리미티브 쉐이더[&lt;a href=&quot;https://gigglehd.com/gg/?mid=hard&amp;amp;document_srl=1533856&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;소개&lt;/a&gt;, &lt;a href=&quot;https://www.resetera.com/threads/primitive-shader-amds-patent-deep-dive.186831/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;분석&lt;/a&gt;]를 밀었는데 최근 소식이 없다].&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dg6sJt/btrTSv7i3Zo/2BlxCEj4cpRsZKiVMoWWi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dg6sJt/btrTSv7i3Zo/2BlxCEj4cpRsZKiVMoWWi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dg6sJt/btrTSv7i3Zo/2BlxCEj4cpRsZKiVMoWWi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdg6sJt%2FbtrTSv7i3Zo%2F2BlxCEj4cpRsZKiVMoWWi0%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;948&quot; height=&quot;474&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.khronos.org/assets/uploads/developers/presentations/opengl46-quick-reference-card.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OpenGL&amp;nbsp;4.6&amp;nbsp;API&amp;nbsp;Reference&amp;nbsp;Guide&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLkaHi/btrTRB1jojq/XLhKWp2wUgkvgz4n6J9U01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLkaHi/btrTRB1jojq/XLhKWp2wUgkvgz4n6J9U01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLkaHi/btrTRB1jojq/XLhKWp2wUgkvgz4n6J9U01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLkaHi%2FbtrTRB1jojq%2FXLhKWp2wUgkvgz4n6J9U01%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;935&quot; height=&quot;512&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.khronos.org/assets/uploads/developers/presentations/vulkan11-reference-guide.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vulkan&amp;nbsp;1.1&amp;nbsp;Reference&amp;nbsp;Guide&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;모바일 GPU의 경우 타일 기반의 렌더링을 가지고 있기도 하다. [&lt;a href=&quot;https://www.rastergrid.com/blog/gpu-tech/2021/07/gpu-architecture-types-explained/&quot;&gt;GPU architecture types explained&lt;/a&gt;, &lt;a href=&quot;https://gitea.yiem.net/QianMo/Real-Time-Rendering-4th-Bibliography-Collection/raw/branch/main/Chapter%201-24/[1200]%20[OpenGL%20Insights%202012]%20Performance%20Tuning%20for%20Tile-Based%20Architectures.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Performance Tuning for Tile-Based Architectures&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://blog.imaginationtech.com/a-look-at-the-powervr-graphics-architecture-tile-based-rendering/&quot;&gt;A look at the PowerVR graphics architecture: Tile-based rendering&lt;/a&gt;, &lt;a href=&quot;https://github.com/anonymousjustice/pvr-pi/blob/master/SDKPackage_OGLES2/Documentation/PowerVR%20Series%205.SGX%20Architecture%20Guide%20for%20Developers.1.0.13.External.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PowerVR&amp;nbsp;Series&amp;nbsp;5&amp;nbsp;SGX&amp;nbsp;Architecture&amp;nbsp;Guide&amp;nbsp;for&amp;nbsp;Developers&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbOt5l/btrTSxD5lKl/wTgVxQAz36g2lORMLPbNK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbOt5l/btrTSxD5lKl/wTgVxQAz36g2lORMLPbNK1/img.png&quot; width=&quot;600&quot; data-original=&quot;https://di.gameres.com/attachment/forum/202001/02/133242hgws26ztu21gz0w2.png&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;271&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.2961%; margin-right: 10px;&quot; data-widthpercent=&quot;55.95&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbOt5l/btrTSxD5lKl/wTgVxQAz36g2lORMLPbNK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbOt5l%2FbtrTSxD5lKl%2FwTgVxQAz36g2lORMLPbNK1%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;756&quot; height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wwkox/btrTWNss86b/RlPk2qCK7t7xYuFoJ1iFFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wwkox/btrTWNss86b/RlPk2qCK7t7xYuFoJ1iFFk/img.png&quot; data-origin-width=&quot;391&quot; data-origin-height=&quot;178&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.5411%;&quot; data-widthpercent=&quot;44.05&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wwkox/btrTWNss86b/RlPk2qCK7t7xYuFoJ1iFFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWwkox%2FbtrTWNss86b%2FRlPk2qCK7t7xYuFoJ1iFFk%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;391&quot; height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;타일 렌더링, 지연 렌더링&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타일 기반 지연 렌더링(TBDR, Tile-Based Deffered Rendering)은 바로 그려주는 즉시모드 렌더링(IMR, Immediate-Mode Rendering)과 달리 타일로 만들어 저장/로드한다. (2 path)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TXMPY/btrTTo7Y1nP/MDX4BZnhfIxdE9KNnLxjTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TXMPY/btrTTo7Y1nP/MDX4BZnhfIxdE9KNnLxjTK/img.png&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;326&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.5831%; margin-right: 10px;&quot; data-widthpercent=&quot;54.21&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TXMPY/btrTTo7Y1nP/MDX4BZnhfIxdE9KNnLxjTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTXMPY%2FbtrTTo7Y1nP%2FMDX4BZnhfIxdE9KNnLxjTK%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;326&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKJI2n/btrTRpT9pt7/coyzP38sKauI5DkBfdpQl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKJI2n/btrTRpT9pt7/coyzP38sKauI5DkBfdpQl0/img.png&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;386&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.2541%;&quot; data-widthpercent=&quot;45.79&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKJI2n/btrTRpT9pt7/coyzP38sKauI5DkBfdpQl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKJI2n%2FbtrTRpT9pt7%2FcoyzP38sKauI5DkBfdpQl0%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;386&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;IMR vs TBDR&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;프레임 전체를 다루는 IMR에 비해 대역폭을 적게 소모(4K 모니터를 쓴다고 생각해보자)&lt;/li&gt;
&lt;li&gt;타일의 크기가 적으므로 제약되는 SRAM만으로도 복잡한 렌더링을 수행할 수 있음&lt;/li&gt;
&lt;li&gt;지연 렌더링을 사용할 경우, 뒤에 있는 물체는 그리지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지연 렌더링에서 Geometry와 Fragement 사이에서 타일을 저장하기 위해 DRAM을 접근하여 캐시에서 손해&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;위와같이 여러 장점을 가지고 있기에 최신 PC GPU들도 &lt;a href=&quot;https://www.techpowerup.com/231129/on-nvidias-tile-based-rendering&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;타일기반 렌더링을 도입&lt;/a&gt;하고 있다. (지연 렌더링은 아님)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5fvj7/btrTSxxoqoV/vWJKi3BhYfrwcp4No9eQVK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5fvj7/btrTSxxoqoV/vWJKi3BhYfrwcp4No9eQVK/img.jpg&quot; data-alt=&quot;Ndivia의 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5fvj7/btrTSxxoqoV/vWJKi3BhYfrwcp4No9eQVK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5fvj7%2FbtrTSxxoqoV%2FvWJKi3BhYfrwcp4No9eQVK%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Ndivia의 방식&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;a href=&quot;https://github.com/nical/lyon/wiki/Related-projects&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;벡터 그래픽까지 GPU에서 실행&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;a href=&quot;https://cvw.cac.cornell.edu/GPUarch/simt_warp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SIMT(Single Instruction MultiThread)&lt;/a&gt;에 대해서도 알아보기 바란다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccfmsh/btrUuA7psrZ/CEbwWh79tFXUtOMJyDneJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccfmsh/btrUuA7psrZ/CEbwWh79tFXUtOMJyDneJ0/img.png&quot; data-origin-width=&quot;1231&quot; data-origin-height=&quot;403&quot; data-is-animation=&quot;false&quot; style=&quot;width: 65.7821%; margin-right: 10px;&quot; data-widthpercent=&quot;66.56&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccfmsh/btrUuA7psrZ/CEbwWh79tFXUtOMJyDneJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fccfmsh%2FbtrUuA7psrZ%2FCEbwWh79tFXUtOMJyDneJ0%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;1231&quot; height=&quot;403&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MskjG/btrUurijdqc/09v5k7qXy3vPkTpWkaxJbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MskjG/btrUurijdqc/09v5k7qXy3vPkTpWkaxJbk/img.png&quot; data-origin-width=&quot;1231&quot; data-origin-height=&quot;802&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 33.0551%;&quot; data-widthpercent=&quot;33.44&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MskjG/btrUurijdqc/09v5k7qXy3vPkTpWkaxJbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMskjG%2FbtrUurijdqc%2F09v5k7qXy3vPkTpWkaxJbk%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;1231&quot; height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.irisa.fr/alf/downloads/collange/talks/collange_warp_synchronous_19.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Warp-synchronous&amp;nbsp;programming&amp;nbsp;with&amp;nbsp;Cooperative&amp;nbsp;Groups&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;벡터 데이터에 동일한 작업을 병렬로 실행하는 SIMD와 달리 여러 스레드가 임의 데이터에 공통적인 명령을 실행하므로 분기명령등에서 차이가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVkBkX/btrUs25ajEE/xizqcU9CgYjVpRj8Pgkxk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVkBkX/btrUs25ajEE/xizqcU9CgYjVpRj8Pgkxk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVkBkX/btrUs25ajEE/xizqcU9CgYjVpRj8Pgkxk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVkBkX%2FbtrUs25ajEE%2FxizqcU9CgYjVpRj8Pgkxk0%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;625&quot; height=&quot;203&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.nvidia.com/blog/using-cuda-warp-level-primitives/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Using&amp;nbsp;CUDA&amp;nbsp;Warp-Level&amp;nbsp;Primitives&lt;/a&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digi.com/resources/documentation/digidocs/90001945-13/reference/yocto/r_an_adding_custom_display.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Adding&amp;nbsp;a&amp;nbsp;custom&amp;nbsp;display&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gpureport.cz/clanky/61-graficka-pipeline4-monitor/uvod.aspx?article=61&amp;amp;page=1&quot;&gt;Grafick&amp;aacute; pipeline IV: Monitor&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LCD 모니터를 사용한다면 다음과 같이 보여진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dc93KT/btrUcfBXrES/4dv9vvpAUK4v8QEGlTKflK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dc93KT/btrUcfBXrES/4dv9vvpAUK4v8QEGlTKflK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dc93KT/btrUcfBXrES/4dv9vvpAUK4v8QEGlTKflK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdc93KT%2FbtrUcfBXrES%2F4dv9vvpAUK4v8QEGlTKflK%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;960&quot; height=&quot;600&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수직동기화(V-Sync): 프레임 시작&lt;/li&gt;
&lt;li&gt;수평동기화(H-Sync): 라인 시작&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;수직 동기화에 의해 프레임이 시작되 위에서 아래쪽으로 출력되며, 이는 전자빔을 이동하며 쏘는 CRT 모니터의 호환성을 위한 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;227&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAJ5oL/btrT9yJQkrZ/kXJA3pvkK5KXGpwE2T2E3k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAJ5oL/btrT9yJQkrZ/kXJA3pvkK5KXGpwE2T2E3k/img.gif&quot; data-alt=&quot;CRT 모니터의 표현방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAJ5oL/btrT9yJQkrZ/kXJA3pvkK5KXGpwE2T2E3k/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cAJ5oL/btrT9yJQkrZ/kXJA3pvkK5KXGpwE2T2E3k/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;326&quot; height=&quot;227&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;227&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CRT 모니터의 표현방식&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;보통의 모니터는 초당 60프레임을 표시할 수 있다. (60Hz)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;16.66ms당 1장씩 보여주어야 한다는 뜻.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;199&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfdZsz/btrUeJP9ZVf/Yu2Am0iOJcHHaz6qNxZYC0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfdZsz/btrUeJP9ZVf/Yu2Am0iOJcHHaz6qNxZYC0/img.gif&quot; data-alt=&quot;60Hz 모니터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfdZsz/btrUeJP9ZVf/Yu2Am0iOJcHHaz6qNxZYC0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cfdZsz/btrUeJP9ZVf/Yu2Am0iOJcHHaz6qNxZYC0/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;550&quot; height=&quot;199&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;199&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;60Hz 모니터&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;여기서 조심해야할 점은 모니터 주사율(Display refresh rate)과 GPU의 프레임 레이트(Frame rate)를 구분하자는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A05qA/btrUh1cv7vk/MDr5WNGrnFpnTlsVBHk2U0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A05qA/btrUh1cv7vk/MDr5WNGrnFpnTlsVBHk2U0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A05qA/btrUh1cv7vk/MDr5WNGrnFpnTlsVBHk2U0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA05qA%2FbtrUh1cv7vk%2FMDr5WNGrnFpnTlsVBHk2U0%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;1149&quot; height=&quot;322&quot; data-origin-width=&quot;1149&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.techspot.com/news/83036-nvidia-high-framerates-could-lead-significantly-better-kd.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nvidia:&amp;nbsp;High&amp;nbsp;frame&amp;nbsp;rates&amp;nbsp;could&amp;nbsp;lead&amp;nbsp;to&amp;nbsp;significantly&amp;nbsp;better&amp;nbsp;K/D&amp;nbsp;ratios&amp;nbsp;in&amp;nbsp;competitive&amp;nbsp;titles&lt;/a&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a id=&quot;AppHeader-notifications-button&quot; href=&quot;https://github.com/notifications&quot; data-hotkey=&quot;g n&quot; data-target=&quot;notification-indicator.link&quot; data-analytics-event=&quot;{&amp;quot;category&amp;quot;:&amp;quot;Header&amp;quot;,&amp;quot;action&amp;quot;:&amp;quot;go to notifications&amp;quot;,&amp;quot;label&amp;quot;:&amp;quot;icon:read&amp;quot;}&quot;&gt; &lt;/a&gt;&lt;a id=&quot;AppHeader-notifications-button&quot; href=&quot;https://github.com/notifications&quot; data-hotkey=&quot;g n&quot; data-target=&quot;notification-indicator.link&quot; data-analytics-event=&quot;{&amp;quot;category&amp;quot;:&amp;quot;Header&amp;quot;,&amp;quot;action&amp;quot;:&amp;quot;go to notifications&amp;quot;,&amp;quot;label&amp;quot;:&amp;quot;icon:read&amp;quot;}&quot;&gt; &lt;/a&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Multiple_buffering&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Multiple&amp;nbsp;buffering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.embedded-wizard.de/framebuffer-concepts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Platform&amp;nbsp;Integration&amp;nbsp;Aspects:&amp;nbsp;Framebuffer&amp;nbsp;Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/MTLBestPracticesGuide/TripleBuffering.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Triple&amp;nbsp;Buffering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raphlinus.github.io/ui/graphics/gpu/2021/10/22/swapchain-frame-pacing.html&quot;&gt;Swapchains&amp;nbsp;and&amp;nbsp;frame&amp;nbsp;pacing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU가 프레임버퍼를 갱신하면, (최신 그래픽 시스템에서는 프레임버퍼가 비디오 메모리에 존재)&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;524&quot; data-origin-height=&quot;285&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czhOx5/btrT4RojIKd/HYQPG7vHsHXhNbq6OMbA4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czhOx5/btrT4RojIKd/HYQPG7vHsHXhNbq6OMbA4k/img.png&quot; data-alt=&quot;싱글 버퍼&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czhOx5/btrT4RojIKd/HYQPG7vHsHXhNbq6OMbA4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczhOx5%2FbtrT4RojIKd%2FHYQPG7vHsHXhNbq6OMbA4k%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;524&quot; height=&quot;285&quot; data-origin-width=&quot;524&quot; data-origin-height=&quot;285&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;프레임 버퍼에 쓰는 속도가 읽는 속도보다 느리기 때문에 깜박임(Flickering)이나 티어링(Tearing) 발생하는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 60FPS를 달성해야 깜박임이 없다고들 설명한다.&lt;/p&gt;
&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;버퍼를 하나를 추가해 미리 정보를 써놓고 복사를 하거나 교환(Swap)을 하자는 말이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lGBWo/btrUeLgaEqW/DZWkbFHek8otyOEUsNku1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lGBWo/btrUeLgaEqW/DZWkbFHek8otyOEUsNku1K/img.png&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;287&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.4546%; margin-right: 10px;&quot; data-widthpercent=&quot;54.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lGBWo/btrUeLgaEqW/DZWkbFHek8otyOEUsNku1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlGBWo%2FbtrUeLgaEqW%2FDZWkbFHek8otyOEUsNku1K%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;597&quot; height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XFLR7/btrT5a82rea/STyMhT3APTUuu8mn8VQlGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XFLR7/btrT5a82rea/STyMhT3APTUuu8mn8VQlGk/img.png&quot; data-origin-width=&quot;551&quot; data-origin-height=&quot;312&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;45.92&quot; style=&quot;width: 45.3826%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XFLR7/btrT5a82rea/STyMhT3APTUuu8mn8VQlGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXFLR7%2FbtrT5a82rea%2FSTyMhT3APTUuu8mn8VQlGk%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;551&quot; height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;복사 vs 교환&lt;/figcaption&gt;
&lt;/figure&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;br /&gt;여전히 쓰기가 읽기보다 느리므로 변경이 많은 경우 적합하지 않다&lt;/li&gt;
&lt;li&gt;교환: 프론트와 백버퍼를 완전히 바꾸는 방식&lt;br /&gt;기본적으로 소모하는 리소스가 많으므로 변경이 적은 경우 불리&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;맞바꾸는 작업을 플리핑(Flipping), 변경가능한 버퍼 컬렉션을 &lt;a href=&quot;https://en.wikipedia.org/wiki/Swap_chain&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스왑체인(Swap Chain)&lt;/a&gt;이라고 부른다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YbXN9/btrUeK2BCLt/ufQkvAL7W5kb83QuSPZfhK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YbXN9/btrUeK2BCLt/ufQkvAL7W5kb83QuSPZfhK/img.gif&quot; data-alt=&quot;플리핑(Flipping)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YbXN9/btrUeK2BCLt/ufQkvAL7W5kb83QuSPZfhK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/YbXN9/btrUeK2BCLt/ufQkvAL7W5kb83QuSPZfhK/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;550&quot; height=&quot;336&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;플리핑(Flipping)&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;Frontbuffer에서 데이터를 출력하는 동안 Backbuffer의 내용으로 바뀐다면?&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;550&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yoOyK/btrUbyIv00t/op3cWN2yjgYlmoj9t2CwTK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yoOyK/btrUbyIv00t/op3cWN2yjgYlmoj9t2CwTK/img.gif&quot; data-alt=&quot;중간에 출력되면?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yoOyK/btrUbyIv00t/op3cWN2yjgYlmoj9t2CwTK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/yoOyK/btrUbyIv00t/op3cWN2yjgYlmoj9t2CwTK/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;550&quot; height=&quot;196&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;196&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;찢어지는 현상(Tearing)이 일어나게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lXjYw/btrUdKPenQd/DGDskgpCKwd06xhhFLeyPK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lXjYw/btrUdKPenQd/DGDskgpCKwd06xhhFLeyPK/img.jpg&quot; data-alt=&quot;티어링&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lXjYw/btrUdKPenQd/DGDskgpCKwd06xhhFLeyPK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlXjYw%2FbtrUdKPenQd%2FDGDskgpCKwd06xhhFLeyPK%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;550&quot; height=&quot;313&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;313&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;이를 해결하는 간단한 방법은 수직동기화(v-sync)와 타이밍을 맞추는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모니터가 갱신되는 타이밍에 맞추기 때문에 추가적인 오버헤드와 레이턴시가 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vC4Ll/btrUadrwQNV/B9nhNqL253hEwsQcF9kZz1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vC4Ll/btrUadrwQNV/B9nhNqL253hEwsQcF9kZz1/img.gif&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;179&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.7186%; margin-right: 10px;&quot; data-widthpercent=&quot;49.29&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vC4Ll/btrUadrwQNV/B9nhNqL253hEwsQcF9kZz1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvC4Ll%2FbtrUadrwQNV%2FB9nhNqL253hEwsQcF9kZz1%2Fimg.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;550&quot; height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhmObu/btrUapFnaQq/UbakWvD5PDYPGvmqHjOBh1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhmObu/btrUapFnaQq/UbakWvD5PDYPGvmqHjOBh1/img.gif&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;174&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.1186%;&quot; data-widthpercent=&quot;50.71&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhmObu/btrUapFnaQq/UbakWvD5PDYPGvmqHjOBh1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhmObu%2FbtrUapFnaQq%2FUbakWvD5PDYPGvmqHjOBh1%2Fimg.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;550&quot; height=&quot;174&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;성능 충분, 성능 부족&lt;/figcaption&gt;
&lt;/figure&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;성능 부족: 동기화 타이밍이 지나버리면 다음 동기화 타이밍까지 지연이 생김 (화면끊김, Stuttering)&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때문에 나온 해결책은 트리플 버퍼링이며 크게 두가지 방식이 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cspGs1/btrUaWiBx0D/SOcsJK8AqGEZnzoW6DaEa1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cspGs1/btrUaWiBx0D/SOcsJK8AqGEZnzoW6DaEa1/img.jpg&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;139&quot; data-is-animation=&quot;false&quot; style=&quot;width: 64.8738%; margin-right: 10px;&quot; data-widthpercent=&quot;65.64&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cspGs1/btrUaWiBx0D/SOcsJK8AqGEZnzoW6DaEa1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcspGs1%2FbtrUaWiBx0D%2FSOcsJK8AqGEZnzoW6DaEa1%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;418&quot; height=&quot;139&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clVgjG/btrUb5F8Dx4/9wHZkpSmAO1W0IlzFg1D9K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clVgjG/btrUb5F8Dx4/9wHZkpSmAO1W0IlzFg1D9K/img.jpg&quot; data-origin-width=&quot;307&quot; data-origin-height=&quot;195&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.9634%;&quot; data-widthpercent=&quot;34.36&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clVgjG/btrUb5F8Dx4/9wHZkpSmAO1W0IlzFg1D9K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclVgjG%2FbtrUb5F8Dx4%2F9wHZkpSmAO1W0IlzFg1D9K%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;307&quot; height=&quot;195&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;직렬화 vs 병렬화&lt;/figcaption&gt;
&lt;/figure&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;br /&gt;백버퍼1를 미리 그려놓으면 프론트버퍼와 교체하는 동시에 다음 프레임을 백버퍼2에 그림&lt;br /&gt;백버퍼2에 미리 그려놓으면 프론트버퍼와 교체하는 동시에 다음 프레임을 백버퍼1에 그림&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;직렬화 방식은 수직동기화를 이용해 교체하기 때문에 성능이 좋은 GPU일 경우 GPU의 성능을 최대한 이용하지 못하고 지연이 생긴다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;194&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DmHtt/btrT9z9N8XR/KICLrO0Pkbnib06VYxC7RK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DmHtt/btrT9z9N8XR/KICLrO0Pkbnib06VYxC7RK/img.gif&quot; data-alt=&quot;직렬화 - 지연문제&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DmHtt/btrT9z9N8XR/KICLrO0Pkbnib06VYxC7RK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/DmHtt/btrT9z9N8XR/KICLrO0Pkbnib06VYxC7RK/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;600&quot; height=&quot;194&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;194&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;반대로 병렬화 방식은 GPU의 성능을 최대한 이용해 준비되면 바로바로 교체하는 방식이기 때문에 지연은 적지만 전력소모 문제가 있을 수 있으며 발열에 의해 오히려 성능제한이 생길 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 보통 트리플 버퍼라고 하면,&amp;nbsp;&lt;span&gt;후자인 병렬화 방식을&lt;span&gt;&amp;nbsp;&lt;/span&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;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lumjZ/btrUb4Hel6O/WX640zQnEKgK6Wf38Hsvu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lumjZ/btrUb4Hel6O/WX640zQnEKgK6Wf38Hsvu1/img.png&quot; data-alt=&quot;정리 버전&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lumjZ/btrUb4Hel6O/WX640zQnEKgK6Wf38Hsvu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlumjZ%2FbtrUb4Hel6O%2FWX640zQnEKgK6Wf38Hsvu1%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;876&quot; height=&quot;876&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&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;h4 data-ke-size=&quot;size20&quot;&gt;수직동기화&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.techspot.com/article/1668-how-many-fps-do-you-need/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How Many FPS Do You Need?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.techspot.com/article/1454-gsync-vs-freesync/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FreeSync&amp;nbsp;vs.&amp;nbsp;G-Sync&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;1280&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bk2OjU/btrUfLaBWvo/lZg6OnP3zkKD02GIU5KfV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bk2OjU/btrUfLaBWvo/lZg6OnP3zkKD02GIU5KfV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bk2OjU/btrUfLaBWvo/lZg6OnP3zkKD02GIU5KfV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbk2OjU%2FbtrUfLaBWvo%2FlZg6OnP3zkKD02GIU5KfV0%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;1280&quot; height=&quot;439&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;/figure&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;br /&gt;지연시간동안 계산하지 않으면 다음 프레임을 그릴시간 부족해질 수도 있음&lt;/li&gt;
&lt;li&gt;성능 부족: 동기화 타이밍이 지나버리면 다음 동기화 타이밍까지 지연이 생김&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;/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;Nvidia의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.nvidia.com/en-us/geforce/technologies/adaptive-vsync/technology/&quot;&gt;적응형 수직동기화(Adaptive V-Sync)&lt;/a&gt;/&lt;span&gt;AMD의 &lt;a href=&quot;https://www.radeonpro.info/features/dynamic-vsync-control/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;동적 수직 컨트롤(Dynamic V-sync Control)&lt;/span&gt;&lt;/a&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;650&quot; data-origin-height=&quot;365&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3QW9q/btrUeXJJzOa/XhRS09Kd3DCoGG1QAjzmK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3QW9q/btrUeXJJzOa/XhRS09Kd3DCoGG1QAjzmK1/img.png&quot; data-alt=&quot;V-Sync를 통한 프레임 제한&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3QW9q/btrUeXJJzOa/XhRS09Kd3DCoGG1QAjzmK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3QW9q%2FbtrUeXJJzOa%2FXhRS09Kd3DCoGG1QAjzmK1%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;650&quot; height=&quot;365&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;365&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;V-Sync를 통한 프레임 제한&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;첫번째는 앞서 idle시간 동안 계산을 못해 다음에 계산이 많이 필요하면 프레임을 만들때 문제가 생길 수 있다는 점.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째는 입력 지연이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vqyYw/btrUfwx4gkU/ejNV6UsiMhksxIQcP0BPu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vqyYw/btrUfwx4gkU/ejNV6UsiMhksxIQcP0BPu1/img.png&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;497&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.9609%; margin-right: 10px;&quot; data-widthpercent=&quot;46.5&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vqyYw/btrUfwx4gkU/ejNV6UsiMhksxIQcP0BPu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvqyYw%2FbtrUfwx4gkU%2FejNV6UsiMhksxIQcP0BPu1%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;1100&quot; height=&quot;497&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tsaap/btrUh2vIEpT/n0chC9ZvhmLI0Nas5EuFJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tsaap/btrUh2vIEpT/n0chC9ZvhmLI0Nas5EuFJ0/img.png&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;432&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.8763%;&quot; data-widthpercent=&quot;53.5&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tsaap/btrUh2vIEpT/n0chC9ZvhmLI0Nas5EuFJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTsaap%2FbtrUh2vIEpT%2Fn0chC9ZvhmLI0Nas5EuFJ0%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;1100&quot; height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;V-Sync 입력지연 vs 티어링&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;Nvidia의 Fast Sync/AMD의 &lt;a href=&quot;https://www.amd.com/ko/technologies/software-enhancedsync&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;향상된 동기화(Enhanced Sync)&lt;/a&gt;는 V-Sync를 사용할때&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;1280&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Oj1ZS/btrUfbnqEap/IjoxeCyfzhBpIj5qtWMSjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Oj1ZS/btrUfbnqEap/IjoxeCyfzhBpIj5qtWMSjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Oj1ZS/btrUfbnqEap/IjoxeCyfzhBpIj5qtWMSjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOj1ZS%2FbtrUfbnqEap%2FIjoxeCyfzhBpIj5qtWMSjk%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;1440&quot; height=&quot;675&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7wP2R/btrUfJDUFdp/eyYDFXKRXKMyzMtREY02Qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7wP2R/btrUfJDUFdp/eyYDFXKRXKMyzMtREY02Qk/img.png&quot; data-origin-width=&quot;1166&quot; data-origin-height=&quot;418&quot; data-is-animation=&quot;false&quot; style=&quot;width: 60.3609%; margin-right: 10px;&quot; data-widthpercent=&quot;61.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7wP2R/btrUfJDUFdp/eyYDFXKRXKMyzMtREY02Qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7wP2R%2FbtrUfJDUFdp%2FeyYDFXKRXKMyzMtREY02Qk%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;1166&quot; height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bniMm4/btrUfvMIRwa/EIM1patgOfQExCTkEUkC10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bniMm4/btrUfvMIRwa/EIM1patgOfQExCTkEUkC10/img.png&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;658&quot; data-is-animation=&quot;false&quot; style=&quot;width: 38.4763%;&quot; data-widthpercent=&quot;38.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bniMm4/btrUfvMIRwa/EIM1patgOfQExCTkEUkC10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbniMm4%2FbtrUfvMIRwa%2FEIM1patgOfQExCTkEUkC10%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;1170&quot; height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;/div&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;그런데!! 여기서 의문, 디스플레이의 주사율(V-Sync 타이밍)를 변경해릴수는 없을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nvidia의&amp;nbsp;&lt;a href=&quot;https://www.nvidia.com/ko-kr/geforce/products/g-sync-monitors/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;G-Sync&lt;/a&gt;/AMD의 &lt;a href=&quot;https://www.amd.com/ko/technologies/free-sync&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Free Sync&lt;/a&gt;는 가변 주사율를 지원하게 만들어 지연 문제 해결에 도움을 준다. (때문에 지원하는 모니터를 가림)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;669&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EKEZG/btrUfrKjw9Z/eRxNWXqA2rHWqJHZ7VEbS0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EKEZG/btrUfrKjw9Z/eRxNWXqA2rHWqJHZ7VEbS0/img.webp&quot; data-alt=&quot;가변 주사율&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EKEZG/btrUfrKjw9Z/eRxNWXqA2rHWqJHZ7VEbS0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEKEZG%2FbtrUfrKjw9Z%2FeRxNWXqA2rHWqJHZ7VEbS0%2Fimg.webp&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;1280&quot; height=&quot;669&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;669&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;가변 주사율이 있다지만 주사율의 상하한 폭은 여전히 존재한다. (예: 60~120Hz)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 24FPS가 지속적으로 나오고 있다고 가정할 때 60Hz가 최저 주사율인 모니터인 경우는 2장, 3장이 반복적으로 표시되며(2:3 pull-down), 끊기거나 부자연스러워 보인다(Judder).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b58gT7/btrUfPqF0DZ/LGtMSAka4tK2hczsiL5qPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b58gT7/btrUfPqF0DZ/LGtMSAka4tK2hczsiL5qPK/img.png&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;229&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.359%; margin-right: 10px;&quot; data-widthpercent=&quot;45.89&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b58gT7/btrUfPqF0DZ/LGtMSAka4tK2hczsiL5qPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb58gT7%2FbtrUfPqF0DZ%2FLGtMSAka4tK2hczsiL5qPK%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;812&quot; height=&quot;229&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baYIR0/btrUfifQhP0/cZYknWB7ugSL3zJIUCZw1K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baYIR0/btrUfifQhP0/cZYknWB7ugSL3zJIUCZw1K/img.jpg&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;144&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.4782%;&quot; data-widthpercent=&quot;54.11&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baYIR0/btrUfifQhP0/cZYknWB7ugSL3zJIUCZw1K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaYIR0%2FbtrUfifQhP0%2FcZYknWB7ugSL3zJIUCZw1K%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;602&quot; height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.rtings.com/tv/tests/motion/24p&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Our&amp;nbsp;TV&amp;nbsp;Motion&amp;nbsp;Tests&lt;/a&gt;, &lt;a href=&quot;https://webzine-eng.snu.ac.kr/web/vol117/sub0103_p2.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;가상현실을&amp;nbsp;위한&amp;nbsp;디스플레이&amp;nbsp;구동&amp;nbsp;기술&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 나온방식이 LFC(Low Framerate Compensation).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정수배(예: $24 \times 3 = 72$, $24 \times 5 = 120$)로 표현해주면 끊기지 않는 듯 한 움직임으로 느끼게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;587&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqCSQZ/btrUgie68Rv/4X1QxkJdkAwKzuBWukRsPK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqCSQZ/btrUgie68Rv/4X1QxkJdkAwKzuBWukRsPK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqCSQZ/btrUgie68Rv/4X1QxkJdkAwKzuBWukRsPK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqCSQZ%2FbtrUgie68Rv%2F4X1QxkJdkAwKzuBWukRsPK%2Fimg.webp&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;1100&quot; height=&quot;587&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;587&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.techspot.com/article/1630-freesync-2-explained/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FreeSync&amp;nbsp;2&amp;nbsp;Explained&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠시 정리를 해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FPS &amp;gt;= 최대 주사율: V-sync + 트리플 버퍼링&lt;/li&gt;
&lt;li&gt;최대주사율 &amp;gt; FPS &amp;gt;= 최소 주사율: 가변 주사율&lt;/li&gt;
&lt;li&gt;최소 주사율 &amp;gt; FPS: 정수배 가변 주사율&lt;/li&gt;
&lt;/ul&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;참고로 보통 게이밍 모니터는 48~144Hz의 가변 주사율를 가진다.&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ps4linux.com/frame-pacing-explanation-fix/&quot;&gt;What&amp;nbsp;is&amp;nbsp;frame&amp;nbsp;pacing,&amp;nbsp;and&amp;nbsp;why&amp;nbsp;it&amp;nbsp;matters&amp;nbsp;in&amp;nbsp;games?&amp;nbsp;Detailed&amp;nbsp;explanation&amp;nbsp;for&amp;nbsp;everyone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/libretro/RetroArch/issues/6984&quot;&gt;Add&amp;nbsp;Beam&amp;nbsp;Racing/Scanline&amp;nbsp;Sync&amp;nbsp;to&amp;nbsp;RetroArch&amp;nbsp;(aka&amp;nbsp;Lagless&amp;nbsp;VSYNC)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;769&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b25tax/btrUi3uuuTg/QxZy1XpO3oFU0kzYHazeB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b25tax/btrUi3uuuTg/QxZy1XpO3oFU0kzYHazeB1/img.png&quot; data-alt=&quot;균일 vs 랜덤&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b25tax/btrUi3uuuTg/QxZy1XpO3oFU0kzYHazeB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb25tax%2FbtrUi3uuuTg%2FQxZy1XpO3oFU0kzYHazeB1%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;769&quot; height=&quot;480&quot; data-origin-width=&quot;769&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;균일 vs 랜덤&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;프레임 페이싱(Frame pacing) 관련 라이브러리는 로직을 디스플레이와 맞추어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가변 주사율(Free Sync, G-Sync)와 달리 소프트웨어적으로 처리보자는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드의 Swappy(&lt;a href=&quot;https://source.android.com/docs/core/graphics/frame-pacing?hl=ko&quot;&gt;프레임 페이싱&lt;/a&gt;, &lt;a href=&quot;https://developer.android.com/games/sdk/frame-pacing&quot;&gt;Frame&amp;nbsp;Pacing&amp;nbsp;Library&lt;/a&gt;)가 좋은 예이니 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QMXe1/btrUgPRdk8m/vCouFt7QZIW2kHSXK8uYzK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QMXe1/btrUgPRdk8m/vCouFt7QZIW2kHSXK8uYzK/img.jpg&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;265&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QMXe1/btrUgPRdk8m/vCouFt7QZIW2kHSXK8uYzK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQMXe1%2FbtrUgPRdk8m%2FvCouFt7QZIW2kHSXK8uYzK%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;797&quot; height=&quot;265&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MTYa0/btrUgiM1oQy/5CQXUFCzb6VPEbvBVDOvp0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MTYa0/btrUgiM1oQy/5CQXUFCzb6VPEbvBVDOvp0/img.jpg&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;265&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MTYa0/btrUgiM1oQy/5CQXUFCzb6VPEbvBVDOvp0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMTYa0%2FbtrUgiM1oQy%2F5CQXUFCzb6VPEbvBVDOvp0%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;797&quot; height=&quot;265&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DHSHV/btrUhmVDh7x/ecV0Tt2BYzkk13ax1P9Kn1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DHSHV/btrUhmVDh7x/ecV0Tt2BYzkk13ax1P9Kn1/img.jpg&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;265&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DHSHV/btrUhmVDh7x/ecV0Tt2BYzkk13ax1P9Kn1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDHSHV%2FbtrUhmVDh7x%2FecV0Tt2BYzkk13ax1P9Kn1%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;797&quot; height=&quot;265&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8RpT2/btrUfgI6IaI/yN4wHkpHVK40mxy9TDTL70/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8RpT2/btrUfgI6IaI/yN4wHkpHVK40mxy9TDTL70/img.jpg&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;265&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8RpT2/btrUfgI6IaI/yN4wHkpHVK40mxy9TDTL70/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8RpT2%2FbtrUfgI6IaI%2FyN4wHkpHVK40mxy9TDTL70%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;797&quot; height=&quot;265&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;/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;CPU와 GPU의 워크로드 타이밍도 정하는 기능을 파이프라인이라는 이름으로 제공해주기도 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgyZ4C/btrUfahLDLE/OaQUkJQYSeniPmM1HxpJX1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgyZ4C/btrUfahLDLE/OaQUkJQYSeniPmM1HxpJX1/img.jpg&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;160&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.7025%; margin-right: 10px;&quot; data-widthpercent=&quot;52.31&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgyZ4C/btrUfahLDLE/OaQUkJQYSeniPmM1HxpJX1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgyZ4C%2FbtrUfahLDLE%2FOaQUkJQYSeniPmM1HxpJX1%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;781&quot; height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKjnbH/btrUfhuvGKZ/JA871VFKXlWSknS5nGUl70/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKjnbH/btrUfhuvGKZ/JA871VFKXlWSknS5nGUl70/img.jpg&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;160&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.1347%;&quot; data-widthpercent=&quot;47.69&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKjnbH/btrUfhuvGKZ/JA871VFKXlWSknS5nGUl70/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKjnbH%2FbtrUfhuvGKZ%2FJA871VFKXlWSknS5nGUl70%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;712&quot; height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;파이프라인 vs 비 파이프라인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이프라인: V-Sync 타이밍을 기준으로 CPU와 GPU 워크로드를 분리&lt;/li&gt;
&lt;li&gt;비 파이프라인: 모든 워크로드가 단일 스왑 간격을 가짐 (지연시간이 더 낮음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 안드로이드의 Swappy는 스왑 간격을 자동적으로 선택(예: 30Hz/60Hz), 자동 파이프라이닝 선택, 가변 주파수 지원등 여러 기능을 제공해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니티도 비슷한 고민을 가지고 접근한적 있으니 확인해보기 바란다. (&lt;a href=&quot;https://blog.unity.com/technology/fixing-time-deltatime-in-unity-2020-2-for-smoother-gameplay-what-did-it-take&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fixing Time.deltaTime in Unity 2020.2 for smoother gameplay: What did it take?&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;AMD의 경우 멀티 GPU일 경우 번갈아 프레임을 생성해 일관된 프레임을 얻기도 했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf6AOl/btrUfvMRzNL/fHz6Lh6maw8v8jVCXhAHYK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf6AOl/btrUfvMRzNL/fHz6Lh6maw8v8jVCXhAHYK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf6AOl/btrUfvMRzNL/fHz6Lh6maw8v8jVCXhAHYK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf6AOl%2FbtrUfvMRzNL%2FfHz6Lh6maw8v8jVCXhAHYK%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;1920&quot; height=&quot;1080&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;771&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MQ7aR/btrUao0YUiF/3LzulnXQquDPHyWiIXmkJk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MQ7aR/btrUao0YUiF/3LzulnXQquDPHyWiIXmkJk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MQ7aR/btrUao0YUiF/3LzulnXQquDPHyWiIXmkJk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMQ7aR%2FbtrUao0YUiF%2F3LzulnXQquDPHyWiIXmkJk%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;1000&quot; height=&quot;771&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;771&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.techarp.com/news/amd-doubles-mgpu-frame-pacing/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMD&amp;nbsp;Doubles&amp;nbsp;Down&amp;nbsp;On&amp;nbsp;mGPU&amp;nbsp;Frame&amp;nbsp;Pacing&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;a href=&quot;https://www.nvidia.com/en-us/geforce/guides/system-latency-optimization-guide/&quot;&gt;How&amp;nbsp;To&amp;nbsp;Reduce&amp;nbsp;Lag&amp;nbsp;-&amp;nbsp;A&amp;nbsp;Guide&amp;nbsp;To&amp;nbsp;Better&amp;nbsp;System&amp;nbsp;Latency&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;378&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RCrrT/btsugkBmBPp/R7Kd7WWvAIZ5P43bAuiFMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RCrrT/btsugkBmBPp/R7Kd7WWvAIZ5P43bAuiFMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RCrrT/btsugkBmBPp/R7Kd7WWvAIZ5P43bAuiFMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRCrrT%2FbtsugkBmBPp%2FR7Kd7WWvAIZ5P43bAuiFMK%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;1999&quot; height=&quot;591&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;378&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.nvidia.com/blog/understanding-and-measuring-pc-latency/&quot;&gt;Understanding&amp;nbsp;and&amp;nbsp;Measuring&amp;nbsp;PC&amp;nbsp;Latency&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;비파이프라인 방식에 중점을 둔 Reflex라는 SDK를 제공해주고 있다. [&lt;a href=&quot;https://www.nvidia.com/en-us/geforce/news/reflex-low-latency-platform/&quot;&gt;Introducing NVIDIA Reflex: Optimize and Measure Latency in Competitive Games&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4FUhb/btst6l238QX/kPSBUhkuCtWtOKBKsZlQFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4FUhb/btst6l238QX/kPSBUhkuCtWtOKBKsZlQFK/img.png&quot; data-src-desktop=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-gpu-bound-latency-pipline.png&quot; data-src-laptop=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-gpu-bound-latency-pipline.png&quot; data-src-tablet=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-gpu-bound-latency-pipline.png&quot; data-src-mobile=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-gpu-bound-latency-pipline.png&quot; data-src-desktop-retina=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-gpu-bound-latency-pipline.png&quot; data-src-laptop-retina=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-gpu-bound-latency-pipline.png&quot; data-src-tablet-retina=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-gpu-bound-latency-pipline.png&quot; data-src-mobile-retina=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-gpu-bound-latency-pipline.png&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;1422&quot; data-is-animation=&quot;false&quot; title=&quot;&quot; style=&quot;width: 49.8322%; margin-right: 10px;&quot; data-widthpercent=&quot;50.42&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4FUhb/btst6l238QX/kPSBUhkuCtWtOKBKsZlQFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4FUhb%2Fbtst6l238QX%2FkPSBUhkuCtWtOKBKsZlQFK%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;3840&quot; height=&quot;1422&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMeK0W/btsugkuz2mi/7ViLszIv4ncqyBVBBAeys1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMeK0W/btsugkuz2mi/7ViLszIv4ncqyBVBBAeys1/img.png&quot; data-src-desktop=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-sdk-latency-pipline.png&quot; data-src-laptop=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-sdk-latency-pipline.png&quot; data-src-tablet=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-sdk-latency-pipline.png&quot; data-src-mobile=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-sdk-latency-pipline.png&quot; data-src-desktop-retina=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-sdk-latency-pipline.png&quot; data-src-laptop-retina=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-sdk-latency-pipline.png&quot; data-src-tablet-retina=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-sdk-latency-pipline.png&quot; data-src-mobile-retina=&quot;/content/dam/en-zz/Solutions/geforce/news/reflex-low-latency-platform/nvidia-reflex-sdk-latency-pipline.png&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;1446&quot; data-is-animation=&quot;false&quot; title=&quot;&quot; style=&quot;width: 49.0051%;&quot; data-widthpercent=&quot;49.58&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMeK0W/btsugkuz2mi/7ViLszIv4ncqyBVBBAeys1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMeK0W%2Fbtsugkuz2mi%2F7ViLszIv4ncqyBVBBAeys1%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;3840&quot; height=&quot;1446&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;적용 전 / 후&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마치 CPU 중심 파이프라인과 비슷하게 만들어졌다고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;1431&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bixtEF/btsudQ17726/32qDZvnT9L1cibU9Ltk9R1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bixtEF/btsudQ17726/32qDZvnT9L1cibU9Ltk9R1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bixtEF/btsudQ17726/32qDZvnT9L1cibU9Ltk9R1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbixtEF%2FbtsudQ17726%2F32qDZvnT9L1cibU9Ltk9R1%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;3840&quot; height=&quot;1431&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;1431&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://blurbusters.com/blur-busters-lagless-raster-follower-algorithm-for-emulator-developers/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Blur Busters Lagless VSYNC ON Algorithm For Emulators: True Beam Racing&lt;/a&gt;, &amp;nbsp;&lt;a href=&quot;https://blog.imaginationtech.com/reducing-latency-in-vr-by-using-single-buffered-strip-rendering/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reducing latency in mobile VR by using single buffered strip rendering&lt;/a&gt;,&amp;nbsp;&amp;nbsp;&lt;a title=&quot;&quot; href=&quot;https://black7375.tumblr.com/post/663908279732289536/%EC%98%9B%EB%82%A0-%EA%B2%8C%EC%9E%84%EC%9D%98-%EC%B5%9C%EC%A0%81%ED%99%94-%EA%B8%B0%EB%B2%95&quot;&gt;옛날 게임의 최적화 기법&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kzuki/btsufjbDd62/opaTFk3L9d3lo4wkw4mgJ0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kzuki/btsufjbDd62/opaTFk3L9d3lo4wkw4mgJ0/img.gif&quot; data-alt=&quot;beam racing&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kzuki/btsufjbDd62/opaTFk3L9d3lo4wkw4mgJ0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/kzuki/btsufjbDd62/opaTFk3L9d3lo4wkw4mgJ0/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;228&quot; height=&quot;270&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;beam racing&lt;/figcaption&gt;
&lt;/figure&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;처음으로 다시 올라가는 타이밍이 곧 수직동기화 타이밍이나 다름 없으므로 v-sync를 사용하지 않아도 됨&lt;/li&gt;
&lt;li&gt;동기적이므로 티어링 현상이 일어나지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점은 구현이 상당히 까다로우며 짧은 시간안에 작업을 완료해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예륻 들어 OpenGL의 렌더링은 &lt;a href=&quot;https://www.khronos.org/opengl/wiki/Synchronization&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비동기적으로 실행&lt;/a&gt;되므로 GPU와 동기화 타이밍 맞추기가 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 수직동기화가 없기 때문에 매번 가로 프레임이 렌더링 되면 업데이트해&amp;nbsp;&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;&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;339&quot; data-origin-height=&quot;405&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgdCjD/btrUpDbtrgG/2vjRw0azKWEkfpOdV31Ubk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgdCjD/btrUpDbtrgG/2vjRw0azKWEkfpOdV31Ubk/img.gif&quot; data-alt=&quot;Beam chasing strip rendering&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgdCjD/btrUpDbtrgG/2vjRw0azKWEkfpOdV31Ubk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cgdCjD/btrUpDbtrgG/2vjRw0azKWEkfpOdV31Ubk/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;339&quot; height=&quot;405&quot; data-origin-width=&quot;339&quot; data-origin-height=&quot;405&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Beam chasing strip rendering&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스캔라인 구역별로 나누어지기 때문에 타일 렌더링과 결합하여 병렬적으로 만들 수 있을 것으로 보인다.&amp;nbsp; [&lt;a href=&quot;https://www.fileformat.info/mirror/egff/ch03_04.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bitmap Data&lt;/a&gt;, &lt;a href=&quot;http://kunzhou.net/zjugaps/pathrendering/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Efficient&amp;nbsp;GPU&amp;nbsp;Path&amp;nbsp;Rendering&amp;nbsp;Using&amp;nbsp;Scanline&amp;nbsp;Rasterization&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AcjRt/btst54NWobJ/kmGbAqSfinLdJo6RmOqGdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AcjRt/btst54NWobJ/kmGbAqSfinLdJo6RmOqGdK/img.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;363&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.6487%; margin-right: 10px;&quot; data-widthpercent=&quot;49.22&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AcjRt/btst54NWobJ/kmGbAqSfinLdJo6RmOqGdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAcjRt%2Fbtst54NWobJ%2FkmGbAqSfinLdJo6RmOqGdK%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;528&quot; height=&quot;363&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LRMGS/btsudPvpoSw/0ibmonNuDNxMSBumqj2yn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LRMGS/btsudPvpoSw/0ibmonNuDNxMSBumqj2yn1/img.png&quot; width=&quot;1000&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot; data-is-animation=&quot;false&quot; title=&quot;&quot; style=&quot;width: 50.1885%;&quot; data-widthpercent=&quot;50.78&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LRMGS/btsudPvpoSw/0ibmonNuDNxMSBumqj2yn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLRMGS%2FbtsudPvpoSw%2F0ibmonNuDNxMSBumqj2yn1%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;1280&quot; height=&quot;853&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 각 스트립 간 지터(jitter)가 문제가 있으므로 현대적인 방식으로 사용하려면 프레임 페이싱등을 이용해 보완해야 할 듯하다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm5YMN/btsueKm6rVj/tbraTrVwOyNk86T0TRQ6CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm5YMN/btsueKm6rVj/tbraTrVwOyNk86T0TRQ6CK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm5YMN/btsueKm6rVj/tbraTrVwOyNk86T0TRQ6CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm5YMN%2FbtsueKm6rVj%2FtbraTrVwOyNk86T0TRQ6CK%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;800&quot; height=&quot;263&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;289&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://macinjune.com/all-posts/mac/tip/final-cut/1080i-vs-1080p-%EC%9D%B8%ED%84%B0%EB%A0%88%EC%9D%B4%EC%8A%A4%EB%93%9C%EC%99%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%A0%88%EC%8B%9C%EB%B8%8C-%EB%B0%A9%EC%8B%9D%EC%9D%B4%EB%9E%80/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;1080i&amp;nbsp;vs&amp;nbsp;1080p?&amp;nbsp;인터레이스드와&amp;nbsp;프로그레시브&amp;nbsp;방식이란?&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;http://norecess.cpcscene.net/the-elders-scrollers.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;전 글의 링크&lt;/a&gt;에도 나왔지만 게임보이에서 하드웨어 제약과 단일 스캔라인의 문제로 2개의 스캔라인을 사용한 경우도... [&lt;a href=&quot;https://imrannazar.com/series/gameboy-emulation-in-javascript/gpu-timing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GameBoy emulation in Javascript: GPU Timings&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://github.com/mattrberry/crab&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Crab&lt;/a&gt;, &lt;a href=&quot;http://blog.kevtris.org/blogfiles/Nitty%20Gritty%20Gameboy%20VRAM%20Timing.txt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nitty&amp;nbsp;Gritty&amp;nbsp;Gameboy&amp;nbsp;Cycle&amp;nbsp;Timing&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0Dblv/btsudKOqZIG/dBHYowM351vZOZtgOjD5z0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0Dblv/btsudKOqZIG/dBHYowM351vZOZtgOjD5z0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0Dblv/btsudKOqZIG/dBHYowM351vZOZtgOjD5z0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/0Dblv/btsudKOqZIG/dBHYowM351vZOZtgOjD5z0/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;512&quot; height=&quot;256&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;256&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://hacks.mozilla.org/2017/10/the-whole-web-at-maximum-fps-how-webrender-gets-rid-of-jank/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;whole&amp;nbsp;web&amp;nbsp;at&amp;nbsp;maximum&amp;nbsp;FPS:&amp;nbsp;How&amp;nbsp;WebRender&amp;nbsp;gets&amp;nbsp;rid&amp;nbsp;of&amp;nbsp;jank&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포지터란 대체 무엇을 하는 물건일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹에서 transform, opacity와 같은 CSS 속성들은 컴포지터 레이어에서 실행되므로 하드웨어 가속이 된다정도 들어봤을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Compositing&quot;&gt;컴포지팅(compositing, 합성)&lt;/a&gt;은 개별 소스의 시각적 요소를 단일 이미지로 결합하는 프로세스다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kw4wP/btrUkCXMjC5/RWKasABw3tMduePtoraDKK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kw4wP/btrUkCXMjC5/RWKasABw3tMduePtoraDKK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kw4wP/btrUkCXMjC5/RWKasABw3tMduePtoraDKK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/kw4wP/btrUkCXMjC5/RWKasABw3tMduePtoraDKK/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;600&quot; height=&quot;375&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/5237120&quot;&gt;최신&amp;nbsp;브라우저의&amp;nbsp;내부&amp;nbsp;살펴보기&amp;nbsp;3&amp;nbsp;-&amp;nbsp;렌더러&amp;nbsp;프로세스의&amp;nbsp;내부&amp;nbsp;동작&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://en.wikipedia.org/wiki/Compositing_window_manager&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;윈도우 매니저&lt;/a&gt;에 좋은 예시들이 나와있다. [&lt;a href=&quot;https://dev.to/l04db4l4nc3r/compositors-in-linux-1hhb&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Compositors&amp;nbsp;in&amp;nbsp;Linux&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdSxJb/btrUGpFET4b/mwvb91wEQkwUVqi1ye8ZL0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdSxJb/btrUGpFET4b/mwvb91wEQkwUVqi1ye8ZL0/img.jpg&quot; width=&quot;880&quot; height=&quot;425&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;425&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5346%; margin-right: 10px;&quot; data-widthpercent=&quot;50.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdSxJb/btrUGpFET4b/mwvb91wEQkwUVqi1ye8ZL0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdSxJb%2FbtrUGpFET4b%2Fmwvb91wEQkwUVqi1ye8ZL0%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;880&quot; height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMdnhc/btrUNViid44/GyDKgOg7atqpnZrbYrBeW1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMdnhc/btrUNViid44/GyDKgOg7atqpnZrbYrBeW1/img.jpg&quot; width=&quot;880&quot; height=&quot;427&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;427&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3026%;&quot; data-widthpercent=&quot;49.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMdnhc/btrUNViid44/GyDKgOg7atqpnZrbYrBeW1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMdnhc%2FbtrUNViid44%2FGyDKgOg7atqpnZrbYrBeW1%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;880&quot; height=&quot;427&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;li&gt;회전/복제&lt;/li&gt;
&lt;li&gt;전환 애니메이션&lt;/li&gt;
&lt;/ul&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;500&quot; data-origin-height=&quot;243&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgaU1j/btrUsPKGkbJ/vl0TBpr5uVW7lRJAvEyqHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgaU1j/btrUsPKGkbJ/vl0TBpr5uVW7lRJAvEyqHk/img.png&quot; data-alt=&quot;스크롤&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgaU1j/btrUsPKGkbJ/vl0TBpr5uVW7lRJAvEyqHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgaU1j%2FbtrUsPKGkbJ%2Fvl0TBpr5uVW7lRJAvEyqHk%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;500&quot; height=&quot;243&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;243&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://raphlinus.github.io/ui/graphics/2020/09/13/compositor-is-evil.html&quot;&gt;지연을 추가&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;레이어가 많아질 때 GPU 대역폭과 메모리 비용&lt;/li&gt;
&lt;li&gt;텍스트처럼 컴포지터로 다룰 수 없는 요소들&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인게 비디오 처리이며, KDE에는 윈도우 합성이 의미 없는 전체화면에서 끄는 확장도 있다. [&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/medfound/gpu-based-content-protection-d3d11&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GPU-Based&amp;nbsp;Content&amp;nbsp;Protection&amp;nbsp;with&amp;nbsp;D3D11&amp;nbsp;Video&lt;/a&gt;, &lt;a href=&quot;https://www.deltacast.tv/technologies/keyer&quot;&gt;What does keying mean ?&lt;/a&gt;, &lt;a href=&quot;https://store.kde.org/p/1502826/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Autocomposer&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xPD3o/btrUuwiR6yq/fxSoABEYZPNim9NEaX9eFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xPD3o/btrUuwiR6yq/fxSoABEYZPNim9NEaX9eFk/img.png&quot; data-alt=&quot;비디오 처리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xPD3o/btrUuwiR6yq/fxSoABEYZPNim9NEaX9eFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxPD3o%2FbtrUuwiR6yq%2FfxSoABEYZPNim9NEaX9eFk%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;617&quot; height=&quot;416&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;416&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;아예 GPU를 벗어나 디스플레이 컨트롤러 레벨에서 합성을 할 수도 있다. [&lt;a href=&quot;https://www.kernel.org/doc/html/latest/gpu/amdgpu/display/mpo-overview.html&quot;&gt;Multiplane Overlay (MPO)&lt;/a&gt;, &lt;a href=&quot;https://source.android.com/docs/core/graphics/implement-hwc&quot;&gt;안드로이드&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://nemoux00.wordpress.com/2015/01/09/wayland-hardware-composer-in-android/&quot;&gt;Wayland&lt;/a&gt;, &lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/win32/medfound/hardware-overlay-support&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;a href=&quot;https://wiki.amigaos.net/wiki/Hardware_Sprites&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;하드웨어 스프라이트(Hardware sprite)&lt;/a&gt;를 가졌둣, &lt;a href=&quot;https://en.wikipedia.org/wiki/Hardware_overlay&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;하드웨어 오버레이&lt;/a&gt;를 사용해 바이패스 함으로서 CPU와 GPU의 자원을 아끼고 각 프레임버퍼는 독립적인 타이밍을 가질 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;624&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/81cBM/btrUsnVOeUw/KT9X9lX4tLknOCm2NlTXj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/81cBM/btrUsnVOeUw/KT9X9lX4tLknOCm2NlTXj1/img.png&quot; data-alt=&quot;하드웨어 오버레이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/81cBM/btrUsnVOeUw/KT9X9lX4tLknOCm2NlTXj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F81cBM%2FbtrUsnVOeUw%2FKT9X9lX4tLknOCm2NlTXj1%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;624&quot; height=&quot;289&quot; data-origin-width=&quot;624&quot; data-origin-height=&quot;289&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;451&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAFf2a/btrUtFgIPAC/B8drRwfsX6adrPnPBsKzV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAFf2a/btrUtFgIPAC/B8drRwfsX6adrPnPBsKzV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAFf2a/btrUtFgIPAC/B8drRwfsX6adrPnPBsKzV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAFf2a%2FbtrUtFgIPAC%2FB8drRwfsX6adrPnPBsKzV1%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;678&quot; height=&quot;451&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;451&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.anandtech.com/show/13060/asus-pg27uq-gsync-hdr-review/5&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;/p&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우의 경우 프로그램에서 자동적으로 하드웨어 오버레이를 사용하기 위해 휴리스틱을 사용하기도 한다. [&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/for-best-performance--use-dxgi-flip-model&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;For best performance, use DXGI flip model&lt;/a&gt;, &lt;a href=&quot;https://learn.microsoft.com/en-us/windows-hardware/test/hlk/testref/8d80da43-4da5-45e9-a629-b3defd3f52ee&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DXGI&amp;nbsp;DirectFlip&lt;/a&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;그래픽&amp;nbsp; API / 라이브러리&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.nvidia.com/transitioning-opengl-vulkan&quot;&gt;Transitioning&amp;nbsp;from&amp;nbsp;OpenGL&amp;nbsp;to&amp;nbsp;Vulkan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://quasarzone.com/bbs/qn_hardware/views/857898&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DirectX 11과 DirectX 12의 차이점은 무엇입니까?&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 그래픽 API와 라이브러리가 혼재하며 많은 사람들이 헷갈려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 API.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8tPLF/btrUvWChC4D/slpt7p4F8d15D8ogCx1gNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8tPLF/btrUvWChC4D/slpt7p4F8d15D8ogCx1gNK/img.png&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;374&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.3538%; margin-right: 10px;&quot; data-widthpercent=&quot;47.91&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8tPLF/btrUvWChC4D/slpt7p4F8d15D8ogCx1gNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8tPLF%2FbtrUvWChC4D%2Fslpt7p4F8d15D8ogCx1gNK%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;670&quot; height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wwhUe/btrUuGsTUZw/SLoCTWM4pbSwqGqKryqyk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wwhUe/btrUuGsTUZw/SLoCTWM4pbSwqGqKryqyk1/img.png&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;344&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.4834%;&quot; data-widthpercent=&quot;52.09&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wwhUe/btrUuGsTUZw/SLoCTWM4pbSwqGqKryqyk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwwhUe%2FbtrUuGsTUZw%2FSLoCTWM4pbSwqGqKryqyk1%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;670&quot; height=&quot;344&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고수준: GPU 구조와 독립적이며, 아래의 Vulkan등과 비교할 때 비교적 고수준이다.&lt;br /&gt;예: &lt;a href=&quot;https://www.opengl.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OpenGL&lt;/a&gt;(임베디드 장치를 위한 &lt;a href=&quot;https://www.khronos.org/opengles/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OpenGL ES&lt;/a&gt;), &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/direct3d11/atoc-dx-graphics-direct3d-11&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DirectX11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;저수준: GPU에 명시적 제어를 할 수 있다.&lt;br /&gt;예:&amp;nbsp;&lt;a href=&quot;https://www.vulkan.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vulkan&lt;/a&gt;, &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/direct3d12/direct3d-12-graphics&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DirectX12&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/metal/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Metal&lt;/a&gt;&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;저수준 제어는 만들기가 어려운대신 잘 만든다면, CPU 사용을 줄이고, 명시적 제어로 인해 일관적인 프레임과 확장성을 유지할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgs63L/btrUvWoI2qN/Zg8qVslCQK4dKLPAKxNPSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgs63L/btrUvWoI2qN/Zg8qVslCQK4dKLPAKxNPSk/img.png&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;344&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgs63L/btrUvWoI2qN/Zg8qVslCQK4dKLPAKxNPSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbgs63L%2FbtrUvWoI2qN%2FZg8qVslCQK4dKLPAKxNPSk%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;670&quot; height=&quot;344&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK2zNM/btrUuoFYvJ2/nZrkz3IU6Fu9kDkLFR8qk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK2zNM/btrUuoFYvJ2/nZrkz3IU6Fu9kDkLFR8qk0/img.png&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;344&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK2zNM/btrUuoFYvJ2/nZrkz3IU6Fu9kDkLFR8qk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK2zNM%2FbtrUuoFYvJ2%2FnZrkz3IU6Fu9kDkLFR8qk0%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;670&quot; height=&quot;344&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉐이더 언어에서도 &lt;a href=&quot;https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Shader_modules&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;변화가 커서&lt;/a&gt; 사람이 읽을 수 있었던&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/High-Level_Shader_Language&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GLSL(OpenGL&amp;nbsp;Shading&amp;nbsp;Language)&lt;/a&gt; / &lt;a href=&quot;https://en.wikipedia.org/wiki/High-Level_Shader_Language&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HLSL(High-Level Shader Language)&lt;/a&gt; 대신 바이트코드인&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Standard_Portable_Intermediate_Representation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SPIR-V(Standard Portable Intermediate Representation)&lt;/a&gt;가 쓰인다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;637&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBFSOi/btrUvV4r24I/bvUDPI4d1ystZaHmWRemY0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBFSOi/btrUvV4r24I/bvUDPI4d1ystZaHmWRemY0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBFSOi/btrUvV4r24I/bvUDPI4d1ystZaHmWRemY0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBFSOi%2FbtrUvV4r24I%2FbvUDPI4d1ystZaHmWRemY0%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;960&quot; height=&quot;477&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;637&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.khronos.org/spir/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SPIR-V&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;플랫폼에 따라 지원하는 그래픽 API가 다양하다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;a href=&quot;https://en.wikipedia.org/wiki/ANGLE_(software)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ANGLE&lt;/a&gt;(OpenGL ES 기준)이나 &lt;a href=&quot;https://github.com/gfx-rs/wgpu&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WGPU&lt;/a&gt;(Web GPU 기준)와 같은 프로젝트가 만들어졌다. [&lt;a href=&quot;https://kvark.github.io/web/gpu/native/2020/05/03/point-of-webgpu-native.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Point&amp;nbsp;of&amp;nbsp;WebGPU&amp;nbsp;on&amp;nbsp;native&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwboE2/btrUtFBGdcw/Zg5fIkE7wKkPKgCu9Yu25K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwboE2/btrUtFBGdcw/Zg5fIkE7wKkPKgCu9Yu25K/img.png&quot; data-origin-width=&quot;897&quot; data-origin-height=&quot;507&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 54.4292%; margin-right: 10px;&quot; data-widthpercent=&quot;55.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwboE2/btrUtFBGdcw/Zg5fIkE7wKkPKgCu9Yu25K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwboE2%2FbtrUtFBGdcw%2FZg5fIkE7wKkPKgCu9Yu25K%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;897&quot; height=&quot;507&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOvrS4/btrUuntxJfW/fxF2aKya1kodgdlRxqUiO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOvrS4/btrUuntxJfW/fxF2aKya1kodgdlRxqUiO1/img.png&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;584&quot; data-is-animation=&quot;false&quot; style=&quot;width: 44.4081%;&quot; data-widthpercent=&quot;44.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOvrS4/btrUuntxJfW/fxF2aKya1kodgdlRxqUiO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOvrS4%2FbtrUuntxJfW%2FfxF2aKya1kodgdlRxqUiO1%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;843&quot; height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Y6EvrieB9IA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;ANGLE:&amp;nbsp;Running&amp;nbsp;OpenGL&amp;nbsp;ES&amp;nbsp;2.0&amp;nbsp;Graphics&amp;nbsp;Code&amp;nbsp;on&amp;nbsp;Windows&amp;nbsp;&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;a href=&quot;https://en.wikipedia.org/wiki/Windowing_system&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;윈도우 시스템&lt;/a&gt;에서도 API가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인게 &lt;a href=&quot;https://en.wikipedia.org/wiki/EGL_(API)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;EGL&lt;/a&gt;(Wayland), &lt;a href=&quot;https://en.wikipedia.org/wiki/GLX&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GLX&lt;/a&gt;(X-Window), &lt;a href=&quot;https://en.wikipedia.org/wiki/WGL_(API)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WGL&lt;/a&gt;(윈도우)이 있으며, 리눅스에서는&amp;nbsp;&lt;a href=&quot;https://docs.kernel.org/userspace-api/media/v4l/dmabuf.html&quot;&gt;DAMBUF&lt;/a&gt;를 통한 제로카피, 부분적 손상지원, 적은 버그등 때문에 GLX에서 EGL로 넘어오는 추세라고 한다. [&lt;a href=&quot;https://mozillagfx.wordpress.com/2021/10/30/switching-the-linux-graphics-stack-from-glx-to-egl/&quot;&gt;Switching the Linux graphics stack from GLX to EGL&lt;/a&gt;, &amp;nbsp;&lt;a href=&quot;https://blog.gtk.org/2021/05/10/adventures-in-graphics-apis/&quot;&gt;Adventures in graphics APIs&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://blog.gtk.org/2021/08/23/gtk-4-4/&quot;&gt;GTK 4.4&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2hwM1/btrUwrIOuwH/MkLNPSPkSWloB4GgYgXwO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2hwM1/btrUwrIOuwH/MkLNPSPkSWloB4GgYgXwO0/img.png&quot; width=&quot;960&quot; height=&quot;720&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2hwM1/btrUwrIOuwH/MkLNPSPkSWloB4GgYgXwO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2hwM1%2FbtrUwrIOuwH%2FMkLNPSPkSWloB4GgYgXwO0%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;1024&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eJUArH/btrUwr9S4cI/57xFNsGdC3JfflfRg7Sox1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eJUArH/btrUwr9S4cI/57xFNsGdC3JfflfRg7Sox1/img.png&quot; width=&quot;960&quot; height=&quot;720&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eJUArH/btrUwr9S4cI/57xFNsGdC3JfflfRg7Sox1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeJUArH%2FbtrUwr9S4cI%2F57xFNsGdC3JfflfRg7Sox1%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;1024&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;GLX와 EGL&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;a href=&quot;https://en.wikipedia.org/wiki/Cairo_(graphics)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cairo&lt;/a&gt;나 &lt;a href=&quot;https://en.wikipedia.org/wiki/Skia_Graphics_Engine&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Skia&lt;/a&gt;는 위와 같은 그래픽 API나 CPU를 사용해 다양한 기능을 제공하는 라이브러리다. (CPU 기반 로우레벨 라이브러리는 &lt;a href=&quot;https://github.com/freedesktop/pixman&quot;&gt;Pixman&lt;/a&gt;이 유명)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안티얼라이싱에 대해서도 다룰려 했는데, &lt;a href=&quot;https://namu.wiki/w/%EC%95%88%ED%8B%B0%EC%97%90%EC%9D%BC%EB%A6%AC%EC%96%B4%EC%8B%B1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;위키&lt;/a&gt;에 이미 보기좋게 정리가 되어있는 듯 하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;14. 기타 칩&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;개요&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.eetimes.com/a-tradeoff-between-microcontroller-dsp-fpga-and-asic-technologies/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;tradeoff&amp;nbsp;between&amp;nbsp;microcontroller,&amp;nbsp;DSP,&amp;nbsp;FPGA&amp;nbsp;and&amp;nbsp;ASIC&amp;nbsp;technologies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zhihuicao.wordpress.com/2015/07/14/dsp-fpga-cpu-gpu/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DSP FPGA CPU GPU&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.intel.com/content/www/us/en/developer/articles/technical/comparing-cpus-gpus-and-fpgas-for-oneapi.html#gs.l49q8x&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Compare Benefits of CPUs, GPUs, and FPGAs for Different oneAPI Compute Workloads&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU를 다룬김에 다른 co-processor들도 간략히 다루어보기로 했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;539&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kLz2G/btrUwqiRF1w/Is5eGRTFBuPj4XMKovV8wK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kLz2G/btrUwqiRF1w/Is5eGRTFBuPj4XMKovV8wK/img.jpg&quot; data-alt=&quot;간단한 비교&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kLz2G/btrUwqiRF1w/Is5eGRTFBuPj4XMKovV8wK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkLz2G%2FbtrUwqiRF1w%2FIs5eGRTFBuPj4XMKovV8wK%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;539&quot; height=&quot;311&quot; data-origin-width=&quot;539&quot; data-origin-height=&quot;311&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;애플 M1칩을 필두로 점점 중요해지고 있는 추세다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://news.hada.io/topic?id=3315&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Apple M1칩은 왜 그렇게 빠를까?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.hada.io/topic?id=3447&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;M1은&amp;nbsp;RISC-V의&amp;nbsp;상승을&amp;nbsp;예고한다&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.hada.io/topic?id=3596&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMX, 애플 M1의 숨겨진 보조프로세서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.hada.io/topic?id=3137&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;예전&amp;nbsp;ARM&amp;nbsp;엔지니어의&amp;nbsp;RISC-V&amp;nbsp;비판&lt;/a&gt;&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;대상은 DSP, FPGA, ASIC의 일종인 TPU.&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;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lves2/btrUur3MidW/VINn7A97maivzZxwDHkv2k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lves2/btrUur3MidW/VINn7A97maivzZxwDHkv2k/img.jpg&quot; data-alt=&quot;한눈에 보기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lves2/btrUur3MidW/VINn7A97maivzZxwDHkv2k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flves2%2FbtrUur3MidW%2FVINn7A97maivzZxwDHkv2k%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;638&quot; height=&quot;479&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;479&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;본격적으로 들어가기 전에 CPU와 GPU의 구조를 비교해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;953&quot; data-origin-height=&quot;545&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8VQWv/btrUuxizcO7/0YmX3RJUAxIM1c7Juwq4yk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8VQWv/btrUuxizcO7/0YmX3RJUAxIM1c7Juwq4yk/img.webp&quot; data-alt=&quot;CPU vs GPU&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8VQWv/btrUuxizcO7/0YmX3RJUAxIM1c7Juwq4yk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8VQWv%2FbtrUuxizcO7%2F0YmX3RJUAxIM1c7Juwq4yk%2Fimg.webp&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;953&quot; height=&quot;545&quot; data-origin-width=&quot;953&quot; data-origin-height=&quot;545&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CPU vs GPU&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU&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;병렬의 경우 SIMD를 사용&lt;/li&gt;
&lt;li&gt;정확한 분기예측&lt;/li&gt;
&lt;li&gt;많은 명령어 (CISC의 경우)&lt;/li&gt;
&lt;li&gt;오프로드할 필요가 없어 낮은 대기시간&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU&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;DRAM 대역폭이 높음&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;DSP&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.qualcomm.com/news/onq/2013/12/whats-so-special-about-digital-signal-processor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What&amp;rsquo;s&amp;nbsp;So&amp;nbsp;Special&amp;nbsp;about&amp;nbsp;the&amp;nbsp;Digital&amp;nbsp;Signal&amp;nbsp;Processor?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.elprocus.com/digital-signal-processor/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What&amp;nbsp;is&amp;nbsp;Digital&amp;nbsp;Signal&amp;nbsp;Processor&amp;nbsp;:&amp;nbsp;Working&amp;nbsp;&amp;amp;&amp;nbsp;Its&amp;nbsp;Applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Digital_signal_processor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DSP(Digital Signal Processor)&lt;/a&gt;는 기본적인 신호처리 알고리즘을 내장하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mmEK2/btrUvXnTawM/xJ9R230WMxADRPinVW1C8K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mmEK2/btrUvXnTawM/xJ9R230WMxADRPinVW1C8K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mmEK2/btrUvXnTawM/xJ9R230WMxADRPinVW1C8K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/mmEK2/btrUvXnTawM/xJ9R230WMxADRPinVW1C8K/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;1280&quot; height=&quot;1266&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1266&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;TI의 &lt;a href=&quot;https://www.ti.com/document-viewer/DRA788/datasheet/device-comparison-int-device-comparison#int_Device_Comparison&quot;&gt;DRA78x Infotainment Applications Processor (Rev. H)&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;a href=&quot;https://en.wikipedia.org/wiki/Very_long_instruction_word&quot;&gt;VLIW&lt;/a&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&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;퀄컴에 따르면 RISC에서 29개의 명령어로 이루어진 고속 푸리에 변환 작업을 1클럭만으로 실행시키는 경우도 있다.&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;640&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3IU8M/btrUwtfMRab/Z7fZ4k4kKJSWHvPqenLMr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3IU8M/btrUwtfMRab/Z7fZ4k4kKJSWHvPqenLMr1/img.png&quot; data-alt=&quot;낮은 클럭에서도 높은 성능을 보여줌&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3IU8M/btrUwtfMRab/Z7fZ4k4kKJSWHvPqenLMr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3IU8M%2FbtrUwtfMRab%2FZ7fZ4k4kKJSWHvPqenLMr1%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;640&quot; height=&quot;353&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;353&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;말이 나온겸 VLIW에 대해서도 알아보자. [&lt;a href=&quot;https://www.isi.edu/~youngcho/cse560m/vliw.pdf&quot;&gt;Very-Long Instruction Word (VLIW) Computer Architecture&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://inst.eecs.berkeley.edu/~cs152/sp18/lectures/L13-VLIW.pdf&quot;&gt;Advanced&amp;nbsp;Out-of-Order&amp;nbsp;Superscalars&amp;nbsp;and&amp;nbsp;IntroducBon&amp;nbsp;to&amp;nbsp;VLIW&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;종속성이 없는 명령어 여러개를 한번에 처리(Execute)하는 명령어 처리기법이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nxSjG/btrUwrWxDRc/CZ67FNMYwwIKh1OUaeNHh0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nxSjG/btrUwrWxDRc/CZ67FNMYwwIKh1OUaeNHh0/img.gif&quot; width=&quot;555&quot; height=&quot;348&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;348&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.1965%; margin-right: 10px;&quot; data-widthpercent=&quot;51.8&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nxSjG/btrUwrWxDRc/CZ67FNMYwwIKh1OUaeNHh0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnxSjG%2FbtrUwrWxDRc%2FCZ67FNMYwwIKh1OUaeNHh0%2Fimg.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;555&quot; height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/stnTw/btrUukcCAjw/EMl6lYy7xPAPE3AJacAqu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/stnTw/btrUukcCAjw/EMl6lYy7xPAPE3AJacAqu1/img.png&quot; width=&quot;960&quot; height=&quot;646&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;690&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;48.2&quot; style=&quot;width: 47.6407%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/stnTw/btrUukcCAjw/EMl6lYy7xPAPE3AJacAqu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FstnTw%2FbtrUukcCAjw%2FEMl6lYy7xPAPE3AJacAqu1%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;1024&quot; height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;a href=&quot;http://ixbtlabs.com/articles2/vliw/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VLIW architecture&lt;/a&gt;, &lt;a href=&quot;https://de.wikipedia.org/wiki/Very_Long_Instruction_Word&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VLIW Pipeline&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 병렬처리가 가능하고, CPU에서 스케쥴링(&lt;a href=&quot;https://en.wikipedia.org/wiki/Superscalar_processor&quot;&gt;슈퍼스칼라&lt;/a&gt;&lt;span&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Out-of-order_execution&quot;&gt;비순차적 실행&lt;/a&gt;)이 없어 회로가 간단해짐&lt;/li&gt;
&lt;li&gt;단점: 의존성이 강한 연속적인 명령어(병렬불가)는 비효율적, 컴파일러의 제작 난이도가 높음, 분기예측과 캐시미스에 취약함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한마디로 말해서 CPU에서 하던 스케쥴링 작업을 컴파일 타임에 해버리고 하드웨어에서는 그냥 실행만 하는 구조로 효율적 클럭사용, 작은 유닛 크기를 얻겠다는 전략인데..&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;그러나 DSP의 경우 데이터 처리자체가 스트리밍에 가깝기에 캐시미스가 중요하지 않고 신호처리는 병렬처리를 요구하므로 VLIW와 잘 맞아떨어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 캐시관련 특수성 때문에 폰노이만이 아닌, &lt;a href=&quot;https://en.wikipedia.org/wiki/Harvard_architecture&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;VLIW 설명겸 &lt;span&gt;인텔과 HP가 심취했다 타격받았던 불운의 설계,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Explicitly_parallel_instruction_computing&quot;&gt;EPIC&lt;/a&gt;도 알아보자. [&lt;a href=&quot;https://www.slideserve.com/makani/epic-architecture-explicitly-parallel-instruction-computing&quot;&gt;EPIC&amp;nbsp;Architecture&amp;nbsp;(Explicitly&amp;nbsp;Parallel&amp;nbsp;Instruction&amp;nbsp;Computing)&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.slideserve.com/terra/the-ia-64-architecture-and-itanium-processors-explicitly-parallel-instruction-computing&quot;&gt;The&amp;nbsp;IA-64&amp;nbsp;architecture&amp;nbsp;and&amp;nbsp;Itanium&amp;nbsp;processors&amp;nbsp;Explicitly&amp;nbsp;Parallel&amp;nbsp;Instruction&amp;nbsp;Computing&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://people.computing.clemson.edu/~mark/epic.html&quot;&gt;Historical&amp;nbsp;background&amp;nbsp;for&amp;nbsp;EPIC&amp;nbsp;instruction&amp;nbsp;set&amp;nbsp;architectures&lt;/a&gt;, &lt;a href=&quot;https://www.cs.nmsu.edu/~rvinyard/itanium/ia64.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IA-64&lt;/a&gt;, &lt;a href=&quot;https://www.cs.auckland.ac.nz/compsci703s1c/resources/Smothermanacmse_epic.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Understanding&amp;nbsp;EPIC&amp;nbsp;Architectures&amp;nbsp;and&amp;nbsp;Implementations&lt;/a&gt;, &lt;a href=&quot;https://www.cs.helsinki.fi/u/kerola/tikra/IA64-Architecture.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IA-64&amp;nbsp;Architecture&amp;nbsp;Overview&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;간단히 말하면 슈퍼스칼라와 비순차적 실행을 VLIW에 접목해 보다 효율적이고 범용적으로 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 놀고있는 CPU를 컴파일러단에서 병렬적으로 만들어 최대한 일하게 만들기 위한게 목적.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 비슷한 목적으로 하이퍼 스레드가 사용되나 설계의 관점으로만 보면 컴파일러만로 장기적인 성능개선이 가능한 EPIC이 좋아보이기는 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ejE0np/btrUuBzbGYl/1bOCkj6ekzeLN4vMd3bGQ1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ejE0np/btrUuBzbGYl/1bOCkj6ekzeLN4vMd3bGQ1/img.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;540&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ejE0np/btrUuBzbGYl/1bOCkj6ekzeLN4vMd3bGQ1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FejE0np%2FbtrUuBzbGYl%2F1bOCkj6ekzeLN4vMd3bGQ1%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;720&quot; height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJYPce/btrUujd56Ds/l73zrXfL7qkkmS6uvs5YG0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJYPce/btrUujd56Ds/l73zrXfL7qkkmS6uvs5YG0/img.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;540&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJYPce/btrUujd56Ds/l73zrXfL7qkkmS6uvs5YG0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJYPce%2FbtrUujd56Ds%2Fl73zrXfL7qkkmS6uvs5YG0%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;720&quot; height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/div&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;먼저 전반적인 명령어 구조는 VLIW와 비슷하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 전부 다 컴파일러가 감당해야 해서 비결정적 메모리 접근등의 문제를 해결하기 어려웠던 VLIW와 달리 작업그룹 종속성에 대한 표현을 위주로 하도록 만들어져 슈퍼스칼라와 가까워진 방향으로 설계되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dynamic VLIW는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Transmeta&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;트랜스메타&lt;/a&gt;의 &lt;a href=&quot;https://en.wikipedia.org/wiki/Transmeta_Crusoe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;크루소&lt;/a&gt; 방식으로 알려져 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz1nDF/btrUBaNtqR8/jQmsEurAvB5LBFuMBVC5k0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz1nDF/btrUBaNtqR8/jQmsEurAvB5LBFuMBVC5k0/img.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;540&quot; data-is-animation=&quot;false&quot; style=&quot;width: 28.2025%; margin-right: 10px;&quot; data-widthpercent=&quot;28.87&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz1nDF/btrUBaNtqR8/jQmsEurAvB5LBFuMBVC5k0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz1nDF%2FbtrUBaNtqR8%2FjQmsEurAvB5LBFuMBVC5k0%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;720&quot; height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebXOY7/btrUyCp4nhL/zSLSyuHdTA4tXGRe1PqRLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebXOY7/btrUyCp4nhL/zSLSyuHdTA4tXGRe1PqRLk/img.png&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;895&quot; data-is-animation=&quot;false&quot; style=&quot;width: 28.2419%; margin-right: 10px;&quot; data-widthpercent=&quot;28.91&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebXOY7/btrUyCp4nhL/zSLSyuHdTA4tXGRe1PqRLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebXOY7%2FbtrUyCp4nhL%2FzSLSyuHdTA4tXGRe1PqRLk%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;1195&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oMbl4/btrUtGODn0j/D7wLdeZQ5Iv5kIwKDvD541/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oMbl4/btrUtGODn0j/D7wLdeZQ5Iv5kIwKDvD541/img.png&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;394&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;42.22&quot; style=&quot;width: 41.23%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oMbl4/btrUtGODn0j/D7wLdeZQ5Iv5kIwKDvD541/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoMbl4%2FbtrUtGODn0j%2FD7wLdeZQ5Iv5kIwKDvD541%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;768&quot; height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;/div&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;a href=&quot;https://en.wikipedia.org/wiki/Branch_(computer_science)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;분기&lt;/a&gt;를 줄일 수 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dc8YhG/btrUuh1F234/3W2CGjlTI5bkGb8Aq5IaUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dc8YhG/btrUuh1F234/3W2CGjlTI5bkGb8Aq5IaUK/img.png&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;895&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dc8YhG/btrUuh1F234/3W2CGjlTI5bkGb8Aq5IaUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdc8YhG%2FbtrUuh1F234%2F3W2CGjlTI5bkGb8Aq5IaUK%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;1195&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X95Zo/btrUwrvPLdS/BWzlHN2GUleuGK45zJgOy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X95Zo/btrUwrvPLdS/BWzlHN2GUleuGK45zJgOy1/img.png&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;895&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X95Zo/btrUwrvPLdS/BWzlHN2GUleuGK45zJgOy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX95Zo%2FbtrUwrvPLdS%2FBWzlHN2GUleuGK45zJgOy1%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;1195&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;/div&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EyGeF/btrUyh7oIVD/EEZKDN915fu84HK3Nsp461/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EyGeF/btrUyh7oIVD/EEZKDN915fu84HK3Nsp461/img.png&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;895&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EyGeF/btrUyh7oIVD/EEZKDN915fu84HK3Nsp461/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEyGeF%2FbtrUyh7oIVD%2FEEZKDN915fu84HK3Nsp461%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;1195&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qtdfG/btrUuos1Xas/kDAwjpcXDYzcn1cmcuRzMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qtdfG/btrUuos1Xas/kDAwjpcXDYzcn1cmcuRzMk/img.png&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;895&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qtdfG/btrUuos1Xas/kDAwjpcXDYzcn1cmcuRzMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqtdfG%2FbtrUuos1Xas%2FkDAwjpcXDYzcn1cmcuRzMk%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;1195&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwgyDh/btrUvVjzzyz/nltltQHNIdpHduYA9RIzzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwgyDh/btrUvVjzzyz/nltltQHNIdpHduYA9RIzzk/img.png&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;895&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwgyDh/btrUvVjzzyz/nltltQHNIdpHduYA9RIzzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwgyDh%2FbtrUvVjzzyz%2FnltltQHNIdpHduYA9RIzzk%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;1195&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8ZTGT/btrUuYA09V7/KDlJ4njRHBpp089TqKYCHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8ZTGT/btrUuYA09V7/KDlJ4njRHBpp089TqKYCHk/img.png&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;895&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8ZTGT/btrUuYA09V7/KDlJ4njRHBpp089TqKYCHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8ZTGT%2FbtrUuYA09V7%2FKDlJ4njRHBpp089TqKYCHk%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;1195&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;제어와 데이터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ALAT(Advancded Load Address Table)이 특이한데, 다음과 같이 이루어진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7YKe6/btrUt7FgTf0/n2xhuQKZ3kcLbiMQW9BWHk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7YKe6/btrUt7FgTf0/n2xhuQKZ3kcLbiMQW9BWHk/img.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;540&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.97&quot; style=&quot;width: 49.3841%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7YKe6/btrUt7FgTf0/n2xhuQKZ3kcLbiMQW9BWHk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7YKe6%2FbtrUt7FgTf0%2Fn2xhuQKZ3kcLbiMQW9BWHk%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;720&quot; height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmdAVJ/btrUurpJ2U5/pnLhPkBWZ56KMkHOpzcBF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmdAVJ/btrUurpJ2U5/pnLhPkBWZ56KMkHOpzcBF0/img.png&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;895&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4531%;&quot; data-widthpercent=&quot;50.03&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmdAVJ/btrUurpJ2U5/pnLhPkBWZ56KMkHOpzcBF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmdAVJ%2FbtrUurpJ2U5%2FpnLhPkBWZ56KMkHOpzcBF0%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;1195&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로드한 메모리(ld.a)의 레지스터(r1)를 엔트리에 추가&lt;/li&gt;
&lt;li&gt;추가를 시도시 충돌이 나면 엔트리에서 제거&lt;/li&gt;
&lt;li&gt;추후 체크(chk.a)할 때 엔트리에 존재하면 성공, 없으면 실패를 의미하므로 분기함&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RRB(Register Rotation Base)는 루프 언롤링 대신 하위집합에 대한 엑세스 이름을 바꾸어 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GR(General Register), FP(Floating Point Resisters)가 대표적인 예였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 RRB의 값이 10일때, GR[35] 참조는 GR[45]의 값을 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JkcmN/btrUtGODjCR/oFNd9M5OXWCy1KCIWDvzeK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JkcmN/btrUtGODjCR/oFNd9M5OXWCy1KCIWDvzeK/img.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;540&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.543%; margin-right: 10px;&quot; data-widthpercent=&quot;33.32&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JkcmN/btrUtGODjCR/oFNd9M5OXWCy1KCIWDvzeK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJkcmN%2FbtrUtGODjCR%2FoFNd9M5OXWCy1KCIWDvzeK%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;720&quot; height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mDTVs/btrUt85fhHI/O6LvKDU7SrMtyn5f7fPtI0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mDTVs/btrUt85fhHI/O6LvKDU7SrMtyn5f7fPtI0/img.jpg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;540&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.543%; margin-right: 10px;&quot; data-widthpercent=&quot;33.32&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mDTVs/btrUt85fhHI/O6LvKDU7SrMtyn5f7fPtI0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmDTVs%2FbtrUt85fhHI%2FO6LvKDU7SrMtyn5f7fPtI0%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;720&quot; height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKQc9Y/btrUuBeM0V7/vfFkoMUKyWhWFUeaiWyMW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKQc9Y/btrUuBeM0V7/vfFkoMUKyWhWFUeaiWyMW0/img.png&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;895&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5884%;&quot; data-widthpercent=&quot;33.36&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKQc9Y/btrUuBeM0V7/vfFkoMUKyWhWFUeaiWyMW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKQc9Y%2FbtrUuBeM0V7%2FvfFkoMUKyWhWFUeaiWyMW0%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;1195&quot; height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;/div&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;이와 반대로 하드웨어 레벨 JIT을 최대한 활용해버리는 방식이 블로그에서 몇번 언급했었던 &lt;a href=&quot;https://www.cs.york.ac.uk/fp/reduceron/&quot;&gt;The Reduceon&lt;/a&gt;이라는 함수형 아키텍쳐다. [&lt;a href=&quot;https://github.com/tommythorn/Reduceron&quot;&gt;Reduceron,&amp;nbsp;an&amp;nbsp;efficient&amp;nbsp;processor&amp;nbsp;for&amp;nbsp;functional&amp;nbsp;programs&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://citeseerx.ist.psu.edu/document?repid=rep1&amp;amp;type=pdf&amp;amp;doi=4ce9630ce73141514acbf5a1cbc4c771f52f6e62&quot;&gt;The&amp;nbsp;Reduceron:&amp;nbsp;Widening&amp;nbsp;the&amp;nbsp;von&amp;nbsp;Neumann&amp;nbsp;Bottleneck&amp;nbsp;for&amp;nbsp;Graph&amp;nbsp;Reduction&amp;nbsp;Using&amp;nbsp;an&amp;nbsp;FPGA&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;91.5MHz FPGA에서 2.8GHz Pentium급 성능을 냈다나.&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://news.hada.io/topic?id=7311&quot;&gt;HVM&lt;/a&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;FPGA&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.xilinx.com/r/en-US/ug1393-vitis-application-acceleration/Design-Migration&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Understanding&amp;nbsp;an&amp;nbsp;FPGA&amp;nbsp;Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rapidwright.io/docs/FPGA_Architecture.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FPGA&amp;nbsp;Architecture&amp;nbsp;Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hardwarebee.com/the-ultimate-guide-to-fpga-architecture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Ultimate Guide to FPGA Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://indico.cern.ch/event/766995/contributions/3295773/attachments/1802757/2940958/Alexander_Ruede_-_A_Scientists_Guide_to_FPGAs_AScientistsGuideToFPGAs.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Scientist&amp;rsquo;s&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;FPGAs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Field-programmable_gate_array&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FPGA&lt;/a&gt;는 프로그래밍 가능한 반도체다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VB1WH/btrUuBMDoRY/7fcMreqMkvXzxdlI6LD2P0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VB1WH/btrUuBMDoRY/7fcMreqMkvXzxdlI6LD2P0/img.png&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;519&quot; data-is-animation=&quot;false&quot; style=&quot;width: 59.5333%; margin-right: 10px;&quot; data-widthpercent=&quot;60.23&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VB1WH/btrUuBMDoRY/7fcMreqMkvXzxdlI6LD2P0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVB1WH%2FbtrUuBMDoRY%2F7fcMreqMkvXzxdlI6LD2P0%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;519&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2xcvN/btrUum27CRt/l8IBnAipDqPpHIPMgMuV5K/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2xcvN/btrUum27CRt/l8IBnAipDqPpHIPMgMuV5K/img.webp&quot; width=&quot;458&quot; height=&quot;635&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;635&quot; data-is-animation=&quot;false&quot; style=&quot;width: 39.3039%;&quot; data-widthpercent=&quot;39.77&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2xcvN/btrUum27CRt/l8IBnAipDqPpHIPMgMuV5K/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2xcvN%2FbtrUum27CRt%2Fl8IBnAipDqPpHIPMgMuV5K%2Fimg.webp&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;458&quot; height=&quot;635&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;자일링스와 알테라 FPGA 아키텍처&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;FPGA는 Switch의 연결에 따라 라우팅되며, 핵심인 CLB를 자세히 들여다보면 LUT(Lookup Table), &lt;a href=&quot;https://en.wikipedia.org/wiki/Flip-flop_(electronics)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;플립플롭(Flip Floop)&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Multiplexer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;멀티플렉서(Multiplexer)&lt;/a&gt;로 이루어졌다. [&lt;a href=&quot;https://www.researchgate.net/figure/Island-style-global-FPGA-architecture-A-unit-tile-consists-of-Configurable-Logic-Block_fig6_323820898&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Performance&amp;nbsp;Analysis&amp;nbsp;of&amp;nbsp;Nanoelectromechanical&amp;nbsp;Relay-Based&amp;nbsp;Field-Programmable&amp;nbsp;Gate&amp;nbsp;Arrays&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P6ws8/btrUuBzeI2s/Tx8EEg3h1y0dxrGDEPvkqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P6ws8/btrUuBzeI2s/Tx8EEg3h1y0dxrGDEPvkqK/img.png&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;380&quot; data-is-animation=&quot;false&quot; style=&quot;width: 39.7666%; margin-right: 10px;&quot; data-widthpercent=&quot;40.23&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P6ws8/btrUuBzeI2s/Tx8EEg3h1y0dxrGDEPvkqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP6ws8%2FbtrUuBzeI2s%2FTx8EEg3h1y0dxrGDEPvkqK%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;714&quot; height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djhvTb/btrUA98TqxX/kPrwNV2KyKs0jTCMpp7QKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djhvTb/btrUA98TqxX/kPrwNV2KyKs0jTCMpp7QKk/img.png&quot; width=&quot;561&quot; height=&quot;201&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;201&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;59.77&quot; style=&quot;width: 59.0706%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djhvTb/btrUA98TqxX/kPrwNV2KyKs0jTCMpp7QKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjhvTb%2FbtrUA98TqxX%2FkPrwNV2KyKs0jTCMpp7QKk%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;561&quot; height=&quot;201&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;스위치와 CLB 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LUT: 논리기능&lt;/li&gt;
&lt;li&gt;Flip Floop: 순차논리&lt;/li&gt;
&lt;li&gt;Mux: 조합논리와 순차논리 중 데이터 출력을 선택&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbJF9F/btrUt2jDBHA/jFKRmLH4jT1CupdBBzyVt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbJF9F/btrUt2jDBHA/jFKRmLH4jT1CupdBBzyVt1/img.png&quot; data-alt=&quot;멀티플렉서&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbJF9F/btrUt2jDBHA/jFKRmLH4jT1CupdBBzyVt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbJF9F%2FbtrUt2jDBHA%2FjFKRmLH4jT1CupdBBzyVt1%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;960&quot; height=&quot;374&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;401&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;LUT는 멀티플렉서와 S램을 사용해 논리 연산을 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 3비트 LUT는 8비트 SRAM과 트리형태의 7개 멀티플렉서로 구성되어 3비트에서 가능한 모든 논리연산을 수행할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5GHW3/btrUur4lUXf/urU2P4ts92yu4YTQLBiLrK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5GHW3/btrUur4lUXf/urU2P4ts92yu4YTQLBiLrK/img.webp&quot; width=&quot;458&quot; height=&quot;503&quot; data-ll-status=&quot;loaded&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;503&quot; data-is-animation=&quot;false&quot; style=&quot;width: 19.9982%; margin-right: 10px;&quot; data-widthpercent=&quot;20.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5GHW3/btrUur4lUXf/urU2P4ts92yu4YTQLBiLrK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5GHW3%2FbtrUur4lUXf%2FurU2P4ts92yu4YTQLBiLrK%2Fimg.webp&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;458&quot; height=&quot;503&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6Rx8W/btrUt7ZBYBm/nUgqWrGGMnOOoor6rvVWi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6Rx8W/btrUt7ZBYBm/nUgqWrGGMnOOoor6rvVWi1/img.png&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;503&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.0263%; margin-right: 10px;&quot; data-widthpercent=&quot;48.15&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6Rx8W/btrUt7ZBYBm/nUgqWrGGMnOOoor6rvVWi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6Rx8W%2FbtrUt7ZBYBm%2FnUgqWrGGMnOOoor6rvVWi1%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;1077&quot; height=&quot;503&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s3DaI/btrUt1rrTtA/OzW8OIhk208h4F0ydTkMpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s3DaI/btrUt1rrTtA/OzW8OIhk208h4F0ydTkMpK/img.png&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;804&quot; data-is-animation=&quot;false&quot; style=&quot;width: 30.65%;&quot; data-widthpercent=&quot;31.38&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s3DaI/btrUt1rrTtA/OzW8OIhk208h4F0ydTkMpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs3DaI%2FbtrUt1rrTtA%2FOzW8OIhk208h4F0ydTkMpK%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;1122&quot; height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;LUT 구조와 동작&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;플립플롭으로는 D플립플롭을 사용하며, 회로와 진리표는 다음과 같다. [&lt;a href=&quot;https://www.javatpoint.com/d-flip-flop-in-digital-electronics&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;D&amp;nbsp;Flip&amp;nbsp;Flop&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUHKzk/btrUuvMfl5z/9EVv5LcrhMHJASdAqQVaq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUHKzk/btrUuvMfl5z/9EVv5LcrhMHJASdAqQVaq0/img.png&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;266&quot; data-is-animation=&quot;false&quot; style=&quot;width: 39.0269%; margin-right: 10px;&quot; data-widthpercent=&quot;39.49&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUHKzk/btrUuvMfl5z/9EVv5LcrhMHJASdAqQVaq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUHKzk%2FbtrUuvMfl5z%2F9EVv5LcrhMHJASdAqQVaq0%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;478&quot; height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UUnYF/btrUunnnGDY/MRpkkbZ3iEGsQGv4HIySoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UUnYF/btrUunnnGDY/MRpkkbZ3iEGsQGv4HIySoK/img.png&quot; data-origin-width=&quot;347&quot; data-origin-height=&quot;126&quot; data-is-animation=&quot;false&quot; style=&quot;width: 59.8103%;&quot; data-widthpercent=&quot;60.51&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UUnYF/btrUunnnGDY/MRpkkbZ3iEGsQGv4HIySoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUUnYF%2FbtrUunnnGDY%2FMRpkkbZ3iEGsQGv4HIySoK%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;347&quot; height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/div&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;최신 FPGA는 연산속도를 올리고 라우팅을 줄이기 위해 6입력 LUT와 산술 연산을 위한 &lt;a href=&quot;https://www.fpga4fun.com/Counters4.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Carry chain&lt;/a&gt;를 CLB에 통합하고, 곱셈 계산을 위한 DSP등을 사용해 LUT를 보완하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q1Sct/btrUxfaXSl9/q8HK7AWmUwGip2fnPrOFAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q1Sct/btrUxfaXSl9/q8HK7AWmUwGip2fnPrOFAk/img.png&quot; data-origin-width=&quot;2037&quot; data-origin-height=&quot;1282&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.8124%; margin-right: 10px;&quot; data-widthpercent=&quot;44.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q1Sct/btrUxfaXSl9/q8HK7AWmUwGip2fnPrOFAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ1Sct%2FbtrUxfaXSl9%2Fq8HK7AWmUwGip2fnPrOFAk%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;2037&quot; height=&quot;1282&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj0IAN/btrUBafFm5R/UTeQ7m3qkYBxf8NF8qNa31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj0IAN/btrUBafFm5R/UTeQ7m3qkYBxf8NF8qNa31/img.png&quot; width=&quot;449&quot; height=&quot;225&quot; data-ll-status=&quot;loaded&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;225&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.0248%;&quot; data-widthpercent=&quot;55.67&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj0IAN/btrUBafFm5R/UTeQ7m3qkYBxf8NF8qNa31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj0IAN%2FbtrUBafFm5R%2FUTeQ7m3qkYBxf8NF8qNa31%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;449&quot; height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;CLB와 6입력 LUT&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coLZly/btrUxeb6jmq/rauczKpBcHuXJXKgKxMV20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coLZly/btrUxeb6jmq/rauczKpBcHuXJXKgKxMV20/img.png&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coLZly/btrUxeb6jmq/rauczKpBcHuXJXKgKxMV20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoLZly%2FbtrUxeb6jmq%2FrauczKpBcHuXJXKgKxMV20%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;1600&quot; height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7eMIh/btrUumPBCJn/FaxVkKDDmIlBem6KgF2NxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7eMIh/btrUumPBCJn/FaxVkKDDmIlBem6KgF2NxK/img.png&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7eMIh/btrUumPBCJn/FaxVkKDDmIlBem6KgF2NxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7eMIh%2FbtrUumPBCJn%2FFaxVkKDDmIlBem6KgF2NxK%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;1600&quot; height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;li&gt;메모리 계층이 유연&lt;/li&gt;
&lt;/ul&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u4zSe/btrUulwd0Qq/4k4qc8IcxyiYMkgYni3FL1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u4zSe/btrUulwd0Qq/4k4qc8IcxyiYMkgYni3FL1/img.webp&quot; width=&quot;397&quot; height=&quot;436&quot; data-origin-width=&quot;397&quot; data-origin-height=&quot;436&quot; data-is-animation=&quot;false&quot; style=&quot;width: 16.697%; margin-right: 10px;&quot; data-widthpercent=&quot;17.09&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u4zSe/btrUulwd0Qq/4k4qc8IcxyiYMkgYni3FL1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu4zSe%2FbtrUulwd0Qq%2F4k4qc8IcxyiYMkgYni3FL1%2Fimg.webp&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;436&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br4Wtg/btrUvYgtHS9/KFH2IN4GaK2UUGZcKJ4k61/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br4Wtg/btrUvYgtHS9/KFH2IN4GaK2UUGZcKJ4k61/img.webp&quot; width=&quot;625&quot; height=&quot;432&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;432&quot; data-is-animation=&quot;false&quot; style=&quot;width: 26.5297%; margin-right: 10px;&quot; data-widthpercent=&quot;27.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br4Wtg/btrUvYgtHS9/KFH2IN4GaK2UUGZcKJ4k61/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr4Wtg%2FbtrUvYgtHS9%2FKFH2IN4GaK2UUGZcKJ4k61%2Fimg.webp&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;625&quot; height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJqK0m/btrUA98STlE/VPtezOT9dMkMfPa3eCpigK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJqK0m/btrUA98STlE/VPtezOT9dMkMfPa3eCpigK/img.webp&quot; width=&quot;772&quot; height=&quot;260&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;260&quot; data-is-animation=&quot;false&quot; style=&quot;width: 54.4477%;&quot; data-widthpercent=&quot;55.75&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJqK0m/btrUA98STlE/VPtezOT9dMkMfPa3eCpigK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJqK0m%2FbtrUA98STlE%2FVPtezOT9dMkMfPa3eCpigK%2Fimg.webp&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;772&quot; height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;FPGA 파이프라인&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;h4 data-ke-size=&quot;size20&quot;&gt;TPU&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/blog/products/ai-machine-learning/what-makes-tpus-fine-tuned-for-deep-learning&quot;&gt;What&amp;nbsp;makes&amp;nbsp;TPUs&amp;nbsp;fine-tuned&amp;nbsp;for&amp;nbsp;deep&amp;nbsp;learning?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/blog/products/ai-machine-learning/an-in-depth-look-at-googles-first-tensor-processing-unit-tpu&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;An&amp;nbsp;in-depth&amp;nbsp;look&amp;nbsp;at&amp;nbsp;Google&amp;rsquo;s&amp;nbsp;first&amp;nbsp;Tensor&amp;nbsp;Processing&amp;nbsp;Unit&amp;nbsp;(TPU)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/tpu/docs/system-architecture-tpu-vm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cloud TPU - &amp;nbsp;System&amp;nbsp;Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.analyticsvidhya.com/blog/2022/08/evolution-of-tpus-and-gpus-in-deep-learning-applications/&quot;&gt;Evolution of TPUs and GPUs in Deep Learning Applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Tensor_Processing_Unit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TPU(Tensor&amp;nbsp;Processing&amp;nbsp;Unit)&lt;/a&gt;는 대표적인 &lt;a href=&quot;https://en.wikipedia.org/wiki/Application-specific_integrated_circuit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ASIC(주문형 반도체, Application-Specific Integrated Circuit)&lt;/a&gt;의 예이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TTeQP/btrUxfaZuIs/NeW6JrSOXUVGBpGiNSxpA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TTeQP/btrUxfaZuIs/NeW6JrSOXUVGBpGiNSxpA1/img.png&quot; data-alt=&quot;TPU v4 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TTeQP/btrUxfaZuIs/NeW6JrSOXUVGBpGiNSxpA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTTeQP%2FbtrUxfaZuIs%2FNeW6JrSOXUVGBpGiNSxpA1%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;762&quot; height=&quot;260&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TPU v4 아키텍처&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;대체 어떠한 이유로 TPU를 만들었는가에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 신경망의 작동방식이다. (GIF 크기가 크므로 새탭에서 열어 확인해보세요)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsSBgp/btrUwrvXGTL/Q70w1WzhFpQI3HUvrIGDTK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsSBgp/btrUwrvXGTL/Q70w1WzhFpQI3HUvrIGDTK/img.gif&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;748&quot; data-is-animation=&quot;true&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsSBgp/btrUwrvXGTL/Q70w1WzhFpQI3HUvrIGDTK/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsSBgp%2FbtrUwrvXGTL%2FQ70w1WzhFpQI3HUvrIGDTK%2Fimg.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;1568&quot; height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bikDX4/btrUtFa9MMO/QrHak0Lubh4bLhqUFgin4k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bikDX4/btrUtFa9MMO/QrHak0Lubh4bLhqUFgin4k/img.gif&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;748&quot; data-is-animation=&quot;true&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bikDX4/btrUtFa9MMO/QrHak0Lubh4bLhqUFgin4k/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbikDX4%2FbtrUtFa9MMO%2FQrHak0Lubh4bLhqUFgin4k%2Fimg.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;1568&quot; height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;784개(28x28)의 벡터로 변환 [입력데이터]&lt;/li&gt;
&lt;li&gt;숫자 &quot;8&quot;을 인식하는 뉴런은 입력값 매개변수 값(가중치, 빨간선)을 곱함&lt;br /&gt;(매개변수는 이미지와 &quot;8&quot; 모양의 유사성을 알려주는 특징을 데이터에서 추출하는 필터 역할)&lt;/li&gt;
&lt;li&gt;곱한 값은 신호강도를 뜻하며, 모두 더하여 가장 높은 결과가 정답일 가능성이 높음&lt;/li&gt;
&lt;/ol&gt;
&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;TPU의 MXU(Matrix Multiplication Unit)이 바로 곱셈과 가산기의 배열인데, 128x128 곱셉/가산기다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yGCJW/btrUyiFrbPk/Wwjpav8Vrff5lT3vQHlx40/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yGCJW/btrUyiFrbPk/Wwjpav8Vrff5lT3vQHlx40/img.gif&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;748&quot; data-is-animation=&quot;true&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yGCJW/btrUyiFrbPk/Wwjpav8Vrff5lT3vQHlx40/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyGCJW%2FbtrUyiFrbPk%2FWwjpav8Vrff5lT3vQHlx40%2Fimg.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;1568&quot; height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AOZmG/btrUDiLpZNW/chQMabjKgCJ6asajeHb650/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AOZmG/btrUDiLpZNW/chQMabjKgCJ6asajeHb650/img.gif&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;748&quot; data-is-animation=&quot;true&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AOZmG/btrUDiLpZNW/chQMabjKgCJ6asajeHb650/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAOZmG%2FbtrUDiLpZNW%2FchQMabjKgCJ6asajeHb650%2Fimg.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;1568&quot; height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYc4ki/btrUuHTDPow/Rzi8KCdVA6lHEgmJP4HCT0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYc4ki/btrUuHTDPow/Rzi8KCdVA6lHEgmJP4HCT0/img.gif&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;748&quot; data-is-animation=&quot;true&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYc4ki/btrUuHTDPow/Rzi8KCdVA6lHEgmJP4HCT0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYc4ki%2FbtrUuHTDPow%2FRzi8KCdVA6lHEgmJP4HCT0%2Fimg.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;1568&quot; height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;CPU, GPU, TPU&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU: 순서대로 처리하며, 계산결과는 매번 내부 메모리(레지스터, 캐시)에 저장&lt;/li&gt;
&lt;li&gt;GPU: 대규모로 병렬연산을 수행함, 그러나 역시 중간 계산 결과를 읽고 저장하기 위해 내부 메모리에 접근해야함&lt;/li&gt;
&lt;li&gt;TPU: 모든 계산 단계를 알고 있으므로, 수천개의 곱셈/가산기를 배치하고 서로 직접 연결해 &lt;a href=&quot;https://en.wikipedia.org/wiki/Systolic_array&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Systolic Array&lt;/a&gt;구조를 만들어 중간단계에는 메모리에 접근할 필요가 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아키텍쳐상 두개의 장점이 있다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SIMD나 GPU의 벡터처리에서 확장해 행렬단위를 단일 클럭에서 처리할 수 있으며, Systolic Array 구조로 중간에 메모리에 접근하지 않는 다는 것.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wBO63/btrUyi6t2JR/JdLxSmaqeMgubTiZYAkCEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wBO63/btrUyi6t2JR/JdLxSmaqeMgubTiZYAkCEk/img.png&quot; data-alt=&quot;계산 단위&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wBO63/btrUyi6t2JR/JdLxSmaqeMgubTiZYAkCEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwBO63%2FbtrUyi6t2JR%2FJdLxSmaqeMgubTiZYAkCEk%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;1200&quot; height=&quot;504&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;계산 단위&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T32MI/btrUwqDSCLw/hmhk5R9a51vQovYvJWxayK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T32MI/btrUwqDSCLw/hmhk5R9a51vQovYvJWxayK/img.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;412&quot; data-is-animation=&quot;false&quot; style=&quot;width: 24.4408%; margin-right: 10px;&quot; data-widthpercent=&quot;25.02&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T32MI/btrUwqDSCLw/hmhk5R9a51vQovYvJWxayK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT32MI%2FbtrUwqDSCLw%2Fhmhk5R9a51vQovYvJWxayK%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;500&quot; height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cT14yX/btrUwpyaLuP/xotVwpk1WDhCJTbt3Z4ZSk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cT14yX/btrUwpyaLuP/xotVwpk1WDhCJTbt3Z4ZSk/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;220&quot; data-is-animation=&quot;true&quot; data-widthpercent=&quot;37.49&quot; style=&quot;width: 36.6168%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cT14yX/btrUwpyaLuP/xotVwpk1WDhCJTbt3Z4ZSk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcT14yX%2FbtrUwpyaLuP%2FxotVwpk1WDhCJTbt3Z4ZSk%2Fimg.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;400&quot; height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q5xNi/btrUuPxxniw/JsW5tCND5AdbtV6UwTz6I1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q5xNi/btrUuPxxniw/JsW5tCND5AdbtV6UwTz6I1/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;220&quot; data-is-animation=&quot;true&quot; style=&quot;width: 36.6168%;&quot; data-widthpercent=&quot;37.49&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q5xNi/btrUuPxxniw/JsW5tCND5AdbtV6UwTz6I1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq5xNi%2FbtrUuPxxniw%2FJsW5tCND5AdbtV6UwTz6I1%2Fimg.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;400&quot; height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;계산 과정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TPU는 커다란 부동소수점 연산(99번째 백분위수), 캐시, 분기예측, 비순차적 실행, 멀티프로세싱, 투기적 프리페칭, 주소병합, 멀티스레딩과 컨텍스트 전환등 범용 연산이 전혀 필요없는 결정론적 설계로 유닛을 효율적으로 쓸 수 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;405&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cx6ZRr/btrUwqw29EF/Pa3JFH2ZrCeRQtL0LPnQKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cx6ZRr/btrUwqw29EF/Pa3JFH2ZrCeRQtL0LPnQKK/img.png&quot; data-alt=&quot;TPU v1 - 2%에 불과한 컨트롤 유닛&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cx6ZRr/btrUwqw29EF/Pa3JFH2ZrCeRQtL0LPnQKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcx6ZRr%2FbtrUwqw29EF%2FPa3JFH2ZrCeRQtL0LPnQKK%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;500&quot; height=&quot;405&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;405&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TPU v1 - 2%에 불과한 컨트롤 유닛&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;최근에는 TelaMalloc이라고 할당을 효율적으로 하는 방식도 나와 할당을 효율적으로 해준다. [&lt;a href=&quot;https://www.aitimes.com/news/articleView.html?idxno=148699&quot;&gt;구글,&amp;nbsp;기계&amp;nbsp;학습&amp;nbsp;가속&amp;nbsp;위한&amp;nbsp;메모리&amp;nbsp;할당&amp;nbsp;기법&amp;nbsp;개발...최대&amp;nbsp;2배&amp;nbsp;속도&amp;nbsp;향상&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCpNZb/btrUOQQibhV/VtTi78n2wweRDVnHMGpMBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCpNZb/btrUOQQibhV/VtTi78n2wweRDVnHMGpMBK/img.png&quot; data-alt=&quot;텔라말록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCpNZb/btrUOQQibhV/VtTi78n2wweRDVnHMGpMBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCpNZb%2FbtrUOQQibhV%2FVtTi78n2wweRDVnHMGpMBK%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;498&quot; height=&quot;192&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;192&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;a href=&quot;https://cloud.google.com/tpu/docs/bfloat16&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;bfloat16&lt;/a&gt;을 사용하고, 덧셈은 Float32를 사용한다. [&lt;a href=&quot;https://cloud.google.com/blog/products/ai-machine-learning/bfloat16-the-secret-to-high-performance-on-cloud-tpus&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BFloat16:&amp;nbsp;The&amp;nbsp;secret&amp;nbsp;to&amp;nbsp;high&amp;nbsp;performance&amp;nbsp;on&amp;nbsp;Cloud&amp;nbsp;TPUs&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FtmAo/btrUwnNY95c/QQDyw9XTfrL3EFGKG3RqX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FtmAo/btrUwnNY95c/QQDyw9XTfrL3EFGKG3RqX0/img.png&quot; data-alt=&quot;bfloat16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FtmAo/btrUwnNY95c/QQDyw9XTfrL3EFGKG3RqX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFtmAo%2FbtrUwnNY95c%2FQQDyw9XTfrL3EFGKG3RqX0%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;960&quot; height=&quot;540&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;bfloat16&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;16bit이므로 32bit에 비해 적은 메모리를 사용하고 칩 크기도 줄일 수 있음&lt;/li&gt;
&lt;li&gt;신경망은 지수부(Exponent)가 가수부(Mantissa)보다 중요하므로 비율을 조정&lt;/li&gt;
&lt;li&gt;조정한 지수부의 크기는 Float32와 같으므로 Float32로의 변환이 쉬움&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷하게 부동소수점을 계산에 적합하게 만들자는 시도로 Posits가 있다. [&lt;a href=&quot;https://news.hada.io/topic?id=7510&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Posits,&amp;nbsp;AI의&amp;nbsp;수학을&amp;nbsp;향상시키는&amp;nbsp;새로운&amp;nbsp;종류의&amp;nbsp;숫자&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dy5h6U/btrUAb60b7O/kKBgJUSJwxs9u1DEwB9KJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dy5h6U/btrUAb60b7O/kKBgJUSJwxs9u1DEwB9KJK/img.png&quot; data-alt=&quot;CPU보다 83배, GPU보다 29배&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dy5h6U/btrUAb60b7O/kKBgJUSJwxs9u1DEwB9KJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdy5h6U%2FbtrUAb60b7O%2FkKBgJUSJwxs9u1DEwB9KJK%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;1200&quot; height=&quot;655&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;655&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CPU보다 83배, GPU보다 29배&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;마지막으로 TPU는 클러스터링인 &lt;a href=&quot;https://cloud.google.com/tpu/docs/training-on-tpu-pods&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TPU Pods&lt;/a&gt;을 구성해 부하를 분산할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nLPw5/btrUuwEASHR/9Q34kC4EJL5gMWsFDL2QBK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nLPw5/btrUuwEASHR/9Q34kC4EJL5gMWsFDL2QBK/img.gif&quot; data-alt=&quot;TPU Pod&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nLPw5/btrUuwEASHR/9Q34kC4EJL5gMWsFDL2QBK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/nLPw5/btrUuwEASHR/9Q34kC4EJL5gMWsFDL2QBK/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;1568&quot; height=&quot;748&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TPU Pod&lt;/figcaption&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;15. 참고&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;전반적으로 참고한 글 목록입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://nikgrozev.com/2015/07/14/overview-of-modern-concurrency-and-parallelism-concepts/&quot;&gt;Overview&amp;nbsp;of&amp;nbsp;Modern&amp;nbsp;Concurrency&amp;nbsp;and&amp;nbsp;Parallelism&amp;nbsp;Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.mineiros.io/how-to-use-multithreading-and-multiprocessing-a-beginners-guide-to-parallel-and-concurrent-a69b9dd21e9d&quot;&gt;How&amp;nbsp;to&amp;nbsp;use&amp;nbsp;Multithreading&amp;nbsp;and&amp;nbsp;Multiprocessing&amp;nbsp;&amp;mdash;&amp;nbsp;A&amp;nbsp;Beginner&amp;rsquo;s&amp;nbsp;guide&amp;nbsp;to&amp;nbsp;parallel&amp;nbsp;and&amp;nbsp;concurrent&amp;nbsp;programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sceweb.uhcl.edu/helm/RationalUnifiedProcess/process/workflow/ana_desi/co_cncry.htm#Managing%20threads%20of%20control&quot;&gt;Concepts:&amp;nbsp;&amp;nbsp;Concurrency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kaisellgren/Concurrency-concepts&quot;&gt;Concurrency, multi-threading and parallel programming concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.ibm.com/articles/l-async/&quot;&gt;Boost application performance using asynchronous I/O&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sqljunkieshare.com/2012/01/06/preemptive-vs-non-preemptive-and-multitasking-vs-multithreading/&quot;&gt;Preemptive&amp;nbsp;Vs&amp;nbsp;Non&amp;nbsp;Preemptive&amp;nbsp;and&amp;nbsp;Multitasking&amp;nbsp;vs&amp;nbsp;Multithreading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/traveloka-engineering/cooperative-vs-preemptive-a-quest-to-maximize-concurrency-power-3b10c5a920fe&quot;&gt;Cooperative&amp;nbsp;vs.&amp;nbsp;Preemptive:&amp;nbsp;a&amp;nbsp;quest&amp;nbsp;to&amp;nbsp;maximize&amp;nbsp;concurrency&amp;nbsp;power&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cgdirector.com/cpu-cores-vs-logical-processors-threads/&quot;&gt;&amp;nbsp;CPU&amp;nbsp;Cores&amp;nbsp;vs.&amp;nbsp;Logical&amp;nbsp;Processors&amp;nbsp;&amp;amp;&amp;nbsp;Threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aaronryu.github.io/2019/05/27/coroutine-and-thread/#Thread-amp-Coroutine%EF%BB%BF&quot;&gt;Coroutine, Thread 와의 차이와 그 특징&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bogotobogo.com/cplusplus/multithreaded.php&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Multi-Threaded Programming Terminology - 2020&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hpc.llnl.gov/documentation/tutorials/introduction-parallel-computing-tutorial&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introduction&amp;nbsp;to&amp;nbsp;Parallel&amp;nbsp;Computing&amp;nbsp;Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>컴퓨터</category>
      <category>논블럭킹</category>
      <category>동시성</category>
      <category>병렬</category>
      <category>비동기</category>
      <category>성능</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/90</guid>
      <comments>https://black7375.tistory.com/90#entry90comment</comments>
      <pubDate>Fri, 3 Jun 2022 11:44:12 +0900</pubDate>
    </item>
    <item>
      <title>Pure CSS + SVG 애니메이션 적용 실패기</title>
      <link>https://black7375.tistory.com/89</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;때는 2022년 2월 21일.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/black7375/Firefox-UI-Fix/issues/335&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비디오 플레이어 디자인&lt;/a&gt;을 고민할 때였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3dTEi/btrzjo6HN2G/m4H7Knw61hQP2YAUue0V3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3dTEi/btrzjo6HN2G/m4H7Knw61hQP2YAUue0V3K/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;450&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3dTEi/btrzjo6HN2G/m4H7Knw61hQP2YAUue0V3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3dTEi%2Fbtrzjo6HN2G%2Fm4H7Knw61hQP2YAUue0V3K%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;800&quot; height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUtoP9/btrzihN16JU/ex78VK28grWTKNqnvwDoU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUtoP9/btrzihN16JU/ex78VK28grWTKNqnvwDoU0/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;450&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUtoP9/btrzihN16JU/ex78VK28grWTKNqnvwDoU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUtoP9%2FbtrzihN16JU%2Fex78VK28grWTKNqnvwDoU0%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;800&quot; height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rqT8B/btrzi1Rry5X/DIZJkQ90ULkZkR01pKhREk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rqT8B/btrzi1Rry5X/DIZJkQ90ULkZkR01pKhREk/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;450&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rqT8B/btrzi1Rry5X/DIZJkQ90ULkZkR01pKhREk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrqT8B%2Fbtrzi1Rry5X%2FDIZJkQ90ULkZkR01pKhREk%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;800&quot; height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;기본, 1줄 프로토타입, 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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이디어 원천은 LG 음악앱.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폰은 구렸지만 음악앱 하나는 기똥차게 좋았던 LG..ㅠ&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CLjMg/btrzghVxoMy/8VrDbCiNI9QiSsYtIwpGK1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CLjMg/btrzghVxoMy/8VrDbCiNI9QiSsYtIwpGK1/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;300&quot; data-is-animation=&quot;true&quot; style=&quot;width: 56.4784%; margin-right: 10px;&quot; data-widthpercent=&quot;57.14&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CLjMg/btrzghVxoMy/8VrDbCiNI9QiSsYtIwpGK1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCLjMg%2FbtrzghVxoMy%2F8VrDbCiNI9QiSsYtIwpGK1%2Fimg.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;400&quot; height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x55TG/btrzjpq2DzH/k3MFIR3b9zVBdJ1momzSH1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x55TG/btrzjpq2DzH/k3MFIR3b9zVBdJ1momzSH1/img.gif&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot; data-is-animation=&quot;true&quot; style=&quot;width: 42.3588%;&quot; data-widthpercent=&quot;42.86&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x55TG/btrzjpq2DzH/k3MFIR3b9zVBdJ1momzSH1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx55TG%2Fbtrzjpq2DzH%2Fk3MFIR3b9zVBdJ1momzSH1%2Fimg.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;600&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;대략 이런 느낌 [&lt;a href=&quot;https://dribbble.com/shots/5384420-Play-Pause&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dribble: Play -&amp;gt; Pause&lt;/a&gt;, &lt;a href=&quot;https://middleton.work/micro-interactions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Micro&amp;nbsp;Interactions&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;먼저 움직이는 SVG를 만들어봤다.&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;이라 단순한 크기조정과 이동 정도를 구현하면 몰라도, 자체적으로 그래픽 리소스를 만들 자신은 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pure CSS + SVG 조합으로 가장 좋은 방법은 SVG 필름스트립(&lt;a href=&quot;https://msuja.ws/svg.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;개념&lt;/a&gt;, &lt;a href=&quot;https://medium.com/jspoint/creating-css-animations-using-sprite-sheet-47e2b7a3793c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구현&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://gist.github.com/sfoster/1027580d5115c8279d0e4b38fc8f0ed0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;툴링&lt;/a&gt;, &lt;a href=&quot;https://github.com/airbnb/lottie-web/issues/47&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lottie-web issue&lt;/a&gt;)이지만 애프터 이펙트를 쓸 줄 모르니ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필름스트립 기법 자체는 리소스가 부족하던 &lt;a href=&quot;http://norecess.cpcscene.net/the-elders-scrollers.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;고전 게임에서도 많이 사용&lt;/a&gt;되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;simplescreenrecorder-2022-02-26_01.47.46.gif&quot; data-origin-width=&quot;100&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caGAgT/btrzg5m5Sgv/1VlV0JUXY1njGngzsVbkkk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caGAgT/btrzg5m5Sgv/1VlV0JUXY1njGngzsVbkkk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caGAgT/btrzg5m5Sgv/1VlV0JUXY1njGngzsVbkkk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/caGAgT/btrzg5m5Sgv/1VlV0JUXY1njGngzsVbkkk/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;100&quot; height=&quot;78&quot; data-filename=&quot;simplescreenrecorder-2022-02-26_01.47.46.gif&quot; data-origin-width=&quot;100&quot; data-origin-height=&quot;78&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;우측 사각형이 작아지며 왼쪽으로 이동&lt;/li&gt;
&lt;li&gt;좌측 사각형에 닿게 되면 사다리꼴 모양이 만들어짐&lt;/li&gt;
&lt;li&gt;좌측 사각형은 작아지며 우측으로 조금 이동하다 사라짐&lt;br /&gt;이때 모양을 연속적으로 관측하면 크기가 작기 때문에 재생버튼과 상당히 유사해짐&lt;/li&gt;
&lt;li&gt;우측 사각형은 작은 재생 버튼으로 교체 후 원래 크기로 복원&lt;br /&gt;자연스러운 모핑과 눈에띄는 강조 표현..ㅎ&lt;/li&gt;
&lt;/ol&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;play-animate.svg&quot; data-origin-width=&quot;16&quot; data-origin-height=&quot;16&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D670T/btrzihAzKTQ/9ByNftkSk4DrBl7o71266K/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D670T/btrzihAzKTQ/9ByNftkSk4DrBl7o71266K/tfile.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D670T/btrzihAzKTQ/9ByNftkSk4DrBl7o71266K/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD670T%2FbtrzihAzKTQ%2F9ByNftkSk4DrBl7o71266K%2Ftfile.svg&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;16&quot; height=&quot;16&quot; data-filename=&quot;play-animate.svg&quot; data-origin-width=&quot;16&quot; data-origin-height=&quot;16&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;실제 SVG 파일 (눌러보세요)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;pre id=&quot;code_1649832657511&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot; height=&quot;16&quot; fill=&quot;context-fill&quot; fill-opacity=&quot;context-fill-opacity&quot;&amp;gt;
  &amp;lt;style type=&quot;text/css&quot;&amp;gt;
    #pauseBar {
      animation: hideBar 2s ease infinite;
      transform-origin: center;
      opacity: 0;
    }
    @keyframes hideBar {
      0% {
        opacity: 1;
        transform: translate(0px);
      }
      75% {
        opacity: 1;
        transform: translate(0px) scale(1);
      }
      80% {
        opacity: 1;
        transform: translate(1px) scale(0.9);
      }
      100% {
        transform: scale(0.8);
      }
    }

    #pauseMove {
      animation: move 1s ease-in-out alternate infinite;
      transform-origin: center;
    }
    @keyframes move {
      from {
        transform: translate(-1px) scale(0.95);
      }
      25% {
        transform: translate(-1px) scale(0.8);
      }
      35% {
        d: path(&quot;m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z&quot;);
        transform: translate(-1px) scale(0.6);
      }

      36% {
        d: path(&quot;m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z&quot;);
        transform: scale(0.75);
      }
      50% {
        transform: scale(0.8);
      }
      to {
        d: path(&quot;m11.5 14-1 0A1.5 1.5 0 0 1 9 12.5l0-9A1.5 1.5 0 0 1 10.5 2l1 0A1.5 1.5 0 0 1 13 3.5l0 9a1.5 1.5 0 0 1-1.5 1.5z&quot;);
        transform: scale(1);
      }
    }
  &amp;lt;/style&amp;gt;
  &amp;lt;path d=&quot;m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z&quot; id=&quot;pauseBar&quot; /&amp;gt;
  &amp;lt;path d=&quot;m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z&quot; id=&quot;pauseMove&quot;/&amp;gt;
&amp;lt;/svg&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일시정지 -&amp;gt;&amp;nbsp; 재생:&amp;nbsp; 순방향&lt;/li&gt;
&lt;li&gt;재생 -&amp;gt; 일시정지: 역방향&lt;/li&gt;
&lt;/ul&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;DOM 수정은 일체 불가하며, 단 한줄의 Javascript도 사용할 수 없는 상황이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유일하게 동적인건 [paused]라는 어트리뷰트를 사용할 수 있다는 점..&lt;/p&gt;
&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;(참고로 animation이 infinite가 아니면 최초 한번밖에 실행이 안되기에 계속 움직이지 않는&amp;nbsp; 의미가 없었다)&lt;/p&gt;
&lt;pre id=&quot;code_1649835662011&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.playButton {
  background-image: url(chrome://global/skin/media/pause-fill.svg);
}
.playButton:not([paused]){
  animation: playPlay 1s;
}
.playButton[paused] {
  background-image: url(chrome://global/skin/media/play-fill.svg);
  animation: playPaused 1s;
}

@keyframes playPlay {
  from {
    background-image: url(&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16' fill='context-fill' fill-opacity='context-fill-opacity'%3E%3Cstyle type='text/css'%3E %23pauseBar %7B animation: hideBar 1s ease reverse infinite; transform-origin: center; opacity: 0; %7D @keyframes hideBar %7B 0%25 %7B opacity: 1; transform: translate(0px); %7D 50%25 %7B opacity: 1; transform: translate(0px) scale(1); %7D 60%25 %7B opacity: 1; transform: translate(1px) scale(0.9); %7D 100%25 %7B transform: scale(0.8); %7D %7D %23pauseMove %7B animation: move 1s ease-in-out infinite; transform-origin: center; %7D @keyframes move %7B from %7B transform: translate(-1px) scale(0.95); %7D 25%25 %7B transform: translate(-1px) scale(0.8); %7D 35%25 %7B d: path('m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z'); transform: translate(-1px) scale(0.6); %7D 36%25 %7B d: path('m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z'); transform: scale(0.75); %7D 50%25 %7B transform: scale(0.8); %7D to %7B d: path('m11.5 14-1 0A1.5 1.5 0 0 1 9 12.5l0-9A1.5 1.5 0 0 1 10.5 2l1 0A1.5 1.5 0 0 1 13 3.5l0 9a1.5 1.5 0 0 1-1.5 1.5z'); transform: scale(1); %7D %7D %3C/style%3E%3Cpath d='m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z' id='pauseBar' /%3E%3Cpath d='m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z' id='pauseMove'/%3E%3C/svg%3E&quot;);
  }
  to {
    background-image: url(&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16' fill='context-fill' fill-opacity='context-fill-opacity'%3E%3Cstyle type='text/css'%3E %23pauseBar %7B animation: hideBar 1s ease reverse infinite; transform-origin: center; opacity: 0; %7D @keyframes hideBar %7B 0%25 %7B opacity: 1; transform: translate(0px); %7D 50%25 %7B opacity: 1; transform: translate(0px) scale(1); %7D 60%25 %7B opacity: 1; transform: translate(1px) scale(0.9); %7D 100%25 %7B transform: scale(0.8); %7D %7D %23pauseMove %7B animation: move 1s ease-in-out infinite; transform-origin: center; %7D @keyframes move %7B from %7B transform: translate(-1px) scale(0.95); %7D 25%25 %7B transform: translate(-1px) scale(0.8); %7D 35%25 %7B d: path('m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z'); transform: translate(-1px) scale(0.6); %7D 36%25 %7B d: path('m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z'); transform: scale(0.75); %7D 50%25 %7B transform: scale(0.8); %7D to %7B d: path('m11.5 14-1 0A1.5 1.5 0 0 1 9 12.5l0-9A1.5 1.5 0 0 1 10.5 2l1 0A1.5 1.5 0 0 1 13 3.5l0 9a1.5 1.5 0 0 1-1.5 1.5z'); transform: scale(1); %7D %7D %3C/style%3E%3Cpath d='m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z' id='pauseBar' /%3E%3Cpath d='m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z' id='pauseMove'/%3E%3C/svg%3E&quot;);
  }
}
@keyframes playPaused {
  from {
    background-image: url(&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16' fill='context-fill' fill-opacity='context-fill-opacity'%3E%3Cstyle type='text/css'%3E %23pauseBar %7B animation: hideBar 1s ease infinite; transform-origin: center; opacity: 0; %7D @keyframes hideBar %7B 0%25 %7B opacity: 1; transform: translate(0px); %7D 50%25 %7B opacity: 1; transform: translate(0px) scale(1); %7D 60%25 %7B opacity: 1; transform: translate(1px) scale(0.9); %7D 100%25 %7B transform: scale(0.8); %7D %7D %23pauseMove %7B animation: move 1s ease-in-out reverse infinite; transform-origin: center; %7D @keyframes move %7B from %7B transform: translate(-1px) scale(0.95); %7D 25%25 %7B transform: translate(-1px) scale(0.8); %7D 35%25 %7B d: path('m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z'); transform: translate(-1px) scale(0.6); %7D 36%25 %7B d: path('m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z'); transform: scale(0.75); %7D 50%25 %7B transform: scale(0.8); %7D to %7B d: path('m11.5 14-1 0A1.5 1.5 0 0 1 9 12.5l0-9A1.5 1.5 0 0 1 10.5 2l1 0A1.5 1.5 0 0 1 13 3.5l0 9a1.5 1.5 0 0 1-1.5 1.5z'); transform: scale(1); %7D %7D %3C/style%3E%3Cpath d='m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z' id='pauseBar' /%3E%3Cpath d='m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z' id='pauseMove'/%3E%3C/svg%3E&quot;);
  }
  to {
    background-image: url(&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16' fill='context-fill' fill-opacity='context-fill-opacity'%3E%3Cstyle type='text/css'%3E %23pauseBar %7B animation: hideBar 1s ease infinite; transform-origin: center; opacity: 0; %7D @keyframes hideBar %7B 0%25 %7B opacity: 1; transform: translate(0px); %7D 50%25 %7B opacity: 1; transform: translate(0px) scale(1); %7D 60%25 %7B opacity: 1; transform: translate(1px) scale(0.9); %7D 100%25 %7B transform: scale(0.8); %7D %7D %23pauseMove %7B animation: move 1s ease-in-out reverse infinite; transform-origin: center; %7D @keyframes move %7B from %7B transform: translate(-1px) scale(0.95); %7D 25%25 %7B transform: translate(-1px) scale(0.8); %7D 35%25 %7B d: path('m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z'); transform: translate(-1px) scale(0.6); %7D 36%25 %7B d: path('m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z'); transform: scale(0.75); %7D 50%25 %7B transform: scale(0.8); %7D to %7B d: path('m11.5 14-1 0A1.5 1.5 0 0 1 9 12.5l0-9A1.5 1.5 0 0 1 10.5 2l1 0A1.5 1.5 0 0 1 13 3.5l0 9a1.5 1.5 0 0 1-1.5 1.5z'); transform: scale(1); %7D %7D %3C/style%3E%3Cpath d='m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z' id='pauseBar' /%3E%3Cpath d='m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z' id='pauseMove'/%3E%3C/svg%3E&quot;);
  }
}&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-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;simplescreenrecorder-2022-02-27_02.42.18.gif&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHTLuu/btrzfzPR4Fk/C3Kg35Y0oXE5fLT7Z7W9YK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHTLuu/btrzfzPR4Fk/C3Kg35Y0oXE5fLT7Z7W9YK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHTLuu/btrzfzPR4Fk/C3Kg35Y0oXE5fLT7Z7W9YK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bHTLuu/btrzfzPR4Fk/C3Kg35Y0oXE5fLT7Z7W9YK/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;182&quot; data-filename=&quot;simplescreenrecorder-2022-02-27_02.42.18.gif&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;182&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;뒤틀리는 싱크 ㅠㅠㅠ&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;다음 시도는 약간 더 복잡해질수 밖에.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;재생-&amp;gt;일시정지까지만&lt;/li&gt;
&lt;li&gt;일시정지-&amp;gt;재생까지만&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;으로 딱 정해진 일만 하게하자라는 아이디어였다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그런데 아까 구현을 보았다시피 진행속도는 ease를 따른다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;764&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgV8wh/btrziRn4BlD/Yjc9RnriIOQlDuKs3Jnj50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgV8wh/btrziRn4BlD/Yjc9RnriIOQlDuKs3Jnj50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgV8wh/btrziRn4BlD/Yjc9RnriIOQlDuKs3Jnj50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgV8wh%2FbtrziRn4BlD%2FYjc9RnriIOQlDuKs3Jnj50%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;960&quot; height=&quot;764&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;764&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cubic-bezier.com/#.25,.1,.25,1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;cubic-bezier(.25, .1, .25, 1)&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;전체가 2초라지만 1초가 절반이 아니며, 가속이 그대로 이어가도록 나누기가 어렵다는 의미다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;베지어 곡선을 나눠서 진행하기 위해 &lt;a href=&quot;https://stackoverflow.com/questions/23475372/extrapolate-split-cubic-bezier-to-1-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스택오버플로우 답변&lt;/a&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;a href=&quot;https://github.com/black7375/SplitCubicalBezier&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SplitCubicalBezier&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1651547888663&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - black7375/SplitCubicalBezier&quot; data-og-description=&quot;Contribute to black7375/SplitCubicalBezier development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/black7375/SplitCubicalBezier&quot; data-og-url=&quot;https://github.com/black7375/SplitCubicalBezier&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bGNI4Z/hyOgpvG21N/LRfZHC9QMeCIJwmz1VLPIk/img.png?width=1200&amp;amp;height=600&amp;amp;face=976_150_1032_211&quot;&gt;&lt;a href=&quot;https://github.com/black7375/SplitCubicalBezier&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/black7375/SplitCubicalBezier&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bGNI4Z/hyOgpvG21N/LRfZHC9QMeCIJwmz1VLPIk/img.png?width=1200&amp;amp;height=600&amp;amp;face=976_150_1032_211');&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;GitHub - black7375/SplitCubicalBezier&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to black7375/SplitCubicalBezier development by creating an account on GitHub.&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 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;다음처럼 나눠진 값이 출력된다.&lt;/p&gt;
&lt;pre id=&quot;code_1649838383721&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { presets, createCubicBezier, getSplitCubicBezier } from &quot;splitCubicalBezier&quot;;

const linear1 = presets.linear;                    // Same as linear2
const linear2 = createCubicBezier(x1, y1, x2, y2); // { xs: [ 0, 0, 1, 1 ], ys: [ 0, 0, 1, 1 ] }
const results = getSplitCubicBezier(linear2, 0.5); // { left: [ 0, 0, 0.5, 0.5 ], right: [ 0.5, 0.5, 1, 1 ] }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;우리가 나눌 구간은 @keyframe hidebar 75%로 먼저 키프레임 각 구간의 시간을 정해주고,&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;627&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TJmxF/btrzi2QHUzR/meKWTmdSGr26adWk7td50k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TJmxF/btrzi2QHUzR/meKWTmdSGr26adWk7td50k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TJmxF/btrzi2QHUzR/meKWTmdSGr26adWk7td50k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTJmxF%2Fbtrzi2QHUzR%2FmeKWTmdSGr26adWk7td50k%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;627&quot; height=&quot;332&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같은 식? (예제라 실제값이랑 다를수도? 당시에 기록용으로 남겨놓기 위한 짤)&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;pause 애니메이션,&lt;/p&gt;
&lt;pre id=&quot;code_1649841840690&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot; height=&quot;16&quot; fill=&quot;context-fill&quot; fill-opacity=&quot;context-fill-opacity&quot;&amp;gt;
  &amp;lt;style type=&quot;text/css&quot;&amp;gt;
    #pauseBar {
      animation: hideBar 0.65s cubic-bezier(0, 0, 0.51, 0.74) alternate;
      transform-origin: center;
    }
    @keyframes hideBar {
      from {
        transform: translate(0.97px) scale(0.85);
      }
      10% {
        transform: translate(0px) scale(1);
      }
      to {
        transform: translate(0px);
      }
    }

    #pauseMove {
      animation: move 0.65s cubic-bezier(0.31, 0.41, 0.57, 1) alternate;
      transform-origin: center;
    }
    @keyframes move {
      from {
        d: path(&quot;m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z&quot;);
        transform: scale(0.75);
      }
      23% {
        transform: scale(0.8);
      }
      to {
        d: path(&quot;m11.5 14-1 0A1.5 1.5 0 0 1 9 12.5l0-9A1.5 1.5 0 0 1 10.5 2l1 0A1.5 1.5 0 0 1 13 3.5l0 9a1.5 1.5 0 0 1-1.5 1.5z&quot;);
        transform: scale(1);
      }
    }
  &amp;lt;/style&amp;gt;
  &amp;lt;path d=&quot;m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z&quot; id=&quot;pauseBar&quot; /&amp;gt;
  &amp;lt;path d=&quot;m11.5 14-1 0A1.5 1.5 0 0 1 9 12.5l0-9A1.5 1.5 0 0 1 10.5 2l1 0A1.5 1.5 0 0 1 13 3.5l0 9a1.5 1.5 0 0 1-1.5 1.5z&quot; id=&quot;pauseMove&quot; /&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;play 애니메이션&lt;/p&gt;
&lt;pre id=&quot;code_1649841872818&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot; height=&quot;16&quot; fill=&quot;context-fill&quot; fill-opacity=&quot;context-fill-opacity&quot;&amp;gt;
  &amp;lt;style type=&quot;text/css&quot;&amp;gt;
    #pauseBar {
      animation: hideBar 0.35s cubic-bezier(0.34, 0.62, 0.68, 1) alternate;
      transform-origin: center;
      opacity: 0;
    }
    @keyframes hideBar {
      33% {
        opacity: 1;
        transform: translate(0.97px) scale(0.85);
      }
      47% {
        opacity: 1;
        transform: translate(0.97px) scale(0.85);
      }
      to {
        transform: scale(0.8);
      }
    }

    #playMove {
      animation: move 0.35s cubic-bezier(0.43, 0, 0.67, 0.66) alternate;
      transform-origin: center;
    }
    @keyframes move {
      from {
        d: path(&quot;m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z&quot;);
        transform: translate(-1px) scale(0.6);
      }
      29% {
        transform: translate(-1px) scale(0.8);
      }
      to {
        transform: translate(-1px) scale(0.95);
      }
    }
  &amp;lt;/style&amp;gt;
  &amp;lt;path d=&quot;m4.5 14-1 0A1.5 1.5 0 0 1 2 12.5l0-9A1.5 1.5 0 0 1 3.5 2l1 0A1.5 1.5 0 0 1 6 3.5l0 9A1.5 1.5 0 0 1 4.5 14z&quot; id=&quot;pauseBar&quot; /&amp;gt;
  &amp;lt;path d=&quot;m2.992 13.498 0-10.996a1.5 1.5 0 0 1 2.245-1.303l9.621 5.498a1.5 1.5 0 0 1 0 2.605L5.237 14.8a1.5 1.5 0 0 1-2.245-1.302z&quot; id=&quot;playMove&quot;/&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;근데 역시 적용해보니 마음처럼 안되드란.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 뻘짓을 하다가 구현 실패는 하고 시간도 날라갔다..ㅠㅠㅠ&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;좋은 아이디어 있으면 댓글 주세요.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;한줄요약:&amp;nbsp; 예능은 예능으로.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;지금보니 키프레임 구간을 나누는 코드가 깃허브에 반영 안되어 있네요.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;집에가서 있나 찾아보겠습니다.&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <category>CSS</category>
      <category>svg</category>
      <category>애니메이션</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/89</guid>
      <comments>https://black7375.tistory.com/89#entry89comment</comments>
      <pubDate>Wed, 13 Apr 2022 14:58:24 +0900</pubDate>
    </item>
    <item>
      <title>객체지향 시스템과 패러다임 그리고 철학</title>
      <link>https://black7375.tistory.com/86</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@limsungmook/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%99%9C-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85%EC%9D%84-%EC%84%A0%ED%83%9D%ED%96%88%EC%9D%84%EA%B9%8C-997f985adb42&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자바스크립트는&amp;nbsp;왜&amp;nbsp;프로토타입을&amp;nbsp;선택했을까&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;원글과는 접근법이 좀 다르며, 기획이 아닌 급하게 쓴 글이라 의식의 흐름 사이에서 표류합니다 ㅠㅠㅠ&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스와 프로토타입의 가장 커다란 차이는 객체 생성 방식 [클래스 -&amp;gt; 인스턴스 vs 객체 -&amp;gt; 복사된 객체].&lt;/li&gt;
&lt;li&gt;가장 큰 공통점은 객체지향이며, 프로그램을 객체라는 단위로 나누고 상호작용하게 하는 것.&lt;/li&gt;
&lt;li&gt;객체지향의 핵심인 캡슐화를 잘하기 위한 가장 간단한 방법은 추상화를 잘 하는 것.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추상화는 데이터 위주의 성질(고전적 OOP), 형태(타입), 상태(데이터 주도 설계)와 관계 중심인 시간(절차지향), 행동(함수형), 정의(논리형), 상황(도메인 주도 설계, AOP) 등으로 나누어 생각할 수 있음.&lt;/li&gt;
&lt;li&gt;잘 분류하고 설계하기 위해서 사고의 형식을 인식하게 만드는 다양한 범주의 이해가 있다면 좋음 [예) 칸트의 4강 12목].&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;철학과 패러다임
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;절차형: 시간은 대부분의 추상화에 영향을 미치며, Goto처럼 컨텍스트가 섞이게 만드는 문법은 좋지 않음.&lt;/li&gt;
&lt;li&gt;함수형: 행동의 형태로 나타내려 하기 때문에 타입(형태)와 깊은 연관관계.&lt;/li&gt;
&lt;li&gt;논리형: 사실과 규칙으로 논리를 구성하고, 질의를 함으로서 술어논리의 결과를 얻을 수 있음.&lt;/li&gt;
&lt;li&gt;전통적 OOP: 직관적. 하지만 완벽한 속성을 알아내기는 불가능함.&lt;/li&gt;
&lt;li&gt;데이터 주도 설계: 로직의 상태를 다루려는 함수형과 달리 컴퓨터 자체에서의 상태를 줄이려 시도. 캐시 히트를 높혀서 성능향상을 가져옴.&lt;/li&gt;
&lt;li&gt;도메인 주도 설계: 전통적 OOP와 달리 도메인과 맥락에 따라 다르게 설계를 함(그림이론-용도의미론과 비슷), 서브도메인의 의존성 주입을 하는 AOP를 사용하면 구현이 편해짐.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MVP&amp;nbsp;
&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;MVP: 최소한의 완성도가 보장된 사용이 가능하고, 최종단계로 생각하는 제품과 유사하게 설계해야함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;클래스-인스턴스는 플라톤의 이데아론을, 프로토타입-복제된 객체는 아리스토텔레스 실체론과 유사.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;0. 객체지향 들어서기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향의 주요구현 형태라 하면 Java, C++등에서 주로 사용하는 클래스와 Javascript, Io등에서 사용하는 프로토타입으로 나눌수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커먼 리스프의 CLOS, 스칼라와 러스트의 Trait, 루비의 Mixin등도 있다고 하지만 가장 대표적이고 극적인 객체지향 형태는 저 둘이죠.&lt;/p&gt;
&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;새로운 객체로 분기하기 위해, 클래스는 new, 프로토타입은 clone으로 이루어진다는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1639135977338&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Object object =  new Object();&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1639136023459&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;anObject := Object clone&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Java와 Io [&lt;a href=&quot;https://github.com/black7375/ReadabilityDocs/tree/master/%EC%9E%91%EA%B3%A0%20%EC%95%84%EB%A6%84%EB%8B%A4%EC%9A%B4%20%EC%96%B8%EC%96%B4%20Io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;작고 아름다운 언어 Io&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;177&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M2Bvh/btrnBbTgXWn/KocshrNC1LskAuxbjPk8AK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M2Bvh/btrnBbTgXWn/KocshrNC1LskAuxbjPk8AK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M2Bvh/btrnBbTgXWn/KocshrNC1LskAuxbjPk8AK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM2Bvh%2FbtrnBbTgXWn%2FKocshrNC1LskAuxbjPk8AK%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;270&quot; height=&quot;177&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;177&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토타입 기반은 클래스와 인스턴스 구분이 없으므로, 당연히 static 메서드와 instance 메서드를 따로 나눌수 없다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램을 객체라는 단위로 &lt;b&gt;나누고&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상호작용&lt;/b&gt;하게 하는 것이다.&lt;/li&gt;
&lt;/ul&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;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;li&gt;다형성: 상황에 따라 여러가지 형태를 가질 수 있음&lt;/li&gt;
&lt;/ul&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많이 알려진 &lt;a href=&quot;https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SOLID 원칙&lt;/a&gt;은 상호작용이 어떻게 일어나야 하는가에 대한 패턴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 추상화와 패러다임&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 추론으로 객체지향에서 가장 핵심은 캡슐화임을 알 수 있으며, 묶기위해 어떻게 나눌(분류, classing)것인가에 대해 논의해볼 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분류하기 위해 간단히 생각해낼 수 있는 일반적인 방법중 하나는 추상화(Abstraction)이다.&lt;/p&gt;
&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;a href=&quot;https://black7375.tistory.com/6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://black7375.tistory.com/6&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639139422011&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;프로그래밍과 추상화에 대하여.&quot; data-og-description=&quot;HtDP를 읽는 중인데 오늘도 뻘 생각이 나서 그냥 필이 꽃힌 김에 적어봤다. (내 성격의 최대 장점이자 단점. 잡생각이 너무 많음. 글 중간에도 의식의 흐름대로 빠지는 것이 보인다.) 내 맘대로 하&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/6&quot; data-og-url=&quot;https://black7375.tistory.com/6&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bG6uvg/hyMEQCNTHm/hcoj32bQFI8pgwgJTKxkW0/img.png?width=342&amp;amp;height=292&amp;amp;face=0_0_342_292,https://scrap.kakaocdn.net/dn/HGxjU/hyME5Ns2OY/cKfNSFlOkuTWRPLRKjvoj0/img.png?width=342&amp;amp;height=292&amp;amp;face=0_0_342_292,https://scrap.kakaocdn.net/dn/bGRW7u/hyMEW35qHe/K8wQ9FVkAhkbmcniQEEwtk/img.png?width=342&amp;amp;height=292&amp;amp;face=0_0_342_292&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/6&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bG6uvg/hyMEQCNTHm/hcoj32bQFI8pgwgJTKxkW0/img.png?width=342&amp;amp;height=292&amp;amp;face=0_0_342_292,https://scrap.kakaocdn.net/dn/HGxjU/hyME5Ns2OY/cKfNSFlOkuTWRPLRKjvoj0/img.png?width=342&amp;amp;height=292&amp;amp;face=0_0_342_292,https://scrap.kakaocdn.net/dn/bGRW7u/hyMEW35qHe/K8wQ9FVkAhkbmcniQEEwtk/img.png?width=342&amp;amp;height=292&amp;amp;face=0_0_342_292');&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;프로그래밍과 추상화에 대하여.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;HtDP를 읽는 중인데 오늘도 뻘 생각이 나서 그냥 필이 꽃힌 김에 적어봤다. (내 성격의 최대 장점이자 단점. 잡생각이 너무 많음. 글 중간에도 의식의 흐름대로 빠지는 것이 보인다.) 내 맘대로 하&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1.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;모든 패러다임은 아니지만, 유명하거나 최근 떠오르는 패러다임은 기술하려 노력했습니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;패러다임) 우리가 보통 생각하는 OOP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;상태: 특정한 기준을 만족시키는 여러 구성 중 하나
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예) On/Off, 교착, 평형&lt;/li&gt;
&lt;li&gt;패러다임) 데이터 주도 설계(Data Oriented Design)&lt;/li&gt;
&lt;/ul&gt;
&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;b&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;시간: 행위가 일어나는 시간
&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;행동: 행동의 형태로 기술
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예) 사상(map), 필터, 리듀스&lt;/li&gt;
&lt;li&gt;패러다임) 함수형&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정의: 행동의 성질을 규정(사실 + 규칙, 제어)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예) A와 B는 C관계가 있다,&amp;nbsp; A가 존재하는가?&lt;/li&gt;
&lt;li&gt;패러다임) 논리형&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;상황: 정보와 활동 영역을 규정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예) (대기업의) 배포, (스타트업의) 배포, (의료용 AI) 개발, (블로그 테마) 개발&lt;/li&gt;
&lt;li&gt;패러다임) 도메인 주도 개발&lt;/li&gt;
&lt;/ul&gt;
&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;a href=&quot;https://ko.wikipedia.org/wiki/%EC%A1%B4%EC%9E%AC%EC%9D%98_%EB%B2%94%EC%A3%BC&quot;&gt;&lt;b&gt;&quot;범주&lt;/b&gt;&quot;&lt;/a&gt;라해도 과언이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;철학에서 유명한 범주로는 칸트의 4강 12목과 헤겔의 범주론이 존재하며 칸트의 범주론은 아랫글의 초반에 나온 파트를 참고해볼 수 있다.&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://black7375.tistory.com/36&quot;&gt;https://black7375.tistory.com/36&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639256195951&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;내 맘대로 프로그램 설계 4. - 고정 크기 데이터.&quot; data-og-description=&quot;이번 섹션에서는 섹션2,3 정리와 고정 크기 데이터에 대하여 배우도록 하겠습니다. 다시 연재 시작했어요. 내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/36&quot; data-og-url=&quot;https://black7375.tistory.com/36&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ltRMh/hyMFM7qyOP/Sl83pDV2xGBsnAKF2OeSa1/img.png?width=277&amp;amp;height=237&amp;amp;face=0_0_277_237,https://scrap.kakaocdn.net/dn/cmW0w9/hyMFMM6Jqr/Euo5O3Zu6SAvJUdNDJPCyk/img.png?width=277&amp;amp;height=237&amp;amp;face=0_0_277_237,https://scrap.kakaocdn.net/dn/diAygf/hyMESuFxxv/PNNS0hnlAmXvDoBnRxQh8K/img.png?width=722&amp;amp;height=406&amp;amp;face=0_0_722_406&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/36&quot; data-source-url=&quot;https://black7375.tistory.com/36&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ltRMh/hyMFM7qyOP/Sl83pDV2xGBsnAKF2OeSa1/img.png?width=277&amp;amp;height=237&amp;amp;face=0_0_277_237,https://scrap.kakaocdn.net/dn/cmW0w9/hyMFMM6Jqr/Euo5O3Zu6SAvJUdNDJPCyk/img.png?width=277&amp;amp;height=237&amp;amp;face=0_0_277_237,https://scrap.kakaocdn.net/dn/diAygf/hyMESuFxxv/PNNS0hnlAmXvDoBnRxQh8K/img.png?width=722&amp;amp;height=406&amp;amp;face=0_0_722_406');&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;내 맘대로 프로그램 설계 4. - 고정 크기 데이터.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이번 섹션에서는 섹션2,3 정리와 고정 크기 데이터에 대하여 배우도록 하겠습니다. 다시 연재 시작했어요. 내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.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;헤겔은 내제된 모순성에서 준동되는 필연성을 이용해 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B2%8C%EC%98%A4%EB%A5%B4%ED%81%AC_%EB%B9%8C%ED%97%AC%EB%A6%84_%ED%94%84%EB%A6%AC%EB%93%9C%EB%A6%AC%ED%9E%88_%ED%97%A4%EA%B2%94#%EC%A0%88%EB%8C%80_%EC%A0%95%EC%8B%A0&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;a href=&quot;https://ko.wikipedia.org/wiki/%EB%8C%80%EB%85%BC%EB%A6%AC%ED%95%99&quot;&gt;https://ko.wikipedia.org/wiki/%EB%8C%80%EB%85%BC%EB%A6%AC%ED%95%99&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639256154987&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;대논리학 - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;대논리학(『철학강요』-『Enzyklop&amp;auml;die der Philosophischen Wissenschaften Im Grundriss』-에 나오는 축약 형태의 논리학을 소논리학이라고 부르며, 이와 구별하여 단독 저작으로서의 논리학을 대논리학이라&quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%EB%8C%80%EB%85%BC%EB%A6%AC%ED%95%99&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%EB%8C%80%EB%85%BC%EB%A6%AC%ED%95%99&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iG73h/hyMFNSMgCR/miM8EPzZKoEDggIxyboXGk/img.jpg?width=736&amp;amp;height=960&amp;amp;face=0_0_736_960,https://scrap.kakaocdn.net/dn/bozTY2/hyMEYBBs9U/Npl9R3CmA6jMrQ5mOCZwd1/img.jpg?width=736&amp;amp;height=960&amp;amp;face=0_0_736_960,https://scrap.kakaocdn.net/dn/pP31q/hyMFDbyocN/7HHfCvGuWUMX9t4FYUjGAK/img.jpg?width=640&amp;amp;height=835&amp;amp;face=0_0_640_835&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%8C%80%EB%85%BC%EB%A6%AC%ED%95%99&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%EB%8C%80%EB%85%BC%EB%A6%AC%ED%95%99&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iG73h/hyMFNSMgCR/miM8EPzZKoEDggIxyboXGk/img.jpg?width=736&amp;amp;height=960&amp;amp;face=0_0_736_960,https://scrap.kakaocdn.net/dn/bozTY2/hyMEYBBs9U/Npl9R3CmA6jMrQ5mOCZwd1/img.jpg?width=736&amp;amp;height=960&amp;amp;face=0_0_736_960,https://scrap.kakaocdn.net/dn/pP31q/hyMFDbyocN/7HHfCvGuWUMX9t4FYUjGAK/img.jpg?width=640&amp;amp;height=835&amp;amp;face=0_0_640_835');&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;대논리학 - 위키백과, 우리 모두의 백과사전&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;대논리학(『철학강요』-『Enzyklop&amp;auml;die der Philosophischen Wissenschaften Im Grundriss』-에 나오는 축약 형태의 논리학을 소논리학이라고 부르며, 이와 구별하여 단독 저작으로서의 논리학을 대논리학이라&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.wikipedia.org&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;&lt;a href=&quot;https://plato.stanford.edu/entries/hegel-dialectics/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://plato.stanford.edu/entries/hegel-dialectics/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639257322139&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;Hegel&amp;rsquo;s Dialectics (Stanford Encyclopedia of Philosophy)&quot; data-og-description=&quot;&amp;ldquo;Dialectics&amp;rdquo; is a term used to describe a method of philosophical argument that involves some sort of contradictory process between opposing sides. In what is perhaps the most classic version of &amp;ldquo;dialectics&amp;rdquo;, the ancient Greek philosopher, Plato (s&quot; data-og-host=&quot;plato.stanford.edu&quot; data-og-source-url=&quot;https://plato.stanford.edu/entries/hegel-dialectics/&quot; data-og-url=&quot;https://plato.stanford.edu/entries/hegel-dialectics/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/daEX8P/hyME58CyjX/30pBt9KUOarel8jy5jp8Z1/img.png?width=572&amp;amp;height=804&amp;amp;face=0_0_572_804,https://scrap.kakaocdn.net/dn/fVN99/hyMFE9pfqT/RyFAnojaA2AzzKlrNZLS00/img.png?width=572&amp;amp;height=784&amp;amp;face=0_0_572_784,https://scrap.kakaocdn.net/dn/cU5qub/hyMEVZcuUN/7bhUkKWYh47DeTAiTWpOdk/img.png?width=600&amp;amp;height=644&amp;amp;face=0_0_600_644&quot;&gt;&lt;a href=&quot;https://plato.stanford.edu/entries/hegel-dialectics/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://plato.stanford.edu/entries/hegel-dialectics/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/daEX8P/hyME58CyjX/30pBt9KUOarel8jy5jp8Z1/img.png?width=572&amp;amp;height=804&amp;amp;face=0_0_572_804,https://scrap.kakaocdn.net/dn/fVN99/hyMFE9pfqT/RyFAnojaA2AzzKlrNZLS00/img.png?width=572&amp;amp;height=784&amp;amp;face=0_0_572_784,https://scrap.kakaocdn.net/dn/cU5qub/hyMEVZcuUN/7bhUkKWYh47DeTAiTWpOdk/img.png?width=600&amp;amp;height=644&amp;amp;face=0_0_600_644');&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;Hegel&amp;rsquo;s Dialectics (Stanford Encyclopedia of Philosophy)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;Dialectics&amp;rdquo; is a term used to describe a method of philosophical argument that involves some sort of contradictory process between opposing sides. In what is perhaps the most classic version of &amp;ldquo;dialectics&amp;rdquo;, the ancient Greek philosopher, Plato (s&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;plato.stanford.edu&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;말이 나온김에 헤갤의 방식으로 수량(Quantity)은 어떻게 표시되나 한번 알아보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7UcYK/btrnBMfe70m/wJK4mqU8e5z6k26f5C0ji1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7UcYK/btrnBMfe70m/wJK4mqU8e5z6k26f5C0ji1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7UcYK/btrnBMfe70m/wJK4mqU8e5z6k26f5C0ji1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7UcYK%2FbtrnBMfe70m%2FwJK4mqU8e5z6k26f5C0ji1%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;340&quot; height=&quot;418&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정량(Quantum): &quot;여럿&quot;이 들어있는 밖 경계의 &quot;하나&quot;&lt;/li&gt;
&lt;li&gt;수(Number): 모든 측면에서의 &quot;하나&quot;&lt;/li&gt;
&lt;li&gt;크기(Extensive, 외연)와 세기(Intensive, 내연)양: 바깥 경계에 있는 &quot;여럿&quot;과 내부의 각각 &quot;하나&quot;&lt;/li&gt;
&lt;li&gt;도(Degree): 모든 측면에서의 &quot;여럿&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꽤나 합리적인 설명이지 않은가? &lt;s&gt;해설의 해설이 필요한 시점이다.&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://bicstudy.org/glossary/%EC%A0%95%EB%9F%89-%ED%95%9C%EA%B3%84/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;정량한계&lt;/a&gt;란 단어를 바탕으로 이해하면 쉽다.&lt;br /&gt;정량한계는 바람직한 확실성을 가지고 정량할 수 있는 최저농도(수치상 유효한 의미)를 뜻한다.&lt;br /&gt;예를 들어 자는 1mm란 단위를 기준으로 &quot;하나&quot;라고 테두리에서 생각하지만, 1mm안에는 &quot;여럿&quot; &amp;micro;m, nm등이 모여있다.&lt;/li&gt;
&lt;li&gt;수: 내부의 &quot;하나들&quot;, 겉의 &quot;하나&quot;들이든 모두 &quot;하나&quot;라는 것이다.&lt;br /&gt;예를 들어&amp;nbsp; 1mm는 1&amp;micro;m 1000개로 구성되지만 둘 다 1이라 부르며, 책 하나나 비행기 하나나 모두 &quot;하나&quot;라 부른다.&lt;/li&gt;
&lt;li&gt;크기와 세기: &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%84%B8%EA%B8%B0_%EC%84%B1%EC%A7%88%EA%B3%BC_%ED%81%AC%EA%B8%B0_%EC%84%B1%EC%A7%88&quot;&gt;세기 성질과 크기 성질&lt;/a&gt;을 참고하면 쉽다.&lt;br /&gt;우선 세기는 변화가 가능하고 계의 크기와 무관한 성질이다. 계의 내부에서 각각 &quot;하나&quot;씩 존재한다.&lt;br /&gt;크기는 계의 크기에 비례하는 양이다. 따라서 각 세기들이 모여 만들어져 &quot;여럿&quot; 크기들을 규정한다.&lt;/li&gt;
&lt;li&gt;도: &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B0%81_(%EC%88%98%ED%95%99)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;각&lt;/a&gt;은 두 반직선이 이루는 도형을 말하는데, 도는 각의 단위이다.&lt;br /&gt;안밖의 &quot;여럿&quot; 각도에서 본다고 생각해보자. 내각이든 외각이든 모두 &quot;여럿&quot; 도들로 이루어져 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9D1Lg/btrnBanlI2y/HrQxNJGgmcHmkeCtybjlN1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9D1Lg/btrnBanlI2y/HrQxNJGgmcHmkeCtybjlN1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9D1Lg/btrnBanlI2y/HrQxNJGgmcHmkeCtybjlN1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9D1Lg%2FbtrnBanlI2y%2FHrQxNJGgmcHmkeCtybjlN1%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;440&quot; height=&quot;286&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://m.blog.naver.com/kingforpoii/221242061976&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2단원&amp;nbsp;각도('각'과&amp;nbsp;'각도'의&amp;nbsp;의미)&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;이처럼 시스템의 안과 밖에서 &quot;하나&quot;와 &quot;여럿&quot;이 동시에 존재하는 것은 &lt;b&gt;모순적&lt;/b&gt;이지만, 모순 덕분에 모든 시스템을 절대적으로 규정할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사각형 안과 밖/하나와 여럿의 모든 경우 $2^n = 2^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;대표적인 것이 비례(Ratio)이다. 비례는 $1:2 = 3:6$처럼 수를 사용하지만 &quot;하나&quot;와 &quot;여럿&quot;만으로 정의하기 힘들다.&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;비례는 양에 대한 보편 개념으로 자신의 내용 속에서 &quot;여럿&quot; &lt;b&gt;집합&lt;/b&gt;적인 성질을 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1:2와 3:6은 사상하므로 일대일 집합이라 할 수 있죠? 또한 2:4, 4: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;&lt;a href=&quot;https://black7375.tistory.com/43&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://black7375.tistory.com/43&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639262114845&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;무한, 집합, 그리고 수에 대해서.&quot; data-og-description=&quot;무한($\infty$)의 성질들을 집합과 수를 통해 간단하게라도 알아보도록 하자. M.C. Escher - M&amp;ouml;bius Strip II(1963)[from Wallup] 1. 집합(Set)과 무한(Infinity). 무한의 성질을 알려면 집합에 대하여 아는 것이..&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/43&quot; data-og-url=&quot;https://black7375.tistory.com/43&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/chsS51/hyME2YnzvG/lco7qfuBQVX3MCCeVVLn41/img.jpg?width=800&amp;amp;height=384&amp;amp;face=0_0_800_384,https://scrap.kakaocdn.net/dn/Sy5PI/hyMEXisvU6/4sKTHgWHQUAAsNNoY5Et80/img.jpg?width=800&amp;amp;height=384&amp;amp;face=0_0_800_384,https://scrap.kakaocdn.net/dn/AVmoK/hyMER3B2s8/5aNvZpZwGu6SAvycfAmRkk/img.png?width=429&amp;amp;height=325&amp;amp;face=0_0_429_325&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/43&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/43&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/chsS51/hyME2YnzvG/lco7qfuBQVX3MCCeVVLn41/img.jpg?width=800&amp;amp;height=384&amp;amp;face=0_0_800_384,https://scrap.kakaocdn.net/dn/Sy5PI/hyMEXisvU6/4sKTHgWHQUAAsNNoY5Et80/img.jpg?width=800&amp;amp;height=384&amp;amp;face=0_0_800_384,https://scrap.kakaocdn.net/dn/AVmoK/hyMER3B2s8/5aNvZpZwGu6SAvycfAmRkk/img.png?width=429&amp;amp;height=325&amp;amp;face=0_0_429_325');&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;무한, 집합, 그리고 수에 대해서.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;무한($\infty$)의 성질들을 집합과 수를 통해 간단하게라도 알아보도록 하자. M.C. Escher - M&amp;ouml;bius Strip II(1963)[from Wallup] 1. 집합(Set)과 무한(Infinity). 무한의 성질을 알려면 집합에 대하여 아는 것이..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.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;지금까지 나온 헤겔의 방식을 정리해보자면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btodcu/btrnClgYxi1/xwI65qDZYunak3H9umzkr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btodcu/btrnClgYxi1/xwI65qDZYunak3H9umzkr0/img.png&quot; width=&quot;222&quot; height=&quot;268&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;536&quot; style=&quot;width: 25.604%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btodcu/btrnClgYxi1/xwI65qDZYunak3H9umzkr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtodcu%2FbtrnClgYxi1%2FxwI65qDZYunak3H9umzkr0%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;444&quot; height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6P8nI/btrnDoxvnhs/8QoOaxUSpRXjvcjHwHPuE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6P8nI/btrnDoxvnhs/8QoOaxUSpRXjvcjHwHPuE0/img.png&quot; width=&quot;266&quot; height=&quot;190&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;380&quot; style=&quot;width: 43.273%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6P8nI/btrnDoxvnhs/8QoOaxUSpRXjvcjHwHPuE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6P8nI%2FbtrnDoxvnhs%2F8QoOaxUSpRXjvcjHwHPuE0%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;532&quot; height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xav7n/btrnBXgk4fz/8dlWmDyPza5jyzxI5fv4K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xav7n/btrnBXgk4fz/8dlWmDyPza5jyzxI5fv4K1/img.png&quot; width=&quot;300&quot; height=&quot;322&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;644&quot; style=&quot;width: 28.7975%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xav7n/btrnBXgk4fz/8dlWmDyPza5jyzxI5fv4K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXav7n%2FbtrnBXgk4fz%2F8dlWmDyPza5jyzxI5fv4K1%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;600&quot; height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;br /&gt;왔다갔다한 덕분에 포괄하게 되는 것이다. (&quot;하나&quot;와 &quot;여럿&quot;을 이용해 수량을 정의한 것을 생각하자)&lt;/li&gt;
&lt;li&gt;그렇지만 역시 또 모순이 존재하고 앞의 과정들을 반복하며 포괄적이고 보편적인 형태로 나아간다.&lt;/li&gt;
&lt;/ul&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;한편 양과 항상 비교당하는 질(Quality)은 헤겔철학에서 대자 존재(자신과 대립하고 있는 것)의 보편적인 개념이다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1.2 설명&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;내가 생각한 순서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절차지향 - 함수형과 타입 - 논리형 - 전통적 객체지향 - 데이터 주도 - 도메인 주도와 AOP 순이다.&lt;/p&gt;
&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;[절차지향] - [ 함수형과 타입, 논리형] - [전통적 객체지향 - 데이터 주도 - 도메인 주도와 AOP]&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_1639149750748&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; 시간         선언형                    객체지향 및 대체
[절차지향] - [함수형과 타입, 논리형] - [전통적 객체지향 - 데이터 주도 - 도메인 주도와 AOP]&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;size18&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;a href=&quot;https://ko.wikipedia.org/wiki/%ED%99%95%EC%A0%95%EC%84%B1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;확실성&lt;/a&gt;(섞이지 않았는가), 정합성[충분한&amp;nbsp;근거를&amp;nbsp;가지고&amp;nbsp;있는가, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%8F%99%EC%9D%BC%EC%84%B1#%EB%8F%99%EC%9D%BC%EC%84%B1%EA%B3%BC_%EB%85%BC%EB%A6%AC%ED%95%99(%EB%8F%99%EC%9D%BC%EB%A5%A0)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;동일률&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%B9%84%EB%AA%A8%EC%88%9C%EC%9C%A8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비모순율&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%B0%B0%EC%A4%91%EB%A5%A0&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/34&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://black7375.tistory.com/34&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639238055453&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;내 맘대로 프로그램 설계 3. - 함수와 변수.&quot; data-og-description=&quot;원래 합쳐져서 Section2 였던 '기초'에서 '간단한 데이터 처리'와 '함수'로 나뉘어 구성하게 되었습니다. 너무 길어서 로딩도 오래걸리고, 읽는 사람도 힘들겠더군요. 내 맘대로 하는 프로그램 설계&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/34&quot; data-og-url=&quot;https://black7375.tistory.com/34&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/shCqX/hyMESH89on/9isQ9gEuBGixYx2rpOFBf1/img.png?width=330&amp;amp;height=327&amp;amp;face=0_0_330_327,https://scrap.kakaocdn.net/dn/yGAYO/hyMFM7nIOw/c4RyWhKfOV2DkycL1eO371/img.png?width=330&amp;amp;height=327&amp;amp;face=0_0_330_327,https://scrap.kakaocdn.net/dn/cn7XEG/hyMFF8fYgO/LcMqdGX2EWTthcN2tFnuoK/img.png?width=728&amp;amp;height=637&amp;amp;face=0_0_728_637&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/34&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/34&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/shCqX/hyMESH89on/9isQ9gEuBGixYx2rpOFBf1/img.png?width=330&amp;amp;height=327&amp;amp;face=0_0_330_327,https://scrap.kakaocdn.net/dn/yGAYO/hyMFM7nIOw/c4RyWhKfOV2DkycL1eO371/img.png?width=330&amp;amp;height=327&amp;amp;face=0_0_330_327,https://scrap.kakaocdn.net/dn/cn7XEG/hyMFF8fYgO/LcMqdGX2EWTthcN2tFnuoK/img.png?width=728&amp;amp;height=637&amp;amp;face=0_0_728_637');&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;내 맘대로 프로그램 설계 3. - 함수와 변수.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;원래 합쳐져서 Section2 였던 '기초'에서 '간단한 데이터 처리'와 '함수'로 나뉘어 구성하게 되었습니다. 너무 길어서 로딩도 오래걸리고, 읽는 사람도 힘들겠더군요. 내 맘대로 하는 프로그램 설계&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.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;온갖 사이드 이펙트가 펼쳐지는 복잡계 시간의 흐름은 상호작용이 일어나는 것을 의미하고, 상태가 변하며 규약과 행동양식 또한 변한다.&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;절차지향이 나오기 전에는 Goto(jmp)문을 이용해 만들었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhX7qf/btrnBtGCKVV/xVzK3C5byRd7KzfR09TFtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhX7qf/btrnBtGCKVV/xVzK3C5byRd7KzfR09TFtK/img.png&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;332&quot; style=&quot;width: 42.712%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhX7qf/btrnBtGCKVV/xVzK3C5byRd7KzfR09TFtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhX7qf%2FbtrnBtGCKVV%2FxVzK3C5byRd7KzfR09TFtK%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;420&quot; height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kIwS2/btrnCmmpz7Q/6eQFUDbpLAQHUaiWKrLGxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kIwS2/btrnCmmpz7Q/6eQFUDbpLAQHUaiWKrLGxK/img.png&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;154&quot; style=&quot;width: 56.1252%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kIwS2/btrnCmmpz7Q/6eQFUDbpLAQHUaiWKrLGxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkIwS2%2FbtrnCmmpz7Q%2F6eQFUDbpLAQHUaiWKrLGxK%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;256&quot; height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Goto vs 절차지향[&lt;a href=&quot;https://docs.microsoft.com/ko-kr/windows/win32/rpc/the-programming-model&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 goto의 단점은 컨텍스트와 흐름이 섞여 나중에 알아보기가 매우 힘들다는 점이다.&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;480&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyVHcp/btrnDpED0d8/Y9bli4FMbieFTNCkRCPQKk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyVHcp/btrnDpED0d8/Y9bli4FMbieFTNCkRCPQKk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyVHcp/btrnDpED0d8/Y9bli4FMbieFTNCkRCPQKk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyVHcp%2FbtrnDpED0d8%2FY9bli4FMbieFTNCkRCPQKk%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;480&quot; height=&quot;269&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;시간이 뒤바뀐다면? [&lt;a href=&quot;https://m.blog.naver.com/2pig1/220231028689&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;백투더퓨쳐1&amp;nbsp;(Back&amp;nbsp;to&amp;nbsp;the&amp;nbsp;Future&amp;nbsp;1&amp;nbsp;:&amp;nbsp;1985)&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;물론 Goto가 무조건 나쁘다는 것은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩된 for문을 탈출하기에는 괜찮은 방법이며, &lt;a href=&quot;https://rosettacode.org/wiki/Look-and-say_sequence#Fast_Imperative_Version&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FSM 구현&lt;/a&gt;이나 &lt;a href=&quot;https://eli.thegreenplace.net/2012/07/12/computed-goto-for-efficient-dispatch-tables&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VM 구현&lt;/a&gt;때에도 유용하게(주로 성능 문제) 쓰이는 등 한정적인 용도로는 쓰이고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Goto로 제어문을 만드는 방법이 궁금하면 어셈블리 게임 해보는 것도 ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/375820/Human_Resource_Machine/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://store.steampowered.com/app/375820/Human_Resource_Machine/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639213613417&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;Human Resource Machine on Steam&quot; data-og-description=&quot;Program little office workers to solve puzzles. Be a good employee! The machines are coming... for your job. From the creators of World of Goo and Little Inferno.&quot; data-og-host=&quot;store.steampowered.com&quot; data-og-source-url=&quot;https://store.steampowered.com/app/375820/Human_Resource_Machine/&quot; data-og-url=&quot;https://store.steampowered.com/app/375820/Human_Resource_Machine/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/8gg6u/hyME0lGFbm/EMg5xtwMIoLepJldk7QTV0/img.jpg?width=616&amp;amp;height=353&amp;amp;face=0_0_616_353,https://scrap.kakaocdn.net/dn/i41uL/hyMFS7oTLb/QrWmSatLe1sCG8R3NqLjvK/img.jpg?width=616&amp;amp;height=353&amp;amp;face=0_0_616_353&quot;&gt;&lt;a href=&quot;https://store.steampowered.com/app/375820/Human_Resource_Machine/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://store.steampowered.com/app/375820/Human_Resource_Machine/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/8gg6u/hyME0lGFbm/EMg5xtwMIoLepJldk7QTV0/img.jpg?width=616&amp;amp;height=353&amp;amp;face=0_0_616_353,https://scrap.kakaocdn.net/dn/i41uL/hyMFS7oTLb/QrWmSatLe1sCG8R3NqLjvK/img.jpg?width=616&amp;amp;height=353&amp;amp;face=0_0_616_353');&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;Human Resource Machine on Steam&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Program little office workers to solve puzzles. Be a good employee! The machines are coming... for your job. From the creators of World of Goo and Little Inferno.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;store.steampowered.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;그러나 일반적인 용도로 사용하기에 적합하지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 말했듯이 컨텍스트가 섞이게 되면 의도치 않은 부작용이 크고 디버깅하기가 매우 힘들어지며 나머지 추상화를 거의 포기하는 것과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 for, while, switch와 같은 제어문, 함수들을 이용해 개발하며 Goto는 컨텍스트의 이동이라는 명확한 가치가 있을때만 사용하는 것을 추천.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;러스트에서는 중첩된 loop용으로 블록을 만들어 부작용을 최소화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://doc.rust-lang.org/rust-by-example/flow_control/loop/nested.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://doc.rust-lang.org/rust-by-example/flow_control/loop/nested.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639218160196&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;Nesting and labels - Rust By Example&quot; data-og-description=&quot;It's possible to break or continue outer loops when dealing with nested loops. In these cases, the loops must be annotated with some 'label, and the label must be passed to the break/continue statement. #![allow(unreachable_code)] fn main() { 'outer: loop &quot; data-og-host=&quot;doc.rust-lang.org&quot; data-og-source-url=&quot;https://doc.rust-lang.org/rust-by-example/flow_control/loop/nested.html&quot; data-og-url=&quot;https://doc.rust-lang.org/rust-by-example/flow_control/loop/nested.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://doc.rust-lang.org/rust-by-example/flow_control/loop/nested.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://doc.rust-lang.org/rust-by-example/flow_control/loop/nested.html&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;Nesting and labels - Rust By Example&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;It's possible to break or continue outer loops when dealing with nested loops. In these cases, the loops must be annotated with some 'label, and the label must be passed to the break/continue statement. #![allow(unreachable_code)] fn main() { 'outer: loop&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;doc.rust-lang.org&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;size18&quot;&gt;&lt;b&gt;선언형&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 UI 부분에서 Flutter, Swift UI, Jetpack compose등 선언형 방식을 채택하는 경우가 늘어나고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1807&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/62Qp3/btrnC22uvHZ/YmHROlmxMH14Z915oSxkD1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/62Qp3/btrnC22uvHZ/YmHROlmxMH14Z915oSxkD1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/62Qp3/btrnC22uvHZ/YmHROlmxMH14Z915oSxkD1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F62Qp3%2FbtrnC22uvHZ%2FYmHROlmxMH14Z915oSxkD1%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;1280&quot; height=&quot;1807&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1807&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;[&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/imperative-vs-declarative-kubernetes-management-a-digitalocean-comic&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Imperative vs. Declarative Kubernetes Management: A DigitalOcean Comic&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;선언형은 어떻게(How) 해야 하는지보다 무엇(What)을 강조한다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2xdRV/btrnDFyM2Qv/mOt1dbKiDV6sQhHtkQXyP0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2xdRV/btrnDFyM2Qv/mOt1dbKiDV6sQhHtkQXyP0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2xdRV/btrnDFyM2Qv/mOt1dbKiDV6sQhHtkQXyP0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2xdRV%2FbtrnDFyM2Qv%2FmOt1dbKiDV6sQhHtkQXyP0%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;660&quot; height=&quot;479&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;[&lt;a href=&quot;https://www.learncomputerscienceonline.com/programming-paradigm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Programming Paradigm&lt;/a&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OVkmY/btrnPLsCFIE/KY1QfvhKJTJduva5qHSvfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OVkmY/btrnPLsCFIE/KY1QfvhKJTJduva5qHSvfk/img.png&quot; width=&quot;756&quot; height=&quot;257&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;257&quot; style=&quot;width: 65.9007%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OVkmY/btrnPLsCFIE/KY1QfvhKJTJduva5qHSvfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOVkmY%2FbtrnPLsCFIE%2FKY1QfvhKJTJduva5qHSvfk%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;756&quot; height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cphhd2/btrnDHqmTSO/CYluwQXXLw5FziYz7JU3gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cphhd2/btrnDHqmTSO/CYluwQXXLw5FziYz7JU3gK/img.png&quot; width=&quot;311&quot; height=&quot;211&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;453&quot; style=&quot;width: 32.9365%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cphhd2/btrnDHqmTSO/CYluwQXXLw5FziYz7JU3gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcphhd2%2FbtrnDHqmTSO%2FCYluwQXXLw5FziYz7JU3gK%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;453&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;[&lt;a href=&quot;https://livebook.manning.com/book/get-programming-with-scala/chapter-21/v-6/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What is Purity?&lt;/a&gt;, &lt;a href=&quot;https://bobonmedicaldevicesoftware.com/blog/2019/01/27/exploring-clojure-and-fp-vs-oop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Exploring Clojure (and FP vs OOP)&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 함수가 행하려는 형태(input/output)를 표현하기 어렵다면 함수형 프로그래밍을 하기 어려워진다.&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;예를 들어 숫자와 문자는 1 + 1 = 2, &quot;가&quot; + &quot;나&quot; = &quot;가나&quot;처럼 달라질 수 있고, &quot;가&quot; / &quot;나&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;일반적으로 생각할때 하나로 묶을수 있는 자료형들이라 할지라도, &quot;없다면 실체를 생각할 수 없는 것&quot;이기 때문에 비슷한 행동을 하지만 다른 자료형들로 분리되어 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 숫자지만 컴퓨터라는 한계(일반적인 정수/실수와 다르게 크기와 정확도등의 제한됨)에 의해 int, double등과 같이 형태를 정의해야만 실체가 생길 수 있는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일정한 제한 내에서 같은 연산자나 함수를 가지더라도 다른 형태이므로 또 서술해야 하는 상황을 막기 위해 제네릭(Generic)으로 추상하여 표현하기도 한다.&lt;/p&gt;
&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;따라서 Stateless와 순수함수를 지향하며, 불변자료구조를 사용하고 모나드와 같은 것을 사용해 어쩔수 없는 상태(I/O 같은것)를 감싸 해결을 하려 시도한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;느긋한 평가(Lazy eval)의 경우 순수함수라서 생길 수 있는 특징이며 커링(Curring, 인자를 하나씩만 받음)등을 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 인자값을 더해야 하는 함수를 커링화했다고 생각하면 이러합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1639401712509&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;add(2)(3)(5)(6) // ...&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;함수형과 관련된 글들은 많이 써두었으니 이 이상은 여기에서는 설명하지 않겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://black7375.tistory.com/62&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639236511840&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.&quot; data-og-description=&quot;내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비. 2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/62&quot; data-og-url=&quot;https://black7375.tistory.com/62&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cyhugY/hyMEU60hZ6/j9z1A1wprBkQXAOT9KLJFK/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/j13ng/hyMFM0AbQE/1GcE593a72lMLEkVdJODq0/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/gc0Kp/hyME3iz3GH/M5aVD8k9S6vmQxxOV4L9m1/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/62&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cyhugY/hyMEU60hZ6/j9z1A1wprBkQXAOT9KLJFK/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/j13ng/hyMFM0AbQE/1GcE593a72lMLEkVdJODq0/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/gc0Kp/hyME3iz3GH/M5aVD8k9S6vmQxxOV4L9m1/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612');&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;내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비. 2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/69&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://black7375.tistory.com/69&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639228541182&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;간단한 모나드 설명과 예제&quot; data-og-description=&quot;리엑트 네이티브 스터디 때문에 시작한 글이었는데 생각보다 길어져서 분리하게 되었다. 자바스크립트 관련 코드는 해당 스터디쪽 문서에 올릴 예정. 역시 모나드를 이해할때는 Haskell이 가장 &quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/69&quot; data-og-url=&quot;https://black7375.tistory.com/69&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bofs9e/hyMFEg8KyC/cbHcAmzIGzlyWnivF1m0Yk/img.png?width=176&amp;amp;height=194&amp;amp;face=0_0_176_194,https://scrap.kakaocdn.net/dn/dICAwS/hyME1dWBI7/3lzmJsaKDwEkZ9GqNW7Bq1/img.png?width=176&amp;amp;height=194&amp;amp;face=0_0_176_194,https://scrap.kakaocdn.net/dn/bBLVKK/hyME1E0UlS/cNUVh2M85QDpq6aKem8tKK/img.png?width=1920&amp;amp;height=1693&amp;amp;face=0_0_1920_1693&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/69&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/69&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bofs9e/hyMFEg8KyC/cbHcAmzIGzlyWnivF1m0Yk/img.png?width=176&amp;amp;height=194&amp;amp;face=0_0_176_194,https://scrap.kakaocdn.net/dn/dICAwS/hyME1dWBI7/3lzmJsaKDwEkZ9GqNW7Bq1/img.png?width=176&amp;amp;height=194&amp;amp;face=0_0_176_194,https://scrap.kakaocdn.net/dn/bBLVKK/hyME1E0UlS/cNUVh2M85QDpq6aKem8tKK/img.png?width=1920&amp;amp;height=1693&amp;amp;face=0_0_1920_1693');&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;간단한 모나드 설명과 예제&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;리엑트 네이티브 스터디 때문에 시작한 글이었는데 생각보다 길어져서 분리하게 되었다. 자바스크립트 관련 코드는 해당 스터디쪽 문서에 올릴 예정. 역시 모나드를 이해할때는 Haskell이 가장&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://black7375.tistory.com/71&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639228553016&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;자바스크립트와 함수형 프로그래밍.&quot; data-og-description=&quot;React Native에서 사용하는 React는 함수형 프로그래밍의 철학을 받아들여 만들어졌습니다. React를 처음 접하는 이들을 위한 문서에서도 함수형 프로그래밍의 특징중 하나라는 불변성을 강조하고 있&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/71&quot; data-og-url=&quot;https://black7375.tistory.com/71&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bYoWlL/hyMFSsVsdP/gReBI63dgSWZHf2GaprnKK/img.png?width=800&amp;amp;height=296&amp;amp;face=0_0_800_296,https://scrap.kakaocdn.net/dn/s0GWj/hyMEUy7ETX/kMPQh0MzJqz9KfyiZV14TK/img.png?width=800&amp;amp;height=296&amp;amp;face=0_0_800_296,https://scrap.kakaocdn.net/dn/dSlbEE/hyMFPQvwJQ/K0tle18LVpDUa6yQ7JBN31/img.png?width=801&amp;amp;height=297&amp;amp;face=0_0_801_297&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/71&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bYoWlL/hyMFSsVsdP/gReBI63dgSWZHf2GaprnKK/img.png?width=800&amp;amp;height=296&amp;amp;face=0_0_800_296,https://scrap.kakaocdn.net/dn/s0GWj/hyMEUy7ETX/kMPQh0MzJqz9KfyiZV14TK/img.png?width=800&amp;amp;height=296&amp;amp;face=0_0_800_296,https://scrap.kakaocdn.net/dn/dSlbEE/hyMFPQvwJQ/K0tle18LVpDUa6yQ7JBN31/img.png?width=801&amp;amp;height=297&amp;amp;face=0_0_801_297');&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;자바스크립트와 함수형 프로그래밍.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;React Native에서 사용하는 React는 함수형 프로그래밍의 철학을 받아들여 만들어졌습니다. React를 처음 접하는 이들을 위한 문서에서도 함수형 프로그래밍의 특징중 하나라는 불변성을 강조하고 있&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tistory.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;&lt;a href=&quot;https://timbaumann.info/pfds-visualizations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://timbaumann.info/pfds-visualizations/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639229094807&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;Purely Functional Queues&quot; data-og-description=&quot;&quot; data-og-host=&quot;timbaumann.info&quot; data-og-source-url=&quot;https://timbaumann.info/pfds-visualizations/&quot; data-og-url=&quot;https://timbaumann.info/pfds-visualizations/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://timbaumann.info/pfds-visualizations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://timbaumann.info/pfds-visualizations/&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;Purely Functional Queues&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;timbaumann.info&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;함수형과 철학에 재밌는 점을 꼽아보자면 함수형에서 형태로 나타나기 위해 자주 사용되는 기법 중에 하나인 재귀가 변증법적이라는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUXKag/btrnDoYAYwk/sLIt9RL7zZpMiUoNSNB9GK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUXKag/btrnDoYAYwk/sLIt9RL7zZpMiUoNSNB9GK/img.png&quot; width=&quot;286&quot; height=&quot;284&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;568&quot; style=&quot;width: 40.1794%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUXKag/btrnDoYAYwk/sLIt9RL7zZpMiUoNSNB9GK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUXKag%2FbtrnDoYAYwk%2FsLIt9RL7zZpMiUoNSNB9GK%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;572&quot; height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C4j0h/btrnE9G2AEp/vGHiKI9CgA7l2NJChMUzk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C4j0h/btrnE9G2AEp/vGHiKI9CgA7l2NJChMUzk0/img.png&quot; width=&quot;286&quot; height=&quot;402&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;804&quot; style=&quot;width: 28.3854%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C4j0h/btrnE9G2AEp/vGHiKI9CgA7l2NJChMUzk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC4j0h%2FbtrnE9G2AEp%2FvGHiKI9CgA7l2NJChMUzk0%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;572&quot; height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KUBH4/btrnHSLyW6a/Cto0Yv8yUgV2qylZ1e5W4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KUBH4/btrnHSLyW6a/Cto0Yv8yUgV2qylZ1e5W4K/img.png&quot; width=&quot;286&quot; height=&quot;392&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;784&quot; style=&quot;width: 29.1096%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KUBH4/btrnHSLyW6a/Cto0Yv8yUgV2qylZ1e5W4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKUBH4%2FbtrnHSLyW6a%2FCto0Yv8yUgV2qylZ1e5W4K%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;572&quot; height=&quot;784&quot;/&gt;&lt;/span&gt;&lt;/div&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;a href=&quot;https://black7375.tumblr.com/post/175291125910&quot;&gt;https://black7375.tumblr.com/post/175291125910&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639256937747&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;재귀가 아름다운 이유.&quot; data-og-description=&quot;재귀가 아름다운 이유. 결론적으로 말하자면 내재적 정합성과 필연성을 가지기 때문이다. 재귀가 왜 아름다운지를 알기하기 위해서 우선 재귀의 과정을 파악할 필요가 있다. 재귀의 과정. 잘 만&quot; data-og-host=&quot;black7375.tumblr.com&quot; data-og-source-url=&quot;https://black7375.tumblr.com/post/175291125910&quot; data-og-url=&quot;https://black7375.tumblr.com/post/175291125910/%EC%9E%AC%EA%B7%80%EA%B0%80-%EC%95%84%EB%A6%84%EB%8B%A4%EC%9A%B4-%EC%9D%B4%EC%9C%A0&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/175291125910&quot; data-source-url=&quot;https://black7375.tumblr.com/post/175291125910&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('&amp;quot;&amp;quot;');&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;재귀가 아름다운 이유.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;재귀가 아름다운 이유. 결론적으로 말하자면 내재적 정합성과 필연성을 가지기 때문이다. 재귀가 왜 아름다운지를 알기하기 위해서 우선 재귀의 과정을 파악할 필요가 있다. 재귀의 과정. 잘 만&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tumblr.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;&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;논리형에서 말하는 논리(Fact + Rules)는 철학에서 말하는 논리와 거의 동일하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IWsGV/btrnAYtiI5C/XpjDAak9tAKDKEgkF7PuHk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IWsGV/btrnAYtiI5C/XpjDAak9tAKDKEgkF7PuHk/img.jpg&quot; width=&quot;567&quot; height=&quot;479&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;479&quot; style=&quot;width: 44.3752%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IWsGV/btrnAYtiI5C/XpjDAak9tAKDKEgkF7PuHk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIWsGV%2FbtrnAYtiI5C%2FXpjDAak9tAKDKEgkF7PuHk%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;567&quot; height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbJ3TQ/btrnDHcOUYK/IAqT8gHE1sCs2kYuVJFZQK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbJ3TQ/btrnDHcOUYK/IAqT8gHE1sCs2kYuVJFZQK/img.jpg&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;413&quot; style=&quot;width: 54.462%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbJ3TQ/btrnDHcOUYK/IAqT8gHE1sCs2kYuVJFZQK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbJ3TQ%2FbtrnDHcOUYK%2FIAqT8gHE1sCs2kYuVJFZQK%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;600&quot; height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;[&lt;a href=&quot;https://www.tutorialspoint.com/prolog/prolog_introduction.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Prolog&amp;nbsp;-&amp;nbsp;Introduction&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;이성론자들이 말하는 사고는 선험적(내재적)이며, 언표(apophansis)로서 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 언표는 &quot;말로 나타낸 바&quot;라 할 수 있으며,&amp;nbsp; 문장에서 핵심이 되는 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%A3%BC%EC%96%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;주어&lt;/a&gt;와 설명하는&amp;nbsp;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%88%A0%EC%96%B4&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;/p&gt;
&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://ko.wikipedia.org/wiki/%EC%88%A0%EC%96%B4_%EB%85%BC%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;술어논리&lt;/a&gt;를 기술할 수 있게 만들어진 프롤로그의 코드를 보여주며 말하자면 [&lt;a href=&quot;http://www.aistudy.com/program/prolog/prolog_lee.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;인공지능언어 PROLOG&lt;/a&gt;, &lt;a href=&quot;https://passexam.tistory.com/entry/Prolog-%EB%85%BC%EB%A6%AC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%96%B8%EC%96%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Prolog 논리 프로그래밍 언어&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;Fact는 일종의 정언판단이다. (실체와 속성을 의미하며, 정언명령과는 다름)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;li&gt;메리는 와인을 좋아한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1639251610111&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% Facts
human(john).
human(mary).
likes(john, wine).
likes(mary, wine).&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;Rule은 가언판단(원인과 결과)등을 기술할 수 있다.&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;/ul&gt;
&lt;pre id=&quot;code_1639252770782&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% Rules
likes(john, X):-likes(X,wine).
die(X):-human(X).&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;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;누가(X)가 죽는가? - 존, 메리&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1639254534530&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% Query
?-die(john).
?-likes(john, mary).
?-die(X).&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;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B3%A0%ED%8B%80%EB%A1%9C%ED%94%84_%ED%94%84%EB%A0%88%EA%B2%8C&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;/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;객체지향 및 대체&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;&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;직관에서 오는 생산성은&amp;nbsp;전통적인 OOP가 오랫동안 지배해왔던 이유이기도 하다.&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;616&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzlHva/btrnHRFTPw6/RdGMeCWYHRWSwHEdnIzqW1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzlHva/btrnHRFTPw6/RdGMeCWYHRWSwHEdnIzqW1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzlHva/btrnHRFTPw6/RdGMeCWYHRWSwHEdnIzqW1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzlHva%2FbtrnHRFTPw6%2FRdGMeCWYHRWSwHEdnIzqW1%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;616&quot; height=&quot;231&quot; data-origin-width=&quot;616&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.c-sharpcorner.com/UploadFile/8a67c0/oops-vs-procedural-programming/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OOPs&amp;nbsp;Vs&amp;nbsp;Procedural&amp;nbsp;Programming&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;심지어 GTK와 리눅스 커널은 OOP를 지원하지 않는 C언어를 쓰면서도 OOP적인 방법을 지원한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://lethean.github.io/2007/02/05/gobject-glib-object-system/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GObject - Glib object system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lethean.github.io/2009/08/10/oop-with-gobject-1/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GObject 객체 지향 프로그래밍 (1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lethean.github.io/2009/08/14/oop-with-gobject-2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GObject 객체 지향 프로그래밍 (2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lethean.github.io/2009/08/18/oop-with-gobject-3/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GObject 객체 지향 프로그래밍 (3)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lethean.github.io/2009/08/24/oop-with-gobject-4/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GObject 객체 지향 프로그래밍 (4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lwn.net/Articles/444910/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Object-oriented&amp;nbsp;design&amp;nbsp;patterns&amp;nbsp;in&amp;nbsp;the&amp;nbsp;kernel,&amp;nbsp;part&amp;nbsp;1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lwn.net/Articles/446317/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Object-oriented design patterns in the kernel, part 2&lt;/a&gt;&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;letter-spacing: 0px;&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;이는 추후 클래스와 프로토타입을 철학과 연결할 때 다시 언급하도록 하자.&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;&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;blockquote&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;시간 변화(時間變化, time evolution)는 시간의 흐름에 따라 계의 상태가 바뀌는 과정이다.&lt;footer&gt;위키백과(&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%8B%9C%EA%B0%84_%EB%B3%80%ED%99%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;시간 변화&lt;/a&gt;)&lt;/footer&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용을 설명하려면 긴 내용이 필요하므로 &lt;s&gt;생략&lt;/s&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;Stateless하면 시간이 흐르지 않았다는 말이다.&lt;/li&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;상태를 기준으로 추상화를 하면 성능이 올라갈 수 있다는 말이다.&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_1639154603112&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1300&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uJihE/btrnAX19EW4/kDyqxy18WNWGKkyj1YRUx0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uJihE/btrnAX19EW4/kDyqxy18WNWGKkyj1YRUx0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uJihE/btrnAX19EW4/kDyqxy18WNWGKkyj1YRUx0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuJihE%2FbtrnAX19EW4%2FkDyqxy18WNWGKkyj1YRUx0%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;1300&quot; height=&quot;500&quot; data-origin-width=&quot;1300&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;OOP vs&amp;nbsp; DOD&amp;nbsp; [&lt;a href=&quot;https://twitter.com/viebel/status/1359456383939321856/photo/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;twitter&lt;/a&gt;] - DOD는 상태가 줄어들고 비슷한 값끼리 묶여 지역성이 늘어난다.&lt;/p&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;/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://en.wikipedia.org/wiki/Lisp_machine&quot;&gt;리스프 머신&lt;/a&gt;이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.cs.york.ac.uk/fp/reduceron/&quot;&gt;The Reduceron&lt;/a&gt;(&lt;a href=&quot;https://news.ycombinator.com/item?id=2645423&quot;&gt;HN&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;반면 데이터 주도 설계는 현재 컴퓨터 설계를 기준으로 상태 변화를 낮추려고 시도한다. [&lt;a href=&quot;https://medium.com/mirum-budapest/introduction-to-data-oriented-programming-85b51b99572d&quot;&gt;Introduction&amp;nbsp;to&amp;nbsp;Data-Oriented&amp;nbsp;Programming&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/dbartolini/data-oriented-design&quot;&gt;Data Oriented Design Resources&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;a href=&quot;https://jamesmcm.github.io/blog/2020/07/25/intro-dod/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;An&amp;nbsp;introduction&amp;nbsp;to&amp;nbsp;Data&amp;nbsp;Oriented&amp;nbsp;Design&amp;nbsp;with&amp;nbsp;Rust&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조체를 사용하는 예제이지만 클래스나 기타 OOP 구현에서도 충분히 사용할 수 있는 기법이다.&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;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBtzHr/btrnB9n1P7n/MfXkxtZPvpeNwUbZLPrSok/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBtzHr/btrnB9n1P7n/MfXkxtZPvpeNwUbZLPrSok/tfile.dat&quot; data-alt=&quot;걸리는 시간 차이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBtzHr/btrnB9n1P7n/MfXkxtZPvpeNwUbZLPrSok/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBtzHr%2FbtrnB9n1P7n%2FMfXkxtZPvpeNwUbZLPrSok%2Ftfile.dat&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; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;pre id=&quot;code_1639304587387&quot; class=&quot;rust&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; 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-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;rust&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pub struct Player {
    name: String,
    health: f64,
    location: (f64, f64),
    velocity: (f64, f64),
    acceleration: (f64, f64),
}

pub fn run_oop(players: &amp;amp;mut Vec&amp;lt;Player&amp;gt;) {
    for player in players.iter_mut() {
        player.location = (
            player.location.0 + player.velocity.0,
            player.location.1 + player.velocity.1,
        );
        player.velocity = (
            player.velocity.0 + player.acceleration.0,
            player.velocity.1 + player.acceleration.1,
        );
    }
}&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;pre id=&quot;code_1639304587387&quot; class=&quot;rust&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; 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-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;rust&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pub struct DOPlayers {
    names: Vec&amp;lt;String&amp;gt;,
    health: Vec&amp;lt;f64&amp;gt;,
    locations: Vec&amp;lt;(f64, f64)&amp;gt;,
    velocities: Vec&amp;lt;(f64, f64)&amp;gt;,
    acceleration: Vec&amp;lt;(f64, f64)&amp;gt;,
}

pub fn run_dop(world: &amp;amp;mut DOPlayers) {
    for (pos, (vel, acc)) in world
        .locations
        .iter_mut()
        .zip(world.velocities.iter_mut().zip(world.acceleration.iter()))
    {
        *pos = (pos.0 + vel.0, pos.1 + vel.1);
        *vel = (vel.0 + acc.0, vel.1 + acc.1);
    }
}&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u0Uxf/btrnCA6Nf4f/Rujc40cb7U6lGPrsvb8H31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u0Uxf/btrnCA6Nf4f/Rujc40cb7U6lGPrsvb8H31/img.png&quot; data-origin-width=&quot;229&quot; data-origin-height=&quot;247&quot; style=&quot;width: 53.5362%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u0Uxf/btrnCA6Nf4f/Rujc40cb7U6lGPrsvb8H31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu0Uxf%2FbtrnCA6Nf4f%2FRujc40cb7U6lGPrsvb8H31%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;229&quot; height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bChIKF/btrnHS6dSFn/bBdapcdTsGuFNgs1KfaZgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bChIKF/btrnHS6dSFn/bBdapcdTsGuFNgs1KfaZgk/img.png&quot; data-origin-width=&quot;233&quot; data-origin-height=&quot;297&quot; style=&quot;width: 45.301%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bChIKF/btrnHS6dSFn/bBdapcdTsGuFNgs1KfaZgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbChIKF%2FbtrnHS6dSFn%2FbBdapcdTsGuFNgs1KfaZgk%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;233&quot; height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@jonathanmines/data-oriented-vs-object-oriented-design-50ef35a99056&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Data-Oriented&amp;nbsp;vs&amp;nbsp;Object-Oriented&amp;nbsp;Design&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;캐싱과 자동 벡터화, 분기예측등 각종 최적화 혜택을 받기에 좋아보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 DOD를 적극적으로 활용하기 위해 나온 패턴이 있는데&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Entity_component_system&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ECS(Entity Component System)&lt;/a&gt;이라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통직인 OOP와는 다소차이가 있지만 유니티에서 &lt;a href=&quot;https://blog.unity.com/kr/technology/on-dots-entity-component-system&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DOTS&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;b&gt;도메인 주도와 AOP&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 주도와 AOP에 대해 이야기 앞서 비트겐슈타인의 그림이론과 용도의미론에 대해 설명할 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림이론은 그의 전기이론[&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%85%BC%EB%A6%AC%EC%B2%A0%ED%95%99_%EB%85%BC%EA%B3%A0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;논리-철학 논고&lt;/a&gt;], 용도의미론은 후기이론[&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%B2%A0%ED%95%99_%ED%83%90%EA%B5%AC&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;a href=&quot;https://imnt.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비트겐슈타인(2)-전기 사상 : 언어그림이론-모사설&lt;/a&gt;, &lt;a href=&quot;https://imnt.tistory.com/207?category=490113&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비트겐슈타인(8)-후기 사상 : 용도의미론(the use theory of meaning)&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;호랑이, 사자와 같은 대상, 사냥하다나 잠자다와 같은 술어등 모두 &quot;공통된 요소들을 추상하여 합친 관념&quot;이거나,&amp;nbsp; &quot;공통된 요소들을 참조하여 나타난 표현&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;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;있다.&lt;/p&gt;
&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://ko.wikipedia.org/wiki/%EB%8F%99%EA%B5%B4%EC%9D%98_%EC%9A%B0%ED%99%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;동굴의 우화&lt;/a&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVKuT7/btrnCPJaNvl/YEd4pHgBhBkxlLARpNyck1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVKuT7/btrnCPJaNvl/YEd4pHgBhBkxlLARpNyck1/img.png&quot; data-alt=&quot;동굴의 우화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVKuT7/btrnCPJaNvl/YEd4pHgBhBkxlLARpNyck1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVKuT7%2FbtrnCPJaNvl%2FYEd4pHgBhBkxlLARpNyck1%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;948&quot; height=&quot;458&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;496&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;구속되어 있는 사람(우측)의 사람은 그림자만 볼 수 있고, 그림자가 &quot;실체&quot;라 생각한다.&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;절대적으로 그렇지 않다.&lt;/p&gt;
&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;&quot;언어는 세계의 그림이다&quot;라는 그림이론도 비슷하다.&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;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;지칭한다.&lt;/p&gt;
&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_1639313557213&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% Facts
human(john).
human(mary).
likes(john, wine).
likes(mary, wine).&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;&quot;존은 사람이다&quot;라는 복합사실은&lt;/li&gt;
&lt;li&gt;&quot;존&quot;과 &quot;사람&quot;이라는 원자사실의 결합이다. (더 이상 나뉠수 없고 독립적임)&lt;/li&gt;
&lt;li&gt;&quot;존&quot;과 &quot;사람&quot;은 존과 사람 각각의 공통된 요소들을 추상한 &quot;대상&quot;을 지칭하는 &quot;이름&quot;이었다.&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;/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;640&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/di6TXL/btrnCBdCKhd/xzooI2nZqhsXTJ4FEGzFA0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/di6TXL/btrnCBdCKhd/xzooI2nZqhsXTJ4FEGzFA0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/di6TXL/btrnCBdCKhd/xzooI2nZqhsXTJ4FEGzFA0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdi6TXL%2FbtrnCBdCKhd%2FxzooI2nZqhsXTJ4FEGzFA0%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;640&quot; height=&quot;352&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;만약 캐스트어웨이의 윌리같은 존재라면..? [&lt;a href=&quot;https://m.blog.naver.com/2710you/120134665045&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;톰행크스의&amp;nbsp;무인도표류기&amp;nbsp;캐스트어웨이&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;사람이 아니더라도 세계의 &quot;판단 자체&quot;에는 영향을 끼치지 않습니다.&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;p data-ke-size=&quot;size16&quot;&gt;이 글을 쓰게된 &lt;a href=&quot;https://medium.com/@limsungmook/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%99%9C-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85%EC%9D%84-%EC%84%A0%ED%83%9D%ED%96%88%EC%9D%84%EA%B9%8C-997f985adb42&quot;&gt;자바스크립트는&amp;nbsp;왜&amp;nbsp;프로토타입을&amp;nbsp;선택했을까&lt;/a&gt;에서도 &quot;벽돌!!&quot;로 설명했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;그래서 후기 비트겐슈타인은 이를&amp;nbsp;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%96%B8%EC%96%B4%EB%86%80%EC%9D%B4&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HoFOM/btrnCPPXKI2/3tEg71tF4lBwNFLYNBmKr1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HoFOM/btrnCPPXKI2/3tEg71tF4lBwNFLYNBmKr1/img.jpg&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;284&quot; style=&quot;width: 76.2516%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HoFOM/btrnCPPXKI2/3tEg71tF4lBwNFLYNBmKr1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHoFOM%2FbtrnCPPXKI2%2F3tEg71tF4lBwNFLYNBmKr1%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;540&quot; height=&quot;284&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dngsdx/btrnEJ2KQuX/PQY0MJiOHfG0jBYA30rULk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dngsdx/btrnEJ2KQuX/PQY0MJiOHfG0jBYA30rULk/img.jpg&quot; width=&quot;811&quot; height=&quot;1440&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;1440&quot; style=&quot;width: 22.5856%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dngsdx/btrnEJ2KQuX/PQY0MJiOHfG0jBYA30rULk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdngsdx%2FbtrnEJ2KQuX%2FPQY0MJiOHfG0jBYA30rULk%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;811&quot; height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;또 다른 예시들[&lt;a href=&quot;https://m.blog.naver.com/fgus/221576338718&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;맥락적&amp;nbsp;사고의&amp;nbsp;중요성&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 OOP와 도메인 주도 설계는 그림이론-용도의미론의 관계와 유사하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 OOP에서는 속성관계를 &lt;b&gt;완벽&lt;/b&gt;하게 정의하려 했지만, 도메인 주도 설계는 &lt;b&gt;컨텍스트&lt;/b&gt;에 따라 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 주도 설계에 대한 글은 SK C&amp;amp;C에서 체계적으로 소개하고 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering-skcc.github.io/msa/DDD-WhatIsDdd/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;도메인 주도 설계가 필요한 이유&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering-skcc.github.io/msa/DDD-StrategicDesign/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;도메인 주도 설계에서의 전략적 설계&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering-skcc.github.io/agile/microservice-agile/&quot;&gt;마이크로서비스&amp;nbsp;모델링&amp;nbsp;①&amp;nbsp;:&amp;nbsp;애자일&amp;nbsp;프로세스에서의&amp;nbsp;마이크로서비스&amp;nbsp;설계/개발&amp;nbsp;공정&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering-skcc.github.io/microservice%20modeling/microservice-%EB%8F%84%EC%B6%9C%EA%B8%B0%EB%B2%95/&quot;&gt;마이크로서비스&amp;nbsp;모델링&amp;nbsp;②&amp;nbsp;:&amp;nbsp;마이크로서비스&amp;nbsp;도출기법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering-skcc.github.io/microservice%20modeling/ddd-Srategic-design/&quot;&gt;마이크로서비스&amp;nbsp;모델링&amp;nbsp;③&amp;nbsp;:&amp;nbsp;DDD의&amp;nbsp;전략적&amp;nbsp;설계&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering-skcc.github.io/microservice%20modeling/Event-Storming/&quot;&gt;마이크로서비스&amp;nbsp;모델링&amp;nbsp;④&amp;nbsp;:&amp;nbsp;이벤트&amp;nbsp;스토밍을&amp;nbsp;통한&amp;nbsp;마이크로서비스&amp;nbsp;도출&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering-skcc.github.io/microservice%20modeling/FrontEnd-modeling/&quot;&gt;마이크로서비스&amp;nbsp;모델링&amp;nbsp;⑤&amp;nbsp;:&amp;nbsp;FrontEnd&amp;nbsp;설계&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering-skcc.github.io/microservice%20modeling/BackEnd-modeling-API/&quot;&gt;마이크로서비스&amp;nbsp;모델링&amp;nbsp;⑥&amp;nbsp;:&amp;nbsp;BackEnd&amp;nbsp;설계&amp;nbsp;-API설계&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering-skcc.github.io/microservice%20modeling/BackEnd-modeling-domainModeling/&quot;&gt;마이크로서비스&amp;nbsp;모델링&amp;nbsp;⑦&amp;nbsp;:&amp;nbsp;BackEnd&amp;nbsp;설계&amp;nbsp;-&amp;nbsp;도메인모델링&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://tech.junhabaek.net/ddd-%EC%A0%84%EB%9E%B5%EC%A0%81-%EC%84%A4%EA%B3%84-event-storming-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%BB%A4%EB%A7%A8%EB%93%9C-%EC%99%B8%EB%B6%80%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%95%A1%ED%84%B0-23ea8af1f457&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DDD&amp;nbsp;전략적&amp;nbsp;설계&amp;nbsp;&amp;mdash;&amp;nbsp;Event&amp;nbsp;Storming&amp;nbsp;&amp;mdash;&amp;nbsp;이벤트,&amp;nbsp;커맨드,&amp;nbsp;외부서비스&amp;nbsp;액터&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tech.junhabaek.net/ddd-%EC%A0%84%EB%9E%B5%EC%A0%81-%EC%84%A4%EA%B3%84-eventstorming-%EC%95%A0%EA%B7%B8%EB%A6%AC%EA%B1%B0%ED%8A%B8-event-grouping-b9188b1b7665&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DDD&amp;nbsp;전략적&amp;nbsp;설계&amp;nbsp;&amp;mdash;&amp;nbsp;EventStorming&amp;nbsp;&amp;mdash;&amp;nbsp;애그리거트&amp;nbsp;추출,&amp;nbsp;Event&amp;nbsp;Grouping&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tech.junhabaek.net/ddd-%EC%A0%84%EB%9E%B5%EC%A0%81-%EC%84%A4%EA%B3%84-event-storming-read-model-policy-%EC%A0%95%EC%B1%85-86e30e96550f&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DDD&amp;nbsp;전략적&amp;nbsp;설계&amp;nbsp;&amp;mdash;&amp;nbsp;Event&amp;nbsp;Storming&amp;nbsp;&amp;mdash;&amp;nbsp;Read&amp;nbsp;Model,&amp;nbsp;Policy(정책)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tech.junhabaek.net/ddd-%EC%A0%84%EB%9E%B5%EC%A0%81-%EC%84%A4%EA%B3%84-event-storming-bounded-context%EC%9D%98-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%8B%9D%EB%B3%84-c28713e7fa12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DDD&amp;nbsp;전략적&amp;nbsp;설계&amp;nbsp;&amp;mdash;&amp;nbsp;Event&amp;nbsp;storming&amp;nbsp;&amp;mdash;&amp;nbsp;Bounded&amp;nbsp;Context의&amp;nbsp;이해와&amp;nbsp;식별&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tech.junhabaek.net/ddd-%EC%A0%84%EB%9E%B5%EC%A0%81-%EC%84%A4%EA%B3%84-event-storming-bounded-context%EC%9D%98-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%8B%9D%EB%B3%84-c28713e7fa12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DDD&amp;nbsp;전략적&amp;nbsp;설계&amp;nbsp;&amp;mdash;&amp;nbsp;Event&amp;nbsp;storming&amp;nbsp;&amp;mdash;&amp;nbsp;Bounded&amp;nbsp;Context의&amp;nbsp;이해와&amp;nbsp;식별&lt;/a&gt;&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;a href=&quot;https://ppiyo5.tistory.com/21&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;용어들 설명&lt;/a&gt;, &lt;a href=&quot;https://steemit.com/kr/@frontalnh/domain-driven-design&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;용어들 설명2&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfrEA9/btrnCBdE7Gi/i5tiMLsJ8eJoW01kXpnqg1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfrEA9/btrnCBdE7Gi/i5tiMLsJ8eJoW01kXpnqg1/tfile.svg&quot; data-origin-width=&quot;271&quot; data-origin-height=&quot;150&quot; data-filename=&quot;ddd1.svg&quot; style=&quot;width: 49.51%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfrEA9/btrnCBdE7Gi/i5tiMLsJ8eJoW01kXpnqg1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfrEA9%2FbtrnCBdE7Gi%2Fi5tiMLsJ8eJoW01kXpnqg1%2Ftfile.svg&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;271&quot; height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JBggn/btrnGkvf3U1/7GSZ5Yb0sVqNi7J3Zjfvb0/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JBggn/btrnGkvf3U1/7GSZ5Yb0sVqNi7J3Zjfvb0/tfile.svg&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;150&quot; data-filename=&quot;ddd2.svg&quot; style=&quot;width: 49.3273%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JBggn/btrnGkvf3U1/7GSZ5Yb0sVqNi7J3Zjfvb0/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJBggn%2FbtrnGkvf3U1%2F7GSZ5Yb0sVqNi7J3Zjfvb0%2Ftfile.svg&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;270&quot; height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.microsoft.com/ko-kr/azure/architecture/microservices/model/domain-analysis&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;모두 컨텍스트에 따라 개발할 도메인이 달라지게 되는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OaLNA/btrnBAswQOm/KKYUVvaoFIk2gYU2bB9p5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OaLNA/btrnBAswQOm/KKYUVvaoFIk2gYU2bB9p5K/img.png&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;316&quot; style=&quot;width: 43.9803%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OaLNA/btrnBAswQOm/KKYUVvaoFIk2gYU2bB9p5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOaLNA%2FbtrnBAswQOm%2FKKYUVvaoFIk2gYU2bB9p5K%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;648&quot; height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dIjn89/btrnJBcbYuH/rt4059cAJeIj9T88uXbFY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dIjn89/btrnJBcbYuH/rt4059cAJeIj9T88uXbFY1/img.png&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;502&quot; style=&quot;width: 54.8569%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dIjn89/btrnJBcbYuH/rt4059cAJeIj9T88uXbFY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdIjn89%2FbtrnJBcbYuH%2Frt4059cAJeIj9T88uXbFY1%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;1284&quot; height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/div&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1166&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKcBId/btrnC2IW1OT/1U4pIgiqqdWMtVzyrf0AB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKcBId/btrnC2IW1OT/1U4pIgiqqdWMtVzyrf0AB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKcBId/btrnC2IW1OT/1U4pIgiqqdWMtVzyrf0AB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKcBId%2FbtrnC2IW1OT%2F1U4pIgiqqdWMtVzyrf0AB1%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;1166&quot; height=&quot;474&quot; data-origin-width=&quot;1166&quot; data-origin-height=&quot;474&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 도메인을 설계할 때는 의존성에 따라 레이어를 나누어 설계를 하는게 좋다. [&lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&quot;&gt;The&amp;nbsp;Clean&amp;nbsp;Architecture&lt;/a&gt;, &lt;a href=&quot;https://docs.abp.io/en/abp/4.0/Domain-Driven-Design-Implementation-Guide&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Implementing Domain Driven Design&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://github.com/Sairyss/domain-driven-hexagon&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Domain-Driven Hexagon&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clZ0pR/btrnLIa3ZUD/barZ4cFKlki4QywQFv3cwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clZ0pR/btrnLIa3ZUD/barZ4cFKlki4QywQFv3cwk/img.png&quot; data-origin-width=&quot;1332&quot; data-origin-height=&quot;847&quot; style=&quot;width: 52.9733%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clZ0pR/btrnLIa3ZUD/barZ4cFKlki4QywQFv3cwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclZ0pR%2FbtrnLIa3ZUD%2FbarZ4cFKlki4QywQFv3cwk%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;1332&quot; height=&quot;847&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lT6lB/btrnJdWDaz7/PRxlm7pwR6kkiKbLHL1rbK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lT6lB/btrnJdWDaz7/PRxlm7pwR6kkiKbLHL1rbK/img.jpg&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;567&quot; style=&quot;width: 45.8639%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lT6lB/btrnJdWDaz7/PRxlm7pwR6kkiKbLHL1rbK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlT6lB%2FbtrnJdWDaz7%2FPRxlm7pwR6kkiKbLHL1rbK%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;772&quot; height=&quot;567&quot;/&gt;&lt;/span&gt;&lt;/div&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlPSTA/btrnC3OyYAW/DezEN6WK2C4mQJtLXYPaGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlPSTA/btrnC3OyYAW/DezEN6WK2C4mQJtLXYPaGK/img.png&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;490&quot; style=&quot;width: 48.8581%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlPSTA/btrnC3OyYAW/DezEN6WK2C4mQJtLXYPaGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlPSTA%2FbtrnC3OyYAW%2FDezEN6WK2C4mQJtLXYPaGK%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;484&quot; height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HtzoS/btrnHR0E0tF/Gstk1Liltw8ehYJLo2geLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HtzoS/btrnHR0E0tF/Gstk1Liltw8ehYJLo2geLK/img.png&quot; data-origin-width=&quot;776&quot; data-origin-height=&quot;768&quot; style=&quot;width: 49.9791%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HtzoS/btrnHR0E0tF/Gstk1Liltw8ehYJLo2geLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHtzoS%2FbtrnHR0E0tF%2FGstk1Liltw8ehYJLo2geLK%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;776&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bartwullems.blogspot.com/2020/10/domain-driven-designstructuring-your.html&quot;&gt;Domain Driven Design&amp;ndash;Structuring your applications&lt;/a&gt;, &lt;a href=&quot;https://devblogs.microsoft.com/cesardelatorre/great-diagram-about-our-ddd-nlayered-net-4-0-architecture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Great Diagram about our DDD NLayered .NET 4.0 Architecture&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;자, DDD를 러프하게 정리하자면 이렇습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용/개발자에 따라 도메인과 컨텍스트를 나눈다.&lt;/li&gt;
&lt;li&gt;같은 컨텍스트 내에서는 동일한 언어를 사용한다.&lt;/li&gt;
&lt;li&gt;도메인을 설계할 때는 의존성에 따라 레이어를 나누어라.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 DDD를 이용한 설계를 적용하게 되면 다음과 같이 변화하게 되겠죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;989&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sZfTd/btrnBLGFEkH/IE368KtocoVHLmtiGLKq7k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sZfTd/btrnBLGFEkH/IE368KtocoVHLmtiGLKq7k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sZfTd/btrnBLGFEkH/IE368KtocoVHLmtiGLKq7k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsZfTd%2FbtrnBLGFEkH%2FIE368KtocoVHLmtiGLKq7k%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;700&quot; height=&quot;495&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;989&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;OOP vs DDD [&lt;a href=&quot;https://blog.pragmatists.com/domain-driven-design-vs-anemic-model-how-do-they-differ-ffdee9371a86&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Domain-Driven&amp;nbsp;Design&amp;nbsp;vs.&amp;nbsp;anemic&amp;nbsp;model.&amp;nbsp;How&amp;nbsp;do&amp;nbsp;they&amp;nbsp;differ?&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;DDD의 실제 구현에 있어 도움이 될만한 패러다임이 있다.&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;744&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beqEA6/btrnHRl4cSF/MpaSwOAjKO8dUksfHNOdRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beqEA6/btrnHRl4cSF/MpaSwOAjKO8dUksfHNOdRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beqEA6/btrnHRl4cSF/MpaSwOAjKO8dUksfHNOdRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeqEA6%2FbtrnHRl4cSF%2FMpaSwOAjKO8dUksfHNOdRK%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;744&quot; height=&quot;498&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tecoble.techcourse.co.kr/post/2021-06-25-aop-transaction/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AOP&amp;nbsp;입문자를&amp;nbsp;위한&amp;nbsp;개념&amp;nbsp;이해하기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 AOP는 관심사 분리를 하여 공통되는 기능을 모으고&amp;nbsp;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%98%EC%A1%B4%EC%84%B1_%EC%A3%BC%EC%9E%85&quot;&gt;DI(Dependeny Injection)&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;원글에서 나왔던 Rosch 의&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Prototype_theory&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;프로토타입&amp;nbsp;이론&lt;/a&gt;은 만들어지는 제품 산출물은 어떠한 형태를 갖추어야 하는가에도 적합한 이론이라고 생각한다. [&lt;a href=&quot;https://medium.com/hgmin/poc-prototype-pilot-mvp%EB%9E%80-b659aa8304df&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MVP와 PoC, Prototype, Pilot 차이&lt;/a&gt;, &lt;a href=&quot;https://expertise.jetruby.com/top-5-biggest-challenges-when-building-an-mvp-and-how-to-avoid-them-2969703e5757&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Top&amp;nbsp;5&amp;nbsp;Biggest&amp;nbsp;Challenges&amp;nbsp;when&amp;nbsp;Building&amp;nbsp;an&amp;nbsp;MVP&amp;nbsp;and&amp;nbsp;how&amp;nbsp;to&amp;nbsp;Avoid&amp;nbsp;Them&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vQjvL/btrnLIIUDGl/JfwXvNRKWAxbwDNdpzSPR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vQjvL/btrnLIIUDGl/JfwXvNRKWAxbwDNdpzSPR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vQjvL/btrnLIIUDGl/JfwXvNRKWAxbwDNdpzSPR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvQjvL%2FbtrnLIIUDGl%2FJfwXvNRKWAxbwDNdpzSPR0%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;600&quot; height=&quot;400&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.codementor.io/blog/MVP-product-market-fit-2lvrzn68b2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Proof&amp;nbsp;of&amp;nbsp;Concept&amp;nbsp;vs.&amp;nbsp;Prototype&amp;nbsp;vs.&amp;nbsp;MVP:&amp;nbsp;Journey&amp;nbsp;to&amp;nbsp;Product&amp;nbsp;Market&amp;nbsp;Fit&lt;/a&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;b&gt;중요한 기능&lt;/b&gt;들이 포함되어 있어야 함&lt;/li&gt;
&lt;li&gt;MVP: 최소 실행제품으로 생존하기 위한 최소한의 노력과 완성도가 있어야 함&lt;/li&gt;
&lt;/ul&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RdqkD/btrnE91QYHQ/RQH5x0kDPr7sq53B8ao170/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RdqkD/btrnE91QYHQ/RQH5x0kDPr7sq53B8ao170/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RdqkD/btrnE91QYHQ/RQH5x0kDPr7sq53B8ao170/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRdqkD%2FbtrnE91QYHQ%2FRQH5x0kDPr7sq53B8ao170%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;700&quot; height=&quot;645&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://laurabecker.gitlab.io/classes/as/08-semantics.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Class&amp;nbsp;8:&amp;nbsp;Semantics&amp;nbsp;&amp;amp;&amp;nbsp;Prototype&amp;nbsp;theory&lt;/a&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;/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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서로 생각하는 프로토타입이나 MVP가 다르다면 유사도가 제대로 측정되지 않을 것이기 때문이다.&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;800&quot; data-origin-height=&quot;566&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s6aRA/btrnLH4kxKu/tPdbKNEqkiBNVKq54EccAk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s6aRA/btrnLH4kxKu/tPdbKNEqkiBNVKq54EccAk/img.jpg&quot; data-alt=&quot;사용가능하고, 최종적인 형태와 유사하게 만들어져야 한다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s6aRA/btrnLH4kxKu/tPdbKNEqkiBNVKq54EccAk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs6aRA%2FbtrnLH4kxKu%2FtPdbKNEqkiBNVKq54EccAk%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;700&quot; height=&quot;496&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;566&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;사용 가능하지 않다면 MVP에서 핵심인 &quot;&lt;b&gt;생존가능&lt;/b&gt;&quot; 자체가 불가하며, 최종적인 형태와 다르다면 &quot;&lt;b&gt;설계변경&lt;/b&gt;&quot; 비용이 클 것이기 때문이다.&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;/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;a href=&quot;https://sciencestudies.science.blog/2021/04/11/%ED%98%95%EC%9D%B4%EC%83%81%ED%95%99-%EB%B3%B4%ED%8E%B8%EC%9E%90-%EC%8B%A4%EC%9E%AC%EB%A1%A0%EC%9D%98-%EC%A1%B4%EC%9E%AC%EB%A1%A0/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;보편자&amp;nbsp;실재론의&amp;nbsp;존재론&lt;/a&gt;, &lt;a href=&quot;http://기초지식칼럼.com/read/read_view.php?idx=101&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;아리스토텔레스의 존재론&lt;/a&gt;, &lt;a href=&quot;https://s-space.snu.ac.kr/bitstream/10371/75965/1/03.%20%EA%B6%8C%ED%98%81%EC%84%B1.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;아리스토텔레스의&amp;nbsp;보편자&amp;nbsp;이해와&amp;nbsp;개별주의&amp;nbsp;실체관&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;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;여기 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;그렇다면 개별자와 보편자는 어떤 관계일까?&lt;/p&gt;
&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;letter-spacing: 0px;&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;수라는 보편적인 개념은 단순히 지운다고 사라지는 것일까? 사라지는게 아니라면 절대적으로 존재하는 걸까, 아니면 실재 값들이 있기에 존재하는 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(보통 존재하지 않는 수라고 오해하는 허수도 $i^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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1219&quot; data-origin-height=&quot;1600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AzZiA/btrnC2h0p4Q/tJRnPWqkEQG97D4TPfICk1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AzZiA/btrnC2h0p4Q/tJRnPWqkEQG97D4TPfICk1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AzZiA/btrnC2h0p4Q/tJRnPWqkEQG97D4TPfICk1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAzZiA%2FbtrnC2h0p4Q%2FtJRnPWqkEQG97D4TPfICk1%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;1219&quot; height=&quot;1600&quot; data-origin-width=&quot;1219&quot; data-origin-height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.britannica.com/story/plato-and-aristotle-how-do-they-differ&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Plato&amp;nbsp;and&amp;nbsp;Aristotle:&amp;nbsp;How&amp;nbsp;Do&amp;nbsp;They&amp;nbsp;Differ?&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;li&gt;개별자는 결여는 되었지만 닮았고, 생성/소멸이 일어남&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;/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;a href=&quot;https://ko.wikipedia.org/wiki/%EC%A2%85%EC%B0%A8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;유종관계&lt;/a&gt;(상하/포함관계)에서 나타나는 표상임 [보편자가 제1 실체라면 개별적 차이성이 없어지며 모순]&lt;/li&gt;
&lt;/ul&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;800&quot; data-origin-height=&quot;566&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw0NeT/btrnBy9sh2b/IYAVYkbkqCuX0K1V5KKuEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw0NeT/btrnBy9sh2b/IYAVYkbkqCuX0K1V5KKuEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw0NeT/btrnBy9sh2b/IYAVYkbkqCuX0K1V5KKuEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcw0NeT%2FbtrnBy9sh2b%2FIYAVYkbkqCuX0K1V5KKuEk%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;800&quot; height=&quot;566&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;566&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Aristotle%27s_theory_of_universals&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Aristotle's&amp;nbsp;theory&amp;nbsp;of&amp;nbsp;universals&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;그렇다 클래스(이데아)와 프로토타입(실체론)이다.&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;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;li&gt;객체는 결여되었지만 닳았고, 생성/소멸이 일어남&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;/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;&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;a href=&quot;https://ko.m.wikipedia.org/wiki/%EB%B3%B4%ED%8E%B8_%EB%85%BC%EC%9F%81&quot;&gt;보편 논쟁&lt;/a&gt;, &lt;a href=&quot;https://brunch.co.kr/@donghee35/51&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;/p&gt;
&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;s&gt;피곤해서 빨리 끝&lt;/s&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;/p&gt;
&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;비슷한 이유에서인지 다른 프로토타입 기반 언어들도 self를 쓰면 다이나믹 스코프가 기본인 모양이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1639358254692&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// io
someValue := &quot;hello&quot;
outerFunc := method(self someValue)
obj := Object clone do (
  someValue ::= &quot;world&quot;
  outerFunc ::= outerFunc
)

outerFunc     // hello
obj outerFunc // world&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_1639358768794&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Perl
$someValue = &quot;hello&quot;;
sub outerFunc {
  return $someValue;
}
sub dynamicScope {
  local $someValue = &quot;world&quot;;
  return outerFunc();
}

print outerFunc();    # hello
print dynamicScope(); # world&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;개인적으로는 Lexical scope가 Dynamic scope보다 이해하기 쉽고, 버그도 적을거라 생각하여 선호한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 화살표 함수나 io의 block 등을 생각하면 이제 스코프는 선택문제 아닐까 ㅎㅎ&lt;/p&gt;
&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;2021 출판사 대표들이 뽑은 &lt;a href=&quot;https://www.khan.co.kr/culture/culture-general/article/202112161835001&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;올해의 책&lt;/a&gt;, 소쉬르의 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%BC%EB%B0%98%EC%96%B8%EC%96%B4%ED%95%99_%EA%B0%95%EC%9D%98&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;a href=&quot;https://nomadiaphilonote.tistory.com/32&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;객체지향 철학&lt;/a&gt;도 한번쯤 알아보면 좋을것 같구.&lt;/p&gt;</description>
      <category>프로그래밍/설계</category>
      <category>객체지향</category>
      <category>철학</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/86</guid>
      <comments>https://black7375.tistory.com/86#entry86comment</comments>
      <pubDate>Tue, 14 Dec 2021 00:31:21 +0900</pubDate>
    </item>
    <item>
      <title>Lepton 2.0  정보 및 이후계획</title>
      <link>https://black7375.tistory.com/84</link>
      <description>&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2.0 정보&lt;/b&gt;&lt;/h3&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;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;아마 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;맥은 Native, None Native 둘 다 대응했어야 해서 좀 귀찮았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맥이 고장나 있는 상태이기 때문에 원래라면 테스트가 불가했겠지만 &lt;a href=&quot;https://github.com/sickcodes/Docker-OSX&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Docker OSX&lt;/a&gt; 덕에 가능했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KVM과 Docker OSX 개발자들 감사합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vewAF/btq8rXiEffT/fzghwMsYMK7KQvU5wQvdak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vewAF/btq8rXiEffT/fzghwMsYMK7KQvU5wQvdak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vewAF/btq8rXiEffT/fzghwMsYMK7KQvU5wQvdak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvewAF%2Fbtq8rXiEffT%2FfzghwMsYMK7KQvU5wQvdak%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&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://github.com/microsoft/fluentui-system-icons&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fluent UI System Icons&lt;/a&gt;로 때웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고퀄 아이콘들을 MIT 라이센스로 풀다니 고맙다.&lt;/p&gt;
&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;1280&quot; data-origin-height=&quot;1766&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bO4qEz/btq8zy2c6x9/iPzKTmenAnIb9eVAIEOlu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bO4qEz/btq8zy2c6x9/iPzKTmenAnIb9eVAIEOlu1/img.png&quot; data-alt=&quot;넘 끔직..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bO4qEz/btq8zy2c6x9/iPzKTmenAnIb9eVAIEOlu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbO4qEz%2Fbtq8zy2c6x9%2FiPzKTmenAnIb9eVAIEOlu1%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1766&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 일러스트 복원&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;귀여운 일러스트들이 브라우저를 조금 더 친근하게 만들어준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coBNNe/btq8v8Dzz90/sInKw7JLeFAuePzzmMqoi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coBNNe/btq8v8Dzz90/sInKw7JLeFAuePzzmMqoi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coBNNe/btq8v8Dzz90/sInKw7JLeFAuePzzmMqoi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoBNNe%2Fbtq8v8Dzz90%2FsInKw7JLeFAuePzzmMqoi1%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&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;3. 윈도우 7 및 테마 호환성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우7에서 다크 테마가 이상하게 적용된다는 이슈가 있었다.&amp;nbsp;&lt;a href=&quot;https://github.com/black7375/Firefox-UI-Fix/issues/53&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#53&lt;/a&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;790&quot; data-origin-height=&quot;190&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tdbgC/btq8vfjbzcO/GSQBNWeMc4ZZLPzWPZR5SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tdbgC/btq8vfjbzcO/GSQBNWeMc4ZZLPzWPZR5SK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tdbgC/btq8vfjbzcO/GSQBNWeMc4ZZLPzWPZR5SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtdbgC%2Fbtq8vfjbzcO%2FGSQBNWeMc4ZZLPzWPZR5SK%2Fimg.png&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;190&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;다음과 같은 목표를 가지고 만들어졌다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/behzef/btq8v8p1Mmz/1DUyhw8zaNNXC8uwyvek00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/behzef/btq8v8p1Mmz/1DUyhw8zaNNXC8uwyvek00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/behzef/btq8v8p1Mmz/1DUyhw8zaNNXC8uwyvek00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbehzef%2Fbtq8v8p1Mmz%2F1DUyhw8zaNNXC8uwyvek00%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 탭 상태&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/77TDw/btq8vRIQEnZ/WsQvd65FDbkrfjGKbhcqY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/77TDw/btq8vRIQEnZ/WsQvd65FDbkrfjGKbhcqY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/77TDw/btq8vRIQEnZ/WsQvd65FDbkrfjGKbhcqY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F77TDw%2Fbtq8vRIQEnZ%2FWsQvd65FDbkrfjGKbhcqY1%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&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;저번에 상당히 신경써서 만들었지만&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;새 탭 버튼&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 2가지 방향으로 개선을 했는데&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;Photon 스타일: 버튼처럼 작게.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새탭 버튼은 말그대로 &quot;새탭&quot;을 생성시키는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 잠재적인 탭(Potential tab)이라 취급할 수 있으며 탭모양의 연장선 상으로 만들어도 어울린다.&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;718&quot; data-origin-height=&quot;117&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cx9bxX/btq8ysCeUuO/paPZznNKH9fbCwQ70qZU8K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cx9bxX/btq8ysCeUuO/paPZznNKH9fbCwQ70qZU8K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cx9bxX/btq8ysCeUuO/paPZznNKH9fbCwQ70qZU8K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cx9bxX/btq8ysCeUuO/paPZznNKH9fbCwQ70qZU8K/img.gif&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;117&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;반면 Photon Style은 버튼의 크기를 상단 컨텍스트 라인까지 맞추어 확실히 버튼 느낌을 주도록 했다.&lt;/p&gt;
&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;파이어폭스는 탭을 잘 보여주기 위한 3단계가 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;공간이 충분할 때: 닫기버튼을 보여줌&lt;/li&gt;
&lt;li&gt;첫번째로 끝에 도달했을 때: 탭 크기가 줄어들며 닫기버튼은 선택이 되었을때만 노출&lt;/li&gt;
&lt;li&gt;최소 탭 크기까지 줄었을 때: 오버스크롤 효과&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;닫기버튼을 감출때의 장점은 탭의 타이틀을 조금이라도 더 보여준다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 2~3단계에서 닫기버튼을 감추는 것은 좋은 UX라 생각할 수있다.&lt;/p&gt;
&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. 인스톨 스크립트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 실험적이고, 업데이트 UX도 부족하지만 인스톨 스크립트가 만들어졌다!!&lt;/p&gt;
&lt;pre id=&quot;code_1625108216901&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/black7375/Firefox-UI-Fix/master/install.sh)&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&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;Lepton 프로젝트의 전반적인 계획&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;시장의 파이를 충분히 확보해 성장가능성이 낮아진다면,&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가지 이정표가 있다.&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;Stage1 - Project Neutrino&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 단계는 정말 가볍고 상호작용도 적은 중성미자(Neutrino)이다.&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;b&gt;목표&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전반적인 디자인을 확립하며 Proton에서 생겨난 각종 불만들을 해결하여, 사용자가 브라우저와 상호작용 시 마찰이 없도록 만들어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 브라우저에서 기대하거나 그보다 나은 자연스러운 UI/UX를 구축하는 CSS 세팅의 결과물.&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;b&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;&lt;b&gt;색&lt;/b&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;윈도우/GTK 기본 테마 지원&lt;/li&gt;
&lt;li&gt;윈도우7 호환성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;아이콘&lt;/b&gt;: 패널, 콘텍스트 메뉴, 글로벌 메뉴등에 세심하고 꼼꼼하게 적용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포인터&lt;/b&gt;: 각종 메뉴에 포인터를 올렸을때 상황에 맞도록 표시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간격(패딩)&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;탭&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;홈&lt;/b&gt;: 아이콘 크기, 포커싱시 컬러, 검색 시 위치 등&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에러 페이지&lt;/b&gt;: 일러스트를 복원하여 인간적으로 만들기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스크롤링&lt;/b&gt;: 부드러운 스크롤의 값 조정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인스톨러&lt;/b&gt;: Bash와 Powershell로 만들어진 인스톨러로 쉬운 설치와 업데이트 지원&lt;/li&gt;
&lt;/ul&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;Stage2 - Project Muon&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째는 중성미자는 물론 전자보다 훨씬 질량이 큰 뮤 입자(Muon)에서 따왔으며, 파이어폭스 자체의 기능을 넘어 Lepton 고유의 UI/UX를 만들어가는 과정.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JS를 도입해 동적인 기능들이 들어가며, CSS나 일반 애드온으로는 할 수 없는 UI/UX, 기능들을 구현한다.&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;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;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;설정 UI를 제공한 후에는 TS 및 Noder기반의 완전한 모던 웹 개발 환경을 구축한다.&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;b&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;&lt;b&gt;완전한 테마&lt;/b&gt;: CSS만으로는 Shadow Dom의 한계로 완전한 색 커스텀이 불가능 했던 점을 극복&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쉬우면서 방대한 UI 커스텀&lt;/b&gt;: 사용자가 원하는 UI를 간단하게 선택할 수 있도록 설정 UI를 제작&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부드러운 애니메이션&lt;/b&gt;: 북마크 애니메이션 복원, 플루언트 효과, 웨일 사운드 웨이브등을 도입&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴포넌트&lt;/b&gt;: 페이지액션 복원, 상태표시줄, 사이드바, 수직 탭등의 기타 UI 요소들&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제어&lt;/b&gt;: 블록 팝업 메뉴, 단축키 조정, 마우스 제스쳐, 기록 트리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;설정&lt;/b&gt;: TOC 표시로 빠른 전환, Lepton UI 조정, 고급모드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;강화/추가&lt;/b&gt;: 이미지 보기 및 수정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;통합&lt;/b&gt;: &lt;a href=&quot;https://github.com/filips123/FirefoxPWA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FirefoxPWA&lt;/a&gt;, &lt;a href=&quot;https://github.com/FilipePS/Traduzir-paginas-web&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Translate Web Pages&lt;/a&gt;등과 완전한 통합&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기타 기능&lt;/b&gt;: 절전모드, 스피드 리더, 탭 미리보기, 탭그룹, 탭스택, 모바일 탭등&lt;/li&gt;
&lt;/ul&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;Stage3 - Project Tau&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 세번째는 Muon보다도 10배는 무거운 Tau로서 더 이상 가벼운 테마 레이어로 보기 힘든 파워유저들이나 특수한 유저들을 위한 기능들이 추가된다.&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;b&gt;목표&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stage2를 거쳐 일반적인 사용자의 요구는 거의 다 맞추었다고 할 수 있다.&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;b&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;&lt;b&gt;각종 전용 프로그램&lt;/b&gt;: Epub 뷰어, 강력한 다운로드 관리자, 내장 비디오 플레이어 대체&lt;/li&gt;
&lt;li&gt;&lt;b&gt;터치모드&lt;/b&gt;: 터치에 적합하게 이벤트 전달, 커서 변형, 각종 UI 수정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Vim 키맵 및 키보드 브라우징&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;미니버퍼&lt;/b&gt;: Fuzzy 검색을 하여 Heading, 탭, 기록, 명령어들을 빠르게 찾고 전환/실행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타일링&lt;/b&gt;: 타일링으로 같은 페이지, 연결된 탭, 다른 탭 등을 쉽게 탐색&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스마트 북마크 마법사&lt;/b&gt;: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Tech/Places/Places_query_URIs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;북마크 쿼리&lt;/a&gt;를 쉽게 만들 수 있는 가이드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;매크로 지원&lt;/b&gt;: 각종 반복작업을 간단하게&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커스텀 설정 코드 지원&lt;/b&gt;: userChorme.js란 파일이름으로 사용자 커스텀 코드를 지원하려고 생각중이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT/UX</category>
      <category>firefox</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/84</guid>
      <comments>https://black7375.tistory.com/84#entry84comment</comments>
      <pubDate>Thu, 1 Jul 2021 00:50:58 +0900</pubDate>
    </item>
    <item>
      <title>러스트 찍먹 후 느낀점?</title>
      <link>https://black7375.tistory.com/85</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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;975&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Prkeo/btrLgZbL2Sp/sFPyy2C9WkCpJPNv0y0MQ1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Prkeo/btrLgZbL2Sp/sFPyy2C9WkCpJPNv0y0MQ1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Prkeo/btrLgZbL2Sp/sFPyy2C9WkCpJPNv0y0MQ1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPrkeo%2FbtrLgZbL2Sp%2FsFPyy2C9WkCpJPNv0y0MQ1%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;975&quot; height=&quot;975&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;975&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;귀여운 &amp;gt;.&amp;lt; &lt;a href=&quot;https://rustacean.net/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ferris&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;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 툴체인!!&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;a href=&quot;https://doc.rust-lang.org/cargo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cargo&lt;/a&gt;, &lt;a href=&quot;https://rustup.rs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;rustup&lt;/a&gt;, &lt;a href=&quot;https://rust-lang.github.io/rustfmt/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rustfmt&lt;/a&gt;, &lt;a href=&quot;https://doc.rust-lang.org/nightly/clippy/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Clippy&lt;/a&gt;, &lt;a href=&quot;https://rust-analyzer.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rust Analyzer&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://www.gnu.org/software/make/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Make&lt;/a&gt;!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느정도 규모가 있는 프로젝트는 크로스 플랫폼 대응이나 각종 설정을 적용하기 위해 Meta Make 시스템을 사용하는게&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://www.gnu.org/software/automake/faq/autotools-faq.html&quot;&gt;GNU Autotools&lt;/a&gt;(&lt;a href=&quot;https://www.gnu.org/software/automake/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Autoconf&lt;/a&gt;, &lt;a href=&quot;https://www.gnu.org/software/automake/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Automake&lt;/a&gt;, &lt;a href=&quot;https://www.gnu.org/software/libtool/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Libtools&lt;/a&gt;). [&lt;a href=&quot;https://opensource.com/article/19/7/introduction-gnu-autotools&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introduction&amp;nbsp;to&amp;nbsp;GNU&amp;nbsp;Autotools&lt;/a&gt;, &lt;a href=&quot;https://devmanual.gentoo.org/general-concepts/autotools/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Basics&amp;nbsp;of&amp;nbsp;Autotools&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.gnu.org/software/m4/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;M4&lt;/a&gt;와 Make 두개의 작은 언어를 더 알아야만 한다..ㅋㅋㅋ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mwQzV/btrIc8O5GfO/5aXfAK5sZSsdW4KM51HXU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mwQzV/btrIc8O5GfO/5aXfAK5sZSsdW4KM51HXU1/img.png&quot; data-alt=&quot;각 파일을 열어볼 생각만 해도 어질어질하다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mwQzV/btrIc8O5GfO/5aXfAK5sZSsdW4KM51HXU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmwQzV%2FbtrIc8O5GfO%2F5aXfAK5sZSsdW4KM51HXU1%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;510&quot; height=&quot;360&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;360&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;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://cmake.org/&quot;&gt;CMake&lt;/a&gt;가 나왔지만 역시 그리 쉽지만은 않다ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에도 &lt;a href=&quot;https://gn.googlesource.com/gn/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GN&lt;/a&gt;, &lt;a href=&quot;https://mesonbuild.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Meson&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;a href=&quot;https://vcpkg.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;vcpkg&lt;/a&gt;나 &lt;a href=&quot;https://conan.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;conan&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;a href=&quot;https://doc.rust-lang.org/cargo/reference/workspaces.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모노레포&lt;/a&gt;나 &lt;a href=&quot;https://doc.rust-lang.org/cargo/reference/features.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;조건부 컴파일/ 선택적 종속성&lt;/a&gt;은 물론&amp;nbsp;&lt;a href=&quot;https://doc.rust-lang.org/cargo/commands/cargo-test.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;테스트&lt;/a&gt;, &lt;a href=&quot;https://doc.rust-lang.org/cargo/commands/cargo-bench.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;벤치마크&lt;/a&gt;, &lt;a href=&quot;https://doc.rust-lang.org/cargo/commands/cargo-doc.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;문서화&lt;/a&gt; 등이 필요한데, Cargo는 모두 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 그냥 지원하는게 아니라 소스코드 파일 안에서 &lt;a href=&quot;https://doc.rust-lang.org/book/ch11-03-test-organization.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;테스트&lt;/a&gt;, &lt;a href=&quot;https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html&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;/p&gt;
&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/rust-lang/rustup&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;rustup&lt;/a&gt;, 포매팅의 &lt;a href=&quot;https://github.com/rust-lang/rustfmt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rustfmt&lt;/a&gt;, 린트의 &lt;a href=&quot;https://github.com/rust-lang/rust-clippy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;clippy&lt;/a&gt;, IDE 지원용인 &lt;a href=&quot;https://github.com/rust-lang/rust-analyzer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Analyzer&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;엉망인 파이썬, 난잡한 자바스크립트의 툴들과 비교해도 확실한 우위라 할 수 있다.&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;2. 메모리 안전&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 관련 오류는 성능에 앞서 보안에 치명적이다. [&lt;a href=&quot;https://www.zdnet.com/article/microsoft-70-percent-of-all-security-bugs-are-memory-safety-issues/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Microsoft:&amp;nbsp;70&amp;nbsp;percent&amp;nbsp;of&amp;nbsp;all&amp;nbsp;security&amp;nbsp;bugs&amp;nbsp;are&amp;nbsp;memory&amp;nbsp;safety&amp;nbsp;issues&lt;/a&gt;, &lt;a href=&quot;https://www.zdnet.com/article/chrome-70-of-all-security-bugs-are-memory-safety-issues/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Chrome:&amp;nbsp;70%&amp;nbsp;of&amp;nbsp;all&amp;nbsp;security&amp;nbsp;bugs&amp;nbsp;are&amp;nbsp;memory&amp;nbsp;safety&amp;nbsp;issues&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 GC(Garbage Collection) 언어는 일반적으로 메모리 안전하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 GC를 위한 런타임이 필요하거나 Stop the world가 발생하는 등 성능 오버헤드가 존재하기 때문에 성능을 중시하면 메모리를 직접 할당/해제하는 언어들을 사용할 수 밖에 없다.&lt;/p&gt;
&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://valgrind.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Valgrind&lt;/a&gt;로 메모리 누수를 잡거나, Go의 &lt;a href=&quot;https://go.dev/doc/effective_go#defer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;defer&lt;/a&gt;처럼 실수를 줄여주기 위한 문법이 있을수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swift처럼 &lt;a href=&quot;https://jusung.gitbook.io/the-swift-language-guide/language-guide/23-automatic-reference-counting&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ARC(Automatic Reference Counting)&lt;/a&gt;로 메모리를 관리하기도 하지만 &lt;a href=&quot;https://jusung.gitbook.io/the-swift-language-guide/language-guide/24-memory-safety&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;게다가 ARC의 경우 할당/해제 시 참조 카운터 또한 증감하기 때문에 오버헤드가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C/C++처럼 Zero Cost를 지향하는 경우는 사용하기 힘들다는 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;D언어가 &lt;a href=&quot;https://dlang.org/spec/memory-safe-d.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;메모리 안전한 스펙&lt;/a&gt;을 어느정도 정해 놓았기 때문에 어느정도 메모리 안전함을 보장한다. [&lt;a href=&quot;https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1000.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DIP1000 Scoped Pointers&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 D언어는 기본적으로 GC를 사용하는 언어라 Zero overhead를 달성했다기에 애매한 점이 있는데다 No GC일때 러스트 수준으로 잡아주지는 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;러스트는 소유권과 차용 시스템으로 Zero overhead &lt;a href=&quot;https://people.mpi-sws.org/~dreyer/papers/rustbelt/paper.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;메모리 안전&lt;/a&gt;, 데이터 경합이 없는 동시성을 달성한다. [&lt;a href=&quot;https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fearless&amp;nbsp;Concurrency&amp;nbsp;with&amp;nbsp;Rust&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;Encore나 Pony가 러스트와 비슷하게 메모리 안전을 보장한다. [&lt;a href=&quot;https://uu.diva-portal.org/smash/get/diva2:1363822/FULLTEXT01.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Comparison&amp;nbsp;of&amp;nbsp;the&amp;nbsp;Capability&amp;nbsp;Systems&amp;nbsp;of&amp;nbsp;Encore,&amp;nbsp;Pony&amp;nbsp;and&amp;nbsp;Rust&lt;/a&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;a href=&quot;https://stw.gitbooks.io/the-encore-programming-language/content/kappa.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Encore - Capabilities&amp;nbsp;and&amp;nbsp;Modes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tutorial.ponylang.io/reference-capabilities/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pony - Reference&amp;nbsp;Capabilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rust - Owernership&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;권한을 사용하는 Pony의 아이디어가 꽤 재미있다. [&lt;a href=&quot;https://zartstrom.github.io/pony/2016/08/28/reference-capabilities-in-pony.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reference&amp;nbsp;Capabilites&amp;nbsp;in&amp;nbsp;Pony&amp;nbsp;for&amp;nbsp;everybody&lt;/a&gt;, &lt;a href=&quot;https://bluishcoder.co.nz/2017/07/31/reference_capabilities_consume_recover_in_pony.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reference&amp;nbsp;Capabilities,&amp;nbsp;Consume&amp;nbsp;and&amp;nbsp;Recover&amp;nbsp;in&amp;nbsp;Pony&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마치 리눅스 chmod 파일 권한을 보는 느낌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0yFMA/btrJA5iBhwL/9689kcIbnGzdsgNlGsVJc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0yFMA/btrJA5iBhwL/9689kcIbnGzdsgNlGsVJc0/img.png&quot; data-origin-width=&quot;443&quot; data-origin-height=&quot;194&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.0276%; margin-right: 10px;&quot; data-widthpercent=&quot;53.65&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0yFMA/btrJA5iBhwL/9689kcIbnGzdsgNlGsVJc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0yFMA%2FbtrJA5iBhwL%2F9689kcIbnGzdsgNlGsVJc0%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;443&quot; height=&quot;194&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br2kzy/btrJwudFmIQ/QVbLKijflwNpKi90KaJwGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br2kzy/btrJwudFmIQ/QVbLKijflwNpKi90KaJwGK/img.png&quot; data-origin-width=&quot;361&quot; data-origin-height=&quot;183&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.8096%;&quot; data-widthpercent=&quot;46.35&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br2kzy/btrJwudFmIQ/QVbLKijflwNpKi90KaJwGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr2kzy%2FbtrJwudFmIQ%2FQVbLKijflwNpKi90KaJwGK%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;183&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cr7M9L/btrJwq2ZQ1N/1xVZzm4MjkKgzZKtR3j6k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cr7M9L/btrJwq2ZQ1N/1xVZzm4MjkKgzZKtR3j6k1/img.png&quot; data-origin-width=&quot;403&quot; data-origin-height=&quot;113&quot; data-is-animation=&quot;false&quot; style=&quot;width: 41.7371%; margin-right: 10px;&quot; data-widthpercent=&quot;42.23&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cr7M9L/btrJwq2ZQ1N/1xVZzm4MjkKgzZKtR3j6k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcr7M9L%2FbtrJwq2ZQ1N%2F1xVZzm4MjkKgzZKtR3j6k1%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;403&quot; height=&quot;113&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRafN0/btrJABPTPle/WZY0k6NSjfJpxE8WKTUUK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRafN0/btrJABPTPle/WZY0k6NSjfJpxE8WKTUUK1/img.png&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;91&quot; data-is-animation=&quot;false&quot; style=&quot;width: 57.1001%;&quot; data-widthpercent=&quot;57.77&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRafN0/btrJABPTPle/WZY0k6NSjfJpxE8WKTUUK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRafN0%2FbtrJABPTPle%2FWZY0k6NSjfJpxE8WKTUUK1%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;444&quot; height=&quot;91&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U14CO/btrJA45abPe/tXZ5wPgdU9Ygf0V2yJKr5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U14CO/btrJA45abPe/tXZ5wPgdU9Ygf0V2yJKr5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U14CO/btrJA45abPe/tXZ5wPgdU9Ygf0V2yJKr5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU14CO%2FbtrJA45abPe%2FtXZ5wPgdU9Ygf0V2yJKr5k%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;673&quot; height=&quot;313&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;313&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;RC의 경우, 요즘 재밌는 기술이 몇가지 나오는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://vale.dev/&quot;&gt;Vale&lt;/a&gt;의 레퍼런스 카운팅을 대체하기 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://verdagon.dev/blog/generational-references&quot;&gt;세대 참조&lt;/a&gt;가 특이하다. 러스트에는&amp;nbsp;&lt;a href=&quot;https://github.com/Kile-Asmussen/genref&quot;&gt;genref&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라이브러리가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koka-lang.github.io/&quot;&gt;Koka&lt;/a&gt;도 레퍼런스 카운팅의 성능을 향상하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.microsoft.com/en-us/research/uploads/prod/2020/11/perceus-tr-v1.pdf&quot;&gt;Perceus&lt;/a&gt;라고 적극적인 재사용을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nim-lang.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nim&lt;/a&gt;은 &lt;a href=&quot;https://nim-lang.org/araq/ownedrefs.html&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;h4 data-ke-size=&quot;size20&quot;&gt;3. 성능&lt;/h4&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;그 중 많은 것은 Class 기반의 OOP 때문이며, 각 명령어가 5~8개의 어셈블리로 변환되던 C와 다르게 생성/소멸자가 있어 예상이 어렵고 클래스의 가상함수 등은 인라인을 어렵게 만들기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://en.cppreference.com/w/cpp/language/constructor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;멤버 초기화 리스트&lt;/a&gt;를 사용해야 함 [&lt;a href=&quot;https://pvs-studio.com/en/docs/warnings/v818/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PVS Studio&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.cppreference.com/w/cpp/language/copy_constructor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;복사 생성자&lt;/a&gt;를 정의하여 RVO, NRVO가 가능하도록 해야 함 [&lt;a href=&quot;https://en.cppreference.com/w/cpp/language/copy_elision&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Copy elision&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.cppreference.com/w/cpp/language/ebo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;EBO&lt;/a&gt;를 사용해 빈 클래스의 크기를 1바이트만 사용하게 만들 수 있음&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.cppreference.com/w/cpp/language/crtp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CRTP&lt;/a&gt;를 사용해 정적 다형성을 달성할 수 있다.&lt;/li&gt;
&lt;li&gt;가상 메소드의 경우, 컴파일 타임에 정보를 알게 하면 인라인이 가능하며, final 키워드를 사용할 수 있다면 쓰는게 좋다.&amp;nbsp; [&lt;a href=&quot;https://www.geeksforgeeks.org/inline-virtual-function/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Can&amp;nbsp;Virtual&amp;nbsp;Functions&amp;nbsp;be&amp;nbsp;Inlined&amp;nbsp;in&amp;nbsp;C++?&lt;/a&gt;, &lt;a href=&quot;https://devblogs.microsoft.com/cppblog/the-performance-benefits-of-final-classes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Performance&amp;nbsp;Benefits&amp;nbsp;of&amp;nbsp;Final&amp;nbsp;Classes&lt;/a&gt;]&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RVO를 지원하는걸로 알려져 있으며(&lt;a href=&quot;https://web.archive.org/web/20141225073722/https://doc.rust-lang.org/guide-pointers.html#returning-pointers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Returning pointers&lt;/a&gt;), EBO도 달성하기가 보다 수월하다 (&lt;a href=&quot;https://docs.rust-embedded.org/book/static-guarantees/zero-cost-abstractions.html&quot;&gt;Zero sized types&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;상속, virtual이 없는 러스트의 특성상 성능을 예측하기 쉽다. [&lt;a href=&quot;https://blog.rust-lang.org/2015/05/11/traits.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Abstraction&amp;nbsp;without&amp;nbsp;overhead:&amp;nbsp;traits&amp;nbsp;in&amp;nbsp;Rust&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Try-Catch 또한 익셉션이 발생할때 느려지기로 유명한데 &lt;a href=&quot;https://rinthel.github.io/rust-lang-book-ko/ch09-02-recoverable-errors-with-result.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Result 타입&lt;/a&gt;을 사용하면 문제가 없을 뿐만 아니라 같은 컨텍스트에서 처리할 수 있다는 장점이 있다. [&lt;a href=&quot;https://yesarang.tistory.com/371&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;C++&amp;nbsp;이야기&amp;nbsp;서른두번째:&amp;nbsp;예외가&amp;nbsp;성능에&amp;nbsp;미치는&amp;nbsp;영향&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=_Ivd3qzgT7U&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CppCon&amp;nbsp;2017:&amp;nbsp;Dave&amp;nbsp;Watson&amp;nbsp;&amp;ldquo;C++&amp;nbsp;Exceptions&amp;nbsp;and&amp;nbsp;Stack&amp;nbsp;Unwinding&amp;rdquo;&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;극도로 최적화된 반복자를 사용하여 &lt;a href=&quot;https://rinthel.github.io/rust-lang-book-ko/ch13-04-performance.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;일반 반복문보다 빠르기도 하다&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;constexpr 대신 &lt;a href=&quot;https://doc.rust-lang.org/reference/const_eval.html#const-context&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;const fn, const generics&lt;/a&gt;를 사용&lt;/li&gt;
&lt;li&gt;rvalue, std::move는 알 필요가 없다!! [&lt;a href=&quot;https://www.thecodedmessage.com/posts/cpp-move/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;C++&amp;nbsp;Move&amp;nbsp;Semantics&amp;nbsp;Considered&amp;nbsp;Harmful&amp;nbsp;(Rust&amp;nbsp;is&amp;nbsp;better)&lt;/a&gt;]&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;라이브러리 면에서도 흥미로운데, C++의 STL은 논쟁의 대상이었다.&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;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=11094436&quot;&gt;pcwalton의 댓글&lt;/a&gt;에 따르면 &lt;a href=&quot;https://github.com/electronicarts/EASTL&quot;&gt;EASTL&lt;/a&gt;(&lt;a href=&quot;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;문서&lt;/a&gt;)을 참고하여 &lt;a href=&quot;https://rust-lang.github.io/rfcs/1398-kinds-of-allocators.html&quot;&gt;allocator_api&lt;/a&gt;를 만들었다고 알려져 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;796&quot; data-origin-height=&quot;109&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fn6Nt/btrK3XRkRhY/YzOxCLvwsQ2vXIYIezQjfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fn6Nt/btrK3XRkRhY/YzOxCLvwsQ2vXIYIezQjfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fn6Nt/btrK3XRkRhY/YzOxCLvwsQ2vXIYIezQjfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFn6Nt%2FbtrK3XRkRhY%2FYzOxCLvwsQ2vXIYIezQjfk%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;796&quot; height=&quot;109&quot; data-origin-width=&quot;796&quot; data-origin-height=&quot;109&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://github.com/rust-lang/regex/blob/master/PERFORMANCE.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;최악의 경우 선형 시간&lt;/a&gt;이며, PCRE2 JIT과 비교해도 느리지 않다. [&lt;a href=&quot;https://rust-leipzig.github.io/regex/2017/03/28/comparison-of-regex-engines/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;comparison&amp;nbsp;of&amp;nbsp;regex&amp;nbsp;engines&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;그럼 보다 전통적인 C와 비교하면 어떨까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://kornel.ski/rust-c-speed&quot;&gt;Speed of Rust vs C&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 또 떠오르는 Zig와 비교한다면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.scattered-thoughts.net/writing/assorted-thoughts-on-zig-and-rust/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Assorted thoughts on zig (and rust)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.scattered-thoughts.net/writing/how-safe-is-zig/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;safe&amp;nbsp;is&amp;nbsp;zig?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 간결함&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 블럭은 일종의 표현문이라 값을 반환할 수 있고, 블럭의 마지막에 세미콜론을 넣지 않으면 return으로 처리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 return을 쓰지 않는 방식에 거부감을 느꼈지만 계속 보다보니 뇌이징이 되서 좋아보인다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문법은 처음에 Rust를 구현할 때 썼던 OCaml에서 자주보이던 구문들.&lt;/p&gt;
&lt;pre id=&quot;code_1662024623162&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5063271951133145&quot;&gt;&lt;code&gt;let big_n = if n &amp;lt; 10 &amp;amp;&amp;amp; n &amp;gt; -10 {
    println!(&quot;, and is a small number, increase ten-fold&quot;);
    10 * n
} else {
    println!(&quot;, and is a big number, reduce by two&quot;);
    n / 2
};&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;구조체와 Enum의 &lt;a href=&quot;https://rinthel.github.io/rust-lang-book-ko/ch06-01-defining-an-enum.html#%EC%97%B4%EA%B1%B0%ED%98%95-%EA%B0%92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;유닛,&amp;nbsp; 튜플, 레코드 값&lt;/a&gt; 방식은 단순, 독특, 유용하면서도 강력하다. &lt;s&gt;역시 OCaml 만세&amp;nbsp;&lt;/s&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661935459063&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6663198128654267&quot;&gt;&lt;code&gt;enum Message {
    Quit,                    // 유닛
    Write(String),           // 튜플
    Move { x: i32, y: i32 }, // 레코드
}

struct QuitMessage;          // 유닛 구조체
struct WriteMessage(String); // 튜플 구조체
struct MoveMessage {         // 레코드 구조체
    x: i32,
    y: i32,
}&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;a href=&quot;https://rinthel.github.io/rust-lang-book-ko/ch05-03-method-syntax.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;amp;self 파라미터가 들어가느냐&lt;/a&gt;로 쉽게 구분해놨다.&lt;/p&gt;
&lt;pre id=&quot;code_1661935915467&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.4974130234078469&quot;&gt;&lt;code&gt;impl MoveMessage {
    // 연관함수
    fn linear(size: i32) -&amp;gt; MoveMessage {
        MoveMessage { x: size, y: size }
    }

    // 메소드
    fn area(&amp;amp;self) -&amp;gt; i32 {
        self.x * self.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;&lt;a href=&quot;https://rinthel.github.io/rust-lang-book-ko/ch18-00-patterns.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;패턴매칭&lt;/a&gt;은 심플하면서도 스위치문 따위와는 비교도 안되게 강력하다.&lt;/p&gt;
&lt;pre id=&quot;code_1662006145856&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.17049538480537751&quot;&gt;&lt;code&gt;let x = 1;

match x {
    1       =&amp;gt; println!(&quot;one&quot;),
    2 | 3   =&amp;gt; println!(&quot;two or three&quot;),
    4 ... 6 =&amp;gt; println!(&quot;four to six&quot;),
    _       =&amp;gt; println!(&quot;anything&quot;),
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조체나 Enum 까지도 모두 커버가 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1662007332779&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5002513466072742&quot;&gt;&lt;code&gt;let msg = Message::Move(0, 50);

match msg {
    Message::Quit =&amp;gt; {
        println!(&quot;The Quit variant has no data to destructure.&quot;)
    },
    Message::Write(text) =&amp;gt; println!(&quot;Text message: {}&quot;, text),
    Message::Move { x: 0, y } =&amp;gt; {
        println!(
            &quot;Move in the y direction {}&quot;,
            y
        );
    }
    Message::Move { x, y } =&amp;gt; {
        println!(
            &quot;Move in the x direction {} and in the y direction {}&quot;,
            x,
            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;&lt;a href=&quot;https://hanbum.gitbooks.io/rustbyexample/content/flow_control/if_let.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;if-let&lt;/a&gt;과 &lt;a href=&quot;https://hanbum.gitbooks.io/rustbyexample/content/flow_control/while_let.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;while-let&lt;/a&gt;은 강력한 패턴매칭을 조건문에서도 쓸수 있게 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 나올 &lt;a href=&quot;https://rust-lang.github.io/rfcs/3137-let-else.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;let-else&lt;/a&gt;, &lt;a href=&quot;https://rust-lang.github.io/rfcs/2497-if-let-chains.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;let-chains&lt;/a&gt;도 기대해도 좋겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1662023876236&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.3911628627509979&quot;&gt;&lt;code&gt;let number = Some(7);
let letter: Option&amp;lt;i32&amp;gt; = None;
let emoticon: Option&amp;lt;i32&amp;gt; = None;
let i_like_letters = false;

if let Some(i) = number {
    println!(&quot;Matched {:?}!&quot;, i);
}

if let Some(i) = letter {
    println!(&quot;Matched {:?}!&quot;, i);
} else {
    println!(&quot;Didn't match a number. Let's go with a letter!&quot;);
};

if let Some(i) = emoticon {
    println!(&quot;Matched {:?}!&quot;, i);
} else if i_like_letters {
    println!(&quot;Didn't match a number. Let's go with a letter!&quot;);
} else {
    println!(&quot;I don't like letters. Let's go with an emoticon :)!&quot;);
}&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;a href=&quot;https://rinthel.github.io/rust-lang-book-ko/ch04-03-slices.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;슬라이스&lt;/a&gt; 개념은 재밌다.&lt;/p&gt;
&lt;pre id=&quot;code_1662009107359&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7210475996810426&quot;&gt;&lt;code&gt;let arr = [0, 1, 2, 3, 4];
assert_eq!(arr[ ..  ], [0, 1, 2, 3, 4]);
assert_eq!(arr[ .. 3], [0, 1, 2      ]);
assert_eq!(arr[ ..=3], [0, 1, 2, 3   ]);
assert_eq!(arr[1..  ], [   1, 2, 3, 4]);
assert_eq!(arr[1.. 3], [   1, 2      ]); // This is a `Range`
assert_eq!(arr[1..=3], [   1, 2, 3   ]);&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;러스트 1.58에서는 &lt;a href=&quot;https://www.rustnote.com/blog/format_strings.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fstring&lt;/a&gt;도 들어갔다고 한다!!&lt;/p&gt;
&lt;pre id=&quot;code_1662010503667&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9684226515520717&quot;&gt;&lt;code&gt;let x = &quot;world&quot;;
println!(&quot;Hello {x}!&quot;)

let items = vec![10, 20, 30];
println!(&quot;{items:?}&quot;)&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;C와 비교해서 편한 기능은 &lt;a href=&quot;https://rinthel.github.io/rust-lang-book-ko/ch15-02-deref.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Deref&lt;/a&gt;라 불리는 자동 역참조 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rinthel.github.io/rust-lang-book-ko/ch05-03-method-syntax.html#--%EC%97%B0%EC%82%B0%EC%9E%90%EB%8A%94-%EC%96%B4%EB%94%94%EB%A1%9C-%EA%B0%94%EB%82%98%EC%9A%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구조체에서 메서드&lt;/a&gt;도 (*object).method()를&amp;nbsp; object-&amp;gt;method()라고 썼던 것과 달리 Deref가 자동으로 참조해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1662083331854&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6464966702261252&quot;&gt;&lt;code&gt;fn hello(name: &amp;amp;str) {
    println!(&quot;Hello, {}!&quot;, name);
}

fn main() {
    let m = MyBox::new(String::from(&quot;Rust&quot;));

    // Deref가 없을 때
    hello(&amp;amp;(*m)[..]);
    
    // Deref가 있을 때
    hello(&amp;amp;m);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. 매크로&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매크로 한정 리스프가 더 쉬워보이지만, 전위식이라는 점과 괄호가 무조건 있어야 하는 언어 특성이 크게 작동한다고 생각한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jt40E/btrLhuCsOrC/mAJ8xr5V5BirqlK48KSXKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jt40E/btrLhuCsOrC/mAJ8xr5V5BirqlK48KSXKK/img.png&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;606&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jt40E/btrLhuCsOrC/mAJ8xr5V5BirqlK48KSXKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJt40E%2FbtrLhuCsOrC%2FmAJ8xr5V5BirqlK48KSXKK%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;832&quot; height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WlDUA/btrLhPM4CSU/t6hcjs3cx9meeeu28O2lX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WlDUA/btrLhPM4CSU/t6hcjs3cx9meeeu28O2lX0/img.png&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;606&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WlDUA/btrLhPM4CSU/t6hcjs3cx9meeeu28O2lX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWlDUA%2FbtrLhPM4CSU%2Ft6hcjs3cx9meeeu28O2lX0%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;832&quot; height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2b9N2/btrLhJlUFaK/48ohpuLK1bivwwSRGd0Gw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2b9N2/btrLhJlUFaK/48ohpuLK1bivwwSRGd0Gw0/img.png&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;606&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2b9N2/btrLhJlUFaK/48ohpuLK1bivwwSRGd0Gw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2b9N2%2FbtrLhJlUFaK%2F48ohpuLK1bivwwSRGd0Gw0%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;832&quot; height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.slideshare.net/ogrigas/history-of-macros&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Evolution of macros&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;a href=&quot;https://rinthel.github.io/rust-lang-book-ko/appendix-04-macros.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;러스트의 매크로&lt;/a&gt;는 일반 문법과 똑같고(Syntactic) 확장 시 실수로 식별자가 캡처되지 않도록 보장한다(Hygenic).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 만드는게 너무 어렵다...ㅠㅠㅠ [&lt;a href=&quot;https://blog.cloudflare.com/ko-kr/writing-complex-macros-in-rust-reverse-polish-notation-ko-kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rust&amp;nbsp;로&amp;nbsp;복잡한&amp;nbsp;매크로를&amp;nbsp;작성하기:&amp;nbsp;역폴란드&amp;nbsp;표기법&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;Hygienic macro에 대한 글들&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Hygienic_macro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hygienic macro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/hygienic-macros-introduction/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hygienic&amp;nbsp;Macros&amp;nbsp;:&amp;nbsp;An&amp;nbsp;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6. 기타&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rust-lang.github.io/chalk/book/#chalk-works-by-converting-rust-goals-into-logical-inference-rules&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;chalk&lt;/a&gt;라는 라이브러리가 특이했는데, 러스트의 trait 시스템에 프롤로그의 논리 솔버를 도입한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/rust-lang/rust-analyzer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;rust analyzer&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;/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;h4 data-ke-size=&quot;size20&quot;&gt;1. 함수형&lt;/h4&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;관련 RFC: &amp;nbsp;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1888&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Proper tail calls #1888&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://seanchen1991.github.io/posts/tco-story/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Story&amp;nbsp;of&amp;nbsp;Tail&amp;nbsp;Call&amp;nbsp;Optimizations&amp;nbsp;in&amp;nbsp;Rust&lt;/a&gt;&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;/p&gt;
&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;느긋함(Lazy)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 RFC:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rust/issues/74465&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tracking&amp;nbsp;Issue&amp;nbsp;for&amp;nbsp;once_cell&amp;nbsp;#74465&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/2788&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;standard lazy types #2788&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/191&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Currying&amp;nbsp;RFC&amp;nbsp;#191&lt;/a&gt;&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;하스켈과 같은 함수형의 특징 중 하나는 Lazy하다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lazy 함은 일반적으로 느리지만 다루어야할 리소스 양이 많거나 무한을 다루어야 할 때 효과적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/2788&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;std::sync::Lazy&lt;/a&gt;처럼 RFC가 제안되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(비슷한 느낌으로 Immutable 자료구조 또한 표준으로 있었으면.. ㅎㅎ)&lt;/p&gt;
&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/Kindelia/HVM&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HVM&lt;/a&gt;같은 경우, Lazy clone 프리미티브를 이용해 공짜에 가깝게 복제하고, 람다 함수의 계산을 공유하여 성능 면에서 이점이 존재한다.&lt;/p&gt;
&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;커링(Currying)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 RFC: &lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/191&quot;&gt;Currying RFC #191&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;a href=&quot;https://github.com/nerdypepper/cutlass&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;cutlass&lt;/a&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;2. 타입&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고차타입(Higher Kinded Types)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 RFC: &lt;a href=&quot;https://github.com/rust-lang/rfcs/issues/324&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Higher&amp;nbsp;kinded&amp;nbsp;polymorphism&amp;nbsp;#324&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWGU03/btrLvEw185Q/u9jytUkTOZ9RcpRtCx9AC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWGU03/btrLvEw185Q/u9jytUkTOZ9RcpRtCx9AC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWGU03/btrLvEw185Q/u9jytUkTOZ9RcpRtCx9AC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWGU03%2FbtrLvEw185Q%2Fu9jytUkTOZ9RcpRtCx9AC0%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;949&quot; height=&quot;766&quot; data-origin-width=&quot;949&quot; data-origin-height=&quot;766&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/CMCDragonkai/a5638f50c87d49f815b8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rust/Haskell:&amp;nbsp;Higher-Kinded&amp;nbsp;Types&amp;nbsp;(HKT)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://typelevel.org/blog/2016/08/21/hkts-moving-forward.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Higher-kinded&amp;nbsp;types:&amp;nbsp;the&amp;nbsp;difference&amp;nbsp;between&amp;nbsp;giving&amp;nbsp;up,&amp;nbsp;and&amp;nbsp;moving&amp;nbsp;forward&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://terbium.io/2021/02/traits-typeclasses/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Comparing Traits and Typeclasses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://see-ro-e.tistory.com/339?category=849800&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Value / Type / Kind 와 Higher Kinded Type (Feat. 고차함수)&lt;/a&gt;&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;b&gt;선형타입(Linear type)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 RFC: &lt;a href=&quot;https://github.com/rust-lang/rfcs/issues/814&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Add&amp;nbsp;linear&amp;nbsp;type&amp;nbsp;facility&amp;nbsp;#814&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;a href=&quot;https://faultlore.com/blah/linear-rust/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Pain&amp;nbsp;Of&amp;nbsp;Real&amp;nbsp;Linear&amp;nbsp;Types&amp;nbsp;in&amp;nbsp;Rust&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 사용할 수 있는 횟수에 따라 4가지로 나뉘는데,&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;한번 이상 쓸 수 없음: Affine 타입&lt;/li&gt;
&lt;li&gt;한번은 사용해야 함: Relevant 타입&lt;/li&gt;
&lt;li&gt;정확히 한번만 사용해야 함: Linear 타입&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;러스트는 사용하면 moving이 일어나기 때문에 기본적으로 Affine 타입이며, 사용하지 않았을 때 컴파일러가 경고해주는게 Relevant 타입이라 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Linear(선형) 타입은 한번만 실행하기 때문에 file 사용 후 close가 적절히 실행되지 않는 것을 보완할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 최대 한번만 값을 사용하도록 강제하기 때문에 free가 여러번 일어나 메모리 버그가 일어나는 일을 방지하고, 인라인 관련 최적화를 수행할 수도 있다.[&lt;a href=&quot;https://www.tweag.io/blog/2017-03-13-linear-types/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Linear&amp;nbsp;types&amp;nbsp;make&amp;nbsp;performance&amp;nbsp;more&amp;nbsp;predictable&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;a href=&quot;https://idris2.readthedocs.io/en/latest/tutorial/multiplicities.html#sect-multiplicities&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Idris 2의 Quantitative Type Theory (QTT)&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;b&gt;가변 제네릭&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 RFC: &lt;a href=&quot;https://github.com/rust-lang/rust/issues/10124&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;variadic&amp;nbsp;generics&amp;nbsp;#10124&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1692371180800&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6852904636511394&quot;&gt;&lt;code&gt;type Tuple&amp;lt;..T&amp;gt; = (..T); // the parens here are the same as the ones around a tuple.
// use =&amp;gt; expansion
Tuple&amp;lt;&amp;gt; =&amp;gt; ()
Tuple&amp;lt;int&amp;gt; =&amp;gt; (int,)
Tuple&amp;lt;A, B, C&amp;gt; =&amp;gt; (A, B, C)&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;익명 Sum 타입&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 RFC: &lt;a href=&quot;https://github.com/rust-lang/rfcs/issues/294&quot;&gt;Anonymous sum types #294&amp;nbsp;&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;a href=&quot;https://joshua1988.github.io/ts/guide/operator.html#union-type&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;유니온(Union) 타입&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;&lt;b&gt;종속(Dependent)&amp;nbsp;타입과&amp;nbsp;정제(Refinement)&amp;nbsp;타입&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 RFC:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/issues/1621&quot;&gt;Numerical Constrained Types #1621&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1657&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;const-dependent&amp;nbsp;type&amp;nbsp;system.&amp;nbsp;#1657&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/issues/1930&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;pi&amp;nbsp;type&amp;nbsp;trilogy&amp;nbsp;#1930&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자에서 0~100까지만 사용할 수 있다면 어떨까?&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://en.wikipedia.org/wiki/Dependent_type&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;종속 타입(Dependent type)&lt;/a&gt;은 일반적으로 런타임에 검증하며, &lt;a href=&quot;https://en.wikipedia.org/wiki/Refinement_type&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;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;literal type&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;b&gt;Enum 강화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 RFC:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/1450&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Types for enum variants #1450&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/2593&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Enum variant types #2593&lt;/a&gt;&amp;nbsp;&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;a href=&quot;https://engineering.linecorp.com/ko/blog/typescript-enum-tree-shaking&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Enum은 type으로 표현&lt;/a&gt;할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://wikidocs.net/5723&quot;&gt;GADT&lt;/a&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;3. 컴파일&lt;/h4&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;관련 RFC:&amp;nbsp; &lt;a href=&quot;https://github.com/rust-lang/rfcs/pull/2033&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Experimentally add coroutines to Rust #2033&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코틀린의 &lt;a href=&quot;https://kotlinlang.org/docs/coroutines-overview.html&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;Rust의 async 설계가 잘되어 있다고는 하나 명시적인 await를 해줘야하는 지연된 값으로 좀 다른 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stackless 코루틴의 경우 컴파일러가 가능한 영역.&lt;/p&gt;
&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;관련 RFC:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/issues/1077&quot;&gt;Design By Contract #1077&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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://tour.dlang.org/tour/kr/gems/contract-programming&quot;&gt;D언어의 계약에 의한 프로그래밍(Design By Contract)&lt;/a&gt;은 멋진 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;in source test와 함께 쓰면 편할 듯.&lt;/p&gt;
&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;http://www.ats-lang.org/&quot;&gt;ATS(Applied Type System)&lt;/a&gt; 언어의 예처럼 증명을 구현과 통합하게 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TDD의 단점은 엣지 케이스를 빠트릴 수 있기 때문이다.&lt;/p&gt;
&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://github.com/agda/agda&quot;&gt;Agda&lt;/a&gt;나&amp;nbsp;&lt;a href=&quot;https://www.fstar-lang.org/&quot;&gt;F*&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;b&gt;컴파일 타임 평가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zig의 &lt;a href=&quot;https://ziglang.org/documentation/master/#comptime&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;comptime&lt;/a&gt;은 꽤 &lt;a href=&quot;https://kristoff.it/blog/what-is-zig-comptime/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;멋진기능&lt;/a&gt;이며, 러스트의 const는 아직 C++의 &lt;a href=&quot;https://en.cppreference.com/w/cpp/language/constexpr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;constexpr&lt;/a&gt;나 D의 &lt;a href=&quot;https://tour.dlang.org/tour/en/gems/compile-time-function-evaluation-ctfe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;static if&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;a href=&quot;https://github.com/nhynes/comptime-rs&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;/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;4. 편의성을 위한 다양한 기능들&lt;/h4&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;F#의 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;단위에 대한 구문&lt;/a&gt;은 깔끔하다. [&amp;nbsp;&lt;a href=&quot;https://davefancher.com/2012/11/17/f-basic-units-of-measure/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;F#&amp;nbsp;Basic&amp;nbsp;Units&amp;nbsp;of&amp;nbsp;Measure&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 GUI를 다룰려면 이 기능이 꼭 있어야 한다고 생각&lt;/p&gt;
&lt;pre id=&quot;code_1692370098966&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.1583462554054792&quot;&gt;&lt;code&gt;let dpiValue = 150.0&amp;lt;dpi&amp;gt;
let inchValue = 8.0&amp;lt;inch&amp;gt;
let pxValue = 1200.0&amp;lt;px&amp;gt;&lt;/code&gt;&lt;/pre&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;&lt;a href=&quot;https://yoric.github.io/post/uom.rs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Units&amp;nbsp;of&amp;nbsp;Measure&amp;nbsp;in&amp;nbsp;Rust&amp;nbsp;with&amp;nbsp;Refinement&amp;nbsp;Types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/iliekturtles/uom&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;uom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paholg/dimensioned/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dimensioned&lt;/a&gt;&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;b&gt;다이나믹 스코프&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다이나믹 스코프는 Dependency injection을 &lt;a href=&quot;https://gulundin.github.io/di-frameworks-are-dynamic-binding/&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;a href=&quot;https://www.cs.princeton.edu/courses/archive/spr96/cs441/notes/l7.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구현&lt;/a&gt;이 좋은편이며, rust에도 &lt;a href=&quot;https://github.com/ilammy/fluid-let&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fluid-let&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;b&gt;Effect 다루기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://overreacted.io/ko/algebraic-effects-for-the-rest-of-us/&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;a href=&quot;https://koka-lang.github.io/koka/doc/book.html#why-effects&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Koka&lt;/a&gt;, 스칼라의 &lt;a href=&quot;https://github.com/zio/zio-direct&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ZIO Direct&lt;/a&gt;,&amp;nbsp; Ocaml의 &lt;a href=&quot;https://github.com/ocaml-multicore/eio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;EIO&lt;/a&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;5. 몇가지 구문설탕&lt;/h4&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;관련 RFC:&amp;nbsp;&lt;a href=&quot;https://github.com/rust-lang/rfcs/issues/542&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Add&amp;nbsp;hashmap,&amp;nbsp;hashset,&amp;nbsp;treemap,&amp;nbsp;and&amp;nbsp;treeset&amp;nbsp;macros&amp;nbsp;#542&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;&lt;a href=&quot;https://github.com/peterjoel/velcro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;velcro&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;컴프리핸션(comprehension)은 보통 &lt;a href=&quot;https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파이썬&lt;/a&gt; 또는 &lt;a href=&quot;https://wiki.haskell.org/List_comprehension&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;a href=&quot;https://github.com/mattgathu/cute&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;cute&lt;/a&gt;나 &lt;a href=&quot;https://github.com/nickeb96/mapcomp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;mapcomp&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;b&gt;삼항연산자&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 RFC: &lt;a href=&quot;https://github.com/rust-lang/rfcs/issues/1362&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rust&amp;nbsp;Needs&amp;nbsp;The&amp;nbsp;Ternary&amp;nbsp;Conditional&amp;nbsp;Operator&amp;nbsp;(-?-:-)&amp;nbsp;#1362&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;&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;관련 RFC:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/rfcs/issues/1594&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Default&amp;nbsp;values&amp;nbsp;for&amp;nbsp;struct&amp;nbsp;fields&amp;nbsp;#1594&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://internals.rust-lang.org/t/pre-rfc-user-provided-default-field-values/15877&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pre-RFC:&amp;nbsp;User-provided&amp;nbsp;default&amp;nbsp;field&amp;nbsp;values&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;struct에 기본 값이 있다면 어떨까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 lazy 제안과 맞물려 좋은 시너지가 될 것이다.&lt;/p&gt;
&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;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://github.com/rust-lang/rfcs/issues/1281&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;nbsp;Implement&amp;nbsp;multiple&amp;nbsp;traits&amp;nbsp;at&amp;nbsp;once&amp;nbsp;#1281&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;subtrait을 사용했을때는 한번에 구현하는게 멘탈모델에 더 적합한 것 같다.&lt;/p&gt;
&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;관련 RFC: &lt;a href=&quot;https://github.com/rust-lang/rfcs/issues/323&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;functions with keyword args, optional args, and/or variable-arity argument (varargs) lists #323&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;&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;F#의 &lt;a href=&quot;https://learn.microsoft.com/ko-kr/dotnet/fsharp/language-reference/symbol-and-operator-reference/#function-symbols-and-operators&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파이프라인 문법&lt;/a&gt;도 좋지만, 타입의 힘을 빌려 D의 &lt;a href=&quot;https://tour.dlang.org/tour/kr/gems/uniform-function-call-syntax-ufcs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;연쇄 함수 호출 문법(Uniform Function Call Syntax (UFCS))&lt;/a&gt;이나 하스켈의 &lt;a href=&quot;https://wiki.haskell.org/TypeDirectedNameResolution&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Type Directed Name Resolution(TDNR)&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;b&gt;데코레이터&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dojang.io/mod/page/view.php?id=2427&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파이썬&lt;/a&gt;, &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/decorators.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;타입스크립트&lt;/a&gt;의 데코레이터, &lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/annotations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자바의 어노테이션&lt;/a&gt;는 Rust의 Derive를 만드는 것보다 훨씬 쉽다. (메서드를 호출한 결과일 뿐)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Manishearth/rust-adorn&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;rust-adorn&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;a href=&quot;https://www.jetbrains.com/help/teamcity/kotlin-dsl.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코틀린의 DSL&lt;/a&gt;도 &lt;a href=&quot;https://toss.tech/article/kotlin-dsl-restdocs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kotlin으로&amp;nbsp;DSL&amp;nbsp;만들기:&amp;nbsp;반복적이고&amp;nbsp;지루한&amp;nbsp;REST&amp;nbsp;Docs&amp;nbsp;벗어나기&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;h4 data-ke-size=&quot;size20&quot;&gt;6. REPL과 핫 리로드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;러스트의 풍부한 툴 인프라 중 유일한 불만은 REPL과 핫 리로드 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크립트 언어 계열을 써봤다면 REPL을, 웹 개발이나 Flutter관련 개발을 해봤다면 핫 리로드가 익숙할 텐데 저 둘의 생산성 증가는 상당하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REPL의 경우 프로토타입이나 간단한 함수나 로직을 테스트하기 좋고, 핫 리로드는 실제 어플리케이션의 상태가 유지되며 실시간으로 반영되기 때문에 불필요한 컴파일 시간과 테스트에 걸리는 시간을 줄일 수 있다.&lt;/p&gt;
&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/google/evcxr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;evcxr&lt;/a&gt;라는 REPL을 개발 중이라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://fasterthanli.me/articles/so-you-want-to-live-reload-rust&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;So&amp;nbsp;you&amp;nbsp;want&amp;nbsp;to&amp;nbsp;live-reload&amp;nbsp;Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://johnaustin.io/articles/2022/hot-reloading-rust&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hot&amp;nbsp;Reloading&amp;nbsp;Rust:&amp;nbsp;Windows&amp;nbsp;and&amp;nbsp;Linux&lt;/a&gt;&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;C++의 경우&amp;nbsp;마이크로소프트는 비주얼 스튜디오 2022에서!! 선보였다 [&lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/debugger/hot-reload?view=vs-2022&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Write and debug running code with Hot Reload in Visual Studio (C#, Visual Basic, C++)&lt;/a&gt;, &lt;a href=&quot;https://docs.microsoft.com/en-us/events/pure-virtual-cpp-2022/hot-reload-for-cpp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hot&amp;nbsp;Reload&amp;nbsp;for&amp;nbsp;C++&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;h3 data-ke-size=&quot;size23&quot;&gt;분류 짤&lt;/h3&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;724&quot; data-origin-height=&quot;1225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DY2kz/btrLiCsNNl4/iG6ig4FrPll7a6AMFLkGb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DY2kz/btrLiCsNNl4/iG6ig4FrPll7a6AMFLkGb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DY2kz/btrLiCsNNl4/iG6ig4FrPll7a6AMFLkGb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDY2kz%2FbtrLiCsNNl4%2FiG6ig4FrPll7a6AMFLkGb1%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;724&quot; height=&quot;1225&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;1225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://thume.ca/2019/07/14/a-tour-of-metaprogramming-models-for-generics/&quot;&gt;Models&amp;nbsp;of&amp;nbsp;Generics&amp;nbsp;and&amp;nbsp;Metaprogramming:&amp;nbsp;Go,&amp;nbsp;Rust,&amp;nbsp;Swift,&amp;nbsp;D&amp;nbsp;and&amp;nbsp;More&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;961&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnxMfU/btrLh9q5gFo/klWkS3Ia8KSMtzOuZnDk70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnxMfU/btrLh9q5gFo/klWkS3Ia8KSMtzOuZnDk70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnxMfU/btrLh9q5gFo/klWkS3Ia8KSMtzOuZnDk70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnxMfU%2FbtrLh9q5gFo%2FklWkS3Ia8KSMtzOuZnDk70%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;1710&quot; height=&quot;961&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;961&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/1q-c7UAyrUlM-eZyTo1pd8SZ0qwA_wYxmPZVOQkoDmH4/pub?start=false&amp;amp;loop=false&amp;amp;delayms=3000#slide=id.p&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Google Docs&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDoPyD/btrLirLNG4a/rYB6pIJ7NTtTxCmyndv420/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDoPyD/btrLirLNG4a/rYB6pIJ7NTtTxCmyndv420/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDoPyD/btrLirLNG4a/rYB6pIJ7NTtTxCmyndv420/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDoPyD%2FbtrLirLNG4a%2FrYB6pIJ7NTtTxCmyndv420%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/usagi/rust-memory-container-cs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rust&amp;nbsp;Memory&amp;nbsp;Container&amp;nbsp;Cheat-sheet&lt;/a&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Rust</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/85</guid>
      <comments>https://black7375.tistory.com/85#entry85comment</comments>
      <pubDate>Sun, 13 Jun 2021 00:36:43 +0900</pubDate>
    </item>
    <item>
      <title>Lepton - 얼마나 파이어폭스 UX를 개선할 수 있을까?</title>
      <link>https://black7375.tistory.com/83</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 Lepton이라 불릴 파이어폭스의 UX를 개선하는 플젝을 진행 중이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/black7375/Firefox-UI-Fix&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/black7375/Firefox-UI-Fix&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1621622064246&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;black7375/Firefox-UI-Fix&quot; data-og-description=&quot;  I respect proton UI and aim to fix it. Contribute to black7375/Firefox-UI-Fix development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/black7375/Firefox-UI-Fix&quot; data-og-url=&quot;https://github.com/black7375/Firefox-UI-Fix&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bgYOVO/hyKhvPfBPv/1YFNLLdxxpMUFF39maxsu0/img.png?width=1200&amp;amp;height=600&amp;amp;face=976_150_1032_211,https://scrap.kakaocdn.net/dn/spcnv/hyKhvBJUrZ/YPJvt0fb3nGg0Ql2S84b71/img.png?width=1560&amp;amp;height=720&amp;amp;face=0_0_1560_720,https://scrap.kakaocdn.net/dn/J3Hz0/hyKhpVMVhs/S2KHMfb00QaBZhk5fkDps1/img.png?width=702&amp;amp;height=850&amp;amp;face=0_0_702_850&quot;&gt;&lt;a href=&quot;https://github.com/black7375/Firefox-UI-Fix&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/black7375/Firefox-UI-Fix&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bgYOVO/hyKhvPfBPv/1YFNLLdxxpMUFF39maxsu0/img.png?width=1200&amp;amp;height=600&amp;amp;face=976_150_1032_211,https://scrap.kakaocdn.net/dn/spcnv/hyKhvBJUrZ/YPJvt0fb3nGg0Ql2S84b71/img.png?width=1560&amp;amp;height=720&amp;amp;face=0_0_1560_720,https://scrap.kakaocdn.net/dn/J3Hz0/hyKhpVMVhs/S2KHMfb00QaBZhk5fkDps1/img.png?width=702&amp;amp;height=850&amp;amp;face=0_0_702_850');&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;black7375/Firefox-UI-Fix&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  I respect proton UI and aim to fix it. Contribute to black7375/Firefox-UI-Fix development by creating an account on GitHub.&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;&amp;nbsp;&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;이 작업을 하게된 계기는 브라우저 업뎃(디벨로퍼 버전을 사용 중) 후 갑자기 엄청난 변화에 깜짝 놀랐기 때문이다.&lt;/p&gt;
&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;2013&quot; data-origin-height=&quot;1054&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR14xp/btq5pXlGkAL/GxGJijMbKHwq3ftLDN1Mg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR14xp/btq5pXlGkAL/GxGJijMbKHwq3ftLDN1Mg1/img.png&quot; data-alt=&quot;Photon 디자인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR14xp/btq5pXlGkAL/GxGJijMbKHwq3ftLDN1Mg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR14xp%2Fbtq5pXlGkAL%2FGxGJijMbKHwq3ftLDN1Mg1%2Fimg.png&quot; data-origin-width=&quot;2013&quot; data-origin-height=&quot;1054&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;Photon 디자인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t6sl6/btq5vOGWLEM/mu18WzkmmdEVVqvEmHfRnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t6sl6/btq5vOGWLEM/mu18WzkmmdEVVqvEmHfRnK/img.png&quot; data-alt=&quot;Proton 디자인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t6sl6/btq5vOGWLEM/mu18WzkmmdEVVqvEmHfRnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft6sl6%2Fbtq5vOGWLEM%2Fmu18WzkmmdEVVqvEmHfRnK%2Fimg.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&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;Proton 디자인&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;/p&gt;
&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-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btDVVM/btq5ufyq1CI/bJUIUSsKhdKwm3IOB2KTKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btDVVM/btq5ufyq1CI/bJUIUSsKhdKwm3IOB2KTKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btDVVM/btq5ufyq1CI/bJUIUSsKhdKwm3IOB2KTKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtDVVM%2Fbtq5ufyq1CI%2FbJUIUSsKhdKwm3IOB2KTKK%2Fimg.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&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;2018&quot; data-origin-height=&quot;1060&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GdIsl/btq5pXFY6qN/JwbyBBBCh3AfSzsvSGbINk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GdIsl/btq5pXFY6qN/JwbyBBBCh3AfSzsvSGbINk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GdIsl/btq5pXFY6qN/JwbyBBBCh3AfSzsvSGbINk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGdIsl%2Fbtq5pXFY6qN%2FJwbyBBBCh3AfSzsvSGbINk%2Fimg.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&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;2018&quot; data-origin-height=&quot;1060&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Gngm/btq5vNgXRZA/1k0eYf8JebERWo3yK076q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Gngm/btq5vNgXRZA/1k0eYf8JebERWo3yK076q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Gngm/btq5vNgXRZA/1k0eYf8JebERWo3yK076q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Gngm%2Fbtq5vNgXRZA%2F1k0eYf8JebERWo3yK076q1%2Fimg.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&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;메뉴를 누른 후 찾아 가는데 한세월 걸리드란;;&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://github.com/black7375/BlaCk-Void-Zsh&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ZSH 설정&lt;/a&gt;과 Doom같은 배포판 없이 직접 만들어 쓰는 이맥스 사용자라는 점만 고려해도.. (이하 생략)&lt;/p&gt;
&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;about:config에서 browser.compactmode.show를 활성화 시켜야지만 접근이 가능하다.&lt;/p&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR7q4Y/btq6b0UbsW6/FWutAJSpgFF8HJyYuM8QzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR7q4Y/btq6b0UbsW6/FWutAJSpgFF8HJyYuM8QzK/img.png&quot; style=&quot;width: 32.5678%; margin-right: 10px;&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;1128&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR7q4Y/btq6b0UbsW6/FWutAJSpgFF8HJyYuM8QzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR7q4Y%2Fbtq6b0UbsW6%2FFWutAJSpgFF8HJyYuM8QzK%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;1917&quot; height=&quot;1128&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3vEYH/btq54mKXIYN/NmFCsQTfZHZDGhjGIsSoPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3vEYH/btq54mKXIYN/NmFCsQTfZHZDGhjGIsSoPK/img.png&quot; style=&quot;width: 32.5678%; margin-right: 10px;&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;1128&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3vEYH/btq54mKXIYN/NmFCsQTfZHZDGhjGIsSoPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3vEYH%2Fbtq54mKXIYN%2FNmFCsQTfZHZDGhjGIsSoPK%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;1917&quot; height=&quot;1128&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biZvJ3/btq54pHUbgT/KP4REi1e00BTKVSxkKUzoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biZvJ3/btq54pHUbgT/KP4REi1e00BTKVSxkKUzoK/img.png&quot; style=&quot;width: 32.53890850149041%;&quot; data-origin-width=&quot;1917&quot; data-origin-height=&quot;1129&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biZvJ3/btq54pHUbgT/KP4REi1e00BTKVSxkKUzoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiZvJ3%2Fbtq54pHUbgT%2FKP4REi1e00BTKVSxkKUzoK%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;1917&quot; height=&quot;1129&quot;/&gt;&lt;/span&gt;&lt;/div&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;a href=&quot;https://black7375.tistory.com/80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;성능과 UX 트릭&lt;/a&gt;에서 소개했던 &lt;a href=&quot;https://en.wikipedia.org/wiki/Fitts%27s_law&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;피츠의 법칙&lt;/a&gt;에서 목표지점으로 빠르게 이동하는데 시간의 기본적인 비율은 $\frac{2 \times D}{W}$ 이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2iUmt%2FbtqZegdc2tp%2F0UBOesKGfs3Kl64hzQZYy1%2Fimg.png&quot; width=&quot;300&quot; height=&quot;220&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;424&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y911Z/btq59OOphNZ/NGU9nIOAYVnzimAO6dvgH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y911Z/btq59OOphNZ/NGU9nIOAYVnzimAO6dvgH1/img.png&quot; data-alt=&quot;D가 거리, W는 크기(너비)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y911Z/btq59OOphNZ/NGU9nIOAYVnzimAO6dvgH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2iUmt%2FbtqZegdc2tp%2F0UBOesKGfs3Kl64hzQZYy1%2Fimg.png&quot; width=&quot;300&quot; height=&quot;220&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;424&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;D가 거리, W는 크기(너비)&lt;/figcaption&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;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;&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.1 초기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;넷스케이프의 유지를 이어 불사조가 되어 돌아온 Phoenix가 있다. [&lt;a href=&quot;https://en.wikipedia.org/wiki/Firefox_early_version_history&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Firefox&amp;nbsp;early&amp;nbsp;version&amp;nbsp;history&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;610&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cepdTC/btq5vFiPeYg/DL0kfukTHUJDrxjfhggzj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cepdTC/btq5vFiPeYg/DL0kfukTHUJDrxjfhggzj1/img.png&quot; data-alt=&quot;v0.1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cepdTC/btq5vFiPeYg/DL0kfukTHUJDrxjfhggzj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcepdTC%2Fbtq5vFiPeYg%2FDL0kfukTHUJDrxjfhggzj1%2Fimg.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;610&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;v0.1&lt;/figcaption&gt;
&lt;/figure&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; srcset=&quot;http://static.micheljansen.org/uploads/firefox-evolution1.png 480w, http://static.micheljansen.org/uploads/firefox-evolution1-320x418.png 320w, http://static.micheljansen.org/uploads/firefox-evolution1-91x120.png 91w&quot; width=&quot;480&quot; height=&quot;627&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmKam3/btq5wvUHp81/nWsSj2KjXzBu9h0PxkJip1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmKam3/btq5wvUHp81/nWsSj2KjXzBu9h0PxkJip1/img.png&quot; data-alt=&quot;v1~3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmKam3/btq5wvUHp81/nWsSj2KjXzBu9h0PxkJip1/img.png&quot; srcset=&quot;http://static.micheljansen.org/uploads/firefox-evolution1.png 480w, http://static.micheljansen.org/uploads/firefox-evolution1-320x418.png 320w, http://static.micheljansen.org/uploads/firefox-evolution1-91x120.png 91w&quot; width=&quot;480&quot; height=&quot;627&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-filename=&quot;blob&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;v1~3&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버전 1부터 3까지의 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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.seamonkey-project.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SeaMonkey&lt;/a&gt;란 포크가 가장 비스무레하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;892&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwtNgD/btq5toJlXg9/BSnkiMpOgThT0FReUK8QSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwtNgD/btq5toJlXg9/BSnkiMpOgThT0FReUK8QSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwtNgD/btq5toJlXg9/BSnkiMpOgThT0FReUK8QSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwtNgD%2Fbtq5toJlXg9%2FBSnkiMpOgThT0FReUK8QSK%2Fimg.png&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;892&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;1.2 Classic (v4, 2006.10)&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;619&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DPeWp/btq5vOfR1oq/1KYvpXK1fFFqjavUNlu3Mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DPeWp/btq5vOfR1oq/1KYvpXK1fFFqjavUNlu3Mk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DPeWp/btq5vOfR1oq/1KYvpXK1fFFqjavUNlu3Mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDPeWp%2Fbtq5vOfR1oq%2F1KYvpXK1fFFqjavUNlu3Mk%2Fimg.png&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;619&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에서 도입된 UI로 가장 장수했다. [&lt;a href=&quot;https://wiki.mozilla.org/Firefox/Projects/3.7_and_4.0_Theme_and_UI_Revamp/Direction_and_Feedback&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Firefox/Projects/3.7&amp;nbsp;and&amp;nbsp;4.0&amp;nbsp;Theme&amp;nbsp;and&amp;nbsp;UI&amp;nbsp;Revamp/Direction&amp;nbsp;and&amp;nbsp;Feedback&lt;/a&gt;, &lt;a href=&quot;https://wiki.mozilla.org/Firefox/4.0_Windows_Theme_Mockups&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Firefox/4.0&amp;nbsp;Windows&amp;nbsp;Theme&amp;nbsp;Mockups&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Classic이라 칭하면 보통 이걸 말한다.&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;676&quot; height=&quot;299&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;299&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LtnCX/btq5uTothjq/LpwE30Y7s1ABGBCP7j7Zyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LtnCX/btq5uTothjq/LpwE30Y7s1ABGBCP7j7Zyk/img.png&quot; data-alt=&quot;버튼 모양과 컬러&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LtnCX/btq5uTothjq/LpwE30Y7s1ABGBCP7j7Zyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLtnCX%2Fbtq5uTothjq%2FLpwE30Y7s1ABGBCP7j7Zyk%2Fimg.png&quot; width=&quot;676&quot; height=&quot;299&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;299&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;b&gt;상징과 같은 좌 상단의 주황 메뉴 버튼 &lt;b&gt; &lt;/b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;차분해진 톤&lt;/li&gt;
&lt;li&gt;Win7의 에어로 글래스 대응&lt;/li&gt;
&lt;li&gt;Stop / Reload / Go를 한개의 버튼으로&lt;/li&gt;
&lt;li&gt;상단으로 이동한 탭&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;/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;/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;a href=&quot;https://www.palemoon.org/&quot;&gt;Pale Moon&lt;/a&gt;이란 브라우저가 잘 간직하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QLDal/btq5uHVJW9j/bXAEYjPsgTa9gbjBZ5B3Mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QLDal/btq5uHVJW9j/bXAEYjPsgTa9gbjBZ5B3Mk/img.png&quot; data-origin-width=&quot;2013&quot; data-origin-height=&quot;1067&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QLDal/btq5uHVJW9j/bXAEYjPsgTa9gbjBZ5B3Mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQLDal%2Fbtq5uHVJW9j%2FbXAEYjPsgTa9gbjBZ5B3Mk%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;2013&quot; height=&quot;1067&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PswVp/btq5tx0KQLX/8MAccaFYSWv6kLSyNA775K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PswVp/btq5tx0KQLX/8MAccaFYSWv6kLSyNA775K/img.png&quot; data-origin-width=&quot;2013&quot; data-origin-height=&quot;1067&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PswVp/btq5tx0KQLX/8MAccaFYSWv6kLSyNA775K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPswVp%2Fbtq5tx0KQLX%2F8MAccaFYSWv6kLSyNA775K%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;2013&quot; height=&quot;1067&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Palemoon 메뉴, 두터운 상태표시줄도 간직하고 있다&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;드디어 Stop / Reload / Go를 한개로 합쳐버리는 등의 함축적 변화가 시작되었다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.3 Australis (v29, 2014.04)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;29 버전에 도입되었다. [&lt;a href=&quot;http://www.donotlick.com/2014/04/28/firefox-and-flux-a-new-beautiful-browser-is-coming/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Firefox&amp;nbsp;and&amp;nbsp;Flux:&amp;nbsp;A&amp;nbsp;New,&amp;nbsp;Beautiful&amp;nbsp;Browser&amp;nbsp;is&amp;nbsp;Coming&lt;/a&gt;, &lt;a href=&quot;https://liliputing.com/2014/03/restore-classic-firefox-theme-firefox-29.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Restore&amp;nbsp;the&amp;nbsp;classic&amp;nbsp;Firefox&amp;nbsp;theme&amp;nbsp;in&amp;nbsp;Firefox&amp;nbsp;29&lt;/a&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;b&gt;드래그앤 드롭 커스터마이징  &lt;/b&gt;&lt;/li&gt;
&lt;li&gt;커브탭&lt;/li&gt;
&lt;li&gt;애니메이션&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;515&quot; height=&quot;328&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;814&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJHuNW/btq5vN2lDsb/G1a6vxqj9W5qyxkGyNMWOk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJHuNW/btq5vN2lDsb/G1a6vxqj9W5qyxkGyNMWOk/img.jpg&quot; data-alt=&quot;Australis&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJHuNW/btq5vN2lDsb/G1a6vxqj9W5qyxkGyNMWOk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJHuNW%2Fbtq5vN2lDsb%2FG1a6vxqj9W5qyxkGyNMWOk%2Fimg.jpg&quot; width=&quot;515&quot; height=&quot;328&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;814&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;Australis&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;http://www.donotlick.com/wp-content/uploads/2014/04/customize.jpg 1650w, http://www.donotlick.com/wp-content/uploads/2014/04/customize-300x190.jpg 300w, http://www.donotlick.com/wp-content/uploads/2014/04/customize-1024x651.jpg 1024w, http://www.donotlick.com/wp-content/uploads/2014/04/customize-700x445.jpg 700w&quot; width=&quot;515&quot; height=&quot;328&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zgrl4/btq5tc3vmcx/g75GaYtf9yXQSAlrt74TyK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zgrl4/btq5tc3vmcx/g75GaYtf9yXQSAlrt74TyK/img.jpg&quot; data-alt=&quot;메뉴 커스텀 기능 - 가장 고무적인 변화라고 생각한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zgrl4/btq5tc3vmcx/g75GaYtf9yXQSAlrt74TyK/img.jpg&quot; srcset=&quot;http://www.donotlick.com/wp-content/uploads/2014/04/customize.jpg 1650w, http://www.donotlick.com/wp-content/uploads/2014/04/customize-300x190.jpg 300w, http://www.donotlick.com/wp-content/uploads/2014/04/customize-1024x651.jpg 1024w, http://www.donotlick.com/wp-content/uploads/2014/04/customize-700x445.jpg 700w&quot; width=&quot;515&quot; height=&quot;328&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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; srcset=&quot;http://www.donotlick.com/wp-content/uploads/2014/04/tab-shape-alt-01.png 600w, http://www.donotlick.com/wp-content/uploads/2014/04/tab-shape-alt-01-300x100.png 300w&quot; width=&quot;515&quot; height=&quot;172&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSEw1o/btq5tpBwX7T/4AqqOY7UKKsKErjMOehJ11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSEw1o/btq5tpBwX7T/4AqqOY7UKKsKErjMOehJ11/img.png&quot; data-alt=&quot;크롬 탭 모양의 영향을&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSEw1o/btq5tpBwX7T/4AqqOY7UKKsKErjMOehJ11/img.png&quot; srcset=&quot;http://www.donotlick.com/wp-content/uploads/2014/04/tab-shape-alt-01.png 600w, http://www.donotlick.com/wp-content/uploads/2014/04/tab-shape-alt-01-300x100.png 300w&quot; width=&quot;515&quot; height=&quot;172&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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; srcset=&quot;http://www.donotlick.com/wp-content/uploads/2014/04/old-new-features.png 600w, http://www.donotlick.com/wp-content/uploads/2014/04/old-new-features-300x100.png 300w&quot; width=&quot;515&quot; height=&quot;172&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGHHfe/btq5qWUl5oK/sFHzqE2NPmnC4TsIz9JKuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGHHfe/btq5qWUl5oK/sFHzqE2NPmnC4TsIz9JKuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGHHfe/btq5qWUl5oK/sFHzqE2NPmnC4TsIz9JKuk/img.png&quot; srcset=&quot;http://www.donotlick.com/wp-content/uploads/2014/04/old-new-features.png 600w, http://www.donotlick.com/wp-content/uploads/2014/04/old-new-features-300x100.png 300w&quot; width=&quot;515&quot; height=&quot;172&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;태블릿용처럼 생긴 패널 UI: 써보면 찾기가 힘들다.&lt;/li&gt;
&lt;li&gt;상태표시줄 제거: 그래도 선택사항으로 남겨두는게 좋지 않았을까?&lt;/li&gt;
&lt;/ul&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 커다란 아이콘 패널은 다시는 PC에서 만나고 싶지 않은 경험.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;445&quot; data-origin-height=&quot;315&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw61Q7/btq5tbpXsgV/LkM6Pk0sneDYSbxogxhtXk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw61Q7/btq5tbpXsgV/LkM6Pk0sneDYSbxogxhtXk/img.gif&quot; data-alt=&quot;그래도 소소한 애니메이션은 좋았던걸로..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw61Q7/btq5tbpXsgV/LkM6Pk0sneDYSbxogxhtXk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cw61Q7/btq5tbpXsgV/LkM6Pk0sneDYSbxogxhtXk/img.gif&quot; data-origin-width=&quot;445&quot; data-origin-height=&quot;315&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.basilisk-browser.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Basilisk&lt;/a&gt;가 가장 비슷하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHbW8B/btq5vfx2yyt/GoZL4sXoqQqe4rWGjsp0GK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHbW8B/btq5vfx2yyt/GoZL4sXoqQqe4rWGjsp0GK/img.png&quot; data-origin-width=&quot;1906&quot; data-origin-height=&quot;1104&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHbW8B/btq5vfx2yyt/GoZL4sXoqQqe4rWGjsp0GK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHbW8B%2Fbtq5vfx2yyt%2FGoZL4sXoqQqe4rWGjsp0GK%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;1906&quot; height=&quot;1104&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uHsp5/btq5s6ieEbv/iOVKEm4FYM6ggBXxNNNlWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uHsp5/btq5s6ieEbv/iOVKEm4FYM6ggBXxNNNlWk/img.png&quot; data-origin-width=&quot;1906&quot; data-origin-height=&quot;1104&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uHsp5/btq5s6ieEbv/iOVKEm4FYM6ggBXxNNNlWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuHsp5%2Fbtq5s6ieEbv%2FiOVKEm4FYM6ggBXxNNNlWk%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;1906&quot; height=&quot;1104&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Basilisk&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.4 Photon (v57, 2017)&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2017&quot; data-origin-height=&quot;1056&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ySEME/btq5sSc9eeX/tm6TU54e1AglV3sWsuWMY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ySEME/btq5sSc9eeX/tm6TU54e1AglV3sWsuWMY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ySEME/btq5sSc9eeX/tm6TU54e1AglV3sWsuWMY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FySEME%2Fbtq5sSc9eeX%2Ftm6TU54e1AglV3sWsuWMY0%2Fimg.png&quot; data-origin-width=&quot;2017&quot; data-origin-height=&quot;1056&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;포톤은 Australis와 다르게 상당한 환영을 받았다.&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;b&gt;애니메이션  &lt;/b&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;&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;a href=&quot;https://dolske.wordpress.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dolske.wordpress.com/&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;애니메이션 이미지가 끊긴다면 한번 눌러서 원본 이미지를 재생해보자.&lt;/p&gt;
&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;640&quot; height=&quot;360&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;360&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXYO8b/btq5vNH564b/C7maaHDHVeK4wsy19c9jg0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXYO8b/btq5vNH564b/C7maaHDHVeK4wsy19c9jg0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXYO8b/btq5vNH564b/C7maaHDHVeK4wsy19c9jg0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cXYO8b/btq5vNH564b/C7maaHDHVeK4wsy19c9jg0/img.gif&quot; width=&quot;640&quot; height=&quot;360&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;360&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://blog.nightly.mozilla.org/2017/08/02/these-weeks-in-firefox-issue-21/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;These&amp;nbsp;Weeks&amp;nbsp;in&amp;nbsp;Firefox:&amp;nbsp;Issue&amp;nbsp;21&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;210&quot; data-origin-height=&quot;210&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBNshs/btq5tDM8psk/4utLQ2MMed7vSXnvCDskF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBNshs/btq5tDM8psk/4utLQ2MMed7vSXnvCDskF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBNshs/btq5tDM8psk/4utLQ2MMed7vSXnvCDskF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBNshs%2Fbtq5tDM8psk%2F4utLQ2MMed7vSXnvCDskF0%2Fimg.png&quot; data-origin-width=&quot;210&quot; data-origin-height=&quot;210&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;figure class=&quot;imageblock alignCenter&quot; data-attachment-id=&quot;3050&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/08/01/photon-engineering-newsletter-10/star/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/08/star.png&quot; data-origin-width=&quot;42&quot; data-origin-height=&quot;44&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XyLKR/btq5tESMFfr/GkhV6dYIxyNbmKDZE0uv9k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XyLKR/btq5tESMFfr/GkhV6dYIxyNbmKDZE0uv9k/img.gif&quot; data-alt=&quot;북마크 별과 스포티파이 애니메이션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XyLKR/btq5tESMFfr/GkhV6dYIxyNbmKDZE0uv9k/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/XyLKR/btq5tESMFfr/GkhV6dYIxyNbmKDZE0uv9k/img.gif&quot; data-attachment-id=&quot;3050&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/08/01/photon-engineering-newsletter-10/star/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/08/star.png&quot; data-origin-width=&quot;42&quot; data-origin-height=&quot;44&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;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;113&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pn7TM/btq5wvUKDyv/QaXj2vCjKKu14RwOdbORLk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pn7TM/btq5wvUKDyv/QaXj2vCjKKu14RwOdbORLk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pn7TM/btq5wvUKDyv/QaXj2vCjKKu14RwOdbORLk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/pn7TM/btq5wvUKDyv/QaXj2vCjKKu14RwOdbORLk/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;113&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;&lt;b&gt;오버플로우 메뉴&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;113&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boJOCD/btq5sR6owkR/kUDTHR6ljqilIrIKa1nCe1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boJOCD/btq5sR6owkR/kUDTHR6ljqilIrIKa1nCe1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boJOCD/btq5sR6owkR/kUDTHR6ljqilIrIKa1nCe1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/boJOCD/btq5sR6owkR/kUDTHR6ljqilIrIKa1nCe1/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;113&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;&lt;b&gt;새로고침 / 취소&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-attachment-id=&quot;2807&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/07/24/photon-engineering-newsletter-9/stopreload/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/07/stopreload.gif&quot; data-orig-size=&quot;650,334&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;stopreload&quot; data-medium-file=&quot;https://dolske.files.wordpress.com/2017/07/stopreload.gif?w=300&quot; data-large-file=&quot;https://dolske.files.wordpress.com/2017/07/stopreload.gif?w=474&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;244&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vRtov/btq5ve0dIug/UwgC6TAV8UDPap7LiP68KK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vRtov/btq5ve0dIug/UwgC6TAV8UDPap7LiP68KK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vRtov/btq5ve0dIug/UwgC6TAV8UDPap7LiP68KK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/vRtov/btq5ve0dIug/UwgC6TAV8UDPap7LiP68KK/img.gif&quot; data-attachment-id=&quot;2807&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/07/24/photon-engineering-newsletter-9/stopreload/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/07/stopreload.gif&quot; data-orig-size=&quot;650,334&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;stopreload&quot; data-medium-file=&quot;https://dolske.files.wordpress.com/2017/07/stopreload.gif?w=300&quot; data-large-file=&quot;https://dolske.files.wordpress.com/2017/07/stopreload.gif?w=474&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;244&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;&lt;b&gt;탭로딩 인디케이터&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-attachment-id=&quot;3409&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/09/11/photon-engineering-newsletter-15/tabload/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/09/tabload.gif&quot; data-orig-size=&quot;516,180&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;tabload&quot; data-medium-file=&quot;https://dolske.files.wordpress.com/2017/09/tabload.gif?w=300&quot; data-large-file=&quot;https://dolske.files.wordpress.com/2017/09/tabload.gif?w=474&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;165&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FTl1K/btq5sUPSJj5/LZCC9hd11u4H0GMZjxF420/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FTl1K/btq5sUPSJj5/LZCC9hd11u4H0GMZjxF420/img.gif&quot; data-alt=&quot;위의 새로고침에 있는 로딩과 비교해보라&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FTl1K/btq5sUPSJj5/LZCC9hd11u4H0GMZjxF420/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/FTl1K/btq5sUPSJj5/LZCC9hd11u4H0GMZjxF420/img.gif&quot; data-attachment-id=&quot;3409&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/09/11/photon-engineering-newsletter-15/tabload/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/09/tabload.gif&quot; data-orig-size=&quot;516,180&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;tabload&quot; data-medium-file=&quot;https://dolske.files.wordpress.com/2017/09/tabload.gif?w=300&quot; data-large-file=&quot;https://dolske.files.wordpress.com/2017/09/tabload.gif?w=474&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;165&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-attachment-id=&quot;3693&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/09/22/photon-engineering-newsletter-16/sync/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/09/sync.gif&quot; data-orig-size=&quot;600,240&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;sync&quot; data-medium-file=&quot;https://dolske.files.wordpress.com/2017/09/sync.gif?w=300&quot; data-large-file=&quot;https://dolske.files.wordpress.com/2017/09/sync.gif?w=474&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;189&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F0a2W/btq5toWTkoH/csh7mKgD9aTxExknPkbfp0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F0a2W/btq5toWTkoH/csh7mKgD9aTxExknPkbfp0/img.gif&quot; data-alt=&quot;로딩 인디케이터 동기화 (출시에 가까워졌을때 동기화되도록 바뀜)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F0a2W/btq5toWTkoH/csh7mKgD9aTxExknPkbfp0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/F0a2W/btq5toWTkoH/csh7mKgD9aTxExknPkbfp0/img.gif&quot; data-attachment-id=&quot;3693&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/09/22/photon-engineering-newsletter-16/sync/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/09/sync.gif&quot; data-orig-size=&quot;600,240&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;sync&quot; data-medium-file=&quot;https://dolske.files.wordpress.com/2017/09/sync.gif?w=300&quot; data-large-file=&quot;https://dolske.files.wordpress.com/2017/09/sync.gif?w=474&quot; data-origin-width=&quot;473&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;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;&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;400&quot; data-origin-height=&quot;103&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AucRn/btq5t1UQGrz/mSWK0yc6P5d2N9erMF9OGk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AucRn/btq5t1UQGrz/mSWK0yc6P5d2N9erMF9OGk/img.gif&quot; data-alt=&quot;Photon&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AucRn/btq5t1UQGrz/mSWK0yc6P5d2N9erMF9OGk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/AucRn/btq5t1UQGrz/mSWK0yc6P5d2N9erMF9OGk/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;103&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;Photon&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3m7xK/btq5vFwnIlh/pG1CSBCpwnazW9ITiOMiFk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3m7xK/btq5vFwnIlh/pG1CSBCpwnazW9ITiOMiFk/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;103&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3m7xK/btq5vFwnIlh/pG1CSBCpwnazW9ITiOMiFk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3m7xK%2Fbtq5vFwnIlh%2FpG1CSBCpwnazW9ITiOMiFk%2Fimg.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;400&quot; height=&quot;103&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqwpJK/btq5txNcMTI/wtDiq58JBHTRwAXMUXeJo0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqwpJK/btq5txNcMTI/wtDiq58JBHTRwAXMUXeJo0/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;103&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqwpJK/btq5txNcMTI/wtDiq58JBHTRwAXMUXeJo0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqwpJK%2Fbtq5txNcMTI%2FwtDiq58JBHTRwAXMUXeJo0%2Fimg.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;400&quot; height=&quot;103&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxpROL/btq5uTWjYEP/I4IVoH89p6cuVNjWxaaEM0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxpROL/btq5uTWjYEP/I4IVoH89p6cuVNjWxaaEM0/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;103&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxpROL/btq5uTWjYEP/I4IVoH89p6cuVNjWxaaEM0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxpROL%2Fbtq5uTWjYEP%2FI4IVoH89p6cuVNjWxaaEM0%2Fimg.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;400&quot; height=&quot;103&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z7KId/btq5ugKSn7W/FZ2RUlTBOKDqDjaG0wBhqK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z7KId/btq5ugKSn7W/FZ2RUlTBOKDqDjaG0wBhqK/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;103&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z7KId/btq5ugKSn7W/FZ2RUlTBOKDqDjaG0wBhqK/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz7KId%2Fbtq5ugKSn7W%2FFZ2RUlTBOKDqDjaG0wBhqK%2Fimg.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;400&quot; height=&quot;103&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Chrome, Edge, Basilisk, Whale&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;Honeycam 2021-05-22 07-02-25.gif&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRiCXC/btq5sTpA3ir/1Yi76vTFI2Ah4Y24lXoZdk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRiCXC/btq5sTpA3ir/1Yi76vTFI2Ah4Y24lXoZdk/img.gif&quot; data-alt=&quot;전체화면 애니메이션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRiCXC/btq5sTpA3ir/1Yi76vTFI2Ah4Y24lXoZdk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bRiCXC/btq5sTpA3ir/1Yi76vTFI2Ah4Y24lXoZdk/img.gif&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot; data-filename=&quot;Honeycam 2021-05-22 07-02-25.gif&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;&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/okZxo/btq5vEqHNfB/z7bVNOg8k4wenjs2VbUem1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/okZxo/btq5vEqHNfB/z7bVNOg8k4wenjs2VbUem1/img.gif&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/okZxo/btq5vEqHNfB/z7bVNOg8k4wenjs2VbUem1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FokZxo%2Fbtq5vEqHNfB%2Fz7bVNOg8k4wenjs2VbUem1%2Fimg.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;1920&quot; height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IeGIT/btq5tDM5CRp/6Ykta3yDTlUu66vhGeuFtK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IeGIT/btq5tDM5CRp/6Ykta3yDTlUu66vhGeuFtK/img.gif&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IeGIT/btq5tDM5CRp/6Ykta3yDTlUu66vhGeuFtK/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIeGIT%2Fbtq5tDM5CRp%2F6Ykta3yDTlUu66vhGeuFtK%2Fimg.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;1920&quot; height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzsPtg/btq5sSKYsT2/ZYcvDkERceRmrm0Bh10EXK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzsPtg/btq5sSKYsT2/ZYcvDkERceRmrm0Bh10EXK/img.gif&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzsPtg/btq5sSKYsT2/ZYcvDkERceRmrm0Bh10EXK/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzsPtg%2Fbtq5sSKYsT2%2FZYcvDkERceRmrm0Bh10EXK%2Fimg.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;1920&quot; height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhLlAB/btq5sRL5rpi/LsH4HJLedjPNLJHBAEgsM0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhLlAB/btq5sRL5rpi/LsH4HJLedjPNLJHBAEgsM0/img.gif&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhLlAB/btq5sRL5rpi/LsH4HJLedjPNLJHBAEgsM0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhLlAB%2Fbtq5sRL5rpi%2FLsH4HJLedjPNLJHBAEgsM0%2Fimg.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;1920&quot; height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/div&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;애니메이션 파트가 끝났고,&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; srcset=&quot;https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=474 474w, https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=946 946w, https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=150 150w, https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=300 300w, https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=768 768w&quot; data-attachment-id=&quot;2459&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/07/05/photon-engineering-newsletter-8/pageactionprotoi/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png&quot; data-orig-size=&quot;1400,503&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;pageactionprotoi&quot; data-medium-file=&quot;https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=300&quot; data-large-file=&quot;https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=474&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;315&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l4CxA/btq5wv1vGh5/wkIQSAqj9B43wKfd95gLkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l4CxA/btq5wv1vGh5/wkIQSAqj9B43wKfd95gLkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l4CxA/btq5wv1vGh5/wkIQSAqj9B43wKfd95gLkK/img.png&quot; srcset=&quot;https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=474 474w, https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=946 946w, https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=150 150w, https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=300 300w, https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=768 768w&quot; data-attachment-id=&quot;2459&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/07/05/photon-engineering-newsletter-8/pageactionprotoi/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png&quot; data-orig-size=&quot;1400,503&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;pageactionprotoi&quot; data-medium-file=&quot;https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=300&quot; data-large-file=&quot;https://dolske.files.wordpress.com/2017/07/pageactionprotoi.png?w=474&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;315&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;마지막으로 직각직각해진 탭바.&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; srcset=&quot;https://dolske.files.wordpress.com/2017/06/win10mock.png?w=474 474w, https://dolske.files.wordpress.com/2017/06/win10mock.png?w=948 948w, https://dolske.files.wordpress.com/2017/06/win10mock.png?w=150 150w, https://dolske.files.wordpress.com/2017/06/win10mock.png?w=300 300w, https://dolske.files.wordpress.com/2017/06/win10mock.png?w=768 768w&quot; data-attachment-id=&quot;1949&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/06/08/photon-engineering-newsletter-5/win10mock/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/06/win10mock.png&quot; data-orig-size=&quot;1928,206&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;win10mock&quot; data-medium-file=&quot;https://dolske.files.wordpress.com/2017/06/win10mock.png?w=300&quot; data-large-file=&quot;https://dolske.files.wordpress.com/2017/06/win10mock.png?w=474&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;93&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IC8kB/btq5wvmRZ7R/xivgTkkkKQ5vfgPD5kdKJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IC8kB/btq5wvmRZ7R/xivgTkkkKQ5vfgPD5kdKJk/img.png&quot; data-alt=&quot;파란색 불빛은 타이틀이 바뀌었을때 알림 기능&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IC8kB/btq5wvmRZ7R/xivgTkkkKQ5vfgPD5kdKJk/img.png&quot; srcset=&quot;https://dolske.files.wordpress.com/2017/06/win10mock.png?w=474 474w, https://dolske.files.wordpress.com/2017/06/win10mock.png?w=948 948w, https://dolske.files.wordpress.com/2017/06/win10mock.png?w=150 150w, https://dolske.files.wordpress.com/2017/06/win10mock.png?w=300 300w, https://dolske.files.wordpress.com/2017/06/win10mock.png?w=768 768w&quot; data-attachment-id=&quot;1949&quot; data-permalink=&quot;https://dolske.wordpress.com/2017/06/08/photon-engineering-newsletter-5/win10mock/&quot; data-orig-file=&quot;https://dolske.files.wordpress.com/2017/06/win10mock.png&quot; data-orig-size=&quot;1928,206&quot; data-comments-opened=&quot;1&quot; data-image-meta=&quot;{&quot; data-image-title=&quot;win10mock&quot; data-medium-file=&quot;https://dolske.files.wordpress.com/2017/06/win10mock.png?w=300&quot; data-large-file=&quot;https://dolske.files.wordpress.com/2017/06/win10mock.png?w=474&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;93&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.waterfox.net&quot;&gt;Waterfox&lt;/a&gt;는 Australis 탭모양에 Photon의 패널 모양을 가지고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1928&quot; data-origin-height=&quot;1162&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tguFq/btq5uuh8qS9/t1HgPqVGTcokJak7waCpN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tguFq/btq5uuh8qS9/t1HgPqVGTcokJak7waCpN1/img.png&quot; data-alt=&quot;Waterfox&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tguFq/btq5uuh8qS9/t1HgPqVGTcokJak7waCpN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtguFq%2Fbtq5uuh8qS9%2Ft1HgPqVGTcokJak7waCpN1%2Fimg.png&quot; data-origin-width=&quot;1928&quot; data-origin-height=&quot;1162&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;Waterfox&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;더 이상 확장기능으로 XUL 커스텀을 지원하지 않음. (Tab Mix Plus, Tab Scope 등 유수의 애드온이 쓸려나갔다. ㅠㅠㅠㅠ)&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;/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.5 Proton (v89, 2021.06)&lt;/b&gt;&lt;/h4&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;2018&quot; data-origin-height=&quot;1060&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDlN37/btq5vOGXF1V/STrCJ5O96LSBtXGXGWtVLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDlN37/btq5vOGXF1V/STrCJ5O96LSBtXGXGWtVLK/img.png&quot; data-alt=&quot;아까는 안보여줬던 화이트 테마&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDlN37/btq5vOGXF1V/STrCJ5O96LSBtXGXGWtVLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDlN37%2Fbtq5vOGXF1V%2FSTrCJ5O96LSBtXGXGWtVLK%2Fimg.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;깔끔히 정리된 메뉴(중복이 많이 사라짐) &lt;b&gt; &lt;/b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;엣지를 떠올릴만큼 이뻐지는 아이콘&lt;/li&gt;
&lt;li&gt;마음에 드는 일부 애니메이션&lt;/li&gt;
&lt;li&gt;스켈레톤 스크린&lt;/li&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전반적 컨셉 자체는 공감하고, 각종 메뉴들의 꼼꼼한 구현까지 마음에 들었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YJZeN/btq5vFwpZPv/TgnNnPYdgfYCOVoA4MdkN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YJZeN/btq5vFwpZPv/TgnNnPYdgfYCOVoA4MdkN0/img.png&quot; data-origin-width=&quot;2017&quot; data-origin-height=&quot;1056&quot; style=&quot;width: 49.4974%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YJZeN/btq5vFwpZPv/TgnNnPYdgfYCOVoA4MdkN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYJZeN%2Fbtq5vFwpZPv%2FTgnNnPYdgfYCOVoA4MdkN0%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;2017&quot; height=&quot;1056&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgysXP/btq5u4iTPER/jWRSKkvnfxdOTCr39HY5Dk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgysXP/btq5u4iTPER/jWRSKkvnfxdOTCr39HY5Dk/img.png&quot; data-origin-width=&quot;2022&quot; data-origin-height=&quot;1062&quot; style=&quot;width: 49.3398%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgysXP/btq5u4iTPER/jWRSKkvnfxdOTCr39HY5Dk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgysXP%2Fbtq5u4iTPER%2FjWRSKkvnfxdOTCr39HY5Dk%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;2022&quot; height=&quot;1062&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvxMbg/btq5uSiMuEH/YiNIvYNcZO8iQdaKkUE5yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvxMbg/btq5uSiMuEH/YiNIvYNcZO8iQdaKkUE5yk/img.png&quot; data-origin-width=&quot;2013&quot; data-origin-height=&quot;1054&quot; style=&quot;width: 49.4976%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvxMbg/btq5uSiMuEH/YiNIvYNcZO8iQdaKkUE5yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvxMbg%2Fbtq5uSiMuEH%2FYiNIvYNcZO8iQdaKkUE5yk%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;2013&quot; height=&quot;1054&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lFffM/btq5tp2zhie/d9uZs8ivIOGKekonzXK9a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lFffM/btq5tp2zhie/d9uZs8ivIOGKekonzXK9a1/img.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&quot; style=&quot;width: 49.3396%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lFffM/btq5tp2zhie/d9uZs8ivIOGKekonzXK9a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlFffM%2Fbtq5tp2zhie%2Fd9uZs8ivIOGKekonzXK9a1%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;2018&quot; height=&quot;1060&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9MbTl/btq5TtKu5Wr/oGpUGlVgDkqjf8FaVy22V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9MbTl/btq5TtKu5Wr/oGpUGlVgDkqjf8FaVy22V0/img.png&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;118&quot; style=&quot;width: 51.9727%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9MbTl/btq5TtKu5Wr/oGpUGlVgDkqjf8FaVy22V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9MbTl%2Fbtq5TtKu5Wr%2FoGpUGlVgDkqjf8FaVy22V0%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;460&quot; height=&quot;118&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uEy6k/btq5XFQCsBa/BDaYLMfGujzToiVgZyjr30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uEy6k/btq5XFQCsBa/BDaYLMfGujzToiVgZyjr30/img.png&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;132&quot; style=&quot;width: 46.8645%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uEy6k/btq5XFQCsBa/BDaYLMfGujzToiVgZyjr30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuEy6k%2Fbtq5XFQCsBa%2FBDaYLMfGujzToiVgZyjr30%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;464&quot; height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;/div&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;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;li&gt;헷갈리게 만드는 탭 인디케이터들&lt;/li&gt;
&lt;li&gt;주소창의 페이지 액션 버튼(3점)이 사라짐 + 스크린샷은 일반 툴바로 옮겨버림&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;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2001&quot; data-origin-height=&quot;1015&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chPQRf/btq5uf0iMut/Jyn7v7BrJcUcuydQcDFFLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chPQRf/btq5uf0iMut/Jyn7v7BrJcUcuydQcDFFLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chPQRf/btq5uf0iMut/Jyn7v7BrJcUcuydQcDFFLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchPQRf%2Fbtq5uf0iMut%2FJyn7v7BrJcUcuydQcDFFLK%2Fimg.png&quot; data-origin-width=&quot;2001&quot; data-origin-height=&quot;1015&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;2018&quot; data-origin-height=&quot;1060&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckF2Ib/btq5w6H4tq6/Nn5gohpIX2yUNqKxI6O5C1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckF2Ib/btq5w6H4tq6/Nn5gohpIX2yUNqKxI6O5C1/img.png&quot; data-alt=&quot;얇상해진게 엣지 같다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckF2Ib/btq5w6H4tq6/Nn5gohpIX2yUNqKxI6O5C1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckF2Ib%2Fbtq5w6H4tq6%2FNn5gohpIX2yUNqKxI6O5C1%2Fimg.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&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;그리고 달라진 재로딩과 다운로드 애니메이션&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pLJED/btq5uTQVA5D/eBBni2XXztAak9RXCVkc7K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pLJED/btq5uTQVA5D/eBBni2XXztAak9RXCVkc7K/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;103&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pLJED/btq5uTQVA5D/eBBni2XXztAak9RXCVkc7K/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpLJED%2Fbtq5uTQVA5D%2FeBBni2XXztAak9RXCVkc7K%2Fimg.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;400&quot; height=&quot;103&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wCUHi/btq5zFcDNdO/6hHDIBHd8Ekb0TyxjoWvlK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wCUHi/btq5zFcDNdO/6hHDIBHd8Ekb0TyxjoWvlK/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;103&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wCUHi/btq5zFcDNdO/6hHDIBHd8Ekb0TyxjoWvlK/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwCUHi%2Fbtq5zFcDNdO%2F6hHDIBHd8Ekb0TyxjoWvlK%2Fimg.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;400&quot; height=&quot;103&quot;/&gt;&lt;/span&gt;&lt;/div&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/06afa/btq5EtDWBFS/7J9FW3ahfksgmDVYWnGo51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/06afa/btq5EtDWBFS/7J9FW3ahfksgmDVYWnGo51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/06afa/btq5EtDWBFS/7J9FW3ahfksgmDVYWnGo51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F06afa%2Fbtq5EtDWBFS%2F7J9FW3ahfksgmDVYWnGo51%2Fimg.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&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;파비콘 정보가 없을 때의 기본 아이콘도 정말 이쁘다고 생각한다. (사진출처: &lt;a href=&quot;https://www.reddit.com/r/firefox/comments/n4j7qr/now_im_not_the_biggest_proton_fan_but_these/&quot;&gt;레딧&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;316&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rZeTu/btq56kNQnD5/mtYfjETyKtQSbiupGIQ8V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rZeTu/btq56kNQnD5/mtYfjETyKtQSbiupGIQ8V0/img.png&quot; data-alt=&quot;파비콘 정보가 없을때&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rZeTu/btq56kNQnD5/mtYfjETyKtQSbiupGIQ8V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrZeTu%2Fbtq56kNQnD5%2FmtYfjETyKtQSbiupGIQ8V0%2Fimg.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;316&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eqI11b/btq6cUHJnBS/Ae1wFv65Y86HGaVA5YUO0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eqI11b/btq6cUHJnBS/Ae1wFv65Y86HGaVA5YUO0K/img.png&quot; data-origin-width=&quot;188&quot; data-origin-height=&quot;220&quot; style=&quot;width: 46.9204%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eqI11b/btq6cUHJnBS/Ae1wFv65Y86HGaVA5YUO0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeqI11b%2Fbtq6cUHJnBS%2FAe1wFv65Y86HGaVA5YUO0K%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;188&quot; height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjfRmr/btq6cTB2bmB/6HlKJtujYuVh88PD83y2Pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjfRmr/btq6cTB2bmB/6HlKJtujYuVh88PD83y2Pk/img.png&quot; data-origin-width=&quot;191&quot; data-origin-height=&quot;202&quot; style=&quot;width: 51.9168%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjfRmr/btq6cTB2bmB/6HlKJtujYuVh88PD83y2Pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjfRmr%2Fbtq6cTB2bmB%2F6HlKJtujYuVh88PD83y2Pk%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;191&quot; height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/div&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;파이어폭스의 로딩 애니메이션은 필름 스트립 기법을 사용하기 때문에 svg 파일이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 다음 링크에 들어가서 확인 가능: resource:///chrome/browser/skin/classic/browser/reload-to-stop.svg&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;74&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPcjAP/btq5w6H3kQN/Nr6a1LDHMECuqKiXkkS4kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPcjAP/btq5w6H3kQN/Nr6a1LDHMECuqKiXkkS4kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPcjAP/btq5w6H3kQN/Nr6a1LDHMECuqKiXkkS4kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPcjAP%2Fbtq5w6H3kQN%2FNr6a1LDHMECuqKiXkkS4kk%2Fimg.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;74&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;88&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rGFct/btq5CBOfwsT/gJMqIdD2KzYqhinHX11k1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rGFct/btq5CBOfwsT/gJMqIdD2KzYqhinHX11k1K/img.png&quot; data-alt=&quot;Photon의 로딩 애니메이션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rGFct/btq5CBOfwsT/gJMqIdD2KzYqhinHX11k1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrGFct%2Fbtq5CBOfwsT%2FgJMqIdD2KzYqhinHX11k1K%2Fimg.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;88&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;Photon의 로딩 애니메이션&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfmC29/btq5w5CoQ8S/PTS4X9S9Bajs7pFrgiJYhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfmC29/btq5w5CoQ8S/PTS4X9S9Bajs7pFrgiJYhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfmC29/btq5w5CoQ8S/PTS4X9S9Bajs7pFrgiJYhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfmC29%2Fbtq5w5CoQ8S%2FPTS4X9S9Bajs7pFrgiJYhk%2Fimg.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;60&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;1920&quot; data-origin-height=&quot;122&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ez0cyx/btq5vfe6Afd/8kj6heOuBNa1I8KNtczlsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ez0cyx/btq5vfe6Afd/8kj6heOuBNa1I8KNtczlsK/img.png&quot; data-alt=&quot;Proton의 로딩 애니메이션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ez0cyx/btq5vfe6Afd/8kj6heOuBNa1I8KNtczlsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fez0cyx%2Fbtq5vfe6Afd%2F8kj6heOuBNa1I8KNtczlsK%2Fimg.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;122&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;Proton의 로딩 애니메이션&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Lepton (Proton Fix) 소개&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;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;li&gt;탭 상태&lt;/li&gt;
&lt;li&gt;새 탭 컨텐츠&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;주소창의 페이지 액션 버튼과 북마크/라이브러리 애니메이션은 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;나중에 고급 사용자를 타겟으로 하거나 인스톨 스크립트가 만들어진 다음에야 들어갈 예정.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아참, 이름이 Lepton(경입자)인 이유는 Proton(양성자)의 얇은 레이어라서 + -ton과의 네이밍 맞추기 말장난.&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;간격&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;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;126&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPnAui/btq5ugx86dw/ZsskdAJ1H6XYVKnVkMHEq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPnAui/btq5ugx86dw/ZsskdAJ1H6XYVKnVkMHEq1/img.png&quot; data-alt=&quot;보여주는 탭 갯수가 더 많다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPnAui/btq5ugx86dw/ZsskdAJ1H6XYVKnVkMHEq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPnAui%2Fbtq5ugx86dw%2FZsskdAJ1H6XYVKnVkMHEq1%2Fimg.png&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;126&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;1104&quot; data-origin-height=&quot;84&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKwC6C/btq5zFXWcOk/BiX375feU0dpB5rgYvO2H1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKwC6C/btq5zFXWcOk/BiX375feU0dpB5rgYvO2H1/img.png&quot; data-alt=&quot;높이도 조정됨&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKwC6C/btq5zFXWcOk/BiX375feU0dpB5rgYvO2H1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKwC6C%2Fbtq5zFXWcOk%2FBiX375feU0dpB5rgYvO2H1%2Fimg.png&quot; data-origin-width=&quot;1104&quot; data-origin-height=&quot;84&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;&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUk2JV/btq5tpvzdEJ/ecjugOjKMarKJhsEkKlco1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUk2JV/btq5tpvzdEJ/ecjugOjKMarKJhsEkKlco1/img.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;1012&quot; style=&quot;width: 33.3965%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUk2JV/btq5tpvzdEJ/ecjugOjKMarKJhsEkKlco1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUk2JV%2Fbtq5tpvzdEJ%2FecjugOjKMarKJhsEkKlco1%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;2002&quot; height=&quot;1012&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btDVVM/btq5ufyq1CI/bJUIUSsKhdKwm3IOB2KTKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btDVVM/btq5ufyq1CI/bJUIUSsKhdKwm3IOB2KTKK/img.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; style=&quot;width: 32.139%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btDVVM/btq5ufyq1CI/bJUIUSsKhdKwm3IOB2KTKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtDVVM%2Fbtq5ufyq1CI%2FbJUIUSsKhdKwm3IOB2KTKK%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;2018&quot; height=&quot;1060&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pYcjY/btq5DaiD0Aw/Gid5K0rxP4B6DJwcwj8JA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pYcjY/btq5DaiD0Aw/Gid5K0rxP4B6DJwcwj8JA0/img.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&quot; style=&quot;width: 32.139%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pYcjY/btq5DaiD0Aw/Gid5K0rxP4B6DJwcwj8JA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpYcjY%2Fbtq5DaiD0Aw%2FGid5K0rxP4B6DJwcwj8JA0%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;2018&quot; height=&quot;1060&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBeP67/btq5w6VC42V/JhpHUDgbHKO2WErGjw97Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBeP67/btq5w6VC42V/JhpHUDgbHKO2WErGjw97Kk/img.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;1012&quot; style=&quot;width: 33.3965%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBeP67/btq5w6VC42V/JhpHUDgbHKO2WErGjw97Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBeP67%2Fbtq5w6VC42V%2FJhpHUDgbHKO2WErGjw97Kk%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;2002&quot; height=&quot;1012&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Gngm/btq5vNgXRZA/1k0eYf8JebERWo3yK076q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Gngm/btq5vNgXRZA/1k0eYf8JebERWo3yK076q1/img.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; style=&quot;width: 32.139%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Gngm/btq5vNgXRZA/1k0eYf8JebERWo3yK076q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Gngm%2Fbtq5vNgXRZA%2F1k0eYf8JebERWo3yK076q1%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;2018&quot; height=&quot;1060&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bum7Mv/btq5xuJoQNt/nrl7vy62HL9OrVHfYGd3oK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bum7Mv/btq5xuJoQNt/nrl7vy62HL9OrVHfYGd3oK/img.png&quot; data-origin-width=&quot;2018&quot; data-origin-height=&quot;1060&quot; style=&quot;width: 32.139%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bum7Mv/btq5xuJoQNt/nrl7vy62HL9OrVHfYGd3oK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbum7Mv%2Fbtq5xuJoQNt%2Fnrl7vy62HL9OrVHfYGd3oK%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;2018&quot; height=&quot;1060&quot;/&gt;&lt;/span&gt;&lt;/div&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;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;805&quot; data-origin-height=&quot;260&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SdquY/btq5Da3Z2En/2Ej3bgyZtKyASHi2KwDzp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SdquY/btq5Da3Z2En/2Ej3bgyZtKyASHi2KwDzp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SdquY/btq5Da3Z2En/2Ej3bgyZtKyASHi2KwDzp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSdquY%2Fbtq5Da3Z2En%2F2Ej3bgyZtKyASHi2KwDzp1%2Fimg.png&quot; data-origin-width=&quot;805&quot; data-origin-height=&quot;260&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;아이콘&lt;/b&gt;&lt;/h4&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;1280&quot; data-origin-height=&quot;590&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MsUzI/btq5x9LL7SV/Nd9NeZr8F4KEwRI2ge15XK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MsUzI/btq5x9LL7SV/Nd9NeZr8F4KEwRI2ge15XK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MsUzI/btq5x9LL7SV/Nd9NeZr8F4KEwRI2ge15XK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMsUzI%2Fbtq5x9LL7SV%2FNd9NeZr8F4KEwRI2ge15XK%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;590&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;1280&quot; data-origin-height=&quot;590&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cu3Egq/btq5yC7OH8O/DJTAYRmqqJ4n49BiKNhGT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cu3Egq/btq5yC7OH8O/DJTAYRmqqJ4n49BiKNhGT1/img.png&quot; data-alt=&quot;꽉꽉 채워 넣었다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cu3Egq/btq5yC7OH8O/DJTAYRmqqJ4n49BiKNhGT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcu3Egq%2Fbtq5yC7OH8O%2FDJTAYRmqqJ4n49BiKNhGT1%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;590&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꽉꽉 채운게 마음에 안든다면 &lt;a href=&quot;https://github.com/black7375/Firefox-UI-Fix/tree/photon-style&quot;&gt;Photon Style&lt;/a&gt;을 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;313&quot; data-origin-height=&quot;531&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/upflA/btq57pAj5Wb/Esdjn4jsD704gEWFV6v1w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/upflA/btq57pAj5Wb/Esdjn4jsD704gEWFV6v1w1/img.png&quot; data-alt=&quot;듬성듬성 넣은 아이콘&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/upflA/btq57pAj5Wb/Esdjn4jsD704gEWFV6v1w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FupflA%2Fbtq57pAj5Wb%2FEsdjn4jsD704gEWFV6v1w1%2Fimg.png&quot; data-origin-width=&quot;313&quot; data-origin-height=&quot;531&quot; data-filename=&quot;blob&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;&amp;nbsp;&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;탭모양&lt;/b&gt;&lt;/h4&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;460&quot; data-origin-height=&quot;127&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ELhMG/btq5x9rxD3w/r3sbhTplynlsJaZoblRxe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ELhMG/btq5x9rxD3w/r3sbhTplynlsJaZoblRxe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ELhMG/btq5x9rxD3w/r3sbhTplynlsJaZoblRxe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FELhMG%2Fbtq5x9rxD3w%2Fr3sbhTplynlsJaZoblRxe0%2Fimg.png&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;127&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;툴바에 연결해 보편적이고 상식적인 모양을 만들었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;118&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M22V1/btq5x87eoJT/cO7HTc9MKxmGyEEcIIwWxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M22V1/btq5x87eoJT/cO7HTc9MKxmGyEEcIIwWxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M22V1/btq5x87eoJT/cO7HTc9MKxmGyEEcIIwWxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM22V1%2Fbtq5x87eoJT%2FcO7HTc9MKxmGyEEcIIwWxk%2Fimg.png&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;118&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;그냥 높이를 조정하면 끝인 별거 없는 모양 같아 보이지만 생각보다 구현이 어려웠다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;117&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vp74O/btq5FUVaG8p/wcMrTd0KTzIkNkwhpZUWq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vp74O/btq5FUVaG8p/wcMrTd0KTzIkNkwhpZUWq1/img.png&quot; data-alt=&quot;라운딩이 없는 탭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vp74O/btq5FUVaG8p/wcMrTd0KTzIkNkwhpZUWq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVp74O%2Fbtq5FUVaG8p%2FwcMrTd0KTzIkNkwhpZUWq1%2Fimg.png&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;117&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;98&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D57BN/btq5yCuuywC/jH1xo6udVHrg9CaS1ifMr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D57BN/btq5yCuuywC/jH1xo6udVHrg9CaS1ifMr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D57BN/btq5yCuuywC/jH1xo6udVHrg9CaS1ifMr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD57BN%2Fbtq5yCuuywC%2FjH1xo6udVHrg9CaS1ifMr1%2Fimg.png&quot; data-origin-width=&quot;1920&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;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;99&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b68z7M/btq5GZuUByi/cRmu0zBWPhBcrwN7bo2RSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b68z7M/btq5GZuUByi/cRmu0zBWPhBcrwN7bo2RSk/img.png&quot; data-alt=&quot;전후 비교&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b68z7M/btq5GZuUByi/cRmu0zBWPhBcrwN7bo2RSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb68z7M%2Fbtq5GZuUByi%2FcRmu0zBWPhBcrwN7bo2RSk%2Fimg.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;99&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 Photon 같은 효과를 사용하고 싶다면 역시&amp;nbsp;&lt;a href=&quot;https://github.com/black7375/Firefox-UI-Fix/tree/photon-style&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Photon Style&lt;/a&gt;을&amp;nbsp;사용하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1494&quot; data-origin-height=&quot;119&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BKsA2/btq5FUPEa7P/Bqgnv2IeY3Klnj4whFRZ81/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BKsA2/btq5FUPEa7P/Bqgnv2IeY3Klnj4whFRZ81/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BKsA2/btq5FUPEa7P/Bqgnv2IeY3Klnj4whFRZ81/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/BKsA2/btq5FUPEa7P/Bqgnv2IeY3Klnj4whFRZ81/img.gif&quot; data-origin-width=&quot;1494&quot; data-origin-height=&quot;119&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;탭 상태&lt;/b&gt;&lt;/h4&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;1997&quot; data-origin-height=&quot;118&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdIRh1/btq5BndlBF0/GmjpuVuskTmf00WP6ue3D0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdIRh1/btq5BndlBF0/GmjpuVuskTmf00WP6ue3D0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdIRh1/btq5BndlBF0/GmjpuVuskTmf00WP6ue3D0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdIRh1%2Fbtq5BndlBF0%2FGmjpuVuskTmf00WP6ue3D0%2Fimg.png&quot; data-origin-width=&quot;1997&quot; data-origin-height=&quot;118&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;2018&quot; data-origin-height=&quot;133&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPzUPW/btq5Ggw5JRG/AxTLtRtD3REscWnQ07fXak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPzUPW/btq5Ggw5JRG/AxTLtRtD3REscWnQ07fXak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPzUPW/btq5Ggw5JRG/AxTLtRtD3REscWnQ07fXak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPzUPW%2Fbtq5Ggw5JRG%2FAxTLtRtD3REscWnQ07fXak%2Fimg.png&quot; data-origin-width=&quot;2018&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;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1927&quot; data-origin-height=&quot;121&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvfIWp/btq5DDNAy3D/pIzqsdg5yYzOQHBgbZEig1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvfIWp/btq5DDNAy3D/pIzqsdg5yYzOQHBgbZEig1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvfIWp/btq5DDNAy3D/pIzqsdg5yYzOQHBgbZEig1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvfIWp%2Fbtq5DDNAy3D%2FpIzqsdg5yYzOQHBgbZEig1%2Fimg.png&quot; data-origin-width=&quot;1927&quot; data-origin-height=&quot;121&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;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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;선택&lt;/li&gt;
&lt;li&gt;호버 (마우스 올림)&lt;/li&gt;
&lt;li&gt;텍스트 잘림 (오버플로우)&lt;/li&gt;
&lt;li&gt;탭 오버플로우 (탭 스크롤 모드)&lt;/li&gt;
&lt;li&gt;소리&lt;/li&gt;
&lt;li&gt;PIP (Picture In Picture)&lt;/li&gt;
&lt;li&gt;고정&lt;/li&gt;
&lt;li&gt;컨테이너&lt;/li&gt;
&lt;li&gt;이미지(파비콘) 없음&lt;/li&gt;
&lt;li&gt;제목 바뀜&lt;/li&gt;
&lt;li&gt;로딩 중&lt;/li&gt;
&lt;li&gt;깨짐&lt;/li&gt;
&lt;li&gt;테마&lt;/li&gt;
&lt;li&gt;밀도&lt;/li&gt;
&lt;li&gt;기타 등등&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;36px~240px의 좁은 공간에서 이렇게나 많은 조건들을 따져가며 상호작용이 되고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&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;이제부터 보여주는 다양한 상호작용들을 보면 머리가 어질어질 해질 예정이다.&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/otjlS/btq5BnLaiVa/bxktkejxPBifNgmqX30tVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/otjlS/btq5BnLaiVa/bxktkejxPBifNgmqX30tVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/otjlS/btq5BnLaiVa/bxktkejxPBifNgmqX30tVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FotjlS%2Fbtq5BnLaiVa%2FbxktkejxPBifNgmqX30tVK%2Fimg.png&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;60&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;703&quot; data-origin-height=&quot;72&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmTTOz/btq5FgEaoyz/dqk29a77ccVVogGhwwkgPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmTTOz/btq5FgEaoyz/dqk29a77ccVVogGhwwkgPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmTTOz/btq5FgEaoyz/dqk29a77ccVVogGhwwkgPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmTTOz%2Fbtq5FgEaoyz%2Fdqk29a77ccVVogGhwwkgPk%2Fimg.png&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;72&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;754&quot; data-origin-height=&quot;66&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pG8fn/btq5DElrLvZ/gw19cW6G6Stj2eep0wtUXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pG8fn/btq5DElrLvZ/gw19cW6G6Stj2eep0wtUXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pG8fn/btq5DElrLvZ/gw19cW6G6Stj2eep0wtUXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpG8fn%2Fbtq5DElrLvZ%2Fgw19cW6G6Stj2eep0wtUXk%2Fimg.png&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;66&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;Photon, Proton 둘 다 넓직한 막대 때문에 약간씩 헷갈릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 Photon은 탭과 툴바가 연결되어서 구분이 가능하나 Proton은 혼동이 온다.&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. 선택된 탭, 다중 선택 된 탭, 호버 탭, 아무것도 선택되지 않은 탭&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1383&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7qapN/btq5YqlpU7T/GgrPYdTztijMjVIGOQeHnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7qapN/btq5YqlpU7T/GgrPYdTztijMjVIGOQeHnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7qapN/btq5YqlpU7T/GgrPYdTztijMjVIGOQeHnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7qapN%2Fbtq5YqlpU7T%2FGgrPYdTztijMjVIGOQeHnk%2Fimg.png&quot; data-origin-width=&quot;1383&quot; data-origin-height=&quot;60&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;1374&quot; data-origin-height=&quot;74&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVMmRw/btq5VwNGAyl/IvFS7l68zJAygBkD6cj7U0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVMmRw/btq5VwNGAyl/IvFS7l68zJAygBkD6cj7U0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVMmRw/btq5VwNGAyl/IvFS7l68zJAygBkD6cj7U0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVMmRw%2Fbtq5VwNGAyl%2FIvFS7l68zJAygBkD6cj7U0%2Fimg.png&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;74&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;1478&quot; data-origin-height=&quot;64&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O9p4j/btq5Ruwx67D/car89RBIKuh3ZmQrlRLKB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O9p4j/btq5Ruwx67D/car89RBIKuh3ZmQrlRLKB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O9p4j/btq5Ruwx67D/car89RBIKuh3ZmQrlRLKB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO9p4j%2Fbtq5Ruwx67D%2Fcar89RBIKuh3ZmQrlRLKB0%2Fimg.png&quot; data-origin-width=&quot;1478&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;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Photon, Lepton은 확실한 구분이 가능하나, Proton은 색이 거의 같다.&lt;/p&gt;
&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;361&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB97g4/btq5DEFEVie/92JGb1bR1js7HnhsDj0lKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB97g4/btq5DEFEVie/92JGb1bR1js7HnhsDj0lKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB97g4/btq5DEFEVie/92JGb1bR1js7HnhsDj0lKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB97g4%2Fbtq5DEFEVie%2F92JGb1bR1js7HnhsDj0lKK%2Fimg.png&quot; data-origin-width=&quot;361&quot; data-origin-height=&quot;60&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;362&quot; data-origin-height=&quot;72&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J0J2A/btq5Bmr1gcY/jPUFtBfwkajVm87P106Ikk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J0J2A/btq5Bmr1gcY/jPUFtBfwkajVm87P106Ikk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J0J2A/btq5Bmr1gcY/jPUFtBfwkajVm87P106Ikk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ0J2A%2Fbtq5Bmr1gcY%2FjPUFtBfwkajVm87P106Ikk%2Fimg.png&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;72&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;401&quot; data-origin-height=&quot;65&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4rCgs/btq5DaEf5oE/GrEbhhk5VsIR2zs6qKB9J0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4rCgs/btq5DaEf5oE/GrEbhhk5VsIR2zs6qKB9J0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4rCgs/btq5DaEf5oE/GrEbhhk5VsIR2zs6qKB9J0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4rCgs%2Fbtq5DaEf5oE%2FGrEbhhk5VsIR2zs6qKB9J0%2Fimg.png&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;65&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;Photon은 닫기 버튼 옆에 음소거 아이콘이 존재하여 나름 일관성이 있다.&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;Proton은 파비콘을 대체해버린다. ㅋㅋㅋ&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lepton은 일관성있게 파비콘쪽에 정보들을 몰아서 보여준다.&lt;/p&gt;
&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;4. 선택 + 호버 + 컨테이너 + 음소거&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nAb8P/btq5Fg5etAX/VDCwqXLufL6vPFaL5IPfK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nAb8P/btq5Fg5etAX/VDCwqXLufL6vPFaL5IPfK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nAb8P/btq5Fg5etAX/VDCwqXLufL6vPFaL5IPfK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnAb8P%2Fbtq5Fg5etAX%2FVDCwqXLufL6vPFaL5IPfK0%2Fimg.png&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;60&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;356&quot; data-origin-height=&quot;71&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6PpvK/btq5CBvHlZ8/WiZld0HjT4nWGwArM5AHJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6PpvK/btq5CBvHlZ8/WiZld0HjT4nWGwArM5AHJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6PpvK/btq5CBvHlZ8/WiZld0HjT4nWGwArM5AHJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6PpvK%2Fbtq5CBvHlZ8%2FWiZld0HjT4nWGwArM5AHJ1%2Fimg.png&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;71&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;402&quot; data-origin-height=&quot;63&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/syVva/btq5C9k18ly/lUlqKxITNiC3nlRKUEhIU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/syVva/btq5C9k18ly/lUlqKxITNiC3nlRKUEhIU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/syVva/btq5C9k18ly/lUlqKxITNiC3nlRKUEhIU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsyVva%2Fbtq5C9k18ly%2FlUlqKxITNiC3nlRKUEhIU0%2Fimg.png&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;63&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;Photon, Proton은 투명도를 살짝 제거해주는 수준이지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lepton은 색상을 반전과 투명도 제거가 동반되며 배경 범위도 살짝 넓어져 확실한 강조표시를 해준다.&lt;/p&gt;
&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;5. 선택 + 컨테이너 + 음소거 + PIP&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AdJiX/btq5APG6oQl/iW1Zv9BufBhGOf7PwKhzGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AdJiX/btq5APG6oQl/iW1Zv9BufBhGOf7PwKhzGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AdJiX/btq5APG6oQl/iW1Zv9BufBhGOf7PwKhzGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAdJiX%2Fbtq5APG6oQl%2FiW1Zv9BufBhGOf7PwKhzGk%2Fimg.png&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;60&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;362&quot; data-origin-height=&quot;72&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J0J2A/btq5Bmr1gcY/jPUFtBfwkajVm87P106Ikk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J0J2A/btq5Bmr1gcY/jPUFtBfwkajVm87P106Ikk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J0J2A/btq5Bmr1gcY/jPUFtBfwkajVm87P106Ikk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ0J2A%2Fbtq5Bmr1gcY%2FjPUFtBfwkajVm87P106Ikk%2Fimg.png&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;72&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;400&quot; data-origin-height=&quot;66&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3yl5Y/btq5FcBYWF2/SrFkV57VGRemKakeWeCvT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3yl5Y/btq5FcBYWF2/SrFkV57VGRemKakeWeCvT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3yl5Y/btq5FcBYWF2/SrFkV57VGRemKakeWeCvT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3yl5Y%2Fbtq5FcBYWF2%2FSrFkV57VGRemKakeWeCvT1%2Fimg.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;66&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;Photon, Lepton은 PIP 표시가 있지만, Proton은 없다.&lt;/p&gt;
&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. 선택 + 호버 + 컨테이너 + 음소거 + PIP&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;371&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6cNtm/btq5DaYwDog/uIkhrhzFzYTYiVQ32c14N1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6cNtm/btq5DaYwDog/uIkhrhzFzYTYiVQ32c14N1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6cNtm/btq5DaYwDog/uIkhrhzFzYTYiVQ32c14N1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6cNtm%2Fbtq5DaYwDog%2FuIkhrhzFzYTYiVQ32c14N1%2Fimg.png&quot; data-origin-width=&quot;371&quot; data-origin-height=&quot;60&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;356&quot; data-origin-height=&quot;71&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6PpvK/btq5CBvHlZ8/WiZld0HjT4nWGwArM5AHJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6PpvK/btq5CBvHlZ8/WiZld0HjT4nWGwArM5AHJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6PpvK/btq5CBvHlZ8/WiZld0HjT4nWGwArM5AHJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6PpvK%2Fbtq5CBvHlZ8%2FWiZld0HjT4nWGwArM5AHJ1%2Fimg.png&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;71&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;400&quot; data-origin-height=&quot;65&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wQZdV/btq5Gc2qiJE/DAsv2x68QpkLwH98v41a91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wQZdV/btq5Gc2qiJE/DAsv2x68QpkLwH98v41a91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wQZdV/btq5Gc2qiJE/DAsv2x68QpkLwH98v41a91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwQZdV%2Fbtq5Gc2qiJE%2FDAsv2x68QpkLwH98v41a91%2Fimg.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;65&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;Photon은 PIP 표시기의 투명도가 그대로이지만, Lepton은 투명도 제거가 존재.&lt;/p&gt;
&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;7. 음소거 + 로딩&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqPIlo/btq5yBWEnUO/gXUDjwEKQurX50DkkxACR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqPIlo/btq5yBWEnUO/gXUDjwEKQurX50DkkxACR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqPIlo/btq5yBWEnUO/gXUDjwEKQurX50DkkxACR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqPIlo%2Fbtq5yBWEnUO%2FgXUDjwEKQurX50DkkxACR1%2Fimg.png&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;60&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;345&quot; data-origin-height=&quot;70&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdqCgk/btq5FUVdwYK/z7peKKX7YcYS8NkCg7SAc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdqCgk/btq5FUVdwYK/z7peKKX7YcYS8NkCg7SAc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdqCgk/btq5FUVdwYK/z7peKKX7YcYS8NkCg7SAc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdqCgk%2Fbtq5FUVdwYK%2Fz7peKKX7YcYS8NkCg7SAc0%2Fimg.png&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;70&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;383&quot; data-origin-height=&quot;64&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnjwmB/btq5HCNcppP/7lkC65rTItTDcDotAJxEIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnjwmB/btq5HCNcppP/7lkC65rTItTDcDotAJxEIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnjwmB/btq5HCNcppP/7lkC65rTItTDcDotAJxEIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnjwmB%2Fbtq5HCNcppP%2F7lkC65rTItTDcDotAJxEIK%2Fimg.png&quot; data-origin-width=&quot;383&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;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proton은 로딩 인디케이터를 감춘다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;성능과 UX 트릭글&lt;/a&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;b&gt;8. 컨테이너 + 음소거 + 이미지 없음&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UtQCF/btq5FcaRLKN/XXsFkQo3PV78OKZsGgY1M1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UtQCF/btq5FcaRLKN/XXsFkQo3PV78OKZsGgY1M1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UtQCF/btq5FcaRLKN/XXsFkQo3PV78OKZsGgY1M1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUtQCF%2Fbtq5FcaRLKN%2FXXsFkQo3PV78OKZsGgY1M1%2Fimg.png&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;60&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;351&quot; data-origin-height=&quot;68&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSjN9Z/btq5Fgc9Kr0/0myCUqU7QrnZCkCfbAQLy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSjN9Z/btq5Fgc9Kr0/0myCUqU7QrnZCkCfbAQLy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSjN9Z/btq5Fgc9Kr0/0myCUqU7QrnZCkCfbAQLy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSjN9Z%2Fbtq5Fgc9Kr0%2F0myCUqU7QrnZCkCfbAQLy1%2Fimg.png&quot; data-origin-width=&quot;351&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;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;387&quot; data-origin-height=&quot;63&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8pQDX/btq5GfycQel/n2KpH4OqgYhERvs4iBd43K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8pQDX/btq5GfycQel/n2KpH4OqgYhERvs4iBd43K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8pQDX/btq5GfycQel/n2KpH4OqgYhERvs4iBd43K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8pQDX%2Fbtq5GfycQel%2Fn2KpH4OqgYhERvs4iBd43K%2Fimg.png&quot; data-origin-width=&quot;387&quot; data-origin-height=&quot;63&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;Photon, Proton은 지금까지 봐왔던 방식 그대로이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lepton은 이미지가 존재하지 않을때만 소리 아이콘으로 파비콘 자리를 대신한다.&lt;/p&gt;
&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;9. 컨테이너 + 음소거 + PIP + 이미지 없음&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dq7a1/btq5C9ZCmhf/yqOycxxmDYMIYTdH1ipxX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dq7a1/btq5C9ZCmhf/yqOycxxmDYMIYTdH1ipxX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dq7a1/btq5C9ZCmhf/yqOycxxmDYMIYTdH1ipxX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDq7a1%2Fbtq5C9ZCmhf%2FyqOycxxmDYMIYTdH1ipxX0%2Fimg.png&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;60&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;351&quot; data-origin-height=&quot;68&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DDY6R/btq5FchF16Q/3D3WXPwcc0cJhUUuYY38Hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DDY6R/btq5FchF16Q/3D3WXPwcc0cJhUUuYY38Hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DDY6R/btq5FchF16Q/3D3WXPwcc0cJhUUuYY38Hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDDY6R%2Fbtq5FchF16Q%2F3D3WXPwcc0cJhUUuYY38Hk%2Fimg.png&quot; data-origin-width=&quot;351&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;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;65&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXGE03/btq5AQlK4bH/cKkMkaRoY9oY3mCJTebps0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXGE03/btq5AQlK4bH/cKkMkaRoY9oY3mCJTebps0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXGE03/btq5AQlK4bH/cKkMkaRoY9oY3mCJTebps0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXGE03%2Fbtq5AQlK4bH%2FcKkMkaRoY9oY3mCJTebps0%2Fimg.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;65&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;Photon은 사운드와 PIP 표시기가 동시에 필요한 경우 강제로 대체 파비콘이 나타난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proton은 여전히 컨테이너와 소리정보만 표시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lepton은 파비콘 대신 사운드 표시기로 대체되며, PIP도 봐왔던 대로 표시된다.&lt;/p&gt;
&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;10. 호버 + 컨테이너 + 음소거 + 이미지 없음&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/22Vn0/btq5yCnIMoc/SnCvvckDvwS3bBkTMIrgF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/22Vn0/btq5yCnIMoc/SnCvvckDvwS3bBkTMIrgF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/22Vn0/btq5yCnIMoc/SnCvvckDvwS3bBkTMIrgF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F22Vn0%2Fbtq5yCnIMoc%2FSnCvvckDvwS3bBkTMIrgF1%2Fimg.png&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;60&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;356&quot; data-origin-height=&quot;71&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6PpvK/btq5CBvHlZ8/WiZld0HjT4nWGwArM5AHJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6PpvK/btq5CBvHlZ8/WiZld0HjT4nWGwArM5AHJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6PpvK/btq5CBvHlZ8/WiZld0HjT4nWGwArM5AHJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6PpvK%2Fbtq5CBvHlZ8%2FWiZld0HjT4nWGwArM5AHJ1%2Fimg.png&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;71&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;380&quot; data-origin-height=&quot;65&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNRbYO/btq5G17wtjs/kPGuBfNHAkkekojjk0So8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNRbYO/btq5G17wtjs/kPGuBfNHAkkekojjk0So8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNRbYO/btq5G17wtjs/kPGuBfNHAkkekojjk0So8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNRbYO%2Fbtq5G17wtjs%2FkPGuBfNHAkkekojjk0So8k%2Fimg.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;65&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;Lepton은 호버동작을 강조해주기 위해 컨테이너 표시를 잠시 감춘다.&lt;/p&gt;
&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;11. 선택 + 컨테이너 + 음소거 + 고정&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;90&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pp3IB/btq5FU1U19e/fQkx71Q1tmtkmXWn18D4yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pp3IB/btq5FU1U19e/fQkx71Q1tmtkmXWn18D4yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pp3IB/btq5FU1U19e/fQkx71Q1tmtkmXWn18D4yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPp3IB%2Fbtq5FU1U19e%2FfQkx71Q1tmtkmXWn18D4yk%2Fimg.png&quot; data-origin-width=&quot;90&quot; data-origin-height=&quot;60&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;88&quot; data-origin-height=&quot;73&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d2Ljdp/btq5DaqGVCm/cfh9eWjgnD9cEAp43ijCo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d2Ljdp/btq5DaqGVCm/cfh9eWjgnD9cEAp43ijCo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d2Ljdp/btq5DaqGVCm/cfh9eWjgnD9cEAp43ijCo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd2Ljdp%2Fbtq5DaqGVCm%2Fcfh9eWjgnD9cEAp43ijCo1%2Fimg.png&quot; data-origin-width=&quot;88&quot; data-origin-height=&quot;73&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;102&quot; data-origin-height=&quot;65&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JJKBN/btq5FbQC9TQ/XgNA0tIkQD5w7GDocMp0tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JJKBN/btq5FbQC9TQ/XgNA0tIkQD5w7GDocMp0tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JJKBN/btq5FbQC9TQ/XgNA0tIkQD5w7GDocMp0tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJJKBN%2Fbtq5FbQC9TQ%2FXgNA0tIkQD5w7GDocMp0tk%2Fimg.png&quot; data-origin-width=&quot;102&quot; data-origin-height=&quot;65&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;Photon은 PIP가 있을때와 비슷한 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proton은 지금까지 꾿꾿히 지켜왔던 일관성을 져버리고, Photon 방식과 유사하게 표시된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lepton은 Chromium의 작은 탭 선택 때 닫기버튼에서 영감을 얻어 닫기 버튼을 표시해준다.&lt;/p&gt;
&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;915&quot; data-origin-height=&quot;144&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baH9Lk/btq59M9I2J6/v0b0YMUE2yFDkrwpDqdTT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baH9Lk/btq59M9I2J6/v0b0YMUE2yFDkrwpDqdTT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baH9Lk/btq59M9I2J6/v0b0YMUE2yFDkrwpDqdTT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaH9Lk%2Fbtq59M9I2J6%2Fv0b0YMUE2yFDkrwpDqdTT1%2Fimg.png&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;144&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;&lt;b&gt;12. 선택 + 호버 + 컨테이너 + 음소거 + 고정&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;92&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8HeM2/btq5Fg5eWkK/uWETkk0oZXgOmogywYJXz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8HeM2/btq5Fg5eWkK/uWETkk0oZXgOmogywYJXz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8HeM2/btq5Fg5eWkK/uWETkk0oZXgOmogywYJXz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8HeM2%2Fbtq5Fg5eWkK%2FuWETkk0oZXgOmogywYJXz1%2Fimg.png&quot; data-origin-width=&quot;92&quot; data-origin-height=&quot;60&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;87&quot; data-origin-height=&quot;74&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wE8ID/btq5yDmIvYx/MivtF5pZjkWeBkTrxKTjyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wE8ID/btq5yDmIvYx/MivtF5pZjkWeBkTrxKTjyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wE8ID/btq5yDmIvYx/MivtF5pZjkWeBkTrxKTjyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwE8ID%2Fbtq5yDmIvYx%2FMivtF5pZjkWeBkTrxKTjyk%2Fimg.png&quot; data-origin-width=&quot;87&quot; data-origin-height=&quot;74&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;104&quot; data-origin-height=&quot;69&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1HgVS/btq5Fg5gIzB/jU500eSIPp0Bn37fabW94k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1HgVS/btq5Fg5gIzB/jU500eSIPp0Bn37fabW94k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1HgVS/btq5Fg5gIzB/jU500eSIPp0Bn37fabW94k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1HgVS%2Fbtq5Fg5gIzB%2FjU500eSIPp0Bn37fabW94k%2Fimg.png&quot; data-origin-width=&quot;104&quot; data-origin-height=&quot;69&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;107&quot; data-origin-height=&quot;67&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JsTsQ/btq5G0UVMX7/LyQ5ACmkkP3rMKNK87Cbp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JsTsQ/btq5G0UVMX7/LyQ5ACmkkP3rMKNK87Cbp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JsTsQ/btq5G0UVMX7/LyQ5ACmkkP3rMKNK87Cbp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJsTsQ%2Fbtq5G0UVMX7%2FLyQ5ACmkkP3rMKNK87Cbp1%2Fimg.png&quot; data-origin-width=&quot;107&quot; data-origin-height=&quot;67&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;Photon은 투명도만 제거해주던게 색반전까지 시켜준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proton은 투명도 제거에 배경이 살짝 넓어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lepton은 역시 Hover 동작에 컨테이너 표시가 사라져 집중하는데 도움을 주며, 사운드 아이콘과 닫기 버튼은 원래 방식대로 이용가능하다.&lt;/p&gt;
&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;13. 선택 + 컨테이너 + 음소거 + 고정 + 로딩&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;89&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mdyEf/btq5FchBGXo/jtuBaS7igEKgCvffTU4KR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mdyEf/btq5FchBGXo/jtuBaS7igEKgCvffTU4KR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mdyEf/btq5FchBGXo/jtuBaS7igEKgCvffTU4KR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmdyEf%2Fbtq5FchBGXo%2FjtuBaS7igEKgCvffTU4KR0%2Fimg.png&quot; data-origin-width=&quot;89&quot; data-origin-height=&quot;60&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;90&quot; data-origin-height=&quot;75&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6SGSx/btq5Ge6W3yL/A1GKwobHbW3VIzsVhL3wNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6SGSx/btq5Ge6W3yL/A1GKwobHbW3VIzsVhL3wNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6SGSx/btq5Ge6W3yL/A1GKwobHbW3VIzsVhL3wNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6SGSx%2Fbtq5Ge6W3yL%2FA1GKwobHbW3VIzsVhL3wNk%2Fimg.png&quot; data-origin-width=&quot;90&quot; data-origin-height=&quot;75&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;95&quot; data-origin-height=&quot;67&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVB1Np/btq5GZ2Ou3X/b4CkkOOJt8aLZBqZvrCoPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVB1Np/btq5GZ2Ou3X/b4CkkOOJt8aLZBqZvrCoPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVB1Np/btq5GZ2Ou3X/b4CkkOOJt8aLZBqZvrCoPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVB1Np%2Fbtq5GZ2Ou3X%2Fb4CkkOOJt8aLZBqZvrCoPk%2Fimg.png&quot; data-origin-width=&quot;95&quot; data-origin-height=&quot;67&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;Hover와 마찬가지로 작업 중이란 표시를 해주기 위해 잠시 컨테이너 표시가 사라진다.&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;14. 호버 + 컨테이너 + 음소거 + 제목 변경&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;87&quot; data-origin-height=&quot;60&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btITDI/btq5HLiTaT0/PK9ofhviT39YjExLt3adh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btITDI/btq5HLiTaT0/PK9ofhviT39YjExLt3adh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btITDI/btq5HLiTaT0/PK9ofhviT39YjExLt3adh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtITDI%2Fbtq5HLiTaT0%2FPK9ofhviT39YjExLt3adh1%2Fimg.png&quot; data-origin-width=&quot;87&quot; data-origin-height=&quot;60&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;87&quot; data-origin-height=&quot;74&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vfgGe/btq5FUnnF77/SvwP1BR8HrmsijStWbk2n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vfgGe/btq5FUnnF77/SvwP1BR8HrmsijStWbk2n0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vfgGe/btq5FUnnF77/SvwP1BR8HrmsijStWbk2n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvfgGe%2Fbtq5FUnnF77%2FSvwP1BR8HrmsijStWbk2n0%2Fimg.png&quot; data-origin-width=&quot;87&quot; data-origin-height=&quot;74&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;99&quot; data-origin-height=&quot;67&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GmY81/btq5L3YC7XZ/X6MHKKhThyu90Hx8qt5CD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GmY81/btq5L3YC7XZ/X6MHKKhThyu90Hx8qt5CD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GmY81/btq5L3YC7XZ/X6MHKKhThyu90Hx8qt5CD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGmY81%2Fbtq5L3YC7XZ%2FX6MHKKhThyu90Hx8qt5CD0%2Fimg.png&quot; data-origin-width=&quot;99&quot; data-origin-height=&quot;67&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;개인적으로 Photon 방식을 선호한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proton도 나쁘지 않게 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lepton은 제목 변경 표시인 점과 컨테이너 선의 표시를 결합하여 점선을 보여준다.&lt;/p&gt;
&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;15.&amp;nbsp; 컨테이너 + 아이콘 없음 + 제목이 길 때&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;100&quot; data-origin-height=&quot;100&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MKhbb/btq59OmaMom/ndI9Dg9hYatiispHo6NGnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MKhbb/btq59OmaMom/ndI9Dg9hYatiispHo6NGnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MKhbb/btq59OmaMom/ndI9Dg9hYatiispHo6NGnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMKhbb%2Fbtq59OmaMom%2FndI9Dg9hYatiispHo6NGnK%2Fimg.png&quot; data-origin-width=&quot;100&quot; data-origin-height=&quot;100&quot; data-filename=&quot;blob&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;99&quot; data-origin-height=&quot;100&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WGN5J/btq52SYbYtR/DCswcWGMLPYKn4sT9lfIZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WGN5J/btq52SYbYtR/DCswcWGMLPYKn4sT9lfIZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WGN5J/btq52SYbYtR/DCswcWGMLPYKn4sT9lfIZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWGN5J%2Fbtq52SYbYtR%2FDCswcWGMLPYKn4sT9lfIZK%2Fimg.png&quot; data-origin-width=&quot;99&quot; data-origin-height=&quot;100&quot; data-filename=&quot;blob&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;109&quot; data-origin-height=&quot;100&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beoHLv/btq54qNyXa1/9PAi2NJ9bwkTfQocSSqoO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beoHLv/btq54qNyXa1/9PAi2NJ9bwkTfQocSSqoO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beoHLv/btq54qNyXa1/9PAi2NJ9bwkTfQocSSqoO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeoHLv%2Fbtq54qNyXa1%2F9PAi2NJ9bwkTfQocSSqoO0%2Fimg.png&quot; data-origin-width=&quot;109&quot; data-origin-height=&quot;100&quot; data-filename=&quot;blob&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;Photon과 Proton에서 ced가 잘 안보이는 반면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lepton에서는 d도 c수준까지 보여준다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Photon: 최대한 많은 정보를 노출함&lt;/li&gt;
&lt;li&gt;Proton: 간단하여 생략되는 정보가 많음&lt;/li&gt;
&lt;li&gt;Lepton: 간단하면서도 많은 정보를 일관적으로 보여줌&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;/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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;새 탭 컨텐츠&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;공간 낭비를 제거해 눈에 띄도록 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2uiMP/btq5Bl0qNA6/QZtvzKjXmNWJkTI2awXsG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2uiMP/btq5Bl0qNA6/QZtvzKjXmNWJkTI2awXsG0/img.png&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;338&quot; data-filename=&quot;blob&quot; style=&quot;width: 48.5179%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2uiMP/btq5Bl0qNA6/QZtvzKjXmNWJkTI2awXsG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2uiMP%2Fbtq5Bl0qNA6%2FQZtvzKjXmNWJkTI2awXsG0%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;668&quot; height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ewqs7c/btq5FVzo0Aq/yvFNKabQUKuesFLbjpx4kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ewqs7c/btq5FVzo0Aq/yvFNKabQUKuesFLbjpx4kK/img.png&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;342&quot; data-filename=&quot;blob&quot; style=&quot;width: 50.3193%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ewqs7c/btq5FVzo0Aq/yvFNKabQUKuesFLbjpx4kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fewqs7c%2Fbtq5FVzo0Aq%2FyvFNKabQUKuesFLbjpx4kK%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;701&quot; height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;/div&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;Proton 다크모드의 강조색으로 바꿨다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;235&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQyUN7/btq5G1snLtx/2UxDKxHGLiI5ypbL9q7fnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQyUN7/btq5G1snLtx/2UxDKxHGLiI5ypbL9q7fnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQyUN7/btq5G1snLtx/2UxDKxHGLiI5ypbL9q7fnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQyUN7%2Fbtq5G1snLtx%2F2UxDKxHGLiI5ypbL9q7fnk%2Fimg.png&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;235&quot; data-filename=&quot;blob&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;701&quot; data-origin-height=&quot;260&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dh27i/btq5FW59MSo/jplqxwEjRYhDxGxgnbMxcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dh27i/btq5FW59MSo/jplqxwEjRYhDxGxgnbMxcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dh27i/btq5FW59MSo/jplqxwEjRYhDxGxgnbMxcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDh27i%2Fbtq5FW59MSo%2FjplqxwEjRYhDxGxgnbMxcK%2Fimg.png&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;260&quot; data-filename=&quot;blob&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;소감&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;정신차리고 보니 새로운 버전업 수준 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갠취에 맞춰서인지 크롬, 파폭(Photon, Proton)보다 훨씬 이쁘다고 느낌.&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q3vrU/btq5ve8pFBX/sAr16n3HNNy2qHfFwJWGtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q3vrU/btq5ve8pFBX/sAr16n3HNNy2qHfFwJWGtK/img.png&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;817&quot; style=&quot;width: 35.6167%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q3vrU/btq5ve8pFBX/sAr16n3HNNy2qHfFwJWGtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ3vrU%2Fbtq5ve8pFBX%2FsAr16n3HNNy2qHfFwJWGtK%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;376&quot; height=&quot;817&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfWP8Z/btq5C946P4S/Ilx7owrWkBe5StphP1w5C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfWP8Z/btq5C946P4S/Ilx7owrWkBe5StphP1w5C0/img.png&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;568&quot; style=&quot;width: 63.2205%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfWP8Z/btq5C946P4S/Ilx7owrWkBe5StphP1w5C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfWP8Z%2Fbtq5C946P4S%2FIlx7owrWkBe5StphP1w5C0%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;464&quot; height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;/div&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;페이지에서 찾기는 페이지 소스 보기랑 혼동되서 Proton Fix에 아예 소스 보기용 아이콘 아이콘으로 넣어버렸다.&lt;/p&gt;
&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;앞으로 실험적으로 JS도 도입(대신 설치과정이 복잡해짐)하면 없어진 북마크 애니메이션과&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;843&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KAzyo/btq6fUmNdsA/HN2dKCOkPkdzEzdcD269E0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KAzyo/btq6fUmNdsA/HN2dKCOkPkdzEzdcD269E0/img.gif&quot; data-alt=&quot;아무 반응도 없다 ㅠㅠ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KAzyo/btq6fUmNdsA/HN2dKCOkPkdzEzdcD269E0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/KAzyo/btq6fUmNdsA/HN2dKCOkPkdzEzdcD269E0/img.gif&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;843&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;411&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r0MgW/btq6f8rJ77l/WPqecCSuFQ5Z0hn53hDbr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r0MgW/btq6f8rJ77l/WPqecCSuFQ5Z0hn53hDbr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r0MgW/btq6f8rJ77l/WPqecCSuFQ5Z0hn53hDbr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr0MgW%2Fbtq6f8rJ77l%2FWPqecCSuFQ5Z0hn53hDbr1%2Fimg.png&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;411&quot; data-filename=&quot;blob&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;540&quot; data-origin-height=&quot;154&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beiNSI/btq6aPGEEr0/1uVsbDP8pRgSy9BbwW3AK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beiNSI/btq6aPGEEr0/1uVsbDP8pRgSy9BbwW3AK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beiNSI/btq6aPGEEr0/1uVsbDP8pRgSy9BbwW3AK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeiNSI%2Fbtq6aPGEEr0%2F1uVsbDP8pRgSy9BbwW3AK1%2Fimg.png&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;154&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;3. 제언&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정식 Proton 디자인은 6월 1일에 출시 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.mozilla.org/firefox/new-firefox-coming-june-1/&quot;&gt;https://blog.mozilla.org/firefox/new-firefox-coming-june-1/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1621632878114&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;Behind the design of the fresh new Firefox coming June 1 &amp;ndash; The Firefox Frontier&quot; data-og-description=&quot;A fresh new Firefox is coming your way on June 1. Worry less, get more done and feel good about what&amp;rsquo;s on the horizon. That&amp;rsquo;s the energy we all need in 2021.&quot; data-og-host=&quot;blog.mozilla.org&quot; data-og-source-url=&quot;https://blog.mozilla.org/firefox/new-firefox-coming-june-1/&quot; data-og-url=&quot;https://blog.mozilla.org/firefox/new-firefox-coming-june-1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/buw0vp/hyKhyytEpw/KJK7O0muC1ahSeocN6Ugk1/img.png?width=1200&amp;amp;height=770&amp;amp;face=0_0_1200_770,https://scrap.kakaocdn.net/dn/BZWJi/hyKhAQACnq/MRZI3VkYnPnnmAFyJ6zoj0/img.png?width=1200&amp;amp;height=770&amp;amp;face=0_0_1200_770&quot;&gt;&lt;a href=&quot;https://blog.mozilla.org/firefox/new-firefox-coming-june-1/&quot; data-source-url=&quot;https://blog.mozilla.org/firefox/new-firefox-coming-june-1/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/buw0vp/hyKhyytEpw/KJK7O0muC1ahSeocN6Ugk1/img.png?width=1200&amp;amp;height=770&amp;amp;face=0_0_1200_770,https://scrap.kakaocdn.net/dn/BZWJi/hyKhAQACnq/MRZI3VkYnPnnmAFyJ6zoj0/img.png?width=1200&amp;amp;height=770&amp;amp;face=0_0_1200_770');&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;Behind the design of the fresh new Firefox coming June 1 &amp;ndash; The Firefox Frontier&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A fresh new Firefox is coming your way on June 1. Worry less, get more done and feel good about what&amp;rsquo;s on the horizon. That&amp;rsquo;s the energy we all need in 2021.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.mozilla.org&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;이 글이 마음에 들었다면,&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;a href=&quot;https://github.com/black7375/Firefox-UI-Fix/tree/interactive-js/JS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/black7375/Firefox-UI-Fix/tree/interactive-js/JS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;105&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HL7ZQ/btq5vd2EEDe/2eGmOviWcOMdkdHRp2HROk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HL7ZQ/btq5vd2EEDe/2eGmOviWcOMdkdHRp2HROk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HL7ZQ/btq5vd2EEDe/2eGmOviWcOMdkdHRp2HROk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/HL7ZQ/btq5vd2EEDe/2eGmOviWcOMdkdHRp2HROk/img.gif&quot; data-origin-width=&quot;1689&quot; data-origin-height=&quot;105&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;</description>
      <category>IT/UX</category>
      <category>firefox</category>
      <category>디자인</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/83</guid>
      <comments>https://black7375.tistory.com/83#entry83comment</comments>
      <pubDate>Tue, 25 May 2021 09:15:06 +0900</pubDate>
    </item>
    <item>
      <title>[스압/데이터주의] 웹 최적화 방식 모음 - 5. 빌드</title>
      <link>https://black7375.tistory.com/82</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/72&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 0. 전반적 원칙과 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/73&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 1. 다운로드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/74&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 2. 파싱 및 렌더링 트리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/79&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3. Layout 및 렌더링&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/80&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3.3 UX 트릭&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/81&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 4. 로드 후&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/82&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 5. 빌드(현재)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 빌드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/nodejs/node&quot;&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;패키지 설치와 의존성 관리를 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/npm/cli&quot;&gt;NPM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;모노레포 관리를 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/lerna/lerna&quot;&gt;Lerna&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;자바스크립트를 정적으로 만들기 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/Microsoft/TypeScript&quot;&gt;Typescript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;트랜스파일링이나 컴파일을 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/babel/babel&quot;&gt;Babel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;코드 퀄리티를 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/eslint/eslint&quot;&gt;ESLint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;코드 스타일을 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/prettier/prettier&quot;&gt;Prettier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;모듈 번들링을 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/webpack/webpack&quot;&gt;Webpack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;모듈 테스트를 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/facebook/jest&quot;&gt;Jest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;E2E 테스트를 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/cypress-io/cypress&quot;&gt;Cypress&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;컴포넌트 개발과 문서화를 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/storybookjs/storybook&quot;&gt;Storybook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CI/CD를 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/features/actions&quot;&gt;Github Action&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;cargo로 &lt;a href=&quot;https://doc.rust-lang.org/cargo/commands/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;패키지, 워크스페이스, 빌드. 테스트&lt;/a&gt; 다해먹고 &lt;a href=&quot;https://github.com/rust-lang/rustfmt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;rustfmt&lt;/a&gt;와 &lt;a href=&quot;https://github.com/rust-lang/rust-clippy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;rust-clippy&lt;/a&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;5.1 패키지 설치와 의존성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&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;&lt;a href=&quot;https://javascript.plainenglish.io/an-abbreviated-history-of-javascript-package-managers-f9797be7cf0e&quot;&gt;An abbreviated history of JavaScript package managers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.logrocket.com/javascript-package-managers-compared/&quot;&gt;JavaScript package managers compared: npm, Yarn, or pnpm?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot;&gt;node_modules로부터 우리를 구원해 줄 Yarn Berry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yceffort.kr/2021/07/javascript-dependency-manager-dont-mange-dependencies&quot;&gt;자바스크립트 의존성 관리자(npm, yarn, pnpm)에서 보다 더 의존성 관리 잘하는 방법&lt;/a&gt;&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;초반에 Npm이 만들어진 이유는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://nodejs.org/fa/blog/npm/npm-1-0-global-vs-local-installation/&quot;&gt;글로벌이 아닌 로컬 패키지&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;예를 들어 여러 패키지가 한 공통 패키지를 참조할 때 공통패키지에서 브레이킹 체인지가 발생한다면 어떻게 할 것인가?&lt;/p&gt;
&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;a href=&quot;https://news.hada.io/topic?id=5724&quot;&gt;Colors.js&amp;nbsp;/&amp;nbsp;Faker.js&amp;nbsp;개발자가&amp;nbsp;무한루프&amp;nbsp;코드를&amp;nbsp;삽입하고,&amp;nbsp;Repo의&amp;nbsp;코드를&amp;nbsp;모두&amp;nbsp;지움&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://yceffort.kr/2022/01/npm-colors-fakerjs&quot;&gt;colors.js와&amp;nbsp;faker.js&amp;nbsp;사태가&amp;nbsp;준&amp;nbsp;교훈&lt;/a&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://wiki.archlinux.org/title/official_repositories&quot;&gt;core, extra, community, aur등&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;순수함수형 패키지 매니저인&amp;nbsp;&lt;a href=&quot;https://nixos.org/guides/how-nix-works.html&quot;&gt;nix가 작동하는 방식&lt;/a&gt;으로 /nix/store/b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z-firefox-33.1/처럼&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rEOxh/btrCvV2Oi3F/CYpwjJKYiKOOmkWkey0kkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rEOxh/btrCvV2Oi3F/CYpwjJKYiKOOmkWkey0kkk/img.png&quot; data-origin-width=&quot;451&quot; data-origin-height=&quot;250&quot; data-is-animation=&quot;false&quot; style=&quot;width: 57.5914%; margin-right: 10px;&quot; data-widthpercent=&quot;58.27&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rEOxh/btrCvV2Oi3F/CYpwjJKYiKOOmkWkey0kkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrEOxh%2FbtrCvV2Oi3F%2FCYpwjJKYiKOOmkWkey0kkk%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;451&quot; height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAawj7/btrCApBl3hQ/cE0Xbf2Ew1jK9RUKLUbuI0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAawj7/btrCApBl3hQ/cE0Xbf2Ew1jK9RUKLUbuI0/img.jpg&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;774&quot; data-is-animation=&quot;false&quot; style=&quot;width: 41.2458%;&quot; data-widthpercent=&quot;41.73&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAawj7/btrCApBl3hQ/cE0Xbf2Ew1jK9RUKLUbuI0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAawj7%2FbtrCApBl3hQ%2FcE0Xbf2Ew1jK9RUKLUbuI0%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;1000&quot; height=&quot;774&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://soshace.com/setting-up-automated-semantic-versioning-for-your-nodejs-project/&quot;&gt;Setting&amp;nbsp;Up&amp;nbsp;Automated&amp;nbsp;Semantic&amp;nbsp;Versioning&amp;nbsp;For&amp;nbsp;Your&amp;nbsp;NodeJS&amp;nbsp;Project&lt;/a&gt;,&lt;a href=&quot;https://stackoverflow.com/questions/22343224/whats-the-difference-between-tilde-and-caret-in-package-json#&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;What's&amp;nbsp;the&amp;nbsp;difference&amp;nbsp;between&amp;nbsp;tilde(~)&amp;nbsp;and&amp;nbsp;caret(^)&amp;nbsp;in&amp;nbsp;package.json?&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;Npm은 몇가지 제한으로 꽤 현명하게 동작한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로컬 패키지&lt;br /&gt;프로젝트 별로 필요한 버전의 패키지를 달리 설치할 수 있으며, ./node_modules에 위치하므로 제거도 간편하다.&lt;/li&gt;
&lt;li&gt;중첩된 종속성구조&lt;br /&gt;서로 다른 버전의 하위 종속성을 가지고 있을시 중첩적으로 존재하여 여러가지 버전을 가짐&lt;/li&gt;
&lt;li&gt;SemVer와 업데이트&lt;br /&gt;&lt;a href=&quot;https://samver.org/&quot;&gt;SemVer(Semantic Versioning)&lt;/a&gt;을 사용함으로서 브레이킹 체인지, 기능 추가, 버그수정를 나눌 수 있게 되었고, 업데이트할 패키지 버전범위를 제어할 수 있게되었다.&lt;br /&gt;특히 틸트(~)와 캐럿(^)을 이용한 방식은 아이디어가 좋다. [&lt;a href=&quot;https://blog.outsider.ne.kr/1041&quot;&gt;npm&amp;nbsp;package.json에서&amp;nbsp;틸드(~)&amp;nbsp;대신&amp;nbsp;캐럿(^)&amp;nbsp;사용하기&lt;/a&gt;]&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩된 종속성 구조의 경우, 윈도우의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://mspoweruser.com/ntfs-260-character-windows-10/&quot;&gt;파일 경로 길이 제한&lt;/a&gt;등 때문에 호이스팅을 통해 종속성 트리를 평평하게 만들었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKrtgH/btrCwf1AlIn/76L55uqBqxvs2O5TAwtrq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKrtgH/btrCwf1AlIn/76L55uqBqxvs2O5TAwtrq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKrtgH/btrCwf1AlIn/76L55uqBqxvs2O5TAwtrq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKrtgH%2FbtrCwf1AlIn%2F76L55uqBqxvs2O5TAwtrq0%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;934&quot; height=&quot;504&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;504&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;yarn(v1)은 성능과 정확한 버전이 명시된 의존성 파일로 주목을 받았으며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://blog.npmjs.org/post/161081169345/v500&quot;&gt;Npm v5&lt;/a&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;yarn.lock이란 락파일 제공&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;그러나 node_modules와 관련된 문제는 많았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2yg0d/btrCwGLoIRP/7od7dvfaDM7e8KwQ8UMrB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2yg0d/btrCwGLoIRP/7od7dvfaDM7e8KwQ8UMrB0/img.png&quot; data-alt=&quot;유령종속성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2yg0d/btrCwGLoIRP/7od7dvfaDM7e8KwQ8UMrB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2yg0d%2FbtrCwGLoIRP%2F7od7dvfaDM7e8KwQ8UMrB0%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;274&quot; height=&quot;536&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;536&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;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;직접 설치하지 않은 패키지에 접근이 가능&lt;/li&gt;
&lt;li&gt;종속성 트리 병합 알고리즘이 복잡&lt;/li&gt;
&lt;li&gt;일부 패키지는 여전히 flatten 되지 않고 중첩적으로 존재&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pnpm은&amp;nbsp; 심볼릭 링크와 하드 링크를 이용해 동작한다. [&lt;a href=&quot;https://medium.com/pnpm/why-should-we-use-pnpm-75ca4bfe7d93&quot;&gt;Why&amp;nbsp;should&amp;nbsp;we&amp;nbsp;use&amp;nbsp;pnpm?&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/swfxD/btrCzZ319LR/szRFKG1bxsRJq1Ii2iicI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/swfxD/btrCzZ319LR/szRFKG1bxsRJq1Ii2iicI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/swfxD/btrCzZ319LR/szRFKG1bxsRJq1Ii2iicI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FswfxD%2FbtrCzZ319LR%2FszRFKG1bxsRJq1Ii2iicI0%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;800&quot; height=&quot;546&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://simpleisit.tistory.com/72&quot;&gt;하드 링크와 심볼릭 링크&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;링크를 사용하므로, 캐시로부터 복사하는 yarn(v1)보다 빠르며 디스크 공간이 절약&lt;/li&gt;
&lt;li&gt;각 패키지는 고유한 종속성을 가지지만, 평평하게 유지된 패키지로 링크하여 경로 길이 해결&lt;/li&gt;
&lt;li&gt;node_modules에 유령 종속성이 없도록 깔끔하게 유지&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ7qLL/btrCyX6sVaR/Exk0TAurD4RhhhUytdQimK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ7qLL/btrCyX6sVaR/Exk0TAurD4RhhhUytdQimK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ7qLL/btrCyX6sVaR/Exk0TAurD4RhhhUytdQimK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ7qLL%2FbtrCyX6sVaR%2FExk0TAurD4RhhhUytdQimK%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;1280&quot; height=&quot;610&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://pnpm.io/motivation&quot;&gt;Motivation&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;a href=&quot;https://github.com/yarnpkg/yarn/issues/499&quot;&gt;1&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/yarnpkg/yarn/issues/1761&quot;&gt;2&lt;/a&gt;]&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;운영체제와 파일시스템에 따라 다름&lt;/li&gt;
&lt;li&gt;watching의 동작&lt;/li&gt;
&lt;li&gt;재귀 관련 오류&lt;/li&gt;
&lt;li&gt;다른 툴들과의 호환성&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;yarn (v2, berry)는 node_modules의 호이스팅 문제를 해결하고, 의존성 탐색과 용량문제를 해결하기 위해&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dabdjp/btrCAvVVG8k/e32LwKFzJkNDEM6ooPJ8MK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dabdjp/btrCAvVVG8k/e32LwKFzJkNDEM6ooPJ8MK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dabdjp/btrCAvVVG8k/e32LwKFzJkNDEM6ooPJ8MK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdabdjp%2FbtrCAvVVG8k%2Fe32LwKFzJkNDEM6ooPJ8MK%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;1000&quot; height=&quot;420&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;pnp(Plug'n'Play)와 ZipFS(Zip Filesystem)을 도입했다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kXzDf/btrCyfsKf5H/58XKWS2eTUala5kJKAFShk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kXzDf/btrCyfsKf5H/58XKWS2eTUala5kJKAFShk/img.png&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;349&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.9843%; margin-right: 10px;&quot; data-widthpercent=&quot;52.6&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kXzDf/btrCyfsKf5H/58XKWS2eTUala5kJKAFShk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkXzDf%2FbtrCyfsKf5H%2F58XKWS2eTUala5kJKAFShk%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;692&quot; height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMBDkg/btrCyXZHPSs/9SkWRG2kYg6YkSginqS4XK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMBDkg/btrCyXZHPSs/9SkWRG2kYg6YkSginqS4XK/img.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;573&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.8529%;&quot; data-widthpercent=&quot;47.4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMBDkg/btrCyXZHPSs/9SkWRG2kYg6YkSginqS4XK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMBDkg%2FbtrCyXZHPSs%2F9SkWRG2kYg6YkSginqS4XK%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;1024&quot; height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.pnp.cjs 파일에 의존성 관련 모든 정보를 기술하여 node_modules 탐색을 하지 않고 직접 접근할 수 있다.&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;node_moudules에서 찾지못하면 상위 디렉토리의 node_modules에서 검색하여 의존성을 찾는 일이 없기 때문에 동일한 재현성을 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 단점이 존재하며 대부분의 문제는 호환성.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;yarn node라는 명령어를 사용해야 하며, 아래에서 나올&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/nrwl/nx/issues/2386&quot;&gt;nx&lt;/a&gt;나&amp;nbsp;&lt;a href=&quot;https://github.com/vercel/turborepo/issues/693&quot;&gt;turborepo&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 경우 동작하지 않는 등의 문제&lt;/li&gt;
&lt;li&gt;각 에디터에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://yarnpkg.com/getting-started/editor-sdks&quot;&gt;SDK&lt;/a&gt;가 필요하다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yarnpkg/berry/issues/8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;eslint의 사용&lt;/a&gt;이나 &lt;a href=&quot;https://github.com/yarnpkg/berry/issues/882&quot;&gt;쉘 스크립트로 된 bin&lt;/a&gt;등의 호환성 문제&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;ZipFS는 설치 용량을 획기적으로 줄여주며(400MB -&amp;gt; 120MB) 구성파일이 적어 변경&amp;nbsp; 감지와 의존성 제거 작업이 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때문에 모든 설치 파일을 git에 포함하는 zero install 전략을 사용할 수 있게 되었다.&lt;/p&gt;
&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;개인적으로 yarn이 마음에 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ZipFS로 Zero-Install,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://dev.to/arcanis/yarn-31-corepack-esm-pnpm-optional-packages--3hak&quot;&gt;v3.1&lt;/a&gt;에서 Pnpm 같은 설치모드 지원과 Conditional Package, 추후 적을 Workspace 등등의 기능들을 잘 묶어서 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 pnp를 그대로 사용하기에는 호환성 문제가 많아서, zero-install + pnpm 모드로 사용해보는게 어떨까 싶다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://psidium.github.io/lerna/monorepo/yarn/nodejs/pnp/zero-install/2021/08/23/migrating-a-monorepo-from-lerna-to-yarn-3.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Migrating&amp;nbsp;a&amp;nbsp;monorepo&amp;nbsp;from&amp;nbsp;Lerna&amp;nbsp;to&amp;nbsp;Yarn&amp;nbsp;3&amp;nbsp;with&amp;nbsp;PnP&amp;nbsp;and&amp;nbsp;Zero&amp;nbsp;Install&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;h4 data-ke-size=&quot;size20&quot;&gt;5.2 모노레포&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&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;&lt;a href=&quot;https://monorepo.tools/&quot;&gt;monorepo.tools&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[&lt;a href=&quot;https://news.hada.io/topic?id=6061&quot;&gt;Monorepo에 대한 모든 것&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/0923884&quot;&gt;모던&amp;nbsp;프론트엔드&amp;nbsp;프로젝트&amp;nbsp;구성&amp;nbsp;기법&amp;nbsp;-&amp;nbsp;모노레포&amp;nbsp;개념&amp;nbsp;편&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/7553804&quot;&gt;모던&amp;nbsp;프론트엔드&amp;nbsp;프로젝트&amp;nbsp;구성&amp;nbsp;기법&amp;nbsp;-&amp;nbsp;모노레포&amp;nbsp;도구&amp;nbsp;편&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모놀리딕하게 모두 하나의 프로젝트로 구성된다면 설계, 배포 등을 커다란 단위로 처리해야 해서 비효율적이다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebasdN/btrCAv2HmYF/DwwCAJwp1ApdyKlgkxy2J1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebasdN/btrCAv2HmYF/DwwCAJwp1ApdyKlgkxy2J1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebasdN/btrCAv2HmYF/DwwCAJwp1ApdyKlgkxy2J1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebasdN%2FbtrCAv2HmYF%2FDwwCAJwp1ApdyKlgkxy2J1%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;1280&quot; height=&quot;802&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7lARc/btrCAvVV4wK/3BEk8BBXf5Yz9zQfhletkK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7lARc/btrCAvVV4wK/3BEk8BBXf5Yz9zQfhletkK/img.jpg&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;748&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.5464%; margin-right: 10px;&quot; data-widthpercent=&quot;46.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7lARc/btrCAvVV4wK/3BEk8BBXf5Yz9zQfhletkK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7lARc%2FbtrCAvVV4wK%2F3BEk8BBXf5Yz9zQfhletkK%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;980&quot; height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/colZDk/btrCyYdfG0S/lqUDN1j7bII2iPv3dOwuo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/colZDk/btrCyYdfG0S/lqUDN1j7bII2iPv3dOwuo1/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;835&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;53.92&quot; style=&quot;width: 53.2909%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/colZDk/btrCyYdfG0S/lqUDN1j7bII2iPv3dOwuo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcolZDk%2FbtrCyYdfG0S%2FlqUDN1j7bII2iPv3dOwuo1%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;1280&quot; height=&quot;835&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&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;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ewtGOq/btrCwgMXW1C/KPKxKhzK9lI0vkI7o0UfRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ewtGOq/btrCwgMXW1C/KPKxKhzK9lI0vkI7o0UfRK/img.png&quot; style=&quot;width: 32.0211%; margin-right: 10px;&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1148&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;32.78&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ewtGOq/btrCwgMXW1C/KPKxKhzK9lI0vkI7o0UfRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FewtGOq%2FbtrCwgMXW1C%2FKPKxKhzK9lI0vkI7o0UfRK%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;1280&quot; height=&quot;1148&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw0aga/btrCyXMavmo/7EDHpvXpkJuZiRXXX9zfe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw0aga/btrCyXMavmo/7EDHpvXpkJuZiRXXX9zfe0/img.png&quot; style=&quot;width: 33.9429%; margin-right: 10px;&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1083&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;34.75&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw0aga/btrCyXMavmo/7EDHpvXpkJuZiRXXX9zfe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw0aga%2FbtrCyXMavmo%2F7EDHpvXpkJuZiRXXX9zfe0%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;1280&quot; height=&quot;1083&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFuehI/btrCw9sZJtT/eNmxmGIaXWeeHE4gE5eUs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFuehI/btrCw9sZJtT/eNmxmGIaXWeeHE4gE5eUs1/img.png&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;480&quot; data-is-animation=&quot;false&quot; style=&quot;width: 31.7104%;&quot; data-widthpercent=&quot;32.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFuehI/btrCw9sZJtT/eNmxmGIaXWeeHE4gE5eUs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFuehI%2FbtrCw9sZJtT%2FeNmxmGIaXWeeHE4gE5eUs1%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;530&quot; height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/div&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bewYhQ/btrCyfTRx6w/r4xtSKMeUUUnDsuITujW5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bewYhQ/btrCyfTRx6w/r4xtSKMeUUUnDsuITujW5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bewYhQ/btrCyfTRx6w/r4xtSKMeUUUnDsuITujW5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbewYhQ%2FbtrCyfTRx6w%2Fr4xtSKMeUUUnDsuITujW5K%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;1280&quot; height=&quot;1386&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1386&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약해서&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모듈화 &amp;lt;-&amp;gt; 모놀리딕&lt;/li&gt;
&lt;li&gt;모노레포 &amp;lt;-&amp;gt; 멀티레포(또는 polyrepo)&lt;/li&gt;
&lt;/ul&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;980&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l3xSP/btrCv88I7Ky/qUkimo99A14ZHk0q5cVOO1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l3xSP/btrCv88I7Ky/qUkimo99A14ZHk0q5cVOO1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l3xSP/btrCv88I7Ky/qUkimo99A14ZHk0q5cVOO1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl3xSP%2FbtrCv88I7Ky%2FqUkimo99A14ZHk0q5cVOO1%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;980&quot; height=&quot;748&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;748&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;b&gt;해결방안&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lerna는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/lerna/lerna/issues/3121&quot;&gt;Nrwl(Nx 팀)이 인수한 상태&lt;/a&gt;이며 기능과 성능은 Nx, Turborepo가 좋은 편이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/scopsy/how-we-reduced-our-nodejs-monorepo-build-time-by-70-3oma&quot;&gt;How we reduced our nodejs monorepo build time by 70%&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pnpm.io/benchmarks&quot;&gt;Benchmarks of JavaScript Package Managers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vsavkin/large-monorepo&quot;&gt;Nx vs Turborepo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/swyx/why-turborepo-will-be-the-first-big-trend-of-2022-4gfj&quot;&gt;Why TurboRepo Will Be The First Big Trend of 2022&lt;/a&gt;&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;Nx는 기능이 많고 통합이 잘되어 있지만 상대적으로 설정이 까다로운 편이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약간 더 설정이 간단한 Vercel의 Turborepo과 비교하여 필요한 것을 도입하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;1323&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhFDIX/btrCw63BIER/gNDkWVIWTpS6R7CoGKbLIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhFDIX/btrCw63BIER/gNDkWVIWTpS6R7CoGKbLIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhFDIX/btrCw63BIER/gNDkWVIWTpS6R7CoGKbLIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhFDIX%2FbtrCw63BIER%2FgNDkWVIWTpS6R7CoGKbLIK%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;1262&quot; height=&quot;1323&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;1323&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;716&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blmKgf/btrCvDBoPlH/tqLkGBgkgXTFfBJNnhBcT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blmKgf/btrCvDBoPlH/tqLkGBgkgXTFfBJNnhBcT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blmKgf/btrCvDBoPlH/tqLkGBgkgXTFfBJNnhBcT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblmKgf%2FbtrCvDBoPlH%2FtqLkGBgkgXTFfBJNnhBcT1%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;1280&quot; height=&quot;716&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;716&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;앞서 말했지만 아직 모노레포 툴들이 yarn pnp를 제대로 지원하지 않고 있다.&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;5.3 트랜스파일링과 컴파일&lt;/h4&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;1000&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rj8AH/btrCscK3vrt/yHDKQpDHleXJ2nlUjzv7S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rj8AH/btrCscK3vrt/yHDKQpDHleXJ2nlUjzv7S1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rj8AH/btrCscK3vrt/yHDKQpDHleXJ2nlUjzv7S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frj8AH%2FbtrCscK3vrt%2FyHDKQpDHleXJ2nlUjzv7S1%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;1000&quot; height=&quot;420&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;420&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/TypeScript&quot;&gt;typescript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rescript-lang/rescript-compiler&quot;&gt;rescript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/clojure/clojurescript&quot;&gt;clojurescript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jashkenas/coffeescript&quot;&gt;coffeescript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;그러나 구형 브라우저를 타겟으로 최신 ESNext 문법을 사용하거나 JSX같은 언어적 확장을 사용하기 위해서도 트랜스파일링(또는 컴파일)과정이 필요하다.&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://github.com/babel/babel&quot;&gt;바벨(Babel)&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;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;첫번째 방안은, 타입스크립트나 flow를 사용한다면 컴파일시 타입정보들을 모두 제거하고 한번에 처리하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입체크는 tsc를 이용해 따로 진행하도록 하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mbeaudru/is-babel-still-relevant-for-typescript-projects-36a7&quot;&gt;Is&amp;nbsp;babel&amp;nbsp;still&amp;nbsp;relevant&amp;nbsp;for&amp;nbsp;TypeScript&amp;nbsp;projects&amp;nbsp;?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20181220&quot;&gt;바벨과&amp;nbsp;타입스크립트의&amp;nbsp;아름다운&amp;nbsp;결혼&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/babel-with-typescript.html&quot;&gt;Using&amp;nbsp;Babel&amp;nbsp;with&amp;nbsp;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/TypeScript-Babel-Starter&quot;&gt;TypeScript-Babel-Starter&lt;/a&gt;&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;그리고 babel보다 빠르게 컴파일되는게 있으니, 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/swc-project/swc&quot;&gt;swc&lt;/a&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;러스트로 만들어졌고, 멀티코어를 활용하며 타입스크립트의 경우 babel처럼 타입정보를 제거하며 동작한다.&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://stc.dudy.dev/docs/status/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;stc&lt;/a&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;5.4 번들링과 태스크 러너&lt;/h4&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;Webpack같은 모듈 번들러가 왜 필요할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에도 css, image같은 각종 리소스 관리, HMR(Hot Module Replacement) 개발서버 등도 지원하기도 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://wormwlrm.github.io/2020/08/12/History-of-JavaScript-Modules-and-Bundlers.html&quot;&gt;JavaScript&amp;nbsp;번들러로&amp;nbsp;본&amp;nbsp;조선시대&amp;nbsp;붕당의&amp;nbsp;이해&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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만을 뜻하는게 아니라&amp;nbsp;HTML, CSS, Javascript, 이미지, 폰트등 모든 파일들 각각은 모두 모듈이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dapTCM/btrCywHwfuM/ax4AQmk5amlHRzvnW4SH91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dapTCM/btrCywHwfuM/ax4AQmk5amlHRzvnW4SH91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dapTCM/btrCywHwfuM/ax4AQmk5amlHRzvnW4SH91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdapTCM%2FbtrCywHwfuM%2Fax4AQmk5amlHRzvnW4SH91%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;1280&quot; height=&quot;602&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nextjs.org/learn/foundations/how-nextjs-works/bundling&quot;&gt;What&amp;nbsp;is&amp;nbsp;Bundling?&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;특히 HTTP/1에서 호출 제한이 있었으며, HTTP/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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 태스크 러너와 &lt;a href=&quot;https://www.cleveroad.com/blog/gulp-browserify-webpack-grunt&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;a href=&quot;https://ko.wikipedia.org/wiki/Make_(%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Make&lt;/a&gt;인데 우리는 빌드를 할 때 사용한다는 점을 알고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹 생태계에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/gruntjs/grunt&quot;&gt;Grunt&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/gulpjs/gulp&quot;&gt;Gulp&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;Webpack에서 webpack --mode=production로 프로덕션용 빌드를 하고, webpack --mode=development로 개발용 빌드를 하지 않던가?&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;820&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzszsD/btrCBoRXoGN/YddzFjAYuQkwO6xYsDJi51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzszsD/btrCBoRXoGN/YddzFjAYuQkwO6xYsDJi51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzszsD/btrCBoRXoGN/YddzFjAYuQkwO6xYsDJi51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzszsD%2FbtrCBoRXoGN%2FYddzFjAYuQkwO6xYsDJi51%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;820&quot; height=&quot;218&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0pV35/btrCC0vmLzf/cTbzAjby3MWz7kxgxDv0f0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0pV35/btrCC0vmLzf/cTbzAjby3MWz7kxgxDv0f0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0pV35/btrCC0vmLzf/cTbzAjby3MWz7kxgxDv0f0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0pV35%2FbtrCC0vmLzf%2FcTbzAjby3MWz7kxgxDv0f0%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;714&quot; height=&quot;318&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jusungpark.tistory.com/52&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹팩(Webpack) 이란, 웹팩 간단 정리 및 리액트(React) 기본 개발환경 세팅.&lt;/a&gt;, &lt;a href=&quot;https://www.toptal.com/front-end/webpack-browserify-gulp-which-is-better&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpack&amp;nbsp;or&amp;nbsp;Browserify&amp;nbsp;&amp;amp;&amp;nbsp;Gulp:&amp;nbsp;Which&amp;nbsp;Is&amp;nbsp;Better?&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;게다가 종속성 분석이 가능해짐으로서 단순히 파일을 merge하는 것보다 빠르고 &lt;a href=&quot;https://webpack.kr/guides/tree-shaking/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tree Shaking&lt;/a&gt;, &lt;a href=&quot;https://webpack.kr/guides/code-splitting/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Code Splitting&lt;/a&gt;, &lt;a href=&quot;https://webpack.kr/guides/lazy-loading/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dynamic Import(Lazy loading)&lt;/a&gt;등을 처리하며 심지어 Dev server와 연동하여 &lt;a href=&quot;https://webpack.kr/guides/hot-module-replacement/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HMR(Hot Module Replacement)&lt;/a&gt;까지 제공한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1241&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnQevt/btrCEeGOoOU/oMgUnxnLkqnM5B2YTRn8G0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnQevt/btrCEeGOoOU/oMgUnxnLkqnM5B2YTRn8G0/img.png&quot; data-alt=&quot;성능차이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnQevt/btrCEeGOoOU/oMgUnxnLkqnM5B2YTRn8G0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnQevt%2FbtrCEeGOoOU%2FoMgUnxnLkqnM5B2YTRn8G0%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;1241&quot; height=&quot;690&quot; data-origin-width=&quot;1241&quot; data-origin-height=&quot;690&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;781&quot; data-origin-height=&quot;131&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oWnQU/btrC871HnuT/10d4cie0MTYTk63yeZ2XS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oWnQU/btrC871HnuT/10d4cie0MTYTk63yeZ2XS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oWnQU/btrC871HnuT/10d4cie0MTYTk63yeZ2XS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoWnQU%2FbtrC871HnuT%2F10d4cie0MTYTk63yeZ2XS1%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;781&quot; height=&quot;131&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;131&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BO6BP/btrC8TbPYGF/tG3EDxV9nt6ys2OeIcmpT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BO6BP/btrC8TbPYGF/tG3EDxV9nt6ys2OeIcmpT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BO6BP/btrC8TbPYGF/tG3EDxV9nt6ys2OeIcmpT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBO6BP%2FbtrC8TbPYGF%2FtG3EDxV9nt6ys2OeIcmpT1%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;801&quot; height=&quot;491&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.to/thespider/using-webpack-for-api-development-52g9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Using&amp;nbsp;Webpack&amp;nbsp;for&amp;nbsp;API&amp;nbsp;development!&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;이쯤되면 &quot;아~ 번들러가 태스크러너의 상위의 존재?구나&quot;라는 생각이 들 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 Webpack의 &lt;a href=&quot;https://webpack.kr/guides/integrations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Integrations&lt;/a&gt; 문서에도 나오듯 잘하는 일이 다른 것 뿐이며 태스크러너는 packages.json의 &lt;a href=&quot;https://docs.npmjs.com/cli/v8/using-npm/scripts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;scripts&lt;/a&gt;에 가깝다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 태스크러너의 예로 나온 makefile이 install과 clean은 수행해도 lint나 test 명령이 쓰이기도 하나 싶지만 실제로 &lt;a href=&quot;https://docs.oracle.com/cd/E19504-01/802-5880/make-53/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;오라클 가이드&lt;/a&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;a href=&quot;https://www.norwegiancreations.com/2018/08/makefiles-part-3-test-lint-deploy/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Makefiles:&amp;nbsp;Part&amp;nbsp;3&amp;nbsp;&amp;mdash;&amp;nbsp;Test,&amp;nbsp;Lint,&amp;nbsp;Deploy!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.vantage-ai.com/blog/speed-up-your-python-development-workflow-with-pre-commit-and-makefile&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Speed up your Python development workflow with pre-commit and Makefile&lt;/a&gt; [&lt;a href=&quot;https://github.com/banksalad/python/blob/b738bca1f9583590c0b9060d1146542443cde6f9/%7B%7Bcookiecutter.project_slug%7D%7D/Makefile&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;뱅크샐러드의 예시&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 린트와 테스팅 도구들이 번들러와 통합하여 쓰이는 경우들이 잦아져 쓸 필요가 줄어들고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그치만 복잡한 publishing등의 작업들이 필요하다면 태스크러너를 사용하는게 유용할 수도 있다.&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://gulpjs.com/docs/en/getting-started/working-with-files&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gulp 기준 src()~dest()&lt;/a&gt;를 효율적으로 실행해주는 프로그램입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹팩에서 &lt;a href=&quot;https://webpack.js.org/concepts/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;src()는 Entry, dest()는 Output&lt;/a&gt;이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로더, 플러그인, 모드는 뭐냐고요?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZhWRi/btrDbvA2zNO/LcIMeLdFp9Vqls8qDRRZQ1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZhWRi/btrDbvA2zNO/LcIMeLdFp9Vqls8qDRRZQ1/img.jpg&quot; width=&quot;724&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;333&quot; data-is-animation=&quot;false&quot; style=&quot;width: 57.4075%; margin-right: 10px;&quot; data-widthpercent=&quot;58.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZhWRi/btrDbvA2zNO/LcIMeLdFp9Vqls8qDRRZQ1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZhWRi%2FbtrDbvA2zNO%2FLcIMeLdFp9Vqls8qDRRZQ1%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;724&quot; height=&quot;333&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E1tty/btrC7zFr2Fm/Z6giJocMKKMSby3UpNJY51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E1tty/btrC7zFr2Fm/Z6giJocMKKMSby3UpNJY51/img.png&quot; data-origin-width=&quot;1227&quot; data-origin-height=&quot;782&quot; data-is-animation=&quot;false&quot; style=&quot;width: 41.4297%;&quot; data-widthpercent=&quot;41.92&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E1tty/btrC7zFr2Fm/Z6giJocMKKMSby3UpNJY51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE1tty%2FbtrC7zFr2Fm%2FZ6giJocMKKMSby3UpNJY51%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;1227&quot; height=&quot;782&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.quora.com/Where-can-I-learn-webpack&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Where can I learn webpack?&lt;/a&gt;, &lt;a href=&quot;https://stackoverflow.com/questions/37452402/webpack-loaders-vs-plugins-whats-the-difference&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpack&amp;nbsp;loaders&amp;nbsp;vs&amp;nbsp;plugins;&amp;nbsp;what's&amp;nbsp;the&amp;nbsp;difference?&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;&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;650&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4Cc2j/btrC75RpM5x/97WZkCqQ3LNhTtEkgai8t0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4Cc2j/btrC75RpM5x/97WZkCqQ3LNhTtEkgai8t0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4Cc2j/btrC75RpM5x/97WZkCqQ3LNhTtEkgai8t0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4Cc2j%2FbtrC75RpM5x%2F97WZkCqQ3LNhTtEkgai8t0%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;650&quot; height=&quot;700&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jdunkerley.co.uk/2017/06/03/how-to-set-up-webpack-based-typescript-electron-react-build-process-with-vsts-ci/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;to&amp;nbsp;set&amp;nbsp;up&amp;nbsp;WebPack&amp;nbsp;based&amp;nbsp;TypeScript&amp;nbsp;Electron&amp;nbsp;React&amp;nbsp;Build&amp;nbsp;Process&amp;nbsp;(with&amp;nbsp;VSTS&amp;nbsp;CI!)&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;여기서!! 번들러가 자바스크립트의 모듈을 분석한다고 했었죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 자바스크립트의 모듈 시스템은 통일성이 없고 매우 다양하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본디 브라우저에서 script 태그로 로드를 하는 형식이었지만, 전역 컨텍스트에서 로드하여 이름이 겹쳐 재정의되는등의 문제가 있었다.&lt;/p&gt;
&lt;pre id=&quot;code_1652928341457&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
  &amp;lt;script src=&quot;/src/foo.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;/src/bar.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;/src/baz.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;/src/qux.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;/src/quux.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/html&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/12864&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript 표준을 위한 움직임: CommonJS와 AMD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yceffort.kr/2020/08/commonjs-esmodules&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CommonJS와&amp;nbsp;ES&amp;nbsp;Modules은&amp;nbsp;왜&amp;nbsp;함께&amp;nbsp;할&amp;nbsp;수&amp;nbsp;없는가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://baeharam.netlify.app/posts/javascript/module&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[JS]&amp;nbsp;모듈에&amp;nbsp;대한&amp;nbsp;이해와&amp;nbsp;사용법&lt;/a&gt;&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;a href=&quot;http://www.commonjs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Common.JS&lt;/a&gt;는 서버 사이드에서 사용하기 위해 나타났으며 &lt;a href=&quot;https://nodejs.org/api/modules.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Node.JS의 기본 모듈 시스템&lt;/a&gt;이기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한계로는 동적이라서 트리쉐이킹에 취약했으며 비동기적으로 사용이 어려웠다. [&lt;a href=&quot;https://web.dev/i18n/ko/commonjs-larger-bundles/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CommonJS가 번들을 더 크게 만드는 방법&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밑에 나올 Rollup은 CommonJS가 아닌 ESM을 사용하여 빌드하므로, 트리쉐이킹에 강점이 있다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1652928561491&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// == Default 모듈 ================================
// Default 모듈 정의, foo.js
const foo = () =&amp;gt; console.log(0);
module.exports = foo;

// Default 모듈 사용
const foo = require(&quot;./foo&quot;);
foo();


// == 모듈 ========================================
// 모듈 정의, bar.js
const baz = () =&amp;gt; console.log(1);
module.exports = {
  baz
};

// 모듈 사용
const barModule = require(&quot;./bar&quot;);
barModule.baz();

const { baz } = require(&quot;./bar&quot;);
baz();&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;a href=&quot;https://github.com/amdjs/amdjs-api/wiki/AMD&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMD(Asynchronous Module Definition)&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;AMD 로더 중 가장 유명한게 &lt;a href=&quot;https://requirejs.org/docs/whyamd.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;require.js&lt;/a&gt;.&lt;/p&gt;
&lt;pre id=&quot;code_1652928585822&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 모듈 정의, foo.js
define({
  foo: () =&amp;gt; console.log(0)
});

// 모듈 정의, qux.js
define(['foo', 'bar', // 의존 모듈들을 배열로 나열
], function (foo, bar) { // 의존 모듈들은 순서대로 매개변수에 담김
  return {
    // 외부에 노출할 함수들만 반환
    foo,
    barModule: bar
  };
});

// 모듈 사용
require(['qux.js', // 사용할 모듈 배열로 나열
], function (quxModule) { // 사용할 모듈들이 순서대로 매개변수에 담김
  quxModule.foo();
  quxModule.barModule.baz();
});&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;a href=&quot;https://github.com/umdjs/umd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;UMD(Universal Module Definition)&lt;/a&gt;은 CommonJS와 AMD를 모두 지원하기 위해 나온 디자인 패턴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Webpack이나 Rollup같은 번들러에서 ESM을 지원하지 않는 브라우저라면 fallback 용으로 사용하기도 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1652944449263&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(function (root, factory) {
  if (typeof define === 'function' &amp;amp;&amp;amp; define.amd) {
    // AMD 방식
    define(['exports', 'foo'], factory);
  } else if (typeof exports === 'object') {
    // CommonJS 방식
    module.exports = factory(require('foo'));
  } else {
    // Browser globals
    root.foo = factory(root.foo);
  }
}(this, function (foo) {
  //use foo in some fashion.
   // 모듈 정의
  const foo = () =&amp;gt; console.log(0);

  return foo;
}));&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;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Modules&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ESM&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;동기/비동기를 모두 지원하고, 순환참조 문제가 없으며 정적분석까지도 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1652939701600&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// == Default 모듈 ================================
// Default 모듈 정의, foo.js
const foo = () =&amp;gt; console.log(0);
export default foo;

// Default 모듈 사용
import foo from &quot;foo&quot;;
foo();


// == 모듈 ========================================
// 모듈 정의, bar.js
export const baz = () =&amp;gt; console.log(1);

// 모듈 사용
import { baz } from &quot;bar&quot;;
baz();&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;a href=&quot;https://udn.realityripple.com/docs/Mozilla/JavaScript_code_modules&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Javascript Code Module&lt;/a&gt;이라고 파이어폭스 내부에서 사용하는 모듈 시스템이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;권한이 있는 다른 범위의 자바스크립트에서 코드를 공유하기 위해 만들어졌다.&lt;/p&gt;
&lt;pre id=&quot;code_1652937998803&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// == JSM 모듈 ===================================
// Default 모듈 정의, foo.jsm
var EXPORTED_SYMBOLS = [&quot;foo&quot;];

const foo = () =&amp;gt; console.log(0);

// Default 모듈 사용
Components.utils.import(&quot;resource://app/foo.jsm&quot;);
foo();

// == CommonJS ===================================
// 모듈 사용
const { require } = Cu.import(&quot;resource://gre/modules/commonjs/toolkit/require.js&quot;, {});
const { baz } = require(&quot;./bar&quot;);
baz();&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;
&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;Browserify를 누르고 올라온&amp;nbsp;&lt;a href=&quot;https://ui.toast.com/fe-guide/ko_BUNDLER&quot;&gt;Webpack&lt;/a&gt;이 한동안 Defacto Standandard였지만 춘추전국시대로 난립중이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z9cxo/btrCC0vwpe6/F3FSLDxGt042aasCbuXZBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z9cxo/btrCC0vwpe6/F3FSLDxGt042aasCbuXZBK/img.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;204&quot; data-is-animation=&quot;false&quot; style=&quot;width: 56.2198%; margin-right: 10px;&quot; data-widthpercent=&quot;56.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z9cxo/btrCC0vwpe6/F3FSLDxGt042aasCbuXZBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz9cxo%2FbtrCC0vwpe6%2FF3FSLDxGt042aasCbuXZBK%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;700&quot; height=&quot;204&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ED9Ng/btrCEdaroli/KUxPoLK32iHCfvoLgRqY8k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ED9Ng/btrCEdaroli/KUxPoLK32iHCfvoLgRqY8k/img.jpg&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;346&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.6175%;&quot; data-widthpercent=&quot;43.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ED9Ng/btrCEdaroli/KUxPoLK32iHCfvoLgRqY8k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FED9Ng%2FbtrCEdaroli%2FKUxPoLK32iHCfvoLgRqY8k%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;900&quot; height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;a href=&quot;https://dev.to/underscorecode/javascript-bundlers-an-in-depth-comparative-is-webpack-still-the-best-bundler-in-2021-59jk&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript Bundlers: An in-depth comparative   Is Webpack still the best bundler in 2021?  &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.seonest.net/posts/Bundle3-Module-Bundler&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bundle(3)&amp;nbsp;-&amp;nbsp;Module&amp;nbsp;Bundler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sambalim.tistory.com/137&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;번들러 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20220127&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;차세대&amp;nbsp;빌드&amp;nbsp;도구&amp;nbsp;비교&lt;/a&gt;&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;a href=&quot;https://github.com/webpack/webpack&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpack&lt;/a&gt;, &lt;a href=&quot;https://github.com/rollup/rollup&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rollup&lt;/a&gt;, &lt;a href=&quot;https://github.com/parcel-bundler/parcel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Parcel&lt;/a&gt;이며, 빠른 빌드로 유명한 &lt;a href=&quot;https://github.com/evanw/esbuild&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;esbuild&lt;/a&gt;도 주목할만 하다.&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;Rollup은 ESM을 기준으로 빌드하여 트리쉐이킹에 강점이 있다. 단, dev sever등의 기능들이 부족.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Parcel은 제로 config를 지향하여 세팅이 쉽다. 대신 커스텀 설정이 어려울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Esbuild는 Go 언어로 짜여졌으며, 병렬처리를 사용하여 &lt;a href=&quot;https://esbuild.github.io/faq/#why-is-esbuild-fast&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;a href=&quot;https://github.com/FredKSchott/snowpack&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Snowpack&lt;/a&gt;, &lt;a href=&quot;https://github.com/vitejs/vite&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vite&lt;/a&gt;, &lt;a href=&quot;https://github.com/preactjs/wmr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;wmr&lt;/a&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1812&quot; data-origin-height=&quot;1028&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZqeYc/btrCBSrsGUj/Ukk3bkbelbgTT4ROsmr2T0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZqeYc/btrCBSrsGUj/Ukk3bkbelbgTT4ROsmr2T0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZqeYc/btrCBSrsGUj/Ukk3bkbelbgTT4ROsmr2T0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZqeYc%2FbtrCBSrsGUj%2FUkk3bkbelbgTT4ROsmr2T0%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;1812&quot; height=&quot;1028&quot; data-origin-width=&quot;1812&quot; data-origin-height=&quot;1028&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.snowpack.dev/concepts/how-snowpack-works&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How Snowpack Works&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저에서도 ESM을 지원함에 따라 매번 번들링을 수행할 필요가 없어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CommonJS는 브라우저에서 지원하지 않아 번들링이 필요했었죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 Snowpack은 NPM의 CommonJS 패키지들을 개별 JS 파일로 변환 후, 브라우저에서 ESM 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;Vite의 접근도 비슷하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스코드는 Native ESM을 사용하고, NPM 패키지들은 Esbuild로 사전 번들링을 수행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FoX6T/btrCBNqQxpb/HBCeApfm3IkVkdBKBvbLk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FoX6T/btrCBNqQxpb/HBCeApfm3IkVkdBKBvbLk1/img.png&quot; data-origin-width=&quot;1918&quot; data-origin-height=&quot;1068&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.2991%; margin-right: 10px;&quot; data-widthpercent=&quot;52.91&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FoX6T/btrCBNqQxpb/HBCeApfm3IkVkdBKBvbLk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFoX6T%2FbtrCBNqQxpb%2FHBCeApfm3IkVkdBKBvbLk1%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;1918&quot; height=&quot;1068&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TtOoP/btrCCgF4pxt/A5OV3Kkv1P1ZfJknKI2yRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TtOoP/btrCCgF4pxt/A5OV3Kkv1P1ZfJknKI2yRK/img.png&quot; data-origin-width=&quot;1646&quot; data-origin-height=&quot;1030&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.5382%;&quot; data-widthpercent=&quot;47.09&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TtOoP/btrCCgF4pxt/A5OV3Kkv1P1ZfJknKI2yRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTtOoP%2FbtrCCgF4pxt%2FA5OV3Kkv1P1ZfJknKI2yRK%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;1646&quot; height=&quot;1030&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://vitejs-kr.github.io/guide/why.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vite를 사용해야 하는 이유&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;Snowpack이 개발용에만 신경썼던 한편, Vite는 프로덕션 빌드에는 Rollup을 사용해 최적화했고 전반적인 통합을 높혔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;독단적인 결정일 수 있지만 나는 꽤나 합리적인 기본값이라 생각하며, 그 결과 Multi-Page App이나 라이브러리 모드등의&amp;nbsp; &lt;a href=&quot;https://vitejs-kr.github.io/guide/comparisons.html&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;단, Vite는 Snowpack과 wmr의 &lt;a href=&quot;https://www.snowpack.dev/guides/streaming-imports&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Streaming Import&lt;/a&gt;를 아직 지원하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Streaming Import는 Native ESM을 최대한 활용하기 위해 &lt;a href=&quot;https://www.skypack.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Skypack&lt;/a&gt;같이 ESM 패키지를 제공하는 CDN에서 직접 로드하여 성능을 높힐 수 있다.(사전 번들링 불필요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wmr은 preact에 중점을 둔 작은 번들러로, 프로덕션 빌드 최적화나 Streaming Import를 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 &lt;a href=&quot;https://github.com/developit/htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTM&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;암튼 최근 경향은 Vite가 대세로&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://portal.gitnation.org/contents/vite-rethinking-frontend-tooling&quot;&gt;Vite: Rethinking Frontend Tooling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering.ab180.co/stories/webpack-to-vite&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpack&amp;nbsp;&amp;rarr;&amp;nbsp;Vite:&amp;nbsp;번들러&amp;nbsp;마이그레이션&amp;nbsp;이야기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;아, 그리고 직접 모노레포를 yarn &amp;amp; vite &amp;amp; typescript로 구축하며 생겼던 몇가지 문제.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;vite.config.js는 괜찮지만, &lt;a href=&quot;https://github.com/vitejs/vite/issues/5370&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;vite.config.ts는 트랜스파일링에서 문제&lt;/a&gt;가 생김: builder 패턴으로 해결&lt;/li&gt;
&lt;li&gt;yarn PnP 모드를 사용시 &lt;a href=&quot;https://github.com/vitejs/vite/issues/8357&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;tsconfig의 extends&lt;/a&gt;가 작동하지 않음: pnpm모드 사용&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;Vite와 통합되어 Storybook과 Jest를 대체하는 프로젝트들도 나오게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 성능에 초점을 맞추고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Storybook - Ladle [&lt;a href=&quot;https://www.ladle.dev/blog/introducing-ladle/&quot;&gt;Introducing&amp;nbsp;Ladle&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Jest - Vitest [&lt;a href=&quot;https://dev.to/mbarzeev/from-jest-to-vitest-migration-and-benchmark-23pl&quot;&gt;From&amp;nbsp;Jest&amp;nbsp;to&amp;nbsp;Vitest&amp;nbsp;-&amp;nbsp;Migration&amp;nbsp;and&amp;nbsp;Benchmark&lt;/a&gt;]&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;그냥 생으로 rollup + esbuild 세팅에 관심있다면 &lt;a href=&quot;https://gist.github.com/aleclarson/9900ed2a9a3119d865286b218e14d226&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;rollup-typescript&lt;/a&gt;라는 gist를 참고해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에어비엔비에서는 React Native에서 사용하는 &lt;a href=&quot;https://github.com/facebook/metro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Metro&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;태스크 러너의 경우 앞서 말했듯 Grunt와 Gulp가 유명하구(&lt;a href=&quot;https://github.com/lukeed/taskr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;taskr&lt;/a&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;a href=&quot;https://deliciousbrains.com/grunt-vs-gulp-battle-build-tools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Grunt&amp;nbsp;vs&amp;nbsp;Gulp:&amp;nbsp;Battle&amp;nbsp;of&amp;nbsp;the&amp;nbsp;Build&amp;nbsp;Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.outsider.ne.kr/1181&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;왜&amp;nbsp;Grunt에서&amp;nbsp;Gulp로&amp;nbsp;갈아탔는가?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윗 글들만 읽어보면 충분할거라 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 npm scripts를 효율적으로 실행시키고 싶은거라면 &lt;a href=&quot;https://github.com/google/wireit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;wireit&lt;/a&gt;이란 프로젝트도 참고해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금, 멀티레포 관리 툴과 wireit을 보면 태스크 러너 바퀴의 재발명이라는 생각이 든다.&lt;/p&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;a href=&quot;https://github.com/typicode/husky&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;husky&lt;/a&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;5.5 린트와 포매팅&lt;/h4&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;보통은 eslint, prettier를 각각 구현방식, 코드 포맷 검증용으로 사용한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;487&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJGIi3/btrCDcQk3y7/Dqti7HWteubxfk2k7fRpG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJGIi3/btrCDcQk3y7/Dqti7HWteubxfk2k7fRpG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJGIi3/btrCDcQk3y7/Dqti7HWteubxfk2k7fRpG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJGIi3%2FbtrCDcQk3y7%2FDqti7HWteubxfk2k7fRpG0%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;730&quot; height=&quot;487&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;487&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.logrocket.com/using-prettier-eslint-automate-formatting-fixing-javascript/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Using&amp;nbsp;Prettier&amp;nbsp;and&amp;nbsp;ESLint&amp;nbsp;to&amp;nbsp;automate&amp;nbsp;formatting&amp;nbsp;and&amp;nbsp;fixing&amp;nbsp;JavaScript&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;린터는 코드의 안티패턴과 에러를 찾아서 검출하려는 목적이며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포매터는 2 space, 4 space처럼 코드의 스타일을 통일하려는 목적이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GYzZH/btrCCFFdbh9/u1MI84AgBKoklIk2SNKIIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GYzZH/btrCCFFdbh9/u1MI84AgBKoklIk2SNKIIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GYzZH/btrCCFFdbh9/u1MI84AgBKoklIk2SNKIIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGYzZH%2FbtrCCFFdbh9%2Fu1MI84AgBKoklIk2SNKIIK%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;730&quot; height=&quot;486&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;486&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://seonghui.github.io/blog/2020/12/27/typescript-eslint-prettier/&quot;&gt;Typescript 프로젝트에 ESLint, Prettier 적용하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pravusid.kr/typescript/2020/07/19/typescript-eslint-prettier.html&quot;&gt;TypeScript&amp;nbsp;ESLint&amp;nbsp;+&amp;nbsp;Prettier&amp;nbsp;함께&amp;nbsp;사용하기(w/&amp;nbsp;VSCode)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://helloinyong.tistory.com/325&quot;&gt;ESLint, Prettier Setting, 헤매지 말고 정확히 알고 설정하자.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freecodecamp.org/news/integrating-prettier-with-eslint-and-stylelint-99e74fede33f/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;to&amp;nbsp;integrate&amp;nbsp;Prettier&amp;nbsp;with&amp;nbsp;ESLint&amp;nbsp;and&amp;nbsp;stylelint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/tbc-engineering/why-and-how-to-lint-like-a-pro-173fc4a73899&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Why&amp;nbsp;and&amp;nbsp;How&amp;nbsp;to&amp;nbsp;Lint&amp;nbsp;like&amp;nbsp;a&amp;nbsp;PRO&lt;/a&gt;&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&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://overreacted.io/ko/goodbye-clean-code/&quot;&gt;잘가, 클린 코드&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;때문에 &lt;a href=&quot;https://github.com/facebook/react/blob/e66e7a0fb875dac2d3e34c005c5be7503f979143/packages/react-reconciler/src/ReactFiberFlags.js#L14-L61&quot;&gt;React의 코드&lt;/a&gt;만 봐도 강제적인 포맷팅에서 회피하기 위해 주석으로 공간을 만들어주는걸 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약간만 유연하게 한다면 내가 작성했던&amp;nbsp;&lt;a href=&quot;https://github.com/black7375/SplitCubicalBezier/blob/main/src/index.ts&quot;&gt;SplitCubicalBezier&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;b&gt;해결방안&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Eslint와 Prettier 대체제는 음..&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://github.com/rome/tools&quot;&gt;Rome&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.logrocket.com/modern-faster-alternatives-eslint/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Modern, faster alternatives to ESLint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/pinterest-engineering/introducing-esprint-a-fast-open-source-eslint-cli-19a470cd1c7d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introducing esprint: a fast, open source eslint CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://survivejs.com/maintenance/appendices/customizing-eslint/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Customizing&amp;nbsp;ESLint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/quick-lint/quick-lint-js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;quick-lint-js&lt;/a&gt;도 빠르지만 아직 타입스크립트를 지원하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 &lt;a href=&quot;https://github.com/eslint/eslint&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;eslint&lt;/a&gt; + &lt;a href=&quot;https://github.com/pinterest/esprint&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;esprint&lt;/a&gt;나 &lt;a href=&quot;https://github.com/mantoni/eslint_d.js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;eslint_d&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.codetd.com/en/article/12056347&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Switching deno fmt from prettier to dprint, performance increase 10+ times&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 eslint_d와 같은 계열인 &lt;a href=&quot;https://github.com/fsouza/prettierd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;prettierd&lt;/a&gt; 또는 &lt;a href=&quot;https://github.com/fsouza/prettierd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;dprint&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://github.com/okonet/lint-staged&quot;&gt;lint-staged&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/azz/pretty-quick&quot;&gt;pretty-quick&lt;/a&gt;은 staging된 파일에만 적용하여 빠르게 체크가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS의 경우 &lt;a href=&quot;https://github.com/jo-sm/stylelint_d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;stylelint_d&lt;/a&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;5.6 테스트&lt;/h4&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;1000&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dClf92/btrCHdO5Z0e/9ScpI3SkP8MM5rvr9jN5jk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dClf92/btrCHdO5Z0e/9ScpI3SkP8MM5rvr9jN5jk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dClf92/btrCHdO5Z0e/9ScpI3SkP8MM5rvr9jN5jk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdClf92%2FbtrCHdO5Z0e%2F9ScpI3SkP8MM5rvr9jN5jk%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;1000&quot; height=&quot;420&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.to/willholmes/why-i-think-jest-is-better-than-mocha-chai-78l&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Why&amp;nbsp;I&amp;nbsp;think&amp;nbsp;Jest&amp;nbsp;is&amp;nbsp;better&amp;nbsp;than&amp;nbsp;Mocha&amp;nbsp;&amp;amp;&amp;nbsp;Chai&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;이 파트도 Toast UI가 잘 정리해줬다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ui.toast.com/fe-guide/ko_TEST&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;테스트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/scraggo/comparing-javascript-test-runners&quot;&gt;Comparing&amp;nbsp;JavaScript&amp;nbsp;Test&amp;nbsp;Runners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.merixstudio.com/blog/mocha-vs-jest/&quot;&gt;Mocha&amp;nbsp;vs.&amp;nbsp;Jest:&amp;nbsp;comparison&amp;nbsp;of&amp;nbsp;two&amp;nbsp;testing&amp;nbsp;tools&amp;nbsp;for&amp;nbsp;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;아 그리고, Enzyme를 사용하고 있다면 React Testing Library를 사용하도록 하자. [&lt;a href=&quot;https://dev.to/wojtekmaj/enzyme-is-dead-now-what-ekl&quot;&gt;Enzyme&amp;nbsp;is&amp;nbsp;dead.&amp;nbsp;Now&amp;nbsp;what?&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.daleseo.com/react-testing-library/&quot;&gt;React&amp;nbsp;Testing&amp;nbsp;Library&amp;nbsp;사용법&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;a href=&quot;https://medium.com/happyprogrammer-in-jeju/%ED%8E%B8%EB%A6%AC%ED%95%98%EA%B3%A0-%EA%B0%95%EB%A0%A5%ED%95%9C-%EC%86%8D%EC%84%B1-%EA%B8%B0%EB%B0%98-%ED%85%8C%EC%8A%A4%ED%8C%85-b405ab54fd3c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Property based testing&lt;/a&gt;도 시도해보는건 어떨까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하스켈의 &lt;a href=&quot;https://hackage.haskell.org/package/QuickCheck&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;QuickCheck&lt;/a&gt;로 유명하며, 자바스크립트쪽에는 &lt;a href=&quot;https://github.com/dubzzz/fast-check&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fast-check&lt;/a&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;a href=&quot;https://dev.to/mokkapps/property-based-testing-with-typescript-2ljj&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Property Based Testing With Typescript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marmelab.com/blog/2019/04/18/property-based-testing-js.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Property&amp;nbsp;Based&amp;nbsp;Testing&amp;nbsp;in&amp;nbsp;Javascript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;a href=&quot;https://github.com/facebook/jest&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Jest&lt;/a&gt;가 가장 많이 쓰이고 있는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, Jest가 병렬로 실행됨에도 느리다는 말이 좀 있다..&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4&quot;&gt;JavaScript&amp;nbsp;Test-Runners&amp;nbsp;Benchmark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://if1live.github.io/posts/escape-from-jest-jest-is-slow/&quot;&gt;Jest 탈출기 - Jest는 느리다&lt;/a&gt;&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;가장 큰 병목 중 하나는 import를 매번 다시 하기 때문인듯하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.petecorey.com/blog/2018/11/05/bending-jest-to-our-will-caching-modules-across-tests/&quot;&gt;Bending&amp;nbsp;Jest&amp;nbsp;to&amp;nbsp;Our&amp;nbsp;Will:&amp;nbsp;Caching&amp;nbsp;Modules&amp;nbsp;Across&amp;nbsp;Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://miyauchi.dev/posts/speeding-up-jest/&quot;&gt;Speed&amp;nbsp;​​up&amp;nbsp;TypeScript&amp;nbsp;with&amp;nbsp;Jest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thymikee/jest-preset-angular/issues/757&quot;&gt;Performance Regression Report&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.codecentric.de/en/2021/11/javascript-test-performance-getting-the-best-out-of-jest/&quot;&gt;JavaScript&amp;nbsp;test&amp;nbsp;performance:&amp;nbsp;getting&amp;nbsp;the&amp;nbsp;best&amp;nbsp;out&amp;nbsp;of&amp;nbsp;Jest&lt;/a&gt;&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;a href=&quot;https://jestjs.io/docs/cli#--shard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;샤딩&lt;/a&gt;을 사용하면 &lt;a href=&quot;https://remarkablemark.org/blog/2022/05/13/jest-shard-test-github-actions/#workflow&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;a href=&quot;https://github.com/vitest-dev/vitest&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;vitest&lt;/a&gt;는 vite의 resolver를 사용하고 esm first등의 이점이 있어 성능면에서 나은 점도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 러스트처럼!!! &lt;a href=&quot;https://vitest.dev/guide/in-source.html&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;s&gt;벤치마크의 경우 &lt;a href=&quot;https://github.com/vitest-dev/vitest/issues/917&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;논의 중&lt;/a&gt;에 있다.&lt;/s&gt;(이제 지원됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;단, 아직 캐싱과 &lt;a href=&quot;https://github.com/vitest-dev/vitest/issues/1464&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;샤딩(이슈)&lt;/a&gt;을 지원하지 않아서 아쉽다.&lt;/s&gt;(이제 지원됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Jest의 &lt;a href=&quot;https://github.com/vitest-dev/vitest/issues/1470&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;커스텀 러너를 허용&lt;/a&gt;하게 되면 일렉트론 환경에서도 테스트가 가능하고, &lt;a href=&quot;https://github.com/jest-community/jest-runner-eslint&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;린트&lt;/a&gt;/&lt;a href=&quot;https://github.com/jest-community/jest-runner-tsd&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;/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;5.7 CI/CD&lt;/h4&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;예전에 Emacs-NG에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/emacs-ng/emacs-ng/pull/205#issuecomment-817071006&quot;&gt;CI 성능관련 PR&lt;/a&gt;을 만들었을때 몇가지 인사이트를 얻을 수 있었다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;[&lt;a href=&quot;https://black7375.tumblr.com/post/645631522744975360/%EA%B9%83%ED%97%88%EB%B8%8C-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%B5%9C%EC%A0%81%ED%99%94&quot;&gt;깃허브 워크플로우 최적화&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.gnu.org/software/autoconf/&quot;&gt;autoconf&lt;/a&gt;로 빌드하는데다가 C, Rust, Elisp 컴파일등 상당히 복잡한 구조를 가졌기에 여러가지를 고려하기 좋은 프로젝트였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핫빌드 기준 무려 278%의 성능향상을 했었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우분투: 26m 5s =&amp;gt; 11m 53s&lt;/li&gt;
&lt;li&gt;맥OS: 39m 7s =&amp;gt; 14m 8s&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;의외로 CI/CD 시간 단축 작업은 쉽지 않은데, 다운로드/업로드와 빌드, 빌드 후 동작등 모든 것을 고려해야 한다.&lt;/p&gt;
&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;- CI/CD 건너뛰기/분리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 좋은 것은 CI/CD 자체를 실행하지 않는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;README만 바뀌었는데 매번 빌드와 테스트까지 모두 할 필요는 없지 않은가.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpushpull_requestpull_request_targetpathspaths-ignore&quot;&gt;커밋 경로&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpull_requestpull_request_targetbranchesbranches-ignore&quot;&gt;브랜치&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs&quot;&gt;커밋 메세지&lt;/a&gt;&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;/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;880&quot; data-origin-height=&quot;394&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vNMne/btrCyXSWMY7/jh7cqCnyU5hOkm1NEmxLGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vNMne/btrCyXSWMY7/jh7cqCnyU5hOkm1NEmxLGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vNMne/btrCyXSWMY7/jh7cqCnyU5hOkm1NEmxLGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvNMne%2FbtrCyXSWMY7%2Fjh7cqCnyU5hOkm1NEmxLGK%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;880&quot; height=&quot;394&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;/figure&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;a href=&quot;https://github.com/marketplace/actions/skip-duplicate-actions&quot;&gt;Skip&amp;nbsp;Duplicate&amp;nbsp;Actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/taskworld/save-the-precious-build-minutes-reusing-build-outputs-with-git-tree-hash-k61&quot;&gt;Save&amp;nbsp;the&amp;nbsp;precious&amp;nbsp;build&amp;nbsp;minutes!&amp;nbsp;Reusing&amp;nbsp;build&amp;nbsp;outputs&amp;nbsp;with&amp;nbsp;Git&amp;nbsp;Tree&amp;nbsp;Hash&amp;nbsp; &lt;/a&gt;&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;서로 의존하지 않는 CI/CD를 분리할 수 있다.&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://jestjs.io/docs/cli#--shard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Jest&lt;/a&gt;나 &lt;a href=&quot;https://vitest.dev/guide/cli.html#shard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vitest&lt;/a&gt;등은 샤딩(shard) 옵션을 제공하므로 병렬 job으로 나누어 실행할 수도 있다.&lt;/p&gt;
&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;- 다운로드 및 CI/CD 환경&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CI/CD를 실행하려면 의존하는 패키지가 설치되어 있어야하고, 레포의 코드 또한 다운로드 받아야 한다.&lt;/p&gt;
&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://github.com/actions/cache&quot;&gt;깃허브 액션 캐시&lt;/a&gt;로 node_modules나 .yarn등만 캐시하면 충분하다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/dtinth/caching-docker-builds-in-github-actions-which-approach-is-the-fastest-a-research-18ei&quot;&gt;Caching Docker builds in GitHub Actions: Which approach is the fastest?   A research.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;buildx, buildkit 사용 [&lt;a href=&quot;https://docs.docker.com/buildx/working-with-buildx/&quot;&gt;Docker buildx&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.docker.com/develop/develop-images/build_enhancements/&quot;&gt;Build&amp;nbsp;images&amp;nbsp;with&amp;nbsp;BuildKit&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://blukat.me/2021/07/docker-buildkit-speedup/&quot;&gt;Docker&amp;nbsp;Buildkit&amp;nbsp;으로&amp;nbsp;빌드&amp;nbsp;시간&amp;nbsp;단축하기&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md#cache-backend-api&quot;&gt;도커 빌드 캐싱&lt;/a&gt;&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;도커빌드시 Nix를 이용해 캐싱하기 (이때 &lt;a href=&quot;https://nixos.wiki/wiki/Impermanence&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;tmpfs&lt;/a&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;a href=&quot;https://grahamc.com/blog/nix-and-layered-docker-images&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimising&amp;nbsp;Docker&amp;nbsp;Layers&amp;nbsp;for&amp;nbsp;Better&amp;nbsp;Caching&amp;nbsp;with&amp;nbsp;Nix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lewo.abesis.fr/posts/nix-build-container-image/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;faster&amp;nbsp;dockerTools.buildImage&amp;nbsp;prototype&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://storage.googleapis.com/nixdoc/nixery-layers.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nixery:&amp;nbsp;Improved&amp;nbsp;Layering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nlewo/nix2container&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;nix2container&lt;/a&gt;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도커 이미지 크기 줄이기 [&lt;a href=&quot;https://velog.io/@idnnbi/Docker-image-%ED%81%AC%EA%B8%B0-%EC%A4%84%EC%9D%B4%EA%B8%B0&quot;&gt;Docker - image 크기 줄이기&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://code-yeongyu.tistory.com/36&quot;&gt;Go 프로젝트 Docker 이미지 크기 99.2% 줄이기 (부제: 이미지 크기 12921% 떡상 시키기)&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#pushing-container-images&quot;&gt;깃허브 레지스트리&lt;/a&gt;: 깃허브 액션에서 깃허브 레지스트리가 더 빠르다는 듯&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 레포지토리 자체의 크기를 줄이는 것을 생각해볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bv5zsx/btrCz0IELoZ/CKZiKkNWPtRli0fxveaEdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bv5zsx/btrCz0IELoZ/CKZiKkNWPtRli0fxveaEdk/img.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.7008%; margin-right: 10px;&quot; data-widthpercent=&quot;47.81&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bv5zsx/btrCz0IELoZ/CKZiKkNWPtRli0fxveaEdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbv5zsx%2FbtrCz0IELoZ%2FCKZiKkNWPtRli0fxveaEdk%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;1200&quot; height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHASRn/btrCw7Bt5R6/vvJaKujaCwZYeek4UGCocK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHASRn/btrCw7Bt5R6/vvJaKujaCwZYeek4UGCocK/img.png&quot; data-origin-width=&quot;343&quot; data-origin-height=&quot;250&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.6386%; margin-right: 10px;&quot; data-widthpercent=&quot;34.44&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHASRn/btrCw7Bt5R6/vvJaKujaCwZYeek4UGCocK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHASRn%2FbtrCw7Bt5R6%2FvvJaKujaCwZYeek4UGCocK%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;343&quot; height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EldFE/btrCvX0CvC4/I4UKERmRFAkZ4VSKyHDKA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EldFE/btrCvX0CvC4/I4UKERmRFAkZ4VSKyHDKA1/img.png&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;1024&quot; data-is-animation=&quot;false&quot; style=&quot;width: 17.335%;&quot; data-widthpercent=&quot;17.75&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EldFE/btrCvX0CvC4/I4UKERmRFAkZ4VSKyHDKA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEldFE%2FbtrCvX0CvC4%2FI4UKERmRFAkZ4VSKyHDKA1%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;724&quot; height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://git-lfs.github.com/&quot;&gt;Git LFS&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://medium.com/day34/git-submodule-9f0ab0b79826&quot;&gt;Git submodule 활용하기&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://devblogs.microsoft.com/devops/introducing-scalar/&quot;&gt;Introducing Scalar: Git at scale for everyone&lt;/a&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;파일과 커밋기록 영구제거: 보통은 패스워드처럼 민감한 파일을 제거하는데 사용하지만 커다란 파일을 삭제하거나 레포지토리를 나눌때도 활용할 수 있다. [&lt;a href=&quot;https://black7375.tumblr.com/post/648508406606462976/%EA%B9%83-%EB%A0%88%ED%8F%AC-%EB%B6%84%EB%A6%AC%ED%95%98%EA%B8%B0%ED%95%A9%EC%B9%98%EA%B8%B0&quot;&gt;깃&amp;nbsp;레포&amp;nbsp;분리하기/합치기&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository&quot;&gt;Removing&amp;nbsp;sensitive&amp;nbsp;data&amp;nbsp;from&amp;nbsp;a&amp;nbsp;repository&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.baeldung.com/git-remove-file-commit-history&quot;&gt;Remove&amp;nbsp;a&amp;nbsp;Large&amp;nbsp;File&amp;nbsp;from&amp;nbsp;Commit&amp;nbsp;History&amp;nbsp;in&amp;nbsp;Git&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://about.gitlab.com/blog/2018/06/07/keeping-git-commit-history-clean/&quot;&gt;How&amp;nbsp;(and&amp;nbsp;why!)&amp;nbsp;to&amp;nbsp;keep&amp;nbsp;your&amp;nbsp;Git&amp;nbsp;commit&amp;nbsp;history&amp;nbsp;clean&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-lfs.github.com/&quot;&gt;Git LFS&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용: 커다란 파일은 텍스트 해시로 만들고 따로 다운로드하여 가볍게 만들 수 있다&lt;/li&gt;
&lt;li&gt;서브모듈 사용: 역시 원본 레포를 가볍게 만들며,&amp;nbsp;&lt;a href=&quot;https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---jobsltngt&quot;&gt;git clone --jobs&lt;/a&gt;로 여러 서브모듈을 한번에 다운로드 받을 수 있다&lt;/li&gt;
&lt;li&gt;레포지토리 GC: 복잡한 레포지토리의 경우 object/pack등을 관리해볼수도 있다 [&lt;a href=&quot;https://black7375.tumblr.com/post/647156727988568064/%EB%A0%88%ED%8F%AC%EC%A7%80%ED%86%A0%EB%A6%AC%EB%A5%BC-%EA%B0%80%EB%B3%8D%EA%B2%8C&quot;&gt;레포지토리를&amp;nbsp;가볍게&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://medium.com/@hyungjun.rho/%EA%B1%B0%EB%8C%80%ED%95%9C-git-%EC%9D%98-%EC%84%B1%EB%8A%A5%EC%9D%84-%EC%9C%A0%EC%A7%80%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EC%A0%84%EB%9E%B5-e5834752b404&quot;&gt;Git&amp;nbsp;저장소의&amp;nbsp;성능을&amp;nbsp;유지하는&amp;nbsp;방법&lt;/a&gt;, &lt;a href=&quot;https://github.blog/2021-04-29-scaling-monorepo-maintenance/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Scaling&amp;nbsp;monorepo&amp;nbsp;maintenance&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1652927410836&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git remote prune orign
git reflog expire --expire=now --all
git gc --aggressive --prune=now
git repack -abdk --window=1000 --depth=500
git repack -fF --write-midx --write-bitmap-index -d --geometric=2&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;&lt;span&gt;Git 2.18에서 도입되어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.blog/2020-03-22-highlights-from-git-2-26/&quot;&gt;2.26&lt;/a&gt;&lt;span&gt;에 기본값으로 채택된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://opensource.googleblog.com/2018/05/introducing-git-protocol-version-2.html&quot;&gt;Git prtocol2&lt;/a&gt;가 큰 도움이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 CI/CD에서 테스트 하는데 모든 정보를 다운로드 받을 필요는 없지 않겠는가?&lt;/p&gt;
&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;800&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D2nIe/btrV46Y1C5s/lof9GSuBHlceCGXUYim2Mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D2nIe/btrV46Y1C5s/lof9GSuBHlceCGXUYim2Mk/img.png&quot; data-alt=&quot;모든 커밋 - 원: 커밋, 삼각형: 디렉토리, 사각형: 파일(blob)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D2nIe/btrV46Y1C5s/lof9GSuBHlceCGXUYim2Mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD2nIe%2FbtrV46Y1C5s%2Flof9GSuBHlceCGXUYim2Mk%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;800&quot; height=&quot;414&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;모든 커밋 - 원: 커밋, 삼각형: 디렉토리, 사각형: 파일(blob)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://git-scm.com/docs/partial-clone&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;부분 복제(Partical clone)&lt;/a&gt;은 --filter 옵션을 통해 기존 파일(--filter=blob:none), 더 나아가 디렉토리(--filter=tree:0)를 제외하고 다운로드 받을 수 있게 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[&lt;a href=&quot;https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/&quot;&gt;Get&amp;nbsp;up&amp;nbsp;to&amp;nbsp;speed&amp;nbsp;with&amp;nbsp;partial&amp;nbsp;clone&amp;nbsp;and&amp;nbsp;shallow&amp;nbsp;clone&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://www.perforce.com/blog/vcs/git-beyond-basics-using-shallow-clones&quot;&gt;How to Use Git Shallow Clone to Improve Performance&lt;/a&gt;, &lt;a href=&quot;https://docs.gitlab.com/ee/topics/git/partial_clone.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gitlab partial clone&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/55l3h/btrV5CQKaNr/LDm8a66iCgwhbIKHmWK6W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/55l3h/btrV5CQKaNr/LDm8a66iCgwhbIKHmWK6W0/img.png&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;414&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3877%; margin-right: 10px;&quot; data-widthpercent=&quot;49.97&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/55l3h/btrV5CQKaNr/LDm8a66iCgwhbIKHmWK6W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F55l3h%2FbtrV5CQKaNr%2FLDm8a66iCgwhbIKHmWK6W0%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;799&quot; height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s4VWN/btrV6Dg9dMv/914QtKB91W8x1zXdrcNgXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s4VWN/btrV6Dg9dMv/914QtKB91W8x1zXdrcNgXk/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;414&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4495%;&quot; data-widthpercent=&quot;50.03&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s4VWN/btrV6Dg9dMv/914QtKB91W8x1zXdrcNgXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs4VWN%2FbtrV6Dg9dMv%2F914QtKB91W8x1zXdrcNgXk%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;800&quot; height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;기존 파일을 빼고, 기존 디렉토리를 빼고&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clone시 --depth=1로 1개의 커밋으로 제한시키고, --single-branch --branch=&amp;lt;branch&amp;gt;로 브랜치를 제한할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAyaCP/btrCzZJJdX7/6lWb5fiuvhfFGwKCCwKUsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAyaCP/btrCzZJJdX7/6lWb5fiuvhfFGwKCCwKUsk/img.png&quot; data-alt=&quot;기존 커밋기록까지 빼고&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAyaCP/btrCzZJJdX7/6lWb5fiuvhfFGwKCCwKUsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAyaCP%2FbtrCzZJJdX7%2F6lWb5fiuvhfFGwKCCwKUsk%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;799&quot; height=&quot;414&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;414&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://github.blog/2020-01-13-highlights-from-git-2-25/&quot;&gt;Git 2.25&lt;/a&gt;에서 도입된 sparse-checkout을 사용하면 원하는 부분만 체크아웃할 수 있어 시간과 디스크 용량을 절약할 수 있다. [&lt;a href=&quot;https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/&quot;&gt;Bring your monorepo down to size with sparse-checkout&lt;/a&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;585&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buJGSo/btrV47p2JLi/zzIIp9k3twZ2dMWzsG9bKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buJGSo/btrV47p2JLi/zzIIp9k3twZ2dMWzsG9bKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buJGSo/btrV47p2JLi/zzIIp9k3twZ2dMWzsG9bKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuJGSo%2FbtrV47p2JLi%2FzzIIp9k3twZ2dMWzsG9bKK%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;800&quot; height=&quot;585&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;585&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---filterltfilter-specgt&quot;&gt;clone --filter&lt;/a&gt; : 옛 커밋에서 복제할 내용을 필터링 가능 (particial clone)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---depthltdepthgt&quot;&gt;clone --depth&lt;/a&gt;&lt;span&gt;: 가져올 커밋 히스토리양을 제한&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---no-single-branch&quot;&gt;clone --single-branch&lt;/a&gt;: 한 브랜치만 클론 할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.git-scm.com/docs/git-sparse-checkout&quot;&gt;sparse-checkout&lt;/a&gt;:&amp;nbsp; 특정 디렉토리나 파일만 사용&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;a href=&quot;https://github.blog/2022-10-03-highlights-from-git-2-38/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; Git 2.38&lt;/a&gt;에는 scalar라는 기능이 들어가서 sparse를 기본으로 lazy하게 쓸 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/2022-10-13-the-story-of-scalar/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Story of Scalar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/devops/introducing-scalar/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introducing&amp;nbsp;Scalar:&amp;nbsp;Git&amp;nbsp;at&amp;nbsp;scale&amp;nbsp;for&amp;nbsp;everyone&lt;/a&gt;&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;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;/p&gt;
&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;소스파일 빌드관련 캐시처럼 매번 캐시업로드가 필요한 경우가 있을 수도 있다.&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;10메가, 20메가 수준이라면 괜찮겠지만 기가 단위처럼 커다란 경우라면 캐시가 깨져 빌드가 조금 느리더라도 일주일에 한번씩처럼 주기적으로 갱신하는게 좋을 수 있다.&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;</description>
      <category>프로그래밍/Web</category>
      <category>빌드</category>
      <category>성능</category>
      <category>웹</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/82</guid>
      <comments>https://black7375.tistory.com/82#entry82comment</comments>
      <pubDate>Fri, 5 Mar 2021 12:32:45 +0900</pubDate>
    </item>
    <item>
      <title>[스압/데이터주의] 웹 최적화 방식 모음 - 4. 로드 후</title>
      <link>https://black7375.tistory.com/81</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/72&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 0. 전반적 원칙과 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/73&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 1. 다운로드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/74&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 2. 파싱 및 렌더링 트리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/79&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3. Layout 및 렌더링&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/80&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3.3 UX 트릭&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/81&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 4. 로드 후(현재)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/82&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 5. 빌드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 로드 후&lt;/h2&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;4.1 요청줄이기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 페이지로 넘어갈 때 요청량을 줄일 수 있는 여러 기법들이 존재한다. &lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://github.com/pazguille/offline-first&quot;&gt;Offline First&lt;/a&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;h4 data-ke-size=&quot;size20&quot;&gt;4.1.1 클라이언트 저장소들 비교와 활용&lt;/h4&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;로드 후, 브라우저에 정보를 저장하는 것은 캐시로 사용해 서버에 요청을 줄이거나 낙관적 UI(Optimistic UI)를 구현할 때 커다란 도움이 될 수 있기 때문에 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크로미움의 어플리케이션 탭에 들어가면 스토리지 항목 5개, 캐시 2개가 등장한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ce6tT3/btqZfg44QxU/1YQXM73vMTPlzOosBWmnCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ce6tT3/btqZfg44QxU/1YQXM73vMTPlzOosBWmnCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ce6tT3/btqZfg44QxU/1YQXM73vMTPlzOosBWmnCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fce6tT3%2FbtqZfg44QxU%2F1YQXM73vMTPlzOosBWmnCK%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;238&quot; height=&quot;290&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 Storage, DB, &lt;span style=&quot;color: #333333;&quot;&gt;Cookie&lt;/span&gt;, Cache로 나누어 간단히 정리해보았다. [&lt;a href=&quot;https://dongwoo.blog/2016/12/19/%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%B8%A1%EC%9D%98-%EC%A0%80%EC%9E%A5%EC%86%8C-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;클라이언트 측의 저장소 살펴보기&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@erwinousy/%EC%BF%A0%ED%82%A4-vs-%EB%A1%9C%EC%BB%AC%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C-28b8db2ca7b2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;쿠키&amp;nbsp;vs&amp;nbsp;로컬스토리지:&amp;nbsp;차이점은&amp;nbsp;무엇일까?&lt;/a&gt;, &lt;a href=&quot;https://okayoon.tistory.com/entry/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%BF%A0%ED%82%A4Cookie-%EC%84%B8%EC%85%98%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80Session-Storage-%EB%A1%9C%EC%BB%AC%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80Local-Storage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;브라우저&amp;nbsp;쿠키(Cookie),&amp;nbsp;세션스토리지(Session&amp;nbsp;Storage),&amp;nbsp;로컬스토리지(Local&amp;nbsp;Storage)&lt;/a&gt;, &lt;a href=&quot;https://www.html5rocks.com/ko/tutorials/offline/quota-research/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Working&amp;nbsp;with&amp;nbsp;quota&amp;nbsp;on&amp;nbsp;mobile&amp;nbsp;browsers&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;b&gt;Storage&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web Storage&lt;/a&gt;는 클라이언트에 데이터를 저장하기 위해 만들어진 HTML5의 새로운 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Key-Value 방식으로 이루어진다.&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;&lt;b&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Session Storage&lt;/a&gt;:&lt;/b&gt; 5MB, 같은 탭, 브라우저 종료 시 삭제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Local Storage&lt;/a&gt;:&lt;/b&gt; 10MB, 모든 탭, 만료기간 없음&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;b&gt;DB&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹어플리케이션을 만들도록 도와주는 브라우저 내부에서 사용할 수 있는 DB다. [&lt;a href=&quot;https://hacks.mozilla.org/2010/06/beyond-html5-database-apis-and-the-road-to-indexeddb/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Beyond&amp;nbsp;HTML5:&amp;nbsp;Database&amp;nbsp;APIs&amp;nbsp;and&amp;nbsp;the&amp;nbsp;Road&amp;nbsp;to&amp;nbsp;IndexedDB&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@pks2974/indexeddb-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-ca9be4add614&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IndexedDB&amp;nbsp;간단&amp;nbsp;정리하기&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;b&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IndexdDB&lt;/a&gt;:&lt;/b&gt; &lt;span style=&quot;color: #333333;&quot;&gt;Key-Value 방식(JSON), 50MB, 모든 탭, 만료기간 없음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.w3.org/TR/webdatabase/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;Web SQL(Deprecated)&lt;/b&gt;&lt;/a&gt;&lt;b&gt;:&lt;/b&gt; SQLite Wrapper, 50MB, 모든 탭, 만료기간 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Web SQL은 표준화를 시키기 어려워서 Deprecated 되었다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;This&amp;nbsp;document&amp;nbsp;was&amp;nbsp;on&amp;nbsp;the&amp;nbsp;W3C&amp;nbsp;Recommendation&amp;nbsp;track&amp;nbsp;but&amp;nbsp;specification&amp;nbsp;work&amp;nbsp;has&amp;nbsp;stopped.&amp;nbsp;The&amp;nbsp;specification&amp;nbsp;reached&amp;nbsp;an&amp;nbsp;impasse:&amp;nbsp;all&amp;nbsp;interested&amp;nbsp;implementors&amp;nbsp;have&amp;nbsp;used&amp;nbsp;the&amp;nbsp;same&amp;nbsp;SQL&amp;nbsp;backend&amp;nbsp;(Sqlite),&amp;nbsp;but&amp;nbsp;we&amp;nbsp;need&amp;nbsp;multiple&amp;nbsp;independent&amp;nbsp;implementations&amp;nbsp;to&amp;nbsp;proceed&amp;nbsp;along&amp;nbsp;a&amp;nbsp;standardisation&amp;nbsp;path.&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;Cookie&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cookie[&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP Cookie&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Document.cookie&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/cookies&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Javascript cookies&lt;/a&gt;]에는 저장 유형, 연결 유형에 따라 여러가지로 나뉘기도 하나 여기에서는 Session Cookie와 Persistent Cookie만 다룬다. [&lt;a href=&quot;https://en.wikipedia.org/wiki/HTTP_cookie#Terminology&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP Cookie - Terminlogy&lt;/a&gt;, &lt;a href=&quot;https://prateeksurana.me/blog/javascript-developer-guide-to-browser-cookies/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;JavaScript&amp;nbsp;developer&amp;rsquo;s&amp;nbsp;guide&amp;nbsp;to&amp;nbsp;browser&amp;nbsp;cookies&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;Key-Value 방식이지만 사용하기는 Storage보다 불편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setCookie나 getCookie 함수를 만들어 사용하는 것이 좋다고 생각한다. [&lt;a href=&quot;https://webisfree.com/2015-02-04/[%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8]-%EC%BF%A0%ED%82%A4(cookie)-%EC%A0%80%EC%9E%A5-%EB%B0%8F-%EC%82%AD%EC%A0%9C-%EC%98%88%EC%A0%9C%EB%B3%B4%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;쿠키(Cookie)&amp;nbsp;저장&amp;nbsp;및&amp;nbsp;삭제&amp;nbsp;예제보기&lt;/a&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: #333333;&quot;&gt;&lt;b&gt;Session Cookie:&lt;/b&gt; 4KB, 모든 탭, 브라우저 종료 시 삭제&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Persistent Cookie:&lt;/b&gt; 4KB, 모든 탭, 만료시기가 되면 삭제&lt;/p&gt;
&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;Cache&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘다 리소스를 캐싱하여 속도를 빠르게 만들고, 서버의 로드비용을 아껴준다. [&lt;a href=&quot;http://researchhubs.com/post/computing/web-application/browser-cache-vs-html5-application-cache.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Browser Cache vs HTML5 Application Cache&lt;/a&gt;, &lt;a href=&quot;https://stackoverflow.com/questions/22958006/browser-cache-vs-html5-application-cache&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Browser&amp;nbsp;Cache&amp;nbsp;Vs&amp;nbsp;HTML5&amp;nbsp;Application&amp;nbsp;Cache&lt;/a&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;b&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cache Storage&lt;/a&gt;:&lt;/b&gt; 실제로 방문한 페이지만&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/applicationCache&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Application Cache(Deprecated)&lt;/a&gt;:&lt;/b&gt; Manifest 사용, 100MB, 오프라인 브라우징&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 Application Cache는 &lt;a href=&quot;https://html.spec.whatwg.org/multipage/offline.html#offline&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Deprecated&lt;/a&gt;가 되었기 때문에 서비스워커 + 캐시 API로 마이그레이션을 해야 한다. [&lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/audits/appcache&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Application&amp;nbsp;Cache를&amp;nbsp;사용하지&amp;nbsp;않는&amp;nbsp;사이트&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;b&gt;해결방안&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 Deprecated된 Web SQL과 Application Cache는 사용하지 않는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storage와 Application Cache는 메인 스레드를 차단하는 동기 API이므로, 대규모 데이터를 사용하려면 비동기적이고 웹워커에서 접근 가능한 IndexedDB를 사용하는 것이 좋다. [&lt;a href=&quot;https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/offline-for-pwa?hl=ko&quot;&gt;Progressive&amp;nbsp;Web&amp;nbsp;App용&amp;nbsp;오프라인&amp;nbsp;저장소&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;또한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Web_Workers_API/Structured_clone_algorithm&quot;&gt;The structured clone algorithm&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;을 사용하여 파일에서 JSON을 저장하거나 검색하는 것보다 낫다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;단, IndexedDB의 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;a href=&quot;https://addyosmani.com/basket.js/&quot;&gt;Basket.js&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;를 사용하면 localStorage에 저장(캐싱)하는 것이 가능하다.&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;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;h4 data-ke-size=&quot;size20&quot;&gt;4.1.2 쿠키 사용 줄이기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Cookies&quot;&gt;HTTP 쿠키&lt;/a&gt;들(cookies)은 인증 및 개인화와 같은 다양한 이유로 사용된다.&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://yuiblog.com/blog/2007/03/01/performance-research-part-3/&quot;&gt;When&amp;nbsp;the&amp;nbsp;Cookie&amp;nbsp;Crumbles&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;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;다른 서브도메인들이 영향을 받지 않도록 적절한 도메인 수준(level)에서 쿠키설정을 주의&lt;/li&gt;
&lt;li&gt;적절한 만료(Expires) 날짜를 설정&lt;br /&gt;이른 만료날짜를 설정하거나 설정하지 않으면, 사용자의 응답시간 개선을 위해 쿠키를 즉시 제거&lt;/li&gt;
&lt;li&gt;클라이언트에 정보를 저장해야 하는 경우 Storage나 IndexedDB 고려&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3번째 항목을 조금 더 설명하자면 쿠키 free 도메인을 사용하자는 뜻이다.&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;만약&amp;nbsp;도메인이&amp;nbsp;www.example.org이라면,&amp;nbsp;static.example.org에&amp;nbsp;정적&amp;nbsp;구성요소들을&amp;nbsp;호스팅&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나&amp;nbsp;www.example.org가 아니라&amp;nbsp;최상위&amp;nbsp;도메인&amp;nbsp;example.org에 쿠키들을 설정했다면, static.example.org로의&amp;nbsp;모든&amp;nbsp;요청은&amp;nbsp;쿠키들을&amp;nbsp;포함한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한&amp;nbsp;이&amp;nbsp;도메인은&amp;nbsp;cookie-free&amp;nbsp;상태로&amp;nbsp;유지될&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Yahoo는&amp;nbsp;&lt;a href=&quot;http://yimg.com&quot;&gt;yimg.com&lt;/a&gt;을&amp;nbsp;사용,&amp;nbsp;YouTube는&amp;nbsp;&lt;a href=&quot;http://ytimg.com&quot;&gt;ytimg.com&lt;/a&gt;을&amp;nbsp;사용하고&amp;nbsp;Amazon은&amp;nbsp;&lt;a href=&quot;images-amazon.com&quot;&gt;images-amazon.com&lt;/a&gt;&amp;nbsp;등을&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;Cookie-free&amp;nbsp;도메인에서&amp;nbsp;적정&amp;nbsp;구성요소들을&amp;nbsp;호스팅&amp;nbsp;하는&amp;nbsp;것의&amp;nbsp;또&amp;nbsp;다른&amp;nbsp;이점은&amp;nbsp;일부&amp;nbsp;proxies가&amp;nbsp;쿠키들과&amp;nbsp;함께&amp;nbsp;요청된&amp;nbsp;구성요소들을&amp;nbsp;cache하는&amp;nbsp;것을&amp;nbsp;거부할&amp;nbsp;수도&amp;nbsp;있다는&amp;nbsp;것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은&amp;nbsp;맥락으로,&amp;nbsp;홈페이지에&amp;nbsp;example.org&amp;nbsp;또는&amp;nbsp;www.example.org의 사용을 망설이고 있는 중이라면, 쿠키에 미치는 영향을 고려해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;www를 생략하는 경우는 *.example.org의&amp;nbsp;쿠키들을&amp;nbsp;작성하는&amp;nbsp;것&amp;nbsp;밖에&amp;nbsp;할&amp;nbsp;수&amp;nbsp;없지만,&amp;nbsp;성능을&amp;nbsp;위해&amp;nbsp;www&amp;nbsp;서브도메인을&amp;nbsp;사용하고&amp;nbsp;그&amp;nbsp;서브도메인에&amp;nbsp;대한&amp;nbsp;쿠키들을&amp;nbsp;작성하는&amp;nbsp;것이&amp;nbsp;최선의&amp;nbsp;방법이다.&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;4.1.3 캐시 제어문&amp;nbsp; 헤더 추가&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; server&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 규칙에는 두 가지 측면이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 components: 미래 설정 시점까지의 &amp;ldquo;Never expire&amp;rdquo; 정책 수행&lt;/li&gt;
&lt;li&gt;동적 components: 조건적 요청의 브라우저를 수행하기 위한 적절한 Cache-Control 헤더의 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지를 처음 방문한 사용자는 여러 개의 HTTP 요청을해야 할 수도 있지만 캐시 제어문 헤더를 사용하면 해당 구성 요소를 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching&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;이는 후속 페이지 로딩 시에서 불필요한 HTTP 요청 수 및 크기를 피하고 로딩속도를 빠르게 만든다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지와 함께 가장 많이 사용하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;스크립트, 스타일 시트를 포함한&lt;span&gt;&amp;nbsp;&lt;/span&gt;모든&lt;span&gt; &lt;/span&gt;구성 요소&lt;span&gt;&amp;nbsp;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BXXSM/btqZctRF5fq/B7ODdVq4CkUNAykQkvx0AK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BXXSM/btqZctRF5fq/B7ODdVq4CkUNAykQkvx0AK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BXXSM/btqZctRF5fq/B7ODdVq4CkUNAykQkvx0AK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBXXSM%2FbtqZctRF5fq%2FB7ODdVq4CkUNAykQkvx0AK%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;910&quot; height=&quot;573&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시는 프록시나 CDN등에서 하는 Shared Cache, 브라우저에서 하는 Local Cache로 나눌수 있다.&lt;/p&gt;
&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://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cache-Control&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Expires&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Pragma&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pragma&lt;/a&gt;로 제어할 수 있는데 Cache-Control이나 Expires를 사용하는 것을 권장한다. [&lt;a href=&quot;https://docs.microsoft.com/ko-kr/azure/cdn/cdn-how-caching-works&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;b&gt;- Cache-Control&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;요청(Request), 응답(Response)&lt;/li&gt;
&lt;li&gt;후에 설명할 Expires 헤더의 제한 사항 해결을 위해 HTTP 1.1에 도입됨&lt;/li&gt;
&lt;li&gt;따라서 Expires와 충돌 시 우선한다.&lt;/li&gt;
&lt;li&gt;헤더 종류
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;no-store: 캐시하지 않고, 항상 다시 다운로드&lt;/li&gt;
&lt;li&gt;no-cache: 캐시하지만, 재검증을 위한 요청&lt;/li&gt;
&lt;li&gt;must-revalidate: 만료된 캐시만 재검증&lt;/li&gt;
&lt;li&gt;public | private: public은 프록시에 저장을 허용하고, private는 브라우저에만 저장을 허용&lt;/li&gt;
&lt;li&gt;max-age=&amp;lt;second&amp;gt;: 리소스가 유효하다고 판단하는 최대시간을 명시, 0이면 no-cache와 같음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시&lt;/p&gt;
&lt;pre id=&quot;code_1585558337220&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      Cache-Control:public, max-age=31536000&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;- 만료(Expires)&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;응답(Response)&lt;/li&gt;
&lt;li&gt;HTTP 1.0에 도입&lt;/li&gt;
&lt;li&gt;&amp;lt;http-date&amp;gt; 값을 사용하며 max-age와 비슷하다.&lt;/li&gt;
&lt;/ul&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;2020년 4월 15일까지 유효한 브라우저를 알리는 미래 시점의 Expires header이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1585558171920&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      Expires:&amp;nbsp;Wed,&amp;nbsp;15&amp;nbsp;Apr&amp;nbsp;2020&amp;nbsp;20:00:00&amp;nbsp;GMT&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;- Pragma&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;요청(Request)&lt;/li&gt;
&lt;li&gt;HTTP 응답에서 명시되지 않았던 헤더라 Cache-Control의 신뢰할 만한 대체제가 아니며, 지원하지 않는 곳들도 많다.&lt;/li&gt;
&lt;li&gt;no-cache: Cache-Control의 no-cache와 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시&lt;/p&gt;
&lt;pre id=&quot;code_1585558224005&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      Pragma: no-cache&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: #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;사용자가 처음으로 사이트를 방문하고 브라우저 캐시가 비어있는 경우 HTTP 요청 수에는 영향을 미치지 않는다는 말.&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;&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;a href=&quot;http://yuiblog.com/blog/2007/01/04/performance-research-part-2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Yahoo!의 측정결과&lt;/a&gt; 캐시되어 있는 페이지 조회수는 75-85 %이었다. &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;&lt;span style=&quot;color: #333333;&quot;&gt;Ajax나 SPA에서도 캐싱을 적극적으로 활용하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;aphache는 .htaccess 파일을 이용해 설정할 수 있다.[&lt;a href=&quot;https://httpd.apache.org/docs/2.4/caching.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Caching Guide&lt;/a&gt;, &lt;a href=&quot;https://httpd.apache.org/docs/2.4/en/mod/mod_expires.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;mod_expires&lt;/a&gt;, &lt;a href=&quot;https://www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Speed&amp;nbsp;Up&amp;nbsp;Sites&amp;nbsp;with&amp;nbsp;htaccess&amp;nbsp;Caching&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1585572646445&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;ifModule mod_expires.c&amp;gt;
ExpiresActive On
ExpiresDefault &quot;access plus 1 month&quot; # years | months | weeks | days | hours | minutes | seconds
ExpiresByType image/gif &quot;access 3 minutes&quot;
ExpiresByType image/png &quot;access 3 minutes&quot;
ExpiresByType image/jpg &quot;access 3 minutes&quot;
ExpiresByType text/css &quot;access 3 minutes&quot;
&amp;lt;/ifModule&amp;gt;

&amp;lt;ifModule mod_headers.c&amp;gt;
# YEAR
&amp;lt;FilesMatch &quot;\.(ico|gif|jpg|jpeg|png|flv|pdf)$&quot;&amp;gt;
  Header set Cache-Control &quot;public, max-age=29030400&quot;
&amp;lt;/FilesMatch&amp;gt;
# WEEK
&amp;lt;FilesMatch &quot;\.(js|css|swf)$&quot;&amp;gt;
  Header set Cache-Control &quot;public, max-age=604800&quot;
&amp;lt;/FilesMatch&amp;gt;
# 45 MIN
&amp;lt;FilesMatch &quot;\.(html|htm|txt)$&quot;&amp;gt;
  Header set Cache-Control &quot;max-age=2700&quot;
&amp;lt;/FilesMatch&amp;gt;
&amp;lt;/ifModule&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;nginx.conf를 다음처럼 설정해볼 수 있다 [&lt;a href=&quot;https://www.nginx.com/blog/nginx-caching-guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;Caching&amp;nbsp;with&amp;nbsp;NGINX&amp;nbsp;and&amp;nbsp;NGINX&amp;nbsp;Plus&lt;/a&gt;, &lt;a href=&quot;https://jootc.com/p/20180519958&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nginx 캐시 설정 및 캐시 만료일 기간 설정&lt;/a&gt;, &lt;a href=&quot;https://serversforhackers.com/c/nginx-caching&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nginx Caching&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1585570503459&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# cache.appcache, your document html and data
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
    expires -1;
    # access_log logs/static.log; # I don't usually include a static log
}

# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|png|gif|ico|gz|svg|svgz|ogg|mp4|webm|ogv|htc|cur)$ {
    expires 3M;
    access_log off;
    add_header Cache-Control &quot;public&quot;, max-age=31536000;
}

# Source File
location ~* \.(?:css|js)$ {
    expires 1M; 
    access_log off;
    add_header Cache-Control &quot;public&quot;;
}

# Favicon
location = /favicon.ico {
    expires max;
    access_log off;
    log_not_found off;
}

# Feed
location ~* \.(?:rss|atom)$ {
    expires 1h;
    add_header Cache-Control &quot;public&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gist.github.com/philipstanislaus/654adafad91efb6de230845b5bdeae61&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sane-caching.nginx.conf(gist)&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;php의 경우 다음과 같이 해볼 수 있는 모양이다. [&lt;a href=&quot;https://www.php.net/manual/en/function.header.php&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;header&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1585571582301&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?php
  header(&quot;Cache-Control: public, max-age=31536000&quot;);
  //or
  header(&quot;Expires:&amp;nbsp;Wed,&amp;nbsp;15&amp;nbsp;Apr&amp;nbsp;2020&amp;nbsp;20:00:00&amp;nbsp;GMT&quot;);
?&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;a href=&quot;https://expressjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;expressjs&lt;/a&gt;를 사용할 경우 &lt;a href=&quot;https://web.dev/codelab-http-cache/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;web.dev의 문서&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;b&gt;- meta 태그 사용&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;a href=&quot;http://vancouver-webpages.com/META/metatags.detail.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Dictionary&amp;nbsp;of&amp;nbsp;HTML&amp;nbsp;META&amp;nbsp;Tags&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1585559985027&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;meta http-equiv=&quot;Cache-control&quot; content=&quot;public, max-age=31536000&quot;&amp;gt;
&amp;lt;meta http-equiv=&quot;expires&quot; content=&quot;Wed,&amp;nbsp;15&amp;nbsp;Apr&amp;nbsp;2020&amp;nbsp;20:00:00&amp;nbsp;GMT&quot;&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;- 기한&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글이 제공하는 &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP Caching 문서&lt;/a&gt;에서는 다음과 같이 되어 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML: no-cache&lt;/li&gt;
&lt;li&gt;CSS: public, max-age=31536000(1년)&lt;/li&gt;
&lt;li&gt;JS: private, max-age=315360000&lt;/li&gt;
&lt;li&gt;Image: max-age: 86400&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JS파일에 개인정보가 없다면 public으로 해도 상관은 없다.&lt;/p&gt;
&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;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;/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;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;예를들어 EXAMPLE&lt;span style=&quot;color: #333333;&quot;&gt;_2.0.6.js처럼 &lt;span style=&quot;color: #333333;&quot;&gt;버전 번호, EXAMPLE_20200402.js처럼 날짜등을&lt;/span&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;webpack의 경우 &lt;a href=&quot;https://webpack.js.org/guides/caching/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Caching 문서&lt;/a&gt;를 확인해보면 자동으로 생성해준다.[&lt;a href=&quot;https://medium.com/@sahilkkrazy/hash-vs-chunkhash-vs-contenthash-e94d38a32208&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hash&amp;nbsp;vs&amp;nbsp;chunkhash&amp;nbsp;vs&amp;nbsp;ContentHash&lt;/a&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;4.1.4 유효성 검사&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; server&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: #333333;&quot;&gt;Cache-Control: must-revalidate이 명시되어 있거나 만료시간이 가까워도 검증은 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;910&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIMCsD/btqZkqyPOmD/AWFdEe7vC17f4PmxaUZEd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIMCsD/btqZkqyPOmD/AWFdEe7vC17f4PmxaUZEd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIMCsD/btqZkqyPOmD/AWFdEe7vC17f4PmxaUZEd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIMCsD%2FbtqZkqyPOmD%2FAWFdEe7vC17f4PmxaUZEd0%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;822&quot; height=&quot;910&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;910&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유효성 검사 결과 수정되지 않았다면 요청한 리소스 본문대신&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;304 Not Modified를 보내며, 수정되었다면 200 OK와 함께 새로운 리소스 본문과 새롭게 대체할 유효성 값을 보낸다.&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;&lt;b&gt;- ETag&lt;/b&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://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ETag&lt;/a&gt; (Entity 태그)는 &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: #333333;&quot;&gt;&quot;Entity&quot;는 이미지, 스크립트, 스타일 시트 등 &quot;Component(구성 요소)&quot;라는 또 다른 단어.&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;&lt;span style=&quot;color: #333333;&quot;&gt;ETag는 후에 설명할 Last-Modified(마지막 수정 일자)보다 유연한 엔터티를 검증하는 메커니즘을 제공한다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&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;span style=&quot;color: #333333;&quot;&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;Etag는 강한 검증, 약한 검증이 존재한다. [&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Conditional_requests&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP 조건부 요청&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강한 검증은 바이트 대 바이트로 동일한지 보장하는 것으로 MD5같은 해시를 이용한다.&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;약한 검증을 하고 싶으면 W/를 앞에 붙이면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1585753591954&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      ETag: &quot;33a64df551425fcc55e4d42a148795d9f25f89d4&quot;
      ETag: W/&quot;0815&quot;&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;응답 받았을 때 Etag 값은 If-None-Match 헤더에 포함시켜 전송 후 유효성을 판단한다.&lt;/p&gt;
&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;- Last-Modified&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Last-Modified&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Last-Modified&lt;/a&gt;는 말 그대로 마지막으로 수정된 날짜를 말하며 Expires의 형식과 같다.&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;응답 받았을 때 Last-Modified 값은 If-Modified-Since 헤더에 포함시켜 전송 후 유효성을 판단한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Last-Modified와 Etags의 관계는 Expires와 Cache-Control과 비슷해서 동시에 존재하면 Etags를 우선한다.&lt;/p&gt;
&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: #333333;&quot;&gt;- 정리&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;먼저 Etag나 Last-Modified와 함께 온다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1584933077052&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      HTTP/1.1 200 OK
      Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
      ETag: &quot;10c24bc-4ab-457e1c1f&quot;
      Content-Length: 12195&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&gt;&amp;nbsp;&lt;/span&gt;경우&lt;span&gt; &lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;If-None-Match나 If-Modified-Since &lt;/span&gt;&lt;/span&gt;헤더를&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용하여 ETag나 Last-Modified 값을 원래 서버로 다시 전달한다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일치하면 304 예제 코드가 리턴되어 이 예제의 응답을 12195 바이트만큼 줄인다.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077052&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      GET /i/yahoo.gif HTTP/1.1
      Host: us.yimg.com
      If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
      If-None-Match: &quot;10c24bc-4ab-457e1c1f&quot;
      HTTP/1.1 304 Not Modified&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;a href=&quot;https://cyberx.tistory.com/m/9&quot;&gt;더 빠른 웹을 위하여 - 웹 캐쉬(WEB CACHE)&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;b&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;&lt;b&gt;유효성(Validation):&lt;/b&gt;&amp;nbsp;If-Modified-Since(1.0),&amp;nbsp;If-None-Match&lt;/li&gt;
&lt;li&gt;&lt;b&gt;신선도(Freshness):&lt;/b&gt;&amp;nbsp;Pragma(1.0),&amp;nbsp;Cache-Control(1.1)&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&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;&lt;b&gt;유효성(Validation):&lt;/b&gt;&amp;nbsp;Last-Modified(1.0),&amp;nbsp;Entity&amp;nbsp;Tag(1.1)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;신선도(Freshness):&lt;/b&gt;&amp;nbsp;Expires(1.0),&amp;nbsp;Cache-Control(1.1)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청과&amp;nbsp;관련된&amp;nbsp;추가적인&amp;nbsp;내용은&amp;nbsp;강/약한&amp;nbsp;검증에서&amp;nbsp;소개했던&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP&amp;nbsp;conditional&amp;nbsp;requests&lt;/a&gt;에&amp;nbsp;잘&amp;nbsp;나와있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;a href=&quot;https://httpd.apache.org/docs/2.4/mod/core.html#fileetag&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FileETag&lt;/a&gt;를, Nginx는 &lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_core_module.html#etag&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;etag&lt;/a&gt; 지시어를 이용해 조절 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;단, 서버를 여러대 사용할 경우, etag 값은 달라질 수도 있는데 이 경우 Etag를 제거하거나 inode 값을 빼야 한다.&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTcPOV/btqZlPrB3CT/McNUX1e3dOAy4TI6dcD7s1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTcPOV/btqZlPrB3CT/McNUX1e3dOAy4TI6dcD7s1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTcPOV/btqZlPrB3CT/McNUX1e3dOAy4TI6dcD7s1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTcPOV%2FbtqZlPrB3CT%2FMcNUX1e3dOAy4TI6dcD7s1%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;595&quot; height=&quot;600&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;600&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://engineering.fb.com/2017/01/26/web/this-browser-tweak-saved-60-of-requests-to-facebook/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;This&amp;nbsp;browser&amp;nbsp;tweak&amp;nbsp;saved&amp;nbsp;60%&amp;nbsp;of&amp;nbsp;requests&amp;nbsp;to&amp;nbsp;Facebook&lt;/a&gt;를 읽어보아도 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5ekkY/btrvXTWFYEm/SnmINnwM5AcgudgfJIHxt0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5ekkY/btrvXTWFYEm/SnmINnwM5AcgudgfJIHxt0/img.jpg&quot; width=&quot;736&quot; height=&quot;414&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;414&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5ekkY/btrvXTWFYEm/SnmINnwM5AcgudgfJIHxt0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5ekkY%2FbtrvXTWFYEm%2FSnmINnwM5AcgudgfJIHxt0%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;736&quot; height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N1j23/btrvWFxPrXS/afpOkr4AWcuEC3vC3J0SNK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N1j23/btrvWFxPrXS/afpOkr4AWcuEC3vC3J0SNK/img.jpg&quot; width=&quot;736&quot; height=&quot;414&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;414&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N1j23/btrvWFxPrXS/afpOkr4AWcuEC3vC3J0SNK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN1j23%2FbtrvWFxPrXS%2FafpOkr4AWcuEC3vC3J0SNK%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;736&quot; height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;/div&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;4.1.5 AJAX/Websocket이나 SPA사용&lt;/h4&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; Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AJAX&lt;/a&gt;는 필요한 내용만 웹서버에 요청해 처리할 수 있다. [&lt;a href=&quot;https://ko.wikipedia.org/wiki/Ajax&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ajax&lt;/a&gt;, &lt;a href=&quot;https://jicjjang.github.io/posts/javascript-optimize-7#7-Ajax&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;786&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ISycM/btqZhfSpvV4/vtQ1mVki8nSAi4A13diYTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ISycM/btqZhfSpvV4/vtQ1mVki8nSAi4A13diYTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ISycM/btqZhfSpvV4/vtQ1mVki8nSAi4A13diYTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FISycM%2FbtqZhfSpvV4%2FvtQ1mVki8nSAi4A13diYTk%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;800&quot; height=&quot;786&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;786&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;따라서 AJAX를 사용하면 동일한 도메인 내의 페이지를 이동할 때 불필요한 부분을 다운받지 않아 성능에 유리하다.&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;&lt;a href=&quot;https://github.com/axios/axios&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;axios&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;b&gt;Websocket&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebSocket&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Websocket&lt;/a&gt;을 사용한다면 데이터 통신을 더 줄일 수 있다. [&lt;a href=&quot;https://niceman.tistory.com/109&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTML5&amp;nbsp;WebSocket(웹&amp;nbsp;소켓)&amp;nbsp;기본&amp;nbsp;예제&amp;nbsp;및&amp;nbsp;설명&lt;/a&gt;, &lt;a href=&quot;https://www.safe.com/blog/2014/08/websockets-ajax-webhooks-comparison/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Moving&amp;nbsp;Data&amp;nbsp;over&amp;nbsp;the&amp;nbsp;Web:&amp;nbsp;AJAX&amp;nbsp;vs.&amp;nbsp;WebSockets&amp;nbsp;vs.&amp;nbsp;Webhooks&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말그대로 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC_%EC%86%8C%EC%BC%93&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;소켓&lt;/a&gt;의 역할을 해서 실시간 업데이트에 유리하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bt13VD/btqZdmdEQ4o/e4AjtROfJTI1CVZOzykBc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bt13VD/btqZdmdEQ4o/e4AjtROfJTI1CVZOzykBc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bt13VD/btqZdmdEQ4o/e4AjtROfJTI1CVZOzykBc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbt13VD%2FbtqZdmdEQ4o%2Fe4AjtROfJTI1CVZOzykBc1%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;900&quot; height=&quot;634&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림에 보이다시피 매번 HTTP 헤더가 필요한 AJAX와 달리 한번만 설정하면 바로바로 통신할 수 있다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;socket.io&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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://developpaper.com/speed-dilemma-of-node-js-which-do-ajax-and-socket-io-choose/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Speed&amp;nbsp;dilemma&amp;nbsp;of&amp;nbsp;Node.js:&amp;nbsp;Which&amp;nbsp;do&amp;nbsp;AJAX&amp;nbsp;and&amp;nbsp;Socket.IO choose?&lt;/a&gt;, &lt;a href=&quot;https://blog.feathersjs.com/http-vs-websockets-a-performance-comparison-da2533f13a77&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP&amp;nbsp;vs&amp;nbsp;Websockets:&amp;nbsp;A&amp;nbsp;performance&amp;nbsp;comparison&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹소켓은 연결을 설정하는데 약 190ms정도의 시간이 필요하기 때문.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lsO3k/btqZlO7jQFV/MllM8jtRzO5P0AfpnUVVdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lsO3k/btqZlO7jQFV/MllM8jtRzO5P0AfpnUVVdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lsO3k/btqZlO7jQFV/MllM8jtRzO5P0AfpnUVVdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlsO3k%2FbtqZlO7jQFV%2FMllM8jtRzO5P0AfpnUVVdK%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;613&quot; height=&quot;406&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적은 수의 데이터를 가끔씩 업데이트: AJAX&lt;/li&gt;
&lt;li&gt;많은 수의 데이터를 빈번히 업데이트: 웹소켓&lt;/li&gt;
&lt;/ul&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;Server-Sent Event도 고려해볼법만 하다. [&lt;a href=&quot;https://news.hada.io/topic?id=5972&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebSockets&amp;nbsp;대신&amp;nbsp;Server-Sent&amp;nbsp;Events&amp;nbsp;사용하기&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;&lt;b&gt;해결방안&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AJAX의 문제와 해결&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AJAX를 사용시 가장 큰 문제는 주소가 업데이트되지 않아 뒤로가기가 되지 않는다는 점이다.&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://blog.outsider.ne.kr/1276&quot;&gt;Ajax를 사용할 때 웹브라우저 &quot;뒤로 가기&quot;의 구현&lt;/a&gt;, &lt;a href=&quot;https://github.com/outsideris/page-back-example&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;page-back-example&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bThb5w/btqZiT2CJhQ/gu6Ea9SxyEHoKfNb0Vgxv1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bThb5w/btqZiT2CJhQ/gu6Ea9SxyEHoKfNb0Vgxv1/img.gif&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;437&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bThb5w/btqZiT2CJhQ/gu6Ea9SxyEHoKfNb0Vgxv1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbThb5w%2FbtqZiT2CJhQ%2Fgu6Ea9SxyEHoKfNb0Vgxv1%2Fimg.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;479&quot; height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btafSq/btqZiVe3Que/nsSGqfteu1xKrisrBqQGHk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btafSq/btqZiVe3Que/nsSGqfteu1xKrisrBqQGHk/img.gif&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;437&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btafSq/btqZiVe3Que/nsSGqfteu1xKrisrBqQGHk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtafSq%2FbtqZiVe3Que%2FnsSGqfteu1xKrisrBqQGHk%2Fimg.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;479&quot; height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;일반 링크 vs AJAX&lt;/figcaption&gt;
&lt;/figure&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;a href=&quot;https://pushstate-vawrtytcgl.now.sh/link/page1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pushstate-vawrtytcgl.now.sh/ajax&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AJAX&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 해결할 수 있는 방법은 HTML5 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/History&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;History&lt;/a&gt;의 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/History/pushState&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;pushState()&lt;/a&gt;를 사용하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMMNxa/btqZn07u3Bf/eztm4Ms9oMztlmu7QFapyK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMMNxa/btqZn07u3Bf/eztm4Ms9oMztlmu7QFapyK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMMNxa/btqZn07u3Bf/eztm4Ms9oMztlmu7QFapyK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cMMNxa/btqZn07u3Bf/eztm4Ms9oMztlmu7QFapyK/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;519&quot; height=&quot;438&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&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;a href=&quot;https://pushstate-vawrtytcgl.now.sh/pushstate/page1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AJAX + pushState&lt;/a&gt;&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;b&gt;SPA와 렌더링&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이러한 AJAX의 장점을 이용해 페이지를 빠르고 부드럽게 렌더링하는 패러다임이 등장했으니 React, Vue, Angular등으로 유명한 SPA다. [&lt;a href=&quot;https://scand.com/company/blog/single-page-application-vs-multi-page-application/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Single&amp;nbsp;Page&amp;nbsp;Application&amp;nbsp;vs&amp;nbsp;Multi&amp;nbsp;Page&amp;nbsp;Application&lt;/a&gt;, &lt;/span&gt;&lt;a href=&quot;https://www.reimaginer.me/entry/spa-and-spa-routing&quot;&gt;SPA와 SPA 라우팅 원리&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://poiemaweb.com/js-spa&quot;&gt;Single&amp;nbsp;Page&amp;nbsp;Application&amp;nbsp;&amp;amp;&amp;nbsp;Routing&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.yunki.kr/m/66&quot;&gt;서버사이드&amp;nbsp;랜더링과&amp;nbsp;SPA&amp;nbsp;라우팅의&amp;nbsp;동작원리&lt;/a&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;보다시피 AJAX의 통신방법을 잘 써먹고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;243&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nX6eB/btqZfgRz2M7/HMdb4jb9unw3fpZww1zGL0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nX6eB/btqZfgRz2M7/HMdb4jb9unw3fpZww1zGL0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nX6eB/btqZfgRz2M7/HMdb4jb9unw3fpZww1zGL0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnX6eB%2FbtqZfgRz2M7%2FHMdb4jb9unw3fpZww1zGL0%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;880&quot; height=&quot;243&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;243&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;span style=&quot;color: #333333;&quot;&gt;그러나 웹페이지 렌더링을 자바스크립트를 이용해 처리해 초기속도가 느리다는 점, AJAX의 특징등 때문에 다양한 렌더링 방식이 등장하게 되었다. [&lt;/span&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://shlrur.github.io/develog/2019/02/14/rendering-on-the-web/&quot;&gt;웹에서의 렌더링&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/updates/2019/02/rendering-on-the-web?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹렌더링&lt;/a&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;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzTLdd/btqZhgqfRDR/cj7c340xUTfpVSPMlJOgK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzTLdd/btqZhgqfRDR/cj7c340xUTfpVSPMlJOgK1/img.png&quot; data-origin-width=&quot;994&quot; data-origin-height=&quot;614&quot; style=&quot;width: 54.706%; margin-right: 10px;&quot; data-widthpercent=&quot;55.35&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzTLdd/btqZhgqfRDR/cj7c340xUTfpVSPMlJOgK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzTLdd%2FbtqZhgqfRDR%2Fcj7c340xUTfpVSPMlJOgK1%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;994&quot; height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvkITy/btqZkqTaIFK/T0I21NQTyqXAD6n2TZPBq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvkITy/btqZkqTaIFK/T0I21NQTyqXAD6n2TZPBq1/img.png&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;974&quot; style=&quot;width: 44.1312%;&quot; data-widthpercent=&quot;44.65&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvkITy/btqZkqTaIFK/T0I21NQTyqXAD6n2TZPBq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdvkITy%2FbtqZkqTaIFK%2FT0I21NQTyqXAD6n2TZPBq1%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;1272&quot; height=&quot;974&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KYy6g/btqZefk26Wy/YuDkbc1zZPq72CsHpJcdEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KYy6g/btqZefk26Wy/YuDkbc1zZPq72CsHpJcdEK/img.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;628&quot; style=&quot;width: 45.1202%; margin-right: 10px;&quot; data-widthpercent=&quot;45.65&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KYy6g/btqZefk26Wy/YuDkbc1zZPq72CsHpJcdEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKYy6g%2FbtqZefk26Wy%2FYuDkbc1zZPq72CsHpJcdEK%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;1562&quot; height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnWdvq/btqZctqCTsk/IbkK7glZnuNRu8v0BjEAmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnWdvq/btqZctqCTsk/IbkK7glZnuNRu8v0BjEAmK/img.png&quot; data-origin-width=&quot;2440&quot; data-origin-height=&quot;824&quot; style=&quot;width: 53.717%;&quot; data-widthpercent=&quot;54.35&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnWdvq/btqZctqCTsk/IbkK7glZnuNRu8v0BjEAmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnWdvq%2FbtqZctqCTsk%2FIbkK7glZnuNRu8v0BjEAmK%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;2440&quot; height=&quot;824&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;순서대로 Server Rendering, Static Rendering, Client-Side Rendering, SSR+hydration&lt;/figcaption&gt;
&lt;/figure&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;b&gt;Server Rendering:&lt;/b&gt; 요청한 페이지의 전체 HTML을 서버에서 생성해 로드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Static Rendering:&lt;/b&gt; 빌드시 HTML을 생성하여 배포&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Client-Side Rendering:&lt;/b&gt; 브라우저에서 자바스크립트로 페이지를 렌더링&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SSR + Rehydration:&lt;/b&gt; 캐시성이 높은 컨텐츠에만 SSR을 적용&lt;/li&gt;
&lt;/ul&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;widthContent&quot; data-origin-width=&quot;2164&quot; data-origin-height=&quot;1434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgoxDH/btqZjwF7cGI/DleVp3iR3AU7s3XW82i1Tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgoxDH/btqZjwF7cGI/DleVp3iR3AU7s3XW82i1Tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgoxDH/btqZjwF7cGI/DleVp3iR3AU7s3XW82i1Tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgoxDH%2FbtqZjwF7cGI%2FDleVp3iR3AU7s3XW82i1Tk%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;2164&quot; height=&quot;1434&quot; data-origin-width=&quot;2164&quot; data-origin-height=&quot;1434&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;b&gt;Full CSR:&lt;/b&gt; 서버에서 JS와 CSS를 뿌리면, SPA이 자동으로 만들어진다. 따라서 처음에 HTML과 컨텐츠는 포함이 되어있지 않고, FCP(최초 컨텐츠 포함된 페인트)가 느려지게 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CSR with Prerendering:&lt;/b&gt; 나아지긴 했지만, 여전히 FCP에서 문제가 있다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SSR with hydration:&lt;/b&gt; 밑에 나오는 SSR의 단점에 이벤트 핸들러가 붙는 시간까지 합쳐야 해서 TTI(상호작용까지의 시간)까지 추가된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Static SSR:&lt;/b&gt; 빌드 타임에 생성하므로 매우 빠르다. 그러나 동적이지 않다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Server Rendering:&lt;/b&gt; 서버에서 생성하는 과정이 필요하므로, TTFB(최초 바이트까지 시간)에서 문제가 있다.&lt;/li&gt;
&lt;/ul&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;일단 Static SSR이 성능만 놓고 보면 최적으로 보인다.&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;첫번째는 Headless CMS로 어느정도 극복가능하구 [&lt;a href=&quot;https://lyingdragon.medium.com/cms%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%98%95%ED%83%9C-headless-cms-81d926335d5e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CMS의&amp;nbsp;새로운&amp;nbsp;형태,&amp;nbsp;Headless&amp;nbsp;CMS&lt;/a&gt;, &lt;a href=&quot;https://business.adobe.com/kr/glossary/headless-cms.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;헤드리스&amp;nbsp;CMS&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째는 Gatsby의 &lt;a href=&quot;https://www.gatsbyjs.com/docs/reference/rendering-options/deferred-static-generation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Deferred Static Generation&lt;/a&gt;, Next.js의 &lt;a href=&quot;https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Incremental Static Regeneration&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;a href=&quot;https://jamstack.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JAM Stack&lt;/a&gt;!! 이 각광을 받고 있다. [&lt;a href=&quot;https://toss.tech/article/faster-initial-rendering&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;조금만&amp;nbsp;신경써서&amp;nbsp;초기&amp;nbsp;렌더링&amp;nbsp;빠르게&amp;nbsp;하기&amp;nbsp;(feat.&amp;nbsp;JAM&amp;nbsp;Stack)&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6QGBm/btrBn6iDxBU/wDOFRIoVhpKik37Y6lKknK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6QGBm/btrBn6iDxBU/wDOFRIoVhpKik37Y6lKknK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6QGBm/btrBn6iDxBU/wDOFRIoVhpKik37Y6lKknK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6QGBm%2FbtrBn6iDxBU%2FwDOFRIoVhpKik37Y6lKknK%2Fimg.webp&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;512&quot; height=&quot;237&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1RmTD/btrBhkpX1m3/HQ8mkmfmYD3Em3KI656KU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1RmTD/btrBhkpX1m3/HQ8mkmfmYD3Em3KI656KU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1RmTD/btrBhkpX1m3/HQ8mkmfmYD3Em3KI656KU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1RmTD%2FbtrBhkpX1m3%2FHQ8mkmfmYD3Em3KI656KU1%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;650&quot; height=&quot;500&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나&amp;nbsp;서버 사이드 CMS, 백엔드와 분리되지 않은 서비스, isomorphic rendering으로 운영되는 서비스에서는 사용하기 어렵다고 한다.&lt;/p&gt;
&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;widthContent&quot; data-origin-width=&quot;2196&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zx4ns/btqZiTBwdFF/JkvJA6HkjaOI2tMyrh3k10/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zx4ns/btqZiTBwdFF/JkvJA6HkjaOI2tMyrh3k10/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zx4ns/btqZiTBwdFF/JkvJA6HkjaOI2tMyrh3k10/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzx4ns%2FbtqZiTBwdFF%2FJkvJA6HkjaOI2tMyrh3k10%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;2196&quot; height=&quot;708&quot; data-origin-width=&quot;2196&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리엑트 18이 이를 가능하게 만든다. [&lt;a href=&quot;https://github.com/reactwg/react-18/discussions/37&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;New&amp;nbsp;Suspense&amp;nbsp;SSR&amp;nbsp;Architecture&amp;nbsp;in&amp;nbsp;React&amp;nbsp;18&lt;/a&gt;, &lt;a href=&quot;https://velog.io/@jay/React-18-%EB%B3%80%EA%B2%BD%EC%A0%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React&amp;nbsp;18&amp;nbsp;변경점&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이른바&amp;nbsp;Selective Hydration라 부르는 물건.&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;b&gt;렌더링 개선법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSR의 효율을 최대한 높히기 위해 PRPL(Push Render Pre-Cache Lazy-load) 패턴이 생겼고(물론 우리가 위에서 다루었던 최적화 방법들),&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;696&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxptbl/btqZehb9HJp/YQxGANAbMiMX2poMLvQ0CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxptbl/btqZehb9HJp/YQxGANAbMiMX2poMLvQ0CK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxptbl/btqZehb9HJp/YQxGANAbMiMX2poMLvQ0CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdxptbl%2FbtqZehb9HJp%2FYQxGANAbMiMX2poMLvQ0CK%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;1280&quot; height=&quot;696&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;696&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;서비스 워커를 사용하면 초기화와 자바스크립트를 사용하지 않은 Navigation에서 스트리밍을 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;2108&quot; data-origin-height=&quot;1328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EQBTO/btqZiTO5G3q/UVXX25ZQYj9UlM3LFluKW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EQBTO/btqZiTO5G3q/UVXX25ZQYj9UlM3LFluKW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EQBTO/btqZiTO5G3q/UVXX25ZQYj9UlM3LFluKW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEQBTO%2FbtqZiTO5G3q%2FUVXX25ZQYj9UlM3LFluKW0%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;2108&quot; height=&quot;1328&quot; data-origin-width=&quot;2108&quot; data-origin-height=&quot;1328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아참, MPA의 경우 &lt;a href=&quot;https://web.archive.org/web/20210402020636/https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#streaming_composite_responses&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Streaming Composite&amp;nbsp; Response&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;b&gt;MPA에서 SPA처럼&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MPA도 AJAX를 사용하면 SPA처럼 렌더링할 수 있지 않을까 싶어 찾아보게 되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그러다 굉장히 흥미로운 구현체들을 보게되었는데 전체 페이지로드를 발생시키지 않고, AJAX를 이용해 페이지의 바뀐부분만 업데이트시키는 방법이었다. [&lt;a href=&quot;https://tyle.io/blog/52&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;pjax를&amp;nbsp;이용한&amp;nbsp;극적인&amp;nbsp;웹페이지&amp;nbsp;속도&amp;nbsp;향상&lt;/a&gt;, &lt;a href=&quot;https://www.honeybadger.io/blog/turbolinks/&quot;&gt;How&amp;nbsp;We&amp;nbsp;Migrated&amp;nbsp;To&amp;nbsp;Turbolinks&amp;nbsp;Without&amp;nbsp;Breaking&amp;nbsp;Javascript&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;&lt;span style=&quot;color: #333333;&quot;&gt;쉽게 설명하면&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;head: 병합&lt;/li&gt;
&lt;li&gt;body: 교체&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/defunkt/jquery-pjax&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;jquery-pjax&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;723&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0NelX/btqZjwzjcuP/5nJ9UWKXsg16qHq0iXZAtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0NelX/btqZjwzjcuP/5nJ9UWKXsg16qHq0iXZAtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0NelX/btqZjwzjcuP/5nJ9UWKXsg16qHq0iXZAtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0NelX%2FbtqZjwzjcuP%2F5nJ9UWKXsg16qHq0iXZAtK%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;723&quot; height=&quot;359&quot; data-origin-width=&quot;723&quot; data-origin-height=&quot;359&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;다음은 PJAX 아이디어를 기반한 라이브러리들.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;609&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JO19a/btqZjwF7cMF/2BN6KQBtd0mowskvykHM8K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JO19a/btqZjwF7cMF/2BN6KQBtd0mowskvykHM8K/img.gif&quot; data-alt=&quot;turbolinks&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JO19a/btqZjwF7cMF/2BN6KQBtd0mowskvykHM8K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/JO19a/btqZjwF7cMF/2BN6KQBtd0mowskvykHM8K/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;1280&quot; height=&quot;609&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;609&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;turbolinks&lt;/figcaption&gt;
&lt;/figure&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;a href=&quot;https://github.com/turbolinks/turbolinks&quot;&gt;Turbolinks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dieulot/instantclick&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;InstantClick&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/barbajs/barba&quot;&gt;Barba.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/swup/swup&quot;&gt;Swup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/miguel-perez/smoothState.js&quot;&gt;smoothState.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Easyfood/pageAccelerator&quot;&gt;pageAccelerator&lt;/a&gt;&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: #333333;&quot;&gt;얼마나 효과가 있을지 모르겠으나 기존 SPA와 함께 사용할 수도 있는듯 하다.&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;&lt;a href=&quot;https://coderwall.com/p/z4cd4g/integrate-with-turbolinks-and-webpacker-react&quot;&gt;Integrate with Turbolinks and webpacker react&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/front-end-weekly/pjax-react-2ee247af0fb5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PJAX + React&lt;/a&gt; [&lt;a href=&quot;https://github.com/MoOx/pjax&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pjax&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tngan/react-pjax&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-pjax&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;a href=&quot;https://hotwire.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hotwire : HTML Over The Wire&lt;/a&gt;(&lt;a href=&quot;https://news.hada.io/topic?id=3479&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;pjax를 활용했는지 확실치 않지만..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유튜브에서 만든 &lt;a href=&quot;https://github.com/youtube/spfjs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SPF(Structured Page Fragments)&lt;/a&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;4.1.6 AJAX 요청에 GET 사용&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; server&lt;br /&gt;야후! 메일팀은 &lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/XMLHttpRequest&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;XMLHttpRequest&lt;/a&gt;의 POST를&lt;/span&gt; 사용할 때 브라우저에서 헤더를 먼저 보낸 다음 데이터를 보내는 2 단계 프로세스로 구현 한다는 것을 알게되었다 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 쿠키가 많지 않은 경우 하나의 TCP 패킷 만 보내면 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/POST&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;POST&lt;/a&gt;보다 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/GET&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GET&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;IE 기준 최대 URL 길이는 2K이므로 2K 이상의 데이터를 보내면 GET을 사용하지 못할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 일반적으로 말하는 GET과 POST의 장단점. [&lt;a href=&quot;https://etutorials.org/Macromedia/Flash+MX+2004.+Actionscript/Lesson+11.+Getting+Data+In+and+Out+of+Flash/GET+vs.+POST/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GET&amp;nbsp;vs.​&amp;nbsp;POST&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;511&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2fsR6/btqZiT9m0s3/a6uu2IXbXj7ghqJSTZ3t2K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2fsR6/btqZiT9m0s3/a6uu2IXbXj7ghqJSTZ3t2K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2fsR6/btqZiT9m0s3/a6uu2IXbXj7ghqJSTZ3t2K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/2fsR6/btqZiT9m0s3/a6uu2IXbXj7ghqJSTZ3t2K/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;500&quot; height=&quot;511&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;511&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;b&gt;- GET&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;고정적인 주소 및 링크를 사용하기 때문에 캐싱 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Content-Type이 필요 없으므로(body가 없음) 가벼움, 야후 메일팀이 말한것&lt;/span&gt;&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;b&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;길이 제한&lt;/li&gt;
&lt;li&gt;주소창에 쿼리 스트링이 보여짐&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;b&gt;- POST&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;객체를 보낼 수 있음&lt;/span&gt;&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;b&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;서버로 보내기 전에 인코딩, 전송 후 디코딩 작업&lt;/li&gt;
&lt;li&gt;캐싱이 힘들고, 데이터를 2단계에 걸쳐 보냄&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;b&gt;- 기타&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흥미로운 부작용은 포스팅된 데이터가 없는 POST는 GET처럼 동작한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP 사양&lt;/a&gt;을&amp;nbsp;기반으로&amp;nbsp;살펴보면&amp;nbsp;GET은&amp;nbsp;fetch(요청)할&amp;nbsp;때&amp;nbsp;사용,&amp;nbsp;POST는&amp;nbsp;수행할&amp;nbsp;때&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;CRUD(Create, Read, Update, Delete) 중 Read할 때만 fetch를 하는 개념이므로 GET을 사용하는 것이 맞다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 개발자들이 구분하지 않고 사용하여 미리 링크를 클릭해(GET) 성능 향상을 하려 시도했던 &lt;a href=&quot;https://web.archive.org/web/20120215014401/http://webaccelerator.google.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구글 Accelerator&lt;/a&gt;(&lt;a href=&quot;https://web.archive.org/web/20080808014033/http://webaccelerator.google.com/&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;h3 data-ke-size=&quot;size23&quot;&gt;4.2 기타&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2.1 로드 전 구성 요소&amp;nbsp;&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프리로드는 포스트로드와 반대되는 것처럼 보이지만 실제로는 다른 목표가 있다.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://web.archive.org/web/20160412130249/https://blog.radware.com/applicationdelivery/applicationaccelerationoptimization/2014/02/the-case-for-auto-preloading/&quot;&gt;The Case for Auto-Preloading: The Anatomy of Battle-Tested WPO Treatment&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://uxplanet.org/how-to-make-users-think-your-app-loads-faster-24052fe307bf&quot;&gt;How To Make Users Think Your App Loa보다 ds Faster&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://en.ryte.com/magazine/faster-loading-times-with-prefetch-preload-prerender&quot;&gt;Faster&amp;nbsp;Loading&amp;nbsp;Times&amp;nbsp;with&amp;nbsp;Prefetch,&amp;nbsp;Preload&amp;nbsp;and&amp;nbsp;Prerender&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://macarthur.me/posts/best-ish-practices-for-dynamically-prefetching-and-prerendering-with-javascript&quot;&gt;Best-ish&amp;nbsp;Practices&amp;nbsp;for&amp;nbsp;Dynamically&amp;nbsp;Prefetching&amp;nbsp;&amp;amp;&amp;nbsp;Prerendering&amp;nbsp;Pages&amp;nbsp;with&amp;nbsp;JavaScript&lt;/a&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&gt;&amp;nbsp;&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 style=&quot;font-size: 1.12em;&quot; 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;b&gt;무조건&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;onload가 발생하자마자 추가 구성 요소를 가져온다.&lt;br /&gt;스프라이트 이미지가 onload후 요청되는 방법에 대한 예는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.google.com&quot;&gt;google.com&lt;/a&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://www.google.com&quot;&gt;google.com&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;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;a href=&quot;https://search.yahoo.com/&quot;&gt;search.yahoo.com&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXqmSm/btqZiVsCvn6/FkqmDwx57o7Zqzu86EtMUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXqmSm/btqZiVsCvn6/FkqmDwx57o7Zqzu86EtMUK/img.png&quot; data-alt=&quot;인스타그램 공유하기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXqmSm/btqZiVsCvn6/FkqmDwx57o7Zqzu86EtMUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXqmSm%2FbtqZiVsCvn6%2FFkqmDwx57o7Zqzu86EtMUK%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;366&quot; height=&quot;600&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;600&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;&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;redesign을 시작하기 전에 미리로드한다는 아이디어.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;새 사이트는 멋지지만 이전보다 느리다.&quot;라는 말은 redesign 후 흔히 들을 수 있다.&lt;/p&gt;
&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;redesign을 시작하기 전에 일부 구성 요소를 사전로드하여 이 부작용을 완화 할 수 있다.&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;SNS이므로 많은 사용자가 좋아하는 컨텐츠에 들어갈 확률이 관심을 적게 받는 컨텐츠보다 높기 때문.&lt;/p&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: #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;b&gt;- 기술&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리소스 힌트를 사용하면 미리 캐싱을 할 수 있다. [&lt;a href=&quot;https://css-tricks.com/prefetching-preloading-prebrowsing/&quot;&gt;Prefetching,&amp;nbsp;preloading,&amp;nbsp;prebrowsing&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://www.stevesouders.com/blog/2013/11/07/prebrowsing/&quot;&gt;Prebrowsing&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://macarthur.me/posts/best-ish-practices-for-dynamically-prefetching-and-prerendering-with-javascript&quot;&gt;Best-ish&amp;nbsp;Practices&amp;nbsp;for&amp;nbsp;Dynamically&amp;nbsp;Prefetching&amp;nbsp;&amp;amp;&amp;nbsp;Prerendering&amp;nbsp;Pages&amp;nbsp;with&amp;nbsp;JavaScript&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://medium.com/@pakss328/resource-hint-8fb4e56ee042&quot;&gt;Resource&amp;nbsp;Hint&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://web.archive.org/web/20120309113126/http://code.google.com/chrome/whitepapers/prerender.html&quot;&gt;Web Developer's Guide to Prerendering in Chrome&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;b&gt;Prerender(실험적)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중 아직 언급하지 않았던 prerender를 다루어보려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prefetch와 같이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&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: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;차이점이라면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;브라우저가 백그라운드에서 URL을 가져오고 렌더링하여 즉각적으로 보여줄 수 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState&quot;&gt;Document.visibilityState&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;/span&gt;&lt;/span&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;b&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;예측되는 도메인: dns-prefetch, preconnect&lt;/li&gt;
&lt;li&gt;예측되는 리소스: prefetch&lt;/li&gt;
&lt;li&gt;예측되는 페이지: prerender&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;b&gt;- 또 다른 활용방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 나온 예시들 말고 한가지 흥미로운 예측방법을 소개하려한다.&amp;nbsp;[&lt;a href=&quot;https://css-tricks.com/prerender-on-hover/&quot;&gt;Prerender on hover?&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;이를 도와주는 라이브러리가 존재한다. [&lt;a href=&quot;https://wpspeedmatters.com/quicklink-vs-instant-page-vs-flying-pages/&quot;&gt;Quicklink&amp;nbsp;vs&amp;nbsp;Instant.page&amp;nbsp;vs&amp;nbsp;Flying&amp;nbsp;Pages&amp;nbsp;&amp;ndash;&amp;nbsp;Why&amp;nbsp;I&amp;nbsp;built&amp;nbsp;Flying&amp;nbsp;Pages&lt;/a&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;a href=&quot;https://github.com/GoogleChromeLabs/quicklink&quot;&gt;Quicklink&lt;/a&gt;: Viewport 기반&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/instantpage/instant.page&quot;&gt;Instant.page&lt;/a&gt;: Hover 기반&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gijo-varghese/flying-pages&quot;&gt;Flying Pages&lt;/a&gt;: Viewport, Hover 둘다&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://guess-js.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Guess.js&lt;/a&gt;: 구글 애널리틱스등의 분석기를 통해 예측&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;Hover 기반에서 문제는 호버 후 서버응답시간(약 300ms)가 누르는 시간보다 짧을 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://mathisonian.github.io/premonish/&quot;&gt;Premonish&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/tristen/hoverintent&quot;&gt;hoverintent&lt;/a&gt;(&lt;a href=&quot;https://github.com/briancherne/jquery-hoverIntent&quot;&gt;jQuery plugin&lt;/a&gt;)처럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;너무 민감하지 않게 만드는 방법이 필요할 수도 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;http://blog.xsolon.net/posts/csshover.html&quot;&gt;Faking&amp;nbsp;Hover&amp;nbsp;Intent&amp;nbsp;with&amp;nbsp;JavaScript&lt;/a&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://tristen.ca/hoverintent/&quot;&gt;hoverintent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://briancherne.github.io/jquery-hoverIntent/&quot;&gt;hoverintent jQuery Plugin&lt;/a&gt;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://instantclick.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;InstantClick&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mskog.com/posts/instant-page-loads-with-turbolinks-and-prefetch/&quot;&gt;Instant page loads with Turbolinks and prefetch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <category>성능</category>
      <category>웹</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/81</guid>
      <comments>https://black7375.tistory.com/81#entry81comment</comments>
      <pubDate>Sun, 14 Feb 2021 18:25:57 +0900</pubDate>
    </item>
    <item>
      <title>[스압/데이터주의] 웹 최적화 방식 모음 - 3.3 UX 트릭</title>
      <link>https://black7375.tistory.com/80</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/72&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 0. 전반적 원칙과 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/73&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 1. 다운로드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/74&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 2. 파싱 및 렌더링 트리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/79&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3. Layout 및 렌더링&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/80&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3.3 UX 트릭(현재)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/81&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 4. 로드 후&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/82&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 5. 빌드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 UX 트릭&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객관적인 성능이 올라가는 것이 아니라 사용자가 빠르다고 느낄 수 있게 만드는 트릭들.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UX는 글로만 설명하기 힘든 부분이 많기 때문에 가급적 GIF나 사진자료 통해 직관적으로 이해할 수 있도록 힘을 썼다.&lt;/p&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(Optimistic UI)와 피츠의 법칙 활용은 일반 개발자에게 상당히 생소한 존재며 흥미로운 방법론들이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;UX에 관심이 있는 사람이 아닐지라도 인사이트를 얻어갈 수 있을 것이다.&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;3.3.1 웹폰트 로드&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;Font&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;앞선 폰트 압축과 서브셋에 이어 로드 최적화를 다루어본다. [&lt;/span&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/4969726&quot;&gt;웹 폰트 사용과 최적화의 최근 동향&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization?hl=ko&quot;&gt;웹폰트 최적화&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://wit.nts-corp.com/2017/02/13/4258&quot;&gt;웹폰트&amp;nbsp;사용하기&amp;nbsp;(웹폰트&amp;nbsp;101)&lt;/a&gt;, &lt;a href=&quot;https://www.zachleat.com/web/comprehensive-webfonts/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A Comprehensive Guide to Font Loading Strategies&lt;/a&gt;, &lt;a href=&quot;https://jonsuh.com/blog/font-loading-with-font-events/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Faster&amp;nbsp;Font&amp;nbsp;Loading&amp;nbsp;with&amp;nbsp;Font&amp;nbsp;Events&lt;/a&gt;, &lt;a href=&quot;https://css-tricks.com/fout-foit-foft/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FOUT, FOIT, FOFT&lt;/a&gt;, &lt;a href=&quot;https://www.igvita.com/2014/01/31/optimizing-web-font-rendering-performance/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimizing Web Font Rendering Performance&lt;/a&gt;, &lt;a href=&quot;https://showerbugs.github.io/2018-02-02/%EC%9B%B9%ED%8F%B0%ED%8A%B8-%EC%B5%9C%EC%A0%81%ED%99%94-%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹폰트&amp;nbsp;최적화&amp;nbsp;기법에&amp;nbsp;관한&amp;nbsp;몇가지&amp;nbsp;이야기&lt;/a&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;b&gt;- 렌더링 차단방식&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8pc44/btqZfhiEkf0/KtdlEX0zRtzl9VgEQgkrWK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8pc44/btqZfhiEkf0/KtdlEX0zRtzl9VgEQgkrWK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8pc44/btqZfhiEkf0/KtdlEX0zRtzl9VgEQgkrWK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/c8pc44/btqZfhiEkf0/KtdlEX0zRtzl9VgEQgkrWK/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;1280&quot; height=&quot;342&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폰트 렌더링 방식은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FOIT(Flash Of Invisible Text): 텍스트가 보이지 않은 상태(invisible)에서 지정된 폰트로 바뀌며 번쩍임 (크롬, 파이어폭스)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;FOUT(Flash Of Unstyled Text):&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Fallback 폰트(unstyled)에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;지정된 폰트로 바뀌며 번쩍임 (IE)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;이중 컨텐츠를 먼저 보여는 FOUT 방식이 UX에 좋다.&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;- FOUT 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;font-display 속성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://caniuse.com/#feat=css-font-rendering-controls&quot;&gt;요즘 브라우저&lt;/a&gt;들은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display&quot;&gt;font-display&lt;/a&gt;를 적용하여 FOUT처럼 사용할 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;2672&quot; data-origin-height=&quot;1502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwhvaj/btqZdmxWixk/FJNWeorMkE441jcX3nosok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwhvaj/btqZdmxWixk/FJNWeorMkE441jcX3nosok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwhvaj/btqZdmxWixk/FJNWeorMkE441jcX3nosok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbwhvaj%2FbtqZdmxWixk%2FFJNWeorMkE441jcX3nosok%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;2672&quot; height=&quot;1502&quot; data-origin-width=&quot;2672&quot; data-origin-height=&quot;1502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;auto: block과 비슷&lt;/li&gt;
&lt;li&gt;block: FOIT처럼 작동, 로딩되지 않을 때는 텍스트를 렌더링하지 않으며(최대 3초) 웹폰트가 로딩되면 적용&lt;/li&gt;
&lt;li&gt;swap: FOUT처럼 작동, 우선 Fallback으로 렌더링하고 웹폰트가 로딩되면 적용&lt;/li&gt;
&lt;li&gt;fallback: 100ms 동안 렌더링하지 않다가 Fallback으로 렌더링, 3초안에 로딩이 완료되면 완료된 폰트로 아니라면 Fallback 폰트 유지&lt;/li&gt;
&lt;li&gt;optional: 100ms 동안 렌더링 하지 않다가 Fallback으로 렌더링, 브라우저가 네트워크 상태를 파악해 웹폰트로 전환여부를 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1586470108480&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@font-face {
  font-family: 'Awesome Font';
  font-display: swap; /* or auto, block, fallback, optional */
  src: local('Awesome Font'),
    url('/fonts/awesome-l.woff2') format('woff2');
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;@font-face의 font-display를 swap으로 설정하면 된다.&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;FOUT 방식으로 로드하도록 도와주는 라이브러리가 역시 존재한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bramstein/fontfaceobserver&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Font Face Observer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/typekit/webfontloader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web Font Loader&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중에서는 Font Face Observer가 가볍고 성능에서도 낫다고 알려져 있다.&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://github.com/dmnsgn/fontfaceobserver&quot;&gt;Font Face Observer ES&lt;/a&gt;를 사용하면 트리 쉐이킹을 사용할 수 있으니 요것을 쓰는게 좋을 듯 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Font Face Observer의 사용방법은 간단하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwM5dr/btqZdmq91ii/7xR3qXa6K1Ag4Jr99i3z80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwM5dr/btqZdmq91ii/7xR3qXa6K1Ag4Jr99i3z80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwM5dr/btqZdmq91ii/7xR3qXa6K1Ag4Jr99i3z80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwM5dr%2FbtqZdmq91ii%2F7xR3qXa6K1Ag4Jr99i3z80%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;1280&quot; height=&quot;542&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;542&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;b&gt;Font Loading API&lt;/b&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://developer.mozilla.org/en-US/docs/Web/API/CSS_Font_Loading_API&quot;&gt;Font Loding API&lt;/a&gt;가 나왔는데 Font Face Observer와 비슷하다. [&lt;a href=&quot;https://medium.com/@matuzo/getting-started-with-css-font-loading-e24e7ffaa791&quot;&gt;Getting&amp;nbsp;started&amp;nbsp;with&amp;nbsp;CSS&amp;nbsp;Font&amp;nbsp;Loading&lt;/a&gt;, &lt;a href=&quot;https://googlechrome.github.io/samples/font-face-set/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;Font&amp;nbsp;Loading&amp;nbsp;API's&amp;nbsp;FontFaceSet&amp;nbsp;Sample&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;pre id=&quot;code_1586472531587&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var font = new FontFace(&quot;Awesome Font&quot;, &quot;url(/fonts/awesome.woff2)&quot;, {
  style: 'normal', unicodeRange: 'U+000-5FF', weight: '400'
});

// don't wait for the render tree, initiate an immediate fetch!
font.load().then(function() {
  document.fonts.add(font); // add font to document
  document.body.classList.add('fonts-loaded'); // enable font with CSS class
});
&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;- 부작용 보완&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 FOUT도 부작용이 존재한다고 하였다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qhNlE/btqZn1SSa44/owTaUpgplP13hbwaoKcPm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qhNlE/btqZn1SSa44/owTaUpgplP13hbwaoKcPm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qhNlE/btqZn1SSa44/owTaUpgplP13hbwaoKcPm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqhNlE%2FbtqZn1SSa44%2FowTaUpgplP13hbwaoKcPm1%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;1280&quot; height=&quot;1305&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1305&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://sangziii.github.io/fontStyleMatcher/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Font style matcher&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rkd4J/btqZlPyotJf/Byih46AkJKldmYfEweIShK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rkd4J/btqZlPyotJf/Byih46AkJKldmYfEweIShK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rkd4J/btqZlPyotJf/Byih46AkJKldmYfEweIShK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRkd4J%2FbtqZlPyotJf%2FByih46AkJKldmYfEweIShK%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;1280&quot; height=&quot;434&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;434&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;b&gt;FOUT 최소화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FOUT이 UX에 좋기는 하나 깜박이는 것은 좋지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 작은 시간내에 로드가 된다면 깜박이지 않게 만드는 것을 고려할만 하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pSvlP/btqZju2y0Ia/YTr6lexJ0wpCfi4Icpq7Z0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pSvlP/btqZju2y0Ia/YTr6lexJ0wpCfi4Icpq7Z0/img.gif&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;728&quot; style=&quot;width: 44.6554%; margin-right: 10px;&quot; data-widthpercent=&quot;45.18&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pSvlP/btqZju2y0Ia/YTr6lexJ0wpCfi4Icpq7Z0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpSvlP%2FbtqZju2y0Ia%2FYTr6lexJ0wpCfi4Icpq7Z0%2Fimg.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;700&quot; height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1yHY6/btqZkqr5aQu/v2LceiMciiMOOgdhBiETn1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1yHY6/btqZkqr5aQu/v2LceiMciiMOOgdhBiETn1/img.gif&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;600&quot; style=&quot;width: 54.1818%;&quot; data-widthpercent=&quot;54.82&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1yHY6/btqZkqr5aQu/v2LceiMciiMOOgdhBiETn1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1yHY6%2FbtqZkqr5aQu%2Fv2LceiMciiMOOgdhBiETn1%2Fimg.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;700&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/div&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: #333333;&quot;&gt;400ms 이내에 전송이 되면 깜빡임 없이 바로 보이게 할 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1587215704667&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.fonts-loaded body {
     font-family: 'Nanum Gothic', sans-serif, Lucida Sans Unicode, arial;
}

.blocking-time {
    opacity: 0;
}

.fonts-loaded.blocking-time {
    opacity: 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1587215720999&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.documentElement.classList.add('blocking-time');
setTimeout(function() {
    document.documentElement.classList.remove('blocking-time');
}, 400)
var font = new FontFaceObserver('Nanum Gothic');
font.load(null, 3000).then(function() {
  document.documentElement.classList.add('fonts-loaded');
});&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;FOFT(Flash of Faux Text)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: 시스템 폰트 - 웹폰트 Regular - 웹폰트 Bold/Italic&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bO13rC/btqZfg45K44/fQPQZqVkLJYM5lRntyPS9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bO13rC/btqZfg45K44/fQPQZqVkLJYM5lRntyPS9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bO13rC/btqZfg45K44/fQPQZqVkLJYM5lRntyPS9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbO13rC%2FbtqZfg45K44%2FfQPQZqVkLJYM5lRntyPS9k%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;1280&quot; height=&quot;375&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;시스템 폰트(FOUT)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p0kif/btqZfhwbTU9/QOpGcuGbd2VCPpx8O1IKS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p0kif/btqZfhwbTU9/QOpGcuGbd2VCPpx8O1IKS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p0kif/btqZfhwbTU9/QOpGcuGbd2VCPpx8O1IKS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp0kif%2FbtqZfhwbTU9%2FQOpGcuGbd2VCPpx8O1IKS1%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;1280&quot; height=&quot;358&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 다운로드된 폰트 적용(FOFT)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UZ5km/btqZegdcVOe/kbVKkTLwogFPIvX9ovzx00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UZ5km/btqZegdcVOe/kbVKkTLwogFPIvX9ovzx00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UZ5km/btqZegdcVOe/kbVKkTLwogFPIvX9ovzx00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUZ5km%2FbtqZegdcVOe%2FkbVKkTLwogFPIvX9ovzx00%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;1280&quot; height=&quot;374&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;h4 data-ke-size=&quot;size20&quot;&gt;3.3.2 스켈레톤 스크린&lt;/h4&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; Content, CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스켈레톤 스크린(Skeleton Screen) 또는 스켈레톤 UI라 부르는 것은 로딩이 조금 더 빠르다고 느끼게 한다. [&lt;a href=&quot;https://www.sitepoint.com/how-to-speed-up-your-ux-with-skeleton-screens/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;to&amp;nbsp;Speed&amp;nbsp;Up&amp;nbsp;Your&amp;nbsp;UX&amp;nbsp;with&amp;nbsp;Skeleton&amp;nbsp;Screens&lt;/a&gt;, &lt;a href=&quot;https://blog.logrocket.com/improve-ux-in-react-apps-by-showing-skeleton-ui/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Improve&amp;nbsp;UX&amp;nbsp;in&amp;nbsp;React&amp;nbsp;apps&amp;nbsp;by&amp;nbsp;showing&amp;nbsp;skeleton&amp;nbsp;UI&lt;/a&gt;, &lt;a href=&quot;https://uxdesign.cc/what-you-should-know-about-skeleton-screens-a820c45a571a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Everything&amp;nbsp;you&amp;nbsp;need&amp;nbsp;to&amp;nbsp;know&amp;nbsp;about&amp;nbsp;skeleton&amp;nbsp;screens&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eoVMUi/btqZju2y0Ug/3fbdPcPJRkGJZzfYkbOZ6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eoVMUi/btqZju2y0Ug/3fbdPcPJRkGJZzfYkbOZ6K/img.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;711&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eoVMUi/btqZju2y0Ug/3fbdPcPJRkGJZzfYkbOZ6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeoVMUi%2FbtqZju2y0Ug%2F3fbdPcPJRkGJZzfYkbOZ6K%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;400&quot; height=&quot;711&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4gEZc/btqZlO0zeMq/VqVS4pNYA9rbK0i0tTdPT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4gEZc/btqZlO0zeMq/VqVS4pNYA9rbK0i0tTdPT0/img.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;711&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4gEZc/btqZlO0zeMq/VqVS4pNYA9rbK0i0tTdPT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4gEZc%2FbtqZlO0zeMq%2FVqVS4pNYA9rbK0i0tTdPT0%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;400&quot; height=&quot;711&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브나 인스타그램 등에서 빈번히 쓰여서 알겠지만 빠르다는 느낌을 준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1346&quot; data-origin-height=&quot;637&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btvxNI/btqZfiaNfAq/IUmNtw5AHaZyqS8D7jlwdk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btvxNI/btqZfiaNfAq/IUmNtw5AHaZyqS8D7jlwdk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btvxNI/btqZfiaNfAq/IUmNtw5AHaZyqS8D7jlwdk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/btvxNI/btqZfiaNfAq/IUmNtw5AHaZyqS8D7jlwdk/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;1346&quot; height=&quot;637&quot; data-origin-width=&quot;1346&quot; data-origin-height=&quot;637&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;그러나 항상 좋은 선택인 것은 아니다. [&lt;a href=&quot;https://www.researchgate.net/publication/326858669_The_effect_of_skeleton_screens_Users%27_perception_of_speed_and_ease_of_navigation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;effect&amp;nbsp;of&amp;nbsp;skeleton&amp;nbsp;screens:&amp;nbsp;Users'&amp;nbsp;perception&amp;nbsp;of&amp;nbsp;speed&amp;nbsp;and&amp;nbsp;ease&amp;nbsp;of&amp;nbsp;navigation&lt;/a&gt;]&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;연구에 따르면 스켈레톤 스크린이 인지 속도와 탐색 용이성을 개선하지만, 스피너를 이용하면 처음 사이트에 들어갈 때 기사를 찾는 속도가 빨랐다고 한다.&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;CSS로 제작 할 수 있는 가이드.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/building-skeleton-screens-css-custom-properties/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Building Skeleton Screens with CSS Custom Properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leerob.io/blog/loading-placeholder-with-sass&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Creating a Loading Placeholder with Sass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marinaaisa.com/blog/design-and-code-skeletons-screens/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Design and code responsive Skeleton Screens&lt;/a&gt;&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;CSS로 만들 때 참고할만한 라이브러리, 생성기&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zalog/placeholder-loading&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Placeholder loading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.andy-howard.com/css-skeleton-screen-generator/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Skeleton Screen Generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/oslego/pen/XdvWmd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;심플한 예제&lt;/a&gt;(&lt;a href=&quot;https://wit.nts-corp.com/2018/11/19/5371&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;설명&lt;/a&gt;)&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/danilowoz/react-content-loader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Content Loader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/buildo/react-placeholder&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Placeholder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dvtng/react-loading-skeleton&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Loding Skeleton&lt;/a&gt;&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;특히 React Content Loader는 &lt;a href=&quot;https://danilowoz.com/create-content-loader/&quot;&gt;Create React Content Loader&lt;/a&gt;에서 50가지가 넘는 예제와 다양한 옵션으로 스켈레톤 스크린 코드를 만들어낼 수 있다!!&lt;/p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/willmendesneto/ngx-skeleton-loader&quot;&gt;ngx skeleton loader&lt;/a&gt;(Angular 용)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3.3 이미지 자리 표시자&lt;/h4&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; Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 Lazy Load시 생기는 빈공간에 쓸 방법이 몇가지 있다.[&lt;a href=&quot;https://www.freecodecamp.org/news/using-svg-as-placeholders-more-image-loading-techniques-bed1b810ab2c/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How to use SVG as a Placeholder, and Other Image Loading Techniques&lt;/a&gt;(&lt;a href=&quot;https://medium.com/free-code-camp/using-svg-as-placeholders-more-image-loading-techniques-bed1b810ab2c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;medium&lt;/a&gt;), &lt;a href=&quot;http://dsheiko.com/weblog/how-to-create-a-kick-ass-image-preview-with-lqip/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;to&amp;nbsp;create&amp;nbsp;a&amp;nbsp;kick-ass&amp;nbsp;image&amp;nbsp;preview&amp;nbsp;with&amp;nbsp;LQIP&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;409&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deOlmS/btqZjwe1HS8/TqQ3GqXkzScdLBrkQyDAkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deOlmS/btqZjwe1HS8/TqQ3GqXkzScdLBrkQyDAkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deOlmS/btqZjwe1HS8/TqQ3GqXkzScdLBrkQyDAkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeOlmS%2FbtqZjwe1HS8%2FTqQ3GqXkzScdLBrkQyDAkK%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;800&quot; height=&quot;409&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;409&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;빈공간:&lt;/b&gt; 자리를 채우지 않고, 그대로 나둠&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자리 표시자:&lt;/b&gt; 빈자리를 채울 때 사용할 만한 아이콘&lt;/li&gt;
&lt;li&gt;&lt;b&gt;색 채우기:&lt;/b&gt; 이미지를 대표하는 색을 이용해 채우기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가벼운 이미지:&lt;/b&gt; 가볍게 만들어진 이미지로 채우기&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;빈공간은 UX에서 나쁘며, 매번 레이아웃 계산을 해야 하기 때문에 성능에 악영향을 끼친다.&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;- 자리 표시자(Place Holder)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자리표시자라는 이미지 &lt;span style=&quot;color: #333333;&quot;&gt;요청을 실패했거나, 기본 아이콘으로도 사용할 수 있어 데이터가 더 필요하지 않으면서 UX를 향상시킬 수 있다.&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbSnZI/btqZjuO5nRK/GYhfv9CCetKLKDMkpfhFm1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbSnZI/btqZjuO5nRK/GYhfv9CCetKLKDMkpfhFm1/img.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1280&quot; style=&quot;width: 42.3588%; margin-right: 10px;&quot; data-widthpercent=&quot;42.86&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbSnZI/btqZjuO5nRK/GYhfv9CCetKLKDMkpfhFm1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbSnZI%2FbtqZjuO5nRK%2FGYhfv9CCetKLKDMkpfhFm1%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;1280&quot; height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Dcey/btqZhgwZfWd/E5K2UaREE1k8ZfmWPACLaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Dcey/btqZhgwZfWd/E5K2UaREE1k8ZfmWPACLaK/img.png&quot; srcset=&quot;&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;435&quot; style=&quot;width: 56.4784%;&quot; data-widthpercent=&quot;57.14&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Dcey/btqZhgwZfWd/E5K2UaREE1k8ZfmWPACLaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Dcey%2FbtqZhgwZfWd%2FE5K2UaREE1k8ZfmWPACLaK%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;435&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.iconspng.com/image/22157/placeholder-graphic-for-temporary-content&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Placeholder Image&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://freebiesbug.com/illustrator-freebies/iconify-650-free-icons/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Icons Image&lt;/a&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;span style=&quot;color: #333333;&quot;&gt;자리표시자 이미지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;해당 자리를 나타내는 기본 이미지&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;a href=&quot;https://loremipsum.io/21-of-the-best-placeholder-image-generators/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;21 of Best Placeholder Image Generator&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://placeholder.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Placeholder.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dummyimage.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dynamic&amp;nbsp;Dummy&amp;nbsp;Image&amp;nbsp;Generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://imgplaceholder.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ImgPlaceholder.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fakeimg.pl/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fake Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ipsumimage.appspot.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ipsum Image&lt;/a&gt;&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;/p&gt;
&lt;pre id=&quot;code_1586740180161&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;img src=&quot;https://dummyimage.com/300x200/000/fff.png&quot;&amp;gt;&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHeQuH/btqZdlZ7eQX/kFEkvv849DFLMh04VfGYDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHeQuH/btqZdlZ7eQX/kFEkvv849DFLMh04VfGYDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHeQuH/btqZdlZ7eQX/kFEkvv849DFLMh04VfGYDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHeQuH%2FbtqZdlZ7eQX%2FkFEkvv849DFLMh04VfGYDk%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;300&quot; height=&quot;200&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;200&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;b&gt;- 색 채우기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://designshack.net/articles/graphics/understanding-color-dominant-vs-recessive-colors/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;상징하는 색(Dominant Color)&lt;/a&gt;을 채운 후, 전환하는 예도 있다.[&lt;a href=&quot;https://manu.ninja/dominant-colors-for-lazy-loading-images&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dominant&amp;nbsp;Colors&amp;nbsp;for&amp;nbsp;Lazy-Loading&amp;nbsp;Images,&lt;/a&gt; &lt;a href=&quot;https://jmperezperez.com/medium-image-progressive-loading-placeholder/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;Medium&amp;nbsp;does&amp;nbsp;progressive&amp;nbsp;image&amp;nbsp;loading&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전환이 부드럽고, 직관적이며 작기 때문에 트래픽 비용도 크지 않다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4sYhe/btqZlP6fpzn/rxcvJ7UNNuGAjCakyPoCp0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4sYhe/btqZlP6fpzn/rxcvJ7UNNuGAjCakyPoCp0/img.gif&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;400&quot; style=&quot;width: 56.4499%; margin-right: 10px;&quot; data-widthpercent=&quot;57.11&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4sYhe/btqZlP6fpzn/rxcvJ7UNNuGAjCakyPoCp0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4sYhe%2FbtqZlP6fpzn%2FrxcvJ7UNNuGAjCakyPoCp0%2Fimg.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;720&quot; height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clnsvH/btqZlOTNWed/MYmTHxGGeA6JCp1XrAtop1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clnsvH/btqZlOTNWed/MYmTHxGGeA6JCp1XrAtop1/img.png&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;566&quot; style=&quot;width: 42.3873%;&quot; data-widthpercent=&quot;42.89&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clnsvH/btqZlOTNWed/MYmTHxGGeA6JCp1XrAtop1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclnsvH%2FbtqZlOTNWed%2FMYmTHxGGeA6JCp1XrAtop1%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;765&quot; height=&quot;566&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;단색&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d9nUtw/btqZn1FkZ44/HiB3e6I4KuCZtBVVLoI0G1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d9nUtw/btqZn1FkZ44/HiB3e6I4KuCZtBVVLoI0G1/img.jpg&quot; style=&quot;width: 39.7964%; margin-right: 10px;&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;480&quot; data-widthpercent=&quot;40.26&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d9nUtw/btqZn1FkZ44/HiB3e6I4KuCZtBVVLoI0G1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd9nUtw%2FbtqZn1FkZ44%2FHiB3e6I4KuCZtBVVLoI0G1%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;726&quot; height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/262Mi/btqZjuO5or9/K2cVJVSHq4Kznea9unK7n0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/262Mi/btqZjuO5or9/K2cVJVSHq4Kznea9unK7n0/img.jpg&quot; data-origin-width=&quot;920&quot; data-origin-height=&quot;410&quot; style=&quot;width: 59.0408%;&quot; data-widthpercent=&quot;59.74&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/262Mi/btqZjuO5or9/K2cVJVSHq4Kznea9unK7n0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F262Mi%2FbtqZjuO5or9%2FK2cVJVSHq4Kznea9unK7n0%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;920&quot; height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;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;/ul&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;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://manu.ninja/dominant-colors-for-lazy-loading-images&quot;&gt;k-means clustering&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;을 사용하거나,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://www.graphicsmagick.org/quantize.html&quot;&gt;색상 양자화&lt;/a&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;그 후 base 인코딩으로 내장하면 끝&lt;/p&gt;
&lt;pre id=&quot;code_1586741312877&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;img src=&quot;data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=&quot;
     data-src=&quot;https://s-media-cache-ak0.pinimg.com/474x/50/1b/74/501b74902935b063816ea8e14f460ca0.jpg&quot;
     alt=&quot;Ghost In The Shell&quot;&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;CSS로 그라디언트를 만드는 것은 &lt;a href=&quot;https://web.archive.org/web/20170610002743/https://gradifycss.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradify&lt;/a&gt;(&lt;a href=&quot;https://github.com/fraser-hemp/gradify&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;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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj4hWQ/btqZefSTfBM/IUPVuwUhkXMLCSklZOAIF0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj4hWQ/btqZefSTfBM/IUPVuwUhkXMLCSklZOAIF0/img.gif&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;380&quot; style=&quot;width: 37.1804%; margin-right: 10px;&quot; data-widthpercent=&quot;37.62&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj4hWQ/btqZefSTfBM/IUPVuwUhkXMLCSklZOAIF0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj4hWQ%2FbtqZefSTfBM%2FIUPVuwUhkXMLCSklZOAIF0%2Fimg.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;345&quot; height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d3SKep/btqZn0NcJDX/mQQSMsmcewTPct0wSzAeQk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d3SKep/btqZn0NcJDX/mQQSMsmcewTPct0wSzAeQk/img.gif&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;538&quot; style=&quot;width: 61.6568%;&quot; data-widthpercent=&quot;62.38&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d3SKep/btqZn0NcJDX/mQQSMsmcewTPct0wSzAeQk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd3SKep%2FbtqZn0NcJDX%2FmQQSMsmcewTPct0wSzAeQk%2Fimg.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;810&quot; height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;widthContent&quot; data-origin-width=&quot;1313&quot; data-origin-height=&quot;786&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNBVQn/btqZn0NcKpl/ENakh2Fk8BVvaMhrFhAfGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNBVQn/btqZn0NcKpl/ENakh2Fk8BVvaMhrFhAfGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNBVQn/btqZn0NcKpl/ENakh2Fk8BVvaMhrFhAfGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNBVQn%2FbtqZn0NcKpl%2FENakh2Fk8BVvaMhrFhAfGK%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;1313&quot; height=&quot;786&quot; data-origin-width=&quot;1313&quot; data-origin-height=&quot;786&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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://github.com/JMPerez/contour&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;contour&lt;/a&gt;나&amp;nbsp;&lt;a href=&quot;https://github.com/tooolbox/node-potrace&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;node-potrace&lt;/a&gt;을 참고하면 된다. [&lt;a href=&quot;https://medium.com/@jmperezperez/drawing-images-using-edge-detection-and-svg-animation-16a1a3676d3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Drawing&amp;nbsp;images&amp;nbsp;using&amp;nbsp;edge&amp;nbsp;detection&amp;nbsp;and&amp;nbsp;SVG&amp;nbsp;animation&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;a href=&quot;https://github.com/zouhir/lqip&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LQIP(Low Quality Images Placeholder)&lt;/a&gt;와 &lt;a href=&quot;https://github.com/axe312ger/sqip&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SQIP(SVG-based LQIP)&lt;/a&gt;를 사용해 블러, 모자이크, 폴리곤 형태의 이미지를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQIP의 art는 마치 인상파와 야수파를 섞은 종이소재 작품 같다. ㅎㅎ&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/EmilTholin/image-trace-loader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image Trace Loader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zouhir/lqip-loader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LQIP-Loader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/EmilTholin/sqip-loader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SQIP-Loader&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGoFxK/btqZju2y3og/wVn6CRxXrvpQlNJEP19wsK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGoFxK/btqZju2y3og/wVn6CRxXrvpQlNJEP19wsK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGoFxK/btqZju2y3og/wVn6CRxXrvpQlNJEP19wsK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGoFxK%2FbtqZju2y3og%2FwVn6CRxXrvpQlNJEP19wsK%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;1280&quot; height=&quot;474&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;474&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://jmperezperez.com/cssconfau16/#/45&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSSConf&lt;/a&gt;나 &lt;a href=&quot;https://jmperezperez.com/renderconf17/#/46&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Render Conf&lt;/a&gt;처럼 &lt;a href=&quot;https://en.wikipedia.org/wiki/Delaunay_triangulation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;들로네 삼각 분할 (Delaunay Triangulation)&lt;/a&gt;을 이용해 삼각 폴리곤처럼 만든 &lt;a href=&quot;https://github.com/possan/polyserver&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;polyserver&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;b&gt;- 비디오&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비디오의 경우 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Element/Video#attr-poster&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;poster 속성&lt;/a&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;3.3.4 로딩 인디케이터와 인터렉션&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적절한 로딩 인디케이터와 인터렉션은 사용자에게 빠르다고 느끼게 만들 수 있다.[&lt;a href=&quot;https://blogs.adobe.com/creativedialogue/design-ko/xd-essentials-best-practices-for-animated-progress-indicators-kr/&quot;&gt;XD 필수 항목: 애니메이션 진행률 표시기의 모범 사례&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;https://medium.com/flawless-app-stories/everything-you-need-to-know-about-loading-animations-10db7f9b61e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Everything&amp;nbsp;you&amp;nbsp;need&amp;nbsp;to&amp;nbsp;know&amp;nbsp;about&amp;nbsp;Loading&amp;nbsp;Animations&lt;/a&gt;, &lt;a href=&quot;https://usersnap.com/blog/progress-indicators/&quot;&gt;Improving&amp;nbsp;the&amp;nbsp;UX&amp;nbsp;of&amp;nbsp;Progress&amp;nbsp;Indicators&amp;nbsp;and&amp;nbsp;Feedback&amp;nbsp;Notifications&lt;/a&gt;, &lt;a href=&quot;http://icunow.co.kr/%EB%AA%A8%EB%B0%94%EC%9D%BC-%EC%95%B1%EC%97%90%EC%84%9C%EC%9D%98-%EB%8C%80%ED%91%9C%EC%A0%81%EC%9D%B8-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98-%ED%99%9C%EC%9A%A9-%EB%B0%A9%EB%B2%95/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모바일&amp;nbsp;앱에서의&amp;nbsp;대표적인&amp;nbsp;애니메이션&amp;nbsp;활용&amp;nbsp;방법&lt;/a&gt;]&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;시스템&amp;nbsp;상태의&amp;nbsp;가시성은&amp;nbsp;유저&amp;nbsp;인터페이스&amp;nbsp;디자인에서&amp;nbsp;&lt;a href=&quot;https://www.nngroup.com/articles/ten-usability-heuristics/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;가장&amp;nbsp;중요한&amp;nbsp;원칙&lt;/a&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;방법입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 웹에서 애니메이션이 빈번히 사용되는 것은 아니나 점점 APP화가 되어가는 추세이기 때문에(PWA, 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;b&gt;로딩 인디케이터&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;&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;a href=&quot;https://uxmovement.com/navigation/progress-bars-vs-spinners-when-to-use-which/&quot;&gt;Progress Bars vs. Spinners: When to Use Which&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&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;&lt;span style=&quot;color: #333333;&quot;&gt;4초이상일 때: 프로그레스바, 아니라면 스피너&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1초 미만일 때: 아무것도 사용하지 말기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;멈추어 있으면 않됨&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxTveh/btqZctc4HoK/ASgR5S4a5G8iq5Su6KLYG0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxTveh/btqZctc4HoK/ASgR5S4a5G8iq5Su6KLYG0/img.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxTveh/btqZctc4HoK/ASgR5S4a5G8iq5Su6KLYG0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxTveh%2FbtqZctc4HoK%2FASgR5S4a5G8iq5Su6KLYG0%2Fimg.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;800&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crwD6S/btqZdly4DJk/mfRkq8dK7KWsFnrs3zQbD0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crwD6S/btqZdly4DJk/mfRkq8dK7KWsFnrs3zQbD0/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;300&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crwD6S/btqZdly4DJk/mfRkq8dK7KWsFnrs3zQbD0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrwD6S%2FbtqZdly4DJk%2FmfRkq8dK7KWsFnrs3zQbD0%2Fimg.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;400&quot; height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5KNat/btqZjwF70Uk/AWZDAJUOK2T5r9KX7q2ACK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5KNat/btqZjwF70Uk/AWZDAJUOK2T5r9KX7q2ACK/img.gif&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;321&quot; style=&quot;width: 42.3588%; margin-right: 10px;&quot; data-widthpercent=&quot;42.86&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5KNat/btqZjwF70Uk/AWZDAJUOK2T5r9KX7q2ACK/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5KNat%2FbtqZjwF70Uk%2FAWZDAJUOK2T5r9KX7q2ACK%2Fimg.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;321&quot; height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIhCuf/btqZn1ZD6AU/abEKgH5xCU48nrnXCkjHn0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIhCuf/btqZn1ZD6AU/abEKgH5xCU48nrnXCkjHn0/img.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; style=&quot;width: 56.4784%;&quot; data-widthpercent=&quot;57.14&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIhCuf/btqZn1ZD6AU/abEKgH5xCU48nrnXCkjHn0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIhCuf%2FbtqZn1ZD6AU%2FabEKgH5xCU48nrnXCkjHn0%2Fimg.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;800&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/div&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;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;a href=&quot;https://brunch.co.kr/@hyeminimi/20&quot;&gt;[번역]UX에서 적절한 애니메이션효과를 위한 가이드&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&lt;/span&gt;&lt;a href=&quot;https://brunch.co.kr/@hyeminimi/21&quot;&gt;2편&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://brunch.co.kr/@lain/2&quot;&gt;모션으로 사용성 만들기 : 모션 선언문의 UX&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&lt;/span&gt;&lt;a href=&quot;https://brunch.co.kr/@lain/3&quot;&gt;2편&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;), &lt;a href=&quot;https://css-tricks.com/ease-out-in-ease-in-out/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ease-out,&amp;nbsp;in;&amp;nbsp;ease-in,&amp;nbsp;out&lt;/a&gt;, &lt;a href=&quot;https://uxdesign.cc/the-ultimate-guide-to-proper-use-of-animation-in-ux-10bd98614fa9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The ultimate&amp;nbsp;guide&amp;nbsp;to&amp;nbsp;proper&amp;nbsp;use&amp;nbsp;of&amp;nbsp;animation&amp;nbsp;in&amp;nbsp;UX&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 style=&quot;font-size: 1.12em;&quot; 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;span style=&quot;color: #333333;&quot;&gt;로딩 인디케이터는&amp;nbsp;&lt;/span&gt;&lt;b&gt;오래 걸리는 작업에만(약 5초 이상)&lt;/b&gt;&amp;nbsp;사용해야한다. [&lt;a href=&quot;https://uxdesign.cc/stop-using-a-loading-spinner-theres-something-better-d186194f771e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Stop&amp;nbsp;Using&amp;nbsp;A&amp;nbsp;Loading&amp;nbsp;Spinner,&amp;nbsp;There&amp;rsquo;s&amp;nbsp;Something&amp;nbsp;Better&lt;/a&gt;, &lt;a href=&quot;https://www.lukew.com/ff/entry.asp?1797&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mobile&amp;nbsp;Design&amp;nbsp;Details:&amp;nbsp;Avoid&amp;nbsp;The&amp;nbsp;Spinner&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;시계가 똑딱 거리는 것을 보는 것과 마찬가지.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buzuI2/btqZdkNKJZk/XWNktVf2nVw4Nkr9rKDdEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buzuI2/btqZdkNKJZk/XWNktVf2nVw4Nkr9rKDdEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buzuI2/btqZdkNKJZk/XWNktVf2nVw4Nkr9rKDdEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuzuI2%2FbtqZdkNKJZk%2FXWNktVf2nVw4Nkr9rKDdEK%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;1000&quot; height=&quot;552&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d3Yosk/btqZnZ1PRak/1B8v6tm5lRy2p3nDPYv8O1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d3Yosk/btqZnZ1PRak/1B8v6tm5lRy2p3nDPYv8O1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d3Yosk/btqZnZ1PRak/1B8v6tm5lRy2p3nDPYv8O1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd3Yosk%2FbtqZnZ1PRak%2F1B8v6tm5lRy2p3nDPYv8O1%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;755&quot; height=&quot;544&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;544&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이때, 인식되는 값을 대기 시간과 일치 시켜야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;어떤 작업을 하고 있는지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDT7fj/btqZcsFeFzv/a68tKiiMNKGEMoXGTQbK2K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDT7fj/btqZcsFeFzv/a68tKiiMNKGEMoXGTQbK2K/img.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDT7fj/btqZcsFeFzv/a68tKiiMNKGEMoXGTQbK2K/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDT7fj%2FbtqZcsFeFzv%2Fa68tKiiMNKGEMoXGTQbK2K%2Fimg.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;800&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/quAmC/btqZlP6fryP/WNDiIc9kzJsoLAoprdHtR1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/quAmC/btqZlP6fryP/WNDiIc9kzJsoLAoprdHtR1/img.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/quAmC/btqZlP6fryP/WNDiIc9kzJsoLAoprdHtR1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FquAmC%2FbtqZlP6fryP%2FWNDiIc9kzJsoLAoprdHtR1%2Fimg.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;800&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccuVCf/btqZdmEIxfB/vd7o8CiBe4KjCAtrM82LNk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccuVCf/btqZdmEIxfB/vd7o8CiBe4KjCAtrM82LNk/img.gif&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;500&quot; style=&quot;width: 29.3023%; margin-right: 10px;&quot; data-widthpercent=&quot;30&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccuVCf/btqZdmEIxfB/vd7o8CiBe4KjCAtrM82LNk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccuVCf%2FbtqZdmEIxfB%2Fvd7o8CiBe4KjCAtrM82LNk%2Fimg.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;500&quot; height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQ2Phz/btqZeg5jpkt/PryvzlqXeoWWG1KDYKKHY1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQ2Phz/btqZeg5jpkt/PryvzlqXeoWWG1KDYKKHY1/img.gif&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;540&quot; style=&quot;width: 29.3023%; margin-right: 10px;&quot; data-widthpercent=&quot;30&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQ2Phz/btqZeg5jpkt/PryvzlqXeoWWG1KDYKKHY1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQ2Phz%2FbtqZeg5jpkt%2FPryvzlqXeoWWG1KDYKKHY1%2Fimg.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;540&quot; height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PF9X4/btqZkpteOtw/nkoER1b2xClgSXrFm9l1w1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PF9X4/btqZkpteOtw/nkoER1b2xClgSXrFm9l1w1/img.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; style=&quot;width: 39.0698%;&quot; data-widthpercent=&quot;40&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PF9X4/btqZkpteOtw/nkoER1b2xClgSXrFm9l1w1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPF9X4%2FbtqZkpteOtw%2FnkoER1b2xClgSXrFm9l1w1%2Fimg.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;800&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/div&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;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;li&gt;각종 팁이나 정보 보여주기&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d68GAZ/btqZfhCVjAJ/BlRWjulaCyVIsqpc3Ehfu0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d68GAZ/btqZfhCVjAJ/BlRWjulaCyVIsqpc3Ehfu0/img.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d68GAZ/btqZfhCVjAJ/BlRWjulaCyVIsqpc3Ehfu0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd68GAZ%2FbtqZfhCVjAJ%2FBlRWjulaCyVIsqpc3Ehfu0%2Fimg.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;800&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bk8kIu/btqZefSTf3I/hH2sPBK7DBvBmfKZu1bvxk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bk8kIu/btqZefSTf3I/hH2sPBK7DBvBmfKZu1bvxk/img.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bk8kIu/btqZefSTf3I/hH2sPBK7DBvBmfKZu1bvxk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbk8kIu%2FbtqZefSTf3I%2FhH2sPBK7DBvBmfKZu1bvxk%2Fimg.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;800&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRRiKK/btqZkrdsPGX/CEkUykv48pX7D1DY31IlL0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRRiKK/btqZkrdsPGX/CEkUykv48pX7D1DY31IlL0/img.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; style=&quot;width: 51.3005%; margin-right: 10px;&quot; data-widthpercent=&quot;52.52&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRRiKK/btqZkrdsPGX/CEkUykv48pX7D1DY31IlL0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRRiKK%2FbtqZkrdsPGX%2FCEkUykv48pX7D1DY31IlL0%2Fimg.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;800&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVZzeH/btqZehiUmbf/P2JV2hiwHjj7905uDChfX1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVZzeH/btqZehiUmbf/P2JV2hiwHjj7905uDChfX1/img.gif&quot; data-origin-width=&quot;375&quot; data-origin-height=&quot;585&quot; style=&quot;width: 24.6637%; margin-right: 10px;&quot; data-widthpercent=&quot;25.25&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVZzeH/btqZehiUmbf/P2JV2hiwHjj7905uDChfX1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVZzeH%2FbtqZehiUmbf%2FP2JV2hiwHjj7905uDChfX1%2Fimg.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;375&quot; height=&quot;585&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4tr2Y/btqZjuO5pQQ/KydTtyhzKox4iLKfOUewV1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4tr2Y/btqZjuO5pQQ/KydTtyhzKox4iLKfOUewV1/img.gif&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;638&quot; style=&quot;width: 21.7102%;&quot; data-widthpercent=&quot;22.23&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4tr2Y/btqZjuO5pQQ/KydTtyhzKox4iLKfOUewV1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4tr2Y%2FbtqZjuO5pQQ%2FKydTtyhzKox4iLKfOUewV1%2Fimg.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;360&quot; height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DAuy4/btqZn0fmzy9/RXoHwjGp2FYKTeHG9M7Ld1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DAuy4/btqZn0fmzy9/RXoHwjGp2FYKTeHG9M7Ld1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DAuy4/btqZn0fmzy9/RXoHwjGp2FYKTeHG9M7Ld1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDAuy4%2FbtqZn0fmzy9%2FRXoHwjGp2FYKTeHG9M7Ld1%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;960&quot; height=&quot;540&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;정보를 보여주는 것은 게임에서 자주 쓰이는 방식. [&lt;a href=&quot;https://www.uplabs.com/posts/pull-to-refresh-airbnb&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;pull to refresh airbnb&lt;/a&gt;, &lt;a href=&quot;https://brunch.co.kr/@bigpic/21&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Case study #01 배달의 민족&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://www.youtube.com/watch?v=PFawDr4ELT4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;배민키친 로딩&lt;/a&gt;, &lt;a href=&quot;https://www.reddit.com/r/FortNiteBR/comments/aavyyy/any_one_else_stuck_on_creative_loading_screen/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Any&amp;nbsp;one&amp;nbsp;else&amp;nbsp;stuck&amp;nbsp;on&amp;nbsp;creative&amp;nbsp;loading&amp;nbsp;screen?&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;/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;span style=&quot;letter-spacing: 0px;&quot;&gt;사용자는 앱 성능 대신 인터넷 연결 또는 장치 속도에 대해 불평 할 가능성이 높음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wz8dG/btqZkrdsSg8/gOtKLs666KgIsBDWnMqT3k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wz8dG/btqZkrdsSg8/gOtKLs666KgIsBDWnMqT3k/img.jpg&quot; style=&quot;width: 54.5429%; margin-right: 10px;&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; data-widthpercent=&quot;55.18&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wz8dG/btqZkrdsSg8/gOtKLs666KgIsBDWnMqT3k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwz8dG%2FbtqZkrdsSg8%2FgOtKLs666KgIsBDWnMqT3k%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;800&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G7t7G/btqZiUHcLZM/jXaUZoNgJ9NDtY9TkaYKW0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G7t7G/btqZiUHcLZM/jXaUZoNgJ9NDtY9TkaYKW0/img.gif&quot; style=&quot;width: 44.294355662729394%;&quot; data-canonical-src=&quot;http://f.cl.ly/items/2G1F1Z0M0k0h2U3V1p39/SVProgressHUD.gif&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;314&quot; data-widthpercent=&quot;44.82&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G7t7G/btqZiUHcLZM/jXaUZoNgJ9NDtY9TkaYKW0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG7t7G%2FbtqZiUHcLZM%2FjXaUZoNgJ9NDtY9TkaYKW0%2Fimg.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;340&quot; height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8gdBt/btqZcsZvDXN/6TmdVKNO8Qug9NuzBw6TQ0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8gdBt/btqZcsZvDXN/6TmdVKNO8Qug9NuzBw6TQ0/img.gif&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;328&quot; style=&quot;width: 40.9159%; margin-right: 10px;&quot; data-widthpercent=&quot;41.4&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8gdBt/btqZcsZvDXN/6TmdVKNO8Qug9NuzBw6TQ0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8gdBt%2FbtqZcsZvDXN%2F6TmdVKNO8Qug9NuzBw6TQ0%2Fimg.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;411&quot; height=&quot;328&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLJBo0/btqZiTVP7et/ffHSQ8tADh3FdIHZ6iMIn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLJBo0/btqZiTVP7et/ffHSQ8tADh3FdIHZ6iMIn0/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;451&quot; style=&quot;width: 57.9213%;&quot; data-widthpercent=&quot;58.6&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLJBo0/btqZiTVP7et/ffHSQ8tADh3FdIHZ6iMIn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLJBo0%2FbtqZiTVP7et%2FffHSQ8tADh3FdIHZ6iMIn0%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;800&quot; height=&quot;451&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;네이티브 로딩 스피너 느낌[&lt;a href=&quot;https://www.sketchappsources.com/free-source/2151-mobile-landing-spinners-sketch-freebie-resource.html&quot;&gt;Mobile Loading Spinners Sketch Resource&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/SVProgressHUD/SVProgressHUD&quot;&gt;SVProgressHUD&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://reactnativeexample.com/native-ios-and-android-loading-spinner-progress-bar-indicator-overlay/&quot;&gt;Native iOS and Android loading spinner (progress bar indicator) overlay&lt;/a&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;ios, android, 웹에 다 적합한 느낌.&lt;/p&gt;
&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://www.chrisharrison.net/projects/progressbars2/ProgressBarsHarrison.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Faster Progress Bars: Manipulating Perceived Duration with Visual Augmentations&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://openventio.org/wp-content/uploads/Does-Progress-Bars-Behavior-Influence-the-User-Experience-in-Human-Computer-Interaction-PCSOJ-5-144.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Does Progress Bars&amp;rsquo; Behavior Influence the User Experience in Human-Computer Interaction?&lt;/a&gt;, &lt;a href=&quot;https://brunch.co.kr/@ebprux/218&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;진행바 속도가 빠르다고 느끼게 만드는 방법&lt;/a&gt;, &lt;a href=&quot;https://m.blog.naver.com/khrireg/10188627711&quot;&gt;'로딩바&amp;nbsp;-&amp;nbsp;프로그레스바'의&amp;nbsp;비밀&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그래스바의 강조를 자주, 스피너라면 회전수를 늘림&amp;nbsp;&lt;/li&gt;
&lt;li&gt;세로무늬가 거꾸로 진행하는 것이 더 빠르다 느낌&lt;/li&gt;
&lt;li&gt;진행 마지막에 가속화(처음에 느리게, 마지막에 빠르게)&lt;/li&gt;
&lt;/ul&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=N6lC-pXY9NU&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/f2GsF/hyFI4nRB0j/7E76zNbPZ4yKGgAJbs9XNK/img.jpg?width=640&amp;amp;height=480&amp;amp;face=0_0_640_480&quot; data-video-width=&quot;640&quot; data-video-height=&quot;480&quot; data-video-origin-width=&quot;undefined&quot; data-video-origin-height=&quot;undefined&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/N6lC-pXY9NU&quot; width=&quot;640&quot; height=&quot;480&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;마지막의 가운데 두개가 가장 빠르다고 느낌&lt;/figcaption&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;&lt;b&gt;애니메이션과 인터렉션&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동작 속도&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;100~350ms 정도&lt;/li&gt;
&lt;li&gt;리스트 아이템은 250ms 이하로&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동작 가속 [&lt;a href=&quot;https://developers.google.com/web/fundamentals/design-and-ux/animations/asymmetric-animation-timing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비대칭&amp;nbsp;애니메이션&amp;nbsp;타이밍&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/fundamentals/design-and-ux/animations/custom-easing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;사용자설정&amp;nbsp;easing&lt;/a&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;li&gt;Ease-in(가속)은 사라질때, Ease-out(감속)은 나타날 때&lt;/li&gt;
&lt;li&gt;Ease-in-out(표준곡선, 가속 후 감속) 시 비대칭으로&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ease-in-out 효과를 사용시 &lt;a href=&quot;https://googlesamples.github.io/web-fundamentals/fundamentals/design-and-ux/animations/curve-playground.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;애니메이션 곡선도구&lt;/a&gt;를 활용해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cv2QI7/btqZdlMzaiV/85QQQF1agdNrkgcRdvip30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cv2QI7/btqZdlMzaiV/85QQQF1agdNrkgcRdvip30/img.png&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;600&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cv2QI7/btqZdlMzaiV/85QQQF1agdNrkgcRdvip30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcv2QI7%2FbtqZdlMzaiV%2F85QQQF1agdNrkgcRdvip30%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;640&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQjDZ3/btqZdkNKPor/AKWuugvQ7qYRWUoUHcvCVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQjDZ3/btqZdkNKPor/AKWuugvQ7qYRWUoUHcvCVk/img.png&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;600&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQjDZ3/btqZdkNKPor/AKWuugvQ7qYRWUoUHcvCVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQjDZ3%2FbtqZdkNKPor%2FAKWuugvQ7qYRWUoUHcvCVk%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;640&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/div&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;같은 컨테이너에서 가능한 적은 요소에만 적용&lt;/li&gt;
&lt;li&gt;같은 컨테이너의 요소는 Offset(상쇄, 원래 상태로), Separateness(분리) 되도록&lt;/li&gt;
&lt;li&gt;크기 변화가 균일하면 직선, 불균일하면 커브로 이동
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커브로 동작시, 스크롤 인터페이스 주축(보통 Virtical out)과 일치해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;상호작용시 공간적/시간적 계층관계 만들기&lt;/li&gt;
&lt;li&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;현재화면에서 새로운 오브젝트가 생성시 Cloning&lt;/li&gt;
&lt;li&gt;새로운 오브젝트 생성시 차원 이용&lt;/li&gt;
&lt;li&gt;모호한 동작시 정적인 상태에서 일시적으로 움직임&lt;/li&gt;
&lt;li&gt;스크롤 시 2차원적인 공간에 계층구조&lt;/li&gt;
&lt;li&gt;오브젝트, 공간을 탐색시 연속적이고 공간적이게&lt;/li&gt;
&lt;/ul&gt;
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기 이쁘고, 좋은 예들이 존재한다. [&lt;a href=&quot;https://brunch.co.kr/@kakao-it/279&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음웹툰의 UX 개편 이야기&lt;/a&gt;, &lt;a href=&quot;https://blog.tubikstudio.com/ux-design-how-to-use-animations-in-mobile-apps/&quot;&gt;UX&amp;nbsp;Design:&amp;nbsp;How&amp;nbsp;to&amp;nbsp;Use&amp;nbsp;Animations&amp;nbsp;in&amp;nbsp;Mobile&amp;nbsp;Apps&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rHF22/btqZhe0hwnu/eUvbEJyRJgFGJOHyKAIzA0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rHF22/btqZhe0hwnu/eUvbEJyRJgFGJOHyKAIzA0/img.gif&quot; data-origin-width=&quot;330&quot; data-origin-height=&quot;640&quot; style=&quot;width: 32.3888%; margin-right: 10px;&quot; data-widthpercent=&quot;32.77&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rHF22/btqZhe0hwnu/eUvbEJyRJgFGJOHyKAIzA0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrHF22%2FbtqZhe0hwnu%2FeUvbEJyRJgFGJOHyKAIzA0%2Fimg.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;330&quot; height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H5agS/btqZhgwZjje/K7ytN6sakBxIY2Vpa9FIyK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H5agS/btqZhgwZjje/K7ytN6sakBxIY2Vpa9FIyK/img.gif&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;484&quot; style=&quot;width: 66.4485%;&quot; data-widthpercent=&quot;67.23&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H5agS/btqZhgwZjje/K7ytN6sakBxIY2Vpa9FIyK/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH5agS%2FbtqZhgwZjje%2FK7ytN6sakBxIY2Vpa9FIyK%2Fimg.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;512&quot; height=&quot;484&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;682&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L7UKC/btqZjwsyL7I/kZGARrJ0IECwroEY64ORkk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L7UKC/btqZjwsyL7I/kZGARrJ0IECwroEY64ORkk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L7UKC/btqZjwsyL7I/kZGARrJ0IECwroEY64ORkk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/L7UKC/btqZjwsyL7I/kZGARrJ0IECwroEY64ORkk/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;364&quot; height=&quot;682&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;682&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 style=&quot;text-align: center;&quot; 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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3.5 낙관적 UI&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낙관적 UI(Optimistic UI)는 &lt;span style=&quot;color: #333333;&quot;&gt;작동하는 척 일종의 사기(?, 그냥 블러핑이라 해두자)를 치는 것 이다. [&lt;a href=&quot;https://story.pxd.co.kr/1193&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;옵티미스틱 UI의 계산된 거짓말&lt;/a&gt;, &lt;a href=&quot;https://uxplanet.org/optimistic-1000-34d9eefe4c05&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimistic UIs in under 1000 words&lt;/a&gt;, &lt;a href=&quot;https://dev.to/tiagodcosta/being-optimistic-in-ui-511k&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Being&amp;nbsp;optimistic&amp;nbsp;in&amp;nbsp;UI&lt;/a&gt;, &lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.fastcompany.com/1669788/the-3-white-lies-behind-instagrams-lightning-speed&quot;&gt;The 3 White Lies Behind Instagram&amp;rsquo;s Lightning Speed&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://speakerdeck.com/mikeyk/secrets-to-lightning-fast-mobile-design&quot;&gt;Secrets to Lightning Fast Mobile Design&lt;/a&gt;, &lt;a href=&quot;https://www.sitepoint.com/3-tips-make-application-feel-faster/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;3&amp;nbsp;Tips&amp;nbsp;To&amp;nbsp;Make&amp;nbsp;Your&amp;nbsp;Application&amp;nbsp;&lt;i&gt;Feel&lt;/i&gt;&amp;nbsp;Faster&lt;/a&gt;&lt;/span&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;먼저 작동완료 된 것처럼 표시하고, 나중에 업데이트를 하자는 뜻인데, 절차는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWTzsg/btqZhe0hwoQ/JWEJZiYWYj8p5KuUQeVwbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWTzsg/btqZhe0hwoQ/JWEJZiYWYj8p5KuUQeVwbk/img.png&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;360&quot; style=&quot;width: 52.2037%; margin-right: 10px;&quot; data-widthpercent=&quot;52.82&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWTzsg/btqZhe0hwoQ/JWEJZiYWYj8p5KuUQeVwbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWTzsg%2FbtqZhe0hwoQ%2FJWEJZiYWYj8p5KuUQeVwbk%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;650&quot; height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wLF8V/btqZlQxi5w8/VTjKFmcNeFqJYzroWiAD1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wLF8V/btqZlQxi5w8/VTjKFmcNeFqJYzroWiAD1K/img.png&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;403&quot; style=&quot;width: 46.6335%;&quot; data-widthpercent=&quot;47.18&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wLF8V/btqZlQxi5w8/VTjKFmcNeFqJYzroWiAD1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwLF8V%2FbtqZlQxi5w8%2FVTjKFmcNeFqJYzroWiAD1K%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;650&quot; height=&quot;403&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;기존 방식과 낙관적 UI&lt;/figcaption&gt;
&lt;/figure&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;li&gt;오류가 생겼는지 파악, 생겼다면 전 상태로 롤백[기준은 보통 2초]&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;바로 전에 나왔던 애니메이션 효과를 이용한 방법도 동작하고 있는 것처럼 시간(약 100~350ms)원리이니 일종의 Optimistic 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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lsWa8/btqZfhCVmwq/ikcOFwsDz8XIfZbkR6pCf1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lsWa8/btqZfhCVmwq/ikcOFwsDz8XIfZbkR6pCf1/img.gif&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;336&quot; style=&quot;width: 45.7872%; margin-right: 10px;&quot; data-widthpercent=&quot;46.33&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lsWa8/btqZfhCVmwq/ikcOFwsDz8XIfZbkR6pCf1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlsWa8%2FbtqZfhCVmwq%2FikcOFwsDz8XIfZbkR6pCf1%2Fimg.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;359&quot; height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhlVEh/btqZkrdsSyx/ERsWnh9frqIktDc6ipJp7K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhlVEh/btqZkrdsSyx/ERsWnh9frqIktDc6ipJp7K/img.gif&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;290&quot; style=&quot;width: 53.05%;&quot; data-widthpercent=&quot;53.67&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhlVEh/btqZkrdsSyx/ERsWnh9frqIktDc6ipJp7K/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhlVEh%2FbtqZkrdsSyx%2FERsWnh9frqIktDc6ipJp7K%2Fimg.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;359&quot; height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;일반 vs Optismitic UI&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/DSMann/pen/KOxJYq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimistic UI Comparison&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 보낸척 표시하고 작은 로딩바가 표시되는 것을 확인가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c15dZn/btqZctRGRiK/DSMGCosxsRaKfGKcFo4AIk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c15dZn/btqZctRGRiK/DSMGCosxsRaKfGKcFo4AIk/img.gif&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;680&quot; style=&quot;width: 58.1929%; margin-right: 10px;&quot; data-widthpercent=&quot;58.88&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c15dZn/btqZctRGRiK/DSMGCosxsRaKfGKcFo4AIk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc15dZn%2FbtqZctRGRiK%2FDSMGCosxsRaKfGKcFo4AIk%2Fimg.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;916&quot; height=&quot;680&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IF3be/btqZlP6fwt0/omml7yNLzZvV6G0ccX1ZV1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IF3be/btqZlP6fwt0/omml7yNLzZvV6G0ccX1ZV1/img.gif&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;524&quot; style=&quot;width: 40.6443%;&quot; data-widthpercent=&quot;41.12&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IF3be/btqZlP6fwt0/omml7yNLzZvV6G0ccX1ZV1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIF3be%2FbtqZlP6fwt0%2Fomml7yNLzZvV6G0ccX1ZV1%2Fimg.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;493&quot; height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;맥 iMessage와 인스타그램&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;인스타그램의 좋아요 표시, Audible의 다운로드 받으며 듣기(스트리밍)도 비슷한 예제.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR1csE/btqZcsLZWKS/e2FtxIOOVlb5YynaEKnkO1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR1csE/btqZcsLZWKS/e2FtxIOOVlb5YynaEKnkO1/img.webp&quot; data-origin-width=&quot;596&quot; data-origin-height=&quot;571&quot; style=&quot;width: 35.8753%; margin-right: 10px;&quot; data-widthpercent=&quot;36.3&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR1csE/btqZcsLZWKS/e2FtxIOOVlb5YynaEKnkO1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR1csE%2FbtqZcsLZWKS%2Fe2FtxIOOVlb5YynaEKnkO1%2Fimg.webp&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;596&quot; height=&quot;571&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbIJnW/btqZfhiEpSR/2OagojlLFRoHWBywqqkB1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbIJnW/btqZfhiEpSR/2OagojlLFRoHWBywqqkB1k/img.png&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;678&quot; style=&quot;width: 62.9619%;&quot; data-widthpercent=&quot;63.7&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbIJnW/btqZfhiEpSR/2OagojlLFRoHWBywqqkB1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbIJnW%2FbtqZfhiEpSR%2F2OagojlLFRoHWBywqqkB1k%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;1242&quot; height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;/div&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;UI와 서버상태를 비동기로 운영한다고 봐도 무방.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8EepT/btqZfhQsUhZ/1wQuk9gtfd3sXzefYRWKbk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8EepT/btqZfhQsUhZ/1wQuk9gtfd3sXzefYRWKbk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8EepT/btqZfhQsUhZ/1wQuk9gtfd3sXzefYRWKbk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/b8EepT/btqZfhQsUhZ/1wQuk9gtfd3sXzefYRWKbk/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;557&quot; height=&quot;306&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;306&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://uxdesign.cc/the-optimistic-ui-with-react-f1420e317d54&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;optimistic&amp;nbsp;UI&amp;nbsp;with&amp;nbsp;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@_erikaybar/optimistic-ui-updates-in-react-9e139ffa2e45&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimistic&amp;nbsp;UI&amp;nbsp;Updates&amp;nbsp;in&amp;nbsp;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.athiemann.net/2015/07/26/optimistic-ui-elm.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimistic&amp;nbsp;UI&amp;nbsp;and&amp;nbsp;Reactive&amp;nbsp;Programming&amp;nbsp;with&amp;nbsp;Elm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://github.com/mamal72/react-optimistic-ui-hook&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-optimistic-ui-hook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;따라서 이것역시 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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;116&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3m6WB/btqZjv8fxVV/k7qw5XY4w9FGthIqwZqrn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3m6WB/btqZjv8fxVV/k7qw5XY4w9FGthIqwZqrn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3m6WB/btqZjv8fxVV/k7qw5XY4w9FGthIqwZqrn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3m6WB%2FbtqZjv8fxVV%2Fk7qw5XY4w9FGthIqwZqrn1%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;600&quot; height=&quot;116&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;116&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HXTNG/btqZegYysA0/PnPYbwd6eGUcbKId9zBxPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HXTNG/btqZegYysA0/PnPYbwd6eGUcbKId9zBxPK/img.png&quot; data-origin-width=&quot;284&quot; data-origin-height=&quot;218&quot; style=&quot;width: 67.6048%; margin-right: 10px;&quot; data-widthpercent=&quot;68.4&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HXTNG/btqZegYysA0/PnPYbwd6eGUcbKId9zBxPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHXTNG%2FbtqZegYysA0%2FPnPYbwd6eGUcbKId9zBxPK%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;284&quot; height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XNsY7/btqZlPFaFjT/kkkRNNEl7UwI3ajmvU0iuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XNsY7/btqZlPFaFjT/kkkRNNEl7UwI3ajmvU0iuK/img.png&quot; data-origin-width=&quot;130&quot; data-origin-height=&quot;216&quot; style=&quot;width: 31.2324%;&quot; data-widthpercent=&quot;31.6&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XNsY7/btqZlPFaFjT/kkkRNNEl7UwI3ajmvU0iuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXNsY7%2FbtqZlPFaFjT%2FkkkRNNEl7UwI3ajmvU0iuK%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;130&quot; height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오류시에는 모달창으로 띄우거나 실패했다는 메세지를 띄울 수 있다. (UX상 후자가 좋음)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DCxsT/btqZiVe4Z7F/CKd4werxZFXCxKddieRYVk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DCxsT/btqZiVe4Z7F/CKd4werxZFXCxKddieRYVk/img.gif&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;530&quot; style=&quot;width: 36.9714%; margin-right: 10px;&quot; data-widthpercent=&quot;37.41&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DCxsT/btqZiVe4Z7F/CKd4werxZFXCxKddieRYVk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDCxsT%2FbtqZiVe4Z7F%2FCKd4werxZFXCxKddieRYVk%2Fimg.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;359&quot; height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwUdaL/btqZn1yzAVZ/KOUOJwkUnpSh3Hc2iZsS40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwUdaL/btqZn1yzAVZ/KOUOJwkUnpSh3Hc2iZsS40/img.png&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;562&quot; style=&quot;width: 61.8658%;&quot; data-widthpercent=&quot;62.59&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwUdaL/btqZn1yzAVZ/KOUOJwkUnpSh3Hc2iZsS40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwUdaL%2FbtqZn1yzAVZ%2FKOUOJwkUnpSh3Hc2iZsS40%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;637&quot; height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;/div&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;79&quot; data-origin-height=&quot;79&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OwMyk/btqZlQjMku3/HQ4dRhTVhSxH5KpkKG90v0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OwMyk/btqZlQjMku3/HQ4dRhTVhSxH5KpkKG90v0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OwMyk/btqZlQjMku3/HQ4dRhTVhSxH5KpkKG90v0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOwMyk%2FbtqZlQjMku3%2FHQ4dRhTVhSxH5KpkKG90v0%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;79&quot; height=&quot;79&quot; data-origin-width=&quot;79&quot; data-origin-height=&quot;79&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;h4 data-ke-size=&quot;size20&quot;&gt;3.3.6 피츠의 법칙과 UI/UX 개선&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Content, JS&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://en.wikipedia.org/wiki/Fitts%27s_law&quot;&gt;피츠의 법칙(Fitts's Law)&lt;/a&gt;이다. [&lt;a href=&quot;https://www.interaction-design.org/literature/book/the-glossary-of-human-computer-interaction/fitts-s-law&quot;&gt;The Glossary of Human Computer Interaction&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://story.pxd.co.kr/578&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;피츠의&amp;nbsp;법칙&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;]&lt;/p&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;widthContent&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2iUmt/btqZegdc2tp/0UBOesKGfs3Kl64hzQZYy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2iUmt/btqZegdc2tp/0UBOesKGfs3Kl64hzQZYy1/img.png&quot; data-alt=&quot;목표B에서 허용하는 너비 W와 거리 D&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2iUmt/btqZegdc2tp/0UBOesKGfs3Kl64hzQZYy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2iUmt%2FbtqZegdc2tp%2F0UBOesKGfs3Kl64hzQZYy1%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;300&quot; height=&quot;220&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;목표B에서 허용하는 너비 W와 거리 D&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연하게 느껴질 수도 있겠지만&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;너비 W는 크게&lt;/li&gt;
&lt;li&gt;거리 D는 작게&lt;/li&gt;
&lt;/ul&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 style=&quot;font-size: 1.12em;&quot; 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;a href=&quot;https://www.asktog.com/columns/022DesignedToGiveFitts.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A Quiz Designed to Give You Fitts&lt;/a&gt;(&lt;a href=&quot;https://story.pxd.co.kr/575&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZDDsu/btqZn1Fk7FI/JYPVmlfKYr9Av7p6esFVpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZDDsu/btqZn1Fk7FI/JYPVmlfKYr9Av7p6esFVpK/img.png&quot; data-origin-width=&quot;301&quot; data-origin-height=&quot;62&quot; style=&quot;width: 37.4542%; margin-right: 10px;&quot; data-widthpercent=&quot;37.89&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZDDsu/btqZn1Fk7FI/JYPVmlfKYr9Av7p6esFVpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZDDsu%2FbtqZn1Fk7FI%2FJYPVmlfKYr9Av7p6esFVpK%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;301&quot; height=&quot;62&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caX2kb/btqZdkUuHQM/uzyiTId4BjPCqIxlvEQan0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caX2kb/btqZdkUuHQM/uzyiTId4BjPCqIxlvEQan0/img.png&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;46&quot; style=&quot;width: 61.3831%;&quot; data-widthpercent=&quot;62.11&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caX2kb/btqZdkUuHQM/uzyiTId4BjPCqIxlvEQan0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaX2kb%2FbtqZdkUuHQM%2FuzyiTId4BjPCqIxlvEQan0%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;366&quot; height=&quot;46&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/uxguide/cmd-toolbars&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Windows32 Toolbars&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uBVGf/btqZhgKvGBB/mq7PvUF4txjLJ6VK2F8huK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uBVGf/btqZhgKvGBB/mq7PvUF4txjLJ6VK2F8huK/img.png&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;224&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uBVGf/btqZhgKvGBB/mq7PvUF4txjLJ6VK2F8huK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuBVGf%2FbtqZhgKvGBB%2Fmq7PvUF4txjLJ6VK2F8huK%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;736&quot; height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A4LtM/btqZn1ZEa9m/ukAfFBRCmdodAhXp0NEikk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A4LtM/btqZn1ZEa9m/ukAfFBRCmdodAhXp0NEikk/img.png&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;224&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A4LtM/btqZn1ZEa9m/ukAfFBRCmdodAhXp0NEikk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA4LtM%2FbtqZn1ZEa9m%2FukAfFBRCmdodAhXp0NEikk%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;736&quot; height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.apple.com/design/human-interface-guidelines/macos/windows-and-views/toolbars/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MacOS Toolbars&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;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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;609&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDpBOL/btqZiVsDnOr/9YjhkMLynyPUIbhhfEtcek/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDpBOL/btqZiVsDnOr/9YjhkMLynyPUIbhhfEtcek/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDpBOL/btqZiVsDnOr/9YjhkMLynyPUIbhhfEtcek/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDpBOL%2FbtqZiVsDnOr%2F9YjhkMLynyPUIbhhfEtcek%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;850&quot; height=&quot;609&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;609&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여러줄은 한줄로[&lt;/span&gt;&lt;a href=&quot;http://www.graficznie.com.pl/web-tools/10-essential-tools-tips-all-photoshop-beginners-should-learn/&quot;&gt;10&amp;nbsp;ESSENTIAL&amp;nbsp;TOOLS&amp;nbsp;&amp;amp;&amp;nbsp;TIPS&amp;nbsp;ALL&amp;nbsp;PHOTOSHOP&amp;nbsp;BEGINNERS&amp;nbsp;SHOULD&amp;nbsp;LEARN&lt;/a&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&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8daBc/btqZhgRjwKu/F3LeBVRbQgjB3M19l8Axa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8daBc/btqZhgRjwKu/F3LeBVRbQgjB3M19l8Axa1/img.png&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;996&quot; style=&quot;width: 54.2272%; margin-right: 10px;&quot; data-widthpercent=&quot;54.87&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8daBc/btqZhgRjwKu/F3LeBVRbQgjB3M19l8Axa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8daBc%2FbtqZhgRjwKu%2FF3LeBVRbQgjB3M19l8Axa1%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;830&quot; height=&quot;996&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uRSay/btqZlO7kKae/uHWi6KKgOn1n2I5VTRbANK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uRSay/btqZlO7kKae/uHWi6KKgOn1n2I5VTRbANK/img.png&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;830&quot; data-filename=&quot;blob&quot; style=&quot;width: 44.61%;&quot; data-widthpercent=&quot;45.13&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uRSay/btqZlO7kKae/uHWi6KKgOn1n2I5VTRbANK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuRSay%2FbtqZlO7kKae%2FuHWi6KKgOn1n2I5VTRbANK%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;569&quot; height=&quot;830&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;가장자리와 맞닿아있게[&lt;a href=&quot;https://community.adobe.com/t5/photoshop/reattaching-the-toolbar/td-p/9716385?page=1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reattaching The Toolbar&lt;/a&gt;, &lt;a href=&quot;https://community.adobe.com/t5/photoshop/perspective-crop-tool-missing/m-p/9673296?page=1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Perspective Crop Tool Missing&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;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;현재자리에서 바로 부를수 있는 대표적인 메뉴가 바로 컨텍스트 메뉴.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;361&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bX4kat/btqZctD636J/koEQ6nC6QAuihroEKVl5d0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bX4kat/btqZctD636J/koEQ6nC6QAuihroEKVl5d0/img.png&quot; data-alt=&quot;현재 위치의 컨텍스트 메뉴(오른쪽 클릭)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bX4kat/btqZctD636J/koEQ6nC6QAuihroEKVl5d0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbX4kat%2FbtqZctD636J%2FkoEQ6nC6QAuihroEKVl5d0%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;360&quot; data-origin-width=&quot;361&quot; data-origin-height=&quot;360&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;이를 이용한 것이 바로 윈도우 시작버튼과 KDE의 화면경계 기능.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVqxVH/btqZhe62V6V/wq6MKTsSUux4pMXWMUFXg0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVqxVH/btqZhe62V6V/wq6MKTsSUux4pMXWMUFXg0/img.jpg&quot; style=&quot;width: 34.5722%; margin-right: 10px;&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;762&quot; data-widthpercent=&quot;34.98&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVqxVH/btqZhe62V6V/wq6MKTsSUux4pMXWMUFXg0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVqxVH%2FbtqZhe62V6V%2Fwq6MKTsSUux4pMXWMUFXg0%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;800&quot; height=&quot;762&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mCcxv/btqZjv1vaHX/7lYQtozoEwH99LMSBcoxQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mCcxv/btqZjv1vaHX/7lYQtozoEwH99LMSBcoxQK/img.png&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;351&quot; style=&quot;width: 64.2651%;&quot; data-widthpercent=&quot;65.02&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mCcxv/btqZjv1vaHX/7lYQtozoEwH99LMSBcoxQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmCcxv%2FbtqZjv1vaHX%2F7lYQtozoEwH99LMSBcoxQK%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;685&quot; height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;윈도우 시작버튼과 KDE 화면경계 기능&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;잘만들어졌다고 칭찬받는 삼성 One 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;때문에 아래 사진들을 보면 하단과 가장자리 위주로 UI가 구성되어있음을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;914&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lk0C1/btqZjuO5uoc/x2IDwCZ67t7uH2lxrKfBR0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lk0C1/btqZjuO5uoc/x2IDwCZ67t7uH2lxrKfBR0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lk0C1/btqZjuO5uoc/x2IDwCZ67t7uH2lxrKfBR0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flk0C1%2FbtqZjuO5uoc%2Fx2IDwCZ67t7uH2lxrKfBR0%2Fimg.webp&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;1440&quot; height=&quot;914&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;914&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;삼성 One UI [&lt;a href=&quot;https://www.samsung.com/sec/apps/one-ui/&quot;&gt;One UI 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;&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;고정된 작업표시줄을 사용하면 수많은 아이콘에 접근할 수 있지만, 자동숨김처리된 작업표시줄을 사용하면 작업표시줄 하나를 접근하기위해 시간을 낭비해야 한다.&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;widthContent&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgFUsp/btqZjwsyMBH/0GvfF7ZhskDtixsPINvwEk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgFUsp/btqZjwsyMBH/0GvfF7ZhskDtixsPINvwEk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgFUsp/btqZjwsyMBH/0GvfF7ZhskDtixsPINvwEk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bgFUsp/btqZjwsyMBH/0GvfF7ZhskDtixsPINvwEk/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;500&quot; height=&quot;350&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;작업표시줄 헤멤 [&lt;a href=&quot;https://www.ilovefreesoftware.com/28/tutorial/how-to-hide-windows-10-taskbar-using-a-hotkey.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How To Hide Windows 10 Taskbar Using A Hotkey&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;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;항상 같은 자리에 있을 것이라는 것을 알며, 화면크기가 작을때도 접근하기 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wsGL6/btqZfhQsUMf/pXgTdTfCXgoqfM2aj21C20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wsGL6/btqZfhQsUMf/pXgTdTfCXgoqfM2aj21C20/img.png&quot; data-origin-width=&quot;1027&quot; data-origin-height=&quot;780&quot; style=&quot;width: 50.2727%; margin-right: 10px;&quot; data-widthpercent=&quot;50.86&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wsGL6/btqZfhQsUMf/pXgTdTfCXgoqfM2aj21C20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwsGL6%2FbtqZfhQsUMf%2FpXgTdTfCXgoqfM2aj21C20%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;1027&quot; height=&quot;780&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n905u/btqZn00JJWx/gHc1K5m0eLIE3OVoZQKpTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n905u/btqZn00JJWx/gHc1K5m0eLIE3OVoZQKpTk/img.png&quot; data-origin-width=&quot;1015&quot; data-origin-height=&quot;798&quot; data-filename=&quot;blob&quot; style=&quot;width: 48.5645%;&quot; data-widthpercent=&quot;49.14&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n905u/btqZn00JJWx/gHc1K5m0eLIE3OVoZQKpTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn905u%2FbtqZn00JJWx%2FgHc1K5m0eLIE3OVoZQKpTk%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;1015&quot; height=&quot;798&quot;/&gt;&lt;/span&gt;&lt;/div&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;a href=&quot;https://thomaspark.co/2011/10/making-menus-escapable/&quot;&gt;Making Menus Escapable&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&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;각도가 좁으면 객체의 너비가 줄어들기 때문.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FSb5K/btqZefZICQH/JAFKVimvVZ7mGkmo9JINik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FSb5K/btqZefZICQH/JAFKVimvVZ7mGkmo9JINik/img.png&quot; data-alt=&quot;OS X: 65도, Ubuntu: 50도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FSb5K/btqZefZICQH/JAFKVimvVZ7mGkmo9JINik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFSb5K%2FbtqZefZICQH%2FJAFKVimvVZ7mGkmo9JINik%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;595&quot; height=&quot;310&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;OS X: 65도, Ubuntu: 50도&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;/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;widthContent&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blO2e3/btqZjwe1MPN/SKAZV7TyWLmC83KBDdFKk1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blO2e3/btqZjwe1MPN/SKAZV7TyWLmC83KBDdFKk1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blO2e3/btqZjwe1MPN/SKAZV7TyWLmC83KBDdFKk1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/blO2e3/btqZjwe1MPN/SKAZV7TyWLmC83KBDdFKk1/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;520&quot; height=&quot;290&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;으아.. 화가난다..[&lt;a href=&quot;https://www.youtube.com/watch?v=lVUokjAlREs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ubuntu&amp;nbsp;Volume&amp;nbsp;Indicator&amp;nbsp;Applet&amp;nbsp;-&amp;nbsp;Maverick&amp;nbsp;(Terrible&amp;nbsp;Design!)&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;&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;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;크기 조절&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;하지만, 실제로 메뉴를 탈출하기는 어려울 수도 있다는 점은 고려대상.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NqvbF/btqZfhwbYpj/kkhvzSDOZq14NIqbECI0Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NqvbF/btqZfhwbYpj/kkhvzSDOZq14NIqbECI0Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NqvbF/btqZfhwbYpj/kkhvzSDOZq14NIqbECI0Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNqvbF%2FbtqZfhwbYpj%2FkkhvzSDOZq14NIqbECI0Xk%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;399&quot; height=&quot;350&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;350&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;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;시간과 공간의 여유&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우는 메뉴가 사라져버리는 것을 10~100ms처럼 여유시간을 두는 방식으로 해결한다. &lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;http://www.mackido.com/Interface/hysteresis.html&quot;&gt;Hysteresis&lt;/a&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무려 80년대(정확히 1986년)에 구현했었다고. [&lt;a href=&quot;https://arstechnica.com/gadgets/1999/12/macos-x-dp2/5/&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Mac&amp;nbsp;OS&amp;nbsp;X&amp;nbsp;DP2&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;http://www.quinn.echidna.id.au/Quinn/WWW/HISubtleties/HierarchicalMenus.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hierarchical&amp;nbsp;Menus&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bN5BA0/btqZehiUttn/ixZHkTQIYvjTz68nKjJ401/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bN5BA0/btqZehiUttn/ixZHkTQIYvjTz68nKjJ401/img.gif&quot; style=&quot;width: 65.769%; margin-right: 10px;&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;135&quot; data-widthpercent=&quot;66.54&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bN5BA0/btqZehiUttn/ixZHkTQIYvjTz68nKjJ401/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbN5BA0%2FbtqZehiUttn%2FixZHkTQIYvjTz68nKjJ401%2Fimg.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;358&quot; height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zFAxs/btqZhfx6qjs/uNk5kcJunwRsDGvrhOAAfk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zFAxs/btqZhfx6qjs/uNk5kcJunwRsDGvrhOAAfk/img.gif&quot; data-origin-width=&quot;368&quot; data-origin-height=&quot;276&quot; style=&quot;width: 33.0682%;&quot; data-widthpercent=&quot;33.46&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zFAxs/btqZhfx6qjs/uNk5kcJunwRsDGvrhOAAfk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzFAxs%2FbtqZhfx6qjs%2FuNk5kcJunwRsDGvrhOAAfk%2Fimg.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;276&quot;/&gt;&lt;/span&gt;&lt;/div&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: #333333;&quot;&gt;그 후, NeXT와 OS X 초기 팀이 복제에 실패해 잊혀졌다가 더 나은 방식으로 왕귀했다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;577&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oMCJ6/btqZcsrFHwV/aYWUHENJLWUKVVZIo0RDSK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oMCJ6/btqZcsrFHwV/aYWUHENJLWUKVVZIo0RDSK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oMCJ6/btqZcsrFHwV/aYWUHENJLWUKVVZIo0RDSK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/oMCJ6/btqZcsrFHwV/aYWUHENJLWUKVVZIo0RDSK/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;577&quot; height=&quot;900&quot; data-origin-width=&quot;577&quot; data-origin-height=&quot;900&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;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oeJp8/btqZiTVP7MA/73lrMp96xDwInC9hWaEIyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oeJp8/btqZiTVP7MA/73lrMp96xDwInC9hWaEIyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oeJp8/btqZiTVP7MA/73lrMp96xDwInC9hWaEIyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoeJp8%2FbtqZiTVP7MA%2F73lrMp96xDwInC9hWaEIyK%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;595&quot; height=&quot;184&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;184&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;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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3tFUv/btqZkpUhd6H/pHH52wAP2FKQR7n5BqDC0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3tFUv/btqZkpUhd6H/pHH52wAP2FKQR7n5BqDC0K/img.png&quot; data-origin-width=&quot;361&quot; data-origin-height=&quot;360&quot; style=&quot;width: 39.5775%; margin-right: 10px;&quot; data-widthpercent=&quot;40.04&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3tFUv/btqZkpUhd6H/pHH52wAP2FKQR7n5BqDC0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3tFUv%2FbtqZkpUhd6H%2FpHH52wAP2FKQR7n5BqDC0K%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;360&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LDCaU/btqZhfZcuqw/l98e2HS5mp9soVURnw5la1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LDCaU/btqZhfZcuqw/l98e2HS5mp9soVURnw5la1/img.gif&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;682&quot; style=&quot;width: 59.2597%;&quot; data-widthpercent=&quot;59.96&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LDCaU/btqZhfZcuqw/l98e2HS5mp9soVURnw5la1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLDCaU%2FbtqZhfZcuqw%2Fl98e2HS5mp9soVURnw5la1%2Fimg.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;1024&quot; height=&quot;682&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;선형 메뉴 vs 원형 메뉴[&lt;a href=&quot;https://www.drawboard.com/blog/new-in-drawboard-pdf-the-advanced-tools-drawer/&quot;&gt;New&amp;nbsp;in&amp;nbsp;Drawboard&amp;nbsp;PDF:&amp;nbsp;The&amp;nbsp;Advanced&amp;nbsp;Tools&amp;nbsp;Drawer&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;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;예를 들어 포인터를 멀리 이동시킬수록 더욱 많은 양을 움직이는 식.&lt;/p&gt;
&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;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=7rpjTiXieu8&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bpogKZ/hyFKlJadhl/B2WmxxBbu5lLWuNrN6gPKk/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360&quot; data-video-width=&quot;480&quot; data-video-height=&quot;360&quot; data-video-origin-width=&quot;undefined&quot; data-video-origin-height=&quot;undefined&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/7rpjTiXieu8&quot; width=&quot;480&quot; height=&quot;360&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biJ6H6/btqZehpDUqW/9LB9aaErORheTZoVSaLzv0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biJ6H6/btqZehpDUqW/9LB9aaErORheTZoVSaLzv0/img.gif&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;851&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biJ6H6/btqZehpDUqW/9LB9aaErORheTZoVSaLzv0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiJ6H6%2FbtqZehpDUqW%2F9LB9aaErORheTZoVSaLzv0%2Fimg.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;472&quot; height=&quot;851&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dprqru/btqZn0l8ocI/b3lNhTvckTowZnTlPWuwA1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dprqru/btqZn0l8ocI/b3lNhTvckTowZnTlPWuwA1/img.gif&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;851&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dprqru/btqZn0l8ocI/b3lNhTvckTowZnTlPWuwA1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdprqru%2FbtqZn0l8ocI%2Fb3lNhTvckTowZnTlPWuwA1%2Fimg.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;472&quot; height=&quot;851&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;관성 스크롤&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ios의 경우 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/-webkit-overflow-scrolling&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;overflow-scrolling&lt;/a&gt;을 쓰면 조절이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1587380492690&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.scroll-touch {
  -webkit-overflow-scrolling: touch; /* Lets it scroll lazy */
}

.scroll-auto {
  -webkit-overflow-scrolling: auto; /* Stops scrolling immediately */
}&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;ios에서 지원하는거라 변태 개발자들이 포팅이나 폴리필을 만들었을까봐 안드로이드나 기타 환경에서도 가능한지 여러가지를 찾아봤는데 아직 딱히 마음에 드는 것을 찾지 못했지만, 다음글은 참고할만 하다.[&lt;a href=&quot;https://medium.com/homullus/recreating-native-ios-scroll-and-momentum-2906d0d711ad&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Recreating&amp;nbsp;native&amp;nbsp;iOS&amp;nbsp;scroll&amp;nbsp;and&amp;nbsp;momentum&lt;/a&gt;, &lt;a href=&quot;https://blog.canapio.com/112&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[번역]iOS10의&amp;nbsp;프리-패칭&amp;nbsp;API로&amp;nbsp;부드러운&amp;nbsp;스크롤&amp;nbsp;증진하기&lt;/a&gt;, &lt;a href=&quot;https://bluebead38.blogspot.com/2019/04/scroll-to-future.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[번역]&amp;nbsp;미래를&amp;nbsp;향한&amp;nbsp;스크롤&amp;nbsp;(Scroll&amp;nbsp;to&amp;nbsp;the&amp;nbsp;future)&lt;/a&gt;, &lt;a href=&quot;https://blogs.windows.com/msedgedev/2020/04/02/scrolling-personality-improvements/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Scrolling personality improvements in Microsoft Edge&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;b&gt;빨아들이기&lt;/b&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oAtmZ/btqZjv1va09/BB6tVds0YRM3HzBnJQiF50/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oAtmZ/btqZjv1va09/BB6tVds0YRM3HzBnJQiF50/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oAtmZ/btqZjv1va09/BB6tVds0YRM3HzBnJQiF50/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/oAtmZ/btqZjv1va09/BB6tVds0YRM3HzBnJQiF50/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;500&quot; height=&quot;281&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;281&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;마치 에임핵처럼(&lt;a href=&quot;https://gfycat.com/ko/warygentleibex&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Aim hack?&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;모바일에서 비슷한 것을 찾으라면 패스트 스크롤(Fast Scroll)이나 사이드 인덱스바(Side Index Bar)라 불리는 물건.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 인덱스의 위치가 중력처럼 작용하여 빠르게 이동할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byOix7/btqZlPrCYRH/ZelyVHDojQaz9wHQON6LeK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byOix7/btqZlPrCYRH/ZelyVHDojQaz9wHQON6LeK/img.gif&quot; data-origin-width=&quot;375&quot; data-origin-height=&quot;812&quot; style=&quot;width: 49.3958%; margin-right: 10px;&quot; data-widthpercent=&quot;49.98&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byOix7/btqZlPrCYRH/ZelyVHDojQaz9wHQON6LeK/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyOix7%2FbtqZlPrCYRH%2FZelyVHDojQaz9wHQON6LeK%2Fimg.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;375&quot; height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kX5R6/btqZlO7kL3m/tB6GDQV4EXc3th8VyqKrvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kX5R6/btqZlO7kL3m/tB6GDQV4EXc3th8VyqKrvK/img.png&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;649&quot; style=&quot;width: 49.4414%;&quot; data-widthpercent=&quot;50.02&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kX5R6/btqZlO7kL3m/tB6GDQV4EXc3th8VyqKrvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkX5R6%2FbtqZlO7kL3m%2FtB6GDQV4EXc3th8VyqKrvK%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;300&quot; height=&quot;649&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Fast Scroll [&lt;a href=&quot;https://apps.apple.com/us/app/contacts-xt-address-book-organiser/id343594350#?platform=iphone&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Contacts XT - Address Book&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;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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bN5BA0/btqZehiUttn/ixZHkTQIYvjTz68nKjJ401/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bN5BA0/btqZehiUttn/ixZHkTQIYvjTz68nKjJ401/img.gif&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;135&quot; style=&quot;width: 53.0337%; margin-right: 10px;&quot; data-widthpercent=&quot;53.66&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bN5BA0/btqZehiUttn/ixZHkTQIYvjTz68nKjJ401/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbN5BA0%2FbtqZehiUttn%2FixZHkTQIYvjTz68nKjJ401%2Fimg.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;358&quot; height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/whx7R/btqZcskRw69/oZqdsrb9GRjBlfkIcPlUk1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/whx7R/btqZcskRw69/oZqdsrb9GRjBlfkIcPlUk1/img.gif&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;279&quot; style=&quot;width: 45.8035%;&quot; data-widthpercent=&quot;46.34&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/whx7R/btqZcskRw69/oZqdsrb9GRjBlfkIcPlUk1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwhx7R%2FbtqZcskRw69%2FoZqdsrb9GRjBlfkIcPlUk1%2Fimg.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;639&quot; height=&quot;279&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;평행하게 vs 중앙으로&lt;/figcaption&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;3.3.7 기타 응답성 개선&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;개요&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;분류: Content&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 파트에서는 기타 응답성(Respose time) 개선하는 방법들을 서술한다.&lt;span&gt; &lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://blog.radware.com/applicationdelivery/wpo/2014/07/eight-tricks-improve-perceived-web-performance/&quot;&gt;How to create the illusion of faster web pages (while also creating actual happier users)&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;span&gt;&lt;/span&gt;&lt;/span&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&gt; &lt;span style=&quot;color: #333333;&quot;&gt;CSS의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/will-change&quot;&gt;will-change&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;속성, 터치나 포인터 이벤트로 300ms 지연속도를 없애는 것은 대표적인 응답성 개선 방법이다.&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;&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;우선 중복된 부분으로는 이벤트와 API에서 다루었던 버튼에 터치 상태를 추가하여 300ms의 지연속도를 없애버리는 게 있다. [&lt;a href=&quot;https://developers.google.com/web/fundamentals/design-and-ux/input/touch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;사이트에&amp;nbsp;터치&amp;nbsp;추가&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;b&gt;- 스크롤링 응답성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 브라우저들은 파이어폭스의 Async Pan/Zoom(APZ)처럼 Off-thread 스크롤링을 지원해&amp;nbsp; 메인 쓰레드가 막히더라도 스크롤링을 지원한다. [&lt;a href=&quot;https://hacks.mozilla.org/2017/11/async-panzoom-apz-lands-in-firefox-quantum/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Async&amp;nbsp;Pan/Zoom&amp;nbsp;(APZ)&amp;nbsp;lands&amp;nbsp;in&amp;nbsp;Firefox&amp;nbsp;Quantum&lt;/a&gt;, &lt;a href=&quot;https://blogs.windows.com/msedgedev/2017/03/08/scrolling-on-the-web/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Scrolling&amp;nbsp;on&amp;nbsp;the&amp;nbsp;web:&amp;nbsp;A&amp;nbsp;primer&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;293&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cla59Z/btqZfiaNlaH/OH037k9hmBDh3LtilFfDK0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cla59Z/btqZfiaNlaH/OH037k9hmBDh3LtilFfDK0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cla59Z/btqZfiaNlaH/OH037k9hmBDh3LtilFfDK0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cla59Z/btqZfiaNlaH/OH037k9hmBDh3LtilFfDK0/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;520&quot; height=&quot;293&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;293&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?time_continue=7&amp;amp;v=3cQekz_-bDw&amp;amp;feature=emb_logodnd3Mtd2l6&amp;amp;sclient=psy-ab&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;apz&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czd0KT/btqZiU8g3W5/76ayfuHjlokwRrdJsg6Jl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czd0KT/btqZiU8g3W5/76ayfuHjlokwRrdJsg6Jl0/img.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;200&quot; style=&quot;width: 59.6161%; margin-right: 10px;&quot; data-widthpercent=&quot;60.32&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czd0KT/btqZiU8g3W5/76ayfuHjlokwRrdJsg6Jl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fczd0KT%2FbtqZiU8g3W5%2F76ayfuHjlokwRrdJsg6Jl0%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;500&quot; height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kGpEN/btqZhgKvHjX/k1euGCjQXTBtUKPfNi91CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kGpEN/btqZhgKvHjX/k1euGCjQXTBtUKPfNi91CK/img.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;304&quot; style=&quot;width: 39.2211%;&quot; data-widthpercent=&quot;39.68&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kGpEN/btqZhgKvHjX/k1euGCjQXTBtUKPfNi91CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkGpEN%2FbtqZhgKvHjX%2Fk1euGCjQXTBtUKPfNi91CK%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;500&quot; height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;/div&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;이 기술의 파워를 알 수 있는 데모를 2가지 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://bl.ocks.org/nolanlawson/raw/dc026a93b91cb448401bb0f1cb3ebad2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Demo of page janking&lt;/a&gt;(버튼을 누르면 메인쓰레드를 5초간 차단)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://staktrace.com/resources/extras/spout/scroll-behavior.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Scroll-Behavior&lt;/a&gt;(500ms 간격으로 차단)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Off-thread 스크롤링을 지원하는 브라우저라면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째 페이지의 &quot;Junk me!&quot;를 누르고 스크롤링을 하거나 두번째 페이지에서 그냥 스크롤링을 할 때 부드러움을 느낄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 Off-thread 스크롤링을 지원하지 않은 키보드 입력의 방향기를 사용하면 작동이 안되거나(1번째), 끊김이 심함(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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CSS 활용&lt;/b&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;여기서는 모질라에서 공개한 문서에서 알려주는 예제를 기반으로 살펴도록 하자. [&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Scroll-linked_effects&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Scroll-linked&amp;nbsp;effects&lt;/a&gt;, &lt;a href=&quot;https://staktrace.com/spout/entry.php?id=834&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Asynchronous&amp;nbsp;scrolling&amp;nbsp;in&amp;nbsp;Firefox&lt;/a&gt;, &lt;a href=&quot;https://lexoral.com/blog/you-dont-need-js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;5&amp;nbsp;things&amp;nbsp;you&amp;nbsp;don't&amp;nbsp;need&amp;nbsp;Javascript&amp;nbsp;for&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior&quot;&gt;scroll-behavior&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;를 smooth로 설정하면 항목끼리 부드럽게 움직일 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 Scroll-Behavior의 Scroll up과 Scroll down 버튼을 눌러보면 알겠지만, 위아래로 부드럽게 움직인다.&lt;/p&gt;
&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://developer.mozilla.org/en-US/docs/Web/CSS/position#Sticky_positioning&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;posion&lt;/a&gt;을 어느 상한선에서 고정시키는 sticky.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밑의 예제에서 스크롤시 Javascipt로 제작한 것은 깜박이고, 버벅이고 난리를 치나 CSS는 고고하게 자리를 지킨다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://staktrace.com/resources/extras/spout/position-sticky.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;position-sticky&lt;/a&gt;(역시 500ms 간격으로 차단)&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Scroll Snap&lt;/a&gt;을 이용하면 CSS만으로 한화면씩 전환하는 테크닉을 만들 수 있다.&amp;nbsp; [&lt;a href=&quot;https://css-tricks.com/practical-css-scroll-snapping/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Practical&amp;nbsp;CSS&amp;nbsp;Scroll&amp;nbsp;Snapping&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/updates/2018/07/css-scroll-snap&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Well-Controlled&amp;nbsp;Scrolling&amp;nbsp;with&amp;nbsp;CSS&amp;nbsp;Scroll&amp;nbsp;Snap&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqj0AN/btqZhfrlhch/3nI8UVFmt1xcn7k38OU791/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqj0AN/btqZhfrlhch/3nI8UVFmt1xcn7k38OU791/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqj0AN/btqZhfrlhch/3nI8UVFmt1xcn7k38OU791/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dqj0AN/btqZhfrlhch/3nI8UVFmt1xcn7k38OU791/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;1024&quot; height=&quot;686&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Snap (&lt;a href=&quot;https://codepen.io/black7375/pen/WNQowPY&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Javascript&lt;/a&gt;, &lt;a href=&quot;https://codepen.io/black7375/pen/gOaLrVz&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pure CSS&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/demos/scroll-snap/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;The scroll-snap-* Properties.&lt;/span&gt;&lt;/a&gt;&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;마지막으로 시차(parallax)를 두고 스크롤링을 하는 것인데 화려한 사이트에서 곧잘 볼 수 있다. [&lt;a href=&quot;https://keithclark.co.uk/articles/practical-css-parallax/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Practical&amp;nbsp;CSS&amp;nbsp;Parallax&lt;/a&gt;, &lt;a href=&quot;https://www.hyungjoo.me/parallax-scroll-%EC%9B%90%EB%A6%AC/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;로만&amp;nbsp;구현한&amp;nbsp;Parallax&amp;nbsp;Scroll&amp;nbsp;원리&amp;nbsp;메모&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현이 살짝 복잡해지기 때문에 위 사이트들을 확인바란다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHYZcr/btqZn0Gq2wR/livFqqG8thmkXkcZZmaOnk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHYZcr/btqZn0Gq2wR/livFqqG8thmkXkcZZmaOnk/img.gif&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;600&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHYZcr/btqZn0Gq2wR/livFqqG8thmkXkcZZmaOnk/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHYZcr%2FbtqZn0Gq2wR%2FlivFqqG8thmkXkcZZmaOnk%2Fimg.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;800&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PlZzW/btqZkqlqjgl/locxroWkEj1hpCzwwyBh10/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PlZzW/btqZkqlqjgl/locxroWkEj1hpCzwwyBh10/img.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;300&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PlZzW/btqZkqlqjgl/locxroWkEj1hpCzwwyBh10/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPlZzW%2FbtqZkqlqjgl%2FlocxroWkEj1hpCzwwyBh10%2Fimg.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;400&quot; height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dribbble.com/shots/5863059-CSS-mix-blend-mode-Awesome-parallax-scrolling&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS mix-blend-mode &amp;amp; Awesome parallax scrolling&lt;/a&gt;, &lt;a href=&quot;http://thewaterbear.com/pure-css-landscape-parallax/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Landscape parallax using CSS&lt;/a&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;a href=&quot;https://keithclark.co.uk/articles/pure-css-parallax-websites/demo3/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A grouped pure CSS parallax demo by Keith Clark&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크의 코드들이나 리스트에 있는 링크의 Debug 버튼을 눌러보면 원리를 이해하는데 커다란 도움이 되리라 확신한다.&lt;/p&gt;
&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF8JTK/btqZiUUI5w2/KhS3ecQ8Vy0r6CCKPuDW0k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF8JTK/btqZiUUI5w2/KhS3ecQ8Vy0r6CCKPuDW0k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF8JTK/btqZiUUI5w2/KhS3ecQ8Vy0r6CCKPuDW0k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF8JTK%2FbtqZiUUI5w2%2FKhS3ecQ8Vy0r6CCKPuDW0k%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&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://developer.mozilla.org/ko/docs/Web/API/Event/preventDefault&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;event.preventDefault&lt;/a&gt;와 같은 패턴이 들어갈 수 있다. [&lt;a href=&quot;https://medium.com/@khwsc1/event-preventdefault-%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%B7%A8%EC%86%8C-%EB%B0%A9%EB%B2%95-71d1343baac&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;event.preventDefault()를 활용한 이벤트 취소 방법&lt;/a&gt;, &lt;a href=&quot;https://programmingsummaries.tistory.com/313&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript에서&amp;nbsp;이벤트&amp;nbsp;전파를&amp;nbsp;중단하는&amp;nbsp;네가지&amp;nbsp;방법&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 body 영역 모두에서 이벤트가 취소가 되버리는 불상사가 일어날 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1587486419683&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.body.addEventListener('touchstart', event =&amp;gt; {  
    if (event.target === area) {
        event.preventDefault();
    }
});&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UByfR/btqZcsFeLnx/42TTUBtqV98kxR6iduN9z0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UByfR/btqZcsFeLnx/42TTUBtqV98kxR6iduN9z0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UByfR/btqZcsFeLnx/42TTUBtqV98kxR6iduN9z0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/UByfR/btqZcsFeLnx/42TTUBtqV98kxR6iduN9z0/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;704&quot; height=&quot;612&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;612&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rbyers.github.io/scroll-latency.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Scroll&amp;nbsp;jank&amp;nbsp;due&amp;nbsp;to&amp;nbsp;touch/wheel&amp;nbsp;handlers&amp;nbsp;demo&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;이는 passive 속성을 true로 바꾸면 preventDefault를 호출하지 않아 성능개선이 가능하다.&amp;nbsp; &lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Improving_scrolling_performance_with_passive_listeners&quot;&gt;Improving&amp;nbsp;scrolling&amp;nbsp;performance&amp;nbsp;with&amp;nbsp;passive&amp;nbsp;listeners&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/audits/passive-event-listeners?hl=ko&quot;&gt;스크롤&amp;nbsp;성능&amp;nbsp;개선을&amp;nbsp;위해&amp;nbsp;패시브&amp;nbsp;이벤트&amp;nbsp;리스너를&amp;nbsp;사용하는&amp;nbsp;사이트&lt;/a&gt;, &lt;a href=&quot;https://amati.io/eventlisteneroptions-passive-true/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;{&amp;nbsp;passive:true&amp;nbsp;}&amp;nbsp;의&amp;nbsp;진정한&amp;nbsp;의미&lt;/a&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;pre id=&quot;code_1587489286335&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.body.addEventListener('touchstart', event =&amp;gt; {  
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});&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;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=65VMej8n23A&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/Mo3kv/hyFLLgoB7H/bOiRvQkbRKEZkR9c44samK/img.jpg?width=640&amp;amp;height=480&amp;amp;face=0_0_640_480&quot; data-video-width=&quot;640&quot; data-video-height=&quot;480&quot; data-video-origin-width=&quot;undefined&quot; data-video-origin-height=&quot;undefined&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/65VMej8n23A&quot; width=&quot;640&quot; height=&quot;480&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&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;만약 preventDefault를 쓰고 싶다면 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Event/cancelable&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;event.cancelable&lt;/a&gt;로 취소가 가능한지 확인해보거나&lt;/p&gt;
&lt;pre id=&quot;code_1587491044167&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.body.addEventListener('pointermove', event =&amp;gt; {  
    if (event.cancelable) {
        event.preventDefault(); // block the native scroll
        /*
        *  do what you want the application to do here
        */
    }
}, {passive: true});&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;touch-action&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;pointer-events&lt;/a&gt;와 같은 CSS로 이벤트 핸들러를 제한할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1587491209227&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#area {
  touch-action: pan-x;
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MDN의 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pointer Events&lt;/a&gt;를 읽다보면 스크롤 차단을 피할 수 있게 만들어졌다고 나온다!! [&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events/Using_Pointer_Events&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Using Pointer Events&lt;/a&gt;, &lt;a href=&quot;https://blogs.windows.com/msedgedev/2017/12/07/better-precision-touchpad-experience-ptp-pointer-events/&quot;&gt;Building&amp;nbsp;a&amp;nbsp;great&amp;nbsp;touchpad&amp;nbsp;experience&amp;nbsp;for&amp;nbsp;the&amp;nbsp;web&amp;nbsp;with&amp;nbsp;Pointer&amp;nbsp;Events&lt;/a&gt;]&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Pointer capture allows events for a particular&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent&quot;&gt;pointer event&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;to be re-targeted to a particular element instead of the normal&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#term_hit_test&quot;&gt;hit test&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;at a pointer's location. This can be used to ensure that an element continues to receive pointer events even if the pointer device's contact moves off the element (for example by scrolling).&lt;/span&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; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkHZMX/btqZefSTjgD/9EgRp8KktdPv3LSBhPkTiK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkHZMX/btqZefSTjgD/9EgRp8KktdPv3LSBhPkTiK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkHZMX/btqZefSTjgD/9EgRp8KktdPv3LSBhPkTiK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bkHZMX/btqZefSTjgD/9EgRp8KktdPv3LSBhPkTiK/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;250&quot; height=&quot;450&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gfycat.com/ko/exaltedfaroffanura&quot;&gt;Comparison&amp;nbsp;of&amp;nbsp;Pointer&amp;nbsp;and&amp;nbsp;Touch&amp;nbsp;Event&amp;nbsp;Scroll&amp;nbsp;Initiation&amp;nbsp;GIF&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;requestAnimationFrame 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 핸들러는 request AnimationFrame 콜백 직전에 실행되며, 이때 스타일을 변경하면 강제동기 레이아웃이 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOPeVC/btqZefMcF06/oKshbmEZkjj0i0DMVXLot1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOPeVC/btqZefMcF06/oKshbmEZkjj0i0DMVXLot1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOPeVC/btqZefMcF06/oKshbmEZkjj0i0DMVXLot1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOPeVC%2FbtqZefMcF06%2FoKshbmEZkjj0i0DMVXLot1%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;1280&quot; height=&quot;517&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;517&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://velog.io/@decody/JS-%EC%A7%80%EC%97%B0%EC%B2%98%EB%A6%AC-%EB%94%94%EB%B0%94%EC%9A%B4%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A1%9C%ED%8B%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JS&amp;nbsp;지연처리:&amp;nbsp;디바운스와&amp;nbsp;스로틀&lt;/a&gt;, &lt;a href=&quot;https://moonspam.github.io/Throttle-and-Debounce/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스로틀(throttle)과 디바운스(debounce)&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1587488088211&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function onScroll (evt) {

  // Store the scroll value for laterz.
  lastScrollY = window.scrollY;

  // Prevent multiple rAF callbacks.
  if (scheduledAnimationFrame)
    return;

  scheduledAnimationFrame = true;
  requestAnimationFrame(readAndUpdatePage);
}

window.addEventListener('scroll', onScroll);&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;
&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;a href=&quot;https://story.pxd.co.kr/655&quot;&gt;아마존의 메가 드롭다운 메뉴 분석&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더보고 말것도 없다. 일단 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bftqaS/btqZn1L6Tbm/X1fAP9D0X91ZG7vAp6qI60/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bftqaS/btqZn1L6Tbm/X1fAP9D0X91ZG7vAp6qI60/img.gif&quot; style=&quot;width: 54.3378%; margin-right: 10px;&quot; width=&quot;447&quot; height=&quot;313&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;313&quot; data-widthpercent=&quot;54.98&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bftqaS/btqZn1L6Tbm/X1fAP9D0X91ZG7vAp6qI60/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbftqaS%2FbtqZn1L6Tbm%2FX1fAP9D0X91ZG7vAp6qI60%2Fimg.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;447&quot; height=&quot;313&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q51lM/btqZiUf9Ytd/gR20HyJnroQ2NoATieJxh0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q51lM/btqZiUf9Ytd/gR20HyJnroQ2NoATieJxh0/img.gif&quot; style=&quot;width: 44.499397167075664%;&quot; width=&quot;407&quot; height=&quot;348&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;348&quot; data-widthpercent=&quot;45.02&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q51lM/btqZiUf9Ytd/gR20HyJnroQ2NoATieJxh0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq51lM%2FbtqZiUf9Ytd%2FgR20HyJnroQ2NoATieJxh0%2Fimg.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;407&quot; height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/div&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;/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;/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;widthContent&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRxqNE/btqZn0l8pZN/oGtpP0Kwkq0Lk0wrX5ONYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRxqNE/btqZn0l8pZN/oGtpP0Kwkq0Lk0wrX5ONYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRxqNE/btqZn0l8pZN/oGtpP0Kwkq0Lk0wrX5ONYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRxqNE%2FbtqZn0l8pZN%2FoGtpP0Kwkq0Lk0wrX5ONYk%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;415&quot; height=&quot;398&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;398&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;지금까지 본 UX 트릭중 가장 감동받은 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇년전 이 글 때문에 UX에 관심을 가지게 되었다.&lt;/p&gt;
&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/kamens/jQuery-menu-aim&quot;&gt;jQuery-menu-aim&lt;/a&gt;(&lt;a href=&quot;https://rawgit.com/kamens/jQuery-menu-aim/master/example/example.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Demo&lt;/a&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;a href=&quot;https://github.com/yuanqing/menu-aim&quot;&gt;menu-aim&lt;/a&gt;(port to vanilla): &lt;a href=&quot;https://codepen.io/lyuanqing/pen/paLgwN&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jasonslyvia/react-menu-aim&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ReactMenuAim&lt;/a&gt;(port to react): &lt;a href=&quot;https://jasonslyvia.github.io/react-menu-aim/demo/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gabrielbull/react-aim&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Aim&lt;/a&gt;:&amp;nbsp; &lt;a href=&quot;https://gabrielbull.github.io/react-aim/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rajesh1158/amazon-like-multi-dropdown-responsive-menu&quot;&gt;Amazon-like&amp;nbsp;Multi&amp;nbsp;Level&amp;nbsp;Responsive&amp;nbsp;Dropdown&amp;nbsp;Menu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/lizlux/bf82423cb04aea4de676fcec1beffa78&quot;&gt;typescript-menu-aim&lt;/a&gt;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://mlaursen.github.io/react-dd-menu/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Dropdown Menu Example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://neocoast.github.io/vue-cascader-select/guide/basic_usage.html#props&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue Cacader Select&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cssscript.com/demo/multi-level-dropdown-menu-pure-javascript-tidy-menu/#&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;tidy-menu Demos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://superfish.joelbirch.design/examples/#a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Superfish Examples&lt;/a&gt;&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;CSS로만 멀티레벨 메뉴를 구현해도 빠르긴 하지만&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://phppot.com/demo/multilevel-dropdown-menu-with-pure-css/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Demo&amp;nbsp;Multilevel&amp;nbsp;Dropdown&amp;nbsp;Menu&amp;nbsp;with&amp;nbsp;Pure&amp;nbsp;CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/design8383/pen/GEcBn&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Infinite Multilevel Dropdown&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;범위를 벗어나면 꺼져버리니 느린것만 못한 UX.&lt;/p&gt;
&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;widthContent&quot; data-filename=&quot;doc_2020-04-20_23-01-00.gif&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;694&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byyRUR/btqZctc4Q5v/vdhCf5ejThQTPztxArH3a0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byyRUR/btqZctc4Q5v/vdhCf5ejThQTPztxArH3a0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byyRUR/btqZctc4Q5v/vdhCf5ejThQTPztxArH3a0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/byyRUR/btqZctc4Q5v/vdhCf5ejThQTPztxArH3a0/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;1474&quot; height=&quot;694&quot; data-filename=&quot;doc_2020-04-20_23-01-00.gif&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;694&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.coupang.com/&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;최근에는 KDE에도 적용되었다. [&lt;a href=&quot;https://bugs.kde.org/show_bug.cgi?id=434904&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Implement&amp;nbsp;a&amp;nbsp;triangle&amp;nbsp;menu&amp;nbsp;filter&amp;nbsp;for&amp;nbsp;Kickoff's&amp;nbsp;categories&amp;nbsp;sidebar&lt;/a&gt;, &lt;a href=&quot;https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/741&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introduce&amp;nbsp;TriangleMouseFilter&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUx0l6/btq5vfFFb1f/FK5uXkkTXlvhEsGHto8lkk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUx0l6/btq5vfFFb1f/FK5uXkkTXlvhEsGHto8lkk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUx0l6/btq5vfFFb1f/FK5uXkkTXlvhEsGHto8lkk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dUx0l6/btq5vfFFb1f/FK5uXkkTXlvhEsGHto8lkk/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;940&quot; height=&quot;624&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;624&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;b&gt;+.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답성에 관련된 글을 찾다보니 재귀적인 setTimeout을 이용한 기법이 나오는데 현대 브라우저 기준으론&amp;nbsp;비효율적인 아이디어라 생각한다. [&lt;a href=&quot;https://m.blog.naver.com/PostView.nhn?blogId=tmondev&amp;amp;logNo=220928561593&amp;amp;proxyReferer=https:%2F%2Fm.facebook.com%2Ftmondev%2Fposts%2F648941921975454&quot;&gt;응답없는&amp;nbsp;페이지가&amp;nbsp;되지&amp;nbsp;않게&amp;nbsp;하는&amp;nbsp;법&amp;nbsp;(feat.&amp;nbsp;setTimeout)&lt;/a&gt;, &lt;a href=&quot;https://github.com/Lee-hyuna/33-js-concepts-kr/wiki/Scheduling:-setTimeout-and-setInterval&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스케쥴링:&amp;nbsp;setTimeout&amp;nbsp;and&amp;nbsp;setInterval&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbSMcM/btqZfihCtBe/Z6fVX29xqqXmT2g6CA27QK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbSMcM/btqZfihCtBe/Z6fVX29xqqXmT2g6CA27QK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbSMcM/btqZfihCtBe/Z6fVX29xqqXmT2g6CA27QK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbSMcM%2FbtqZfihCtBe%2FZ6fVX29xqqXmT2g6CA27QK%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;553&quot; height=&quot;178&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1587549177727&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let i = 1;
setTimeout(function run() {
  func(i);
  setTimeout(run, 100);
}, 100);&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;오래 걸리는 작업은 워커 쓰레드를 이용해처리하고 메인쓰레드에서 꼭 유지시킬 필요가 있다면 requestIdleCallback을 사용하는게 낫다고 본다.&lt;/p&gt;
&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;Timer Resolution이 윈도우(15ms), 리눅스(10ms)정도가 되며,&amp;nbsp; 브라우저에서 setTimeout(4ms)와 setInterval(10ms)의 각지연이 더 필요하다.&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[&lt;/span&gt;&lt;a href=&quot;https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/&quot;&gt;Windows&amp;nbsp;Timer&amp;nbsp;Resolution:&amp;nbsp;Megawatts&amp;nbsp;Wasted&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://elinux.org/High_Resolution_Timers&quot;&gt;High&amp;nbsp;Resolution&amp;nbsp;Timers&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://humanwhocodes.com/blog/2011/12/14/timer-resolution-in-browsers/&quot;&gt;Timer&amp;nbsp;resolution&amp;nbsp;in&amp;nbsp;browsers&lt;/a&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;약 25(15 + 10)ms&lt;/span&gt;보다 짧은 간격을 사용하는 것은 권장하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 25ms만에 끝날작업은 애초에 응답성 향상을 위해 재귀적 setTimeout을 이용한 기법을 사용할 이유가 없으며, 커다란 작업을 하기에는 타이머가 너무 빈번히 일어난다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;250ms나 500ms 정도로 넉넉하게 간격을 두고 처리하고, 타이머를 여러개 설정해버려서 경쟁하지 않도록 하는 것이 좋을 듯.&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <category>성능</category>
      <category>웹</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/80</guid>
      <comments>https://black7375.tistory.com/80#entry80comment</comments>
      <pubDate>Sun, 14 Feb 2021 18:25:37 +0900</pubDate>
    </item>
    <item>
      <title>[스압/데이터주의] 웹 최적화 방식 모음 - 3. Layout 및 렌더링</title>
      <link>https://black7375.tistory.com/79</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/72&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 0. 전반적 원칙과 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/73&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 1. 다운로드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/74&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 2. 파싱 및 렌더링 트리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/79&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3. Layout 및 렌더링(현재)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/80&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3.3 UX 트릭&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/81&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 4. 로드 후&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/82&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 5. 빌드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Layout 및 렌더링&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Layout &lt;b&gt;발생 빈도 최소화&lt;/b&gt;&amp;nbsp;및 비용 최소화와 &lt;span style=&quot;color: #333333;&quot;&gt;CPU &lt;b&gt;처리 효율화&lt;/b&gt;, &lt;b&gt;UX 트릭&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: #333333;&quot;&gt;레이아웃에 영향을 미치는 것들에 대한 정리는 &lt;a href=&quot;https://gist.github.com/paulirish/5d52fb081b3570c81e3a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What forces layout/reflow&lt;/a&gt;란 글이 잘 설명해준다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 발생 빈도 최소화&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1.1 CSS 속성&lt;/h4&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;span&gt; &lt;/span&gt;CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이야기가 나온김에 리플로우에 영향을 미치는 유명한 CSS 요소들을 뽑아보자면 [&lt;a href=&quot;https://csstriggers.com/&quot;&gt;CSS Triggers&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.sitepoint.com/optimizing-css-performance/&quot;&gt;20&amp;nbsp;Tips&amp;nbsp;for&amp;nbsp;Optimizing&amp;nbsp;CSS&amp;nbsp;Performance&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&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;창 크기 조정&lt;/li&gt;
&lt;li&gt;폰트 변경&lt;/li&gt;
&lt;li&gt;CSS 추가와 삭제&lt;/li&gt;
&lt;li&gt;input 에 입력시 내용 변경&lt;/li&gt;
&lt;li&gt;CSS&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/Pseudo-classes&quot;&gt;가상 클래스&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;활성화&lt;/li&gt;
&lt;li&gt;클래스 속성, 스타일 속성과 DOM 조작&lt;/li&gt;
&lt;li&gt;offsetWidth, offsetHeight 계산&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;border-radius&lt;/li&gt;
&lt;li&gt;box-shadow&lt;/li&gt;
&lt;li&gt;opacity&lt;/li&gt;
&lt;li&gt;transform&lt;/li&gt;
&lt;li&gt;filter&lt;/li&gt;
&lt;li&gt;position: fixed&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;보통 JS-리플로우(Layout)-페인트-컴포지터의 과정으로 렌더링이 되기 때문에 동일한 동작을 수행시&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;background-repeat&lt;/li&gt;
&lt;li&gt;각종 그라디언트&lt;/li&gt;
&lt;/ul&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;a href=&quot;https://amp.dev/ko/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMP&lt;/a&gt;나 &lt;a href=&quot;https://cobalt.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cobalt&lt;/a&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;a href=&quot;https://amp.dev/ko/documentation/guides-and-tutorials/learn/spec/amphtml/?format=websites&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMP HTML 사양&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amp.dev/ko/documentation/guides-and-tutorials/develop/style_and_layout/style_pages/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMP Supported CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cobalt.dev/development/reference/supported-features.html#html-elements&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cobalt&amp;nbsp;Support&amp;nbsp;Quick&amp;nbsp;Reference&lt;/a&gt;&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;b&gt;++.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS를 동적으로 수정해야 할 일이 있다면 직접 CSS 속성을 제어하기보다는&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;CSS 이미지 교체 관련 기술 [&lt;a href=&quot;https://css-tricks.com/css-image-replacement/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nine&amp;nbsp;Techniques&amp;nbsp;for&amp;nbsp;CSS&amp;nbsp;Image&amp;nbsp;Replacement&lt;/a&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;3.1.2 DOM 액세스 최소화&lt;/h4&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;DOM 모델에 대한 글들을 읽어보자&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@yejineee/DOM%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-DOM-Node%EC%99%80-Element%EC%9D%98-%EC%B0%A8%EC%9D%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DOM은&amp;nbsp;무엇인가?&amp;nbsp;DOM&amp;nbsp;Node와&amp;nbsp;Element의&amp;nbsp;차이&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://poiemaweb.com/js-dom&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;문서&amp;nbsp;객체&amp;nbsp;모델(Document&amp;nbsp;Object&amp;nbsp;Model)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://feel5ny.github.io/2017/12/26/JS_08_1/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;8/&amp;nbsp;DOM(1)&amp;nbsp;-&amp;nbsp;노드의&amp;nbsp;계층&amp;nbsp;구조(1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://feel5ny.github.io/2017/12/27/JS_08_2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;8/ DOM(1) - 노드의 계층 구조(2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://feel5ny.github.io/2017/12/28/JS_08_4/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;8/ DOM 확장&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Javascript&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript로 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;&lt;span style=&quot;color: #333333;&quot;&gt;DOM과 관련된 영향을 고려하며 프로그래밍 해야한다.&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;부모-자식 관계: 부모 엘리먼트가 가변적인 크기를 가질 때 자식 엘리먼트의 크기를 수정하면 부모에게 영향&lt;/li&gt;
&lt;li&gt;같은 위치: 여러 엘리먼트가 인라인일때 첫 번째 엘리먼트의 크기 수정으로 나머지 엘리먼트에 영향&lt;/li&gt;
&lt;li&gt;숨겨진 엘리먼트: 숨겨진(display: none) 스타일이면 돔 조작이나 스타일 변경시에도 레이아웃, 리페인트가 생기지 않음&lt;br /&gt;visibility: hidden일 경우 리페인트는 발생하지 않아도 레이아웃은 계산&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;a href=&quot;https://www.phpied.com/dom-access-optimization/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DOM&amp;nbsp;access&amp;nbsp;optimization&lt;/a&gt;, &lt;a href=&quot;https://medium.com/naver-fe-platform/%EB%AC%B4%ED%95%9C-dom-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%B5%9C%EC%A0%81%ED%99%94-%EA%B2%BD%ED%97%98%EA%B8%B0-237e6e9088e8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;무한&amp;nbsp;DOM&amp;nbsp;렌더링&amp;nbsp;최적화&amp;nbsp;경험기&lt;/a&gt;, &lt;a href=&quot;https://abbagames.tistory.com/4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;html5 성능최적화 방법들&lt;/a&gt;, &lt;a href=&quot;https://essentialjavascript.wordpress.com/2016/08/08/dom-creation-and-manipulation-tips-and-tricks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DOM&amp;nbsp;creation&amp;nbsp;and&amp;nbsp;manipulation&amp;nbsp;tips&amp;nbsp;and&amp;nbsp;tricks&lt;/a&gt;, &lt;a href=&quot;https://dev.to/grandemayta/javascript-dom-manipulation-to-improve-performance-459a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Javascript&amp;nbsp;DOM&amp;nbsp;Manipulation&amp;nbsp;to&amp;nbsp;improve&amp;nbsp;performance&lt;/a&gt;, &lt;a href=&quot;https://codeburst.io/taming-huge-collections-of-dom-nodes-bebafdba332&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Taming huge collections of DOM nodes&lt;/a&gt;, &lt;a href=&quot;https://okky.kr/article/24368&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DHTML&amp;nbsp;속도&amp;nbsp;향상을&amp;nbsp;위한&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;팁&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DOM 연산 결과 캐싱&lt;br /&gt;접근했던 요소(element)에 대한 참조를 캐시&lt;/li&gt;
&lt;li&gt;DOM 변경 시 개별 노드단위 반복변경보다는 배칭 작업&lt;/li&gt;
&lt;li&gt;DOM 노드 변환은 오프라인에서 수행&lt;br /&gt;노드(node)는 오프라인으로 업데이트 한 다음 트리에 추가(변경노드 떼기 -&amp;gt; 연산 -&amp;gt; 붙이기)&lt;/li&gt;
&lt;li&gt;JavaScript로 레이아웃을 고정하지 않기&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;b&gt;- 강제 동기 레이아웃 및 스래싱 피하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레이아웃은 원래 비동기적이지만, 특정 속성을 읽을 때 최신 값을 계산하는 등 레이아웃이 동기적으로 발생할 때가 있다. [&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;크고 복잡한 레이아웃 및 레이아웃 스래싱 피하기&lt;/a&gt;, &lt;a href=&quot;http://wilsonpage.co.uk/preventing-layout-thrashing/&quot;&gt;Preventing 'layout thrashing&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타일 변경 후 offsetHeight나 offsetTop처럼 계산된 값을 속성으로 읽을 때가 대표적인 예.&lt;/p&gt;
&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://en.wikipedia.org/wiki/Thrashing_(computer_science)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스래싱&lt;/a&gt;[&lt;a href=&quot;http://blog.skby.net/%EC%8A%A4%EB%A0%88%EC%8B%B1-thrashing/&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DOM 트리 상위노드를 변경시 하위 노드에 영향&lt;/li&gt;
&lt;/ul&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 style=&quot;font-size: 1.12em;&quot; 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;- DOM 연산 결과 캐싱&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM에 접근하는 것을 매번 이용하는 것은 좋은 선택이 아니다.&lt;/p&gt;
&lt;pre id=&quot;code_1587029054396&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.getElementById('box').style.top = &quot;10px&quot;;
document.getElementById('box').style.left = &quot;10px&quot;;
document.getElementById('box').style.color = &quot;lightgrey&quot;;&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: #333333;&quot;&gt;어찌보면 당연하겠지만, 변수로 만들어놓으면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1587029081392&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const boxSty = document.getElementById('box').style;
boxSty.top = &quot;10px&quot;;
boxSty.left = &quot;20px&quot;;
boxSty.color = &quot;lightgrey&quot;;&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;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/HTMLCollection&quot;&gt;HTMLCollection&lt;/a&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;HTMLCollection의 여러값들에 지속적으로 접근해야 하는 경우 Array로 바꾸는 것도 고려할만 하다. [&lt;a href=&quot;https://stackoverflow.com/questions/222841/most-efficient-way-to-convert-an-htmlcollection-to-an-array&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Most&amp;nbsp;efficient&amp;nbsp;way&amp;nbsp;to&amp;nbsp;convert&amp;nbsp;an&amp;nbsp;HTMLCollection&amp;nbsp;to&amp;nbsp;an&amp;nbsp;Array&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;lodash의 &lt;a href=&quot;https://lodash.com/docs/#template&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;template()&lt;/a&gt;같은 것도 캐싱이 가능하다. [&lt;a href=&quot;https://lostechies.com/derickbailey/2012/04/10/javascript-performance-pre-compiling-and-caching-html-templates/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript&amp;nbsp;Performance:&amp;nbsp;Pre-Compiling&amp;nbsp;And&amp;nbsp;Caching&amp;nbsp;HTML&amp;nbsp;Templates&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;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;- 개별노드 변경보다 배칭 작업&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개별 노드를 반복변경하기보다 배칭(Batching, 일괄처리)을 하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니티 같은 엔진에서 잘 사용하고 있는 기법. [&lt;a href=&quot;https://docs.unity3d.com/kr/2018.4/Manual/DrawCallBatching.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;드로우 콜 배칭&lt;/a&gt;, &lt;a href=&quot;https://mgun.tistory.com/2062&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dynamic Batching이 효율적인가&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;Main UI thread를 막을 수 있기 때문.&lt;/p&gt;
&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;CSS 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 예제는 CSS를 사용해 한번에 업데이트가 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1587039148842&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const boxSty = document.getElementById('box').style;
boxSty.classList.add('boxstyles')&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1587039187537&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.boxstyles {
  top: 10px;
  left: 20px;
  color: lightgrey;
}&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;DocumentFragment 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음코드에서 appendChild(쓰기)와 getBoundingClientRect(읽기)의 최적화가 목표.&lt;/p&gt;
&lt;pre id=&quot;code_1587034193890&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function noBatch(elements) {
  elements.forEach(el =&amp;gt; {
    // This is alternating write and read
    this.parentElement.appendChild(el);
    el.getBoundingClientRect();
  });
}&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: #333333;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/DocumentFragment&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DocumentFragment&lt;/a&gt;를 사용하면 리플로우를 일으키지 않으며 처리가 가능하다. [&lt;/span&gt;&lt;a href=&quot;https://davidwalsh.name/documentfragment&quot;&gt;JavaScript&amp;nbsp;DocumentFragment&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1587038271380&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function batch(elements) {
  // First write
  const fragment = document.createFragment();
  elements.forEach(el =&amp;gt; {
    fragment.appendChild(el);
  });
  this.parentElement.appendChild(fragment);
  
  // Then read
  elements.forEach(el =&amp;gt; {
    el.getBoundingClientRect();
  });
}&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;DOM 노드 변경은 오프라인으로&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 수의 DOM을 조작해야 한다면 DocumentFragment와 마찬가지로 직접적인 돔 조작을 줄여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 생각해볼 만한 것은&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DOM에서 때어냄&lt;/li&gt;
&lt;li&gt;연산&lt;/li&gt;
&lt;li&gt;다시 붙임&lt;/li&gt;
&lt;/ol&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;jQuery의 &lt;a href=&quot;https://api.jquery.com/detach/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;detach()&lt;/a&gt;가 대표적인 예.[&lt;a href=&quot;https://www.zerocho.com/category/jQuery/post/57c3a8821efc521700a70918&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;제이쿼리 성능 향상하기(performance)&lt;/a&gt;, &lt;a href=&quot;http://www.devkuma.com/books/pages/385&quot;&gt;다른 삭제와 비교&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바닐라의 경우 &lt;a href=&quot;https://gist.github.com/cowboy/938767&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ba-detach.js&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;뭐 사실, GTK의&lt;a href=&quot;https://developer.gnome.org/pygtk/stable/class-gdkpixmap.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; Pixmap&lt;/a&gt;(페인트가 필요 없음)과 &lt;a href=&quot;https://developer.gnome.org/pygtk/stable/class-gdkpixbuf.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pixbuf&lt;/a&gt;(X11 서버에 접근 불필요) 같은 것을 보면 새로운 개념은 아닌듯 하다.&lt;/p&gt;
&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;&lt;span style=&quot;color: #333333;&quot;&gt;offsetWidth처럼 강제 동기 레이아웃 속성들은 되도록 사용하지 않는 것이 좋다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;순서변경&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다음 코드는 box의 너비(Width)를 기록하기 위한 코드이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1587017147005&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Schedule our function to run at the start of the frame.
requestAnimationFrame(logBoxWidth);

function logBoxWidth() {
  box.classList.add('super-big');

  // Gets the width of the box in pixels
  // and logs it out.
  console.log(box.offsetWidth);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면 높이를 요청하기 전에 box의 클래스를 바꾸었기 때문에 스타일 변경이 적용되어 있어야 하는 상황.&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_1587017111976&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function logBoxWidth() {
  // Gets the width of the box in pixels
  // and logs it out.
  console.log(box.offsetWidth);

  box.classList.add('super-big');
}&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;변수로 선언&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 offsetWidth를 호출하면 스래싱이 생겨서 성능이 확 줄어든다.&lt;/p&gt;
&lt;pre id=&quot;code_1587016053342&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function resizeAllParagraphs() {
  for (let i = 0; i &amp;lt; paragraphs.length; i += 1) {
    paragraphs[i].style.width = box.offsetWidth + 'px';
  }
}&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;pre id=&quot;code_1587026181623&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function resizeAllParagraphs() {
  const width = box.offsetWidth;

  for (let i = 0; i &amp;lt; paragraphs.length; i += 1) {
    paragraphs[i].style.width = width + 'px';
  }
}&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;추가 및 innerHTML&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;innerHTML과 성능에 관한 글들이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://medium.com/codex/what-is-faster-to-insert-into-dom-html-or-dom-nodes-ff11586f8570&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What is faster to insert into DOM - HTML or DOM nodes?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.naver.com/loudon23/30061435593&quot;&gt;innerHTML로 html 작성 속도&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://firejune.com/1174/2012&quot;&gt;innerHTML의&amp;nbsp;속도가&amp;nbsp;만족스럽지&amp;nbsp;않을&amp;nbsp;때&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@kevinchi118/innerhtml-vs-createelement-appendchild-3da39275a694&quot;&gt;innerHTML&amp;nbsp;vs&amp;nbsp;createElement/appendChild&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.javascripttutorial.net/javascript-dom/javascript-innerhtml-vs-createelement/&quot;&gt;JavaScript&amp;nbsp;innerHTML&amp;nbsp;vs&amp;nbsp;createElement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/42135466/which-method-is-better-faster-for-performance-createelement-or-innerhtml&quot;&gt;Which&amp;nbsp;method&amp;nbsp;is&amp;nbsp;better/&amp;nbsp;faster&amp;nbsp;for&amp;nbsp;performance&amp;nbsp;-&amp;nbsp;createElement&amp;nbsp;or&amp;nbsp;innerHTML?&amp;nbsp;[duplicate]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/jeannienguyen/insertadjacenthtml-vs-innerhtml-4epd&quot;&gt;insertAdjacentHTML&amp;nbsp;vs&amp;nbsp;innerHTML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hacks.mozilla.org/2011/11/insertadjacenthtml-enables-faster-html-snippet-injection/&quot;&gt;insertAdjacentHTML()&amp;nbsp;Enables&amp;nbsp;Faster&amp;nbsp;HTML&amp;nbsp;Snippet&amp;nbsp;Injection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전반적으로 insertAdjacentHTML이 빠른듯&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://rusingh.com/javascript-benchmark-removechild-vs-innerhtml/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;is&amp;nbsp;removeChild&amp;nbsp;faster&amp;nbsp;than&amp;nbsp;innerHTML&amp;nbsp;given&amp;nbsp;thousands&amp;nbsp;of&amp;nbsp;DOM&amp;nbsp;elements?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/2298927/what-is-the-fastest-way-to-remove-child-elements-from-the-dom-in-ie/8998764&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What&amp;nbsp;is&amp;nbsp;the&amp;nbsp;fastest&amp;nbsp;way&amp;nbsp;to&amp;nbsp;remove&amp;nbsp;child&amp;nbsp;elements&amp;nbsp;from&amp;nbsp;the&amp;nbsp;DOM&amp;nbsp;in&amp;nbsp;IE?&lt;/a&gt;&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;b&gt;탐색&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM 탐색 관련 글. 역시 유의점은 같음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://paul.kinlan.me/dom-treewalker/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TreeWalker&lt;/a&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;a href=&quot;https://stackoverflow.com/questions/64551229/queryselectorall-vs-nodeiterator-vs-treewalker-fastest-pure-js-flat-dom-iterat&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;querySelectorAll vs NodeIterator vs TreeWalker - fastest pure JS flat DOM iterator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@knidarkness/javascript-dom-access-methods-speed-benchmark-64bb6fd4f8a6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Javascript DOM access methods speed benchmark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/sindresorhus/1989724&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TreeWalker Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://paul.kinlan.me/dom-treewalker/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dom TreeWalker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WD-DOM-Level-2/traversal.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Document Object Model Traversal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/hidden&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Document.hidden&lt;/a&gt; 여부에 따라 비용이 많이드는 로직은 실행하지 않을 수 있다. [&lt;a href=&quot;https://www.juxt.pro/blog/clojurescript-app-performance#_hidden_tab&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Speed&amp;nbsp;up&amp;nbsp;your&amp;nbsp;ClojureScript&amp;nbsp;Webapp&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;&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;레이아웃 스레싱 문제를 해결하기 위해 DOM을 자동으로 읽고 써주는 [&lt;a href=&quot;http://wilsonpage.co.uk/preventing-layout-thrashing/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Preventing&amp;nbsp;'layout&amp;nbsp;thrashing'&lt;/a&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;a href=&quot;https://github.com/wilsonpage/fastdom&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FastDOM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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의 Vsync 클래스도 비슷한 원리인듯. [&lt;a href=&quot;https://d2.naver.com/helloworld/6856597&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMP는 어떻게 웹 페이지의 성능을 높일 수 있나&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1021&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SGdBx/btqXgpvkXbM/cjSyjQiVB1r7B67v0D0Z5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SGdBx/btqXgpvkXbM/cjSyjQiVB1r7B67v0D0Z5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SGdBx/btqXgpvkXbM/cjSyjQiVB1r7B67v0D0Z5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSGdBx%2FbtqXgpvkXbM%2FcjSyjQiVB1r7B67v0D0Z5k%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;1021&quot; height=&quot;366&quot; data-origin-width=&quot;1021&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리엑트18은 각종 상태, 이벤트등을 모두 &lt;a href=&quot;https://github.com/reactwg/react-18/discussions/21&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Automatic Batching&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;b&gt;DOM 조작&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jQuery 독점기를 깨고 나오는 각종 라이브러리들은 돔조작을 간편하고 효율적으로 만드려고 눈물나는 노력들의 산물이다. [&lt;a href=&quot;https://teropa.info/blog/2015/03/02/change-and-its-detection-in-javascript-frameworks.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Change&amp;nbsp;And&amp;nbsp;Its&amp;nbsp;Detection&amp;nbsp;In&amp;nbsp;JavaScript&amp;nbsp;Frameworks&lt;/a&gt;, &lt;a href=&quot;https://auth0.com/blog/face-off-virtual-dom-vs-incremental-dom-vs-glimmer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React&amp;nbsp;Virtual&amp;nbsp;DOM&amp;nbsp;vs&amp;nbsp;Incremental&amp;nbsp;DOM&amp;nbsp;vs&amp;nbsp;Ember&amp;rsquo;s&amp;nbsp;Glimmer:&amp;nbsp;Fight&lt;/a&gt;, &lt;a href=&quot;https://dev.to/this-is-learning/javascript-vs-javascript-fight-53fa&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript&amp;nbsp;vs&amp;nbsp;JavaScript.&amp;nbsp;Fight!&lt;/a&gt;, &amp;nbsp;&lt;a href=&quot;https://www.heise.de/select/ix/2021/5/2018311514916341034&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Die Rendering-Engines von React, Angular und Ember im Vergleich&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;a href=&quot;https://backbonejs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Backbone.js&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://www.sencha.com/products/extjs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ext JS&lt;/a&gt;, &lt;a href=&quot;https://dojotoolkit.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dojo&lt;/a&gt;는 데이터 모델의 상태를 변경하여 반영하려했는데, 변경의 이벤트의 대해 다시 렌더링을 해야할지 결정하고 해결해야하는 것은 프로그래머가 해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7WrME/btqWXamh13y/vCNTXWWI85VEDX0EIzusr0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7WrME/btqWXamh13y/vCNTXWWI85VEDX0EIzusr0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7WrME/btqWXamh13y/vCNTXWWI85VEDX0EIzusr0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7WrME%2FbtqWXamh13y%2FvCNTXWWI85VEDX0EIzusr0%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;509&quot; height=&quot;205&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;205&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://emberjs.com/&quot;&gt;Ember.js&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;는 데이터 바인딩을 통해 이벤트가 수행할 리스너를 등록하여 동기화를 편하게 만들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Uh9Kl/btqW8FS12EV/rIwoPRfUNtf3ehQJkBimW1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Uh9Kl/btqW8FS12EV/rIwoPRfUNtf3ehQJkBimW1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Uh9Kl/btqW8FS12EV/rIwoPRfUNtf3ehQJkBimW1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUh9Kl%2FbtqW8FS12EV%2FrIwoPRfUNtf3ehQJkBimW1%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;509&quot; height=&quot;205&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;205&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://angularjs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AngularJS&lt;/a&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mY2wu/btqW4hrnZiq/gSHICsktiOkrgepZUJt6i1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mY2wu/btqW4hrnZiq/gSHICsktiOkrgepZUJt6i1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mY2wu/btqW4hrnZiq/gSHICsktiOkrgepZUJt6i1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmY2wu%2FbtqW4hrnZiq%2FgSHICsktiOkrgepZUJt6i1%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;509&quot; height=&quot;205&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;205&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Angular는 &lt;a href=&quot;https://github.com/angular/angular/tree/master/packages/zone.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Zone&lt;/a&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;a href=&quot;https://medium.com/better-programming/zone-js-for-angular-devs-573d89bbb890&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;10 Things Every Angular Developer Should Know About Zone.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bkim.tistory.com/10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Change&amp;nbsp;Detection&amp;nbsp;란&amp;nbsp;무엇인가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://indepth.dev/posts/1059/do-you-still-think-that-ngzone-zone-js-is-required-for-change-detection-in-angular&quot;&gt;아직도 NgZone이 단순하게 Angular의 변화감지(Change Detection)를 위해서만 필요하다고 생각하시나요?&lt;/a&gt;(&lt;a href=&quot;https://norux.me/66?category=731892&quot;&gt;번역&lt;/a&gt;)&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;thoughtram란 블로그에 Angular 구조 및 성능과 관련된 좋은 글들이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Taking advantage of Observables in Angular[&lt;a href=&quot;https://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;part1&lt;/a&gt;, &lt;a href=&quot;https://blog.thoughtram.io/angular/2016/01/07/taking-advantage-of-observables-in-angular2-pt2.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;part2&lt;/a&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;a href=&quot;https://blog.thoughtram.io/angular/2016/01/22/understanding-zones.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Zone의 이해&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.thoughtram.io/angular/2016/02/01/zones-in-angular-2.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Angular에서 Zones의 역할&lt;/a&gt;(&lt;a href=&quot;https://norux.me/64?category=731892&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;번역&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Angular Change Detection Explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.thoughtram.io/angular/2016/10/13/two-way-data-binding-in-angular-2.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Two-way Data Binding in Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.thoughtram.io/angular/2017/02/02/making-your-angular-app-fast.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Making your Angular apps fast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.thoughtram.io/angular/2017/02/21/using-zones-in-angular-for-better-performance.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; Using&amp;nbsp;Zones&amp;nbsp;in&amp;nbsp;Angular&amp;nbsp;for&amp;nbsp;better&amp;nbsp;performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.thoughtram.io/angular/2018/03/05/advanced-caching-with-rxjs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Advanced&amp;nbsp;caching&amp;nbsp;with&amp;nbsp;RxJS&lt;/a&gt;&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;a href=&quot;https://ko.reactjs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React&lt;/a&gt;는 매우 가벼운 Virtual DOM을 매번 생성 후, 비교후 실제 돔조작을 하는 방식이다.&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://d2.naver.com/helloworld/7226235&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2020년과&amp;nbsp;이후&amp;nbsp;JavaScript의&amp;nbsp;동향&amp;nbsp;-&amp;nbsp;라이브러리와&amp;nbsp;프레임워크&amp;nbsp;1&lt;/a&gt;, &lt;a href=&quot;https://yceffort.kr/2020/07/change-detection-in-angular-react&quot;&gt;프론트엔드 개발자가 알아야 하는 Angular와 React의 Change Detection&lt;/a&gt;(&lt;a href=&quot;https://indepth.dev/posts/1064/what-every-front-end-developer-should-know-about-change-detection-in-angular-and-react&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;영문&lt;/a&gt;), &lt;a href=&quot;https://medium.com/better-programming/angular-vs-react-change-detection-c54ae33139fe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Angular vs. React: Change Detection&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bARo1a/btqW1sms0XA/N6xVbEJ9OTCqw62Poek5G0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bARo1a/btqW1sms0XA/N6xVbEJ9OTCqw62Poek5G0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bARo1a/btqW1sms0XA/N6xVbEJ9OTCqw62Poek5G0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbARo1a%2FbtqW1sms0XA%2FN6xVbEJ9OTCqw62Poek5G0%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;576&quot; height=&quot;324&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기타 리엑트 스타일의 가벼운 라이브러리들. (보통 Diff 알고리즘을 개선했다고 알려져있다. &lt;a href=&quot;https://github.com/facebook/react/issues/10703&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#10703 A faster diff algorithm&lt;/a&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;a href=&quot;https://github.com/preactjs/preact&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Preact&lt;/a&gt;: 이 중 가장 유명한 걸로 안다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/infernojs/inferno&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Inferno&lt;/a&gt;: 메모이즈, 노멀라이징, 마이크로레벨 최적화&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/localvoid/ivi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ivi&lt;/a&gt;: Directed Graph와 Observable을 사용해 더티체킹&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yisar/fre&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fre&lt;/a&gt;: 리엑트처럼 Concurrent 모드를 지원&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NervJS/nerv&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nerv&lt;/a&gt;: 빠른 결정적 Diff&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bikeshaving/crank&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Crank&lt;/a&gt;: 제네레이터와 비동기함수(프로미스)를 JSX에서 지원&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;Ember의 &lt;a href=&quot;https://glimmerjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Glimmer&lt;/a&gt; 엔진에는 Virtual DOM에서 영감을 받은 Stream Tree를 이용해 변경점을 업데이트하고, &lt;a href=&quot;https://github.com/google/incremental-dom&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Incremental&amp;nbsp;DOM&lt;/a&gt;는 실제 DOM과 메모리상 DOM을 비교하여 업데이트 한다.[&lt;a href=&quot;https://auth0.com/blog/incremental-dom/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Incremental&amp;nbsp;DOM&amp;nbsp;101:&amp;nbsp;What&amp;nbsp;is&amp;nbsp;it&amp;nbsp;and&amp;nbsp;why&amp;nbsp;I&amp;nbsp;should&amp;nbsp;care?&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2xJlo/btqXobQMRct/kWkRSMJ8oEqxbIaKAKiMvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2xJlo/btqXobQMRct/kWkRSMJ8oEqxbIaKAKiMvk/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;722&quot; style=&quot;width: 60.8391%; margin-right: 10px;&quot; data-widthpercent=&quot;61.55&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2xJlo/btqXobQMRct/kWkRSMJ8oEqxbIaKAKiMvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2xJlo%2FbtqXobQMRct%2FkWkRSMJ8oEqxbIaKAKiMvk%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;1280&quot; height=&quot;722&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4SPh2/btqXgoiR7x9/VnHAzpO5dB3BiopHmaCUtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4SPh2/btqXgoiR7x9/VnHAzpO5dB3BiopHmaCUtk/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1156&quot; style=&quot;width: 37.9981%;&quot; data-widthpercent=&quot;38.45&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4SPh2/btqXgoiR7x9/VnHAzpO5dB3BiopHmaCUtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4SPh2%2FbtqXgoiR7x9%2FVnHAzpO5dB3BiopHmaCUtk%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;1280&quot; height=&quot;1156&quot;/&gt;&lt;/span&gt;&lt;/div&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://github.com/omcljs/om&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Om&lt;/a&gt;이나 &lt;a href=&quot;http://reagent-project.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reagent&lt;/a&gt;는 변경이 안된 것들을&amp;nbsp; &lt;a href=&quot;https://en.wikipedia.org/wiki/Persistent_data_structure&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Persistent 데이터구조&lt;/a&gt;를 이용해 파악하여 재사용하여 성능에 이점이 있다.[&lt;a href=&quot;https://hypirion.com/musings/understanding-persistent-vector-pt-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Understanding&amp;nbsp;Clojure's&amp;nbsp;Persistent&amp;nbsp;Vectors,&amp;nbsp;pt.&amp;nbsp;1&lt;/a&gt;, &lt;a href=&quot;https://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Persistent Data Structures and Managed References&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZMB5l/btqXobpICi7/1jARcUi0ykbS6gCKgpdcb1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZMB5l/btqXobpICi7/1jARcUi0ykbS6gCKgpdcb1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZMB5l/btqXobpICi7/1jARcUi0ykbS6gCKgpdcb1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZMB5l%2FbtqXobpICi7%2F1jARcUi0ykbS6gCKgpdcb1%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;576&quot; height=&quot;324&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점은 사람들이 익숙하지 않은 LISP 계열의 &lt;a href=&quot;https://github.com/clojure/clojurescript&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Closurescript&lt;/a&gt;를 이용한다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 아이디어는 불변성을 관리하는 라이브러리인&amp;nbsp;&lt;a href=&quot;https://immutable-js.github.io/immutable-js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Immutable JS&lt;/a&gt;, &lt;a href=&quot;https://immerjs.github.io/immer/docs/introduction&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Immer&lt;/a&gt;를 탄생시켰고,&amp;nbsp;&lt;a href=&quot;https://angular.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Angular&lt;/a&gt;에도 적용되고 있다. [&lt;a href=&quot;https://web.archive.org/web/20161003213754/https://vsavkin.com/change-detection-in-angular-2-4f216b855d4c?gi=b2e512a2086f&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Change Detection in Angular 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;자료들을 읽다보면 알겠지만&amp;nbsp; Reactive한 Signal-Graph를 만들어 성능 개선을 할 수도 있다. [&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;a href=&quot;https://arnebrasseur.net/talks/2016-react-fast/#1&quot;&gt;Why React &amp;amp; re-frame are fast in 8 Performance Hacks&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(&lt;/span&gt;&lt;a href=&quot;https://lambdaisland.com/blog/2017-02-02-why-react-reagent-fast-7-performance-hacks&quot;&gt;영상&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;), &lt;a href=&quot;https://www.slideshare.net/SangKyuPark1/re-frame-68818376&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Re frame&lt;/a&gt;&lt;/span&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reactive하기 때문에 즉시 업데이트가 필요한지 알 수 있으며(예를 들어 Angular는 주기적으로 CD를 한다),&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Signal-Graph로 이루어져 즉시 전파가 된다. (상태 전파를 파악하고 중복되는 변화등을 막음, Reactive 자체로는 성능 향상이 크지 않고 Signal-Graph가 핵심)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O9LSD/btqXgn5IWpP/mU4nLqadt9Tk8m69lXuY50/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O9LSD/btqXgn5IWpP/mU4nLqadt9Tk8m69lXuY50/img.jpg&quot; data-small=&quot;https://image.slidesharecdn.com/re-frame-161113130216/85/re-frame-10-320.jpg?cb=1479042211&quot; data-normal=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-10-638.jpg?cb=1479042211&quot; data-full=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-10-1024.jpg?cb=1479042211&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;359&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O9LSD/btqXgn5IWpP/mU4nLqadt9Tk8m69lXuY50/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO9LSD%2FbtqXgn5IWpP%2FmU4nLqadt9Tk8m69lXuY50%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;638&quot; height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCluK3/btqXrDmkpZ3/hB6yXTOfibdcOkq87sIkV1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCluK3/btqXrDmkpZ3/hB6yXTOfibdcOkq87sIkV1/img.jpg&quot; data-small=&quot;https://image.slidesharecdn.com/re-frame-161113130216/85/re-frame-11-320.jpg?cb=1479042211&quot; data-normal=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-11-638.jpg?cb=1479042211&quot; data-full=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-11-1024.jpg?cb=1479042211&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;359&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCluK3/btqXrDmkpZ3/hB6yXTOfibdcOkq87sIkV1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCluK3%2FbtqXrDmkpZ3%2FhB6yXTOfibdcOkq87sIkV1%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;638&quot; height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vHjnS/btqW8HcDPq6/mGNOv4aks3vpwtv5HRIjG0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vHjnS/btqW8HcDPq6/mGNOv4aks3vpwtv5HRIjG0/img.jpg&quot; data-small=&quot;https://image.slidesharecdn.com/re-frame-161113130216/85/re-frame-14-320.jpg?cb=1479042211&quot; data-normal=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-14-638.jpg?cb=1479042211&quot; data-full=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-14-1024.jpg?cb=1479042211&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;359&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vHjnS/btqW8HcDPq6/mGNOv4aks3vpwtv5HRIjG0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvHjnS%2FbtqW8HcDPq6%2FmGNOv4aks3vpwtv5HRIjG0%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;638&quot; height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwZaut/btqXgpJc8Kf/It55JWfmF6lsbkwVeIRZ00/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwZaut/btqXgpJc8Kf/It55JWfmF6lsbkwVeIRZ00/img.jpg&quot; data-small=&quot;https://image.slidesharecdn.com/re-frame-161113130216/85/re-frame-26-320.jpg?cb=1479042211&quot; data-normal=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-26-638.jpg?cb=1479042211&quot; data-full=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-26-1024.jpg?cb=1479042211&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;359&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwZaut/btqXgpJc8Kf/It55JWfmF6lsbkwVeIRZ00/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwZaut%2FbtqXgpJc8Kf%2FIt55JWfmF6lsbkwVeIRZ00%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;638&quot; height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHf14u/btqXgn5JzTT/NTUOLhlbXTlvzAImc2uA7K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHf14u/btqXgn5JzTT/NTUOLhlbXTlvzAImc2uA7K/img.jpg&quot; data-small=&quot;https://image.slidesharecdn.com/re-frame-161113130216/85/re-frame-33-320.jpg?cb=1479042211&quot; data-normal=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-33-638.jpg?cb=1479042211&quot; data-full=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-33-1024.jpg?cb=1479042211&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;359&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHf14u/btqXgn5JzTT/NTUOLhlbXTlvzAImc2uA7K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHf14u%2FbtqXgn5JzTT%2FNTUOLhlbXTlvzAImc2uA7K%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;638&quot; height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvi3V9/btqXoaLvjiz/uiny35qPHAjvfYVOOiUqoK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvi3V9/btqXoaLvjiz/uiny35qPHAjvfYVOOiUqoK/img.jpg&quot; data-small=&quot;https://image.slidesharecdn.com/re-frame-161113130216/85/re-frame-35-320.jpg?cb=1479042211&quot; data-normal=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-35-638.jpg?cb=1479042211&quot; data-full=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-35-1024.jpg?cb=1479042211&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;359&quot; style=&quot;width: 32.5581%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvi3V9/btqXoaLvjiz/uiny35qPHAjvfYVOOiUqoK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbvi3V9%2FbtqXoaLvjiz%2Fuiny35qPHAjvfYVOOiUqoK%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;638&quot; height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tdOre/btqXj8HdIU7/Ajd7fgBsuPEVUB6HJSOPxK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tdOre/btqXj8HdIU7/Ajd7fgBsuPEVUB6HJSOPxK/img.jpg&quot; data-small=&quot;https://image.slidesharecdn.com/re-frame-161113130216/85/re-frame-37-320.jpg?cb=1479042211&quot; data-normal=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-37-638.jpg?cb=1479042211&quot; data-full=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-37-1024.jpg?cb=1479042211&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;359&quot; style=&quot;width: 32.5581%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tdOre/btqXj8HdIU7/Ajd7fgBsuPEVUB6HJSOPxK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtdOre%2FbtqXj8HdIU7%2FAjd7fgBsuPEVUB6HJSOPxK%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;638&quot; height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGxEsS/btqXrCnqYSG/58xDL3XZHHXD5Nj5ff9aGk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGxEsS/btqXrCnqYSG/58xDL3XZHHXD5Nj5ff9aGk/img.jpg&quot; data-small=&quot;https://image.slidesharecdn.com/re-frame-161113130216/85/re-frame-40-320.jpg?cb=1479042211&quot; data-normal=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-40-638.jpg?cb=1479042211&quot; data-full=&quot;https://image.slidesharecdn.com/re-frame-161113130216/95/re-frame-40-1024.jpg?cb=1479042211&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;359&quot; style=&quot;width: 32.5581%; margin-top: 10px;&quot; data-widthpercent=&quot;33.34&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGxEsS/btqXrCnqYSG/58xDL3XZHHXD5Nj5ff9aGk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGxEsS%2FbtqXrCnqYSG%2F58xDL3XZHHXD5Nj5ff9aGk%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;638&quot; height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;/div&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://github.com/facebookexperimental/Recoil&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Recoil&lt;/a&gt;에도 적용된듯 하다. [&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20200616&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Recoil - 또 다른 React 상태 관리 라이브러리?&lt;/a&gt;(&lt;a href=&quot;https://kelly-kh-woo.medium.com/%EB%B2%88%EC%97%AD-recoil-%EC%83%88%EB%A1%9C%EC%9A%B4-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-95b5bea91b0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다른 번역 버전&lt;/a&gt;), &lt;a href=&quot;https://deview.kr/2020/sessions/336&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Recoil: 왕위를 계승하는 중입니다 (새로운 React 상태 관리 라이브러리)&lt;/a&gt;(&lt;a href=&quot;https://deview.kr/data/deview/session/attach/Recoil_%E1%84%8B%E1%85%AA%E1%86%BC%E1%84%8B%E1%85%B1%E1%84%85%E1%85%B3%E1%86%AF_%E1%84%80%E1%85%A8%E1%84%89%E1%85%B3%E1%86%BC%E1%84%8C%E1%85%AE%E1%86%BC.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PDF&lt;/a&gt;), &lt;a href=&quot;https://medium.com/better-programming/recoil-a-new-state-management-library-moving-beyond-redux-and-the-context-api-63794c11b3a5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Recoil:&amp;nbsp;A&amp;nbsp;New&amp;nbsp;State&amp;nbsp;Management&amp;nbsp;Library&amp;nbsp;Moving&amp;nbsp;Beyond&amp;nbsp;Redux&amp;nbsp;and&amp;nbsp;the&amp;nbsp;Context&amp;nbsp;API&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;692&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdby5P/btqWX5escax/jZxNjdGOKotIxqNIc4rm00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdby5P/btqWX5escax/jZxNjdGOKotIxqNIc4rm00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdby5P/btqWX5escax/jZxNjdGOKotIxqNIc4rm00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcdby5P%2FbtqWX5escax%2FjZxNjdGOKotIxqNIc4rm00%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;1868&quot; height=&quot;1010&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;692&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://dev.to/ryansolid/thinking-granular-how-is-solidjs-so-performant-4g37&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Thinking Granular: How is SolidJS so Performant?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/ryansolid/a-hands-on-introduction-to-fine-grained-reactivity-3ndf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A Hands-on Introduction to Fine-Grained Reactivity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/ryansolid/building-a-reactive-library-from-scratch-1i0p&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Building&amp;nbsp;a&amp;nbsp;Reactive&amp;nbsp;Library&amp;nbsp;from&amp;nbsp;Scratch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://indepth.dev/posts/1269/finding-fine-grained-reactive-programming&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Finding Fine-Grained Reactive Programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/this-is-learning/what-the-hell-is-reactive-programming-anyway-31p5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What the hell is Reactive Programming anyway?&lt;/a&gt;&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;a href=&quot;https://medium.com/dailyjs/a-realworld-comparison-of-front-end-frameworks-2020-4e50655fe4c1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;RealWorld&amp;nbsp;Comparison&amp;nbsp;of&amp;nbsp;Front-End&amp;nbsp;Frameworks&amp;nbsp;2020&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;2151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cR0BCW/btqWWtzCj0S/GRHTUrLUJJ6cQRijBCwPMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cR0BCW/btqWWtzCj0S/GRHTUrLUJJ6cQRijBCwPMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cR0BCW/btqWWtzCj0S/GRHTUrLUJJ6cQRijBCwPMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcR0BCW%2FbtqWWtzCj0S%2FGRHTUrLUJJ6cQRijBCwPMk%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;4000&quot; height=&quot;2151&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;2151&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://elm-lang.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Elm&lt;/a&gt;과 &lt;span style=&quot;color: #333333;&quot;&gt;최근에 뜨고 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://svelte.dev/&quot;&gt;Svelte&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;가 그 대상이다.&amp;nbsp; [Blazing Fast HTML(&lt;a href=&quot;https://elm-lang.org/news/blazing-fast-html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Round 1,&lt;/a&gt; &lt;a href=&quot;https://elm-lang.org/news/blazing-fast-html-round-two&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Round 2&lt;/a&gt;), &lt;a href=&quot;https://medium.com/happyprogrammer-in-jeju/elm-%EC%9B%B9-%EC%95%B1-%EC%A0%84%EB%AC%B8-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%96%B8%EC%96%B4-b3742303a78e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Elm&amp;nbsp;&amp;mdash;&amp;nbsp;웹&amp;nbsp;앱&amp;nbsp;전문&amp;nbsp;함수형&amp;nbsp;프로그래밍&amp;nbsp;언어&lt;/a&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;이중 Elm의 아키텍처는 언어적으로 상태관리를 하도록 만들어 &lt;a href=&quot;https://hyperapp.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hyperapp&lt;/a&gt;등에도 영향을 주었다.&amp;nbsp; [&lt;a href=&quot;https://elmprogramming.com/subscriptions.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Subscriptions&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@l.mugnaini/the-elm-architecture-tea-animation-3efc555e8faf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Elm Architecture (TEA) animation&lt;/a&gt;, &lt;a href=&quot;https://blog.eduonix.com/web-programming-tutorials/everything-n&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Everything&amp;nbsp;You&amp;nbsp;Need&amp;nbsp;To&amp;nbsp;Know&amp;nbsp;About&amp;nbsp;Hyperapp&amp;nbsp;JS&lt;/a&gt;]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4qb4Q/btqW1tZXQO9/KGky0O4wcW56N1AHis631K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4qb4Q/btqW1tZXQO9/KGky0O4wcW56N1AHis631K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4qb4Q/btqW1tZXQO9/KGky0O4wcW56N1AHis631K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/4qb4Q/btqW1tZXQO9/KGky0O4wcW56N1AHis631K/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;800&quot; height=&quot;359&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;359&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;개인적으로 Elm의 아키텍처를 가장 쉽게 풀어낸 것이 &lt;a href=&quot;https://apprun.js.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Apprun&lt;/a&gt;이나 &lt;a href=&quot;https://github.com/day8/re-frame&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;re-frame&lt;/a&gt;인 듯하다. [&lt;a href=&quot;https://apprun.js.org/docs/#/04-architecture&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AppRun - Architecture&lt;/a&gt;, &lt;a href=&quot;https://day8.github.io/re-frame/a-loop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Re-frame&amp;nbsp; - A Data Loop&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nu1em/btqXj8thFag/CHgnM1cIy61dkH61bcLcV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nu1em/btqXj8thFag/CHgnM1cIy61dkH61bcLcV0/img.png&quot; data-origin-width=&quot;1121&quot; data-origin-height=&quot;545&quot; style=&quot;width: 75.6713%; margin-right: 10px;&quot; data-widthpercent=&quot;76.56&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nu1em/btqXj8thFag/CHgnM1cIy61dkH61bcLcV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNu1em%2FbtqXj8thFag%2FCHgnM1cIy61dkH61bcLcV0%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;1121&quot; height=&quot;545&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OGTiU/btqWX4F51dm/FaHPoUICLKzik9dIYagwo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OGTiU/btqWX4F51dm/FaHPoUICLKzik9dIYagwo0/img.png&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;613&quot; style=&quot;width: 23.1659%;&quot; data-widthpercent=&quot;23.44&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OGTiU/btqWX4F51dm/FaHPoUICLKzik9dIYagwo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOGTiU%2FbtqWX4F51dm%2FFaHPoUICLKzik9dIYagwo0%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;386&quot; height=&quot;613&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에서는 &lt;a href=&quot;https://github.com/gcanti/elm-ts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;elm-ts&lt;/a&gt;란 라이브러리나&amp;nbsp;&lt;a href=&quot;https://github.com/ncthbrt/react-use-elmish&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-use-elmish&lt;/a&gt; 훅을 이용해 elm을 흉내낼 수 있다.&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://en.wikipedia.org/wiki/Entity_component_system&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ECS(Entity Component System) 패턴&lt;/a&gt;이라는 것이 존재한다. [&lt;a href=&quot;https://blog.unity.com/kr/technology/on-dots-entity-component-system&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DOTS&amp;nbsp;기술&amp;nbsp;소개:&amp;nbsp;엔티티&amp;nbsp;컴포넌트&amp;nbsp;시스템&lt;/a&gt;, &lt;a href=&quot;https://docs.unity3d.com/Packages/com.unity.entities@0.17/manual/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Entity&amp;nbsp;Component&amp;nbsp;System&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@jonathanmines/data-oriented-vs-object-oriented-design-50ef35a99056&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Data Oriented vs Object Oriented Design&lt;/a&gt;, &lt;a href=&quot;https://medium.com/mirum-budapest/introduction-to-data-oriented-programming-85b51b99572d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introduction to Data-Oriented Programming&lt;/a&gt;, &lt;a href=&quot;https://www.ea.com/frostbite/news/introduction-to-data-oriented-design&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introduction to Data-Oriented Programming(FrostBite)&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dT7Suf/btrnAixoHdI/RtHcFDBNu02PNNEgatudw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dT7Suf/btrnAixoHdI/RtHcFDBNu02PNNEgatudw1/img.png&quot; data-alt=&quot;ECS Pattern&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dT7Suf/btrnAixoHdI/RtHcFDBNu02PNNEgatudw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdT7Suf%2FbtrnAixoHdI%2FRtHcFDBNu02PNNEgatudw1%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;694&quot; height=&quot;538&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ECS Pattern&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 모여있어 캐싱(지역성)이 유리하고, 병렬로 처리하기도 좋은 편이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXkCwN/btrnBssKNXL/pUZCyzbB4FYnnHO9P3DAs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXkCwN/btrnBssKNXL/pUZCyzbB4FYnnHO9P3DAs1/img.png&quot; width=&quot;229&quot; height=&quot;247&quot; data-origin-width=&quot;229&quot; data-origin-height=&quot;247&quot; style=&quot;width: 53.5362%; margin-right: 10px;&quot; data-widthpercent=&quot;54.17&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXkCwN/btrnBssKNXL/pUZCyzbB4FYnnHO9P3DAs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXkCwN%2FbtrnBssKNXL%2FpUZCyzbB4FYnnHO9P3DAs1%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;229&quot; height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vQoYu/btrnBLZUDf2/VG3u1IKFPOGDbaLT2u8JD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vQoYu/btrnBLZUDf2/VG3u1IKFPOGDbaLT2u8JD1/img.png&quot; width=&quot;233&quot; height=&quot;297&quot; data-origin-width=&quot;233&quot; data-origin-height=&quot;297&quot; style=&quot;width: 45.301%;&quot; data-widthpercent=&quot;45.83&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vQoYu/btrnBLZUDf2/VG3u1IKFPOGDbaLT2u8JD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvQoYu%2FbtrnBLZUDf2%2FVG3u1IKFPOGDbaLT2u8JD1%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;233&quot; height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 웹에서 사용해보려는 시도가 존재한다. [&lt;a href=&quot;https://medium.com/@drvondevious/entity-component-systems-for-the-web-22065c95de4c&quot;&gt;Entity&amp;nbsp;Component&amp;nbsp;Systems&amp;nbsp;For&amp;nbsp;The&amp;nbsp;Web&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://medium.com/@abulka/todomvc-implemented-using-a-game-architecture-ecs-88bb86ea5e98&quot;&gt;TodoMVC implemented using a game architecture &amp;mdash; ECS&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ECS 패턴을 구현한 라이브러리에서는&amp;nbsp;&lt;a href=&quot;https://github.com/EnderShadow8/wolf-ecs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WolfECS&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;a href=&quot;https://xstate.js.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Xstate&lt;/a&gt;도 한번쯤 살펴보는 것도 좋다. [&lt;a href=&quot;http://blog.hwahae.co.kr/all/tech/tech-tech/6707/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Finite state machine &amp;amp; statecharts &amp;ndash; XState&lt;/a&gt;, &lt;a href=&quot;https://medium.com/frontmen/boost-your-react-applications-performance-by-xstate-cc7d5588805f&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Boost&amp;nbsp;your&amp;nbsp;React&amp;nbsp;application&amp;rsquo;s&amp;nbsp;performance&amp;nbsp;by&amp;nbsp;Xstate&lt;/a&gt;, &lt;a href=&quot;https://statecharts.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Welcom to the world of Statecharts&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: #333333;&quot;&gt;Svelte의 목표는 컴포넌트들을 컴파일하여 매우 효율적인 코드로 변환해 Virtual DOM의 오버헤드를 제거하자는 것이다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://svelte.dev/blog/frameworks-without-the-framework&quot;&gt;Frameworks without the framework: why didn't we think of this sooner?&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;, &lt;a href=&quot;https://svelte.dev/blog/virtual-dom-is-pure-overhead&quot;&gt;Virtual Dom is pure overhead&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://svelte.dev/blog/svelte-3-rethinking-reactivity&quot;&gt;Svelte 3: Rethinking reactivity&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://velog.io/@vnthf/svelte%EA%B0%80-%EB%B9%A0%EB%A5%B8-%EC%9D%B4%EC%9C%A0&quot;&gt;svelte가 빠른 이유&lt;/a&gt;, &lt;a href=&quot;http://www.tellmehow.co/svelte-cheatsheet-crash-course/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Svelte CheetSheet&lt;/a&gt;, &lt;a href=&quot;https://lihautan.com/the-svelte-compiler-handbook/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Svelte Compiler Handbook&lt;/a&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;a href=&quot;https://github.com/malinajs/malinajs&quot;&gt;malina&lt;/a&gt;라고 svelte와 비슷한 프로젝트, vdom의 컴파일인 &lt;a href=&quot;https://github.com/aidenybai/million&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;million&lt;/a&gt;도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d92EJU/btqXj7uoNIG/2dWCEctkMNJQXIWbA9k8N0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d92EJU/btqXj7uoNIG/2dWCEctkMNJQXIWbA9k8N0/img.png&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;440&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d92EJU/btqXj7uoNIG/2dWCEctkMNJQXIWbA9k8N0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd92EJU%2FbtqXj7uoNIG%2F2dWCEctkMNJQXIWbA9k8N0%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;880&quot; height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R0FOt/btqWXaGB8XX/9pYcxqYKHtmnoskcvz59O1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R0FOt/btqWXaGB8XX/9pYcxqYKHtmnoskcvz59O1/img.png&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;440&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R0FOt/btqWXaGB8XX/9pYcxqYKHtmnoskcvz59O1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR0FOt%2FbtqWXaGB8XX%2F9pYcxqYKHtmnoskcvz59O1%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;880&quot; height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Svelte&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;4911&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgNraV/btqXb1BvtbN/TbmVkEi5AEBy4XbUSTvHbk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgNraV/btqXb1BvtbN/TbmVkEi5AEBy4XbUSTvHbk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgNraV/btqXb1BvtbN/TbmVkEi5AEBy4XbUSTvHbk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgNraV%2FbtqXb1BvtbN%2FTbmVkEi5AEBy4XbUSTvHbk%2Fimg.webp&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;4911&quot; height=&quot;860&quot; data-origin-width=&quot;4911&quot; data-origin-height=&quot;860&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;span style=&quot;color: #333333;&quot;&gt;사실 Ember의 Glimmer 엔진은 비슷하지만 완전 다른 접근법을 가지고 있다.[&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Glimmer:&amp;nbsp;Blazing&amp;nbsp;Fast&amp;nbsp;Rendering&amp;nbsp;for&amp;nbsp;Ember.js(&lt;/span&gt;&lt;a href=&quot;https://engineering.linkedin.com/blog/2017/03/glimmer--blazing-fast-rendering-for-ember-js--part-1&quot;&gt;part1&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://engineering.linkedin.com/blog/2017/06/glimmer--blazing-fast-rendering-for-ember-js--part-2&quot;&gt;part2&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;),&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://yehudakatz.com/2017/04/05/the-glimmer-vm-boots-fast-and-stays-fast/&quot;&gt;The&amp;nbsp;Glimmer&amp;nbsp;VM:&amp;nbsp;Boots&amp;nbsp;Fast&amp;nbsp;and&amp;nbsp;Stays&amp;nbsp;Fast&lt;/a&gt;, &lt;a href=&quot;https://engineering.linkedin.com/blog/2017/12/the-glimmer-binary-experience&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Glimmer&amp;nbsp;Binary&amp;nbsp;Experience&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4ildo/btqWX4znJMt/e4XUSRoOQ9k6rLT6FEhJik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4ildo/btqWX4znJMt/e4XUSRoOQ9k6rLT6FEhJik/img.png&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;421&quot; style=&quot;width: 48.3237%; margin-right: 10px;&quot; data-widthpercent=&quot;48.89&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4ildo/btqWX4znJMt/e4XUSRoOQ9k6rLT6FEhJik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4ildo%2FbtqWX4znJMt%2Fe4XUSRoOQ9k6rLT6FEhJik%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;750&quot; height=&quot;421&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sCsTG/btqXb19lzRe/whlJzDwGE4mz2WAk0N8tFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sCsTG/btqXb19lzRe/whlJzDwGE4mz2WAk0N8tFK/img.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;537&quot; style=&quot;width: 50.5135%;&quot; data-widthpercent=&quot;51.11&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sCsTG/btqXb19lzRe/whlJzDwGE4mz2WAk0N8tFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsCsTG%2FbtqXb19lzRe%2FwhlJzDwGE4mz2WAk0N8tFK%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;1000&quot; height=&quot;537&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;컴파일? 과정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OvpkQ/btqXb0WVG2c/QMayZVIYdYOJA9k6QVXbRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OvpkQ/btqXb0WVG2c/QMayZVIYdYOJA9k6QVXbRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OvpkQ/btqXb0WVG2c/QMayZVIYdYOJA9k6QVXbRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOvpkQ%2FbtqXb0WVG2c%2FQMayZVIYdYOJA9k6QVXbRk%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;1264&quot; height=&quot;316&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ember의 템플릿 형식인 Handlerbar를 이용해 AST를 만든뒤, OP코드 형태와 같이 스트림 목록으로 만들고 최적화를 수행한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;우리는 효과적으로 프로그래밍 언어와 기본 런타임을 설계하고 있기 때문에 JIT 컴파일러와 바이트코드 인터프리터와 같이 언어 구현을 프로그래밍할 때 잘 확립된 원칙을 사용하여 그것을 설계해야 한다. VM 아키텍처를 구축하면 constant folding, 인라이닝, 매크로 확장 등과 같은 잘 알려진 최적화를 보다 쉽게 구현할 수 있을 것이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적, 동적인 템플릿을 구분하여 최적화가 수행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Virtual Dom과 Svelete 방식의 사이 느낌이랄까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Svelte부터 시작해 좋은 성능을 내는 라이브러리들 중&amp;nbsp; Virtual Dom을 사용하지 않는 경우가&amp;nbsp; 많아지고 있는 듯 하다. [&lt;a href=&quot;https://svelte.dev/blog/virtual-dom-is-pure-overhead&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Virtual&amp;nbsp;DOM&amp;nbsp;is&amp;nbsp;pure&amp;nbsp;overhead&lt;/a&gt;, &lt;a href=&quot;https://medium.com/better-programming/the-fastest-way-to-render-the-dom-e3b226b15ca3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Fastest Way to Render the DOM&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;앞서 이야기한 Reactive Signal-Graph 방식으로만 업데이트하는 경우도 있고,&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;&lt;a href=&quot;https://github.com/ryansolid/solid&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Solid&lt;/a&gt;: Fine-Grained Reactive Graph 사용&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/adamhaile/surplus&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Surplus&lt;/a&gt;: 컴파일하며, &lt;a href=&quot;https://github.com/adamhaile/S&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;S.js&lt;/a&gt;를 이용해 돔을 업데이트&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/luwes/sinuous&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sinuous&lt;/a&gt;: Surplus와 비슷한데 역시 더 빠르다. Reactive/Observable 기반&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Freak613/domc&quot;&gt;Domc&lt;/a&gt;: Top-Down 방식으로 Diff&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Freak613/stage0&quot;&gt;Stage0&lt;/a&gt;: Domc의 아이디어 바탕이라는데 더 빠르다는 듯&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ged-odoo/blockdom&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;blockdom&lt;/a&gt;: Element 단위가 아니라 Block 단위로 비교&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Domc처럼 diff 관련 라이브러리도 있는데 diff쪽은 &lt;a href=&quot;https://webreflection.medium.com/the-web-smallest-dom-diffing-library-5b69ac4d1f4d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;udomdiff&lt;/a&gt;(&lt;a href=&quot;https://webreflection.medium.com/the-web-smallest-dom-diffing-library-5b69ac4d1f4d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;관련글&lt;/a&gt;), &lt;a href=&quot;https://github.com/choojs/nanomorph&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;nanomorph&lt;/a&gt;, &lt;a href=&quot;https://github.com/yidafu/x-tree-diff-plus&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;x-tree-diff-plus&lt;/a&gt;(&lt;a href=&quot;https://link.springer.com/chapter/10.1007/11802167_104&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;논문&lt;/a&gt;), &lt;a href=&quot;https://thume.ca/2017/06/17/tree-diffing/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A* Tree Diff&lt;/a&gt;, &lt;a href=&quot;https://stackoverflow.com/questions/5894879/calculate-minimal-operations-to-make-two-tree-structures-identical&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스택오버플로우&lt;/a&gt;, 네이버 &lt;a href=&quot;https://github.com/naver/egjs-list-differ&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;list-differ&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;a href=&quot;https://medium.com/@Sujithnath/angular-aot-vs-jit-comparison-ce1d96ede491&quot;&gt;Angular&amp;nbsp;{{AOT&amp;nbsp;vs&amp;nbsp;JIT}}&amp;nbsp;vs&amp;nbsp;React&amp;nbsp;compiler:&amp;nbsp;Part&amp;nbsp;&amp;mdash;&amp;nbsp;I&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://blog.mgechev.com/2016/08/14/ahead-of-time-compilation-angular-offline-precompilation/&quot;&gt;Ahead-of-Time&amp;nbsp;Compilation&amp;nbsp;in&amp;nbsp;Angular&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://medium.jonasbandi.net/angular-vs-react-compilers-45b279a8f571&quot;&gt;Angular&amp;nbsp;vs.&amp;nbsp;React:&amp;nbsp;Compilers&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앵귤러는 AOT 컴파일을 도입하며, 리엑트는 &lt;a href=&quot;https://github.com/facebook/prepack/wiki/React-Compiler&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Prepack을 이용&lt;/a&gt;하거나 Svelte처럼 직접 변환하는 식(&lt;a href=&quot;https://github.com/sokra/rawact&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;rawact&lt;/a&gt;, &lt;a href=&quot;https://github.com/fabiosantoscode/ecmacomp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ecmacomp&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2kUiz/btrpOwHAHBd/0LhKBIUe4yh2KKRnmH8VR1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2kUiz/btrpOwHAHBd/0LhKBIUe4yh2KKRnmH8VR1/img.jpg&quot; width=&quot;638&quot; height=&quot;479&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;479&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2kUiz/btrpOwHAHBd/0LhKBIUe4yh2KKRnmH8VR1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2kUiz%2FbtrpOwHAHBd%2F0LhKBIUe4yh2KKRnmH8VR1%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;638&quot; height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n7148/btrpPGiQ59C/TxbKWO3YtVuzFSyFK2g9C0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n7148/btrpPGiQ59C/TxbKWO3YtVuzFSyFK2g9C0/img.jpg&quot; width=&quot;638&quot; height=&quot;479&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;479&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n7148/btrpPGiQ59C/TxbKWO3YtVuzFSyFK2g9C0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn7148%2FbtrpPGiQ59C%2FTxbKWO3YtVuzFSyFK2g9C0%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;638&quot; height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DOhIK/btrpQXxDhxB/tWZe52M49aEVNva4ClU1Rk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DOhIK/btrpQXxDhxB/tWZe52M49aEVNva4ClU1Rk/img.jpg&quot; width=&quot;638&quot; height=&quot;479&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;479&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DOhIK/btrpQXxDhxB/tWZe52M49aEVNva4ClU1Rk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDOhIK%2FbtrpQXxDhxB%2FtWZe52M49aEVNva4ClU1Rk%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;638&quot; height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 Solid의 저자가 쓴 컴파일과 컴포넌트 관련 글들이 인상깊다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/this-is-learning/a-look-at-compilation-in-javascript-frameworks-3caj&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Look&amp;nbsp;at&amp;nbsp;Compilation&amp;nbsp;in&amp;nbsp;JavaScript&amp;nbsp;Frameworks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://betterprogramming.pub/the-real-cost-of-ui-components-6d2da4aba205&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Real&amp;nbsp;Cost&amp;nbsp;of&amp;nbsp;UI&amp;nbsp;Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/this-is-learning/components-are-pure-overhead-hpm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Components are Pure Overhead&lt;/a&gt; [Svelte의 &lt;a href=&quot;https://svelte.dev/blog/virtual-dom-is-pure-overhead&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Virtual DOM is pure overhead&lt;/a&gt;&amp;nbsp;따라하기인듯 ㅋㅋ]&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;a href=&quot;https://github.com/Polymer/lit-html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lit-html&lt;/a&gt;, &lt;a href=&quot;https://github.com/WebReflection/hyperHTML&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;hyperHtml&lt;/a&gt;처럼 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;템플릿 리터럴&lt;/a&gt;을 이용하기도 한다. [&lt;a href=&quot;https://webreflection.medium.com/lit-html-vs-hyperhtml-vs-lighterhtml-c084abfe1285&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lit-html&amp;nbsp;vs&amp;nbsp;hyperHTML&amp;nbsp;vs&amp;nbsp;lighterhtml&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 Virtual DOM에 비해 주된 성능 향상 원리는 템플릿 리터럴을 사용하기 때문에 정적, 동적인지 판별하기 쉬워 변화가 생기는 문자열만 업데이트하고 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Element/innerHTML&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;innerHTML&lt;/a&gt;로 렌더링을 하는 것이다. [&lt;a href=&quot;https://2ality.com/2015/01/template-strings-html.html#the-template-handler&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTML&amp;nbsp;templating&amp;nbsp;with&amp;nbsp;ES6&amp;nbsp;template&amp;nbsp;strings&lt;/a&gt;, &lt;a href=&quot;https://malloc.fi/lit-html-javascript-templating-from-polymer-team-google&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lit-html,&amp;nbsp;JavaScript&amp;nbsp;templating&amp;nbsp;from&amp;nbsp;the&amp;nbsp;Polymer&amp;nbsp;team&amp;nbsp;at&amp;nbsp;Google&lt;/a&gt;, &lt;a href=&quot;https://codeburst.io/a-night-experimenting-with-lit-html-585a8c69892a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;night&amp;nbsp;experimenting&amp;nbsp;with&amp;nbsp;Lit-HTML&amp;hellip;&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@kennethrohde/a-bit-about-lit-html-rendering-2964c50ee56c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;bit&amp;nbsp;about&amp;nbsp;lit-html&amp;nbsp;rendering&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rblb4/btqW1tzyChu/1LKOpKaYyKFX64ks4aQoJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rblb4/btqW1tzyChu/1LKOpKaYyKFX64ks4aQoJ0/img.png&quot; data-alt=&quot;lit-html의 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rblb4/btqW1tzyChu/1LKOpKaYyKFX64ks4aQoJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRblb4%2FbtqW1tzyChu%2F1LKOpKaYyKFX64ks4aQoJ0%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;700&quot; height=&quot;263&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;lit-html의 방식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;713&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biLTuP/btqW4idkXzR/FE6M6veZ7turTeF2qsRQTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biLTuP/btqW4idkXzR/FE6M6veZ7turTeF2qsRQTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biLTuP/btqW4idkXzR/FE6M6veZ7turTeF2qsRQTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiLTuP%2FbtqW4idkXzR%2FFE6M6veZ7turTeF2qsRQTk%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;1280&quot; height=&quot;713&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;713&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q1y6G/btqXj8tYJ7g/ykDOaez6Nxtcst04C8AYa1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q1y6G/btqXj8tYJ7g/ykDOaez6Nxtcst04C8AYa1/img.gif&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;329&quot; style=&quot;width: 62.0943%; margin-right: 10px;&quot; data-widthpercent=&quot;62.82&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q1y6G/btqXj8tYJ7g/ykDOaez6Nxtcst04C8AYa1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq1y6G%2FbtqXj8tYJ7g%2FykDOaez6Nxtcst04C8AYa1%2Fimg.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;601&quot; height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l6MlI/btqXgnSo5uS/GXOgDNdZD0rgd32h5NbiD0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l6MlI/btqXgnSo5uS/GXOgDNdZD0rgd32h5NbiD0/img.gif&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;556&quot; style=&quot;width: 36.7429%;&quot; data-widthpercent=&quot;37.18&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l6MlI/btqXgnSo5uS/GXOgDNdZD0rgd32h5NbiD0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl6MlI%2FbtqXgnSo5uS%2FGXOgDNdZD0rgd32h5NbiD0%2Fimg.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;601&quot; height=&quot;556&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;h1, h3태그가 새로 생성되는 Preact와 달리 수정만 되는 모습을 볼 수 있다.&lt;/p&gt;
&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/nextapps-de/mikado&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mikado&lt;/a&gt;라는 템플릿 엔진의 성능도 주목할만 했다. [&lt;a href=&quot;https://krausest.github.io/js-framework-benchmark/current.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JS Framework Benchmark&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Recycle, Reuse를 극대화하며 독자적인 Diff 알고리즘을 사용했다나.&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;widthContent&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;711&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qOJDU/btqWX5SBbtY/K7u4rrbKXNSDNermGJ51v0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qOJDU/btqWX5SBbtY/K7u4rrbKXNSDNermGJ51v0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qOJDU/btqWX5SBbtY/K7u4rrbKXNSDNermGJ51v0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqOJDU%2FbtqWX5SBbtY%2FK7u4rrbKXNSDNermGJ51v0%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;838&quot; height=&quot;711&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;711&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/neomjs/neo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Neo&lt;/a&gt;라 하여 추후 나올 워커의 사용을 극대화한 프레임워크 또한 존재한다. [&lt;a href=&quot;https://betterprogramming.pub/create-blazing-fast-multithreading-user-interfaces-outside-of-nodejs-c4199b0023ec&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Create&amp;nbsp;Blazing&amp;nbsp;Fast&amp;nbsp;Multi-Threading&amp;nbsp;User&amp;nbsp;Interfaces&amp;nbsp;Outside&amp;nbsp;Node.js&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;279&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qDeWr/btrmoqRzOM9/kkRKU1qhFN3RSWfkxbyR2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qDeWr/btrmoqRzOM9/kkRKU1qhFN3RSWfkxbyR2K/img.png&quot; data-alt=&quot;일반 프론트엔드 아키텍쳐&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qDeWr/btrmoqRzOM9/kkRKU1qhFN3RSWfkxbyR2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqDeWr%2FbtrmoqRzOM9%2FkkRKU1qhFN3RSWfkxbyR2K%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;481&quot; height=&quot;279&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;279&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;일반 프론트엔드 아키텍쳐&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pvNdF/btrmyi5BsXy/hdiPNDdJfJD6Revcaf62z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pvNdF/btrmyi5BsXy/hdiPNDdJfJD6Revcaf62z1/img.png&quot; data-origin-width=&quot;721&quot; data-origin-height=&quot;519&quot; style=&quot;width: 45.3817%; margin-right: 10px;&quot; data-widthpercent=&quot;45.92&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pvNdF/btrmyi5BsXy/hdiPNDdJfJD6Revcaf62z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpvNdF%2Fbtrmyi5BsXy%2FhdiPNDdJfJD6Revcaf62z1%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;721&quot; height=&quot;519&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctSLuI/btrmiS2pIIw/8cQEwDtkEhu2fqh6lo7c8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctSLuI/btrmiS2pIIw/8cQEwDtkEhu2fqh6lo7c8K/img.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;440&quot; style=&quot;width: 53.4555%;&quot; data-widthpercent=&quot;54.08&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctSLuI/btrmiS2pIIw/8cQEwDtkEhu2fqh6lo7c8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctSLuI%2FbtrmiS2pIIw%2F8cQEwDtkEhu2fqh6lo7c8K%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;720&quot; height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;일반 워커와 Shared 워커 아키텍처&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;a href=&quot;https://github.com/BuilderIO/qwik&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Qwik&lt;/a&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재개가 가능하며, &lt;a href=&quot;https://github.com/BuilderIO/qwik/blob/main/docs/pages/guide/lazy-loading.mdx&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;세분화된 lazy loading&lt;/a&gt;이 가능하다고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GE2qH/btrAB0Lod6j/c04EyPkkP7I29u5AkHQQqk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GE2qH/btrAB0Lod6j/c04EyPkkP7I29u5AkHQQqk/img.jpg&quot; width=&quot;200&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;425&quot; data-widthpercent=&quot;58.9&quot; style=&quot;width: 58.2126%; margin-right: 10px;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GE2qH/btrAB0Lod6j/c04EyPkkP7I29u5AkHQQqk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGE2qH%2FbtrAB0Lod6j%2Fc04EyPkkP7I29u5AkHQQqk%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;940&quot; height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zw8Mc/btrADDPHX1p/DkR2u9IfK32bnGsoIAQ5qk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zw8Mc/btrADDPHX1p/DkR2u9IfK32bnGsoIAQ5qk/img.jpg&quot; width=&quot;400&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;609&quot; data-widthpercent=&quot;41.1&quot; data-is-animation=&quot;false&quot; style=&quot;width: 40.6246%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zw8Mc/btrADDPHX1p/DkR2u9IfK32bnGsoIAQ5qk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzw8Mc%2FbtrADDPHX1p%2FDkR2u9IfK32bnGsoIAQ5qk%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;940&quot; height=&quot;609&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;a href=&quot;https://www.builder.io/blog/hydration-is-pure-overhead&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hydration is Pure Overhead&lt;/a&gt; (또 다른 Pure Overhead 시리즈, &lt;a href=&quot;https://news.ycombinator.com/item?id=31101271&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HN 토론&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1.3 이벤트 핸들러를 잘 개발하기 with API&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Javascript&lt;br /&gt;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;이벤트를 사용하지 않으면 해제시켜주고, Observable을 subscribe했으면 unsubscribe를 해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;이벤트 위임(event delegation)을 사용 하는 것이 좋은 방법. [&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20160826/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;왜 이벤트 위임(delegation)을 해야 하는가?&lt;/a&gt;, &lt;a href=&quot;https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이벤트&amp;nbsp;버블링,&amp;nbsp;이벤트&amp;nbsp;캡처&amp;nbsp;그리고&amp;nbsp;이벤트&amp;nbsp;위임까지&lt;/a&gt;, &lt;a href=&quot;https://github.com/Im-D/Dev-Docs/blob/master/Javascript/Event%20Delegation.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Event Delegation&lt;/a&gt;, &lt;a href=&quot;https://www.freecodecamp.org/news/event-propagation-event-bubbling-event-catching-beginners-guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Event&amp;nbsp;Bubbling&amp;nbsp;and&amp;nbsp;Event&amp;nbsp;Catching&amp;nbsp;in&amp;nbsp;JavaScript&amp;nbsp;and&amp;nbsp;React&amp;nbsp;&amp;ndash;&amp;nbsp;A&amp;nbsp;Beginner's&amp;nbsp;Guide&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안에 10 개의 버튼이있는 div경우 각 버튼마다 하나의 핸들러 대신 하나의 이벤트 핸들러만 div 래퍼에 연결하는 방식을 쓰자.&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;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;716&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xfp0A/btqWX5kJ1jW/lDbJ9tinjMpAbpIdRP8f70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xfp0A/btqWX5kJ1jW/lDbJ9tinjMpAbpIdRP8f70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xfp0A/btqWX5kJ1jW/lDbJ9tinjMpAbpIdRP8f70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxfp0A%2FbtqWX5kJ1jW%2FlDbJ9tinjMpAbpIdRP8f70%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;1280&quot; height=&quot;716&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;716&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://en.wikipedia.org/wiki/Event_bubbling&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;a href=&quot;https://ko.reactjs.org/docs/events.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;합성 이벤트(SyntheticEvent)&lt;/a&gt;에서 자동적으로 위임을 하여 수동으로 하지 않아도 된다. [&lt;a href=&quot;https://dev.to/thawsitt/should-i-use-event-delegation-in-react-nl0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Should I use event delegation in React?&lt;/a&gt;, &lt;a href=&quot;https://velog.io/@dev-mish-mash/React%EC%97%90%EC%84%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%9C%84%EC%9E%84%EC%9D%84-%ED%86%B5%ED%95%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A6%AC%EC%8A%A4%EB%84%88-%EC%B5%9C%EC%A0%81%ED%99%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React에서&amp;nbsp;이벤트&amp;nbsp;위임을&amp;nbsp;통한&amp;nbsp;이벤트&amp;nbsp;리스너&amp;nbsp;최적화&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 이벤트 풀링(Pooling)을 하여 최적화를 하였는데 모던 브라우저에서 이득이 없어 v17부터 제거 되었다. [&lt;a href=&quot;https://github.com/facebook/react/pull/18969&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Remove event pooling in the modern system&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://velog.io/@dev-mish-mash/React%EC%97%90%EC%84%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%9C%84%EC%9E%84%EC%9D%84-%ED%86%B5%ED%95%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A6%AC%EC%8A%A4%EB%84%88-%EC%B5%9C%EC%A0%81%ED%99%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;리액트를&amp;nbsp;처음부터&amp;nbsp;배워보자.&amp;nbsp;&amp;mdash;&amp;nbsp;06.&amp;nbsp;합성&amp;nbsp;이벤트와&amp;nbsp;Event&amp;nbsp;Pooling&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;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Event/stopPropagation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;stopPropagation()&lt;/a&gt;과 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Event/preventDefault&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;preventDefault()&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;b&gt;- onload vs DOMContentLoad&lt;/b&gt;&lt;br /&gt;DOM 트리로 무언가를 시작하기 위해 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;onload&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;모든 이미지가 다운로드 될 때까지 기다릴 필요도 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;195&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXGPKP/btqW4gMMpgD/xWRz0a0Cumo6wE6ZrIk4Hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXGPKP/btqW4gMMpgD/xWRz0a0Cumo6wE6ZrIk4Hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXGPKP/btqW4gMMpgD/xWRz0a0Cumo6wE6ZrIk4Hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXGPKP%2FbtqW4gMMpgD%2FxWRz0a0Cumo6wE6ZrIk4Hk%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;657&quot; height=&quot;195&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;195&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://support.smartbear.com/alertsite/docs/monitors/metrics/web-page-load-time.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web Page Load Time&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; DOMContentLoaded&lt;/a&gt;는 onload 대신에 사용할 수 있다. [&lt;a href=&quot;https://webdir.tistory.com/515&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;문서의 로드시점 - onload, DOMContentLoaded&lt;/a&gt;, &lt;a href=&quot;https://codepen.io/LukeAskew/pen/LnJsE&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DOMContentLoaded vs load&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;자세한 정보는 Julien&amp;nbsp;Lecomte이&amp;nbsp;작성한 &quot;&lt;a href=&quot;https://yuiblog.com/blog/2007/12/20/video-lecomte/&quot;&gt;High Performance Ajax Applications&lt;/a&gt;&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;b&gt;- requestAnimationFrame(), requestIdleCallback() 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;requestAnimationFrame&lt;/a&gt;과 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;requestIdleCallback&lt;/a&gt;을 사용하면 작업을 작은 조각으로 나누어 처리할 수 있다. [&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;시각적 변화에 requestAnimationFrame 사용&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/updates/2015/08/using-requestidlecallback?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Using requestIdleCallback&lt;/a&gt;, &lt;a href=&quot;https://www.slideshare.net/deview/133-vsync&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;브라우저는 vsync를 어떻게 활용하고 있을까&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 장기 실행중인 자바스크립트가 메인 스레드를 차단하여 반응성을 낮추는 일을 막을 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4EidE/btqXb2HcjyS/I3YXm4pJr5Eba0YFHdqfHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4EidE/btqXb2HcjyS/I3YXm4pJr5Eba0YFHdqfHK/img.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;231&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4EidE/btqXb2HcjyS/I3YXm4pJr5Eba0YFHdqfHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4EidE%2FbtqXb2HcjyS%2FI3YXm4pJr5Eba0YFHdqfHK%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;1000&quot; height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb5uBL/btqXgoJVZXb/05KKsxFeT3gry7itUkscQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb5uBL/btqXgoJVZXb/05KKsxFeT3gry7itUkscQ0/img.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;231&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb5uBL/btqXgoJVZXb/05KKsxFeT3gry7itUkscQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb5uBL%2FbtqXgoJVZXb%2F05KKsxFeT3gry7itUkscQ0%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;1000&quot; height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;/div&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://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;setTimeout&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;setInterval&lt;/a&gt;을 대체해 사용하는데 &lt;span style=&quot;color: #333333;&quot;&gt;성능 향상폭이 상당하다.[&lt;a href=&quot;https://medium.com/@codesquad_yoda/%EB%82%A8%EB%8B%A4%EB%A5%B8-%EA%B0%9C%EC%84%A0%EB%B0%A9%EB%B2%95%EC%9D%84-%EB%8B%A4%EC%8B%9C-%EB%B3%B4%EC%97%AC%EC%A4%80-%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%B6%81%EC%9D%98-react-fiber-80b7ca5bd9bb&quot;&gt;남다른 개선방법을 다시 보여준 페이스북의 React Fiber&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://meetup.toast.com/posts/160&quot;&gt;100,000개의&amp;nbsp;아이템도&amp;nbsp;거뜬한&amp;nbsp;셀렉트박스&amp;nbsp;만들기&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;&lt;a href=&quot;https://github.com/gnarf/jquery-requestAnimationFrame&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;jQuery requestAnimationFrame&lt;/a&gt;은 requestAnimationFrame을 사용해 jQuery의 animate 반응성을 높이는 대표적인 라이브러리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리엑트에서 requestAnimationFrame을 사용하려면 다음글이 유용할 것이다. [&lt;a href=&quot;https://css-tricks.com/using-requestanimationframe-with-react-hooks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Using requestAnimationFrame with React Hooks&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;b&gt;- IntersectionObserver 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lazy 로딩시 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event&quot;&gt;scroll&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이벤트나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event&quot;&gt;resize&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이벤트를 받아서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect&quot;&gt;getBoundingClientRect()&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;같은 DOM API를 사용하여 뷰포트 위치를 계산하는 것이 일반적이지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;IntersectionObserver&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;를 사용하는 것이 효율적.[&lt;a href=&quot;https://developers.google.com/web/updates/2016/04/intersectionobserver?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IntersectionObserver's Coming into View&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@pks2974/intersection-observer-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-fc24789799a3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Intersection&amp;nbsp;Observer&amp;nbsp;간단&amp;nbsp;정리하기&lt;/a&gt;, &lt;a href=&quot;https://www.smashingmagazine.com/2018/01/deferring-lazy-loading-intersection-observer-api/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Now&amp;nbsp;You&amp;nbsp;See&amp;nbsp;Me:&amp;nbsp;How&amp;nbsp;To&amp;nbsp;Defer,&amp;nbsp;Lazy-Load&amp;nbsp;And&amp;nbsp;Act&amp;nbsp;With&amp;nbsp;IntersectionObserver&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;구형 브라우저를 위한 폴리필이 존재한다. [&lt;a href=&quot;https://github.com/w3c/IntersectionObserver/tree/master/polyfill&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IntersectionObserver polyfill&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;b&gt;- pointer 이벤트나 touch 이벤트 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모바일에서는 더블탭이 될수도 있고, 제스쳐와 같은 동작을 위해 클릭 이벤트는 300ms를 대기 시간으로 둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;touchstart - touchmove - touchend - mouseover - mousemove - mousedown - mouseup - click&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의 순으로 이벤트가 일어난다는 점을 고려하면 [&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Supporting_both_TouchEvent_and_MouseEvent&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Supporting both TouchEvent and MouseEvent&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Handling Gesture Events&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/fundamentals/design-and-ux/input/touch?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;사이트에 터치추가&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/edjDVx/btqW8FFvnBL/FSgPdQ4KWtsfn2kg9BNZ9k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/edjDVx/btqW8FFvnBL/FSgPdQ4KWtsfn2kg9BNZ9k/img.gif&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;851&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/edjDVx/btqW8FFvnBL/FSgPdQ4KWtsfn2kg9BNZ9k/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FedjDVx%2FbtqW8FFvnBL%2FFSgPdQ4KWtsfn2kg9BNZ9k%2Fimg.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;472&quot; height=&quot;851&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCNWkp/btqW4gTwJwa/yG3IafNTAPDzhN3443r4V0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCNWkp/btqW4gTwJwa/yG3IafNTAPDzhN3443r4V0/img.gif&quot; style=&quot;width: 49.4186%;&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;851&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCNWkp/btqW4gTwJwa/yG3IafNTAPDzhN3443r4V0/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCNWkp%2FbtqW4gTwJwa%2FyG3IafNTAPDzhN3443r4V0%2Fimg.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;472&quot; height=&quot;851&quot;/&gt;&lt;/span&gt;&lt;/div&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;click&lt;/a&gt;보다는 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/touchstart_event&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;touchstart&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/touchend_event&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;touchend&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;pre id=&quot;code_1586848358511&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const clickEvent = (() =&amp;gt; {
  if ('ontouchstart' in document.documentElement === true) return 'touchstart';
  else return 'click';
})&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;a href=&quot;https://github.com/ftlabs/fastclick&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fastclick&lt;/a&gt;과 같은 라이브러리를 사용해 응답성을 개선할 수 있다. [&lt;a href=&quot;https://developers.google.com/web/updates/2013/12/300ms-tap-delay-gone-away&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;300ms tap delay, gone away&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pointer Event&lt;/a&gt;란 터치이벤트보다 좋은 것이 나왔다. &lt;span style=&quot;color: #333333;&quot;&gt;[&lt;a href=&quot;https://techhtml.github.io/pointerevents/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;포인터 이벤트&lt;/a&gt;, &lt;a href=&quot;https://patrickhlauke.github.io/getting-touchy-presentation/&quot;&gt;getting&amp;nbsp;touchy&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://www.slideshare.net/wittemann/pointer-events-35463353&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pointer Events&lt;/a&gt;, &lt;/span&gt;&lt;a href=&quot;https://medium.com/naver-fe-platform/ios-13%EC%9D%98-pointer-%EC%9D%B4%EB%B2%A4%ED%8A%B8-da3be033a9ac&quot;&gt;iOS&amp;nbsp;13의&amp;nbsp;Pointer&amp;nbsp;이벤트&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://medium.com/better-programming/pointer-events-with-react-the-why-how-what-617a5b51dbb2&quot;&gt;Pointer&amp;nbsp;Events&amp;nbsp;in&amp;nbsp;React&amp;nbsp;&amp;mdash;&amp;nbsp;The&amp;nbsp;Why,&amp;nbsp;How,&amp;nbsp;and&amp;nbsp;What&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://christianliebel.com/2015/05/enabling-cross-platform-touch-interactions-pointer-vs-touch-events/&quot;&gt;Enabling Cross-Platform Touch Interactions: Pointer vs. Touch Events&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u7dLB/btqXb1uISMF/WubKhIMxaKhcQtWtej9vL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u7dLB/btqXb1uISMF/WubKhIMxaKhcQtWtej9vL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u7dLB/btqXb1uISMF/WubKhIMxaKhcQtWtej9vL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu7dLB%2FbtqXb1uISMF%2FWubKhIMxaKhcQtWtej9vL0%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;264&quot; height=&quot;272&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마우스, 터치 뿐만아니라 팬까지 모두 사용할 수 있도록 만든 이벤트라는데&amp;nbsp;&lt;a href=&quot;https://patrickhlauke.github.io/touch/&quot;&gt;Touch/pointer&amp;nbsp;tests&amp;nbsp;and&amp;nbsp;demos&lt;/a&gt;(&lt;a href=&quot;https://patrickhlauke.github.io/touch/tests/event-listener.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이벤트 리스너&lt;/a&gt;)&lt;span style=&quot;color: #333333;&quot;&gt;로 테스트 해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddVZMf/btqW8Gdi3nZ/qGZPCIGLRY9gkSDemTYVT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddVZMf/btqW8Gdi3nZ/qGZPCIGLRY9gkSDemTYVT1/img.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;338&quot; style=&quot;width: 47.2832%; margin-right: 10px;&quot; data-widthpercent=&quot;47.84&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddVZMf/btqW8Gdi3nZ/qGZPCIGLRY9gkSDemTYVT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddVZMf%2FbtqW8Gdi3nZ%2FqGZPCIGLRY9gkSDemTYVT1%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;496&quot; height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2Phuo/btqXgpoyLgb/VNENoPTPgDCjkTMQq0vMS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2Phuo/btqXgpoyLgb/VNENoPTPgDCjkTMQq0vMS0/img.png&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;320&quot; style=&quot;width: 51.554%;&quot; data-widthpercent=&quot;52.16&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2Phuo/btqXgpoyLgb/VNENoPTPgDCjkTMQq0vMS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2Phuo%2FbtqXgpoyLgb%2FVNENoPTPgDCjkTMQq0vMS0%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;512&quot; height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;비교표와 순서&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘을 대체 가능할 뿐만아니라 클릭 이벤트의 300ms 지연도 막을 수 있다.(우선순위가 가장 높음)&lt;/p&gt;
&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/jquery/PEP&quot;&gt;PEP(Pointer Events Polyfill)&lt;/a&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;3.1.4 로드 후(Post-load) 구성 요소&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;content&lt;br /&gt;페이지를 곰곰히 살피다보면 &quot;처음에 페이지를 렌더링하기 위해 반드시 필요한 것은 무엇인가?&quot;에 대한&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 style=&quot;font-size: 1.12em;&quot; 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;JavaScript는 onload 이벤트 전후에 분할하기에 이상적인 후보이다.&lt;/p&gt;
&lt;pre id=&quot;code_1587530331394&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function afterPageLoad(){
   console.log('after page load');
}
 
window.onload = function afterPageLoad();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;예를 들어, 드래그 앤 드롭 및 애니메이션을 수행하는 JavaScript&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;Post load의 후보를 찾을만한 다른 장소로는 fold 아래에 숨겨진 콘텐츠 (사용자 작업 후에 표시되는 콘텐츠)와 이미지가 있다.&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;이 경우 점진적 향상이라는 아이디어는 JavaScript를 사용하여 UX을 향상시킬 수 있지만, JavaScript 없이도 페이지가 작동하는지 확인해야한다는 것을 뜻한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 페이지가 제대로 작동하는지 확인한 후 드래그 앤 드롭 및 애니메이션과 같은 부가기능을 제공하는 Post Load 스크립트로 페이지를 향상시킬 수 있다.&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;3.1.5 Flexbox, Grid 활용&lt;/h4&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; CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날에는 CSS로 레이아웃을 구성하는 방법은 [&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/Introduction&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;레이아웃&amp;nbsp;입문서&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;레거시&amp;nbsp;조판&amp;nbsp;메서드&lt;/a&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;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/Building_blocks/%EC%83%81%EC%9E%90_%EB%AA%A8%EB%8D%B8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;박스모델&lt;/a&gt; [&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;기본&amp;nbsp;박스&amp;nbsp;모델&amp;nbsp;입문&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/%EC%9C%84%EC%B9%98%EC%9E%A1%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;포지션&lt;/a&gt; [&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/position&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;position 속성&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/Floats&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Floats&lt;/a&gt; [&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/float&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;float 속성&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 이용하였다. (더 옛날은 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table&quot;&gt;Table&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;그러나 최신 CSS의 방식을 사용하면 훨씬 빠르다. [&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing?hl=ko#%EC%9D%B4%EC%A0%84_%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83_%EB%AA%A8%EB%8D%B8_%EB%8C%80%EC%8B%A0_flexbox_%EC%82%AC%EC%9A%A9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 레이아웃 모델 대신 Flexbox 사용&lt;/a&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;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/Flexbox&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Flexbox&lt;/a&gt; [&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Flexible_Box_Layout&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Flexible Box Layout&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/CSS_layout/Grids&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;그리드&lt;/a&gt; [&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Grid_Layout&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS 그리드 레이아웃&lt;/a&gt;]&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;다음은 1300개의 상자들의 레이아웃을 짠 것.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7O4Db/btqW4gTwJyW/otmejuLlsrBDDR7jG9cKYk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7O4Db/btqW4gTwJyW/otmejuLlsrBDDR7jG9cKYk/img.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;870&quot; style=&quot;width: 48.2558%; margin-right: 10px;&quot; data-widthpercent=&quot;48.82&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7O4Db/btqW4gTwJyW/otmejuLlsrBDDR7jG9cKYk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7O4Db%2FbtqW4gTwJyW%2FotmejuLlsrBDDR7jG9cKYk%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;1280&quot; height=&quot;870&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhpE5I/btqWX6qrwzK/cmGywAlKdnvP80QpxxTMWk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhpE5I/btqWX6qrwzK/cmGywAlKdnvP80QpxxTMWk/img.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;830&quot; style=&quot;width: 50.5814%;&quot; data-widthpercent=&quot;51.18&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhpE5I/btqWX6qrwzK/cmGywAlKdnvP80QpxxTMWk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhpE5I%2FbtqWX6qrwzK%2FcmGywAlKdnvP80QpxxTMWk%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;1280&quot; height=&quot;830&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;3.544ms로 14.289 ms보다 훨씬 빠름&lt;/p&gt;
&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;레거시한 방법은 더 많은 DOM을 요구하거나, 더 많은 마진/패딩을 요구하기 때문이다.&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;3.1.6 Contain 속성 활용하기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/contain&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;contain&lt;/a&gt;은 웹페이지에서 선택된 하위 트리를 문서의 나머지 영역과 분리하는 기능을 가지고 있다. [&lt;a href=&quot;https://wit.nts-corp.com/2019/07/08/5594&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Containment Module&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/updates/2016/06/css-containment&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Containment in Chrome 52&lt;/a&gt;, &lt;a href=&quot;https://www.smashingmagazine.com/2019/12/browsers-containment-css-contain-property/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Helping Browsers Optimize With The CSS Contain Property&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@johan.isaksson/how-i-made-googles-data-grid-scroll-10x-faster-with-one-line-of-css-78cb1e8d9cb1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How I made Google's data grid scroll 10x faster with one line of CSS&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;첫번째 참조 링크에 따르면 3~6ms에서 0.3~1.9ms로 약 2~10배까지 차이가 난다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI7MBm/btqW4hkCT54/vSqFfoOdFu2hj9RA1gwL9k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI7MBm/btqW4hkCT54/vSqFfoOdFu2hj9RA1gwL9k/img.gif&quot; width=&quot;473&quot; height=&quot;637&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;637&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI7MBm/btqW4hkCT54/vSqFfoOdFu2hj9RA1gwL9k/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI7MBm%2FbtqW4hkCT54%2FvSqFfoOdFu2hj9RA1gwL9k%2Fimg.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;473&quot; height=&quot;637&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MVB5v/btqWWt7vONJ/F0BfUgl7awpbtyKSl8WPj1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MVB5v/btqWWt7vONJ/F0BfUgl7awpbtyKSl8WPj1/img.gif&quot; width=&quot;473&quot; height=&quot;637&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;637&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;true&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MVB5v/btqWWt7vONJ/F0BfUgl7awpbtyKSl8WPj1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMVB5v%2FbtqWWt7vONJ%2FF0BfUgl7awpbtyKSl8WPj1%2Fimg.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;473&quot; height=&quot;637&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;텍스트 요소를 바꿔 리플로우 발생[&lt;a href=&quot;https://codepen.io/witblog/pen/wLbRrj&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKMzQb/btqW1tez0ap/qTbCm7fKPkE68bm8gkhmk1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKMzQb/btqW1tez0ap/qTbCm7fKPkE68bm8gkhmk1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKMzQb/btqW1tez0ap/qTbCm7fKPkE68bm8gkhmk1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKMzQb%2FbtqW1tez0ap%2FqTbCm7fKPkE68bm8gkhmk1%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;1024&quot; height=&quot;464&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;464&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strict: size + layout + paint&lt;/li&gt;
&lt;li&gt;content: size + paint&lt;/li&gt;
&lt;li&gt;size: 상위요소는 하위요소의 크기와 독립적임&lt;/li&gt;
&lt;li&gt;layout: 하위요소는 상위요소 안에서만 움직임&lt;/li&gt;
&lt;li&gt;style: 요소와 해당 요소에 영향을 끼치지만, 그 이상 벗어나진 않음(서로 영향을 끼치지 않음, 독립적)&lt;/li&gt;
&lt;li&gt;paint: 하위요소는 상위요소 안에서만 보임&lt;/li&gt;
&lt;/ul&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;h4 data-ke-size=&quot;size20&quot;&gt;3.1.7 content-visibility 속성 활용하기&lt;/h4&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;span&gt;&amp;nbsp;&lt;/span&gt;CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면 밖 컨텐츠의 렌더링을 생략하여 초기 로드 속도를 개선 하는 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/content-visibility&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;content-visibility&lt;/a&gt; 속성이 Chrome 85에 적용되었다. [&lt;a href=&quot;https://web.dev/content-visibility/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;랜더링 성능을 향상 시키는 새로운 CSS 속성 css-visibility&lt;/a&gt;(&lt;a href=&quot;https://wit.nts-corp.com/2020/09/11/6223&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;번역&lt;/a&gt;), &lt;a href=&quot;https://css-tricks.com/almanac/properties/c/content-visibility/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Tricks content-visibility&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;pre id=&quot;code_1638419543614&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.story {
  content-visibility: auto;
  contain-intrinsic-size: 1000px; /* Explained in the next section. */
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;709&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLTyHO/btrmMhsj8l6/iYensQWVZpbZAVsdGuLqLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLTyHO/btrmMhsj8l6/iYensQWVZpbZAVsdGuLqLk/img.png&quot; data-alt=&quot;232ms에서 30ms&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLTyHO/btrmMhsj8l6/iYensQWVZpbZAVsdGuLqLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLTyHO%2FbtrmMhsj8l6%2FiYensQWVZpbZAVsdGuLqLk%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;1024&quot; height=&quot;709&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;709&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;232ms에서 30ms&lt;/figcaption&gt;
&lt;/figure&gt;
&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;따라서 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/contain-intrinsic-size&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;contain-intrinsic-size&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;hidden 속성 잘 이용하면 성능향상에 도움을 줄 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;display: none: 숨기며 렌더링 상태를 제거. 나중에 다시 표시하면 새 요소를 렌더링 하는 것만큼 비용이 듦&lt;/li&gt;
&lt;li&gt;visibility: hidden: 숨기며 렌더링 상태는 유지. 요소를 실제로 제거하지는 않기 때문에 공간을 차지하고 클릭할 수 있으며, 렌더링 상태가 업데이트 됨&lt;/li&gt;
&lt;li&gt;content-visibility: hidden: 숨기며 렌더링 상태는 유지. 상태를 변경할 일이 생기면 화면에 표시될 때만 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;content-visibility: hidden은 바로 다음에 나올 대형 리스트 최적화에 사용하면 좋을 것으로 보인다.&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;3.1.8 대형/연속적 리스트 최적화&lt;/h4&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; Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글 검색시 인피니티 스크롤, 페이스북이나 인스타그램의 타임라인, 핀터레스트의 Masonry 레이아웃은 끝없는 데이터를 연속적으로 보여주는 예다. [&lt;a href=&quot;https://web.dev/virtualize-long-lists-react-window/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Virtualize&amp;nbsp;large&amp;nbsp;lists&amp;nbsp;with&amp;nbsp;react-window&lt;/a&gt;, &lt;a href=&quot;https://github.blog/2021-03-25-how-github-actions-renders-large-scale-logs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;GitHub&amp;nbsp;Actions&amp;nbsp;renders&amp;nbsp;large-scale&amp;nbsp;logs&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이맥스의 &lt;a href=&quot;https://www.emacswiki.org/emacs/VLF&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VLF&lt;/a&gt;(&lt;a href=&quot;https://github.com/m00natic/vlfi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VLFI&lt;/a&gt;)가 대표적인 예인데 OS에서 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B0%80%EC%83%81_%EB%A9%94%EB%AA%A8%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;가상 메모리&lt;/a&gt;의 페이징 기법처럼 사용하여 커다란 데이터를 필요한 만큼만(Lazy하게) 다룰 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;585&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc0dbJ/btqXgpoyLvP/6suUG2XwYv16uJaGPa3hs1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc0dbJ/btqXgpoyLvP/6suUG2XwYv16uJaGPa3hs1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc0dbJ/btqXgpoyLvP/6suUG2XwYv16uJaGPa3hs1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc0dbJ%2FbtqXgpoyLvP%2F6suUG2XwYv16uJaGPa3hs1%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;733&quot; height=&quot;585&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;585&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/9_VirtualMemory.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Virtual&amp;nbsp;Memory&lt;/a&gt;(&lt;a href=&quot;https://twinw.tistory.com/106&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;약간 더 직관적으로 바라보고, UX를 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 작업을 페이지와 프레임단위로 사용자가 사용할 페이지들만 메모리에 올려놓고, 보여주는 것은 뷰에서 현재 사용할(Visible Window, Viewport) 또는 곧 사용할 리스트(Realization Window)만 보여주자는 이야기다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Realization Window처럼 리스트 여백을 남겨두는 이유는 사용자가 스크롤할 때 곧장 보여줄 수 있기 때문.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cL3Kna/btqXb03EYsc/5kZy4VkPgYfyZPG1MaweK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cL3Kna/btqXb03EYsc/5kZy4VkPgYfyZPG1MaweK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cL3Kna/btqXb03EYsc/5kZy4VkPgYfyZPG1MaweK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcL3Kna%2FbtqXb03EYsc%2F5kZy4VkPgYfyZPG1MaweK1%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;495&quot; height=&quot;610&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.microsoft.com/ko-kr/archive/blogs/alainza/listview-basics-and-virtualization-concepts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ListView&amp;nbsp;basics&amp;nbsp;and&amp;nbsp;virtualization&amp;nbsp;concepts&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;어차피 Realized View까지 한정된 갯수의 아이템만 사용할 것이라면, 각 Item을 매번 재생성하는 것은 비효율적이지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드의 ReycylerView나 IOS의 UICollectionView는 Item을 재사용(recyler, reuse)한다. [&lt;a href=&quot;https://wooooooak.github.io/android/2019/03/28/recycler_view/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RecyclerView(리사이클러뷰)의 원리와 사용법(feat. Kotlin)&lt;/a&gt;, &lt;a href=&quot;https://recipes4dev.tistory.com/154&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;안드로이드 리사이클러뷰 기본 사용법. (Android RecyclerView)&lt;/a&gt;, &lt;a href=&quot;https://www.andreasjakl.com/kotlin-recyclerview-for-high-performance-lists-in-android/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kotlin &amp;amp; RecyclerView for High Performance Lists in Android&lt;/a&gt;, &lt;a href=&quot;https://developer.android.com/guide/topics/ui/layout/recyclerview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RecyclerView로&amp;nbsp;목록&amp;nbsp;만들기&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biumX9/btqW1r8SbxI/2VAWMkpTU6F9ZSQFkrhI21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biumX9/btqW1r8SbxI/2VAWMkpTU6F9ZSQFkrhI21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biumX9/btqW1r8SbxI/2VAWMkpTU6F9ZSQFkrhI21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiumX9%2FbtqW1r8SbxI%2F2VAWMkpTU6F9ZSQFkrhI21%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;700&quot; height=&quot;576&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@kish.imss/listview-vs-recyclerview-2965d50b363&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ListView&amp;nbsp;vs&amp;nbsp;RecyclerView&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;보여지는 각 Item을 View Holder 객체에 저장해두고, View Holder 내부에서 바꿔야 할 데이터들만 바인딩하여 바꿔치기만하면, 매번 Item을 제거하고 다시 생성할 필요가 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cedZlF/btqXj7HVhrJ/fmfbpfzfmDvxEFmFzkf1G1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cedZlF/btqXj7HVhrJ/fmfbpfzfmDvxEFmFzkf1G1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cedZlF/btqXj7HVhrJ/fmfbpfzfmDvxEFmFzkf1G1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcedZlF%2FbtqXj7HVhrJ%2FfmfbpfzfmDvxEFmFzkf1G1%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;685&quot; height=&quot;318&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://pomprogrammer.blogspot.com/2016/01/viewholder-pattern.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Using the ViewHolder Pattern&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;a href=&quot;https://devblogs.microsoft.com/xamarin/creating-highly-performant-smooth-scrolling-android-listviews/&quot;&gt;Tips&amp;nbsp;&amp;amp;&amp;nbsp;Tricks&amp;nbsp;for&amp;nbsp;Highly&amp;nbsp;Performing&amp;nbsp;Android&amp;nbsp;ListViews&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;a href=&quot;https://blog.canapio.com/112&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;iOS10의 프리-패칭 API로 부드러운 스크롤 증진하기&lt;/a&gt;, &lt;a href=&quot;https://velog.io/@hanseop95/%EB%B2%88%EC%97%AD-UICollectionView-Tutorial-Prefetching-APIs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;UICollectionView&amp;nbsp;Tutorial:&amp;nbsp;Prefetching&amp;nbsp;APIs&lt;/a&gt;, &lt;a href=&quot;https://ontheswift.tistory.com/23&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;UICollectionViewCell의&amp;nbsp;LifeCycle과&amp;nbsp;PreFetching&lt;/a&gt;, &lt;a href=&quot;https://texturegroup.org/docs/intelligent-preloading.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Texture - Intelligent Preloading&lt;/a&gt;(&lt;a href=&quot;https://texture-kr.gitbook.io/wiki/newbie-guide/intelligent-preloading&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gap13/btqXj8z25sE/yccSPTWwHTb7W2GByk0qs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gap13/btqXj8z25sE/yccSPTWwHTb7W2GByk0qs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gap13/btqXj8z25sE/yccSPTWwHTb7W2GByk0qs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGap13%2FbtqXj8z25sE%2FyccSPTWwHTb7W2GByk0qs0%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;700&quot; height=&quot;297&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Data List: 물리적 메모리&lt;/li&gt;
&lt;li&gt;Adapter: 메모리 맵&lt;/li&gt;
&lt;li&gt;ViewHolder: 페이지&lt;/li&gt;
&lt;/ul&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;React의 경우 다음을 사용가능하다. [&lt;a href=&quot;https://blog.logrocket.com/windowing-wars-react-virtualized-vs-react-window/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Windowing&amp;nbsp;wars:&amp;nbsp;React-virtualized&amp;nbsp;vs.&amp;nbsp;react-window&lt;/a&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;a href=&quot;https://github.com/bvaughn/react-window&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React-Window&lt;/a&gt;: 보이는 것들만 로딩&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bvaughn/react-virtualized&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React-Virtualized&lt;/a&gt;: React-Window보다 살짝 더 무거움&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Flipkart/recyclerlistview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Recylerlistview&lt;/a&gt;: 재사용 가능, ReactNative 기반이지만 웹에서도 사용가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 플랫폼의 경우 Facebook의 &lt;a href=&quot;https://github.com/facebook/litho&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Litho&lt;/a&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;a href=&quot;https://engineering.fb.com/2016/10/26/android/components-for-android-a-declarative-framework-for-efficient-uis/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Components&amp;nbsp;for&amp;nbsp;Android:&amp;nbsp;A&amp;nbsp;declarative&amp;nbsp;framework&amp;nbsp;for&amp;nbsp;efficient&amp;nbsp;UIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering.fb.com/2017/09/26/android/multithreaded-rendering-on-android-with-litho-and-infer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Multithreaded&amp;nbsp;rendering&amp;nbsp;on&amp;nbsp;Android&amp;nbsp;with&amp;nbsp;Litho&amp;nbsp;and&amp;nbsp;Infer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering.fb.com/2017/10/26/android/open-sourcing-sections-declarative-data-handling-for-litho-lists/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Open-sourcing&amp;nbsp;Sections:&amp;nbsp;Declarative&amp;nbsp;data&amp;nbsp;handling&amp;nbsp;for&amp;nbsp;Litho&amp;nbsp;lists&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering.fb.com/2018/01/31/android/improving-android-video-on-news-feed-with-litho/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Improving&amp;nbsp;Android&amp;nbsp;video&amp;nbsp;on&amp;nbsp;News&amp;nbsp;Feed&amp;nbsp;with&amp;nbsp;Litho&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1.9 React 최적화&lt;/h4&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; Javascript&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서는 리엑트의 렌더링성능을 최적화시키는 방법들에 대해 다루려한다. [&lt;a href=&quot;https://medium.com/myheritage-engineering/how-to-greatly-improve-your-react-app-performance-e70f7cbbb5f6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How to greatly improve your React app performance&lt;/a&gt;, &lt;a href=&quot;https://medium.com/vingle-tech-blog/react-hook-ec3f25c2d8fa&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React&amp;nbsp;렌더링&amp;nbsp;이해&amp;nbsp;및&amp;nbsp;최적화&amp;nbsp;(With&amp;nbsp;Hook)&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://overreacted.io/ko/react-as-a-ui-runtime/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;UI 런타임으로서의 React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://overreacted.io/ko/writing-resilient-components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;탄력적인 컴포넌트 작성하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://overreacted.io/ko/how-are-function-components-different-from-classes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;함수형 컴포넌트와 클래스, 어떤 차이가 존재할까?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://overreacted.io/ko/a-complete-guide-to-useeffect/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;useEffect 완벽 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://overreacted.io/making-setinterval-declarative-with-react-hooks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Hooks로 setInterval 선언적 만들기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리엑트 Core 팀 개발자인 Dan Abramov의 글이니 신뢰할만하다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://bogdan-lyashenko.github.io/Under-the-hood-ReactJS/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Under the hood ReactJS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/react-render-cheat-sheet/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A Visual Guide to React Rendering - Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/react-render-always-rerenders/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Visual&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;React&amp;nbsp;Rendering&amp;nbsp;-&amp;nbsp;It&amp;nbsp;Always&amp;nbsp;Re-renders&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/react-render-props/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Visual&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;React&amp;nbsp;Rendering&amp;nbsp;-&amp;nbsp;Props&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/react-render-usememo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Visual&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;React&amp;nbsp;Rendering&amp;nbsp;-&amp;nbsp;useMemo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/react-render-usecallback/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Visual&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;React&amp;nbsp;Rendering&amp;nbsp;-&amp;nbsp;useCallback&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/react-render-context/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A Visual Guide to React Rendering - Context&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/react-render-dom/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Visual&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;React&amp;nbsp;Rendering&amp;nbsp;-&amp;nbsp;DOM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/react-render-refs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Visual&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;React&amp;nbsp;Rendering&amp;nbsp;-&amp;nbsp;Refs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/useeffect/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A Visual Guide to React Rendering - useEffect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/useeffect-cleanups/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A Visual Guide to React Rendering - useEffect Cleanups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/react-javascript-first-class-functions/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Visual&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;Javascript&amp;nbsp;for&amp;nbsp;React&amp;nbsp;developers&amp;nbsp;-&amp;nbsp;First-class&amp;nbsp;functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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&gt;&amp;nbsp;&lt;/span&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://ko.reactjs.org/docs/state-and-lifecycle.html&quot;&gt;라이프 사이클&lt;/a&gt;이 함수형 컴포넌트에는 없기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/hooks-intro.html&quot;&gt;Hooks&lt;/a&gt;를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라이프사이클과 Hooks의 관계는 대략 다음과 같다.&lt;/p&gt;
&lt;div data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/616396328590786560&quot; data-did=&quot;860c272ef1a1d1a10a12bdd437c251e669e707d4&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/616396328590786560/%ED%8B%B0%EC%8A%A4%ED%86%A0%EB%A6%AC-%EA%B8%80%EC%9D%84-%EC%A0%81%EC%9D%84-%EB%95%8C-%EC%95%84%EB%AC%B4%EB%9E%98%EB%8F%84-%EB%94%B0%EB%A1%9C-%EB%B6%84%EB%A6%AC%ED%95%B4-%EC%A0%81%EB%8A%94%EA%B2%8C-%EB%82%98%EC%9D%84-%EB%93%AF%ED%95%98%EC%97%AC-%EC%9E%91%EC%84%B1%ED%95%98%EA%B2%8C-%EB%90%98%EC%97%88%EB%8B%A4&quot;&gt;https://black7375.tumblr.com/post/616396328590786560/&lt;/a&gt;
&lt;figure id=&quot;og_1651417802081&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;라이프사이클과 클래스 컴포넌트&quot; data-og-description=&quot;티스토리 글을 적을 때 아무래도 따로 분리해 적는게 나을 듯하여 작성하게 되었다. 라이프사이클과 클래스 컴포넌트 react-lifecycle-methods-diagram - Mount 순서 constructor(props): 컴포넌트를 새로 만들때&quot; data-og-host=&quot;black7375.tumblr.com&quot; data-og-source-url=&quot;https://black7375.tumblr.com/post/616396328590786560/%ED%8B%B0%EC%8A%A4%ED%86%A0%EB%A6%AC-%EA%B8%80%EC%9D%84-%EC%A0%81%EC%9D%84-%EB%95%8C-%EC%95%84%EB%AC%B4%EB%9E%98%EB%8F%84-%EB%94%B0%EB%A1%9C-%EB%B6%84%EB%A6%AC%ED%95%B4-%EC%A0%81%EB%8A%94%EA%B2%8C-%EB%82%98%EC%9D%84-%EB%93%AF%ED%95%98%EC%97%AC-%EC%9E%91%EC%84%B1%ED%95%98%EA%B2%8C-%EB%90%98%EC%97%88%EB%8B%A4&quot; data-og-url=&quot;https://black7375.tumblr.com/post/616396328590786560/%ED%8B%B0%EC%8A%A4%ED%86%A0%EB%A6%AC-%EA%B8%80%EC%9D%84-%EC%A0%81%EC%9D%84-%EB%95%8C-%EC%95%84%EB%AC%B4%EB%9E%98%EB%8F%84-%EB%94%B0%EB%A1%9C-%EB%B6%84%EB%A6%AC%ED%95%B4-%EC%A0%81%EB%8A%94%EA%B2%8C-%EB%82%98%EC%9D%84-%EB%93%AF%ED%95%98%EC%97%AC-%EC%9E%91%EC%84%B1%ED%95%98%EA%B2%8C-%EB%90%98%EC%97%88%EB%8B%A4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/db2h1C/hyOdwXJ46e/czkwIyEQfh79NW3oCDaiN1/img.png?width=1114&amp;amp;height=643&amp;amp;face=0_0_1114_643,https://scrap.kakaocdn.net/dn/GDrY9/hyOdvxLtOl/Y0QMonAoIxRuusWExKvKD0/img.png?width=967&amp;amp;height=741&amp;amp;face=0_0_967_741,https://scrap.kakaocdn.net/dn/oQBnE/hyOdwDp3Gs/9mItyfpkjfB03GbW8IvVeK/img.jpg?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/616396328590786560/%ED%8B%B0%EC%8A%A4%ED%86%A0%EB%A6%AC-%EA%B8%80%EC%9D%84-%EC%A0%81%EC%9D%84-%EB%95%8C-%EC%95%84%EB%AC%B4%EB%9E%98%EB%8F%84-%EB%94%B0%EB%A1%9C-%EB%B6%84%EB%A6%AC%ED%95%B4-%EC%A0%81%EB%8A%94%EA%B2%8C-%EB%82%98%EC%9D%84-%EB%93%AF%ED%95%98%EC%97%AC-%EC%9E%91%EC%84%B1%ED%95%98%EA%B2%8C-%EB%90%98%EC%97%88%EB%8B%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tumblr.com/post/616396328590786560/%ED%8B%B0%EC%8A%A4%ED%86%A0%EB%A6%AC-%EA%B8%80%EC%9D%84-%EC%A0%81%EC%9D%84-%EB%95%8C-%EC%95%84%EB%AC%B4%EB%9E%98%EB%8F%84-%EB%94%B0%EB%A1%9C-%EB%B6%84%EB%A6%AC%ED%95%B4-%EC%A0%81%EB%8A%94%EA%B2%8C-%EB%82%98%EC%9D%84-%EB%93%AF%ED%95%98%EC%97%AC-%EC%9E%91%EC%84%B1%ED%95%98%EA%B2%8C-%EB%90%98%EC%97%88%EB%8B%A4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/db2h1C/hyOdwXJ46e/czkwIyEQfh79NW3oCDaiN1/img.png?width=1114&amp;amp;height=643&amp;amp;face=0_0_1114_643,https://scrap.kakaocdn.net/dn/GDrY9/hyOdvxLtOl/Y0QMonAoIxRuusWExKvKD0/img.png?width=967&amp;amp;height=741&amp;amp;face=0_0_967_741,https://scrap.kakaocdn.net/dn/oQBnE/hyOdwDp3Gs/9mItyfpkjfB03GbW8IvVeK/img.jpg?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080');&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;라이프사이클과 클래스 컴포넌트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;티스토리 글을 적을 때 아무래도 따로 분리해 적는게 나을 듯하여 작성하게 되었다. 라이프사이클과 클래스 컴포넌트 react-lifecycle-methods-diagram - Mount 순서 constructor(props): 컴포넌트를 새로 만들때&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tumblr.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한점: 함수형 컴포넌트는 &quot;라이프사이클&quot; 개념이 전혀 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&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;b&gt;- 컴포넌트와 State 구조&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깊이 있는 컴포넌트까지 너무 많은 Props를 전달하는 것은 쓸데없이 재렌더링이 일어날 수 있으며 성능에 영향을 미칠수도 있다. [&lt;a href=&quot;https://netflixtechblog.com/crafting-a-high-performance-tv-user-interface-using-react-3350e5a6ad3b&quot;&gt;Crafting a high-performance TV user interface using React&lt;/a&gt;, &lt;a href=&quot;https://frontarm.com/james-k-nelson/react-context-performance/&quot;&gt;Avoiding&amp;nbsp;unnecessary&amp;nbsp;renders&amp;nbsp;with&amp;nbsp;React&amp;nbsp;context&lt;/a&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://velog.io/@public_danuel/trendy-react-context&quot;&gt;React&amp;nbsp;Context&amp;nbsp;알아보기&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;853&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/69nhx/btrA5blRmtt/1S1Lwmqvtvc81KXcXvKZcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/69nhx/btrA5blRmtt/1S1Lwmqvtvc81KXcXvKZcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/69nhx/btrA5blRmtt/1S1Lwmqvtvc81KXcXvKZcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F69nhx%2FbtrA5blRmtt%2F1S1Lwmqvtvc81KXcXvKZcK%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;700&quot; height=&quot;390&quot; data-origin-width=&quot;853&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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://ko.reactjs.org/docs/context.html&quot;&gt;Context&lt;/a&gt;를 사용하면 state를 바로 전달할 수 있어 쓸데없이 렌더링이 이루어지는 것을 막을 수 있겠구나고 생각 할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;625&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK1rzN/btqWWsOd51a/yxYwC2BfE4WXQLbter6hxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK1rzN/btqWWsOd51a/yxYwC2BfE4WXQLbter6hxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK1rzN/btqWWsOd51a/yxYwC2BfE4WXQLbter6hxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK1rzN%2FbtqWWsOd51a%2FyxYwC2BfE4WXQLbter6hxk%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;1280&quot; height=&quot;625&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;625&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 Context API는 Context 값에 의존 할 경우, &lt;b&gt;다른 값이 변경되도 리렌더링&lt;/b&gt;이 발생한다. [&lt;a href=&quot;https://ridicorp.com/story/how-to-use-redux-in-ridi/&quot;&gt;리덕스&amp;nbsp;잘&amp;nbsp;쓰고&amp;nbsp;계시나요?&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 관련이 없는 상태라면 Context를 따로 분리해줘야 하며, 위 글과 같이 상태를 위한 Context와 상태 업데이트를 위한 Context를 분리해야하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 상태 업데이트를 분리하도록 만들어야 하는게 올바른 패턴이라는 점에서 약간의 설계미스가 있는게 아닌가 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context API 내부의 state들이 리엑트 state로 관리되어 깔끔하긴 하다만 컴포넌트 트리에서 분리되는게 좋지않나..&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://yahooeng.tumblr.com/post/152078809581/refactoring-components-for-redux-performance&quot;&gt;Refactoring Components for Redux Performance&lt;/a&gt;, &lt;a href=&quot;https://reactrocket.com/post/react-redux-optimization/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Redux isn't slow, you're just doing it wrong - An optimization guide&lt;/a&gt;, &lt;a href=&quot;https://overreacted.io/ko/before-you-memo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;memo()를 하기 전에&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC9uDY/btrATSUGbau/KsspCDcbBwCyyO5eBxR851/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC9uDY/btrATSUGbau/KsspCDcbBwCyyO5eBxR851/img.png&quot; width=&quot;452&quot; height=&quot;344&quot; data-orig-height=&quot;344&quot; data-orig-width=&quot;452&quot; data-origin-width=&quot;452&quot; data-origin-height=&quot;344&quot; data-is-animation=&quot;false&quot; style=&quot;width: 41.7243%; margin-right: 10px;&quot; data-widthpercent=&quot;42.22&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC9uDY/btrATSUGbau/KsspCDcbBwCyyO5eBxR851/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC9uDY%2FbtrATSUGbau%2FKsspCDcbBwCyyO5eBxR851%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;452&quot; height=&quot;344&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbCjdv/btrAZdXledF/ogSLJuknlKqXJSvK6i2YfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbCjdv/btrAZdXledF/ogSLJuknlKqXJSvK6i2YfK/img.png&quot; width=&quot;500&quot; height=&quot;278&quot; data-orig-height=&quot;293&quot; data-orig-width=&quot;527&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;278&quot; data-is-animation=&quot;false&quot; style=&quot;width: 57.1129%;&quot; data-widthpercent=&quot;57.78&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbCjdv/btrAZdXledF/ogSLJuknlKqXJSvK6i2YfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbCjdv%2FbtrAZdXledF%2FogSLJuknlKqXJSvK6i2YfK%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;500&quot; height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;리팩토링 전, 후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파생된 상태의 경우 &lt;a href=&quot;https://github.com/reduxjs/reselect&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;reselect&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;상태를 데이터베이스처럼 생각하고, &lt;a href=&quot;https://redux.js.org/usage/structuring-reducers/normalizing-state-shape&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;정규화&lt;/a&gt;를 하자. [&lt;a href=&quot;https://jbee.io/react/react-redux-normalize/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Redux에서&amp;nbsp;Normalize&amp;nbsp;다루기&lt;/a&gt;, &lt;a href=&quot;https://dataonair.or.kr/db-tech-reference/d-guide/sql/?mod=document&amp;amp;uid=332&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;정규화와&amp;nbsp;성능&lt;/a&gt;, &lt;a href=&quot;https://dataonair.or.kr/db-tech-reference/d-guide/sql/?mod=document&amp;amp;uid=333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;반정규화와 성능&lt;/a&gt;]&lt;br /&gt;관심사 분리가 자연적으로 되며, 평평하게(Flatten)하게 유지됨&lt;br /&gt;단, 너무 심한 정규화는 읽기 성능에 지장을 줄 수도 있으며, 데이터가 크다면 &lt;a href=&quot;https://gmlwjd9405.github.io/2018/09/24/db-partitioning.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파티셔닝&lt;/a&gt;도 고려하자.&lt;/li&gt;
&lt;li&gt;컴포넌트의 상태구독 계층을 분리한다.&lt;br /&gt;모든 값이 공유되지 않도록 하며, 상태는 아래로 내리고 내용물은 위로 끌어올린다.&lt;/li&gt;
&lt;li&gt;상태 업데이트는 최소한만 하며, 파생된 상태의 경우 reselector등으로 메모이징을 활용한다.&lt;/li&gt;
&lt;/ol&gt;
&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_1651450536214&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
const state = {
  articles: [{
    comments: [{
      users: [{
      }]
    }]
  }],
  ...
};

// Good
const state = {
  articles: [{
    ...
  }],
  comments: [{
    articleId: ..,
    userId: ...,
    ...
  }],
  users: [{
    ...
  }]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; 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;pre id=&quot;code_1651450319129&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
const BigComponent = ({ a, b, c, d }) =&amp;gt; (
  &amp;lt;div&amp;gt;
    &amp;lt;CompA a={a} /&amp;gt;
    &amp;lt;CompB b={b} /&amp;gt;
    &amp;lt;CompC c={c} /&amp;gt;
  &amp;lt;/div&amp;gt;
);

const ConnectedBigComponent = connect(
  ({ a, b, c }) =&amp;gt; ({ a, b, c })
);

// Good
const ConnectedA = connect(CompA, ({ a }) =&amp;gt; ({ a }));
const ConnectedB = connect(CompB, ({ b }) =&amp;gt; ({ b }));
const ConnectedC = connect(CompC, ({ c }) =&amp;gt; ({ c }));

const BigComponent = () =&amp;gt; (
  &amp;lt;div&amp;gt;
    &amp;lt;ConnectedA /&amp;gt;
    &amp;lt;ConnectedB /&amp;gt;
    &amp;lt;ConnectedC /&amp;gt;
  &amp;lt;/div&amp;gt;
);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; 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_1651451126116&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
export default function App() {
  let [color, setColor] = useState('red');
  return (
    &amp;lt;div style={{ color }}&amp;gt;
      &amp;lt;input value={color} onChange={(e) =&amp;gt; setColor(e.target.value)} /&amp;gt;
      &amp;lt;p style={{ color }}&amp;gt;Hello, world!&amp;lt;/p&amp;gt;
      &amp;lt;ExpensiveTree /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}


// Good
export default function App() {
  return (
    &amp;lt;ColorPicker&amp;gt;
      &amp;lt;p&amp;gt;Hello, world!&amp;lt;/p&amp;gt;
      &amp;lt;ExpensiveTree /&amp;gt;
    &amp;lt;/ColorPicker&amp;gt;
  );
}

function ColorPicker({ children }) {
  let [color, setColor] = useState(&quot;red&quot;); // 1. 상태를 내리기
  return (
    &amp;lt;div style={{ color }}&amp;gt;
      &amp;lt;input value={color} onChange={(e) =&amp;gt; setColor(e.target.value)} /&amp;gt;
      {children}                           // 2. 내용물은 끌어올리기
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; 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;pre id=&quot;code_1651452126031&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
const ListItem = connect(
  ({ selectedItem }) =&amp;gt; ({ selectedItem })
)(SimpleListItem);

// Good
const ListItem = connect(
  ({ selectedItem }, { itemId }) =&amp;gt; ({ isSelected: selectedItem === itemId })
)(SimpleListItem);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; 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://www.smashingmagazine.com/2021/08/react-children-iteration-methods/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Children And Iteration Methods&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;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;a href=&quot;https://thebook.io/080203/ch11/05/&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;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;useState 대신 useReducer 활용하기&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;b&gt;데이터 불변성 유지하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax&quot;&gt;Spread Syntax&lt;/a&gt;나 바벨의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/tc39/proposal-object-rest-spread&quot;&gt;Object Spread Syntax&lt;/a&gt;를 이용하면 쉽게 데이터 불변성을 유지하면서 값을 업데이트할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1651412380959&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// spread syntax
handleClick() {
  this.setState(state =&amp;gt; ({
    words: [...state.words, 'marklar'],
  }));
};

// object spread syntax
function updateColorMap(colormap) {
  return {...colormap, right: 'blue'};
}&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;불변성을 유지하기 위해 앞서 이야기했던 immutable.js, immer를 사용해볼 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형을 좋아한다면 하스켈 optics와 비슷한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/gcanti/monocle-ts&quot;&gt;monocle-ts&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;b&gt;함수형 업데이트 활용하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/hooks-reference.html#functional-updates&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;a href=&quot;https://overreacted.io/ko/a-complete-guide-to-useeffect/#%ED%95%A8%EC%88%98%ED%98%95-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8%EC%99%80-%EA%B5%AC%EA%B8%80-%EB%8B%A5%EC%8A%A4google-docs&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;마지막으로 초기 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;b&gt;useState 대신 useReducer 활용하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/hooks-reference.html#usereducer&quot;&gt;useReducer&lt;/a&gt;는 콜백 대신 dispatch를 전달한다. [&lt;a href=&quot;https://ko.reactjs.org/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down&quot;&gt;How&amp;nbsp;to&amp;nbsp;avoid&amp;nbsp;passing&amp;nbsp;callbacks&amp;nbsp;down?&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://medium.com/crowdbotics/how-to-use-usereducer-in-react-hooks-for-performance-optimization-ecafca9e7bf5&quot;&gt;How&amp;nbsp;to&amp;nbsp;use&amp;nbsp;useReducer&amp;nbsp;in&amp;nbsp;React&amp;nbsp;Hooks&amp;nbsp;for&amp;nbsp;performance&amp;nbsp;optimization&lt;/a&gt;]&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;다수의&amp;nbsp;하윗값을&amp;nbsp;포함하는&amp;nbsp;복잡한&amp;nbsp;정적&amp;nbsp;로직을&amp;nbsp;만드는&amp;nbsp;경우나&amp;nbsp;다음&amp;nbsp;state가&amp;nbsp;이전&amp;nbsp;state에&amp;nbsp;의존적인&amp;nbsp;경우에&amp;nbsp;보통&amp;nbsp;useState보다&amp;nbsp;useReducer를&amp;nbsp;선호합니다.&amp;nbsp;또한&amp;nbsp;useReducer는&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;dispatch를&amp;nbsp;전달&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있기&amp;nbsp;때문입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 dispatch는 렌더시 변화하지 않고 같다는 것을 보장하며 역시 의존성을 제거하여 필요시보다 자주 업데이트 되는 것을 방지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flux의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://haruair.github.io/flux/docs/dispatcher.html&quot;&gt;Dispatcher 문서&lt;/a&gt;에서는 다음과 같이 차이를 정의한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;콜백은&amp;nbsp;이벤트를&amp;nbsp;개별적으로&amp;nbsp;구독하지&amp;nbsp;않는다.&amp;nbsp;모든&amp;nbsp;데이터&amp;nbsp;변동은&amp;nbsp;등록된&amp;nbsp;모든&amp;nbsp;콜백에&amp;nbsp;전달된다.&lt;/li&gt;
&lt;li&gt;콜백이&amp;nbsp;실행될&amp;nbsp;때&amp;nbsp;콜백의&amp;nbsp;전체나&amp;nbsp;일부를&amp;nbsp;중단할&amp;nbsp;수&amp;nbsp;있다.&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;Redux에는 &lt;a href=&quot;https://redux.js.org/api/combinereducers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;combineReducers()&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;b&gt;- 컴포넌트 라이프사이클 / 메모이제이션&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;shouldComponentUpdate(): 클래스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/react-component.html#shouldcomponentupdate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;shouldCompontnentUpdate&lt;/a&gt;는 현재 props와 state와 다음 props, state를 비교후, 렌더링할 것인지 말것이지 결정한다. [&lt;a href=&quot;https://ko.reactjs.org/docs/optimizing-performance.html#avoid-reconciliation&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;true는 렌더링. false면 렌더링을 하지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;371&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIYkyW/btqW4hkCR42/fgHyxSK7lQhjxuOaMOT8e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIYkyW/btqW4hkCR42/fgHyxSK7lQhjxuOaMOT8e0/img.png&quot; data-alt=&quot;C2에서 false를 반환하여 렌더링을 하지 않음&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIYkyW/btqW4hkCR42/fgHyxSK7lQhjxuOaMOT8e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIYkyW%2FbtqW4hkCR42%2FfgHyxSK7lQhjxuOaMOT8e0%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;555&quot; height=&quot;371&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;C2에서 false를 반환하여 렌더링을 하지 않음&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;트위터에서는 deffering rendering을 하기도 했다. [&lt;a href=&quot;https://medium.com/@paularmstrong/twitter-lite-and-high-performance-react-progressive-web-apps-at-scale-d28a00e780a3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&amp;nbsp;Lite&amp;nbsp;and&amp;nbsp;High&amp;nbsp;Performance&amp;nbsp;React&amp;nbsp;Progressive&amp;nbsp;Web&amp;nbsp;Apps&amp;nbsp;at&amp;nbsp;Scale&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;b&gt;React.PureComponent: 클래스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/react-api.html#reactpurecomponent&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Purecomponent&lt;/a&gt;는 &lt;a href=&quot;https://ko.reactjs.org/docs/shallow-compare.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Shallow Compare(얕은 비교)&lt;/a&gt;를 이용하는 것과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1587849405740&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export class SampleComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState);
  }

  render() {
    return &amp;lt;div className={this.props.className}&amp;gt;foo&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;그렇다면 얕은 비교는 어떻게 이루어질까?&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EIjjg/btqWWs8zUxG/5FCx3t14KjclcI82qS51G1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EIjjg/btqWWs8zUxG/5FCx3t14KjclcI82qS51G1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EIjjg/btqWWs8zUxG/5FCx3t14KjclcI82qS51G1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEIjjg%2FbtqWWs8zUxG%2F5FCx3t14KjclcI82qS51G1%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;683&quot; height=&quot;464&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/39311394/are-javascript-object-variables-just-reference-type&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Are&amp;nbsp;javascript&amp;nbsp;object&amp;nbsp;variables&amp;nbsp;just&amp;nbsp;reference&amp;nbsp;type?&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;s2는 s1의 포인터를 사용하는 것과 같아 같은 레퍼런스를 가르치므로 같으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;s3는 값은 같으나 전혀 다른 객체이므로 달랐던 것처럼.&lt;/p&gt;
&lt;pre id=&quot;code_1587849103609&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const s1 = {text: &quot;first&quot;};
const s2 = s1;
const s3 = {text: &quot;first&quot;};

s1 === s2; // true
s1 === s3; // false&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;PureComponent는 props와 state에 대해 얕은 비교를 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 깊은 비교가 필요하면 &lt;a href=&quot;https://github.com/FormidableLabs/react-fast-compare&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-fast-compare&lt;/a&gt;나&amp;nbsp;&lt;a href=&quot;https://github.com/epoberezkin/fast-deep-equal&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fast-deep-equal&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;b&gt;React.memo: 함수형&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/react-api.html#reactmemo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React.memo&lt;/a&gt;는 PureComponent와 shouldComponentUpdate의 일부를 사용하도록 만들어졌다. [&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20190731/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React.memo()&amp;nbsp;현명하게&amp;nbsp;사용하기&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째 인수로 PureComponent로 사용할 컴포넌트, 두번째 인수로 같은 컴포넌트인지 확인하기 위한 비교할 콜백 함수를 넣을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이라면, props에 대해서만 얕은 비교를 수행하며,&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;shouldComponentUpdate와 정반대로&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;&lt;span style=&quot;color: #333333;&quot;&gt;true: 같으므로 렌더링 하지 않음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;false: 다르므로 렌더링&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;다음은 React.PureComponent나 React.memo를 사용하면 좋은 상황들.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순수 컴포넌트(Pure Component): props의 값이 같으면 렌더링이 같을 때.&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;&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://royi-codes.vercel.app/thousand-usecallbacks/&quot;&gt;Death&amp;nbsp;by&amp;nbsp;a&amp;nbsp;thousand&amp;nbsp;useCallbacks&lt;/a&gt;]&lt;br /&gt;참조/ID의 재사용 때문에 선제적으로 최적화하자는 말도 있다. [&lt;a href=&quot;https://www.zhenghao.io/posts/memo-or-not&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Preemptive&amp;nbsp;memoization&amp;nbsp;in&amp;nbsp;React&amp;nbsp;is&amp;nbsp;probably&amp;nbsp;not&amp;nbsp;Evil&amp;nbsp;(yet)&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cppDPG/btrAECjKhCE/KfhUmfnjcfREmrksUlnkTk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cppDPG/btrAECjKhCE/KfhUmfnjcfREmrksUlnkTk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cppDPG/btrAECjKhCE/KfhUmfnjcfREmrksUlnkTk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcppDPG%2FbtrAECjKhCE%2FKfhUmfnjcfREmrksUlnkTk%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;960&quot; height=&quot;540&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;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;React.PureComponent나 React.memo를 사용시 해당 컴포넌트에 의존하지 않는다면 컴포넌트 밖에 정의하면 참조 값이 같으므로 새로운 함수나 값이 생성되지 않는다. [&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20180911/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이벤트&amp;nbsp;리스너&amp;nbsp;캐시를&amp;nbsp;이용한&amp;nbsp;React&amp;nbsp;성능&amp;nbsp;향상&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;b&gt;this로 바인딩: 클래스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리엑트의 클래스형 컴포넌트에서 콜백을 올바르게 사용하는 방법은 유독 까다롭다. [&lt;a href=&quot;https://ko.reactjs.org/docs/handling-events.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이벤트 처리하기&lt;/a&gt;, React Binding &lt;a href=&quot;https://www.freecodecamp.org/news/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Patterns: 5 Approaches for Handling `this`&lt;/a&gt;, &lt;a href=&quot;https://siosio3103.medium.com/react-binding-%EC%96%B4%EB%96%A4-%EB%B0%A9%EC%8B%9D%EC%9D%84-%EC%8D%A8%EC%95%BC%ED%95%A0%EA%B0%80-be5894ba1dae&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;당신이&amp;nbsp;몰랐을수도&amp;nbsp;있는&amp;nbsp;React&amp;nbsp;Binding&amp;nbsp;에&amp;nbsp;관한&amp;nbsp;사실&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;a href=&quot;https://medium.com/@charpeni/arrow-functions-in-class-properties-might-not-be-as-great-as-we-think-3b3551c440b1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Arrow&amp;nbsp;Functions&amp;nbsp;in&amp;nbsp;Class&amp;nbsp;Properties&amp;nbsp;Might&amp;nbsp;Not&amp;nbsp;Be&amp;nbsp;As&amp;nbsp;Great&amp;nbsp;As&amp;nbsp;We&amp;nbsp;Think&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1651473372109&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {boundMethod} from 'autobind-decorator'

class BindMethod extends React.Compnent {
  constructor(props) {
    super(props);
    this.state = {
      isChecked: false
    };
  }

  @boundMethod
  handleClick(e) {
    this.setState({ isChecked: true });
  }
  
  render() {
    return &amp;lt;button onClick={this.handleClick}&amp;gt;바인딩&amp;lt;/button&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;useCallback/useMemo: 함수형&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/hooks-reference.html#usecallback&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;useCallback&lt;/a&gt;은 이벤트 리스너를 &lt;a href=&quot;https://ko.reactjs.org/docs/hooks-reference.html#usememo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;useMemo&lt;/a&gt;는 값을 메모이제이션한다. [&lt;a href=&quot;https://blog.bitsrc.io/optimize-your-react-functional-components-with-usecallback-and-usememo-34bb52bc9a13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimize&amp;nbsp;Your&amp;nbsp;React&amp;nbsp;Functional&amp;nbsp;Components&amp;nbsp;with&amp;nbsp;useCallback&amp;nbsp;and&amp;nbsp;useMemo&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;class때처럼 인라인 콜백은 매번 새로운 함수객체를 생성하므로 좋은 습관이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useCallback을 적극 활용하자.&lt;/p&gt;
&lt;pre id=&quot;code_1651474167994&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
function fnComponent() {
  const [state, setState] = useState({ isChecked: false });

  return return &amp;lt;button onClick={(e) =&amp;gt; setState({ isChecked: true })}&amp;gt;인라인&amp;lt;/button&amp;gt;;
}

// Good
function fnComponent() {
  const [state, setState] = useState({ isChecked: false });
  const handleClick = useCallback((e) =&amp;gt; {
    setState({ isChecked: true });
  }, [state]);
  return return &amp;lt;button onClick={handleClick}&amp;gt;인라인&amp;lt;/button&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;- 올바른 Key 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열에서 올바르게 키를 지정해주는 것도 쉬운듯, 쉽지 않은 일이다. [&lt;a href=&quot;https://levelup.gitconnected.com/optimize-react-performance-c1a491ed9c36&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimize&amp;nbsp;React&amp;nbsp;Performance&lt;/a&gt;, &lt;a href=&quot;https://velog.io/@xpmxf4/%EC%95%84%EC%9D%B4%EB%94%94%EC%97%90-%EA%B3%A0%EC%9C%A0-%EA%B0%92-%EC%A3%BC%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;아이디에&amp;nbsp;고유&amp;nbsp;값&amp;nbsp;주기&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통의 경우, DB에서 불러올 ID 정보값을 사용하여 설정해주는게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의외로 많이 하는 실수인 Math.random()은 성능이 나뻐지고 안전한 난수를 생성하지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LVvTj/btrA4Smy16l/kPp253D8GJ3FgINBm3KBpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LVvTj/btrA4Smy16l/kPp253D8GJ3FgINBm3KBpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LVvTj/btrA4Smy16l/kPp253D8GJ3FgINBm3KBpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLVvTj%2FbtrA4Smy16l%2FkPp253D8GJ3FgINBm3KBpk%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;1184&quot; height=&quot;788&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;788&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;b&gt;- React.lazy/React.Suspense 사용 및 동시성 모드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/react-api.html#reactlazy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React.lazy&lt;/a&gt;를 사용하면 컴포넌트를 동적으로 불러올 함수를 등록할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/react-api.html#reactsuspense&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React.Suspense&lt;/a&gt;로 렌더링이 준비되지 않은 컴포넌트를 불러오고, fallback으로 스피너를 사용할 수 있다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/concurrent-mode-adoption.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Concurrent&amp;nbsp;모드&amp;nbsp;도입하기&amp;nbsp;(실험&amp;nbsp;단계)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/concurrent-mode-patterns.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;컨커런트&amp;nbsp;UI&amp;nbsp;패턴&amp;nbsp;(실험)&lt;/a&gt;&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;b&gt;- Ref와 비제어 컴포넌트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리엑트의 경우 기본적으로 &lt;a href=&quot;https://ko.reactjs.org/docs/forms.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;제어 컴포넌트&lt;/a&gt;로 동작하여 입력을 하면 렌더링이 일어난다. [&lt;a href=&quot;https://so-so.dev/react/form-handling/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;입력을&amp;nbsp;다루는&amp;nbsp;다양한&amp;nbsp;방법&lt;/a&gt;, &lt;a href=&quot;https://dev.to/bluebill1049/uncontrolled-form-for-react-2b3n&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Uncontrolled&amp;nbsp;form&amp;nbsp;validation&amp;nbsp;with&amp;nbsp;React&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(onChange와 state를 연결한다는 가정하에)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1104&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M557u/btrAMuZmKlu/7YokupKe4Q2u4TGDucFRTK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M557u/btrAMuZmKlu/7YokupKe4Q2u4TGDucFRTK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M557u/btrAMuZmKlu/7YokupKe4Q2u4TGDucFRTK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/M557u/btrAMuZmKlu/7YokupKe4Q2u4TGDucFRTK/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;1104&quot; height=&quot;346&quot; data-origin-width=&quot;1104&quot; data-origin-height=&quot;346&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;Dom에 빈번한 접근 또한 성능에 안좋지 않던가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement&quot;&gt;Form&lt;/a&gt;은 기본적으로 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;Dom에 상태를 저장하고, &lt;a href=&quot;https://ko.reactjs.org/docs/forwarding-refs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ref&lt;/a&gt;를 이용하면 &lt;a href=&quot;https://ko.reactjs.org/docs/uncontrolled-components.html&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;a href=&quot;https://github.com/unform/unform&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;unform&lt;/a&gt;나 &lt;a href=&quot;https://github.com/react-hook-form/react-hook-form&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-hook-form&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;한마디로 변경 가능한 값을 유지해야할 때는 ref 사용을 고려해볼 수 있다는 말이다. [&lt;a href=&quot;https://www.smashingmagazine.com/2020/11/react-useref-hook/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Thoughtful&amp;nbsp;Way&amp;nbsp;To&amp;nbsp;Use&amp;nbsp;React&amp;rsquo;s&amp;nbsp;useRef()&amp;nbsp;Hook&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@vpromotorov/optimize-react-performance-through-combination-usestate-and-useref-hooks-c4161623ef89&quot;&gt;userStateWithRef()&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 그리드를 userRef로 최적화한 사례인&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://hackernoon.com/how-to-optimize-react-performace-by-using-useref-hooks-4t1n315h&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;to&amp;nbsp;Optimize&amp;nbsp;React&amp;nbsp;Performace&amp;nbsp;by&amp;nbsp;Using&amp;nbsp;useRef&amp;nbsp;Hooks&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;b&gt;- 기타 실용적 예제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토스트&amp;nbsp;UI와&amp;nbsp;체커의&amp;nbsp;데이터&amp;nbsp;그리드&amp;nbsp;시스템[&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20191204&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;반응형&amp;nbsp;시스템&amp;nbsp;개선하기(feat.&amp;nbsp;TOAST&amp;nbsp;UI&amp;nbsp;Grid)&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://medium.com/chequer/react-datagrid-component-%EC%A0%9C%EC%9E%91%EA%B8%B0-with-es6-typescript-4efcbfe1b442&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React&amp;nbsp;datagrid&amp;nbsp;component&amp;nbsp;제작기&amp;nbsp;(with&amp;nbsp;ES6,&amp;nbsp;TypeScript)&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;앞서 나왔던 넷플릭스 예제에는 인라이닝, 스타일의 static-dynamic 요소 분리와 정적 diff&amp;amp;apply처럼 흥미로운 예가 있지만,&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;3.2 처리 효율화&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3.2.1 워커나 워클릿 활용하기&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;개요&lt;/span&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;b&gt;분류:&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;Javascript&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Web_Workers_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹워커&lt;/a&gt;는 무거운 연산들을 메인 쓰레드와 분리시켜 백그라운드에서 처리할 수 있도록 도와준다. [&lt;a href=&quot;http://www.hanbit.co.kr/store/books/look.php?p_code=E2357353643&quot;&gt;멀티스레드를 위한 자바스크립트 프로그래밍 웹 워커&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(&lt;/span&gt;&lt;a href=&quot;https://blog.naver.com/sef16/70162786823&quot;&gt;요약&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;), &lt;a href=&quot;https://medium.com/@pks2974/web-worker-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-4ec90055aa4d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web Worker 간단 정리하기&lt;/a&gt;, &lt;a href=&quot;https://bitsofco.de/web-workers-vs-service-workers-vs-worklets/&quot;&gt;Web workers vs Service workers vs Worklets&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@cwdoh/main-thread-is-a-bad-place-to-run-your-code-6c83abcd75a7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;main&amp;nbsp;thread&amp;nbsp;is&amp;nbsp;a&amp;nbsp;bad&amp;nbsp;place&amp;nbsp;to&amp;nbsp;run&amp;nbsp;your&amp;nbsp;code&lt;/a&gt;, &lt;a href=&quot;https://www.slideshare.net/WooGenius/html5-web-workers-40451621&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Html5 web workers&lt;/a&gt;&lt;/span&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SI80d/btqW4gF0uOd/kTeDJ1teODV3hMZsaSKZI1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SI80d/btqW4gF0uOd/kTeDJ1teODV3hMZsaSKZI1/img.jpg&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;400&quot; style=&quot;width: 41.8101%; margin-right: 10px;&quot; data-widthpercent=&quot;42.3&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SI80d/btqW4gF0uOd/kTeDJ1teODV3hMZsaSKZI1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSI80d%2FbtqW4gF0uOd%2FkTeDJ1teODV3hMZsaSKZI1%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;566&quot; height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ch98k/btqW1stbC1O/g4T8j1lhv7kvYZqY9B2Cqk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ch98k/btqW1stbC1O/g4T8j1lhv7kvYZqY9B2Cqk/img.jpg&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;400&quot; style=&quot;width: 57.0271%;&quot; data-widthpercent=&quot;57.7&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ch98k/btqW1stbC1O/g4T8j1lhv7kvYZqY9B2Cqk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCh98k%2FbtqW1stbC1O%2Fg4T8j1lhv7kvYZqY9B2Cqk%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;772&quot; height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;li&gt;트래픽 높은 네트워크 통신(네트워크 데이터 처리, 캐싱과 프리페칭)&lt;/li&gt;
&lt;li&gt;백그라운드 I/O, 웹사이트 폴링(Polling)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등이 대표적인 예. [&lt;a href=&quot;https://velog.io/@godori/JavaScript-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%84%B1%EB%8A%A5-%ED%96%A5%EC%83%81&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript 프로그램 성능 향상&lt;/a&gt;&amp;nbsp;]&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전용 워커(Dedicated Woker): 처음 생성한 스크립트에서만 사용 가능, 보통 웹워커라 함은 전용 워커를 뜻함&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공유 워커(Shared Worker)&lt;/a&gt;: 워커간 데이터를 공유하는 목적, 동일한 도메인 내의 여러 스크립트나 컨텍스트(tab, iframe, worker)에서 접근 가능&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;서비스 워커(Service Worker)&lt;/a&gt;: 프록시의 역할을 하며, 네트워크 요청과 캐싱, 푸시알람, 백그라운드 동기화등에 사용[&lt;a href=&quot;https://developers.google.com/web/fundamentals/primers/service-workers?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;서비스 워커: 소개&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;오프라인 설명서&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Gecko/Chrome/API/ChromeWorker&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;크롬 워커(Chrome Worker)&lt;/a&gt;: 파이어폭스 독점 API로 확장기능에서 사용하고, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;js-ctype&lt;/a&gt;에 접근할 때 사용, &lt;b&gt;신경쓰지 않아도&lt;/b&gt; 좋다.&lt;/li&gt;
&lt;/ul&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXOTWt/btqWWsHted5/qvkkdCiSEXsr6rd5WlAxVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXOTWt/btqWWsHted5/qvkkdCiSEXsr6rd5WlAxVK/img.png&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;430&quot; style=&quot;width: 51.6702%; margin-right: 10px;&quot; data-widthpercent=&quot;52.28&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXOTWt/btqWWsHted5/qvkkdCiSEXsr6rd5WlAxVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXOTWt%2FbtqWWsHted5%2FqvkkdCiSEXsr6rd5WlAxVK%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;430&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xn8Tw/btqW1tr5OCE/kHNL0xBzrXKK2voEeIMmu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xn8Tw/btqW1tr5OCE/kHNL0xBzrXKK2voEeIMmu1/img.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;401&quot; style=&quot;width: 47.167%;&quot; data-widthpercent=&quot;47.72&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xn8Tw/btqW1tr5OCE/kHNL0xBzrXKK2voEeIMmu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxn8Tw%2FbtqW1tr5OCE%2FkHNL0xBzrXKK2voEeIMmu1%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;498&quot; height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;웹 워커 성능 향상 예[&lt;a href=&quot;https://levelup.gitconnected.com/web-workers-with-angular-cli-5791795989a8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web Workers with the Angular CLI&lt;/a&gt;, &lt;a href=&quot;https://www.twilio.com/blog/optimize-javascript-application-performance-web-workers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimizing&amp;nbsp;JavaScript&amp;nbsp;Application&amp;nbsp;Performance&amp;nbsp;with&amp;nbsp;Web&amp;nbsp;Workers&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btlNdI/btqXb19lygW/SqLKfoPovMXZpZPrTzlrs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btlNdI/btqXb19lygW/SqLKfoPovMXZpZPrTzlrs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btlNdI/btqXb19lygW/SqLKfoPovMXZpZPrTzlrs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtlNdI%2FbtqXb19lygW%2FSqLKfoPovMXZpZPrTzlrs1%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;2000&quot; height=&quot;1136&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;서비스 워커 성능 향상 예[&lt;a href=&quot;https://medium.com/@koh.yesl/progressive-web-app-libaries-in-production-991da49cc97&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Progressive&amp;nbsp;Web&amp;nbsp;App&amp;nbsp;Libaries&amp;nbsp;in&amp;nbsp;Production&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/fundamentals/architecture/app-shell?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앱 셸 모델&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@onejohi/service-workers-in-depth-f5c9993ab8e7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Service workers in Depth&lt;/a&gt;, &lt;a href=&quot;https://developer.chrome.com/docs/workbox/caching-strategies-overview/#streaming_composite_responses&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Strategies&amp;nbsp;for&amp;nbsp;service&amp;nbsp;worker&amp;nbsp;caching&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;하지만 메인(UI) 쓰레드가 아니기 때문에&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Window Object&lt;/li&gt;
&lt;li&gt;Document Object&lt;/li&gt;
&lt;li&gt;Parent Object&lt;/li&gt;
&lt;/ul&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://hacks.mozilla.org/2015/07/how-fast-are-web-workers/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How fast are web workers?&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;워커랑 비슷하지만, 가볍고 렌더링시에도 사용할 수 있는 Worklet도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coDJxJ/btqW1tezTr3/7ojV8rKDMQlixcyFRrR3RK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coDJxJ/btqW1tezTr3/7ojV8rKDMQlixcyFRrR3RK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coDJxJ/btqW1tezTr3/7ojV8rKDMQlixcyFRrR3RK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoDJxJ%2FbtqW1tezTr3%2F7ojV8rKDMQlixcyFRrR3RK%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;1045&quot; height=&quot;390&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Worklet&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Worklets&lt;/a&gt;:&lt;/b&gt; Worker의 초기 비용이 큰 문제를 해결하기 위한 경량버전, 저수준 렌더링 파이프 라인에 접근가능[&lt;a href=&quot;https://medium.com/@jihyerish/worklet-5a193167606f&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;worklet&lt;/a&gt;, &lt;a href=&quot;https://wit.nts-corp.com/2018/05/02/5214&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Paint API&lt;/a&gt;, &lt;a href=&quot;https://houdini.glitch.me/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Houdini&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/updates/2016/05/houdini?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Houdini: Demystifying CSS&lt;/a&gt;, &lt;a href=&quot;https://github.com/CSSHoudini/awesome-css-houdini&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Awesome CSS Houdini&lt;/a&gt;]
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/PaintWorklet&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PaintWorklet&lt;/a&gt;[&lt;a href=&quot;https://developers.google.com/web/updates/2018/01/paintapi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Paint API&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/AudioWorklet&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AudioWorklet&lt;/a&gt;[&lt;a href=&quot;https://developers.google.com/web/updates/2017/12/audio-worklet&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Enter Audio Worklet&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/updates/2018/06/audio-worklet-design-pattern&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Audio Worklet Design Pattern&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;AnimationWorklet[&lt;a href=&quot;https://developers.google.com/web/updates/2018/10/animation-worklet&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Houdini's Animation Worklet&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;LayoutWorklet 로 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C6Thx/btqWWtGsEp7/PDpECNvgRnswo8C8iJkw30/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C6Thx/btqWWtGsEp7/PDpECNvgRnswo8C8iJkw30/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C6Thx/btqWWtGsEp7/PDpECNvgRnswo8C8iJkw30/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC6Thx%2FbtqWWtGsEp7%2FPDpECNvgRnswo8C8iJkw30%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;599&quot; height=&quot;351&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;351&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;가장 큰 단점은 아직 지원하는 &lt;a href=&quot;https://ishoudinireadyyet.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;브라우저가 많지 않다&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;한가지 주의할 점은 3D 렌더링을 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebGL&lt;/a&gt;과 같이 사용할 수 없으며 WebGL의 GLSL 코드를 사용해야 한다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;전용 워커:&lt;/b&gt; CPU 중심의 작업을 메인 스레드에서 오프로드 할 때 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;공유 워커:&lt;/b&gt; 워커간 공유가 필요할 때 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;서비스 워커:&lt;/b&gt; 네트워크 요청을 캐싱하거나 오프라인 작업을 위해 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;워크렛&lt;/b&gt;: 브라우저 렌더링 파이프 라인에 연결되어, 스타일이나 레이아웃등 렌더링 프로세스에 저수준 접근이 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;b&gt;+.&lt;/b&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://www.khronos.org/webcl/&quot;&gt;WebCL&lt;/a&gt;이란 표준이 있었는데 지원하는 브라우저가 없는 모양.[&lt;a href=&quot;https://en.wikipedia.org/wiki/WebCL&quot;&gt;WebCL&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;b&gt;전용 워커&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;new Worker를 이용해 생성하며, postMessage와 onmessage로 통신한다. [&lt;a href=&quot;https://css-tricks.com/off-the-main-thread/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;ldquo;Off&amp;nbsp;The&amp;nbsp;Main&amp;nbsp;Thread&amp;rdquo;&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;확장기능을 만들어본 사람은 background와 content의 통신방식과 유사해 적응이 쉬울것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1586713908149&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* main.js */

// Create worker
const myWorker = new Worker('worker.js');

// Send message to worker
myWorker.postMessage('Hello!');

// Receive message from worker
myWorker.onmessage = function(e) {
  console.log(e.data);
}&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;worker에서도 사용방법은 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1586714051624&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* worker.js */

// Receive message from main file
self.onmessage = function(e) {
  console.log(e.data);

  // Send message to main file
  self.postMessage(workerResult);
}&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: #333333;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/OffscreenCanvas&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Offscreen Canvas&lt;/a&gt;가 주목받을만 하다.[&lt;a href=&quot;https://brunch.co.kr/@clay1987/102&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;크로미움 엔진과 오프스크린 캔버스 기술&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/updates/2018/08/offscreen-canvas&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OffscreenCanvas &amp;mdash; Speed up Your Canvas Operations with a Web Worker&lt;/a&gt;, &lt;a href=&quot;http://www.secmem.org/blog/2019/04/10/worker-postable/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web&amp;nbsp;Worker-Postable&amp;nbsp;라이브러리&amp;nbsp;작성기&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;&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;a href=&quot;https://felixgerschau.com/how-to-make-your-react-app-a-progressive-web-app-pwa/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;to&amp;nbsp;Make&amp;nbsp;your&amp;nbsp;React&amp;nbsp;App&amp;nbsp;a&amp;nbsp;Progressive&amp;nbsp;Web&amp;nbsp;App&amp;nbsp;(PWA)&lt;/a&gt;]&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1586714172157&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* main.js */

navigator.serviceWorker.register('/service-worker.js');&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: #333333;&quot;&gt;서비스 워커는 프록시의 역할을 하기 때문에 모든 네트워크 요청을 가로챌 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1586714237579&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* service-worker.js */

// Install 
self.addEventListener('install', function(event) {
    // ...
});

// Activate 
self.addEventListener('activate', function(event) {
    // ...
});

// Listen for network requests from the main document
self.addEventListener('fetch', function(event) {
    // ...
});&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;PWA에 필수적인 요소니 꼭 알아두었으면 한다.[&lt;a href=&quot;https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;고성능 서비스 워커 로딩&lt;/a&gt;, &lt;a href=&quot;https://jdlrobson.github.io/serviceworkerimagelazyloader/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lazy load your images with Service Worker&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1586715484285&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* service-worker.js */

const cacheName = 'shell-content';
const filesToCache = [
  '/css/styles.css',
  '/js/scripts.js',
  '/images/logo.svg',

  '/offline.html&amp;rsquo;,

  '/&amp;rsquo;,
];

self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);
    })
  );
});
&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;pre id=&quot;code_1586714306989&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* service-worker.js */

self.addEventListener('fetch', function(event) {
    // Return data from cache
    event.respondWith(
        caches.match(event.request);
    );
});&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;페인트 워크렛&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시나 JS 파일을 등록한다.&lt;/p&gt;
&lt;pre id=&quot;code_1586717319309&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* main.js */

CSS.paintWorklet.addModule('myWorklet.js');&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;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Canvas&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Canvas API&lt;/a&gt;와 유사하다.&lt;/p&gt;
&lt;pre id=&quot;code_1586717357242&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* myWorklet.js */

registerPaint('myGradient', class {
  paint(ctx, size, properties) {
    var gradient = ctx.createLinearGradient(0, 0, 0, size.height / 3);

    gradient.addColorStop(0, &quot;black&quot;);
    gradient.addColorStop(0.7, &quot;rgb(210, 210, 210)&quot;);
    gradient.addColorStop(0.8, &quot;rgb(230, 230, 230)&quot;);
    gradient.addColorStop(1, &quot;white&quot;);

    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, size.width, size.height / 3);
  }
});&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;만든 사용자 정의 이미지는 CSS에서 적용하면 끝!!&lt;/p&gt;
&lt;pre id=&quot;code_1586717505117&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;div {
    background-image: paint(myGradient);
}&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;- 라이브러리&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;&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChromeLabs/comlink&quot;&gt;Comlink&lt;/a&gt;: 구글이 만든 것으로 잘 추상화 시켜놨다. [&lt;a href=&quot;https://github.com/GoogleChromeLabs/comlink-loader&quot;&gt;comlink-loader&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/greenlet&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Greenlet&lt;/a&gt;:&amp;nbsp; async 함수를 웹워커로 처리&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/workerize&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Workerize&lt;/a&gt;: 모듈을 웹워커로 처리&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pshihn/workly&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Workly&lt;/a&gt;: 역시 함수나 클래스를 워커로 처리도록 만든 것&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/padolsey/operative&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Operative&lt;/a&gt;: 콜백 형식으로 처리하도록 만듦&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/andywer/threads.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Thread.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/parallel-js/parallel.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Parallel.js&lt;/a&gt;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/alewin/useWorker&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;useWorker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nitish24p/react-worker-image&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-worker-image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BuilderIO/partytown&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;partytown&lt;/a&gt;: 제 3자 스크립트를 웹워커에서&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;b&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;&lt;a href=&quot;https://developers.google.com/web/tools/workbox&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Workbox&lt;/a&gt;: 구글이 PWA에 쓰라고 잘 만든 라이브러리. (&lt;a href=&quot;https://github.com/GoogleChrome/sw-toolbox/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sw-toolbox&lt;/a&gt; + &lt;a href=&quot;https://github.com/GoogleChrome/sw-precache/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sw-precache&lt;/a&gt; + &lt;a href=&quot;https://developers.google.com/web/updates/2016/07/offline-google-analytics&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sw-offline-google-analytics&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.talater.com/upup/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;UpUp&lt;/a&gt;: 한줄의 명령으로 오프라인 기능 제공&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NekR/offline-plugin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;offline-plugin&lt;/a&gt;: 서비스 워커와 앱캐시를 웹팩에서 쓰기 편하게&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jimmywarting/StreamSaver.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;StreamSaver.js&lt;/a&gt;: 스트리밍 받아 파일로 저장&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://brucelawson.github.io/manifest/&quot;&gt;Manifest Generator&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;: 푸시 알림 또는 PWA에 필요한 웹 앱 매니페스트 생성기&lt;/span&gt;&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;b&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;&lt;a href=&quot;https://extra-css.netlify.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;extra css&lt;/a&gt;: 웹사이트 꾸미기에 좋은 Paint API 라이러리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2.2 그래픽 최적화&lt;/h4&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; Content, CSS, Javascript&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래픽 최적화의 핵심은 GPU를 어떻게 써먹는가이다. [&lt;a href=&quot;https://d2.naver.com/helloworld/2061385&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;하드웨어&amp;nbsp;가속에&amp;nbsp;대한&amp;nbsp;이해와&amp;nbsp;적용&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Performance/Animation_performance_and_frame_rate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Animation&amp;nbsp;performance&amp;nbsp;and&amp;nbsp;frame&amp;nbsp;rate&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bux7yf/btqXj7uop7r/9HhcK16n18Rp8JkbrNrgZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bux7yf/btqXj7uop7r/9HhcK16n18Rp8JkbrNrgZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bux7yf/btqXj7uop7r/9HhcK16n18Rp8JkbrNrgZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbux7yf%2FbtqXj7uop7r%2F9HhcK16n18Rp8JkbrNrgZ1%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;650&quot; height=&quot;268&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어 가속은 Graphics Layer 단위로 처리되며, GPU를 이용해 이미지로 합성(Composition)해 화면에 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transforms&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;3D&amp;nbsp;Transform&lt;/a&gt;(translate3d,&amp;nbsp;preserve-3d&amp;nbsp;등)이나&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/perspective&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;perspective&lt;/a&gt;&amp;nbsp;속성이&amp;nbsp;적용된&amp;nbsp;경우&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Element/Video&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lt;video&amp;gt;&lt;/a&gt; 또는 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Element/canvas&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lt;canvas&amp;gt;&lt;/a&gt; 요소&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS3 애니메이션 함수&lt;/a&gt;나 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/filter&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS 필터 함수&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;자식 요소가 레이어로 구성&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/z-index&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;z-index&lt;/a&gt;값이 낮은 형제 요소가 레이어로 구성된 경우&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;그러나 하드웨어 가속은 조심히 사용해야 하는데 5가지만 뽑아보았다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리: 많은 텍스처를 로드하면 메모리 문제가 발생할 수 있다.&lt;br /&gt;특히, 모바일 장치에서 문제가 생길 수 있으며, 모든 요소에 하드웨어 가속을 적용하면 안된다.&lt;/li&gt;
&lt;li&gt;깜박임: 영역이 크면 화면이 깜박일 수도 있다.&lt;/li&gt;
&lt;li&gt;변경: 컨텐츠 내용이 변경되면 GPU 메모리에 다시 업로드 해야한다.&lt;/li&gt;
&lt;li&gt;글씨 렌더링: CPU와 CPU의 렌더링 방식으로 인해 안티얼라이싱에 영향을 주어 흐리게 표시될 수 있다. &lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://keithclark.co.uk/articles/gpu-text-rendering-in-webkit/&quot;&gt;GPU&amp;nbsp;text&amp;nbsp;rendering&amp;nbsp;in&amp;nbsp;webkit&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;기기: 가속을 지원하지 않는 기기에서는 성능저하가 생길 수 있다.&lt;/li&gt;
&lt;/ul&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 style=&quot;font-size: 1.12em;&quot; 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;a href=&quot;https://css-tricks.com/comparison-animation-technologies/&quot;&gt;A Comparison of Animation Technologies&lt;/a&gt;, &lt;a href=&quot;https://flaviocopes.com/animations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Compare&amp;nbsp;the&amp;nbsp;options&amp;nbsp;for&amp;nbsp;Animations&amp;nbsp;on&amp;nbsp;the&amp;nbsp;Web&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS: 앞서 언급한 것. [&lt;a href=&quot;https://www.sitepoint.com/introduction-to-hardware-acceleration-css-animations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;An&amp;nbsp;Introduction&amp;nbsp;to&amp;nbsp;Hardware&amp;nbsp;Acceleration&amp;nbsp;with&amp;nbsp;CSS&amp;nbsp;Animations&lt;/a&gt;, &lt;a href=&quot;https://www.smashingmagazine.com/2016/12/gpu-animation-doing-it-right/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS GPU Animation: Doing It Right&lt;/a&gt;(&lt;a href=&quot;https://wit.nts-corp.com/2017/08/31/4861&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;번역&lt;/a&gt;), &lt;a href=&quot;https://wit.nts-corp.com/2017/06/05/4571&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;애니메이션&amp;nbsp;성능&amp;nbsp;개선&amp;nbsp;방법(reflow&amp;nbsp;최소화,&amp;nbsp;will-change&amp;nbsp;사용)&lt;/a&gt;, &lt;a href=&quot;https://www.paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Why Moving Elements With Translate() Is Better Than Pos:abs Top/left&lt;/a&gt;, &lt;a href=&quot;https://wit.nts-corp.com/2020/06/05/6134&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;애니메이션의&amp;nbsp;성능&amp;nbsp;아는&amp;nbsp;만큼&amp;nbsp;좋아져요!&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Canvas&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Canvas&lt;/a&gt;: javascript와 &amp;lt;canvas&amp;gt;를 이용해 그래픽을 그릴 수 있는 API.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/SVG/SVG_animation_with_SMIL&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SMIL&lt;/a&gt;: SVG 애니메이션, deprecated 됨.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebAnimation API&lt;/a&gt;: 애니메이션을 만들 수 있는 자바스크립트 API&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/WebGL_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebGL&lt;/a&gt;: OpenGL(1.0: &lt;span style=&quot;color: #333333;&quot;&gt;ES 2.0, 2.0: ES 3.0&lt;/span&gt;) 기반 API를 이용해 HTML canvas에 렌더링하는 것[&lt;a href=&quot;https://webglfundamentals.org/webgl/lessons/ko/webgl-fundamentals.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebGL 기초&lt;/a&gt;], 최근 WebGL 2.0이 메이져 브라우저에서 &lt;a href=&quot;https://www.khronos.org/blog/webgl-2-achieves-pervasive-support-from-all-major-web-browsers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;지원된다&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gpuweb.github.io/gpuweb/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebGPU&lt;/a&gt; : WebGL의 뒤를 이을 표준, 아직 만들어지고 있는 중 (Apple에서는 WebGPU 라는 이름으로 사용하다가 WebMetal로 이름이 바뀜) [&lt;a href=&quot;https://en.wikipedia.org/wiki/WebGPU&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebGPU&lt;/a&gt;, &lt;a href=&quot;https://webkit.org/blog/9528/webgpu-and-wsl-in-safari/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebGPU&amp;nbsp;and&amp;nbsp;WSL&amp;nbsp;in&amp;nbsp;Safari&lt;/a&gt;, &lt;a href=&quot;https://github.com/gpuweb/gpuweb&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GPU Web&lt;/a&gt;]&lt;br /&gt;애플의 사례를 볼때 WebGL보다 성능에서 유리한듯.&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;CSS와 자바스크립트의 애니메이션에 대해 다음 문서에서 간략히 다루고 있다.[&lt;a href=&quot;https://developers.google.com/web/fundamentals/design-and-ux/animations/css-vs-javascript&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS와 자바스크립트 애니메이션&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Performance/CSS_JavaScript_animation_performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;and&amp;nbsp;JavaScript&amp;nbsp;animation&amp;nbsp;performance&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;간단한 애니메이션은 CSS를 사용&lt;/li&gt;
&lt;li&gt;복잡한 것은 WebAnimation API 사용 &lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://hacks.mozilla.org/2016/08/animating-like-you-just-dont-care-with-element-animate/&quot;&gt;Animating&amp;nbsp;like&amp;nbsp;you&amp;nbsp;just&amp;nbsp;don&amp;rsquo;t&amp;nbsp;care&amp;nbsp;with&amp;nbsp;Element.animate&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;3D나 더욱 세밀한 제어, VR등에서 필요시 WebGL 사용&lt;/li&gt;
&lt;li&gt;간단할 때 CSS의 성능이 SVG보다 낫고, deprecated 되어 사용하지 않는게 좋음 [&lt;a href=&quot;https://css-tricks.com/weighing-svg-animation-techniques-benchmarks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Weighing SVG Animation Techniques(with Benchmarks)&lt;/a&gt;]&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;b&gt;CSS&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU 가속이 되도독 작성해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재는 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/opacity&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;opacity&lt;/a&gt;와 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/transform&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;transform&lt;/a&gt; 정도만 지원. [&lt;a href=&quot;https://amp.dev/ko/documentation/guides-and-tutorials/develop/style_and_layout/style_pages/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMP - 지원하는 CSS&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/rendering/stick-to-compositor-only-properties-and-manage-layer-count&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Stick to Compositor-Only Properties and Manage Layer Count&lt;/a&gt;, &lt;a href=&quot;https://www.html5rocks.com/ko/tutorials/speed/high-performance-animations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Highperformacne Animations&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAVlxq/btqXb21t8Bm/4ZVOrnnxgqW1iLIx0akKnk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAVlxq/btqXb21t8Bm/4ZVOrnnxgqW1iLIx0akKnk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAVlxq/btqXb21t8Bm/4ZVOrnnxgqW1iLIx0akKnk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAVlxq%2FbtqXb21t8Bm%2F4ZVOrnnxgqW1iLIx0akKnk%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;1024&quot; height=&quot;768&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&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://motion.dev/guides/performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Motion One&lt;/a&gt;에 따르면 &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;background-color&lt;/code&gt;, &lt;code&gt;clip-path&lt;/code&gt;, SVG도 많은 브라우저에서 지원한다고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1632452326217&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;element {
  /* Box shadow Accelerate */
  box-shadow: 10px 10px black;
  filter: drop-shadow(10px 10px black);
 
  /* Border radius Accelerate */
  border-radius: 50px;
  clip-path: inset(0 round 50px);
}&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;position&lt;/a&gt;을 absolute나 fixed로 설정하면 주변 영역에 영향을 주지 않는다.&lt;/p&gt;
&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;widthContent&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;740&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clhBPq/btqW8HDiRjL/JLSmal1HGE5q2BZ41ZjXOK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clhBPq/btqW8HDiRjL/JLSmal1HGE5q2BZ41ZjXOK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clhBPq/btqW8HDiRjL/JLSmal1HGE5q2BZ41ZjXOK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclhBPq%2FbtqW8HDiRjL%2FJLSmal1HGE5q2BZ41ZjXOK%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;861&quot; height=&quot;740&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;740&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://developer.mozilla.org/en-US/docs/Web/CSS/will-change&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;will-change&lt;/a&gt;를 사용하면 애니메이션이 곧 일어날 것이라고 알려줘 응답성을 개선할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 레스터화 시키고 우선순위를 변경하는 것이기 때문에 신중히 사용하고 해제해야 한다. [&lt;a href=&quot;https://dev.opera.com/articles/ko/css-will-change-property/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;will-change&amp;nbsp;프로퍼티에&amp;nbsp;관해&amp;nbsp;알아둬야&amp;nbsp;할&amp;nbsp;것&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1587398543883&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.moving-element {
  will-change: transform;
}&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;will-change가 먹히지 않는 브라우저라면, 강제로 적용 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1587398571237&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.moving-element {
  transform: translateZ(0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 CPU와 GPU의 대역폭, GPU의 메모리, 모바일의 하드웨어 가속여부 및 리소스 크기를 따져가며 작업해야 한다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://motion.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Motion One&lt;/a&gt;: Web Animations API로 구축되었으며 하드웨어 가속을 적극 활용&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jeremyckahn/shifty&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;shifty&lt;/a&gt;: &lt;a href=&quot;https://github.com/greensock/GSAP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GSAP(GreenSock Animation Platform)&lt;/a&gt;보다 메모리를 적게 사용&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pixijs/pixijs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PixiJS&lt;/a&gt;: 2D 라이브러리&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mrdoob/three.js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Three.js&lt;/a&gt;: 3D 라이브러리&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;/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;3.2.3 웹 어셈블리&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;분류:&lt;/b&gt; wasm&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/WebAssembly&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹 어셈블리&lt;/a&gt;는 네이티브에 가까운 성능으로 동작하는 바이너리 포맷을 제공하는 프로젝트로 C/C++, Rust 등의 컴파일 타겟으로 사용될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나오게 된 계기는 &lt;a href=&quot;https://www.popit.kr/%EA%B0%9C%EB%B0%9C%EB%B0%94%EB%B3%B4-webassembly-emscripten-asmjs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebAssembly,&amp;nbsp;브라우저에&amp;nbsp;올리는&amp;nbsp;네이티브&amp;nbsp;코드&lt;/a&gt;를 살펴보면 재미있게 읽을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hacks.mozilla.org/2017/02/a-cartoon-intro-to-webassembly&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A cartoon intro to WebAssembly&lt;/a&gt;(&lt;a href=&quot;https://dongwoo.blog/2017/06/06/%EB%B2%88%EC%97%AD-%EC%B9%B4%ED%88%B0%EC%9C%BC%EB%A1%9C-%EC%86%8C%EA%B0%9C%ED%95%98%EB%8A%94-%EC%9B%B9%EC%96%B4%EC%85%88%EB%B8%94%EB%A6%AC/&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이어폭스의 &lt;a href=&quot;https://hacks.mozilla.org/2018/01/making-webassembly-even-faster-firefoxs-new-streaming-and-tiering-compiler/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스트리밍 + 계층형 컴파일러&lt;/a&gt;(계층형 컴파일러가 궁금하면 &lt;a href=&quot;https://github.com/dotnet/runtime/blob/master/docs/design/features/tiered-compilation.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;닷넷문서&lt;/a&gt; 참고)&lt;/li&gt;
&lt;li&gt;웹킷의 BBQBuild Bytecode Quickly)와 OMG(Optimized Machine-code Generator) &lt;a href=&quot;https://webkit.org/blog/7691/webassembly/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;계층형 컴파일러&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;블링크의 &lt;a href=&quot;https://v8.dev/blog/liftoff&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Litoff 컴파일러&lt;/a&gt;&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;a href=&quot;https://blogs.unity3d.com/2018/09/17/webassembly-load-times-and-performance/&quot;&gt;WebAssembly LoadTimes and Performance&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;742&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eycMsv/btqXb2mT02l/oRMWNo4ZTKTs5ZY3okJnA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eycMsv/btqXb2mT02l/oRMWNo4ZTKTs5ZY3okJnA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eycMsv/btqXb2mT02l/oRMWNo4ZTKTs5ZY3okJnA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeycMsv%2FbtqXb2mT02l%2FoRMWNo4ZTKTs5ZY3okJnA1%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;1200&quot; height=&quot;742&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;742&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;메인 스크린에 보이는 총시간(낮은 것이 좋음)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rbpeM/btqWXaNoNhl/6IYii3y8sCbKSwRQTcPw8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rbpeM/btqWXaNoNhl/6IYii3y8sCbKSwRQTcPw8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rbpeM/btqWXaNoNhl/6IYii3y8sCbKSwRQTcPw8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrbpeM%2FbtqWXaNoNhl%2F6IYii3y8sCbKSwRQTcPw8K%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;1036&quot; height=&quot;638&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;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;li&gt;타입이나 기타 정보가 있어 최적화에 유리&lt;/li&gt;
&lt;li&gt;명령어셋을 사용할 수 있음&lt;/li&gt;
&lt;li&gt;직접 메모리를 관리해 GC가 필요 없음&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;써보려면 MDN 문서를 정독해보는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 DOM에 접근할 수 없기 때문에&amp;nbsp;자바스크립트를 완전 대체하기보다 CPU 성능 집약적인 작업이나 기존 C/C++ 코드를 포팅해서 사용할 때 유용할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dodrio&lt;/a&gt;나 &lt;a href=&quot;https://github.com/mbasso/asm-dom&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;asm-dom&lt;/a&gt;처럼 Virtual 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;현재로서 가장 좋은 성능을 내고 싶다면 WebGL + WASM(쉐이더) + Worker 조합인듯&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.chinedufn.com/3d-webgl-basic-water-tutorial/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebGL&amp;nbsp;+&amp;nbsp;Rust:&amp;nbsp;Basic&amp;nbsp;Water&amp;nbsp;Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://julien-decharentenay.medium.com/implementing-a-webassembly-webgl-viewer-using-rust-a6d8a703153d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Implementing&amp;nbsp;a&amp;nbsp;WebAssembly&amp;nbsp;WebGL&amp;nbsp;viewer&amp;nbsp;using&amp;nbsp;Rust&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rustwasm.github.io/docs/wasm-bindgen/web-sys/index.html#the-web-sys-crate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;web-sys&lt;/a&gt;라는 러스트 라이브러리가 잘 되어 있는 듯 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언젠가는 PWA로 그래픽좋은 게임을 설치해서 플레이 할 수 있지 않을까&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;3.2.4 전용 페이지&lt;/h4&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; Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텐츠를 전용 페이지로 만들어 제공하면 빠르고 로드 할 수 있다.&lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://medium.com/31-ten/instant-loading-on-mobile-should-you-amp-ify-mip-ify-your-website-in-2018-b42c76093ed&quot;&gt;Instant&amp;nbsp;loading&amp;nbsp;on&amp;nbsp;mobile:&amp;nbsp;should&amp;nbsp;you&amp;nbsp;AMP-ify&amp;nbsp;/&amp;nbsp;MIP-ify&amp;nbsp;your&amp;nbsp;website&amp;nbsp;in&amp;nbsp;2018?&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://ampexamples.com/facebook-instant-articles-vs-google-amp-1632.html&quot;&gt;Facebook&amp;nbsp;Instant&amp;nbsp;Articles&amp;nbsp;vs.&amp;nbsp;Google&amp;nbsp;AMP&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://sudonull.com/post/15-AMP-and-Turbo-Pages-Pros-Cons-and-Implementation-Results&quot;&gt;AMP and Turbo Pages: Pros, Cons, and Implementation Results&lt;/a&gt;, &lt;a href=&quot;https://ez.no/Blog/What-do-Facebook-Instant-Articles-Apple-News-Google-AMP-mean-for-publishers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What do Facebook Instant Articles, Apple News &amp;amp; Google AMP mean for publishers?&lt;/a&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;처음에는 컨텐츠를 일정한 UI로 만들어 통일성을 만들고, 광고 수익을 챙기고, 접속율을 늘리려는 과정에서 다음과 같은 것들이 등장하였다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이스북:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.facebook.com/facebookmedia/solutions/instant-articles&quot;&gt;Instant Article&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[&lt;a href=&quot;https://www.adplugg.com/blog/why-is-facebook&quot;&gt;Why&amp;nbsp;Is&amp;nbsp;Facebook&amp;nbsp;Instant&amp;nbsp;Articles&amp;nbsp;Faster?&lt;/a&gt;, &lt;a href=&quot;https://www.facebook.com/facebookmedia/blog/instant-articles-now-open-to-all-publishers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Instant Articles Now Open to All Publishers&lt;/a&gt;, &lt;a href=&quot;https://www.theverge.com/2015/5/13/8595263/facebooks-instant-articles-arrive-to-speed-up-the-news-feed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Facebooks's instant articles arrive to speed up&amp;nbsp; the News Feed&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;애플:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.apple.com/apple-news/&quot;&gt;Apple News&lt;/a&gt; [&lt;a href=&quot;https://developer.apple.com/documentation/apple_news&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Apple News Document&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;텐센트(위챗):&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://wechatwiki.com/wechat-resources/wechat-mini-program-epic-tutorial-guide/&quot;&gt;Mini Program&lt;/a&gt; [&lt;a href=&quot;https://wechatwiki.com/wechat-resources/wechat-mini-program-epic-tutorial-guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wechat Mini Program: an epic guide&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&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;widthContent&quot; data-origin-width=&quot;4740&quot; data-origin-height=&quot;2880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RkowT/btqW1s7OFLF/PBcGKmVFUaWYhxkR1tXA01/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RkowT/btqW1s7OFLF/PBcGKmVFUaWYhxkR1tXA01/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RkowT/btqW1s7OFLF/PBcGKmVFUaWYhxkR1tXA01/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRkowT%2FbtqW1s7OFLF%2FPBcGKmVFUaWYhxkR1tXA01%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;4740&quot; height=&quot;2880&quot; data-origin-width=&quot;4740&quot; data-origin-height=&quot;2880&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사이트의 CSS, Javascript, 광고 및 분석 등을 아낄 수 있음&lt;/li&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플의 경우, 이미지 캐싱과 JSON 포맷이라 가벼워 성능에서 유리한 편.&lt;/p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구글: &lt;a href=&quot;https://amp.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMP(Accelerated Mobile Pages)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;바이두: &lt;a href=&quot;https://www.mipengine.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MIP(Mobile Instant Pages)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;얀덱스: &lt;a href=&quot;https://tech.yandex.com/turbo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Turbo Pages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AMP와 MIP는 동일한 기술.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AMP는 Yahoo Japan과 Sogou에서도 지원한다고 한다. &lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://9to5google.com/2017/03/07/accelerated-mobile-pages-expansion-yahoo-japan-baidu-china/&quot;&gt;Accelerated&amp;nbsp;Mobile&amp;nbsp;Pages&amp;nbsp;rolling&amp;nbsp;out&amp;nbsp;to&amp;nbsp;a&amp;nbsp;billion&amp;nbsp;Yahoo&amp;nbsp;Japan,&amp;nbsp;Baidu,&amp;nbsp;&amp;amp;&amp;nbsp;Sogou&amp;nbsp;users&amp;nbsp;in&amp;nbsp;Asia&lt;/a&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;AMP가 성능을 높힐 수 있었던 주요 이유는 다음과 같다. [&lt;a href=&quot;https://d2.naver.com/helloworld/6856597&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMP는&amp;nbsp;어떻게&amp;nbsp;웹&amp;nbsp;페이지의&amp;nbsp;성능을&amp;nbsp;높일&amp;nbsp;수&amp;nbsp;있나&lt;/a&gt;, &lt;a href=&quot;https://amp.dev/ko/about/how-amp-works/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMP&amp;nbsp;작동&amp;nbsp;원리&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AMP HTML: 커스텀 엘리먼트를 사용하여 레이아웃 계산 최소화&lt;/li&gt;
&lt;li&gt;AMP JS: 리소스 로딩 관리(비동기, 느린 것 차단) 및 커스텀 엘리먼트 제어.&lt;/li&gt;
&lt;li&gt;AMP Cache: 프록시 기반 CDN으로 캐시를 이용, 모든 스크립트와 이미지를 같은 출처(Origin)에서 다운 가능&lt;/li&gt;
&lt;li&gt;제한: 서드파티 CSS, JS 미허용 및 용량 제한, GPU 가속 애니메이션만 허용, 상태 및 이벤트 관리&lt;/li&gt;
&lt;/ul&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;Turbo Pages의 컨셉을 살펴보면 AMP와 Instant Page 사이.&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;3.2.5 자바스크립트 코딩 스타일&lt;/h4&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;span&gt; &lt;/span&gt;Javascript&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;코딩 스타일을 변경하는 것만으로도 성능을 향상 시킬 수 있다.[&lt;/span&gt;&lt;a href=&quot;https://engineering.huiseoul.com/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94%EA%B0%80-v8-%EC%97%94%EC%A7%84%EC%9D%98-%EB%82%B4%EB%B6%80-%EC%B5%9C%EC%A0%81%ED%99%94%EB%90%9C-%EC%BD%94%EB%93%9C%EB%A5%BC-%EC%9E%91%EC%84%B1%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8B%A4%EC%84%AF-%EA%B0%80%EC%A7%80-%ED%8C%81-6c6f9832c1d9&quot;&gt;자바스크립트는 어떻게 작동하는가: V8 엔진의 내부 + 최적화된 코드를 작성을 위한 다섯 가지 팁&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://kkangil.github.io/2020/02/09/%EC%84%B1%EB%8A%A5%EC%9D%84-%EB%86%92%EC%9D%B4%EB%8A%94-%EC%BD%94%EB%93%9C-%EC%8A%A4%ED%83%80%EC%9D%BC/&quot;&gt;성능을 높이는 코드 스타일&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(&lt;/span&gt;&lt;a href=&quot;https://vinomuse.github.io/Javascript/code-style-for-performance/&quot;&gt;다른 버전1&lt;/a&gt;, &lt;a href=&quot;https://mobicon.tistory.com/110&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다른버전2&lt;/a&gt;, &lt;a href=&quot;https://12bme.tistory.com/134&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다른버전3&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2012/11/writing-fast-memory-efficient-javascript/&quot;&gt;How&amp;nbsp;To&amp;nbsp;Write&amp;nbsp;Fast,&amp;nbsp;Memory-Efficient&amp;nbsp;JavaScript&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://gamealchemist.wordpress.com/2013/05/01/lets-get-those-javascript-arrays-to-work-fast/&quot;&gt;Let&amp;rsquo;s&amp;nbsp;get&amp;nbsp;those&amp;nbsp;Javascript&amp;nbsp;Arrays&amp;nbsp;to&amp;nbsp;work&amp;nbsp;fast&lt;/a&gt;, &lt;a href=&quot;https://github.com/sq/JSIL/wiki/Optimizing-dynamic-JavaScript-with-inline-caches&quot;&gt;Optimizing dynamic JavaScript with inline caches&lt;/a&gt;, &lt;a href=&quot;https://bonsaiden.github.io/JavaScript-Garden/ko/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript&amp;nbsp;Garden&lt;/a&gt;, &lt;a href=&quot;https://v8.dev/blog/react-cliff&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React-Cliff&lt;/a&gt;, &lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20210611&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;당신이&amp;nbsp;모르는&amp;nbsp;자바스크립트의&amp;nbsp;메모리&amp;nbsp;누수의&amp;nbsp;비밀&lt;/a&gt;, &lt;a href=&quot;https://github.com/amark/gun/wiki/Performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;amark/gun - Performance&lt;/a&gt;, &lt;a href=&quot;https://github.com/petkaantonov/bluebird/wiki/Optimization-killers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimiztion-killers&lt;/a&gt;, &lt;a href=&quot;https://velog.io/@wongue_shin/JS%EC%9D%98-%EA%B0%9D%EC%B2%B4%EB%8A%94-hash-table%EC%9D%B4-%EC%95%84%EB%8B%99%EB%8B%88%EB%8B%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JS의&amp;nbsp;객체는&amp;nbsp;hash&amp;nbsp;table이&amp;nbsp;아닙니다!&lt;/a&gt;, &lt;a href=&quot;https://felixgerschau.com/javascript-memory-management/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript's&amp;nbsp;Memory&amp;nbsp;Management&amp;nbsp;Explained&lt;/a&gt;, 자바스크립트 성능 최적화(&lt;a href=&quot;https://jicjjang.github.io/posts/javascript-optimize-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;1&lt;/a&gt;, &lt;a href=&quot;https://jicjjang.github.io/posts/javascript-optimize-2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2&lt;/a&gt;, &lt;a href=&quot;https://jicjjang.github.io/posts/javascript-optimize-3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;3&lt;/a&gt;, &lt;a href=&quot;https://jicjjang.github.io/posts/javascript-optimize-4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;4&lt;/a&gt;, &lt;a href=&quot;https://jicjjang.github.io/posts/javascript-optimize-6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;6&lt;/a&gt;, &lt;a href=&quot;https://jicjjang.github.io/posts/javascript-optimize-7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;7&lt;/a&gt;, &lt;a href=&quot;https://jicjjang.github.io/posts/javascript-optimize-8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;8&lt;/a&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;/p&gt;
&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;- 스코프 체인(Scope Chain)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 함수 내부에서 접근 가능한 활성화 객체와 전역 객체로 나눌수 있다. [&lt;a href=&quot;https://learn.co/lessons/js-principles-scope-chain-readme&quot;&gt;Js Principles Scope Chain Readme&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://dmitryfrank.com/articles/js_closures&quot;&gt;How&amp;nbsp;do&amp;nbsp;JavaScript&amp;nbsp;closures&amp;nbsp;work&amp;nbsp;under&amp;nbsp;the&amp;nbsp;hood&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수에서 지역변수나 this, arguments등은 활성화 객체,&lt;span&gt;&amp;nbsp;&lt;/span&gt;전역변수, document 등은 전역 객체다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1D29F/btqXobiXopx/9jYKAQ918su85wfF4GRkT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1D29F/btqXobiXopx/9jYKAQ918su85wfF4GRkT0/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot; style=&quot;width: 51.9575%; margin-right: 10px;&quot; data-widthpercent=&quot;52.57&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1D29F/btqXobiXopx/9jYKAQ918su85wfF4GRkT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1D29F%2FbtqXobiXopx%2F9jYKAQ918su85wfF4GRkT0%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;1280&quot; height=&quot;853&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5C1Zr/btqWXa7ELhn/qZxRVERQyboKARmOEpR88k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5C1Zr/btqWXa7ELhn/qZxRVERQyboKARmOEpR88k/img.png&quot; style=&quot;width: 46.8797%;&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;356&quot; data-widthpercent=&quot;47.43&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5C1Zr/btqWXa7ELhn/qZxRVERQyboKARmOEpR88k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5C1Zr%2FbtqWXa7ELhn%2FqZxRVERQyboKARmOEpR88k%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;482&quot; height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Scope Chain&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;span style=&quot;color: #333333;&quot;&gt;각 객체에 접근하기 위한 객체의 참조가 특정한 공간에 저장되어 있으며 이를 스코프 체인이라 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boLayr/btqW4hSrXXV/b660Lf1K7qS5ZK7DrWrfUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boLayr/btqW4hSrXXV/b660Lf1K7qS5ZK7DrWrfUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boLayr/btqW4hSrXXV/b660Lf1K7qS5ZK7DrWrfUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboLayr%2FbtqW4hSrXXV%2Fb660Lf1K7qS5ZK7DrWrfUK%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;671&quot; height=&quot;384&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&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 style=&quot;color: #333333;&quot;&gt;실행 문맥 -&amp;gt; 스코프 체인 -&amp;gt; 활성화 객체 -&amp;gt; 스코프 체인 -&amp;gt; 전역 객체&lt;/span&gt;&lt;/span&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;&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;해시 함수를 이용해 객체 속성 값의 위치를 메모리에 저장하기 때문이다.&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crxgU8/btqXb2gahya/tiWknLg20hDHZDcXZtRASK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crxgU8/btqXb2gahya/tiWknLg20hDHZDcXZtRASK/img.png&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crxgU8/btqXb2gahya/tiWknLg20hDHZDcXZtRASK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrxgU8%2FbtqXb2gahya%2FtiWknLg20hDHZDcXZtRASK%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;1024&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlPirh/btqXj8GOron/Z6FSTXfDCJGJC5xQKBPweK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlPirh/btqXj8GOron/Z6FSTXfDCJGJC5xQKBPweK/img.png&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlPirh/btqXj8GOron/Z6FSTXfDCJGJC5xQKBPweK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlPirh%2FbtqXj8GOron%2FZ6FSTXfDCJGJC5xQKBPweK%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;1024&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dK12kL/btqXobQMMM9/cfQkc4RpDz9F6aHHZktQa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dK12kL/btqXobQMMM9/cfQkc4RpDz9F6aHHZktQa1/img.png&quot; style=&quot;width: 32.5581%;&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot; data-widthpercent=&quot;33.34&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dK12kL/btqXobQMMM9/cfQkc4RpDz9F6aHHZktQa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdK12kL%2FbtqXobQMMM9%2FcfQkc4RpDz9F6aHHZktQa1%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;1024&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;히든 클래스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1610543047169&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;function Point(x, y) {
  this.x = x; // New Hidden Class based C0 - C1
  this.y = y; // New Hidden Class based C1 - C2
}

const p1 = new Point(1, 2); // Initcial Hidden Class - C0&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;&lt;span style=&quot;color: #333333;&quot;&gt;컴파일 과정을 배워본 사람, 또는 C로 코딩을 조금이라도 해본 사람이라면 인라인닝을 들어본적이 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ektAtm/btqWXa7EL0k/9zwCkkEqBKHvkNJd7Oqs70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ektAtm/btqWXa7EL0k/9zwCkkEqBKHvkNJd7Oqs70/img.png&quot; style=&quot;width: 44.132%; margin-right: 10px;&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;476&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-widthpercent=&quot;44.65&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ektAtm/btqWXa7EL0k/9zwCkkEqBKHvkNJd7Oqs70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FektAtm%2FbtqWXa7EL0k%2F9zwCkkEqBKHvkNJd7Oqs70%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;512&quot; height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biUomT/btqW4gF0rTf/Ec6qZUxuye3wkVvpxlMSk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biUomT/btqW4gF0rTf/Ec6qZUxuye3wkVvpxlMSk0/img.png&quot; style=&quot;width: 54.7052%;&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot; data-widthpercent=&quot;55.35&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biUomT/btqW4gF0rTf/Ec6qZUxuye3wkVvpxlMSk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiUomT%2FbtqW4gF0rTf%2FEc6qZUxuye3wkVvpxlMSk0%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;1024&quot; height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/div&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;내가 알기로 인라인 캐싱을 가장 잘 사용하는 라이브러리 중 하나가 most.js [&lt;a href=&quot;https://github.com/kefirjs/kefir/issues/198&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Improving&amp;nbsp;performance&lt;/a&gt;, &lt;a href=&quot;https://github.com/cujojs/most/issues/137&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;comes&amp;nbsp;it&amp;nbsp;so&amp;nbsp;much&amp;nbsp;faster&amp;nbsp;than&amp;nbsp;LoDash?&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;V8엔진에서 --trace_inlining 옵션을 켰을때 다음과 같이 나온다고.&lt;/p&gt;
&lt;pre id=&quot;code_1613904297763&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Inlined sum called from AccumulateSink.event.
Inlined noop called from Observer.event.
Inlined Observer.event called from AccumulateSink.event.
Inlined even called from FilterMapSink.event.
Inlined add1 called from FilterMapSink.event.
Inlined sum called from AccumulateSink.event.
Inlined noop called from Observer.event.
Inlined Observer.event called from AccumulateSink.event.
Inlined AccumulateSink.event called from FilterMapSink.event.
Inlined even called from FilterMapSink.event.
Inlined add1 called from FilterMapSink.event.
Inlined sum called from AccumulateSink.event.
Inlined noop called from Observer.event.
Inlined Observer.event called from AccumulateSink.event.
Inlined AccumulateSink.event called from FilterMapSink.event.
Inlined FilterMapSink.event called from produce.
250000000000&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;
&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;&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;&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_1613285947813&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const globalVar = {}; // Bad

// Good
fucntion fn() {
  const localVar = {};
}&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;- 리터럴 할당&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트링도 리터럴이 살짝 빠르다.&lt;/p&gt;
&lt;pre id=&quot;code_1610549665214&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const arr1 = new Array()  // Bad
const arr2 = []           // Good

const obj1 = new Object() // Bad
const obj2 = {}           // Good

const str1 = new String('ABCDEFGHIJKLMNOPQRSTUVWXYZ') // Bad
const str2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'             // Good&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;단, Object의 경우 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JSON.parse()&lt;/a&gt;를 사용하는게 더 빠름. [&lt;a href=&quot;https://www.youtube.com/watch?v=ff4fgQxPaO0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Faster apps with JSON.parse(Chrome Dev Summit 2019)&lt;/a&gt;, &lt;a href=&quot;https://wormwlrm.github.io/2019/12/04/Why-JSON-parse-is-faster-than-object-literal.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;왜 JSON.parse로&amp;nbsp;객체를&amp;nbsp;선언하는&amp;nbsp;방법이&amp;nbsp;더&amp;nbsp;빠를까?&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;b&gt;- 31비트 값&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V8은 객체와 숫자를 32비트로 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체와 숫자여부를 판단하기 위해 SMI(Small Integer, 각각 1, 0) 비트를 쓰기 때문에 31비트가 남는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 31비트를 넘는다면 double 타입으로 전환 후 새로운 객체를 생성하여 성능을 깎아먹는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 31비트 안(2,147,483,647)에서 사용하는게 좋다.&lt;/p&gt;
&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;짧을때는 +=, 길때는 join함수를 사용하는게 좋다.&lt;/p&gt;
&lt;pre id=&quot;code_1610549665215&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Short
let str1 = &quot;&quot;;
str1 += &quot;short&quot;

// long
const arr = [];
arr.push(&quot;long&quot;);
const str2 = arr.join('');&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;- 배열&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;희소 배열(sparse array)은 피하는게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값이 꽉 채워지지 않은 배열은 해시 테이블과 같으며 접근 비용이 크다.&lt;/p&gt;
&lt;pre id=&quot;code_1610549665215&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; 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;// Bad
const arr = new Array(5);
const arr[2] = 3;
const arr[5] = 1;

// Good
const arr = [];
const arr.push(3);
const arr.push(1);&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;배열의 키가 띄엄띄엄 배치되어 좋지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차라리 null로 할당하는게 낫다.&lt;/p&gt;
&lt;pre id=&quot;code_1610549665216&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; 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;const arr = [3, 1];
delete arr[1]; // Bad
arr[1] = null; // Good&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;pre id=&quot;code_1610549665216&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; 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;const arr = [];
const arr[&quot;1&quot;] = 3; // Bad
const arr[0] = 1;   // Good&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;오히려 사용하면서 크기가 커지도록 하는 게 낫다.&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;widthContent&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWQ7jI/btqWWtzB9De/KDveAuZizKp9TleunDOypk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWQ7jI/btqWWtzB9De/KDveAuZizKp9TleunDOypk/img.jpg&quot; data-alt=&quot;사파리만 예외&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWQ7jI/btqWWtzB9De/KDveAuZizKp9TleunDOypk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWQ7jI%2FbtqWWtzB9De%2FKDveAuZizKp9TleunDOypk%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;600&quot; height=&quot;387&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사파리만 예외&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1610549665217&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; 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;const let = new Array(1000000); // Bad
const arr = [];                 // Good&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;push보다 접근자로 할당하는게 더 빠르다.&lt;/p&gt;
&lt;pre id=&quot;code_1610549665217&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; 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;const arr = [];

arr.push(3); // Bad
arr[1] = 5;  // Good&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;hasOwnProperty가 IndexOf보다 낫다. &lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://programmersought.com/article/81685688650/&quot;&gt;Performance&amp;nbsp;comparison&amp;nbsp;between&amp;nbsp;hasOwnProperty&amp;nbsp;and&amp;nbsp;IndexOf&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613301587948&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr.indexOf(1000000)        // Bad
arr.hasOwnProperty(1000000) // Good&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;- 객체 접근&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이는 거의 없으나 .이 []로 접근하는 것보다 살짝 빠르다.[&lt;a href=&quot;https://stackoverflow.com/questions/7291964/javascript-performance-consideration-is-dot-operator-faster-than-subscript-nota&quot;&gt;Javascript&amp;nbsp;performance&amp;nbsp;consideration.&amp;nbsp;Is&amp;nbsp;dot&amp;nbsp;operator&amp;nbsp;faster&amp;nbsp;than&amp;nbsp;subscript&amp;nbsp;notation?&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 IDE 지원면에서 .을 사용하는게 마음에 들더라.&lt;/p&gt;
&lt;pre id=&quot;code_1610549665217&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; 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;const obj = {a: &quot;test&quot;};

obj['a']; // Bad
obj.a     // Good&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;a href=&quot;https://www.toptal.com/javascript/javascript-prototypes-scopes-and-performance-what-you-need-to-know&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript Prototype Chains, Scope Chains, and Performance: What You Need to Know&lt;/a&gt;(&lt;a href=&quot;https://medium.com/@tamm_/%EB%B0%9C%EB%B2%88%EC%97%AD-javascript-prototypes-scopes-and-performance-what-you-need-to-know-5736e20e10c4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;번역&lt;/a&gt;)]&lt;/p&gt;
&lt;pre id=&quot;code_1610549665218&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
const arr = [];
function addFn () {
  arr.push(&quot;test&quot;);
}

// Good
const arr = [];
function addFn () {
  const localArr = arr;
  localArr.push(&quot;test&quot;);
}&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;delete를 한다고 가비지 컬렉션이 일어나지 않으며, 히든클래스만 변경시켜 악영향을 끼친다.&lt;/p&gt;
&lt;pre id=&quot;code_1610553901578&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;const o = { x: 1 };
delete o.x; // Bad
o.x = null; // Good&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;객체를 생성하고 할당할 때, 일정한 순서대로 하는게 좋다.&lt;/p&gt;
&lt;pre id=&quot;code_1610549665218&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; 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;// Bad
const p1 = new Point(1, 2);
p1.a = 5;
p1.b = 6;

const p2 = new Point(3, 4);
p2.b = 7;
p2.a = 8;

// Good
const p3 = new Point(1, 2);
p3.a = 5;
p3.b = 6;

const p4 = new Point(3, 4);
p4.a = 7;
p4.b = 8;&lt;/code&gt;&lt;/pre&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;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;&lt;span style=&quot;color: #333333;&quot;&gt;따라서 처음에 생성자로부터 할당하는게 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610553025217&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
function Point(x, y) {
  this.x = x;
  this.y = y;
}

const p1 = new Point(1, 2);
p1.a = 5;
p1.b = 6;

// Good
function Point(x, y, a, b) {
  this.x = x;
  this.y = y;
  this.a = a;
  this.b = b;
}
const p1 = new Point(1, 2, 5, 6);&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;- 병합하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작을때는 스프레드, 클때는 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/concat&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;concat&lt;/a&gt;이 유리하다. [&lt;a href=&quot;https://javascript.plainenglish.io/efficiently-merging-arrays-in-javascript-32993788a8b2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;to&amp;nbsp;Efficiently&amp;nbsp;Merge&amp;nbsp;Arrays&amp;nbsp;in&amp;nbsp;JavaScript&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDKbUg/btrADS1Cpn1/fROSf8Ojv5tY96Zw97OlwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDKbUg/btrADS1Cpn1/fROSf8Ojv5tY96Zw97OlwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDKbUg/btrADS1Cpn1/fROSf8Ojv5tY96Zw97OlwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDKbUg%2FbtrADS1Cpn1%2FfROSf8Ojv5tY96Zw97OlwK%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;692&quot; height=&quot;526&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;526&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;Deepcopy의 경우, 아직 공식명세에는 없지만 주요 브라우저들에 구현된 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/structuredClone&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;structuredClone()&lt;/a&gt;을 사용해볼 수 있다. [&lt;a href=&quot;https://2ality.com/2022/01/structured-clone.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;structuredClone(): deeply copying objects in JavaScript&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;b&gt;- 상속 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속을 활용하면 메모리를 아낄 수 있다. [&lt;a href=&quot;https://blog.yonatan.dev/prototype-optimizing-memory-usage/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Prototype's real world usage: optimizing memory usage&lt;/a&gt;, &lt;a href=&quot;https://blog.yonatan.dev/prototype-optimizing-memory-usage/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Creating&amp;nbsp;Memory-Optimized&amp;nbsp;Instances&amp;nbsp;with&amp;nbsp;Constructor&amp;nbsp;Functions&amp;nbsp;and&amp;nbsp;Prototypes&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://github.com/fabricjs/fabric.js/wiki/Focus-on-speed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fabric.js&lt;/a&gt;는 상속을 활용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1631807340144&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
function Point(x, y) {
  this.x = x;
  this.y = y;
  
  this.add = function() {
    return this.x + this.y;
  }
}
const p1 = new Point(1, 2);

// Good - Protype
function Point(x, y) {
  this.x = x;
  this.y = y;
}
Point.prototype.add = function() {
  return this.x + this.y;
}
const p2 = new Point(1, 2);

// Good - ES6 Classes
class Point{
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  
  add () {
    return this.x + this.y;
  }
}
const p3 = new Point(1, 2);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 생성관련 내용 이 글들을 참고바란다. [&lt;a href=&quot;https://levelup.gitconnected.com/javascript-best-practices-object-creation-511036aee198&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript Best Practices &amp;mdash; Object Creation&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Details of the object model&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://seokjun.kim/javascript-prototype-inheritance/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Javascript&amp;nbsp;prototype&amp;nbsp;inheritance&lt;/a&gt;, &lt;a href=&quot;https://velog.io/@youngkiu/JavaScript%EC%97%90%EC%84%9C-%EB%8B%A4%EC%96%91%ED%95%9C-%EC%83%81%EC%86%8D-%EB%B0%A9%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript&amp;nbsp;다양한&amp;nbsp;상속&amp;nbsp;방법&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Protype과 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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/The_performance_hazards_of_prototype_mutation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;performance&amp;nbsp;hazards&amp;nbsp;of&amp;nbsp;[[Prototype]]&amp;nbsp;mutation&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[[prototype]]은 수정하지 않는 걸 전제로 최적화 되어있다.&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;옛날에 Promise가 구현이 안되거나 느렸을때 아주 효율적인 구현을 보여준 &lt;a href=&quot;http://bluebirdjs.com/docs/getting-started.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bluebird&lt;/a&gt; 제작자의 조언이다. [&lt;a href=&quot;https://www.reaktor.com/blog/javascript-performance-fundamentals-make-bluebird-fast/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Three JavaScript performance fundamentals that make Bluebird fast&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 내부에 함수 선언 X&lt;/li&gt;
&lt;li&gt;객체 크기 최소화&lt;/li&gt;
&lt;li&gt;계산이 아닌 함수는 일단 적용하고, lazy하게 덮어쓰며 선택적 기능을 구현&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;b&gt;- 동일한 함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일한 함수를 반복적으로 사용하는 방식이 인라인 캐싱에 유리하다.&lt;/p&gt;
&lt;pre id=&quot;code_1610553025217&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
function add1(a, b) {
  return a + b;
}
function add2(a, b) {
  return a + b;
}

const a = add1(1, 2);
const b = add2(3, 5);


// Good
function add(a, b) {
  return a + b;
}

const a = add(1, 2);
const b = add(3, 5);&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;- 동일한 타입&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;pre id=&quot;code_1613299816650&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Funciton
function add(x, y) {
   return x+y;
}

add(1, 2);
add('a','b');
add(my_custom_object, undefined);

// Array
const arr = [1, &amp;ldquo;1&amp;rdquo;, undefined, true, &amp;ldquo;true&amp;rdquo;]);&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;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/TypedArray&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TypedArray&lt;/a&gt;(&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Typed_arrays&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;TypedArray를 사용한 String의 경우 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Archive/Add-ons/Code_snippets/StringView_library&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;StringView&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;b&gt;- 배열 반복&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 반복이다 [&lt;a href=&quot;https://shlrur.github.io/develog/2018/10/18/about-loop-performance/&quot;&gt;About&amp;nbsp;JavaScript&amp;nbsp;Loop&amp;nbsp;Performance(forEach,&amp;nbsp;for,&amp;nbsp;while,&amp;nbsp;etc&amp;hellip;)&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://medium.com/better-programming/which-is-the-fastest-while-for-foreach-for-of-9022902be15e&quot;&gt;Which&amp;nbsp;Is&amp;nbsp;the&amp;nbsp;Fastest:&amp;nbsp;While,&amp;nbsp;For,&amp;nbsp;forEach(),&amp;nbsp;For&amp;hellip;of?&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.freecodecamp.org/news/how-to-optimize-your-javascript-apps-using-loops-d5eade9ba89f/&quot;&gt;How to optimize your JavaScript apps using Loops&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qti9Y/btqWX40vx1M/c8iXEMJnbkEYHwTwBNw5p0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qti9Y/btqWX40vx1M/c8iXEMJnbkEYHwTwBNw5p0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qti9Y/btqWX40vx1M/c8iXEMJnbkEYHwTwBNw5p0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQti9Y%2FbtqWX40vx1M%2Fc8iXEMJnbkEYHwTwBNw5p0%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;768&quot; height=&quot;320&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;while&amp;nbsp;&amp;gt;=&amp;nbsp;for&amp;nbsp;&amp;gt;&amp;nbsp;for&amp;nbsp;of&amp;nbsp;&amp;gt;&amp;nbsp;forEach(native)&amp;nbsp;&amp;gt;&amp;nbsp;forEach(loadsh)&amp;nbsp;&amp;gt;&amp;nbsp;each(underscore)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Native가 빠르며, 우리가 C/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;&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;widthContent&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cT2mHX/btqXgpB5t5b/HIzH6E5uE2HQnbdhu0P97K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cT2mHX/btqXgpB5t5b/HIzH6E5uE2HQnbdhu0P97K/img.png&quot; data-alt=&quot;milliseconds&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cT2mHX/btqXgpB5t5b/HIzH6E5uE2HQnbdhu0P97K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcT2mHX%2FbtqXgpB5t5b%2FHIzH6E5uE2HQnbdhu0P97K%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;1012&quot; height=&quot;588&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;588&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;milliseconds&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 곳에서는 For of가, 클때는 While이 유리하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;For은 평균, ForEach는 항상 느리다는 듯 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 map, filter, reduce 성능과 비교하면 어떨까?? [&lt;a href=&quot;https://github.com/dg92/Performance-Analysis-JS&quot;&gt;Performance-Analysis JS&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://daesuni.github.io/Loop-performance/&quot;&gt;for,&amp;nbsp;foreach,&amp;nbsp;filter,&amp;nbsp;map,&amp;nbsp;reduce&amp;nbsp;기능&amp;nbsp;및&amp;nbsp;성능&amp;nbsp;비교&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vpT5v/btqXgopDpWB/a7unFESyqEnAxSsiBRDe7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vpT5v/btqXgopDpWB/a7unFESyqEnAxSsiBRDe7K/img.png&quot; style=&quot;width: 53.5365%; margin-right: 10px;&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;1398&quot; data-widthpercent=&quot;54.17&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vpT5v/btqXgopDpWB/a7unFESyqEnAxSsiBRDe7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvpT5v%2FbtqXgopDpWB%2Fa7unFESyqEnAxSsiBRDe7K%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;1210&quot; height=&quot;1398&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfeHZ4/btqXoa5qyKJ/5iByT1Qk6WvyR0mCxY2kD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfeHZ4/btqXoa5qyKJ/5iByT1Qk6WvyR0mCxY2kD0/img.png&quot; style=&quot;width: 45.3007%;&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;1390&quot; data-widthpercent=&quot;45.83&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfeHZ4/btqXoa5qyKJ/5iByT1Qk6WvyR0mCxY2kD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfeHZ4%2FbtqXoa5qyKJ%2F5iByT1Qk6WvyR0mCxY2kD0%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;1018&quot; height=&quot;1390&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;for이 빠르다!!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;For이 Native 고차함수들 보다 빠름을 알 수 있다.&lt;/p&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 in문은 확연히 느린 편이며 가능하다면, 다른 구분을 사용하는게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열이 아니라 일반 객체로 취급하며, 반복 때마다 property에 접근해야 하기 때문이다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클 때: While&lt;/li&gt;
&lt;li&gt;작을 때: For of&lt;/li&gt;
&lt;li&gt;네이티브가 빠름&lt;/li&gt;
&lt;li&gt;For in은 상당히 느림&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 루프 성능이 중요한 프로그램을 짤 일이 있을까 싶으니 For in이 느리다는 점만은 기억해두는것을 추천.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 길이를 지역변수에 할당하면 매번 크기를 체크할 필요가 없고, 역순으로 순회하면 변수가 아닌 상수 0과 비교하므로 약간의 이득이 있다. [&lt;a href=&quot;https://techblog.woowahan.com/2547/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;실시간&amp;nbsp;서비스&amp;nbsp;경험기(배달운영시스템)&lt;/a&gt;, &lt;a href=&quot;https://stackoverflow.com/questions/1340589/are-loops-really-faster-in-reverse&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Are&amp;nbsp;loops&amp;nbsp;really&amp;nbsp;faster&amp;nbsp;in&amp;nbsp;reverse?&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1646014378408&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// length를 지역 변수에, 루프 순서를 역으로 
for (let i = (array.length - 1); i &amp;gt;= 0; i--) {
  // for문 내부에 배열을 지역변수에 할당
  const item = array[i];
  //...
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩된 for문 같은 경우, 큰 반복이 안쪽에 있는게 효율적이다. [&lt;a href=&quot;https://bytefish.medium.com/does-for-loop-nesting-order-affect-performance-dbc677217e66&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Does for-loop Nesting Order Affect Performance?&lt;/a&gt;]&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;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/315Fi/btrAFNZo49e/LQCqRgIjzar0gfKqP1e5k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/315Fi/btrAFNZo49e/LQCqRgIjzar0gfKqP1e5k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/315Fi/btrAFNZo49e/LQCqRgIjzar0gfKqP1e5k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F315Fi%2FbtrAFNZo49e%2FLQCqRgIjzar0gfKqP1e5k1%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;500&quot; height=&quot;514&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;514&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;b&gt;- 객체 반복&lt;/b&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://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Map&quot;&gt;Map&lt;/a&gt;을 사용하는게 좋다.&amp;nbsp; [&lt;a href=&quot;https://medium.com/@wdjty326/javascript-es6-map-vs-object-performance-%EB%B9%84%EA%B5%90-7f98e30bf6c8&quot;&gt;JavaScript&amp;nbsp;ES6&amp;nbsp;Map&amp;nbsp;vs&amp;nbsp;Object&amp;nbsp;Performance&amp;nbsp;비교&lt;/a&gt;, &lt;a href=&quot;https://benediktmeurer.de/2017/09/07/restoring-for-in-peak-performance/&quot;&gt;Restoring for..in peak performance&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;999&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pNz8f/btqXb1O2cE5/lGBdNrVDwwcjYhnCgf2ZH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pNz8f/btqXb1O2cE5/lGBdNrVDwwcjYhnCgf2ZH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pNz8f/btqXb1O2cE5/lGBdNrVDwwcjYhnCgf2ZH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpNz8f%2FbtqXb1O2cE5%2FlGBdNrVDwwcjYhnCgf2ZH1%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;999&quot; height=&quot;524&quot; data-origin-width=&quot;999&quot; data-origin-height=&quot;524&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;그러나 API로부터 받아오는 정보가 객체 타입이라던지,&amp;nbsp; 일반적인 객체를 이용해야 하는 상황이 있을 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통의 상황에서는 Object.keys &amp;gt; for in &amp;gt; Object.getOwnPropertyNames, Object.values, Object.entries 순이다. [&lt;a href=&quot;https://gists.cwidanage.com/2018/06/how-to-iterate-over-object-entries-in.html&quot;&gt;How&amp;nbsp;to&amp;nbsp;Iterate&amp;nbsp;Over&amp;nbsp;JavaScript&amp;nbsp;Object&amp;nbsp;Entries&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;371&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9kimT/btqW1sGHoAD/xGBnAsGnQHI6b74Kbu5Ug1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9kimT/btqW1sGHoAD/xGBnAsGnQHI6b74Kbu5Ug1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9kimT/btqW1sGHoAD/xGBnAsGnQHI6b74Kbu5Ug1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9kimT%2FbtqW1sGHoAD%2FxGBnAsGnQHI6b74Kbu5Ug1%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;717&quot; height=&quot;371&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;371&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;a href=&quot;https://stackoverflow.com/a/25700742&quot;&gt;What's&amp;nbsp;the&amp;nbsp;fastest&amp;nbsp;way&amp;nbsp;to&amp;nbsp;iterate&amp;nbsp;over&amp;nbsp;an&amp;nbsp;object's&amp;nbsp;properties&amp;nbsp;in&amp;nbsp;Javascript?&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://benediktmeurer.de/2017/07/14/faster-collection-iterators/&quot;&gt;Faster&amp;nbsp;Collection&amp;nbsp;Iterators&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;679&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAS9hY/btqXobQMLqL/7HYhR1n91z5mj60KB3OrYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAS9hY/btqXobQMLqL/7HYhR1n91z5mj60KB3OrYk/img.png&quot; data-alt=&quot;훨씬 빠르다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAS9hY/btqXobQMLqL/7HYhR1n91z5mj60KB3OrYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAS9hY%2FbtqXobQMLqL%2F7HYhR1n91z5mj60KB3OrYk%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;820&quot; height=&quot;679&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;679&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보통의 경우 Map&lt;/li&gt;
&lt;li&gt;객체 사용이 꼭 필요한 경우 Object.keys + for 루프&lt;/li&gt;
&lt;li&gt;더 나은 성능이 필요하다면 Pre-Compiled 이터레이터 기법을 써보는게 어떨까&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;b&gt;- 비동기/병렬 루프&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기나 병렬로 빠르게 반복하는 방법도 존재한다.&amp;nbsp; [&lt;a href=&quot;https://lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795/&quot;&gt;JavaScript&amp;nbsp;loops&amp;nbsp;-&amp;nbsp;how&amp;nbsp;to&amp;nbsp;handle&amp;nbsp;async/await,&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://velog.io/@minsangk/2019-09-06-0209-%EC%9E%91%EC%84%B1%EB%90%A8-eik06xy8mm&quot;&gt;map, reduce 함수에서 async/await 쓰기&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;1123&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y4v2O/btqXgo4giUa/YoPOVUnlEvGecnJfYI49a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y4v2O/btqXgo4giUa/YoPOVUnlEvGecnJfYI49a1/img.png&quot; data-alt=&quot;Async Loop, Lower is better&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y4v2O/btqXgo4giUa/YoPOVUnlEvGecnJfYI49a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY4v2O%2FbtqXgo4giUa%2FYoPOVUnlEvGecnJfYI49a1%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;768&quot; height=&quot;1123&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;1123&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Async Loop, Lower is better&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;map과 Promise.all의 오버헤드 때문.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로미스나 Async는 오버헤드가 존재합니다. [&lt;a href=&quot;https://madelinemiller.dev/blog/javascript-promise-overhead/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Performance&amp;nbsp;Overhead&amp;nbsp;of&amp;nbsp;JavaScript&amp;nbsp;Promises&amp;nbsp;and&amp;nbsp;Async&amp;nbsp;Await&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dYEZ8W/btqXgpvkUkI/ySZ5dtkQWhOQ542rKDaOf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dYEZ8W/btqXgpvkUkI/ySZ5dtkQWhOQ542rKDaOf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dYEZ8W/btqXgpvkUkI/ySZ5dtkQWhOQ542rKDaOf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdYEZ8W%2FbtqXgpvkUkI%2FySZ5dtkQWhOQ542rKDaOf1%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;768&quot; height=&quot;320&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;320&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;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;/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;b&gt;- 조건문&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삼항연산자가 if문보다 성능이 좋다. [&lt;a href=&quot;https://stackoverflow.com/questions/2586842/is-ternary-operator-if-else-or-logical-or-faster-in-javascript&quot;&gt;Is&amp;nbsp;ternary&amp;nbsp;operator,&amp;nbsp;if-else&amp;nbsp;or&amp;nbsp;logical&amp;nbsp;OR&amp;nbsp;faster&amp;nbsp;in&amp;nbsp;javascript?&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 JS Perf에 들어가서 측정했다.&lt;/p&gt;
&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_1610552062708&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; 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;const a = true;
let b;

// 1st: 590,142,828 Ops/sec
b = (a === true) ? true : false;

// 2nd: 589,956,625 Ops/sec
if (a === true) {
  b = true;
} else {
  b = false
}

// 3rd: 574,265,651 Ops/sec
b = (a) ? true : false;

// 4th: 570,864,623 Ops/sec
if (a) {
  b = true;
} else {
  b = false;
}

// 5th: 33,590,726 Ops/sec
// 94% slower
b = (a == true) ? true : false;

// 6th: 33,215,602 Ops/sec
if (a == true) {
  b = true;
} else {
  b = false;
}&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;조건문이 많아질 때는 switch가 if보다 유리하다. [&lt;a href=&quot;https://www.oreilly.com/library/view/high-performance-javascript/9781449382308/ch04.html#if-else_versus_switch&quot;&gt;Chapter&amp;nbsp;4.&amp;nbsp;Algorithms&amp;nbsp;and&amp;nbsp;Flow&amp;nbsp;Control&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;&lt;b&gt;- 느긋한 계산&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지연 평가를 사용하여 성능 개선을 할 수 있다. [&lt;a href=&quot;https://armadillo-dev.github.io/javascript/whit-is-lazy-evaluation/&quot;&gt;지연 평가(Lazy evaluation) 를 이용한 성능 개선&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;http://filimanjaro.com/blog/2014/introducing-lazy-evaluation/&quot;&gt;How to Speed Up Lo-Dash &amp;times;100? Introducing Lazy Evaluation&lt;/a&gt;(&lt;a href=&quot;https://edykim.com/ko/post/introduction-to-lodashs-delay-evaluation-by-filip-zawada/&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;lodash-naive.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgwsK2/btrlDAuxeWo/dA1WZ9oEkLLefkMI84caJk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgwsK2/btrlDAuxeWo/dA1WZ9oEkLLefkMI84caJk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgwsK2/btrlDAuxeWo/dA1WZ9oEkLLefkMI84caJk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cgwsK2/btrlDAuxeWo/dA1WZ9oEkLLefkMI84caJk/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;400&quot; height=&quot;280&quot; data-filename=&quot;lodash-naive.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;grafika.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XQXbp/btrlFctbCVY/WoSDy4TJJYEZ63uK9Eb8I0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XQXbp/btrlFctbCVY/WoSDy4TJJYEZ63uK9Eb8I0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XQXbp/btrlFctbCVY/WoSDy4TJJYEZ63uK9Eb8I0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/XQXbp/btrlFctbCVY/WoSDy4TJJYEZ63uK9Eb8I0/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;400&quot; height=&quot;280&quot; data-filename=&quot;grafika.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;280&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;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;530&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RFKNd/btrlM1Km7aX/b1QJ0smGNhnqdr4BwwK4H1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RFKNd/btrlM1Km7aX/b1QJ0smGNhnqdr4BwwK4H1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RFKNd/btrlM1Km7aX/b1QJ0smGNhnqdr4BwwK4H1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRFKNd%2FbtrlM1Km7aX%2Fb1QJ0smGNhnqdr4BwwK4H1%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;530&quot; height=&quot;388&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;388&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;&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;a href=&quot;https://www.slideshare.net/julyfool/high-performance-javascript-chapter-5-strings-and-regular-expressions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;High&amp;nbsp;Performance&amp;nbsp;JavaScript&amp;nbsp;-&amp;nbsp;Chapter&amp;nbsp;5.&amp;nbsp;Strings&amp;nbsp;and&amp;nbsp;Regular&amp;nbsp;Expressions&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;pre id=&quot;code_1646028446875&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
for (let i = 0; i &amp;lt; 100; i++) {
  str.replace(/^\s+/, '').replace(/\s+$/, '');
}
 
// Good
const reg1 = /^\s+/;
const reg2 = /\s+$/;
for (let i = 0; i &amp;lt; 100; i++) {
  str.replace(reg1, '').replace(reg2, '');
}&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;간단한 예는 각종 그룹을 하나로 만드는 것이다. [&lt;a href=&quot;https://github.com/DmitrySoshnikov/regexp-tree/tree/master/src/optimizer&quot;&gt;예제들&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1641524912368&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const re = /[a-zA-Z_0-9][A-Z_\da-z]*\e{1,}/; // Bad
const re = /\w+e+/; // Good&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;&lt;a href=&quot;https://github.com/BrainMaestro/eslint-plugin-optimize-regex&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;eslint-plugin-optimize-regex&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 동작은 Trim을 하는데, 정규표현식은 문자열 마지막으로 건너뛰는 동작이 불가능하므로 첫번째 코드는 비효율적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;trim12의 경우 &lt;a href=&quot;https://blog.stevenlevithan.com/archives/faster-trim-javascript&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Faster&amp;nbsp;JavaScript&amp;nbsp;Trim&lt;/a&gt;의 최적화가 적용된 코드.&lt;/p&gt;
&lt;pre id=&quot;code_1646017478344&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Bad
str.replace(/^\s+|\s+$/g, &quot;&quot;);

// Good
str.replace(/^\s+/, '').replace(/\s+$/, '');

// Trick
function trim12 (input) {
  const	str = input.replace(/^\s\s*/, '');
  const ws = /\s/;
  let i = str.length;

  while (ws.test(str.charAt(--i)));
  return str.slice(0, i + 1);
}&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;일치하는 것을 찾는데&quot; 걸리는 것이 아니라 &quot;일치하지 않는다고 판단&quot;하는데 시간이 소모되기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHipS2/btruDBRsh0g/ocKAOuUK8kqzSJq62mHmkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHipS2/btruDBRsh0g/ocKAOuUK8kqzSJq62mHmkk/img.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;464&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHipS2/btruDBRsh0g/ocKAOuUK8kqzSJq62mHmkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHipS2%2FbtruDBRsh0g%2FocKAOuUK8kqzSJq62mHmkk%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;618&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tgXaA/btrup74xVAc/OXLKTWAQNswpgl4jB5Clw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tgXaA/btrup74xVAc/OXLKTWAQNswpgl4jB5Clw0/img.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tgXaA/btrup74xVAc/OXLKTWAQNswpgl4jB5Clw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtgXaA%2Fbtrup74xVAc%2FOXLKTWAQNswpgl4jB5Clw0%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;618&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C15pm/btruIUic4YE/u7K7UU5cBFoKjXlPL6dbdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C15pm/btruIUic4YE/u7K7UU5cBFoKjXlPL6dbdK/img.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C15pm/btruIUic4YE/u7K7UU5cBFoKjXlPL6dbdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC15pm%2FbtruIUic4YE%2Fu7K7UU5cBFoKjXlPL6dbdK%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;618&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V0L0i/btruArBODVF/oWZXgykYsyGJM5K3wToql1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V0L0i/btruArBODVF/oWZXgykYsyGJM5K3wToql1/img.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-top: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V0L0i/btruArBODVF/oWZXgykYsyGJM5K3wToql1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV0L0i%2FbtruArBODVF%2FoWZXgykYsyGJM5K3wToql1%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;618&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfe6tn/btruIT4FVfz/k5dlBnvemFNtX3ixnqHDz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfe6tn/btruIT4FVfz/k5dlBnvemFNtX3ixnqHDz0/img.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfe6tn/btruIT4FVfz/k5dlBnvemFNtX3ixnqHDz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcfe6tn%2FbtruIT4FVfz%2Fk5dlBnvemFNtX3ixnqHDz0%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;618&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1Jyx1/btruxk4kM0g/rWpymYKsFkOymq8FTBcB81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1Jyx1/btruxk4kM0g/rWpymYKsFkOymq8FTBcB81/img.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-top: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1Jyx1/btruxk4kM0g/rWpymYKsFkOymq8FTBcB81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1Jyx1%2Fbtruxk4kM0g%2FrWpymYKsFkOymq8FTBcB81%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;618&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;618&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lY7RB/btruHx1TeVJ/xyy6Ob4MyHz9XpIhBkFCF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lY7RB/btruHx1TeVJ/xyy6Ob4MyHz9XpIhBkFCF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lY7RB/btruHx1TeVJ/xyy6Ob4MyHz9XpIhBkFCF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlY7RB%2FbtruHx1TeVJ%2Fxyy6Ob4MyHz9XpIhBkFCF0%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;618&quot; height=&quot;464&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmWDLE/btruI7V5jHm/zBfEZGN6FSALon0Wfv1U51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmWDLE/btruI7V5jHm/zBfEZGN6FSALon0Wfv1U51/img.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmWDLE/btruI7V5jHm/zBfEZGN6FSALon0Wfv1U51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmWDLE%2FbtruI7V5jHm%2FzBfEZGN6FSALon0Wfv1U51%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;618&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eoJQG2/btrulTeLTmg/tijamI4NijPMiMKLutvDrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eoJQG2/btrulTeLTmg/tijamI4NijPMiMKLutvDrk/img.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eoJQG2/btrulTeLTmg/tijamI4NijPMiMKLutvDrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeoJQG2%2FbtrulTeLTmg%2FtijamI4NijPMiMKLutvDrk%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;618&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPcVLh/btruKiC9jZJ/qw7EynWhiXUaeToAqmo1I1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPcVLh/btruKiC9jZJ/qw7EynWhiXUaeToAqmo1I1/img.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPcVLh/btruKiC9jZJ/qw7EynWhiXUaeToAqmo1I1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPcVLh%2FbtruKiC9jZJ%2Fqw7EynWhiXUaeToAqmo1I1%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;618&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;/div&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;/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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/puritanic/nsfw-use-cases-for-bitwise-operators-in-js-2om5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NSFW:&amp;nbsp;Use&amp;nbsp;cases&amp;nbsp;for&amp;nbsp;Bitwise&amp;nbsp;operators&amp;nbsp;in&amp;nbsp;Js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/everget/320499f197bc27901b90847bf9159164&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript&amp;nbsp;Bitwise&amp;nbsp;Hacks&lt;/a&gt;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FlorianWendelborn/bitwise&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;bitwise&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Relik77/bitwise-operation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;bitwise-operation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/aesy/easy-bits&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Easy Bits&lt;/a&gt;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비트 플래그(Bit Flags)&lt;/li&gt;
&lt;li&gt;비트 필드(Bit Fields)&lt;/li&gt;
&lt;li&gt;비트 마스크(Bit Masks)&lt;/li&gt;
&lt;li&gt;비트 어레이(Bit Arrays)&lt;/li&gt;
&lt;li&gt;Enum(타입스크립트 한정)&lt;/li&gt;
&lt;/ul&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;- Asm.js와 LLJS&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트만 이용해 정말로 극한까지 짜내보고 싶다!!는 사람은 &lt;a href=&quot;http://asmjs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;asm.js&lt;/a&gt;(&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Games/Tools/asm.js?source=post_page&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN&lt;/a&gt;)와 &lt;a href=&quot;https://github.com/mbebenita/LLJS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LLJS&lt;/a&gt;의 코딩 패턴을 살펴보면 되겠다. [&lt;a href=&quot;http://badassjs.com/post/43420901994/asm-js-a-low-level-highly-optimizable-subset-of&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;asm.js: 컴파일러를 위한 low level, 고도로 최적화 가능한 JavaScript의 서브셋&lt;/a&gt;(&lt;a href=&quot;https://web.archive.org/web/20130409003659/http://atconsole.com/2013/04/04/%EB%B2%88%EC%97%AD-asm-js-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC%EB%A5%BC-%EC%9C%84%ED%95%9C-low-level-%EA%B3%A0%EB%8F%84%EB%A1%9C-%EC%B5%9C%EC%A0%81%ED%99%94-%EA%B0%80%EB%8A%A5%ED%95%9C-javascript/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;번역&lt;/a&gt;), &lt;a href=&quot;https://johnresig.com/blog/asmjs-javascript-compile-target/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Asm.js:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://johnresig.com/blog/asmjs-javascript-compile-target/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The JavaScript Compile Target&lt;/a&gt;,&lt;/span&gt; &lt;a href=&quot;https://jlongster.github.io/cascadiajs-2013/#/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;High-Performance WebGL Apps with LLJS and asm.js&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 typescript 덕에 알게모르게 많이 쓰이는 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Strict_mode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;strict&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;Asm.js의 작성법은 &lt;a href=&quot;https://github.com/zbjornson/human-asmjs&quot;&gt;human-asm.js&lt;/a&gt;, LLJS의 작성법은 공식 홈페이지에서 확인바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLJS를 asm.js로 컴파일한 사람도 있다. [&lt;a href=&quot;https://archive.jlongster.com/Compiling-LLJS-to-asm.js,-Now-Available-&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Compiling LLJS to asm.js&lt;/a&gt;, &lt;a href=&quot;https://gist.github.com/jlongster/5202173&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;</description>
      <category>프로그래밍/Web</category>
      <category>성능</category>
      <category>웹</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/79</guid>
      <comments>https://black7375.tistory.com/79#entry79comment</comments>
      <pubDate>Sun, 14 Feb 2021 18:25:29 +0900</pubDate>
    </item>
    <item>
      <title>좋은 에디터란?</title>
      <link>https://black7375.tistory.com/78</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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3월 업데이트!! 3/19에 Emacs NG에 합류했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/emacs-ng&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/emacs-ng&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1616309608224&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;profile&quot; data-og-title=&quot;Emacs NG&quot; data-og-description=&quot;Emacs New Generation. Emacs NG has 2 repositories available. Follow their code on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/emacs-ng&quot; data-og-url=&quot;https://github.com/emacs-ng&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cD6RLJ/hyJCibdbC6/ghVq3OhSwbXHjyn1PE6OyK/img.png?width=280&amp;amp;height=280&amp;amp;face=0_0_280_280&quot;&gt;&lt;a href=&quot;https://github.com/emacs-ng&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/emacs-ng&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cD6RLJ/hyJCibdbC6/ghVq3OhSwbXHjyn1PE6OyK/img.png?width=280&amp;amp;height=280&amp;amp;face=0_0_280_280');&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;Emacs NG&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Emacs New Generation. Emacs NG has 2 repositories available. Follow their code on GitHub.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&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/emacs-ng/emacs-ng&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;emacs-ng&lt;/a&gt;(&lt;a href=&quot;https://github.com/emacs-ng/emacs-ng/issues/163&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이슈&lt;/a&gt;)라고 &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Emacs&lt;/a&gt; + &lt;a href=&quot;https://deno.land/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Deno&lt;/a&gt;란 끔직한 혼종(?)을 발견했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 끔직한 혼종은 &lt;a href=&quot;https://github.com/remacs/remacs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Remacs&lt;/a&gt;에 &lt;a href=&quot;https://github.com/remacs/remacs/pull/1581&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;풀리퀘스트&lt;/a&gt;로 날라왔던&amp;nbsp; &lt;a href=&quot;https://github.com/servo/webrender&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webrender&lt;/a&gt;까지도 지원하고 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tkxUb/btqWWs02Zz3/8unFpYelYjOUaEImn5Jq7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tkxUb/btqWWs02Zz3/8unFpYelYjOUaEImn5Jq7K/img.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;659&quot; style=&quot;width: 58.656%; margin-right: 10px;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tkxUb/btqWWs02Zz3/8unFpYelYjOUaEImn5Jq7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtkxUb%2FbtqWWs02Zz3%2F8unFpYelYjOUaEImn5Jq7K%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;962&quot; height=&quot;659&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KRcdq/btqW4hjTkGQ/9dqTB0YDVKkTllWkFsyFW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KRcdq/btqW4hjTkGQ/9dqTB0YDVKkTllWkFsyFW0/img.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot; style=&quot;width: 40.1812%;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KRcdq/btqW4hjTkGQ/9dqTB0YDVKkTllWkFsyFW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKRcdq%2FbtqW4hjTkGQ%2F9dqTB0YDVKkTllWkFsyFW0%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;1200&quot; height=&quot;1200&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Emacs X Deno??&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;덕분에 Remacs 프로젝트가 잘 돌아가나 확인하니 2020년 들어 업데이트가 안되고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/remacs/remacs/issues/1571&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Still Alive/Lost Momentum?&lt;/a&gt;란 이슈에서&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;For&amp;nbsp;the&amp;nbsp;most&amp;nbsp;part,&amp;nbsp;the&amp;nbsp;stuff&amp;nbsp;that's&amp;nbsp;left&amp;nbsp;to&amp;nbsp;do&amp;nbsp;is&amp;nbsp;hard.&amp;nbsp;The&amp;nbsp;garbage&amp;nbsp;collector,&amp;nbsp;the&amp;nbsp;bytecode&amp;nbsp;interpreter,&amp;nbsp;anything&amp;nbsp;like&amp;nbsp;that.&amp;nbsp;If&amp;nbsp;we&amp;nbsp;were&amp;nbsp;all&amp;nbsp;getting&amp;nbsp;paid&amp;nbsp;to&amp;nbsp;work&amp;nbsp;on&amp;nbsp;it&amp;nbsp;I'm&amp;nbsp;sure&amp;nbsp;we&amp;nbsp;could&amp;nbsp;figure&amp;nbsp;it&amp;nbsp;out,&amp;nbsp;but&amp;nbsp;as&amp;nbsp;things&amp;nbsp;are&amp;nbsp;now,&amp;nbsp;it's&amp;nbsp;quite&amp;nbsp;a&amp;nbsp;challenge. &lt;br /&gt;&lt;br /&gt;It's important to keep some perspective though. If we look at Remacs as a serious attempt to replace the C core of Emacs with Rust, then we can safely call it a failure, because that isn't going to happen any time soon, maybe ever. BUT, if we look at Remacs as a proof-of-concept to show that it would be possible to do such a replacement, then I would call it a wild success.&lt;br /&gt;- 콜라보레이터&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Although I'm glad there have been more upstream changes than I expected, I think it would have been possible if there wouldn't be that much new code we have to deal with. It's work that doesn't really pay off.&lt;br /&gt;&lt;br /&gt;Maybe we can see this as a decision of the emacs community to stick with things how they are. It's not realistic that such an ambitious project can be handled by a few people since we have to update remacs for code by many more people that lands in upstream.&lt;br /&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;란 코멘트를 보게 되었다.&lt;/p&gt;
&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;이맥스 GUI의 뿌리인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/emacs-mirror/emacs/blob/master/src/xdisp.c&quot;&gt;xdisp.c&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;로 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613140493224&quot; class=&quot;c++ arduino&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: 0.04px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   /*
   +--------------+   redisplay     +----------------+
   | Lisp machine |----------------&amp;gt;| Redisplay code |&amp;lt;--+
   +--------------+   (xdisp.c)     +----------------+   |
	  ^				     |		 |
	  +----------------------------------+           |
	    Block input to prevent this when             |
	    called asynchronously!			 |
							 |
		    note_mouse_highlight (asynchronous)	 |
							 |
				    X mouse events  -----+
							 |
			    expose_frame (asynchronous)	 |
							 |
				   X expose events  -----+
*/&lt;/code&gt;&lt;/pre&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;span&gt;&lt;span&gt;GNU Emacs is an old-school C program emulating a 1980s Symbolics Lisp Machine emulating an old-fashioned Motif-style Xt toolkit emulating a 1970s text terminal emulating a 1960s teletype. Compiling Emacs is a challenge. Adding modern rendering features to the redisplay engine is a miracle.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;a href=&quot;https://www.facebook.com/notes/daniel-colascione/buttery-smooth-emacs/10155313440066102/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Buttery Smooth Emacs&lt;/a&gt;&lt;/span&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;그저 웃음만 나올 것이 틀림없다. ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조도 문제지만 1.1mb의 코드는 더하고 ㅋㅋㅋㅋㅋㅋ&lt;/p&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/emacs-mirror/emacs/blob/master/src/lisp.h&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lisp.h&lt;/a&gt;, &lt;a href=&quot;https://github.com/emacs-mirror/emacs/blob/master/src/eval.c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;eval.c&lt;/a&gt;, &lt;a href=&quot;https://github.com/emacs-mirror/emacs/blob/master/src/bytecode.c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;bytecode.c&lt;/a&gt;처럼 Elisp VM쪽 코드는 각종 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;a href=&quot;https://github.com/remacs/remacs/issues/1571#issuecomment-776542229&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;comment&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Emacs VM(JS VM) + Xi-Editor(Web APIS) 조합으로&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQOI9n/btqWX6wsv5D/21LDzRqtYYwuxhm9K8HeK0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQOI9n/btqWX6wsv5D/21LDzRqtYYwuxhm9K8HeK0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQOI9n/btqWX6wsv5D/21LDzRqtYYwuxhm9K8HeK0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cQOI9n/btqWX6wsv5D/21LDzRqtYYwuxhm9K8HeK0/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;800&quot; height=&quot;422&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;422&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;405&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCvSaL/btqWUMzbHUr/Kv3zgXCuhtyFxYz8kBJXIK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCvSaL/btqWUMzbHUr/Kv3zgXCuhtyFxYz8kBJXIK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCvSaL/btqWUMzbHUr/Kv3zgXCuhtyFxYz8kBJXIK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bCvSaL/btqWUMzbHUr/Kv3zgXCuhtyFxYz8kBJXIK/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;720&quot; height=&quot;405&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;405&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@Rahulx1/understanding-event-loop-call-stack-event-job-queue-in-javascript-63dcd2c71ecd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Understanding Event Loop, Call Stack, Event &amp;amp; Job Queue in Javascript&lt;/a&gt;, &lt;a href=&quot;https://kkangdda.tistory.com/73&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;움짤로&amp;nbsp;보는&amp;nbsp;자바스크립트&amp;nbsp;동작&amp;nbsp;원리(1)&amp;nbsp;-&amp;nbsp;Event&amp;nbsp;Loop&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yUYSC/btq2P4NZmTw/whrMNPrmVuhjecHGJrBdtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yUYSC/btq2P4NZmTw/whrMNPrmVuhjecHGJrBdtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yUYSC/btq2P4NZmTw/whrMNPrmVuhjecHGJrBdtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyUYSC%2Fbtq2P4NZmTw%2FwhrMNPrmVuhjecHGJrBdtK%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;693&quot; height=&quot;418&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;사실 Dart의 이벤트 루프가 마음에 더 든다. [&lt;a href=&quot;https://buildflutter.com/flutter-threading-isolates-future-async-and-await/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Flutter&amp;nbsp;Threading:&amp;nbsp;Isolates,&amp;nbsp;Future,&amp;nbsp;Async&amp;nbsp;And&amp;nbsp;Await&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://github.com/swiboe/swiboe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Swiboe&lt;/a&gt;의 접근(&lt;a href=&quot;https://www.sirver.net/blog/2015/08/04/the-ideal-text-editor/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Ideal&amp;nbsp;Text&amp;nbsp;Editor&lt;/a&gt;, &lt;a href=&quot;http://www.sirver.net/blog/2015/08/04/the-ideal-text-editor/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Design for the ideal text editor&lt;/a&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;b&gt;무료:&lt;/b&gt; 무료가 아니면 요즘 누가 쓸까?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실현 가능성:&lt;/b&gt; 실현 가능해야 한다. 기존의 시스템을 최대한 활용하자.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;크로스 플랫폼:&lt;/b&gt; 어디서든 실행 가능해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능:&lt;/b&gt; 당연하지만 빨라야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장 가능성:&lt;/b&gt; 간단한 모듈이나 스크립트, 매크로 형태는 물론 플러그인을 지원하고 UI의 수정까지 가능해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;협업:&lt;/b&gt; 실시간으로 협업이 가능해야 한다.&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://emacsconf.org/2019/talks/26/&quot;&gt;Emacs: The Editor for the Next Forty Years - Perry E. Metzger&lt;/a&gt;(&lt;a href=&quot;https://mirror.csclub.uwaterloo.ca/emacsconf/2019/emacsconf-2019-26-emacs-the-editor-for-the-next-forty-years--slides--pmetzger.pdf&quot;&gt;PDF&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.murilopereira.com/emacs-from-catching-up-to-getting-ahead/&quot;&gt;Emacs:&amp;nbsp;from&amp;nbsp;catching&amp;nbsp;up&amp;nbsp;to&amp;nbsp;getting&amp;nbsp;ahead&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;그리고 OSI 7 Layer처럼 추상화가 이루어져&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Lv1 코어:&lt;/b&gt; 에디터 엔진, 스크립트 VM, I/O 기능 등이 들어간다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Lv2 프론트:&lt;/b&gt; 각종 기본 UI 컴포넌트와 API 구현에 집중.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Lv3 스타터 키트:&lt;/b&gt; VS Code처럼 기본적으로 사용하는데 무리가 없을정도로 제공.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Lv4 IDE:&lt;/b&gt; 디버깅, 프로파일링등 다양한 부가기능이 통합적으로 제공된다.&lt;/li&gt;
&lt;/ul&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;Lv1 코어&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;핵심 가치&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;b&gt;크로스 플랫폼:&lt;/b&gt; 이식 가능성을 고려해야함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능:&lt;/b&gt; 백엔드다. 절대적으로 빨라야 할 필요가 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장 가능성:&lt;/b&gt; 백엔드단 부터 고려되어야 함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;협업:&lt;/b&gt; 네트워킹 및 동시 편집도 백엔드단 부터 고려될 필요가 있음.&lt;/li&gt;
&lt;/ul&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://neovim.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Neovim&lt;/a&gt;과&amp;nbsp;&lt;a href=&quot;https://github.com/onivim/libvim&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;libvim&lt;/a&gt;, &lt;a href=&quot;https://github.com/atom-archive/xray&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Xray&lt;/a&gt;, &lt;a href=&quot;https://xi-editor.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;xi-editor&lt;/a&gt;는 에디터의 벡엔드 가능성을 충분히 실험 해주었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;module-structure-model.png&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ekNUk0/btsrdjmhioQ/kxZ6Ne1FLSmKpsg3YnvhI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ekNUk0/btsrdjmhioQ/kxZ6Ne1FLSmKpsg3YnvhI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ekNUk0/btsrdjmhioQ/kxZ6Ne1FLSmKpsg3YnvhI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FekNUk0%2FbtsrdjmhioQ%2FkxZ6Ne1FLSmKpsg3YnvhI1%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;836&quot; height=&quot;467&quot; data-filename=&quot;module-structure-model.png&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://delftswa.gitbooks.io/desosa-2017/content/neovim/chapter.html&quot;&gt;&amp;nbsp;Neovim &amp;middot; Delft Students on Software Architecture: DESOSA 2017&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vY90t/btqXDgsOIep/dtZwvt5HRe5gN7GTyDCEK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vY90t/btqXDgsOIep/dtZwvt5HRe5gN7GTyDCEK0/img.png&quot; data-media-id=&quot;37155956&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;359&quot; style=&quot;width: 64.1526%; margin-right: 10px;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vY90t/btqXDgsOIep/dtZwvt5HRe5gN7GTyDCEK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvY90t%2FbtqXDgsOIep%2FdtZwvt5HRe5gN7GTyDCEK0%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;820&quot; height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czruva/btqXDfAE4hL/2BhnOZsaiZk9yGKt2Hvj11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czruva/btqXDfAE4hL/2BhnOZsaiZk9yGKt2Hvj11/img.png&quot; data-media-id=&quot;37156263&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;647&quot; style=&quot;width: 34.6846%;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czruva/btqXDfAE4hL/2BhnOZsaiZk9yGKt2Hvj11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fczruva%2FbtqXDfAE4hL%2F2BhnOZsaiZk9yGKt2Hvj11%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;799&quot; height=&quot;647&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.patreon.com/posts/onivim-2-update-27614608&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Onivim 2 - Update #3: A re-architecture...&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;950&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/34TPv/btqWVRNPnNb/pBKkLEy9nuEO3a2h707EPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/34TPv/btqWVRNPnNb/pBKkLEy9nuEO3a2h707EPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/34TPv/btqWVRNPnNb/pBKkLEy9nuEO3a2h707EPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F34TPv%2FbtqWVRNPnNb%2FpBKkLEy9nuEO3a2h707EPk%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;1059&quot; height=&quot;950&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;950&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/atom-archive/xray&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Xray&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8mxMJ/btqW1tkDa5v/7WqDHAHjtwEYlHf1lvES80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8mxMJ/btqW1tkDa5v/7WqDHAHjtwEYlHf1lvES80/img.png&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;472&quot; style=&quot;width: 49.4879%; margin-right: 10px;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8mxMJ/btqW1tkDa5v/7WqDHAHjtwEYlHf1lvES80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8mxMJ%2FbtqW1tkDa5v%2F7WqDHAHjtwEYlHf1lvES80%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;848&quot; height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eqblRV/btqWULmQnx5/DRVq7B8EDpPLMU5c8R7xDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eqblRV/btqWULmQnx5/DRVq7B8EDpPLMU5c8R7xDk/img.png&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;475&quot; style=&quot;width: 49.3493%;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eqblRV/btqWULmQnx5/DRVq7B8EDpPLMU5c8R7xDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeqblRV%2FbtqWULmQnx5%2FDRVq7B8EDpPLMU5c8R7xDk%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;851&quot; height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.recurse.com/events/localhost-raph-levien&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Xi:&amp;nbsp;an&amp;nbsp;editor&amp;nbsp;for&amp;nbsp;the&amp;nbsp;next&amp;nbsp;20&amp;nbsp;years&lt;/a&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;&lt;a href=&quot;https://github.com/xi-editor/xi-editor/issues/1187#issuecomment-491473599&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Towards a text editor construction kit&lt;/a&gt;(&lt;a href=&quot;https://news.ycombinator.com/item?id=19886883&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HN&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raphlinus.github.io/xi/2020/06/27/xi-retrospective.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;xi-editor retrospective&lt;/a&gt;(&lt;a href=&quot;https://news.ycombinator.com/item?id=23663878&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HN&lt;/a&gt;, &lt;a href=&quot;https://www.reddit.com/r/rust/comments/hgzdu5/xieditor_retrospective/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reddit&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raphlinus.github.io/personal/2019/02/20/more-small-updates.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;More small updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://xi-editor.io/gsoc.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;xi-editor GSoC&lt;/a&gt;&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;특히 xi-editor의 텍스트에 대한 연구와 집착은 놀라운 수준이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식문서의 &lt;span style=&quot;color: #333333;&quot;&gt;CRDT(&lt;/span&gt;Conflict-free Replicated Data Type)와 Rope에 대한 글을 읽어보자..&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Emacs: The Editor for the Next Forty Years에서도 그렇듯 새로운 프로젝트는 Rust를 적극적으로 활용하는 듯한 모습을 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 소개한 &lt;span style=&quot;color: #333333;&quot;&gt;Swiboe, Xray, xi-editor&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;&lt;a href=&quot;https://github.com/curlpipe/ox&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rhysd/kiro-editor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;kiro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mcobzarenco/zee&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;zee&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;그럼 Rust로 코어를 구성한다고 가정하고, 필요한 기능은 무엇이 있을까?&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cy4eOh/btqXgovWCJ7/GPKaOFvyWEVNkvsr6E88yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cy4eOh/btqXgovWCJ7/GPKaOFvyWEVNkvsr6E88yk/img.png&quot; data-origin-width=&quot;606&quot; data-origin-height=&quot;480&quot; style=&quot;width: 32.5113%; margin-right: 10px;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cy4eOh/btqXgovWCJ7/GPKaOFvyWEVNkvsr6E88yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcy4eOh%2FbtqXgovWCJ7%2FGPKaOFvyWEVNkvsr6E88yk%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;606&quot; height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oXauE/btqWVRtuRPC/XlFPpbgz8UkFJvukHpRN9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oXauE/btqWVRtuRPC/XlFPpbgz8UkFJvukHpRN9K/img.png&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;409&quot; style=&quot;width: 34.6292%; margin-right: 10px;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oXauE/btqWVRtuRPC/XlFPpbgz8UkFJvukHpRN9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoXauE%2FbtqWVRtuRPC%2FXlFPpbgz8UkFJvukHpRN9K%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;550&quot; height=&quot;409&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgCpkm/btqW4ichUKM/fqszoKFKzbmHqYlTtSmjY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgCpkm/btqW4ichUKM/fqszoKFKzbmHqYlTtSmjY1/img.png&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;630&quot; style=&quot;width: 30.5339%;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgCpkm/btqW4ichUKM/fqszoKFKzbmHqYlTtSmjY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgCpkm%2FbtqW4ichUKM%2FfqszoKFKzbmHqYlTtSmjY1%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;747&quot; height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Chrome, Firefox Safari Architecture(&lt;a href=&quot;https://medium.com/web-god-mode/how-web-browsers-work-behind-the-scene-architecture-technologies-and-internal-working-fec601488bfa&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;Web&amp;nbsp;Browsers&amp;nbsp;Work&amp;nbsp;&amp;mdash;&amp;nbsp;Behind&amp;nbsp;the&amp;nbsp;scene&amp;nbsp;Architecture,&amp;nbsp;Technologies,&amp;nbsp;and&amp;nbsp;Internal&amp;nbsp;Working&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sz8VB/btqWX4yTC2X/o2fTnv6xG1ZMxENtD3WBn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sz8VB/btqWX4yTC2X/o2fTnv6xG1ZMxENtD3WBn1/img.png&quot; data-alt=&quot;Chorme's Multipress&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sz8VB/btqWX4yTC2X/o2fTnv6xG1ZMxENtD3WBn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsz8VB%2FbtqWX4yTC2X%2Fo2fTnv6xG1ZMxENtD3WBn1%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;950&quot; height=&quot;310&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Chorme's Multipress&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 에디터 아키텍처와 브라우저 아키텍처를 참고했을때 난&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Editor
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Editor Engine: 텍스트 편집, 협업 등을 위한 기능&lt;/li&gt;
&lt;li&gt;Rendering Engine: 말그대로 렌더링과 관련된 기능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;External Process Manager
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VM: JS, Elisp, Guile처럼 확장을 위한 언어&lt;/li&gt;
&lt;li&gt;Parser&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/language-server-protocol&quot;&gt;LSP(Language Server Protocol)&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;amp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/microsoft/debug-adapter-protocol&quot;&gt;DAP(Debugging Adapter Protocol)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Shell&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I/O&lt;/li&gt;
&lt;/ul&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;&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;size18&quot;&gt;&lt;b&gt;Editor Engine&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;앞서 소개한 Xi-Editor가 가장 적합하다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Xi-Editor는&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;a href=&quot;https://en.wikipedia.org/wiki/Rope_(data_structure)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rope&lt;/a&gt; 구조&lt;/li&gt;
&lt;li&gt;동시 수정을 위한 &lt;a href=&quot;https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CRDT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;Rope 데이터구조는 최악의 경우에서 성능문제가 적으며, [&lt;a href=&quot;https://iq.opengenus.org/data-structures-used-in-text-editor/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Data&amp;nbsp;Structures&amp;nbsp;used&amp;nbsp;in&amp;nbsp;Text&amp;nbsp;Editors&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CRDT를 이용해 중앙서버가 없이도 협업 편집이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Gapbuffer, Zipper(&lt;a href=&quot;https://stanch.github.io/zipper/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JS 구현&lt;/a&gt;), Piece table도 흥미로운 데이터구조다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CRDT의 모델이 상당히 복잡해서 적합하냐는 말들도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://github.com/guevara/read-it-later/issues/6980&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Are&amp;nbsp;CRDTs&amp;nbsp;suitable&amp;nbsp;for&amp;nbsp;shared&amp;nbsp;editing?&lt;/a&gt;&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;VM이 있다지만, 에디터 엔진도 확장 가능하게 만드는게 맞다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 프로젝트 단위에서 코드를 검색하기 위해 &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ripgrep&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-unofficial/awesome-rust#text-processing&quot;&gt;Text Processing&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/variar/klogg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;klogg&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://emacsconf.org/2020/talks/07/&quot;&gt;Beyond&amp;nbsp;Vim&amp;nbsp;and&amp;nbsp;Emacs:&amp;nbsp;A&amp;nbsp;Scalable&amp;nbsp;UI&amp;nbsp;Paradigm&lt;/a&gt;(&lt;a href=&quot;https://github.com/countvajhula/rigpa&quot;&gt;rigpa&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&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;widthContent&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JrX7y/btqW4hEAyCi/ax03GEasq2C0hsI2kJjQRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JrX7y/btqW4hEAyCi/ax03GEasq2C0hsI2kJjQRk/img.png&quot; data-alt=&quot;Mode Tower&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JrX7y/btqW4hEAyCi/ax03GEasq2C0hsI2kJjQRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJrX7y%2FbtqW4hEAyCi%2Fax03GEasq2C0hsI2kJjQRk%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;608&quot; height=&quot;380&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Mode Tower&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;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(예: Vim 키맵, Nano 키맵 등)을&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Rendering Engine&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈화된 코어라 하면 Front 코드가 없는게 맞지 않을까 생각할 수 있다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://pavelfatin.com/typing-with-pleasure/&quot;&gt;Typing with pleasure(Zero-latency typing)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pavelfatin.com/scrolling-with-pleasure/&quot;&gt;Scrolling with pleasure(Smooth scrolling)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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://github.com/servo/webrender&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebRender&lt;/a&gt; + &lt;a href=&quot;https://github.com/servo/pathfinder&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pathfinder&lt;/a&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;a href=&quot;https://gist.github.com/pcwalton/33bd1049d6e3b686d59fbba76fc3575a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebRender Benefits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/servo/servo/wiki/Roadmap&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Servo Roadmap&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 상당히 낮은 레벨의 구현이므로 GUI 툴킷과는 구분될 수 있다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://mrandri19.github.io/2019/07/24/modern-text-rendering-linux-overview.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Modern&amp;nbsp;text&amp;nbsp;rendering&amp;nbsp;with&amp;nbsp;Linux:&amp;nbsp;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mrandri19.github.io/2019/07/18/modern-text-rendering-linux-ep1.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Modern&amp;nbsp;text&amp;nbsp;rendering&amp;nbsp;with&amp;nbsp;Linux:&amp;nbsp;Part&amp;nbsp;1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mrandri19.github.io/2019/08/08/modern-text-rendering-linux-ep2.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Modern text rendering with Linux: Antialiasing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://behdad.org/text/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;State of Text Rendering&lt;/a&gt;(다른 시리즈. 그러나 좋은 글이다.)&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;Pathfinder가 Freetype을 대체할 수 있다고 한다.&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;b&gt;VM&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;a href=&quot;https://www.npmjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NPM&lt;/a&gt;의 라이브러리를 모두 사용할 수 있으며, 프론트/스타터 킷 레벨에서 &lt;a href=&quot;https://code.visualstudio.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Visual Studio Code&lt;/a&gt; 호환 API를 제공하면 &lt;a href=&quot;https://marketplace.visualstudio.com/vscode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Market Place&lt;/a&gt;의 확장기능들을 사용할 길이 열린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 &lt;a href=&quot;https://github.com/denoland/deno&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Deno&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;Elisp나 Vim Script를 쓰고 싶다고??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Elisp는 앞서 말한 Emacs 소스를 사용하거나 Emacs 유저들의 꿈 중 하나인 &lt;a href=&quot;https://www.gnu.org/software/guile/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Guile&lt;/a&gt;(&lt;a href=&quot;https://github.com/texmacs/guile&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;소스&lt;/a&gt;) Emacs를 구현할 수 있겠고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vimscript는 NeoVim의 &lt;a href=&quot;https://github.com/neovim/neovim/tree/master/src/nvim/eval&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Eval&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;내가 Emacs 사용자에 Vim 키맵도 좋아하지만, Deno가 최선의 선택지 아닐까.&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;b&gt;Parser&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LSP를 지원함에도 대체 왜!!&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://meetup.toast.com/posts/229&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;새로운 마크다운 파서가 필요한 이유&lt;/a&gt;(&lt;a href=&quot;https://ui.toast.com/weekly-pick/en_20200402&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;영문&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marijnhaverbeke.nl/blog/lezer.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lezer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nvim-treesitter/nvim-treesitter/issues/484&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Relationship with LSP (especially coc.nvim)&lt;/a&gt;&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;LSP도 구문강조를 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 실시간 문법 강조나 점진적 분석(Incremental Parsing)이 힘들다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;베스트라 하면 &lt;a href=&quot;https://github.com/lezer-parser/lezer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lezer&lt;/a&gt;의 Rust 버전이겠지만, &lt;a href=&quot;https://github.com/tree-sitter/tree-sitter&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tree-Sitter&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;b&gt;+.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://github.com/raphlinus/pulldown-cmark&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;pulldown-cmark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://talk.commonmark.org/t/why-is-md4c-so-fast-c/2520&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Why is MD4C so fast?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/happyprogrammer-in-jeju/%EB%A7%88%ED%81%AC%EB%8B%A4%EC%9A%B4-%ED%8C%8C%EC%84%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-1-%ED%95%A9%EB%A6%AC%ED%99%94%EC%99%80-%EC%82%AC%EC%A0%84%EC%A1%B0%EC%82%AC-932a269b7233&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;마크다운&amp;nbsp;파서&amp;nbsp;만들기&amp;nbsp;(1)&amp;nbsp;-&amp;nbsp;합리화와&amp;nbsp;사전조사&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;b&gt;LSP(Language Sever Protocol) &amp;amp; DAP(Debugging Adapter Protocol)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동완성에서 &lt;a href=&quot;https://github.com/company-mode/company-mode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;company-mode&lt;/a&gt;/&lt;a href=&quot;https://github.com/auto-complete/auto-complete&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;auto-complete&lt;/a&gt;, 디버깅에서 &lt;a href=&quot;https://github.com/weirdNox/emacs-gdb&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GUD&lt;/a&gt;/&lt;a href=&quot;https://github.com/realgud/realgud&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RealGUD&lt;/a&gt;처럼 바로 인터페이스를 구현 후 하나하나 대응하는 것보단 LSP, DAP를 구현만 하는게 낫지 않겠는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 만들어지는 에디터라면 LSP/DAP를 지원하지 않을 이유가 없다.&lt;/p&gt;
&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;비록 C/C++ 전용이지만&lt;/span&gt; &lt;a href=&quot;https://github.com/Andersbakken/rtags&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;rtags&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;size18&quot;&gt;&lt;b&gt;Shell&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Shell을 적극적으로 활용하던 에디터가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://macromates.com/manual/en/shell_commands&quot;&gt;Shell Commands &amp;mdash; TextMate 1.x Manual (macromates.com)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs0HOs/btqXKvvYEi8/pjmYImJRFE0douITMrp4IK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs0HOs/btqXKvvYEi8/pjmYImJRFE0douITMrp4IK/img.png&quot; data-origin-width=&quot;212&quot; data-origin-height=&quot;182&quot; style=&quot;width: 42.4626%; margin-right: 10px;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs0HOs/btqXKvvYEi8/pjmYImJRFE0douITMrp4IK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs0HOs%2FbtqXKvvYEi8%2FpjmYImJRFE0douITMrp4IK%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;212&quot; height=&quot;182&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJuqBy/btqXHfAujjU/ToYUKZjDqOqxglmnkyBkl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJuqBy/btqXHfAujjU/ToYUKZjDqOqxglmnkyBkl0/img.png&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;269&quot; style=&quot;width: 56.3746%;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJuqBy/btqXHfAujjU/ToYUKZjDqOqxglmnkyBkl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJuqBy%2FbtqXHfAujjU%2FToYUKZjDqOqxglmnkyBkl0%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;269&quot;/&gt;&lt;/span&gt;&lt;/div&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;맥에서 Notepad++(윈도우), Kate(리눅스)처럼 사용하던 TextMate의 텍스트 필터 기능이다.&lt;/p&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;size18&quot;&gt;&lt;b&gt;I/O&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검증된 라이브러리인 &lt;a href=&quot;https://github.com/tokio-rs/tokio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tokio&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;다만 커다란 크기의 파일을 위한 모드가 있어야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.emeditor.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Em Editor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/atom/atom/issues/307&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Atom&lt;/a&gt;과&lt;a href=&quot;https://github.com/microsoft/vscode/issues/6474&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; VS Code&lt;/a&gt;의 이슈&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jhallen/joes-sandbox/tree/master/editor-perf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Text&amp;nbsp;Editor&amp;nbsp;Performance&amp;nbsp;Comparison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cixtor.com/blog/editor-latency&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Text&amp;nbsp;Editor&amp;nbsp;Latency&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Lv2 프론트&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;핵심 가치&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;b&gt;크로스 플랫폼:&lt;/b&gt;&lt;span&gt;&amp;nbsp;각 플랫폼 특화 기능 제공&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능:&lt;/b&gt;&lt;span&gt; GPU를 이용한 프로세싱,&amp;nbsp; 최소 60fps를 지원하며 낮은 키입력 레이턴시, 부드러운 스크롤&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장 가능성:&lt;/b&gt;&lt;span&gt; UI &lt;/span&gt;커스텀이 쉬워야 한다.&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;처음에 Vim을 생으로 사용해본적 있는가?&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;Vim/Gvim 정도가 딱 좋다.&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;참고할 만한 프로젝트&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csDLOz/btqWX5dJHdx/UqwQYTjSBUsvuQGY9uPCxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csDLOz/btqWX5dJHdx/UqwQYTjSBUsvuQGY9uPCxK/img.png&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1000&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csDLOz/btqWX5dJHdx/UqwQYTjSBUsvuQGY9uPCxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsDLOz%2FbtqWX5dJHdx%2FUqwQYTjSBUsvuQGY9uPCxK%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;1600&quot; height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c90PT8/btqWXbL0TgC/WOaKJiI4P9uN9i0uAcoiPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c90PT8/btqWXbL0TgC/WOaKJiI4P9uN9i0uAcoiPK/img.png&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1000&quot; style=&quot;width: 49.4186%;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c90PT8/btqWXbL0TgC/WOaKJiI4P9uN9i0uAcoiPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc90PT8%2FbtqWXbL0TgC%2FWOaKJiI4P9uN9i0uAcoiPK%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;1600&quot; height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://levelup.gitconnected.com/flutter-vs-react-native-comparing-the-features-of-each-framework-f61bfd146a90&quot;&gt;Flutter vs React Native &amp;mdash; Comparing the Features of Each Framework | by Vitaly Kuprenko | Level Up Coding (gitconnected.com)&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;&lt;a href=&quot;https://github.com/xi-editor/xi-editor/issues/140&quot;&gt;Servo WebRenderer for Xi front-end &amp;middot; Issue #140 &amp;middot; xi-editor/xi-editor &amp;middot; GitHub&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1616375474065&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Servo WebRenderer for Xi front-end &amp;middot; Issue #140 &amp;middot; xi-editor/xi-editor&quot; data-og-description=&quot;I like the way you think, first goal: performances. But I think about something else: performances, multi-OS and customization. That's just something I think about and I believe I'm not the...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/xi-editor/xi-editor/issues/140&quot; data-og-url=&quot;https://github.com/xi-editor/xi-editor/issues/140&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PwyGO/hyJCupGKj1/wClDqKGELbVxWp7ToPHUvk/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://github.com/xi-editor/xi-editor/issues/140&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/xi-editor/xi-editor/issues/140&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PwyGO/hyJCupGKj1/wClDqKGELbVxWp7ToPHUvk/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&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;Servo WebRenderer for Xi front-end &amp;middot; Issue #140 &amp;middot; xi-editor/xi-editor&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I like the way you think, first goal: performances. But I think about something else: performances, multi-OS and customization. That's just something I think about and I believe I'm not the...&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;&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;size18&quot;&gt;&lt;b&gt;TUI&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rust로 TUI 구현은 문제 없다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/fdehau/tui-rs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;tui-rs&lt;/a&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;a href=&quot;https://blog.logrocket.com/rust-and-tui-building-a-command-line-interface-in-rust/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rust&amp;nbsp;and&amp;nbsp;TUI:&amp;nbsp;Building&amp;nbsp;a&amp;nbsp;command-line&amp;nbsp;interface&amp;nbsp;in&amp;nbsp;Rust&lt;/a&gt;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;색상: &lt;a href=&quot;https://github.com/magiblot/tvision&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Turbo Vision&lt;/a&gt;처럼 BIOS 4bit, Xterm 256(8bit), True Color(24bit), 터미널 기본 색상지원&lt;/li&gt;
&lt;li&gt;이벤트: 단축키와 마우스 지원&lt;/li&gt;
&lt;li&gt;클립보드: 상호작용 가능해야 한다.&lt;/li&gt;
&lt;li&gt;위젯: 2D 셀 형식 말고, 팝업형태도 지원 가능, 반응형(터미널의 크기는 바뀔 수 있다)&lt;/li&gt;
&lt;li&gt;이미지 표시: &lt;a href=&quot;https://github.com/saitoha/libsixel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;libsixel&lt;/a&gt;이나 &lt;a href=&quot;https://hpjansson.org/chafa/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;chafa&lt;/a&gt;를 이용한 이미지 표현 | &lt;a href=&quot;https://github.com/atanunq/viu&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;viu&lt;/a&gt;란 러스트 이미지 라이브러리도 있다.&lt;/li&gt;
&lt;li&gt;성능: TTY로의 빈번한 정보 업뎃은 느리게 만들며, 리페인트되는 영역이 많으면 플리커링이 생기기 때문에 상태관리가 되어야 한다. (버퍼링, 이벤트 루프, 반복된 시퀸스 방지, 동일한 셀 유지등의 기법이 가능하며 심지어 &lt;a href=&quot;https://github.com/gansm/finalcut#virtual-terminal&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;가상터미널&lt;/a&gt;을 구현할 수도 있다. &lt;a href=&quot;https://github.com/ggerganov/imtui&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ImTUI&lt;/a&gt;, &lt;a href=&quot;https://github.com/jtdaugherty/vty&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vty&lt;/a&gt;도 흥미롭다)&lt;/li&gt;
&lt;li&gt;기타: Terminfo, 유니코드 지원등&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;기타 TUI 라이브러리들&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dankamongmen/notcurses/blob/master/doc/OTHERS.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Other&amp;nbsp;TUI&amp;nbsp;libraries&amp;nbsp;of&amp;nbsp;note&lt;/a&gt;&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;b&gt;+.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색하다 &lt;a href=&quot;http://ignorethecode.net/blog/2009/04/22/oberon/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oberon&lt;/a&gt;이란 신기한 물건 발견 ㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/cfyzium/bearlibterminal&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BearLibTerminal&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;size18&quot;&gt;&lt;b&gt;GUI&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 러스트의 GUI는 매우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.to/davidedelpapa/rust-gui-introduction-a-k-a-the-state-of-rust-gui-libraries-as-of-january-2021-40gl&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rust GUI: Introduction, a.k.a. the state of Rust GUI libraries (As of January 2021)&lt;/a&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;&lt;a href=&quot;https://crates.io/crates/druid&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;druid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/maps4print/azul&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;azul&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/redox-os/orbtk&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;orbtk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/emilk/egui&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;egui&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PistonDevelopers/conrod&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;conrod&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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://docs.google.com/document/d/1aw41q_izail-p99mN8dHrJeh9tMQ-Pldi54W6m7MHU8/edit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;로드맵&lt;/a&gt;, &lt;a href=&quot;https://raphlinus.github.io/rust/skribo/text/2019/02/27/text-layout-kickoff.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;설명&lt;/a&gt;, &lt;a href=&quot;https://github.com/linebender/skribo&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;a href=&quot;https://raphlinus.github.io/text/2020/10/26/text-layout.html&quot;&gt;https://raphlinus.github.io/text/2020/10/26/text-layout.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1616329513264&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Text layout is a loose hierarchy of segmentation&quot; data-og-description=&quot;I love text layout, and have been working with it in one form or other for over 35 years. Yet, knowledge about it is quite arcane. I don&amp;rsquo;t believe there is a single place where it&amp;rsquo;s all properly written down. I have some explanation for that: while bas&quot; data-og-host=&quot;raphlinus.github.io&quot; data-og-source-url=&quot;https://raphlinus.github.io/text/2020/10/26/text-layout.html&quot; data-og-url=&quot;https://raphlinus.github.io/text/2020/10/26/text-layout.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/uz6gB/hyJCu324ML/bEszTwUbPzhPiCyv76hIaK/img.png?width=897&amp;amp;height=507&amp;amp;face=0_0_897_507&quot;&gt;&lt;a href=&quot;https://raphlinus.github.io/text/2020/10/26/text-layout.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://raphlinus.github.io/text/2020/10/26/text-layout.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/uz6gB/hyJCu324ML/bEszTwUbPzhPiCyv76hIaK/img.png?width=897&amp;amp;height=507&amp;amp;face=0_0_897_507');&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;Text layout is a loose hierarchy of segmentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I love text layout, and have been working with it in one form or other for over 35 years. Yet, knowledge about it is quite arcane. I don&amp;rsquo;t believe there is a single place where it&amp;rsquo;s all properly written down. I have some explanation for that: while bas&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;raphlinus.github.io&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;GUI는 이슈가 너무 많아서 터미널과 달리 나열하기가 힘들지 않나.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 최근에 알게된 설계 패턴이나 기억하는 용도로.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdVyvS/btq0AHf2oPS/AhjoSuApMfk21AQhEh4a9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdVyvS/btq0AHf2oPS/AhjoSuApMfk21AQhEh4a9k/img.png&quot; data-origin-width=&quot;1544&quot; data-origin-height=&quot;580&quot; style=&quot;width: 49.376%; margin-right: 10px;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdVyvS/btq0AHf2oPS/AhjoSuApMfk21AQhEh4a9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdVyvS%2Fbtq0AHf2oPS%2FAhjoSuApMfk21AQhEh4a9k%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;1544&quot; height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UxCsM/btq0A2xwIBg/QSsJQRyWqg2R2KxSs0wfKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UxCsM/btq0A2xwIBg/QSsJQRyWqg2R2KxSs0wfKk/img.png&quot; data-origin-width=&quot;1544&quot; data-origin-height=&quot;579&quot; style=&quot;width: 49.4612%;&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UxCsM/btq0A2xwIBg/QSsJQRyWqg2R2KxSs0wfKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUxCsM%2Fbtq0A2xwIBg%2FQSsJQRyWqg2R2KxSs0wfKk%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;1544&quot; height=&quot;579&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;a href=&quot;https://en.wikipedia.org/wiki/Retained_mode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Retained&amp;nbsp;mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Immediate&amp;nbsp;mode&lt;/a&gt;&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;기타 인텔리J 개발자의 다양한 고민&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://pavelfatin.com/scrolling-with-pleasure/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Scrolling&amp;nbsp;with&amp;nbsp;pleasure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pavelfatin.com/typing-with-pleasure/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Typing with pleasure&lt;/a&gt; (&lt;a href=&quot;https://pavelfatin.com/typometer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Typometer&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pavelfatin.com/low-latency-painting-in-awt-and-swing/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Low-latency&amp;nbsp;painting&amp;nbsp;in&amp;nbsp;AWT&amp;nbsp;and&amp;nbsp;Swing&lt;/a&gt;&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;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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Emacs: 이맥스 유저니 당연하다.&lt;br /&gt;이맥스의 키맵은 구린걸로 유명하며 &lt;a href=&quot;https://github.com/emacs-tw/awesome-emacs#key-bindings&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;수많은 키맵&lt;/a&gt;들을 양산 시켰다.&lt;br /&gt;나도 이맥스 유저지만 Ctrl+n(next, 다음 줄로 이동), Ctrl+p(prev, 전 줄로 이동) 같은 구린 키맵은 &lt;a href=&quot;https://en.wikipedia.org/wiki/Repetitive_strain_injury&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RSI&lt;/a&gt;를 유발한다고 믿는다.&lt;br /&gt;그러나 Ctrl+h(도움말), Ctrl+c(모드 관련), Ctrl+x(기타)같은 프리픽스 키 시스템이나 Ctrl+g(취소), Alt+x(명령)는 잘 만들어졌다.&lt;br /&gt;&lt;br /&gt;프리픽스 키 시스템이 왜 좋냐?&lt;br /&gt;수많은 경우의 수를 창출 가능하며 프리픽스키를 통해 보다 직관적인 모달 에디터에 가까워질 수 있다.&lt;br /&gt;예를 들어 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%95%9C/%EA%B8%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;한글 워드프로세서&lt;/a&gt; 사용자라면 알 수 있다.&lt;br /&gt;&amp;lt;Ctrl+k h&amp;gt;(하이퍼링크), &amp;lt;Ctrl+k o&amp;gt;(개요)처럼 비슷한 기능끼리 직관적으로 모아놓는게 가능하며 능숙한 사람이라면 키보드만으로도 사용이 가능하지 않은가?&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/emacs-evil/evil&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Evil&lt;/a&gt;: 최고의 Vim 키맵 에뮬레이터. 기존 키맵과 완전히 통합된 것은 Evil-Mode 밖에 없다고 생각한다.&lt;br /&gt;&lt;a href=&quot;https://github.com/JetBrains/ideavim&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IdeaVim&lt;/a&gt;/&lt;a href=&quot;http://www.viemu.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ViEmu&lt;/a&gt;도 나쁘지 않지만.. 기존 키맵과 통합이 뭔가 부족함.&lt;/li&gt;
&lt;li&gt;Terminal Based Common: Ctrl+c, Ctrl+v는 이맥스 키맵과 겹친다.&lt;br /&gt;이를 해결하기 위해 내장된 &lt;a href=&quot;https://www.emacswiki.org/emacs/CuaMode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CUA(Common User Access)&lt;/a&gt; 키바인딩도 충돌 해결이 안되서 섞어쓰기 어렵다.&lt;br /&gt;원래 이맥스 키맵과 충돌을 피하기 위해 같은 Ctrl+c/Ctrl+x라도 블럭 지정시 복사/잘라내기(이맥스 프리픽스키는 Ctrl+Shift+c/Ctrl+Shift+x), 안했을때는 이맥스의 프리픽스로 지정이 되나 추가되는 기능인&amp;nbsp;&lt;a href=&quot;https://www.emacswiki.org/emacs/WholeLineOrRegion&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Whole Line or Region&lt;/a&gt; 개념, Vim의 Ctrl+v등과 충돌, 일부 이맥스 키맵의 변경등 때문에 사용성에 문제가 생긴다.&lt;br /&gt;&lt;br /&gt;그러나 Ctrl+Shift+c, Ctrl+Shift+v 형태로 일반적인 키맵들을 설정하면 충돌 위험이 없다.&lt;br /&gt;Ctrl+Shift+x(잘라내기), Ctrl+Shift+z(undo), Ctrl+Shift+r(redo), Ctrl+Shift+n(새 파일), Ctrl+Shift+o(파일 찾기등등처럼 하면 되며 CUA모드처럼 쓰고 싶으면 Capslock을 사용한다.&lt;br /&gt;&lt;br /&gt;Cua 모드 전용 기능 중 &lt;a href=&quot;https://github.com/emacs-mirror/emacs/blob/master/lisp/emulation/cua-rect.el&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cua-Rect&lt;/a&gt; 하나만큼은 발군으로 Rectangle Selection Mode를 대체해서 사용 중. [&lt;a href=&quot;https://karthinks.com/software/more-batteries-included-with-emacs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;More Batteries Included with Emacs&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;일부 &lt;a href=&quot;https://en.wikipedia.org/wiki/Brief_(text_editor)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Brief&lt;/a&gt; : Emacs의 &lt;a href=&quot;https://www.emacswiki.org/emacs/BriefMode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Brief-Mode&lt;/a&gt;/&lt;a href=&quot;https://bitbucket.org/MikeWoolley/brf-mode/src/master/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Brf-Mode&lt;/a&gt;, &lt;a style=&quot;letter-spacing: 0px; -webkit-text-stroke-width: 0.04px;&quot; href=&quot;https://texteditors.org/cgi-bin/wiki.pl?BriefKeyboardLayout&quot;&gt;Brief Keyboard Layout&lt;/a&gt;, &lt;a href=&quot;https://www.slickedit.com/images/stories/products/slickedit/emulation_charts/brief_emulation.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cheet Sheet&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;문서들을 읽어보면 알겠지만 Home/End 키 연타(라인-윈도우-파일 순으로 이동)처럼 번뜩이는 아이디어가 참 좋다.&lt;br /&gt;Emacs도 의미 기반으로 이루어졌지만, Brief 키맵이 훨씬 설득력 있는 듯.&lt;/span&gt;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Emacs 키맵의 확장/변형: &lt;a href=&quot;https://en.wikipedia.org/wiki/Epsilon_(text_editor)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Epsilon&lt;/a&gt;이란 에디터(&lt;a href=&quot;https://www.lugaru.com/man/Epsilon.Key.Assignments.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식&lt;/a&gt;, &lt;a href=&quot;http://docwiki.embarcadero.com/RADStudio/Sydney/en/Epsilon_Keyboard_Shortcuts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RAD Studio&lt;/a&gt;, &lt;a href=&quot;https://www.slickedit.com/images/stories/products/slickedit/emulation_charts/epsilon_emulation.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SlickEdit&lt;/a&gt;), &lt;a href=&quot;https://github.com/jyp/boon&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Boon&lt;/a&gt;, &lt;a href=&quot;https://github.com/fgeller/fingers.el&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fingers&lt;/a&gt; 참고&lt;/li&gt;
&lt;li&gt;Vim 키맵의 통합/확장/변형: &lt;a href=&quot;https://invisible-island.net/vile/vile.faq.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vile&lt;/a&gt;의 통합, &lt;a href=&quot;https://github.com/martanne/vis&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vis&lt;/a&gt;의 &lt;a href=&quot;http://sam.cat-v.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sam&lt;/a&gt;에디터 &lt;a href=&quot;http://doc.cat-v.org/bell_labs/structural_regexps/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구조적 정규표현식&lt;/a&gt; 및 &lt;a href=&quot;http://doc.cat-v.org/bell_labs/sam_lang_tutorial/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;명령 언어&lt;/a&gt;를 이용한 확장, &lt;a href=&quot;https://kakoune.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kakoune&lt;/a&gt;의 변형&lt;/li&gt;
&lt;li&gt;Common 키맵: Visual Studio/Viusal Studio Code등의 키맵을 겹치지 않는 선에서 도입해볼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 확장과 변형은 정답이 아닐수도 있지만 sam 에디터 구조적 정규표현식은 흥미로운듯.&lt;/p&gt;
&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;Common&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Atom, Vistual Studio, Visual Studio Code, IntelliJ, Sublime등처럼 일반적인 키맵을 베이스로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, &lt;span style=&quot;color: #333333;&quot;&gt;앞서 소개한 Brief, Emacs, Emacs Others(Boon, Fingers)의 장단점을 잘 분석하여 인체공학/의미기반/호환성등을 염두하여 Global Keymap을 만들 필요가 있다.&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;Vim&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vim 에뮬레이션에 충실&lt;/p&gt;
&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;Emacs&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Emacs 에뮬레이션에 충실&lt;/p&gt;
&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;Vim+&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 쓰고 있는 키맵과 같은 혼종. 그러나 재설계가 포함되어 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Global Keymap&lt;/li&gt;
&lt;li&gt;수정된 Vim 키맵 포함&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;size18&quot;&gt;&lt;b&gt;기타 UI 요소&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Lv3 스타터 킷&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;핵심 가치&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;즉시 사용:&lt;/b&gt; 잘 설정되서 바로 쓰기 편한 상태여야 한다. VS Code나 Doom Emacs가 예시로 쓰일 수 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UX:&lt;/b&gt; 일관성있고 자동화된 사용자 경험을 제시 해줘야한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다양한 기능:&lt;/b&gt; Git, 프로젝트 단위로 열기 등은 이제 필수 기능이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가벼움:&lt;/b&gt; 그럼에도 불구하고 가벼워야..&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;VS 코드와 둠 이맥스가 가장 적절한 예.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 IDE에 들어갈만한 기능이라지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은 다음 정도 부가기능은 기본으로 들어가야 하지 않을까.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버전관리/배포&amp;nbsp;&lt;/li&gt;
&lt;li&gt;원격접속/협업&lt;/li&gt;
&lt;li&gt;파일/터미널/워크스페이스&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Lv4 IDE&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다양한 부가기능:&lt;/b&gt; 리소스 에디터, DB/HTTP 클라이언트, 노코드 블럭 기능?(&lt;a href=&quot;https://www.itworld.co.kr/print/86657&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;예1&lt;/a&gt;, &lt;a href=&quot;https://powerapps.microsoft.com/ko-kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;예2&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;통합:&lt;/b&gt; 문서(&lt;a href=&quot;https://kapeli.com/dash&quot;&gt;dash&lt;/a&gt; 같은?), 프레임워크(SwiftUI, RAD Studio, XAML Designer), 빌드/컴파일/커버리지/에뮬레이터,&amp;nbsp;&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;</description>
      <category>IT/견물생심</category>
      <category>Emacs</category>
      <category>에디터</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/78</guid>
      <comments>https://black7375.tistory.com/78#entry78comment</comments>
      <pubDate>Fri, 12 Feb 2021 23:00:51 +0900</pubDate>
    </item>
    <item>
      <title>쿠팡 마케팅 전략 보고서 공개</title>
      <link>https://black7375.tistory.com/77</link>
      <description>&lt;p&gt;최근 쿠팡이 중고거래 시장에 진출한다는 뉴스를 보게 되었다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://news.v.daum.net/v/20201028030208951&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;news.v.daum.net/v/20201028030208951&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1604626218600&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;'고객 2000만명' 쿠팡, 중고거래 시장 진출 채비&quot; data-og-description=&quot;쿠팡이 중고거래 시장에 뛰어드는 것으로 알려졌다. 2300만 명에 육박하는 사용자 규모와 거대한 자체 물류 인프라를 보유한 이커머스 공룡 쿠팡이 뛰어들면서 당근마켓을 비롯한 스타트업들이 &quot; data-og-host=&quot;news.v.daum.net&quot; data-og-source-url=&quot;https://news.v.daum.net/v/20201028030208951&quot; data-og-url=&quot;https://news.v.daum.net/v/AiPCt0QaPp&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/4KNbP/hyH9AXkz8O/pUOtFr3FE7KPjrSxcAMZ70/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/J8cvT/hyH74Ti0At/YsKXCEqKSMQwMFC3mXl4R1/img.jpg?width=658&amp;amp;height=240&amp;amp;face=0_0_658_240&quot;&gt;&lt;a href=&quot;https://news.v.daum.net/v/20201028030208951&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://news.v.daum.net/v/20201028030208951&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/4KNbP/hyH9AXkz8O/pUOtFr3FE7KPjrSxcAMZ70/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/J8cvT/hyH74Ti0At/YsKXCEqKSMQwMFC3mXl4R1/img.jpg?width=658&amp;amp;height=240&amp;amp;face=0_0_658_240');&quot; title=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;'고객 2000만명' 쿠팡, 중고거래 시장 진출 채비&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;쿠팡이 중고거래 시장에 뛰어드는 것으로 알려졌다. 2300만 명에 육박하는 사용자 규모와 거대한 자체 물류 인프라를 보유한 이커머스 공룡 쿠팡이 뛰어들면서 당근마켓을 비롯한 스타트업들이&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;news.v.daum.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;문득 작년에 만들었던 보고서가 생각나서 올려본다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;경영정보시스템 시간(이라 쓰고 인터넷 마케팅)에 만들었는데,&lt;/p&gt;
&lt;p&gt;문서와 보고서는 물론 전반적인 컨셉, 구조, 아이디어를 거의 다 만들거나 손봤기 때문에 밥을 많이 얻어먹었던 기억이 ㅎㅎㅎ&lt;/p&gt;
&lt;p&gt;발표까지 담당했기 때문에 설사 공개 후, 옛팀원이 봐도 뭐라 안하겠지..&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;분할 압축된 보고서입니다.&lt;/p&gt;
&lt;p&gt;경영쪽은 오픈된 보고서들이 적은데 참고하세요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://blog.opensurvey.co.kr/category/trendreport/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;오픈 서베이 자료들&lt;/a&gt;이 정말 유용했었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;마케팅이나 전략 관련 보고서를 짜려는 분들은 오픈 서베이 꼭 들어가보길 권합니다.&lt;/span&gt;&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/pzNAD/btqMCgpSylx/C3azRuKQctFKPkqDArxsHk/%EC%9D%B8%ED%84%B0%EB%84%B7%EB%A7%88%EC%BC%80%ED%8C%85%EC%A0%84%EB%9E%B5%EC%82%AC%EB%A1%80_01%EC%A1%B0_Anonymous.7z.001?attach=1&amp;amp;knm=tfile.001&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;인터넷마케팅전략사례_01조_Anonymous.7z.001&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;10.00MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bdLKxi/btqMG7k7SoW/AChTMoRAOgJaS2Ot5qAal1/%EC%9D%B8%ED%84%B0%EB%84%B7%EB%A7%88%EC%BC%80%ED%8C%85%EC%A0%84%EB%9E%B5%EC%82%AC%EB%A1%80_01%EC%A1%B0_Anonymous.7z.002?attach=1&amp;amp;knm=tfile.002&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;인터넷마케팅전략사례_01조_Anonymous.7z.002&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;9.97MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;마케팅을 배우며 고민했던 것은 각종 분석 방법을 어떻게 통합해서 솔루션을 낼 수 있을지 였다.&lt;/p&gt;
&lt;p&gt;여러방안을 생각했었는데 결국 채택한 것은&lt;/p&gt;
&lt;p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;3C:&lt;/b&gt; 고객(Customers), 경쟁(Competitors), 자사(Company)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&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;b&gt;5 Forece:&lt;/b&gt; 전통적 경쟁자(Traditional Competitors), 새로운 시장 진입자(New Market Entrants), 대체 제품과 서비스(Substitute Products and Services), 고객(Customers), 공급자(Suppliers)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;를 살펴&amp;nbsp; 전반적인 상황을 파악한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&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;&lt;b&gt;STP:&lt;/b&gt; 세분화(Segmentation), 표적 시장(Targeting), 위상 정립(Positioning)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;5C:&lt;/b&gt; 4P의 업데이트된 방안.&amp;nbsp; 협업(Collaboration), 컨텐츠웨어(Contentware, Product와 비슷), 가치(Commitment, Price와 비슷), 소통(Communication, Promotion과 비슷), 채널(Channel, Place와 비슷)로 이루어져 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&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&gt;얻은 정보들을 토대로 분석을 해야한다.&lt;/p&gt;
&lt;p&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;b&gt;SWOT:&lt;/b&gt; 강점(Strength), 약점(Weakness), 기회(Opportunity), 위협(Threat)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;본디 SWOT는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SO전략 : 강점을 가지고, 기회를 살리는 전략&lt;/li&gt;
&lt;li&gt;ST전략 : 강점을 가지고, 위협을 최소화하는 전략&lt;/li&gt;
&lt;li&gt;WO전략 : 약점을 보완하며, 기회를 살리는 전략&lt;/li&gt;
&lt;li&gt;WT전략 : 약점을 보완하며, 위협을 최소화하는 전략&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;을 세우는 것이 맞지만, 근시안적인 대책위주로 나올 가능성이 높기 때문에(약간 Local Optimum 느낌),&lt;/p&gt;
&lt;p&gt;마치 재귀적으로 STP와 5C를 사용해 새로운 전략을 세우기로 했다. (시간 문제도 있었다)&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;hr /&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아래 그림파일들인 PPT입니다.&lt;/p&gt;
&lt;p&gt;자세한 내용은 보고서 보세요.&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/c2cV8N/btqMGNf6FqW/JiYGJ1CTykfVl4RhgTfUr0/%EC%9D%B8%ED%84%B0%EB%84%B7%EB%A7%88%EC%BC%80%ED%8C%85%EC%A0%84%EB%9E%B5%EC%82%AC%EB%A1%80_01%EC%A1%B0_%EB%B0%9C%ED%91%9C_Anonymous.pdf?attach=1&amp;amp;knm=tfile.pdf&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;인터넷마케팅전략사례_01조_발표_Anonymous.pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;3.53MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;대신 당시 중간고사 기간과 겹쳐서 죽을뻔 했었던 기억이 ㅋㅋㅋ&lt;/p&gt;
&lt;p&gt;발표날 아침까지 보고서와 파워포인트를 잡고 싸웠다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;소개&lt;/h3&gt;
&lt;p&gt;팀에 외국인도 있었는데 이름이 긴점을 이용해, 마치 로켓모양처럼 만들려고 했었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드1.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6DB00/btqMDyDNwIq/DABDNF4rXFGKQrWXcIGrB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6DB00/btqMDyDNwIq/DABDNF4rXFGKQrWXcIGrB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6DB00/btqMDyDNwIq/DABDNF4rXFGKQrWXcIGrB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6DB00%2FbtqMDyDNwIq%2FDABDNF4rXFGKQrWXcIGrB1%2Fimg.png&quot; data-filename=&quot;슬라이드1.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;분석 부분의 STP는 겹치므로 제외시켜 깔끔하게 만들었다.&lt;/p&gt;
&lt;p&gt;마치 코딩에서 줄을 띄워 컨텍스트를 구분하는 것처럼 직관적으로 구분할 수 있도록 했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드2.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJDMve/btqMG8xxWQg/E9fKfpsSXFasse4bUxHwgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJDMve/btqMG8xxWQg/E9fKfpsSXFasse4bUxHwgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJDMve/btqMG8xxWQg/E9fKfpsSXFasse4bUxHwgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJDMve%2FbtqMG8xxWQg%2FE9fKfpsSXFasse4bUxHwgK%2Fimg.png&quot; data-filename=&quot;슬라이드2.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;/p&gt;
&lt;p&gt;라는 말이 나와 선정하게 되었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;마침 당시 손정의와 투자에 관련한 여러 뉴스들이 쏟아져서 적기라 판단했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드3.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0csq8/btqMHVY01pc/eXhngvh9FX5K7K0t6hvpb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0csq8/btqMHVY01pc/eXhngvh9FX5K7K0t6hvpb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0csq8/btqMHVY01pc/eXhngvh9FX5K7K0t6hvpb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0csq8%2FbtqMHVY01pc%2FeXhngvh9FX5K7K0t6hvpb0%2Fimg.png&quot; data-filename=&quot;슬라이드3.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;기업 소개는 간단히 CEO, 투자받은 내역, 쿠팡의 서비스.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드4.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7UlVx/btqMHVY01rg/MMQA7TYiQndkYj5Ouzpak0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7UlVx/btqMHVY01rg/MMQA7TYiQndkYj5Ouzpak0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7UlVx/btqMHVY01rg/MMQA7TYiQndkYj5Ouzpak0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7UlVx%2FbtqMHVY01rg%2FMMQA7TYiQndkYj5Ouzpak0%2Fimg.png&quot; data-filename=&quot;슬라이드4.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;분석&lt;/h3&gt;
&lt;p&gt;분석의 시작. 3C.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;시장과 미래 예측, 그리고 쪼그라드는 오프라인.&lt;/p&gt;
&lt;p&gt;코로나 때문에 가속화 될 듯?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드5.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HvXLM/btqMDzvSTl1/rKCzMj3rU5sIQqg9US3ZV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HvXLM/btqMDzvSTl1/rKCzMj3rU5sIQqg9US3ZV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HvXLM/btqMDzvSTl1/rKCzMj3rU5sIQqg9US3ZV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHvXLM%2FbtqMDzvSTl1%2FrKCzMj3rU5sIQqg9US3ZV0%2Fimg.png&quot; data-filename=&quot;슬라이드5.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;/p&gt;
&lt;p&gt;유통 대기업 E마트, 오픈마켓 왕 이베이의 대표 옥션, 똑같이 소셜커머스로 시작한 티몬을 골랐다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드6.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LdXqT/btqMBvAMKk3/zQ6HWuGjzEXiIlbKrgfV3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LdXqT/btqMBvAMKk3/zQ6HWuGjzEXiIlbKrgfV3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LdXqT/btqMBvAMKk3/zQ6HWuGjzEXiIlbKrgfV3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLdXqT%2FbtqMBvAMKk3%2FzQ6HWuGjzEXiIlbKrgfV3K%2Fimg.png&quot; data-filename=&quot;슬라이드6.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;/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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드7.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cclLD2/btqMAQE8emB/RLmpJUCadR0cQVXBD4Rf80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cclLD2/btqMAQE8emB/RLmpJUCadR0cQVXBD4Rf80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cclLD2/btqMAQE8emB/RLmpJUCadR0cQVXBD4Rf80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcclLD2%2FbtqMAQE8emB%2FRLmpJUCadR0cQVXBD4Rf80%2Fimg.png&quot; data-filename=&quot;슬라이드7.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음은 5C 차례.&lt;/p&gt;
&lt;p&gt;중소기업과 상생을 위한 여러가지 지원과 월정산 시스템으로 높은 성장률을 보여준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드8.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boIm3E/btqMG7em9GW/yWYs4wXctzVDC2Q11MHlY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boIm3E/btqMG7em9GW/yWYs4wXctzVDC2Q11MHlY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boIm3E/btqMG7em9GW/yWYs4wXctzVDC2Q11MHlY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboIm3E%2FbtqMG7em9GW%2FyWYs4wXctzVDC2Q11MHlY1%2Fimg.png&quot; data-filename=&quot;슬라이드8.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&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;b&gt;쿠팡:&lt;/b&gt; 배송, 직구, 프레시, 정기배송 등 배달 관련 메뉴를 잘보이도록 배치해놓은 걸 알 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이마트:&lt;/b&gt; 신세계, 이마트, 트레이더스, 까사미아 등 상이한 느낌의 브랜드를 함께 서비스하기 어려웠는지 들어가는 탭으로 만들어놓았다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;옥션:&lt;/b&gt; 지마켓 등과 같이 쓸 수 있는 스마일배송, 스마일 클럽이 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;티몬:&lt;/b&gt; 무료배송데이, 1212타임, 특가, 10분어택 등 각종 이벤트가 눈에 띈다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드9.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzzdoy/btqMIs98D6u/o1kII30fIzdF9GWecmOEbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzzdoy/btqMIs98D6u/o1kII30fIzdF9GWecmOEbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzzdoy/btqMIs98D6u/o1kII30fIzdF9GWecmOEbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzzdoy%2FbtqMIs98D6u%2Fo1kII30fIzdF9GWecmOEbK%2Fimg.png&quot; data-filename=&quot;슬라이드9.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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://www.zdnet.co.kr/view/?no=20190418142445&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;1초 빨라지면 아마존의 판매량이 1% 증가, 월마트의 전환율은 2% 증가&lt;/a&gt;한다는 것처럼 성능은 매출에 직결된다.&lt;/p&gt;
&lt;p&gt;첫로딩(캐시가 꺼진 상태)와 재방문(캐시가 켜진 상태(를 비교해보았다.&lt;/p&gt;
&lt;p&gt;쿠팡이 가장 빨랐다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드10.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C3z3m/btqMGd0qxIj/HNZOEmXnRVZr9iIkaRgiIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C3z3m/btqMGd0qxIj/HNZOEmXnRVZr9iIkaRgiIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C3z3m/btqMGd0qxIj/HNZOEmXnRVZr9iIkaRgiIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC3z3m%2FbtqMGd0qxIj%2FHNZOEmXnRVZr9iIkaRgiIK%2Fimg.png&quot; data-filename=&quot;슬라이드10.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;UI/UX는 레이아웃의 일관성, 가독성 그리고 특색들을 비교했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;쿠팡:&lt;/b&gt; 일관성 있는 레이아웃과 호버 인터렉션 구성, 메가드롭다운으로 3단계 메뉴를 빠르게 볼 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이마트:&lt;/b&gt; 상단은 눈에 띄게 구성되어 있으나 레이아웃이 무려 6번이나 변화하며 간혹 그리드가 심하게 깨진 경우가 존재, 상품에 마우스를 올리면 뒷면과 메뉴를 보여주는 인터렉션이 인상깊었음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;옥션:&lt;/b&gt; 간결하고 명확하나 일관성이 떨어지고 보여주는 상품의 양이 적다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;티몬:&lt;/b&gt; 일관적인 레이아웃, 상품이미지가 큼직큼직하며 이벤트-인기-신규 상품의 카테고리 접근이 직관적&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;쿠팡-티몬-이마트-옥션 순이었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드11.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2t74o/btqMHWQ9sdN/JxS4AFgbi3mI7xd35QJmD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2t74o/btqMHWQ9sdN/JxS4AFgbi3mI7xd35QJmD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2t74o/btqMHWQ9sdN/JxS4AFgbi3mI7xd35QJmD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2t74o%2FbtqMHWQ9sdN%2FJxS4AFgbi3mI7xd35QJmD0%2Fimg.png&quot; data-filename=&quot;슬라이드11.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;쿠런티는 최저가 보장제도이다.&lt;/p&gt;
&lt;p&gt;쿠런티 인증 상품이 배송비를 포함해 더 저렴한 상품이 다른 사이트에 존재한다면 차액을 쿠팡캐시로 보상받을 수 있다.&lt;/p&gt;
&lt;p&gt;쿠페이는 간편결제 시스템으로 번거로운 결제 과정을 거치지 않도록 하며, 로켓와우클럽과 쿠팡이츠 등 핵심 서비스의 기반이 되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드12.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4PqXB/btqMDyKxjP3/LhkimKCTdkXrFtp2skTwHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4PqXB/btqMDyKxjP3/LhkimKCTdkXrFtp2skTwHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4PqXB/btqMDyKxjP3/LhkimKCTdkXrFtp2skTwHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4PqXB%2FbtqMDyKxjP3%2FLhkimKCTdkXrFtp2skTwHk%2Fimg.png&quot; data-filename=&quot;슬라이드12.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&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;b&gt;쿠팡:&lt;/b&gt; 로켓배송 무료, 당일배송, 신선식품, 무료 반품처럼 배송에 초점이 맞춰져 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;옥션:&lt;/b&gt; 연장시 할인, 캐시백, 첫가입캐시, 적립과 할인처럼 할인위주의 정책이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;티몬:&lt;/b&gt; 비싸지만 소셜커머스로 시작한 업체답게 멤버쉽 전용 특가, 전용딜 무료배송과 균일가격에 혜택이 컸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드13.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bH9B5e/btqMCgwBIDO/ZMTta6eW32AfjfctBkO4SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH9B5e/btqMCgwBIDO/ZMTta6eW32AfjfctBkO4SK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH9B5e/btqMCgwBIDO/ZMTta6eW32AfjfctBkO4SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH9B5e%2FbtqMCgwBIDO%2FZMTta6eW32AfjfctBkO4SK%2Fimg.png&quot; data-filename=&quot;슬라이드13.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;옥션을 가장 많이 사용했고, 쿠팡의 만족도가 높았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드14.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nLGgE/btqMAQ6df8V/VMwrHLMX6sRcap9dLPmXKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nLGgE/btqMAQ6df8V/VMwrHLMX6sRcap9dLPmXKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nLGgE/btqMAQ6df8V/VMwrHLMX6sRcap9dLPmXKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnLGgE%2FbtqMAQ6df8V%2FVMwrHLMX6sRcap9dLPmXKk%2Fimg.png&quot; data-filename=&quot;슬라이드14.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;여기선 4개를 기준으로 정렬했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;쿠팡&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;아마존처럼 카테고리별로 모아 배치하지 않고, 입출고 시점을 예측해 상품의 크기와 동선을 고려해 배치하는 렌덤스토&lt;/li&gt;
&lt;li&gt;쿠팡 직원인 쿠팡맨 이외에 일반인 배송파트너인 쿠팡 플렉스. 물류 물량을 유동적으로 대응가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이마트&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;Ne.O란 물류센터는 상품 픽업 오류 방지, 완충재 포장, 콜드체인(영상 10도 이하의 일정 온도를 유지), 검수 시스템이 존재&lt;/li&gt;
&lt;li&gt;매장 후방에 P.P(Picking &amp;amp; Packing) 센터를 만들고 온라인 주문이 들어오면 매장 직원이 포장해 배송. 그러나 최대 출고량 문제가 존재.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;옥션&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;CJ대한통운과 협력해 스마트배송 전담택배 서비스를 만들었다.&lt;/li&gt;
&lt;li&gt;1회 배송비로 여러 상품을 묶음배송 받을 수 있다. (예: 인천 해외 물류센터는 소량의 여러 베품을 구매할 경우 묶어 배송하는 합배송을 지원해 세금을 아낄 수 있다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;티몬:&lt;/b&gt; 제2 물류센터 건립이 좌초되어 물류면에서 부족한 점이 많다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img style=&quot;letter-spacing: 0px; -webkit-text-stroke-width: 0.04px;&quot; src=&quot;https://blog.kakaocdn.net/dn/bcVclB/btqMHVLxkBe/MHlQueGOQUyM15hLpksbp1/img.png&quot; data-filename=&quot;슬라이드15.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-image-src=&quot;https://blog.kakaocdn.net/dn/bcVclB/btqMHVLxkBe/MHlQueGOQUyM15hLpksbp1/img.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결&lt;/h3&gt;
&lt;p&gt;앞서 이야기했듯, 이 보고서의 SWOT는 정리를 하는 역할을 하여 전반적인 경향을 살피는 역할만 담당한다.&lt;/p&gt;
&lt;p&gt;쿠팡은 상당한 강점과 기회가 존재하는 회사지만, 적자와 경쟁심화 문제가 가장 심각했으며 풀어야될 목표로 정했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드16.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhFvz8/btqMBxrNHGI/m9kZXsMibwklveDhYKHIw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhFvz8/btqMBxrNHGI/m9kZXsMibwklveDhYKHIw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhFvz8/btqMBxrNHGI/m9kZXsMibwklveDhYKHIw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhFvz8%2FbtqMBxrNHGI%2Fm9kZXsMibwklveDhYKHIw0%2Fimg.png&quot; data-filename=&quot;슬라이드16.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;고객을 세분화하는 과정이다.&lt;/p&gt;
&lt;p&gt;먼저 인구통계.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드17.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TIx73/btqMGfDVVH7/klqHd1jF8vEnE6vRuWZKjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TIx73/btqMGfDVVH7/klqHd1jF8vEnE6vRuWZKjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TIx73/btqMGfDVVH7/klqHd1jF8vEnE6vRuWZKjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTIx73%2FbtqMGfDVVH7%2FklqHd1jF8vEnE6vRuWZKjk%2Fimg.png&quot; data-filename=&quot;슬라이드17.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&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&gt;과 장바구니 사용 습관을 알 수 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드18.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/09p5J/btqMGOMTbLl/5liPUcEuN2ZeHQKFnpynxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/09p5J/btqMGOMTbLl/5liPUcEuN2ZeHQKFnpynxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/09p5J/btqMGOMTbLl/5liPUcEuN2ZeHQKFnpynxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F09p5J%2FbtqMGOMTbLl%2F5liPUcEuN2ZeHQKFnpynxK%2Fimg.png&quot; data-filename=&quot;슬라이드18.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;최우선 타겟 고객은 여전히 IT기술에 익숙하고 구매력이 높은 2-30대다.&lt;/p&gt;
&lt;p&gt;그러나 현재의 싼 가격을 강조하는 정책보다 가치를 강조해야 한다고 생각했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;적자를 해결하고, 경쟁이 심화될때 차별화를 위해서는 가치를 강조하는게 가장 현명하다고 봤다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드19.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RucRz/btqMHWjju6G/nbKv6urhA1IusKXhIhmig1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RucRz/btqMHWjju6G/nbKv6urhA1IusKXhIhmig1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RucRz/btqMHWjju6G/nbKv6urhA1IusKXhIhmig1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRucRz%2FbtqMHWjju6G%2FnbKv6urhA1IusKXhIhmig1%2Fimg.png&quot; data-filename=&quot;슬라이드19.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;CEO의 말은 가격/프로모션보다 가치에 중시하자는 의견을 뒷받침해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드20.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WhhYb/btqMJEibldp/Y8l6QRukGNJmhVKMmzeGQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WhhYb/btqMJEibldp/Y8l6QRukGNJmhVKMmzeGQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WhhYb/btqMJEibldp/Y8l6QRukGNJmhVKMmzeGQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWhhYb%2FbtqMJEibldp%2FY8l6QRukGNJmhVKMmzeGQ0%2Fimg.png&quot; data-filename=&quot;슬라이드20.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그래서 최종적으로 정한 포지션은&lt;/p&gt;
&lt;p&gt;싸고 빠른 배송을 지원하는 쇼핑몰에서 배송, 커뮤니케이션을 잘하는 IT 기업으로 인식을 바꿔야 한다는 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;현재 쿠팡은 쇼핑몰이라 생각하는 사람이 많은 반면, 아마존은 IT기업이라 생각하는 사람이 많지 않은가?&lt;/p&gt;
&lt;p&gt;아마존은 AWS, 킨들 등으로 테크회사란 인식이 있지만 쿠팡은 IT회사로서 내세울게 마땅치 않다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드21.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cs544H/btqMGfKGMCc/xbiky7kVZatqrgqYKLUJS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cs544H/btqMGfKGMCc/xbiky7kVZatqrgqYKLUJS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cs544H/btqMGfKGMCc/xbiky7kVZatqrgqYKLUJS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcs544H%2FbtqMGfKGMCc%2Fxbiky7kVZatqrgqYKLUJS0%2Fimg.png&quot; data-filename=&quot;슬라이드21.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;나는 키워드 강조를 매우 중시하는 편.&lt;/p&gt;
&lt;p&gt;명확하게 생각을 전달하는데 도움이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드22.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRXw05/btqMG7rS7xN/CkqanIdfoEBkvsw1RRbEmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRXw05/btqMG7rS7xN/CkqanIdfoEBkvsw1RRbEmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRXw05/btqMG7rS7xN/CkqanIdfoEBkvsw1RRbEmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRXw05%2FbtqMG7rS7xN%2FCkqanIdfoEBkvsw1RRbEmk%2Fimg.png&quot; data-filename=&quot;슬라이드22.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;기술은 고부가가치 산업이다.&lt;/p&gt;
&lt;p&gt;쿠팡도 물류센터의 회전율을 높이기 위해 IT기술을 적극적으로 활용하고 있으며 좋은 UI/UX를 제공하기 위해 노력을 많이한다.&lt;/p&gt;
&lt;p&gt;IT회사라고 주장하지만 아직 허울뿐으로만 외침을 실체화할 필요가 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;현재 쿠팡의 지위를 만든 것은 배송이라 해도 과언이 아니다.&lt;/p&gt;
&lt;p&gt;강점을 포기할 필요는 없으며 계속 강화, 이용해야 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;커뮤니케이션.&lt;/p&gt;
&lt;p&gt;어찌되었건 쿠팡은 소셜 커머스라는 예전과 다른 형태로 시장에 진입했지만, 현재는 특색을 잃어버렸다.&lt;/p&gt;
&lt;p&gt;다시&amp;nbsp;기존&amp;nbsp;쇼핑몰의&amp;nbsp;형태와는&amp;nbsp;다르다는&amp;nbsp;것을&amp;nbsp;보여줘야&amp;nbsp;한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;IT 회사라는 차가움과 거리감을 보완하기 위해서 커뮤니케이션의 강화를 신경써볼만 하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;배송시스템은&amp;nbsp;유지된&amp;nbsp;채&amp;nbsp;IT&amp;nbsp;회사로&amp;nbsp;인식되는&amp;nbsp;것이&amp;nbsp;가장&amp;nbsp;중요하다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;일반적으로&amp;nbsp;기술은&amp;nbsp;기법(Mechanism)에&amp;nbsp;가깝고,&amp;nbsp;커뮤니케이션은&amp;nbsp;정책(Policy)에&amp;nbsp;가깝다.&lt;/p&gt;
&lt;p&gt;기법은&amp;nbsp;&amp;lsquo;어떻게&amp;rsquo;,&amp;nbsp;정책은&amp;nbsp;&amp;lsquo;무엇&amp;rsquo;을&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;(OS&amp;nbsp;이론)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드23.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ncmCK/btqMBv8EiRR/HTpCw0MuQ3GxQodDsSWKm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ncmCK/btqMBv8EiRR/HTpCw0MuQ3GxQodDsSWKm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ncmCK/btqMBv8EiRR/HTpCw0MuQ3GxQodDsSWKm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FncmCK%2FbtqMBv8EiRR%2FHTpCw0MuQ3GxQodDsSWKm1%2Fimg.png&quot; data-filename=&quot;슬라이드23.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아이디어는 총 6개를 세웠으며, 각각 해당되는 카테고리를 할당하였다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;로켓TV, 로켓중고, UI/UX 개선은 온전히 내 아이디어였고, 나머지는 다른 팀원들의 아이디어를 가공했던걸로 기억한다.&lt;/p&gt;
&lt;p&gt;이름부터, 실현가능성, 세부계획은 많이 고치긴 했지만.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드24.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uCJQd/btqMGM9pce7/jMkot8twhgct5Ru2B1fqQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uCJQd/btqMGM9pce7/jMkot8twhgct5Ru2B1fqQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uCJQd/btqMGM9pce7/jMkot8twhgct5Ru2B1fqQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuCJQd%2FbtqMGM9pce7%2FjMkot8twhgct5Ru2B1fqQ0%2Fimg.png&quot; data-filename=&quot;슬라이드24.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;제목 밑에 서비스의 지향점을 적어 청중들에게 서비스의 정체성을 인식 가능하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;공급자와 소비자의 직접 소통을 위한 방송 플랫폼이다.&lt;/p&gt;
&lt;p&gt;까다로운 실시간 영상처리 기술과 트래픽 관리등은 IT개발자가 많은 기업에게 유리하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;IT 기업으로의 인식, 공급자와 구매자 교섭력 증가, 즐기러오는 공간으로 만들어 접속율과 트래픽을 증가를 기대한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드25.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnJCWq/btqMHWQ9szc/hNYduk9i3Mlj6KwQKT2JXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnJCWq/btqMHWQ9szc/hNYduk9i3Mlj6KwQKT2JXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnJCWq/btqMHWQ9szc/hNYduk9i3Mlj6KwQKT2JXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnJCWq%2FbtqMHWQ9szc%2FhNYduk9i3Mlj6KwQKT2JXk%2Fimg.png&quot; data-filename=&quot;슬라이드25.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;PD, 영상제작자로 자연스러운 앵글과 스토리를 만들고,&lt;/p&gt;
&lt;p&gt;쇼호스트, MC, 인플루언서 등을 지원하여 자연스럽게 진행하도록 만든다.&lt;/p&gt;
&lt;p&gt;한정된 수의 채널만 열경우(예: 베타 서비스) 순위를 매겨 활발하게 경쟁하게 하며, 예능적 요소를 도입할 수도 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;방송은 진행자와 기업관계자가 함께 판매하며, 쿠팡의 배송시스템을 적극적으로 활용한다.&lt;/p&gt;
&lt;p&gt;하루만에 배송을 완료하고, 하루뒤에 바로 피드백 방송을 열어 협력업체와 소비자의 니즈를 모두 충족할 수 있도록 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예전 소셜 커머스적인 면도 놓치지 않기 위해 특가상품을 게릴라로 파는 방송을 할 수도.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드26.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6Uk8o/btqMDzbyrV9/KJaRCUyLMVTB9NNQW7ZuB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6Uk8o/btqMDzbyrV9/KJaRCUyLMVTB9NNQW7ZuB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6Uk8o/btqMDzbyrV9/KJaRCUyLMVTB9NNQW7ZuB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6Uk8o%2FbtqMDzbyrV9%2FKJaRCUyLMVTB9NNQW7ZuB1%2Fimg.png&quot; data-filename=&quot;슬라이드26.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;중고 시장은 알라딘으로 검증된 수익모델이며, 당근마켓등이 빠르게 성장하는 걸보아 아직 블루오션이다.&lt;/p&gt;
&lt;p&gt;쿠팡이 중고시장에 진출한다면 가격문제를 제외하면(직거래가 아니라 마진이 필요) 대부분의 문제를 해결 할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;쿠페이 시스템을 활용하면 공급자에게 즉시 돈을 지급하며, 로켓배송을 활용해 소비자에게는 빠른 배송 또한 가능하다.&lt;/p&gt;
&lt;p&gt;여기에 고가의 제품은 3D 스캔을 제공한다면, 신뢰성과 IT 기업 이미지를 줄 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드27.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wYxMs/btqMJFH9B3Y/jT4kSxSaOe4MuCJZCogcwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wYxMs/btqMJFH9B3Y/jT4kSxSaOe4MuCJZCogcwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wYxMs/btqMJFH9B3Y/jT4kSxSaOe4MuCJZCogcwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwYxMs%2FbtqMJFH9B3Y%2FjT4kSxSaOe4MuCJZCogcwK%2Fimg.png&quot; data-filename=&quot;슬라이드27.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;예비 - 리소스를 아끼기 위한 과정&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;사용자가 예상 물건 등급을 책정 후 정보를 전달하면, 머신러닝을 활용해 적절한 가격을 책정해 알려준다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;실거래 - 물건 매입&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;예상 가격을 보고 판매를 원한다면 쿠팡으로 배송하며, 쿠팡이 물건의 등급을 재측정하여 최종가격을 결정한다.&lt;/p&gt;
&lt;p&gt;판매를 원한다면 즉시 매수하며, 아니라면 반송할 수 있다.&lt;/p&gt;
&lt;p&gt;개인간의 거래라면 결코 할 수 없는 일이며 비동기적인 거래를 보장한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;구매 - 빠른 배송&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;쿠팡에서 적절한 각도로 찍은 사진과 기타 결점 사유정보등을 포함한 상품을 게시하면,&lt;/p&gt;
&lt;p&gt;소비자는 로켓배송이 가능한 지역이라면 빠르게 받아볼 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;고관여 제품은 3D 스캔을 고려할 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드28.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jxd11/btqMIsCh92e/HxfoGem0LFfGbBJzGwpaO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jxd11/btqMIsCh92e/HxfoGem0LFfGbBJzGwpaO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jxd11/btqMIsCh92e/HxfoGem0LFfGbBJzGwpaO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJxd11%2FbtqMIsCh92e%2FHxfoGem0LFfGbBJzGwpaO0%2Fimg.png&quot; data-filename=&quot;슬라이드28.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;AI &amp;amp; IOT 플랫폼 연동 전략이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;IOT와 AI 스피커 연계를 원하는 팀원이 낸 아이디어.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드29.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kGDR4/btqMG8dcWdi/Uo8ZU6SzeGpPM7zkqREZm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kGDR4/btqMG8dcWdi/Uo8ZU6SzeGpPM7zkqREZm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kGDR4/btqMG8dcWdi/Uo8ZU6SzeGpPM7zkqREZm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkGDR4%2FbtqMG8dcWdi%2FUo8ZU6SzeGpPM7zkqREZm1%2Fimg.png&quot; data-filename=&quot;슬라이드29.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;음성, 이미지 쇼핑은 물론 각종 배송 제안을 할 수 있다.&lt;/p&gt;
&lt;p&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&gt;를 들 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 기타 개발자를 위해 API를 제공을 고려할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드30.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cExOcd/btqMGeSwV1V/knv26A32B1gBdbMlz4NnVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cExOcd/btqMGeSwV1V/knv26A32B1gBdbMlz4NnVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cExOcd/btqMGeSwV1V/knv26A32B1gBdbMlz4NnVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcExOcd%2FbtqMGeSwV1V%2Fknv26A32B1gBdbMlz4NnVK%2Fimg.png&quot; data-filename=&quot;슬라이드30.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다른 팀원이 낸 아이디어였는데, 실현 가능성/효용성이 없다고 판단해서 가위질을 많이했다.&lt;/p&gt;
&lt;p&gt;음.. 아마 게임처럼 만들거나 옛 싸이월드마냥 아바타를 도입하자는 걸로 기억한다..&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;게임화, 크라우드 펀딩등등은 까다로운 레벨 디자인과 유저, 모금 성공률을 들어 기각했고,&lt;/p&gt;
&lt;p&gt;대신 현재 있는 후기를 발전 시켜보는게 어떨까 싶었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;단순 후기 뿐만 아니라 제품을 사용하는 팁 등으로 사용자들이 소통과 유용한 정보를 생산하기 때문에,&lt;/p&gt;
&lt;p&gt;트래픽의 증가와 광고 수입의 증가도 노려볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드31.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxvdia/btqMAP0yeoy/nzowxjnDrE7MVg3Xs3KwLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxvdia/btqMAP0yeoy/nzowxjnDrE7MVg3Xs3KwLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxvdia/btqMAP0yeoy/nzowxjnDrE7MVg3Xs3KwLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxvdia%2FbtqMAP0yeoy%2FnzowxjnDrE7MVg3Xs3KwLK%2Fimg.png&quot; data-filename=&quot;슬라이드31.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;/p&gt;
&lt;p&gt;기본적인 서식 기능, 메인화면 노출, 좋은 후기는 추가 포인트, 단순 후기를 넘어 강좌/팁 정보도 노려볼 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;사람끼리 부대끼며, 상업화 요소가 들어가면 당연히 바이럴과 스팸등의 문제가 생긴다.&lt;/p&gt;
&lt;p&gt;이는 AI를 이용해 바이럴과 스팸 방지 시스템을 만들어 최대한 잡아볼 수 있다고 생각한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드32.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZWKEG/btqMGM2yuGX/oSbaZh4iCWNFJ6rLAfbUuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZWKEG/btqMGM2yuGX/oSbaZh4iCWNFJ6rLAfbUuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZWKEG/btqMGM2yuGX/oSbaZh4iCWNFJ6rLAfbUuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZWKEG%2FbtqMGM2yuGX%2FoSbaZh4iCWNFJ6rLAfbUuK%2Fimg.png&quot; data-filename=&quot;슬라이드32.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;메인화면은 트래픽이 집중되는 곳으로, 모든 사이트에 중요하며 신중한 접근이 필요하다.&lt;/p&gt;
&lt;p&gt;내가 생각한 자리는 전면광고와 오늘의 발견(추천상품) 사이이며, 텍스트로 노출해야 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;텍스트는 많은 양의 글을 노출할 수 있게 만들 수 있으며, 일반인이 찍은 사진은 일관성, 구도, 화이트밸런스등 때문에 사이트 디자인을 해치는 요소가 될 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;또한 사진을 넣을경우, 밑에 나오는 오늘의 발견에 대한 시각적 집중 효과를 잃게 만들 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드33.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pT3yd/btqMBwsUFYh/sGePk0HYVM8Veb87onkcPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pT3yd/btqMBwsUFYh/sGePk0HYVM8Veb87onkcPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pT3yd/btqMBwsUFYh/sGePk0HYVM8Veb87onkcPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpT3yd%2FbtqMBwsUFYh%2FsGePk0HYVM8Veb87onkcPK%2Fimg.png&quot; data-filename=&quot;슬라이드33.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;내가 스트리밍 서비스 이야기를 하자 AI 스피커 아이디어를 냈던 팀원이 제안한 아이디어였던 것 같다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;넷플릭스는 계정 공유를 문제삼지 않으며 앱스토어나 플레이스토어의 경우 가족끼리 앱공유를 할 수도 있게 만든 점등을 고려할 때, 비교적 가격에 민감한 높은 연령대와 경쟁사로부터 끌여들일때 유효성이 상당하다고 판단했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드34.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bicfdj/btqMG6zIU79/YIoIoYhkKsBO5VY78Ivy2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bicfdj/btqMG6zIU79/YIoIoYhkKsBO5VY78Ivy2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bicfdj/btqMG6zIU79/YIoIoYhkKsBO5VY78Ivy2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbicfdj%2FbtqMG6zIU79%2FYIoIoYhkKsBO5VY78Ivy2k%2Fimg.png&quot; data-filename=&quot;슬라이드34.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;경험상 회원등급이 높은 가족의 계정으로 물건을 구매하는 경우(쿠폰 등 혜택)가 종종 일어나는데, 개인정보의 문제가 발생한다. (상품 주문 목록, 비밀번호 공유 등)&lt;/p&gt;
&lt;p&gt;그렇다면, 주소지가 같은 4인까지는 100원씩만 추가하는 선에서 가족 요금제를 신청하는게 어떨까라고 생각했다.&lt;/p&gt;
&lt;p&gt;무작정 주는 혜택은 재정파탄을 일으킬 수도 있기 때문.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드35.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLreHw/btqMCgcjQzO/9tBV0b8eKceJwhkoDz77k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLreHw/btqMCgcjQzO/9tBV0b8eKceJwhkoDz77k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLreHw/btqMCgcjQzO/9tBV0b8eKceJwhkoDz77k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLreHw%2FbtqMCgcjQzO%2F9tBV0b8eKceJwhkoDz77k1%2Fimg.png&quot; data-filename=&quot;슬라이드35.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;쿠팡의 사이트를 돌아봤을때, 깔끔하지만 개성이 없다는 느낌이 었다.&lt;/p&gt;
&lt;p&gt;베스트프랙티스들을 준수하는데 열중해서 고유성이 없달까? (&lt;a href=&quot;https://brunch.co.kr/@scottim/4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;쿠팡 UX BIBLE &amp;amp; Complex&lt;/a&gt;란 블로그 글을 읽으면 왜 그런지 알 것도 같다.)&lt;/p&gt;
&lt;p&gt;고유성은 BX에서 중요하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이외 전환과 이탈을 막고, 구매 결정을 돕기 위한 UI/UX 보완이 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드36.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvoCnG/btqMJDQ7URK/fheTvMZHaUHkhiKXujIAKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvoCnG/btqMJDQ7URK/fheTvMZHaUHkhiKXujIAKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvoCnG/btqMJDQ7URK/fheTvMZHaUHkhiKXujIAKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvoCnG%2FbtqMJDQ7URK%2FfheTvMZHaUHkhiKXujIAKk%2Fimg.png&quot; data-filename=&quot;슬라이드36.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;타이포그패피에 관심있다보니&amp;nbsp;폰트 이야기가 등장한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;로켓은 거대한 물체가 중력을 벗어나기 위해 강력한 화력을 내뿜는 이미지가 강하므로,&lt;/p&gt;
&lt;p&gt;두껍고 역동적인 느낌이었으면 했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예를 들어 Rix 자유로에 기울임을 준 정도?&lt;/p&gt;
&lt;p&gt;임의로 만든 이미지가 훨씬 낫지 않나 싶다. ㅎㅎ&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;지금보니 오른쪽 사진 배치가 위로 치우쳐저 있는 듯 하다.&lt;/p&gt;
&lt;p&gt;그때 시간이 워낙 없어서...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드37.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R1UwI/btqMHWjjvif/ko230XssYeKvrR4kl1pBik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R1UwI/btqMHWjjvif/ko230XssYeKvrR4kl1pBik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R1UwI/btqMHWjjvif/ko230XssYeKvrR4kl1pBik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR1UwI%2FbtqMHWjjvif%2Fko230XssYeKvrR4kl1pBik%2Fimg.png&quot; data-filename=&quot;슬라이드37.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;쿠팡은 호버 인터렉션이 잘되어 있었다.&lt;/p&gt;
&lt;p&gt;여기에 이마트처럼 상품의 뒷면과 메뉴를 보여주는 인터렉션이 들어가면 금상첨화다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;많은 사용자들이 장바구니를 관심목록과 가격비교용으로 사용하므로,&lt;/p&gt;
&lt;p&gt;직관적으로 가격을 비교할 수 있는 시스템 도입도 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드38.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbCOdR/btqMDzQeohx/yTeDeDDAKfpHeJsrIZjbMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbCOdR/btqMDzQeohx/yTeDeDDAKfpHeJsrIZjbMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbCOdR/btqMDzQeohx/yTeDeDDAKfpHeJsrIZjbMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbCOdR%2FbtqMDzQeohx%2FyTeDeDDAKfpHeJsrIZjbMK%2Fimg.png&quot; data-filename=&quot;슬라이드38.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다시 마케팅 방안과 포지션을 적어, 수미상관처럼 배치.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드39.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yq9m7/btqMHWczfFP/75ehQoyQi9RURKvnp8EabK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yq9m7/btqMHWczfFP/75ehQoyQi9RURKvnp8EabK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yq9m7/btqMHWczfFP/75ehQoyQi9RURKvnp8EabK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYq9m7%2FbtqMHWczfFP%2F75ehQoyQi9RURKvnp8EabK%2Fimg.png&quot; data-filename=&quot;슬라이드39.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다시금 해결해야할 목표를 떠올리게 만들어 신뢰성을 높혔다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드40.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dU4GaU/btqMGOTBseV/SAKfc3qW3YhJuqmwMivY5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dU4GaU/btqMGOTBseV/SAKfc3qW3YhJuqmwMivY5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dU4GaU/btqMGOTBseV/SAKfc3qW3YhJuqmwMivY5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdU4GaU%2FbtqMGOTBseV%2FSAKfc3qW3YhJuqmwMivY5k%2Fimg.png&quot; data-filename=&quot;슬라이드40.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;출처들.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드41.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JVd1Z/btqMGMVPh1G/KqQUZuQpLeSKv03lCe6b6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JVd1Z/btqMGMVPh1G/KqQUZuQpLeSKv03lCe6b6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JVd1Z/btqMGMVPh1G/KqQUZuQpLeSKv03lCe6b6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJVd1Z%2FbtqMGMVPh1G%2FKqQUZuQpLeSKv03lCe6b6K%2Fimg.png&quot; data-filename=&quot;슬라이드41.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Q&amp;amp;A를 배달 온 모양처럼 만들었다.&lt;/p&gt;
&lt;p&gt;끝.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;슬라이드42.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pE1lD/btqMBvtZ78x/DjRgPlBTAjY2CzxdGWIbz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pE1lD/btqMBvtZ78x/DjRgPlBTAjY2CzxdGWIbz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pE1lD/btqMBvtZ78x/DjRgPlBTAjY2CzxdGWIbz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpE1lD%2FbtqMBvtZ78x%2FDjRgPlBTAjY2CzxdGWIbz0%2Fimg.png&quot; data-filename=&quot;슬라이드42.PNG&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>기타 정보</category>
      <category>경영</category>
      <category>쿠팡</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/77</guid>
      <comments>https://black7375.tistory.com/77#entry77comment</comments>
      <pubDate>Fri, 30 Oct 2020 13:17:32 +0900</pubDate>
    </item>
    <item>
      <title>React + RxJS Todo App (with 오버엔지니어링?)</title>
      <link>https://black7375.tistory.com/75</link>
      <description>&lt;p&gt;처음에는 React에 RxJS를 섞어보는 것을 목표로 하는 플젝이었는데&lt;/p&gt;
&lt;p&gt;재미로 이것저것 넣다보니 산으로 갔다ㅋㅋ&lt;/p&gt;
&lt;p&gt;아직 만드는 중이지만 벌써 5월이 되서 일단 소개해본다.&lt;/p&gt;
&lt;p&gt;&lt;s&gt;회사 지원해야뎌..&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/black7375/React-RxJS-Todo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/black7375/React-RxJS-Todo&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1588462969326&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;black7375/React-RxJS-Todo&quot; data-og-description=&quot;Contribute to black7375/React-RxJS-Todo development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/black7375/React-RxJS-Todo&quot; data-og-url=&quot;https://github.com/black7375/React-RxJS-Todo&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/JwMCt/hyFTc64u2D/TKt1EoyMffRdtzZnFAMMTk/img.jpg?width=400&amp;amp;height=400&amp;amp;face=116_158_218_269&quot;&gt;&lt;a href=&quot;https://github.com/black7375/React-RxJS-Todo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/black7375/React-RxJS-Todo&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/JwMCt/hyFTc64u2D/TKt1EoyMffRdtzZnFAMMTk/img.jpg?width=400&amp;amp;height=400&amp;amp;face=116_158_218_269');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;black7375/React-RxJS-Todo&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Contribute to black7375/React-RxJS-Todo development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&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;li&gt;반응형 | 유동적 디자인&lt;/li&gt;
&lt;li&gt;시간나면 PWA, Web Component까지도 도입&lt;/li&gt;
&lt;li&gt;등등 각종 개념 증명용 또는 오버엔지니어링 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;우선 생긴건 대충 이런식.&lt;/p&gt;
&lt;p&gt;다양한 기술이나 개념을 조화롭게 접목시키는 것이 목적인 프로젝트다보니 기능은 최소한으로 유지했다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKNYdg/btqDQbDYLcF/f3Z8fa4mtaQE6rfzB0swp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKNYdg/btqDQbDYLcF/f3Z8fa4mtaQE6rfzB0swp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKNYdg/btqDQbDYLcF/f3Z8fa4mtaQE6rfzB0swp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKNYdg%2FbtqDQbDYLcF%2Ff3Z8fa4mtaQE6rfzB0swp0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;성능에 신경을 어느정도 써서 프로덕션이 아닌 &lt;b&gt;개발용 모드 ,캐시 비활성화, CPU 쓰로틀링(6배)&lt;/b&gt;에도 쓸만한 수치를 보여준다.&lt;/p&gt;
&lt;p&gt;초기 리스트 갯수는 2500개.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;로드 시간: 773ms&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTW8kz/btqDRL5ACRj/BUDiqdkLhr6RjYTKcyQuRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTW8kz/btqDRL5ACRj/BUDiqdkLhr6RjYTKcyQuRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTW8kz/btqDRL5ACRj/BUDiqdkLhr6RjYTKcyQuRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTW8kz%2FbtqDRL5ACRj%2FBUDiqdkLhr6RjYTKcyQuRK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;체크박스를 On/Off시 렌더싱 시간은 6.4ms&lt;/p&gt;
&lt;p&gt;아직 많은 최적화 기법을 적용하지 않아서 개선 여지가 많은데도 쓸만하다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DYvil/btqDQbYDh8Z/THRFuYD5NiCvJ4uln5abdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DYvil/btqDQbYDh8Z/THRFuYD5NiCvJ4uln5abdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DYvil/btqDQbYDh8Z/THRFuYD5NiCvJ4uln5abdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDYvil%2FbtqDQbYDh8Z%2FTHRFuYD5NiCvJ4uln5abdK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;특이한 점으로 App과 TodoTemplate, TodoInsert는 렌더링에서 제외된 것을 볼 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;(버블링이 일어나지 않음)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;간단한 설명들&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기술/라이브러리&lt;/h3&gt;
&lt;p&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;b&gt;메인:&lt;/b&gt; ReactJS(with @types), RxJS, Typescript, Node SASS(with @types)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서브:&lt;/b&gt; ImmutableJS(with @types), RecyclerListView&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기타:&lt;/b&gt; Normalize.css, React Icons, Classnames, Postinstall-Postinstall, TS-Object-Utils&lt;/li&gt;
&lt;/ul&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;&lt;b&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;ReactJS : 아무래도 사용하는 사람이 많고, 나도 프론트엔드 3대장중 가장 관심이 가는 녀석&lt;/li&gt;
&lt;li&gt;RxJS: 앵귤러쪽에서 주로 사용되기는 하지만, 내 포스트들을 보면 Rx나 함수형 패러다임쪽을 선호하는 편이라.&lt;/li&gt;
&lt;li&gt;Typescript: 동적/인터프린터 언어인 JS를 생으로 쓰기는 좀,, 싶기도 하고 자동완성, 에러체크등 때문에 정적인 언어를 좋아하기 때문에&lt;/li&gt;
&lt;li&gt;SCSS: CSS-in-JS를 몇개 살펴보긴 했으나 PostCSS에 있는 CSSNext 및 각종 기능들과 섞어쓰기에 SCSS가 나을 듯하여(SASS는 중괄호 블럭이 없어서 싫다. 불명확하며 인공지능 코딩할 때가 생각나기도 해서;;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&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;ImmutableJS: Immer도 충분히 매력적이지만, 함수형 자료구조들을 파워풀하게 사용할 수 있고 성능도 더 나아서&lt;/li&gt;
&lt;li&gt;RecyclerListView: 안드로이드에서 RecyclerView와 ViewPager2를 잘 쓰던 기억과 React-Window/Virtualized와 다르게 뷰를 재활용한다는 점 때문에 매력적이여서 선택했으나.. 커다란 고비가. 애증의 라이브러리.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&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;Normalize.css: CSS 초기화&lt;/li&gt;
&lt;li&gt;React Icons: 다양한 SVG 아이콘을 쓸 수 있어서.&lt;/li&gt;
&lt;li&gt;Classnames: props로 클래스를 적용/해제시 간단하게 할 수 있다&lt;/li&gt;
&lt;li&gt;Postinstall-Postinstall: yarn에서 add를 할 때만 postinstall이벤트가 작동하나, 이 패키지를 설치하면 remove시에도 작동&lt;/li&gt;
&lt;li&gt;TS-Object-Utils: 다른건 아니고, 라이브러리 커스텀을 할 때 필요해서 사용했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;고민했던 것&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;이것저것 기술을 적용해보자는 플젝이라 리덕스나 MobX를 넣어볼까 하다가 RxJS 위주로 사용하기 위해 브런치로 분리하여 &lt;a href=&quot;https://github.com/black7375/React-RxJS-Todo/tree/redux&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구현만&lt;/a&gt;해두고, 합치지 않았다.&lt;/p&gt;
&lt;p&gt;TSTL(타입스크립트 STL) + Immer VS ImmutableJS를 써볼까하다 데이터구조 + 불변성을 한꺼번에 지원하는 Immutable로 결정.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;폴더 구조&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;최상위&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;patches 폴더가 추가된 것 빼고는 별다를 것 없다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pL5hT/btqDRNaTtwS/ks2R0IBrl7COfSUdBAxBV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pL5hT/btqDRNaTtwS/ks2R0IBrl7COfSUdBAxBV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pL5hT/btqDRNaTtwS/ks2R0IBrl7COfSUdBAxBV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpL5hT%2FbtqDRNaTtwS%2Fks2R0IBrl7COfSUdBAxBV1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;ITCSS 철학을 기반으로 만들어졌다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Settings: 전역적인 변수들 (Color, Font 등)&lt;/li&gt;
&lt;li&gt;Tools: 자주 쓰여질 만한 유틸이나 믹스인&lt;/li&gt;
&lt;li&gt;Generic: 프로젝트 첫번째 레이어(모델, Nomalize 등)&lt;/li&gt;
&lt;li&gt;Layouts: 꾸미는 것, 컨텐츠들보다 정렬 또는 컨테이너&lt;/li&gt;
&lt;li&gt;Components: 컴포넌트들&lt;/li&gt;
&lt;li&gt;Service: RxJS를 이용한 이벤트 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5gASG/btqDQ80S4Jo/K8oqjtoHNKy3Y0epVa3mHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5gASG/btqDQ80S4Jo/K8oqjtoHNKy3Y0epVa3mHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5gASG/btqDQ80S4Jo/K8oqjtoHNKy3Y0epVa3mHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5gASG%2FbtqDQ80S4Jo%2FK8oqjtoHNKy3Y0epVa3mHK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;디자인 컨셉&lt;/h3&gt;
&lt;p&gt;지난학기 내가 디자인했던 플젝에서 따왔다.&lt;/p&gt;
&lt;p&gt;종이처럼 스큐어모피즘스러운 편안한 느낌과 플랫/타이포그래피 위주의 디자인.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;상충하는 스큐어모피즘과 플랫이 만날수 있는 지점, 개인적으로 좋아하는 타이포그래피를 이용하기 위한 디자인, 눈이 편안한 색감을 찾다보니 이런 결과가 나올 수 밖에 없더란.&lt;/p&gt;
&lt;p&gt;어느때나 블로그에 예전자료를 개시해도 상관없도록 매달 산돌과 폰트릭스에게 상납하고 있다. 흒흒&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;포인트 컬러는 옥색이라 해야 하나, 민트&lt;s&gt;초코&lt;/s&gt;색이라 해야 하나.&lt;/p&gt;
&lt;p&gt;예전에 넷스케이프를 쓸때 감명받아 좋아하게된 색인데 만자로를 쓰면서 primary 색으로 사용해도 좋겠다는 생각이 들어 적용했다.&lt;/p&gt;
&lt;p&gt;단, Todo App에서는 홈버튼처럼 확 띄어야하거나, 오밀조밀한 UI에 섞여 구분하기 어려운 상황이 아니기 때문에 자연스래 섞이게 만들기 위해 채도를 낮췄다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biJl8M/btqDPYSumcc/HPiwOyEG6aWBIzODnJQdY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biJl8M/btqDPYSumcc/HPiwOyEG6aWBIzODnJQdY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biJl8M/btqDPYSumcc/HPiwOyEG6aWBIzODnJQdY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiJl8M%2FbtqDPYSumcc%2FHPiwOyEG6aWBIzODnJQdY1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주요 코드 소개&lt;/h2&gt;
&lt;p&gt;아직은 별것 없지만 어떻게 설계했는지 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Generic/TodoModel.tsx&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;인터페이스로 기본 아이템 값을 만들어준뒤, ImmutableJS로 데이터 모델을 생성하여 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1588468374613&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface TodoItemI {
  id:      number;
  text:    string;
  checked: boolean;
}

export const TodoItem: Record.Factory&amp;lt;TodoItemI&amp;gt; = Record({
  id:      0,
  text:    &quot;&quot;,
  checked: false,
} as TodoItemI);
export type TodoItemT = Record&amp;lt;TodoItemI&amp;gt; &amp;amp; Readonly&amp;lt;TodoItemI&amp;gt;;

export type TodoItemsT = List&amp;lt;TodoItemT&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;App.tsx&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;이렇게 내용이 없어도 될 정도인가 싶을정도로 간단하다.&lt;/p&gt;
&lt;p&gt;App.tsx에서 필요한 글로벌 이벤트 관련 로직은 TodoService로 분리하여 Rx를 이용해 관리하기 때문.&lt;/p&gt;
&lt;pre id=&quot;code_1588468016817&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function App() {
  return (
    &amp;lt;TodoTemplate&amp;gt;
      &amp;lt;TodoInsert /&amp;gt;
      &amp;lt;TodoList /&amp;gt;
    &amp;lt;/TodoTemplate&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Services/TodoService.tsx&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;App.tsx에 있어야 할 것들이 모여있어 상당히 긴편이다.&lt;/p&gt;
&lt;p&gt;하지만 역할 구분이 잘 되어있어 어렵지 않다.&lt;/p&gt;
&lt;p&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;Large Size Sample: 초기 로딩할 데이터&lt;/li&gt;
&lt;li&gt;Core Event: 업데이트, 생성, 삭제, 토글 이벤트 타입정의 및 생성&lt;/li&gt;
&lt;li&gt;Data: 아직 리덕스나 MobX를 적용하지 않아 글로벌 상태는 여기에서 관리한다. todo$는 각 이벤트 발생시 todos =&amp;gt; todos인 함수를 적용&lt;/li&gt;
&lt;li&gt;Event Implementation: 각 이벤트가 일어날 때 처리방법 구현 및 업데이트 처리&lt;/li&gt;
&lt;li&gt;Interface: TodoService를 사용해 외부에서 Observable이나 이벤트 발생을 받아들이기 위한 인터페이스&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1588468323494&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// == Large Size Sample ========================================================
const largeItemSize = 2500;
const largeInitItems = List((() =&amp;gt; {
  const array = [];
  for (let i = 0; i &amp;lt; largeItemSize; i++) {
    array.push(new TodoItem({
      id: i,
      text: `Task ${i}`,
      checked: false
    }));
  }
  return array;
})());


// == Core Events ==============================================================
const update$ = new BehaviorSubject((todos: TodoItemsT) =&amp;gt; todos);
const insert$ = new Subject&amp;lt;TodoItemT&amp;gt;();
const remove$ = new Subject&amp;lt;TodoItemT['id']&amp;gt;();
const toggle$ = new Subject&amp;lt;TodoItemT['id']&amp;gt;();


// == Data =====================================================================
let nextId = largeItemSize + 1;
const todos$ = update$.pipe(
  scan((todos, operation) =&amp;gt; operation(todos), largeInitItems),

  // cache
  publishReplay(1),
  refCount()
);


// == Events Implementation ====================================================
insert$.pipe(
  map((todo) =&amp;gt; (todos: TodoItemsT) =&amp;gt; todos.push(todo))
).subscribe(update$);

remove$.pipe(
  map((id)   =&amp;gt; (todos: TodoItemsT) =&amp;gt; todos.filter(todo =&amp;gt; todo.id !== id))
).subscribe(update$);

toggle$.pipe(
  map((id)   =&amp;gt; (todos: TodoItemsT) =&amp;gt; todos.map(todo =&amp;gt; todo.id === id
    ? todo.set(&quot;checked&quot;, !todo.checked)
    : todo
  ))
).subscribe(update$);


// == Interface ================================================================
const TodoService = {
  initData: largeInitItems,
  todos$: todos$,

  onInsert: (text: TodoItemT['text']) =&amp;gt; {
    insert$.next(new TodoItem({
      id:      nextId,
      text:    text,
      checked: false
    }));
    nextId++;
  },
  onRemove: (id: TodoItemT['id']) =&amp;gt; remove$.next(id),
  onToggle: (id: TodoItemT['id']) =&amp;gt; toggle$.next(id)
};

export default TodoService;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Components/TodoListItem.tsx&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;그럼 필요한 props와 콜백은 어떻게 전달될까?&lt;/p&gt;
&lt;p&gt;꼭 필요한 props만 의존하고, 글로벌 이벤트는 TodoServcie로부터 불러와 사용한다.&lt;/p&gt;
&lt;p&gt;TodoService가 이벤트를 관리하기 때문에 App까지 이벤트 버블링이 필요없고, 상태변화 후 렌더링시에도 영향이 제한된다.&lt;/p&gt;
&lt;pre id=&quot;code_1588544122043&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const cx = stylesBind(styles);

interface TodoListItemProps {
  todo: TodoItemT;
  key: TodoItemT['id'];
}

const TodoListItem = ({ todo }: TodoListItemProps) =&amp;gt; {
  const { id, text, checked } = todo;
  const onRemoveDown = useCallback(() =&amp;gt; TodoService.onRemove(id), [id]);
  const onToggleDown = useCallback(() =&amp;gt; TodoService.onToggle(id), [id]);

  return (
    &amp;lt;div className={cx('TodoListItem')}&amp;gt;
      &amp;lt;div className={cx('checkbox', { checked })} onPointerDown={onToggleDown} &amp;gt;
        {checked ? &amp;lt;IoMdCheckmarkCircleOutline /&amp;gt; : &amp;lt;IoIosRadioButtonOff /&amp;gt; }
        &amp;lt;div className={cx('text')}&amp;gt;{text}&amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div className={cx('remove')} onPointerDown={onRemoveDown} &amp;gt;
        &amp;lt;BsTrash /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default React.memo(TodoListItem);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Components/TodoList.tsx&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;로딩과 렌더링 시 성능향상의 핵심인 RecyclerListView를 사용한다.&lt;/p&gt;
&lt;p&gt;처음 초기화시를 제외하고, Observable로 상태를 바로 업그레이드 하도록 만들었다.&lt;/p&gt;
&lt;pre id=&quot;code_1588469898222&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const cx = stylesBind(styles);

const ListViewType = {
  TODOLISTITEMS: 0
}

const TodoList = () =&amp;gt; {
  const width = window.innerWidth;
  const renderData = new ListDataProvider(
    (r1: TodoItemT, r2: TodoItemT) =&amp;gt; r1 !== r2
  ).cloneWithRows(TodoService.initData);

  const [dataProvider, setDataProvider] = useState(renderData);
  useEffect(() =&amp;gt; {
    const sub = TodoService.todos$.subscribe((todos) =&amp;gt; {
      setDataProvider((dataProvider) =&amp;gt; dataProvider.cloneWithRows(todos));
      }
    );
    return () =&amp;gt; { sub.unsubscribe(); };
  }, []);

  const layoutProvider = new LayoutProvider(
    (index) =&amp;gt; { return ListViewType.TODOLISTITEMS },
    (type, dim) =&amp;gt; {
      switch(type) {
        case ListViewType.TODOLISTITEMS: {
          dim.width  = width; // 630.4 584
          dim.height = 55;    // 55.2  54.4
          break;
        }
        default:
          dim.width  = 0;
          dim.height = 0;
      }
    }
  );

  const rowRenderer = (viewType: React.ReactText, todo: TodoItemT) =&amp;gt; {
    switch (viewType) {
      case ListViewType.TODOLISTITEMS: {
        return (&amp;lt;TodoListItem todo={todo} key={todo.id} /&amp;gt;);
      }
      default:
        return null;
    }
  }

  return (
    &amp;lt;div className={cx('TodoList')}&amp;gt;
      &amp;lt;RecyclerListView dataProvider={dataProvider} layoutProvider={layoutProvider}
                        rowRenderer={rowRenderer} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default React.memo(TodoList);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Tools/RecyclerProvider.ts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;빠르게 만들려고 도입했던 RecyclerListView.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;처음에 도입하려했더니 ImmutableJS의 List는 사용할 수 없고, 오직 기본 []만 쓸 수 있었다.&lt;/p&gt;
&lt;p&gt;그래서 데이터 주입 및 관리하는 부분을 까보면서 인터페이스의 내부 부분을 싹 재설계한 결과.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;물론 여기서도 성능향상이 있었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커다란 List를 toArray나 toJS로 바꾸는데 드는 비용이 상당히 큰데 이를 최소화(이게 크다)&lt;/li&gt;
&lt;li&gt;데이터 구조의 특성을 이용한 빠른 비교&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;타입을 지원하기 위해 아래 코드창에는 없는 제네릭 클래스 부분부터 다 만들었지만, 타입변환이 필요없는 것에서 오는 최적화는 이해하기 쉬우니 두번째 항목인 빠른 비교 위주로 설명하려 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그 중 핵심은 처음 바뀐 인덱스를 반환해주는 getFirstIndexChange.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;원래의 &lt;a href=&quot;https://github.com/Flipkart/recyclerlistview/blob/master/src/core/dependencies/DataProvider.ts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DataProvider&lt;/a&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;배열 크기 비교 후 작은 배열에 맞춤&lt;/li&gt;
&lt;li&gt;크기가 작은 배열의 크기까지 각 인덱스별 데이터가 바뀌었는지 반복하며 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이었던 구조를&lt;/p&gt;
&lt;p&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;Immutable 컬렉션의 equal을 사용해 같다면 현재 크기 사용&lt;/li&gt;
&lt;li&gt;크기 비교 후 작은 List에 맞춘 후&lt;/li&gt;
&lt;li&gt;조건을 만족하는 첫번째 인덱스를 반환하는 .findIndex를 사용하여 .get으로 접근 횟수를 줄이며 최적화 가능성을 최대한 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;로 바꾸었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1588472791265&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// == RecyclerListView Dataprovider with IMMUTABLE.JS ==========================
export abstract class ListBaseDataProvider&amp;lt;T&amp;gt; extends GenericDataProvider&amp;lt;T, List&amp;lt;T&amp;gt;&amp;gt; {
  public abstract newInstance(
    rowHasChanged: (r1: T, r2: T)  =&amp;gt; boolean,
    getStableId?:  (index: number) =&amp;gt; string  ): ListBaseDataProvider&amp;lt;T&amp;gt;;

  public getDataForIndex(index: number): T | undefined {
    return this.m_data.get(index);
  }

  // Fast Matching Lists
  private getFirstIndexChange(newData: List&amp;lt;T&amp;gt;, newSize: number): number {
    if(this.m_data.equals(newData)) {
      return this.m_size;
    }

    if(this.m_size &amp;gt; newSize) {
      const sizeData = newData.setSize(this.m_size);
      return (this.m_data as List&amp;lt;T&amp;gt;)
        .findIndex((value, index) =&amp;gt; this.rowHasChanged(value, sizeData.get(index)));
    } else {
      const sizeData = this.m_data.setSize(newSize);
      return (sizeData as List&amp;lt;T&amp;gt;)
        .findIndex((value, index) =&amp;gt; this.rowHasChanged(value, newData.get(index)));
    }
  }

  //No need to override this one
  //If you already know the first row where rowHasChanged will be false pass it upfront to avoid loop
  public cloneWithRows(newData: List&amp;lt;T&amp;gt;, firstModifiedIndex?: number): DataProvider {
    const dp        = this.newInstance(this.rowHasChanged, this.getStableId);
    const newSize   = newData.size;

    dp.m_firstIndexToProcess = ObjectUtil.isNullOrUndefined(firstModifiedIndex)
                            ? this.getFirstIndexChange(newData, newSize)
                            : Math.max(Math.min(firstModifiedIndex, this.m_data.size), 0);

    if (dp.m_firstIndexToProcess !== this.m_data.size) {
      dp.m_requiresDataChangeHandling = true;
    }
    dp.m_data = newData;
    dp.m_size = newSize;
    return dp;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;../patches/의 patch 삼총사와 yarn 라이프사이클&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;방금 RecyclerListView에서 List&amp;lt;&amp;gt;를 사용할 수 없게 되었다고 하였다.&lt;/p&gt;
&lt;p&gt;데이터 프로바인더 내부 말고,&amp;nbsp; props의 타입 정의 또한 any와 any[]로 이루어져있기 때문에 패치해주었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;patch_list.sh는 타겟 위치, 패치된 파일 위치, 패치를 생성할 위치를 정의한다.&lt;/p&gt;
&lt;pre id=&quot;code_1588473706334&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Patch Path
## TargetPath, PatchPatch, CreatedPatchPath
PATCH_PATH=(../node_modules/recyclerlistview/dist/web/core/RecyclerListView.d.ts
            ./recyclerlistview/RecyclerListView.d.ts
            ./created/recyclerlistview-recyclerlistview.patch

            ../node_modules/recyclerlistview/dist/web/core/dependencies/DataProvider.d.ts
            ./recyclerlistview/dependencies/DataProvider.d.ts
            ./created/recyclerlistview-dataprovider.patch
           )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;create_patch를 사용하면 두파일을 비교해 생성할 위치에 패치를 생성한다.&lt;/p&gt;
&lt;p&gt;DIR는 현재 파일의 절대경로를 생성해주는 트릭.&lt;/p&gt;
&lt;p&gt;10년 넘는 리눅스 생활 덕. ㅎㅎ&lt;/p&gt;
&lt;pre id=&quot;code_1588473937825&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DIR=$( cd &quot;$(dirname &quot;$0&quot;)&quot; ; pwd )

# Source Patch List
source ${DIR}/patch_list.sh

# Create Patch File
create_patch() {
  local target=$1
  local patched=$2
  local patch=$3
  diff -Naur ${DIR}/${target} ${DIR}/${patched} &amp;gt; ${DIR}/${patch}
}

for (( i = 0; i&amp;lt;${#PATCH_PATH[@]}; i++ )); do
  create_patch ${PATCH_PATH[i]} ${PATCH_PATH[i+1]} ${PATCH_PATH[i+2]}
  ((i+=2))
done&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;마지막으로 apply_patch는 node_modules에 패치를 적용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1588474075403&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DIR=$( cd &quot;$(dirname &quot;$0&quot;)&quot; ; pwd )

# Source Patch List
source ${DIR}/patch_list.sh

# apply patch
apply_patch() {
  local target=$1
  local patch=$2
  patch --forward ${DIR}/${target} &amp;lt; ${DIR}/${patch}
}

for (( i = 0; i&amp;lt;${#PATCH_PATH[@]}; i++)); do
   apply_patch ${PATCH_PATH[i]} ${PATCH_PATH[i+2]}
   ((i+=2))
done&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그 후, package.json의 postinstall에 bash로 실행해주라는 명령만 날리면 매 패키지 설치마다 실행이 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1588474161589&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;react-scripts start&quot;,
    &quot;build&quot;: &quot;react-scripts build&quot;,
    &quot;test&quot;: &quot;react-scripts test&quot;,
    &quot;eject&quot;: &quot;react-scripts eject&quot;,
    &quot;postinstall&quot;: &quot;bash ./patches/apply_patch.sh&quot;
  },&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;하지만 패키지 삭제시에는 안됐는데 Postinstall-Postinstall 패키지로 해결.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이렇게 RecyclerListView를 사용하려는 노오력이 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이외에도 3일동안 해매서 아이템 상태변화 시 스크롤 위치 초기화 문제를 겨우 잡았기 때문에 애증의 라이브러리라 할만하다. ㅠㅠㅠㅠ&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;재랜더링시 가까운 아이템 요소 크기로 움직이는 문제도 있었는데 깃헙의 도움으로 해결되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Layouts/TodoTemplate.module.scss&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;클래스들이 BEM 네이밍 스타일로 만들어도록 하기위해 CSS Module을 이용하고 있다.&lt;/p&gt;
&lt;p&gt;이 프로젝트는 개념 증명용으로 만들었기 때문에 변수와 믹스인을 최대한 활용하도록 코드를 짜보기도 했다.&lt;/p&gt;
&lt;p&gt;Atomic CSS에서 영감을 받아서 이리 구성해봤는데 처음 네이밍에 익숙해지는 것만 넘으면 의외로 쓸 만한듯.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;뷰포트가 작을 때 레이아웃이 깨지는 것을 보고 도입한 반응형 레이아웃이 적용되어 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1588476146309&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@import '~include-media-or/dist/include-media';
@import '../Settings/Colors.scss';
@import '../Settings/Fonts.scss';
@import '../Settings/Layouts.scss';
@import '../Tools/Tools.scss';

.TodoTemplate {
  @include flex-container-start-top;
  @include flex-container-alignY-center;
  @include font-legibility;
  font-family:      $notoSans;
  font-weight:      $medium;
  height:           $full-height;
  color:            $black;
  background-color: $white;

  .app-title {
    @include container-all;
    @include flex-item-alignY-fill;
    @include font-size($header-font-size, $header-font-max-size);
    font-family: $notoSerif;
    font-weight: $heavy;
    text-align:  center;
    padding:     $default-padding * 2;
    max-height:  $half-height;
  }
  .content {
    @include container;
    @include font-size($default-font-size, $default-font-max-size);
    @include media(&quot;&amp;gt;=laptop&quot;) {
      width: 40rem;
    }
    @include media(&quot;&amp;gt;=tablet&quot;) {
      margin-left:  30%;
      margin-right: 30%;
    }
    width: 80%;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Tools/Tools.scss&lt;/b&gt;&lt;/p&gt;
&lt;p&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;a href=&quot;https://developers.google.com/web/fundamentals/design-and-ux/responsive/patterns?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;반응형&amp;nbsp;웹&amp;nbsp;디자인&amp;nbsp;패턴&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;처럼 레이아웃에 대한 것들이 대부분이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&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;a href=&quot;https://www.creativebloq.com/rwd/expert-responsive-typography-tips-101517572&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;9&amp;nbsp;responsive&amp;nbsp;typography&amp;nbsp;tips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learnui.design/blog/mobile-desktop-website-font-size-guidelines.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Responsive&amp;nbsp;Website&amp;nbsp;Font&amp;nbsp;Size&amp;nbsp;Guidelines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;레이아웃은 %나 뷰포트 관련값으로 실시간 크기 조정이 되지만,&lt;/p&gt;
&lt;p&gt;폰트는 뷰포트나 % 값을 사용한 유동적 조정을 하기가 매우 어려웠기에 자료를 찾아보았다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&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;a href=&quot;https://css-tricks.com/books/fundamental-css-tactics/scale-typography-screen-size/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Scale&amp;nbsp;Typography&amp;nbsp;For&amp;nbsp;Any&amp;nbsp;Screen&amp;nbsp;Size&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;란 글을 통해&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&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;/ul&gt;
&lt;p&gt;를 산출하여 뷰포트 크기에 따라 자동으로 크기가 조정할 수 있는 방법을 알아냈다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;여기서 2차 멘붕이 몰려왔다.&lt;/p&gt;
&lt;p&gt;모바일~데스크톱 크기 그리고 HD~4K 해상도등을 고려해 글씨의 최소/최대 크기를 지정해야 하는 것이다.&lt;/p&gt;
&lt;p&gt;내가 디자이너였다면 감(?)이나 시각 디자인 이론에 따라 각 장치에 맞는 크기를 얻어낼 수 있겠지.&lt;/p&gt;
&lt;p&gt;그치만 나는 공돌이인 걸..&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다양한 장치에서 일관된 크기를 결정할 방법을 찾기 시작했다.&lt;/p&gt;
&lt;p&gt;처음에는 IOS의 pt, 안드로이드의 dp/sp 단위처럼 ppi 기반으로 사용해볼까 생각했다.&lt;/p&gt;
&lt;p&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;a href=&quot;https://blog.grotesq.com/post/593&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;pt와&amp;nbsp;px단위를&amp;nbsp;혼용하지&amp;nbsp;맙시다&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;란 글을 보고 난 후 생각을 접었고...&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;장치와 사용자와의 거리를 포함하지 않는 단위라는 점도 매력적이지 않았다.&lt;/p&gt;
&lt;p&gt;(예를들어 같은 크기라도 가까이서 보는 모바일에서 느껴지는 체감크기가 PC 모니터의 크기보다 클 수밖에 없다)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하루동안 열쇠를 찾기위해 고심했고.&lt;/p&gt;
&lt;p&gt;한때 장래희망이어서 열심히 공부했던 천문학에서 핵심 아이디어를 가져왔다.&lt;/p&gt;
&lt;p&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;View_Distance.jpeg&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;813&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7XFJ6/btqEhO1EEk0/5IZGgcN33BQQknO3auOOmk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7XFJ6/btqEhO1EEk0/5IZGgcN33BQQknO3auOOmk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7XFJ6/btqEhO1EEk0/5IZGgcN33BQQknO3auOOmk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7XFJ6%2FbtqEhO1EEk0%2F5IZGgcN33BQQknO3auOOmk%2Fimg.jpg&quot; data-filename=&quot;View_Distance.jpeg&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;813&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;&amp;nbsp;&lt;/p&gt;
&lt;p&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&gt;를 모두 포함하여 필요한 크기를 계산할 수 있는 단위이며 시력검사를 하는 원리이기도 했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;세부적인 이론과 자료는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/617328373467856896/%EA%B8%80%EC%94%A8-%ED%81%AC%EA%B8%B0%EC%99%80-%EA%B0%80%EB%8F%85%EC%84%B1-%EC%97%B0%EA%B5%AC%EC%A4%91&quot;&gt;글씨&amp;nbsp;크기와&amp;nbsp;가독성&amp;nbsp;연구중.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/617559750421446656/%EA%B8%80%EC%94%A8-%ED%81%AC%EA%B8%B0%EC%99%80-%EA%B0%80%EB%8F%85%EC%84%B1-%EC%9D%B4%EB%A1%A0&quot;&gt;글씨&amp;nbsp;크기와&amp;nbsp;가독성&amp;nbsp;이론.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;를 참고하면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;임의적으로 각도로 산출해낸 크기를 '적합 크기(Fit Size)'라고 부르는 중인데&lt;/p&gt;
&lt;p&gt;고해상도 &amp;gt; 폰 &amp;gt; 데스크탑 &amp;gt; 랩탑 &amp;gt; 태블릿 순이란 결과를 얻을 수 있었으며 합리적으로 변환을 해주었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;fluid-font-size.png&quot; data-origin-width=&quot;3683&quot; data-origin-height=&quot;1017&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xomV8/btqEgRkhldP/vofXpSZXkWUKDaHJJiEJa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xomV8/btqEgRkhldP/vofXpSZXkWUKDaHJJiEJa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xomV8/btqEgRkhldP/vofXpSZXkWUKDaHJJiEJa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxomV8%2FbtqEgRkhldP%2FvofXpSZXkWUKDaHJJiEJa1%2Fimg.png&quot; data-filename=&quot;fluid-font-size.png&quot; data-origin-width=&quot;3683&quot; data-origin-height=&quot;1017&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: center;&quot;&gt;각 장치에 맞는 크기 생성&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하지만 사람이 매번 수동적으로 기기와의 거리,&amp;nbsp; 기기의 크기, 가로 해상도, 세로 해상도를 입력해 각 장치에 맞는 크기를 구하기는 복잡했고, 인터페이스를 만들었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그냥 폰트 지정하듯&lt;/p&gt;
&lt;pre id=&quot;code_1589938330628&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@include font-size($size, $max-size: 옵션);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;만 지정해주면&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;크기 입력&lt;/li&gt;
&lt;li&gt;가장 작게 보일 장치에서의 각도 계산 (또는 기준이 될 장치를 지정해볼 수 있겠죠?)&lt;/li&gt;
&lt;li&gt;각도를 기반으로 각 장치별 적합 크기 생성&lt;/li&gt;
&lt;li&gt;장치 사이의 유동성 제공&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;란 과정을 통해 각장치 맞는 크기를 생성하고 유동적으로 크기가 조절된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;나중에 라이브러리로 따로 뺄 예정.&lt;/p&gt;
&lt;pre id=&quot;code_1589935368620&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ** Responsive ***************************************************************
// == Size =====================================================================
$DEFAULT-BREAK: default !default;
$DEFAULT-SIZE:  16px    !default;

@function zip-responsive() {
  @return zip(
    map-values($screen-distances), map-values($screen-sizes      ),
    map-values($breakpoints     ), map-values($breakpoints-height)
  );
}

@function calc-ppi($screen-width, $screen-height, $screen-size) {
  @return sqrt(pow($screen-width, 2) + pow($screen-height, 2)) / $screen-size;
}

@function calc-angle($size) {
  $size:     num(px($size));
  $values:   zip-responsive();
  $smallest: null;

  @each $value in $values {
    $screen-distance: nth($value, 1) * 100;
    $screen-size:     nth($value, 2);
    $screen-width:    num(nth($value, 3));
    $screen-height:   num(nth($value, 4));

    $ppi: calc-ppi($screen-width, $screen-height, $screen-size);
    $independent-value: $screen-distance * $ppi;
    @if (($smallest == null) or ($smallest &amp;gt; $independent-value)) {
      $smallest: $independent-value;
    }
  }

  $angle: $size * 54 / $smallest;
  $visual-angle: atan($angle) * (10800 / pi());
  @return count-round($visual-angle, 2);
}

@function calc-size($visual-angle) {
  $values:      zip-responsive();
  $break-sizes: ();

  @each $value in $values {
    $screen-distance: nth($value, 1) * 100;
    $screen-size:     nth($value, 2);
    $screen-width:    num(nth($value, 3));
    $screen-height:   num(nth($value, 4));

    $ppi: calc-ppi($screen-width, $screen-height, $screen-size);
    $angle: tan(pi() * $visual-angle / 10800);
    $size: $screen-distance * $angle * $ppi / 54;

    $break-sizes: append($break-sizes, ($size));
  }

  @return $break-sizes;
}

// https://gist.github.com/eduardoboucas/84144cd85cbd2ad4db1ca8b902585ca0
@function im-to-em($breakpoints, $base-value: 16px) {
  $new-breakpoints: ();

  @each $key, $value in $breakpoints {
    $em-value: ($value / $base-value) * 1em;
    $new-breakpoints: map-merge($new-breakpoints, ($key: $em-value));
  }

  @return $new-breakpoints;
}

// https://www.madebymike.com.au/writing/fluid-type-calc-examples/
@function fluid-rate($start-size, $end-size, $min-screen, $max-screen) {
  @return ($end-size - $start-size) / ($max-screen - $min-screen);
}
@function fluid-basic-size($start-size, $min-screen, $rate) {
  @return $start-size - $rate * $min-screen;
}

@function fluid-size($start-size, $end-size, $min-screen, $max-screen) {
  $start-size: em($start-size);
  $end-size:   em($end-size);
  $min-screen: em($min-screen);
  $max-screen: em($max-screen);

  $rate: fluid-rate($start-size, $end-size, $min-screen, $max-screen);
  $basic-size: fluid-basic-size($start-size, $min-screen, $rate);

  $sign: &quot;+&quot;;
  @if ($basic-size &amp;lt; 0) {
    $sign: &quot;-&quot;;
    $basic-size: abs($basic-size);
  }
  @return calc(#{$rate*100}vw #{$sign} #{$basic-size});
}
@function fluid-limit-break($start-size, $end-size, $max-size,
                            $min-screen, $max-screen) {
  $start-size: px($start-size);
  $end-size:   px($end-size);
  $max-size:   px($max-size);
  $min-screen: px($min-screen);
  $max-screen: px($max-screen);

  $rate: fluid-rate($start-size, $end-size, $min-screen, $max-screen);
  $basic-size: fluid-basic-size($start-size, $min-screen, $rate);

  @return ($max-size - $basic-size) / $rate;
}

@mixin fluid-media($property, $sizes, $max-size: null) {
  $fluid-sizes: to-unit-map($sizes, px);
  $fluid-breakpoints: map-merge(($DEFAULT-BREAK: 0px), to-unit-map($breakpoints, px));
  @if not map-has-key($fluid-sizes, $DEFAULT-BREAK) {
    $default-map: ($DEFAULT-BREAK: $DEAFULT-SIZE);
    $fluid-sizes: map-merge($default-map, $fluid-sizes);
  }
  $limit-break: null;

  $last-size: length($fluid-breakpoints) - 1;
  @each $i in range($last-size) {
    $now-key:  map-nth($fluid-breakpoints, $i);
    $next-key: map-nth($fluid-breakpoints, $i + 1);

    $now-size:   map-get($fluid-sizes, $now-key );
    $next-size:  map-get($fluid-sizes, $next-key);
    $now-break:  map-get($fluid-breakpoints, $now-key );
    $next-break: map-get($fluid-breakpoints, $next-key);

    @if ($max-size != null) {
      $limit-break: fluid-limit-break($now-size,  $next-size, $max-size,
                                      $now-break, $next-break);

      $max-size:  px($max-size);
      $now-size:  if($now-size  &amp;gt; $max-size, $max-size, $now-size );
      $next-size: if($next-size &amp;gt; $max-size, $max-size, $next-size);
    }

    $fluid-size: fluid-size($now-size, $next-size, $now-break, $next-break);
    @if $now-key == $DEFAULT-BREAK {
      #{$property}: $fluid-size;
    }
    @else if($max-size != null) and ($i == $last-size) {
      @include media(&quot;&amp;gt;=#{$limit-break}&quot;) {
        #{$property}: $max-size;
      }
    }
    @else {
      @include media(&quot;&amp;gt;=#{$now-key}&quot;) {
        #{$property}: $fluid-size;
      }
    }
  }
}

@mixin fluid($property, $size, $max-size: null) {
  $scaled-size: calc-size(calc-angle($size));

  $keys:   join($DEFAULT-BREAK, map-keys($breakpoints));
  $values: join($size, $scaled-size);

  @include fluid-media($property, to-map($keys, $values), $max-size);
}

// -- Interface ----------------------------------------------------------------
// Font
@mixin font-size($size, $max-size: null) {
  @include fluid(font-size, $size, $max-size);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/75</guid>
      <comments>https://black7375.tistory.com/75#entry75comment</comments>
      <pubDate>Sun, 3 May 2020 09:01:19 +0900</pubDate>
    </item>
    <item>
      <title>[스압/데이터주의] 웹 최적화 방식 모음 - 2. 파싱 및 렌더링 트리</title>
      <link>https://black7375.tistory.com/74</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/72&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 0. 전반적 원칙과 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/73&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 1. 다운로드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/74&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 2. 파싱 및 렌더링 트리(현재)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/79&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3. Layout 및 렌더링&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/80&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3.3 UX 트릭&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/81&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 4. 로드 후&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/82&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 5. 빌드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 파싱 및 렌더링 트리&lt;/h2&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;,&amp;nbsp; 기타 &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;2.1 배치순서&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1.1 CSS를 상단에 배치&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HEAD에 스타일 시트를 넣으면 페이지가 점진적으로 렌더링 될 수 있어 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSSOM 트리는 CSS를 모두 해석해야 구성되고, 구성되지 않으면 렌더링이 차단되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 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;성능에 관심이 있는 프론트엔드 엔지니어들은 점진적으로 페이지를 읽어오길 원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 브라우저에 가능하면 빨리 어떠한 컨텐츠 표시할 수 있기를 원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 컨텐츠가 많은 페이지와 느린 인터넷 접속 사용자에게 특히 중요한데, 사용자에게 진행률 표시기(progress indicator)와 같은 시각적 피드백 제공의 중요성은 잘 연구되고 &lt;a href=&quot;https://www.nngroup.com/articles/response-times-3-important-limits/&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;브라우저가 페이지를 점진적으로 읽어올 때, 상단의 헤더(header), 메뉴바(navigation bar), 로고 등은 페이지를 기다리는 사용자에게 시각적 피드백을 제공하는 역할을 하고 이것은 전반적인 사용자경험(UX)을 향상시킨다.&lt;/p&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를 배치한다면 많은 브라우저에서 점진적으로 렌더링되는 것에 악영향을 끼친다.&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;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;다시 말하지만, 최적의 솔루션은 HTML 사양을 따르고 스타일 시트를 문서 HEAD에 로드하는 것이다.&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://www.w3.org/TR/html4/struct/links.html#h-12.3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTML&amp;nbsp;스펙&lt;/a&gt;은&amp;nbsp;명확하게&amp;nbsp;스타일이&amp;nbsp;페이지의&amp;nbsp;HEAD에&amp;nbsp;포함시킬&amp;nbsp;것을&amp;nbsp;기술한다&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Unlike A, [LINK] may only appear in the HEAD section of a document, although it may appear any number of times.&lt;br /&gt;a태그가 여러 번 나타날 수 있는 것과 달리, [LINK]는 오직 문서의 HEAD 섹션에 표시 될 수 있습니다.&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;pre id=&quot;code_1585022734115&quot; class=&quot;html xml&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;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;head&amp;gt;
  ...
  &amp;lt;link href=&quot;STYLE.css&quot; rel=&quot;stylesheet&quot; /&amp;gt;
  ...
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1.2 Script를 하단에 배치&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; 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;&lt;a href=&quot;https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP / 1.1 규격&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;하지만 무엇보다 중요한 것은 자바스크립트는 DOM과 CSSOM 트리를&amp;nbsp; 변경할 수&amp;nbsp; 있기 때문에 파싱을 차단하는 리소스라는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부에서 가져오는 스크립트도 모두 다운로드되고 실행될 때까지 DOM 트리 생성를 중단한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;head에 위치시: 스크립트를 실행한 후 body를 렌더링&lt;/li&gt;
&lt;li&gt;body에 위치시: DOM 랜더링 도중 스크립트를 만나면 처리완료시까지 랜더링이 중단&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;따라서 /body의 직전에 두는 것이 가장 현명한 방법.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트와 렌더링은 &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/critical-rendering-path/adding-interactivity-with-javascript#parser_blocking_versus_asynchronous_javascript&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 style=&quot;font-size: 1.12em;&quot; 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;pre id=&quot;code_1585025768770&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;script src=&quot;SCRIPT.js&quot; type=&quot;text/javascript&quot;&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;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: #333333;&quot;&gt;document.write를&amp;nbsp;&lt;/span&gt;사용하는 경우 페이지에서 하단 이동할 수 없으며 Scope 문제가 있을 수도 있다.&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;바로 비동기(async)나 지연된(deferred) 스크립트를 사용하는 것이다.[&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Element/script&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lt;script&amp;gt; 요소&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크립트에 document.write가 포함되어 있지 않으며(지정된 순서대로 실행된다는 보장이 없기 때문) 브라우저에서 렌더링을 계속할 수 있는 단서다. [&lt;a href=&quot;https://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;async&amp;nbsp;vs&amp;nbsp;defer&amp;nbsp;attributes&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;335&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FAiHg/btqW8FS150A/KstylioKB7bPrgoFLal2e1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FAiHg/btqW8FS150A/KstylioKB7bPrgoFLal2e1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FAiHg/btqW8FS150A/KstylioKB7bPrgoFLal2e1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFAiHg%2FbtqW8FS150A%2FKstylioKB7bPrgoFLal2e1%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;600&quot; height=&quot;335&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;335&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;async: 다운이 완료되면 실행&lt;/li&gt;
&lt;li&gt;defer: HTML 파싱이 끝나면 실행&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1.3 우선순위에 대한 힌트 제공&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위에 대한 &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/resource-prioritization?hl=ko&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;바로 전에 언급했던 async, defer와 같은 예도 속한다.&lt;/p&gt;
&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content&quot;&gt;preload&lt;/a&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Link_prefetching_FAQ&quot;&gt;prefetch&lt;/a&gt;에 대해서만 다루어보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 것은 MDN의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link&quot;&gt;link항목&lt;/a&gt;&lt;span&gt;와 참조 링크들을&amp;nbsp;&lt;/span&gt;참조. [&lt;a href=&quot;https://medium.com/@koh.yesl/preload-prefetch-and-priorities-in-chrome-15d77326f646&quot;&gt;Preload,&amp;nbsp;Prefetch&amp;nbsp;And&amp;nbsp;Priorities&amp;nbsp;in&amp;nbsp;Chrome&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://beomy.github.io/tech/browser/preload-preconnect-prefetch/&quot;&gt;리소스 우선순위 - preload, preconnect, prefetch&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://codeburst.io/how-to-improve-web-performance-by-using-preload-preconnect-prefetch-6c64e0ecd164&quot;&gt;How&amp;nbsp;to&amp;nbsp;improve&amp;nbsp;web&amp;nbsp;performance&amp;nbsp;By&amp;nbsp;using(Preload,&amp;nbsp;Preconnect,&amp;nbsp;Prefetch)&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Link_prefetching_FAQ&quot;&gt;Link prefetching FAQ&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;b&gt;- Preload&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저에게 페이지에서 필요한 자원을 일찍이 fetch하라는 속성이다.&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;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;- Prefetch&lt;/span&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;&lt;span style=&quot;color: #333333;&quot;&gt;현재 페이지 로딩이 마치고 사용 가능한 대역폭(bandwidth)이 있을 때(다운 받을 여유가 생겼을 때) 가장 낮은 우선순위로 리소스를 가져온다는 뜻.&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: #333333;&quot;&gt;이번에는 dns-prefetch와 preconnect 차례.&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;이 둘은 현재 페이지에서 외부 도메인의 리소스를 참고하는 것을 브라우저에게 알려 미리 외부 도메인과 연결을 설정할 수 있게 하는 것이 목표.&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;- DNS-Prefetch&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 출처의 DNS 조회를 처리해 놓는다.&lt;/p&gt;
&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;- Preconnect&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DNS 조회 뿐만 아니라 TCP 핸드 쉐이킹까지 해결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;preconnect를 사용하면 브라우저가 사이트에 필요한 연결을 미리 예상 할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 브라우저는 필요한 소켓을 미리 설정할 수 있기 때문에 DNS, TCP, TLS 왕복에 필요한 시간을 절약 할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;- Preload&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1585468784141&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;link rel=&quot;preload&quot; as=&quot;script&quot; href=&quot;super-important.js&quot;&amp;gt;
&amp;lt;link rel=&quot;preload&quot; as=&quot;style&quot; href=&quot;critical.css&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;as 속성을 사용하여 리소스의 유형을 알려줘야 한다.&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;브라우저에서 글꼴을 요청이 바로 일어나는 것이 아니라 CSSOM이 생성되고 렌더링 트리를 생성할 때서야 비로소 요청이 발생하기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKoDUn/btqXgpoyOV7/dSRtq794q8IW820MkpMLHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKoDUn/btqXgpoyOV7/dSRtq794q8IW820MkpMLHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKoDUn/btqXgpoyOV7/dSRtq794q8IW820MkpMLHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKoDUn%2FbtqXgpoyOV7%2FdSRtq794q8IW820MkpMLHK%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;1280&quot; height=&quot;484&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;484&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;pre id=&quot;code_1585470886420&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 rel=&quot;preload&quot; as=&quot;font&quot; crossorigin=&quot;crossorigin&quot; type=&quot;font/woff2&quot; href=&quot;myfont.woff2&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 폰트는 다른 호스트에 있는 경우가 대부분이므로 crossorigin을 표시해주는 것이 좋다.&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;span style=&quot;color: #333333;&quot;&gt;- Prefetch&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&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;&lt;span style=&quot;color: #333333;&quot;&gt;받아온 요청이나 자원이 유저의 앞으로도 navigation(예를 들어 다른 뷰나 페이지 사이) 지속되어야 한다면 쓸 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;만약 Page 1이 Page 2에 꼭 필요한 자원을 prefetch하는 요청을 날리는 경우라면, 중요한 자원과 navigation requests는 병행으로 수행될 수 있다. &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;만약에 이 경우에 preload를 사용한다면 즉시 Page A의 unload가 취소될 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1585472008751&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 rel=&quot;prefetch&quot; href=&quot;page-2.html&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 data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- importance(실험적)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;preload와 prefetch시에만 쓸 수 있는 속성이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;auto: 브라우저의 휴리스틱에 의해 우선순위가 자동적으로 결정된다.&lt;/li&gt;
&lt;li&gt;how: 높은 우선순위라는 것을 알려줌&lt;/li&gt;
&lt;li&gt;low: 낮은 우선순위라는 것을 알려줌&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;b&gt;- DNS-Prefetch&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1586364283542&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; 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;link  rel=&quot;dns-prefetch&quot;  href = &quot;//example.com&quot;&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;DNS Prefetch나 Preconnect는 정확한 경로를 알 수 없을 때나 미디어 스트리밍시 유용하다.&lt;/p&gt;
&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;주어진 CDN으로 부터 리소스를 가져와야 한다는 것은 알지만 정확한 경로를 모르는 상황이 발생 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 브라우저 별로 가져와야 하는 라이브러리 등의 버전이 다를 때, CDN 주소는 알지만 정확한 경로는 알지 못하는 상황을 들 수 있다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Preconnect&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1586364336168&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; 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;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;link rel=&quot;preconnect&quot; href=&quot;https://example.com&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;href 속성에 의해 URL을 해석, URL이 유효한 URL인지 아닌지 해석하여 아닐경우 error처리, HTTP/HTTPS인지 판단&lt;/li&gt;
&lt;li&gt;유효할 경우 이 url을 origin으로 판단&lt;/li&gt;
&lt;li&gt;cors에 대한 상태를 대상 엘리먼트의 crossOrigin 속성에 할당&lt;/li&gt;
&lt;li&gt;cors의 속성의 값이 anonymous 이거나 credentials이 false가 아닐경우 연결을 시도&lt;/li&gt;
&lt;li&gt;http의 경우 (DNS+TCP), https의 경우 (DNS+TCP+TLS)를 수행, 이러한 커넥션을 열어두게 되며, 얼마나 많은 연결을 하게 될지는 user agent가 결정&lt;/li&gt;
&lt;/ol&gt;
&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://googlefonts.3perf.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Make your Google Fonts render faster&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;b&gt;주의사항&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Preconnect는 외부 도메인과 연결을 구축하기 때문에 많은 CPU 시간을 차지할 수 있으며 보안 연결의 경우 더 많은 시간을 차지 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Preconnect는 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;2.1.4 스크롤 없이 볼 수 있는 영역 우선&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크롤 없이 볼 수 있는 영역(ATF, Above The Fold)을 먼저 로드하도록 구성해야 한다. [&lt;a href=&quot;https://css-tricks.com/authoring-critical-fold-css/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Authoring Critical Above-the-Fold CSS&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;872&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T7Hxu/btqW8F6zXuF/OD73xQwYwef6Ekk6OWqPC1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T7Hxu/btqW8F6zXuF/OD73xQwYwef6Ekk6OWqPC1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T7Hxu/btqW8F6zXuF/OD73xQwYwef6Ekk6OWqPC1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT7Hxu%2FbtqW8F6zXuF%2FOD73xQwYwef6Ekk6OWqPC1%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;1081&quot; height=&quot;872&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;872&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;스크롤 없이 보이는 부분에 우선순위 부여[from&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://stackoverflow.com/questions/14681058/how-to-make-the-1st-part-of-the-site-loads-first-like-in-google-pagespeed&quot;&gt;stackoverflow&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;a href=&quot;https://varvy.com/pagespeed/prioritize-visible-content.html&quot;&gt;Prioritize&amp;nbsp;visible&amp;nbsp;content&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만들면 ATF의 CSS를 위한 부분과 나머지로 분할할 수도 있다.&lt;/p&gt;
&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&gt;&amp;nbsp;&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;서버의 초기 응답에서 페이지의 중요한 부분을 렌더링하는 데 필요한 데이터를 즉시 보내고 나머지를 지연하도록 페이지를 구성해야한다는 것이다.&lt;/p&gt;
&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: #333333;&quot;&gt;footer영역,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;기타 제3자 위젯(SNS 공유 위젯 등)등은 메인 컨텐츠보다 중요치 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 컨텐츠가 점진적으로 렌더링 되도록 만든다.&lt;/p&gt;
&lt;pre id=&quot;code_1586175246016&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;content&amp;gt;
  &amp;lt;/content&amp;gt;
  &amp;lt;sidebar&amp;gt;
  &amp;lt;/sidebar&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- CSS 분리 및 비동기 로드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 CSS 결정 도구를 사용하면 첫화면에 사용되는 CSS만 따로 뽑아 인라인으로 사용할 수 있다. [&lt;a href=&quot;https://web.dev/extract-critical-css/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Extract&amp;nbsp;critical&amp;nbsp;CSS&lt;/a&gt;, &lt;a href=&quot;https://project-awesome.org/addyosmani/critical-path-css-tools&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Critical-path&amp;nbsp;(Above-the-fold)&amp;nbsp;CSS&amp;nbsp;Tools&lt;/a&gt;, &lt;a href=&quot;https://codeburst.io/how-to-speed-up-the-initial-rendering-of-a-web-page-f07cbfaaf46e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;to&amp;nbsp;speed&amp;nbsp;up&amp;nbsp;the&amp;nbsp;initial&amp;nbsp;rendering&amp;nbsp;of&amp;nbsp;a&amp;nbsp;web&amp;nbsp;page&lt;/a&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;a href=&quot;https://github.com/addyosmani/critical&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Critical&lt;/a&gt; [&lt;a href=&quot;https://github.com/anthonygore/html-critical-webpack-plugin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;webpack plugin&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/filamentgroup/criticalCSS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CriticalCSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pocketjoso/penthouse&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Penthouse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ABVanton200/critical-css-inliner&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;critical-css-inliner&lt;/a&gt;&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;a href=&quot;https://css-tricks.com/the-simplest-way-to-load-css-asynchronously/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Simplest&amp;nbsp;Way&amp;nbsp;to&amp;nbsp;Load&amp;nbsp;CSS&amp;nbsp;Asynchronously&lt;/a&gt;, &lt;a href=&quot;https://www.filamentgroup.com/lab/load-css-simpler/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Simplest&amp;nbsp;Way&amp;nbsp;to&amp;nbsp;Load&amp;nbsp;CSS&amp;nbsp;Asynchronously&lt;/a&gt;, &lt;a href=&quot;https://keithclark.co.uk/articles/loading-css-without-blocking-render/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Loading CSS without blocking render&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1587566555517&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 rel=&quot;stylesheet&quot; href=&quot;/path/to/my.css&quot; media=&quot;none&quot; onload=&quot;if(media!='all')media='all'&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;media를 none으로 설정하면 화면의 렌더링을 막지 않기 때문에 일단 다운로드 후, onload 이벤트가 일어날때까지 미룬후 all로 바꾸어 로딩하자는 일종의 꼼수.&lt;/p&gt;
&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/filamentgroup/loadCSS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;loadCSS&lt;/a&gt;를 사용하면 나머지 CSS를 비동기적으로 로드할 수 있다.[&lt;a href=&quot;https://css-tricks.com/authoring-critical-fold-css/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Authoring&amp;nbsp;Critical&amp;nbsp;Above-the-Fold&amp;nbsp;CSS&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는 다음처럼 하여 첫 번째 페인트 후 로드되도록 하는 것이 가능. (역시 렌더링을 차단하지 않는다) [차이: &lt;a href=&quot;https://github.com/filamentgroup/loadCSS/issues/244&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Google deferred CSS vs loadCSS&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1586194719971&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;style&amp;gt;
      .blue{color:blue;}
    &amp;lt;/style&amp;gt;
    &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;blue&quot;&amp;gt;
      Hello, world!
    &amp;lt;/div&amp;gt;
    &amp;lt;noscript id=&quot;deferred-styles&quot;&amp;gt;
      &amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;small.css&quot;/&amp;gt;
    &amp;lt;/noscript&amp;gt;
    &amp;lt;script&amp;gt;
      var loadDeferredStyles = function() {
        var addStylesNode = document.getElementById(&quot;deferred-styles&quot;);
        var replacement = document.createElement(&quot;div&quot;);
        replacement.innerHTML = addStylesNode.textContent;
        document.body.appendChild(replacement)
        addStylesNode.parentElement.removeChild(addStylesNode);
      };
      var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
          window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
      if (raf) raf(function() { window.setTimeout(loadDeferredStyles, 0); });
      else window.addEventListener('load', loadDeferredStyles);
    &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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://github.com/GoogleChromeLabs/critters&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Critters&lt;/a&gt;&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;나중에는 웹컴포넌트의&amp;nbsp;&lt;a href=&quot;http://w3c.github.io/webcomponents/spec/imports/#link-type-import&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTML Import&lt;/a&gt;를 사용할 수 있다면, 렌더링을 차단하지 않고도 CSS를 로드할 수도?? [&lt;a href=&quot;https://www.html5rocks.com/ko/tutorials/webcomponents/imports/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTML Rocks: HTML Import&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML Import가 표준으로 안들어 갈 것 같은 분위기가 문제일것 같긴 하다만.&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;2.1.5 사이트 빌더&lt;/h4&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;span&gt;&amp;nbsp;&lt;/span&gt;Conent&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트로 클라이언트 렌더링을 하는 것보다 HTML과 CSS를 생성 시킨채 배포한다면 동적인 작업이 줄어들고 봇이 해석하기 편하므로 성능/SEO에 모두 유리하다. [&lt;a href=&quot;https://dev.to/this-is-learning/is-0kb-of-javascript-in-your-future-48og&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Is&amp;nbsp;0kb&amp;nbsp;of&amp;nbsp;JavaScript&amp;nbsp;in&amp;nbsp;your&amp;nbsp;Future?&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;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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Astro&lt;/a&gt;: React, Preact, Vue, Svelte, Solid등 가능, Partical hydration 지원&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://elderguide.com/tech/elderjs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Elder.js&lt;/a&gt;: Svelte용, Partical hydration 지원, 사용자 지정 라우팅&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby&lt;/a&gt;: React용, 정적 사이트 생성(SSG, Static Site Generation), 지연된 정적생성(DSG, Deferred Static Generation), 서버 사이드 렌더링(SSR, Server Side Rendering) 처럼 다양한 &lt;a href=&quot;https://v4.gatsbyjs.com/docs/conceptual/rendering-options/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;렌더링 옵션&lt;/a&gt; 제공&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Eleventy&lt;/a&gt;: 정적 사이트 생성기로, 마크다운, &lt;a href=&quot;https://www.11ty.dev/docs/languages/javascript/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;11ty.js&lt;/a&gt;, &lt;a href=&quot;https://liquidjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Liquid&lt;/a&gt;(&lt;a href=&quot;https://shopify.github.io/liquid/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;또 다른 문서&lt;/a&gt;), &lt;a href=&quot;https://mozilla.github.io/nunjucks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nunjucks&lt;/a&gt;, &lt;a href=&quot;https://handlebarsjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Handlebars&lt;/a&gt;, &lt;a href=&quot;https://ejs.co/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;EJS&lt;/a&gt;, &lt;a href=&quot;https://pugjs.org/api/getting-started.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pug&lt;/a&gt;와 같은 HTML 템플릿 지원. JS 사용을 최대한 피하도록 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기타 차이점은 &lt;a href=&quot;https://docs.astro.build/comparing-astro-vs-other-tools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Astro vs X&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;a href=&quot;https://github.com/stereobooster/react-snap&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-snap&lt;/a&gt;같은 프리렌더러, &lt;a href=&quot;https://github.com/react-static/react-static&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react static&lt;/a&gt;같이 SSG에 최적화된 프레임워크도 살펴볼만하다.&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;2.1.6 Lazy load&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Conent, Image&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;느긋하게(Lazy) 로딩을 하면 시간을 아낄 수 있다. [&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이미지 및 동영상의 지연 로딩&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lazy loading,&lt;/a&gt; &lt;a href=&quot;https://imagekit.io/blog/lazy-loading-images-complete-guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lazy&amp;nbsp;Loading&amp;nbsp;Images&amp;nbsp;&amp;ndash;&amp;nbsp;The&amp;nbsp;Complete&amp;nbsp;Guide&lt;/a&gt;, &lt;a href=&quot;https://frontdev.tistory.com/entry/Image-Lazy-Loading-%EA%B8%B0%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image&amp;nbsp;Lazy&amp;nbsp;Loading&amp;nbsp;기법&amp;nbsp;그리고&amp;nbsp;Google&amp;nbsp;I/O&amp;nbsp;에서의&amp;nbsp;새로운&amp;nbsp;방법&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lazy&amp;nbsp;Loading&amp;nbsp;이란?&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;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;li&gt;JS로 대형 이미지를 로딩시 잠시 반응하지 않을 수 있음&lt;/li&gt;
&lt;li&gt;로드가 실패할 수 있음&lt;/li&gt;
&lt;li&gt;JS를 사용하지 못할 수도 있음&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&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-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Intersection Observer&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;IntersectionObserver&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;를 사용하면 간단하게 lazy 로드를 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1586897926055&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;img class=&quot;lazy&quot; src=&quot;placeholder-image.jpg&quot; data-src=&quot;image-to-lazy-load-1x.jpg&quot; data-srcset=&quot;image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x&quot; alt=&quot;저는 이미지입니다!&quot;&amp;gt;&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;lazy란 클래스 속성으로 선택할 요소 지정&lt;/li&gt;
&lt;li&gt;src에는 자리 표시자 이미지&lt;/li&gt;
&lt;li&gt;data-src와 data-srcset으로 로드할 이미지의 URL을 담음&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;이때 Intersection Observer를 사용하면&lt;/p&gt;
&lt;pre id=&quot;code_1586898072077&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.addEventListener(&quot;DOMContentLoaded&quot;, function() {
  var lazyImages = [].slice.call(document.querySelectorAll(&quot;img.lazy&quot;));

  if (&quot;IntersectionObserver&quot; in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove(&quot;lazy&quot;);
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to a more compatible method here
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOMContentLoaded 시, lazy 클래스의 모든 이미지에 대한 DOM을 조회해 lazy load 대상 이미지 영역에 진입시 콜백을 실행하는 옵저버를 생성한다.&lt;/p&gt;
&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event&quot;&gt;scroll&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이벤트,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event&quot;&gt;resize&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이벤트를 받아서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect&quot;&gt;getBoundingClientRect()&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;같은 DOM API를 사용해도&amp;nbsp;&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;/p&gt;
&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_1586898296704&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.addEventListener(&quot;DOMContentLoaded&quot;, function() {
  let lazyImages = [].slice.call(document.querySelectorAll(&quot;img.lazy&quot;));
  let active = false;

  const lazyLoad = function() {
    if (active === false) {
      active = true;

      setTimeout(function() {
        lazyImages.forEach(function(lazyImage) {
          if ((lazyImage.getBoundingClientRect().top &amp;lt;= window.innerHeight &amp;amp;&amp;amp; lazyImage.getBoundingClientRect().bottom &amp;gt;= 0) &amp;amp;&amp;amp; getComputedStyle(lazyImage).display !== &quot;none&quot;) {
            lazyImage.src = lazyImage.dataset.src;
            lazyImage.srcset = lazyImage.dataset.srcset;
            lazyImage.classList.remove(&quot;lazy&quot;);

            lazyImages = lazyImages.filter(function(image) {
              return image !== lazyImage;
            });

            if (lazyImages.length === 0) {
              document.removeEventListener(&quot;scroll&quot;, lazyLoad);
              window.removeEventListener(&quot;resize&quot;, lazyLoad);
              window.removeEventListener(&quot;orientationchange&quot;, lazyLoad);
            }
          }
        });

        active = false;
      }, 200);
    }
  };

  document.addEventListener(&quot;scroll&quot;, lazyLoad);
  window.addEventListener(&quot;resize&quot;, lazyLoad);
  window.addEventListener(&quot;orientationchange&quot;, lazyLoad);
});&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;- Loading 속성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading&quot;&gt;&amp;lt;img&amp;gt;&lt;/a&gt;나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-loading&quot;&gt;&amp;lt;iframe&amp;gt;&lt;/a&gt;같은 경우 loading 속성을 이용해 사용이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1586890891058&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;img src=&quot;image.jpg&quot; loading=&quot;lazy&quot; alt=&quot;...&quot; /&amp;gt;
&amp;lt;iframe src=&quot;video-player.html&quot; loading=&quot;lazy&quot;&amp;gt;&amp;lt;/iframe&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;- 비디오 Lazy Load&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지처럼 동영상도 Lazy Load 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Element/Video&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lt;video&amp;gt;&lt;/a&gt;로 사용하지만, 제한적으로는 &lt;a href=&quot;https://calendar.perfplanet.com/2017/animated-gif-without-the-gif/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lt;img&amp;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;b&gt;자동 재생하지 않는 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동 재생(Autoplay)을 하지 않는 경우 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Element/Video#attr-preload&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;preload&lt;/a&gt;를 할 필요가 없다.&lt;/p&gt;
&lt;pre id=&quot;code_1586899457593&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;video controls preload=&quot;none&quot; poster=&quot;one-does-not-simply-placeholder.jpg&quot;&amp;gt;
  &amp;lt;source src=&quot;one-does-not-simply.webm&quot; type=&quot;video/webm&quot;&amp;gt;
  &amp;lt;source src=&quot;one-does-not-simply.mp4&quot; type=&quot;video/mp4&quot;&amp;gt;
&amp;lt;/video&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;a href=&quot;https://developers.google.com/web/fundamentals/media/fast-playback-with-video-preload&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fast Playback with Video Preload&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;b&gt;GIF&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GIF는 자동 재생이 되어야 한다는 것이 가장 큰 차이다.&lt;/p&gt;
&lt;pre id=&quot;code_1586900108654&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;video autoplay muted loop playsinline class=&quot;lazy&quot; width=&quot;610&quot; height=&quot;254&quot; poster=&quot;one-does-not-simply.jpg&quot;&amp;gt;
  &amp;lt;source data-src=&quot;one-does-not-simply.webm&quot; type=&quot;video/webm&quot;&amp;gt;
  &amp;lt;source data-src=&quot;one-does-not-simply.mp4&quot; type=&quot;video/mp4&quot;&amp;gt;
&amp;lt;/video&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;역시 data-src를 src로 바꿔주면 끝.&lt;/p&gt;
&lt;pre id=&quot;code_1586900216186&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.addEventListener(&quot;DOMContentLoaded&quot;, function() {
  var lazyVideos = [].slice.call(document.querySelectorAll(&quot;video.lazy&quot;));

  if (&quot;IntersectionObserver&quot; in window) {
    var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(video) {
        if (video.isIntersecting) {
          for (var source in video.target.children) {
            var videoSource = video.target.children[source];
            if (typeof videoSource.tagName === &quot;string&quot; &amp;amp;&amp;amp; videoSource.tagName === &quot;SOURCE&quot;) {
              videoSource.src = videoSource.dataset.src;
            }
          }

          video.target.load();
          video.target.classList.remove(&quot;lazy&quot;);
          lazyVideoObserver.unobserve(video.target);
        }
      });
    });

    lazyVideos.forEach(function(lazyVideo) {
      lazyVideoObserver.observe(lazyVideo);
    });
  }
});
&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;- 주의사항&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;메뉴나 헤더등에는 적용하지 말고, 메인 컨텐츠에서도 처음나오는 3~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;스크롤을 내려야 로드 시작&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;pre id=&quot;code_1586902857047&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // Lazy loading image code goes here
}, {
  rootMargin: &quot;0px 0px 256px 0px&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;&lt;b&gt;자리 표시자&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명할 수 있는 옵션이 많아 렌더링의 UX 파트에서 따로 다루도록 한다.&lt;/p&gt;
&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;JS로 대형 이미지 로드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;곧 나올 Streams를 이용해 청크 단위로 다운을 받거나 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image()&lt;/a&gt;를 이용한다. [&lt;a href=&quot;https://medium.com/dailyjs/image-loading-with-image-decode-b03652e7d2d2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image&amp;nbsp;loading&amp;nbsp;with&amp;nbsp;image.decode()&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1586903177014&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const newImage = new Image();
newImage.src = &quot;my-awesome-image.jpg&quot;;

if (&quot;decode&quot; in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, Lazy 로드 알고리즘을 복잡하게 만들수도 있다.&lt;/p&gt;
&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;pre id=&quot;code_1586903377069&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const newImage = new Image();
newImage.src = &quot;my-awesome-image.jpg&quot;;

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};&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;JS 미사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;noscript&amp;gt;로 JS를 사용못할 때를 대비할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1586903580557&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- An image that eventually gets lazy loaded by JavaScript --&amp;gt;
&amp;lt;img class=&quot;lazy&quot; src=&quot;placeholder-image.jpg&quot; data-src=&quot;image-to-lazy-load.jpg&quot; alt=&quot;저는 이미지입니다!&quot;&amp;gt;
&amp;lt;!-- An image that is shown if JavaScript is turned off --&amp;gt;
&amp;lt;noscript&amp;gt;
  &amp;lt;img src=&quot;image-to-lazy-load.jpg&quot; alt=&quot;저는 이미지입니다!&quot;&amp;gt;
&amp;lt;/noscript&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;a href=&quot;https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video#%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8_%EA%B0%80%EC%9A%A9%EC%84%B1&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;b&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;&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video#%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC_%EC%A7%80%EC%97%B0_%EB%A1%9C%EB%94%A9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lazysizes&lt;/a&gt;: 이미지와 iframe을 lazy load하는 라이브러리로 다양한 기능을 가지고 있다. 여러가지 &lt;a href=&quot;https://github.com/aFarkas/lazysizes#available-plugins-in-this-repo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;확장&lt;/a&gt;이 있다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ApoorvSaxena/lozad.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lozad.js&lt;/a&gt;: Intersection Observer를 이용하는 경량 라이브러리&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/malchata/yall.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;yall.js&lt;/a&gt;: &lt;span style=&quot;color: #333333;&quot;&gt;Intersection Observer를 이용하는 경량 라이브러리2&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://github.com/dinbror/blazy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;blazy&lt;/a&gt;: IE7+를 지원하는 가벼운 라이브러리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jasonslyvia/react-lazyload&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-lazyload&lt;/a&gt;: 리엑트 개발자에게 익숙한 방식을 제공&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기타 이미지 로딩 최적화는&amp;nbsp;&lt;a href=&quot;https://www.smashingmagazine.com/2021/04/humble-img-element-core-web-vitals/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Humble&amp;nbsp;&amp;lt;img&amp;gt;&amp;nbsp;Element&amp;nbsp;And&amp;nbsp;Core&amp;nbsp;Web&amp;nbsp;Vitals&lt;/a&gt;에서 잘 설명하고 있다. (&lt;a href=&quot;https://twitter.com/addyosmani/status/1388031656355794945&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;트윗&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-filename=&quot;image-optimize.jpg&quot; data-origin-width=&quot;3600&quot; data-origin-height=&quot;2025&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NL2xv/btq3XcwtZ2j/iZrbCKEC7bAT8ynEdMWQeK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NL2xv/btq3XcwtZ2j/iZrbCKEC7bAT8ynEdMWQeK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NL2xv/btq3XcwtZ2j/iZrbCKEC7bAT8ynEdMWQeK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNL2xv%2Fbtq3XcwtZ2j%2FiZrbCKEC7bAT8ynEdMWQeK%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;3600&quot; height=&quot;2025&quot; data-filename=&quot;image-optimize.jpg&quot; data-origin-width=&quot;3600&quot; data-origin-height=&quot;2025&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;2.1.7 버퍼를 일찍 비우기(Flush)&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Server&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 페이지를 요청하면 백엔드 서버가 HTML 페이지를 함께 연결하는 데 200 ~ 500ms가 소요될 수 있다.&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://www.php.net/flush&quot;&gt;flush() &lt;/a&gt;함수(PHP 기준)다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부분적으로&amp;nbsp;준비된&amp;nbsp;HTML&amp;nbsp;응답을&amp;nbsp;브라우저로&amp;nbsp;보내는것을&amp;nbsp;허용함으로써&amp;nbsp;백엔드가&amp;nbsp;나머지&amp;nbsp;HTML&amp;nbsp;페이지로&amp;nbsp;바쁠때&amp;nbsp;브라우저는&amp;nbsp;구성요소를&amp;nbsp;가져오는&amp;nbsp;것(fetching)을&amp;nbsp;시작할&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bT3leV/btqWX4TDICc/WPWoNM9xDJaX3g0iuZHtZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bT3leV/btqWX4TDICc/WPWoNM9xDJaX3g0iuZHtZ1/img.png&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;249&quot; style=&quot;width: 50.8636%; margin-right: 10px;&quot; data-widthpercent=&quot;51.46&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bT3leV/btqWX4TDICc/WPWoNM9xDJaX3g0iuZHtZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbT3leV%2FbtqWX4TDICc%2FWPWoNM9xDJaX3g0iuZHtZ1%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;703&quot; height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebIcGB/btqWXa7ES6l/UKXx2IUwlhbC4JEjhuU8uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebIcGB/btqWXa7ES6l/UKXx2IUwlhbC4JEjhuU8uK/img.png&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;264&quot; style=&quot;width: 47.9736%;&quot; data-widthpercent=&quot;48.54&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebIcGB/btqWXa7ES6l/UKXx2IUwlhbC4JEjhuU8uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebIcGB%2FbtqWXa7ES6l%2FUKXx2IUwlhbC4JEjhuU8uK%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;703&quot; height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Flushing&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;head에 대한 HTML은 일반적으로 생성하기 쉬우며 백엔드가 동작하는 동안 브라우저가 CSS나 JavaScript 파일들을 병렬적으로 가져오도록 포함 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;따라서 &amp;lt;/head&amp;gt; 바로 다음이 플러시를 고려하기 좋은 위치이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;PHP, ASP, JSP와 같은 템플릿 엔진들은 다음처럼 플러싱을 할 수 있다. [&lt;a href=&quot;https://www.stevesouders.com/blog/2013/01/31/http-archive-adding-flush/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP&amp;nbsp;Archive:&amp;nbsp;adding&amp;nbsp;flush&lt;/a&gt;, &lt;a href=&quot;https://www.phpied.com/progressive-rendering-via-multiple-flushes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Progressive&amp;nbsp;rendering&amp;nbsp;via&amp;nbsp;multiple&amp;nbsp;flushes&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://www.willhastings.me/posts/speeding-up-page-load-with-early-flush/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Speeding Up Page Load with Early Flush&lt;/a&gt;, &lt;a href=&quot;https://tech.ebayinc.com/engineering/async-fragments-rediscovering-progressive-html-rendering-with-marko/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Async&amp;nbsp;Fragments:&amp;nbsp;Rediscovering&amp;nbsp;Progressive&amp;nbsp;HTML&amp;nbsp;Rendering&amp;nbsp;with&amp;nbsp;Marko&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1585031015358&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; ... &amp;lt;!-- css, js --&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;?php flush(); ?&amp;gt;         &amp;lt;!-- PHP --&amp;gt;
&amp;lt;% Response.Flush(); %&amp;gt;   &amp;lt;!-- ASP.NET --&amp;gt;
&amp;lt;% out.flush() %&amp;gt;         &amp;lt;!-- JSP --&amp;gt;
&amp;lt;body&amp;gt;
... &amp;lt;!-- content --&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;파이썬 Flask의 경우 &lt;a href=&quot;https://stackoverflow.com/questions/27160551/how-to-flush-head-early-with-flask-python-jinja&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;a href=&quot;https://github.com/marko-js/marko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Marko&lt;/a&gt;라는 템플릿 엔진은 플러싱의 이점을 극대화 하여 비동기 프레그먼트를 비순차적으로 플러싱 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJ8CGf/btqWXbrZKNY/veQPVuCkJ42X46XSQnGsr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJ8CGf/btqWXbrZKNY/veQPVuCkJ42X46XSQnGsr0/img.png&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;500&quot; style=&quot;width: 30.5078%; margin-right: 10px;&quot; data-widthpercent=&quot;30.87&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJ8CGf/btqWXbrZKNY/veQPVuCkJ42X46XSQnGsr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJ8CGf%2FbtqWXbrZKNY%2FveQPVuCkJ42X46XSQnGsr0%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;599&quot; height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCTLdb/btqXoaRSW0f/eNKVMr6bc2suDyXOah1bc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCTLdb/btqXoaRSW0f/eNKVMr6bc2suDyXOah1bc0/img.png&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;262&quot; style=&quot;width: 68.3294%;&quot; data-widthpercent=&quot;69.13&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCTLdb/btqXoaRSW0f/eNKVMr6bc2suDyXOah1bc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCTLdb%2FbtqXoaRSW0f%2FeNKVMr6bc2suDyXOah1bc0%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;703&quot; height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Out-of-order flushing of Async Fragments&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Async Fragment는 리엑트의 &lt;a href=&quot;https://ko.reactjs.org/docs/code-splitting.html#reactlazy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React.lazy&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;페이스북의 빅파이프(BigPipe)로 유명하다. [&lt;a href=&quot;https://engineering.fb.com/2010/06/04/web/bigpipe-pipelining-web-pages-for-high-performance/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BigPipe: Pipelining web pages for high performance&lt;/a&gt;(&lt;a href=&quot;https://myondal.tistory.com/43&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;번역&lt;/a&gt;), &lt;a href=&quot;https://medium.com/@arpingajjar/faster-web-page-loading-with-facebook-bigpipe-fbbc49b28959&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Faster&amp;nbsp;Web&amp;nbsp;Page&amp;nbsp;Loading&amp;nbsp;with&amp;nbsp;Facebook&amp;nbsp;BigPipe&lt;/a&gt;, &lt;a href=&quot;https://stackoverflow.com/questions/9106651/facebook-bigpipe-technique-algorithm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Facebook&amp;nbsp;Bigpipe&amp;nbsp;Technique&amp;nbsp;Algorithm&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLY1dK/btrpu6obMCY/oChMrrFWlYM5gbtFtUFKT1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLY1dK/btrpu6obMCY/oChMrrFWlYM5gbtFtUFKT1/img.webp&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;571&quot; style=&quot;width: 40.6467%; margin-right: 10px;&quot; data-widthpercent=&quot;41.12&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLY1dK/btrpu6obMCY/oChMrrFWlYM5gbtFtUFKT1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLY1dK%2Fbtrpu6obMCY%2FoChMrrFWlYM5gbtFtUFKT1%2Fimg.webp&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;720&quot; height=&quot;571&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvRQTY/btrpu2Twsbu/yyZv1p5GFCLdUJEsDnuqC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvRQTY/btrpu2Twsbu/yyZv1p5GFCLdUJEsDnuqC1/img.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;385&quot; style=&quot;width: 58.1906%;&quot; data-widthpercent=&quot;58.88&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvRQTY/btrpu2Twsbu/yyZv1p5GFCLdUJEsDnuqC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvRQTY%2Fbtrpu2Twsbu%2FyyZv1p5GFCLdUJEsDnuqC1%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;695&quot; height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://github.com/shay-te/bigpipe-response&quot;&gt;https://github.com/shay-te/bigpipe-response&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bigpipe/bigpipe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/bigpipe/bigpipe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/garo/bigpipe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/garo/bigpipe&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹소켓을 이용해 파이프라이닝을 해보려는 시도도 있다. [&lt;a href=&quot;https://jacsm.ro/view/?pid=14_3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SPADOCK:&amp;nbsp;Adaptive&amp;nbsp;Pipeline&amp;nbsp;Technology&amp;nbsp;for&amp;nbsp;Web&amp;nbsp;System&amp;nbsp;using&amp;nbsp;WebSocket&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;a href=&quot;https://github.com/youtube/spfjs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SPF(Structured Page Fragments)&lt;/a&gt;와 세분화된 Lazy loading을 제공하는 &lt;a href=&quot;https://github.com/BuilderIO/qwik&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Qwik&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;2.2 제한&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2.1 유효성&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Content, CSS&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;다음 성능과 관계된 몇가지 예시이다.&lt;/p&gt;
&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;HTML의 frame, img, li, p등을 닫힌태그(&amp;lt;/태그&amp;gt;)&amp;nbsp; 없이 암시적으로 사용해도 페이지는 잘 렌더링 된다.[&lt;a href=&quot;https://web.archive.org/web/20081011192845/http://msdn2.microsoft.com/en-us/library/ms533020.aspx#Close_Your_Tags&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Building High Performance HTML Pages&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1586034682438&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p&amp;gt;The following is a list of ingredients.
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;flour
&amp;lt;li&amp;gt;sugar
&amp;lt;li&amp;gt;butter
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; 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;b&gt;- 크기 지정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지의 width와 height 속성을 생략시 크기를 정확히 모르기 때문에 Placeholder를 할당하고, 리플로우시 레이아웃이 업데이트 되어야 하기 때문에 성능에 영향을 미친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블도 역시 width와 height 속성을 생략하면 리플로시 업데이트가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한&lt;/p&gt;
&lt;pre id=&quot;code_1586367520359&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  table-layout: fixed;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 사용하고, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/col&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lt;col&amp;gt;&lt;/a&gt;과 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/colgroup&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lt;colgroup&amp;gt;&lt;/a&gt;에 width를 지정하는 것이 좋다.&lt;/p&gt;
&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;- 빈문자열 src 이미지&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈&amp;nbsp;문자열&amp;nbsp;src&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;br /&gt;&lt;br /&gt;1. straight HTML&lt;/p&gt;
&lt;pre id=&quot;code_1586367877342&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;img src=&quot;&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. JavaScript&lt;/p&gt;
&lt;pre id=&quot;code_1586367877343&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var img = new Image();
img.src = &quot;&quot;;&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;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특히 하루에 수백만 페이지를 보는 페이지에 대해 대량의 예기치 않은 트래픽을 보내 서버를 손상시킨다.&lt;/li&gt;
&lt;li&gt;서버는 절대 보여지지 않을 페이지를 생성하는 사이클(cycles)을 컴퓨팅 하는 것으로 낭비된다.&lt;/li&gt;
&lt;li&gt;사용자 데이터는 오류가 생길 가능성이 있다.&lt;br /&gt;만약 요청이 추적상태에 있다면, 쿠키 또는 다른 방식으로 데이터를 파괴할 가능성이 있다.&lt;br /&gt;비록 이미지 요청이 이미지를 반환하지 않더라도, 모든 쿠키들을 포함하는 브라우저에 의해 모든 header들은 읽고 수락될 수 있다. 응답의 나머지가 버려지는 동안, 이미 손상 되었을지도 모른다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 작동의 근본 원인은 URI 해상도가 browser에서 실행되는 방식 때문이다.&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://tools.ietf.org/html/rfc3986&quot;&gt;RFC 3986- Uniform Resource Identifiers&lt;/a&gt;에 정의되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 문자열이 URI로 발생되면, 그것은 상대적인 URI로 간주되며,&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc3986#section-5.2&quot;&gt;5.2&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&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://tools.ietf.org/html/rfc3986#section-5.4&quot;&gt;5.4&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;섹션에 등록된 빈 문자열이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Internet Explorer가 부정확하게 실행되는 동안, 명백히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc2396&quot;&gt;RFC 2396 - Uniform Resource Identifiers&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사양(이것은 RFC 3986에 의해 더 이상 사용되지 않음)의 초기버전과 일맥상통하는 Firefox, Safari, 그리고 Chrome 섹션은 모두 사양마다 정확하게 빈 문자열을 해결할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 기술적으로, browsers는 상대적 URIs를 해결하기 위한 것들을 수행 중이다.&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;HTML&amp;nbsp;5는&amp;nbsp;섹션&amp;nbsp;4.8.2에서&amp;nbsp;추가요청을&amp;nbsp;하지&amp;nbsp;않는&amp;nbsp;browsers를&amp;nbsp;지시하기&amp;nbsp;위해&amp;nbsp;태그의&amp;nbsp;src&amp;nbsp;속성의&amp;nbsp;설명을&amp;nbsp;추가한다:&lt;br /&gt;src&amp;nbsp;속성은&amp;nbsp;반드시&amp;nbsp;존재해야&amp;nbsp;하고,&amp;nbsp;페이지&amp;nbsp;및&amp;nbsp;script되지&amp;nbsp;않으며&amp;nbsp;쌍방향이&amp;nbsp;아니고(non-interactive),&amp;nbsp;선택적으로&amp;nbsp;애니메이션(optionally&amp;nbsp;animated)된&amp;nbsp;이미지&amp;nbsp;자원(image&amp;nbsp;resource)을&amp;nbsp;참조하는&amp;nbsp;유효한&amp;nbsp;URL을&amp;nbsp;반드시&amp;nbsp;포함해야&amp;nbsp;한다.&amp;nbsp;만약&amp;nbsp;요소(element)의&amp;nbsp;기본&amp;nbsp;URI가&amp;nbsp;문서의&amp;nbsp;주소와&amp;nbsp;동일한&amp;nbsp;경우,&amp;nbsp;src&amp;nbsp;속성값은&amp;nbsp;빈&amp;nbsp;문자열이어서는&amp;nbsp;안&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;script src=&quot;&quot;&amp;gt; 및 &amp;lt;link herf=&quot;&quot;&amp;gt;에는 해당 조항이 없으니&amp;nbsp;브라우저가 실수로 이 동작을 구현하지 않도록 조정해야 할 때가 있다.&lt;br /&gt;&lt;br /&gt;이 규칙은 Yahoo!의 JavaScript 전문가 인 Nicolas C. Zakas에서 영감을 받았으며 자세한 내용은 &quot;&lt;a href=&quot;http://www.nczonline.net/blog/2009/11/30/empty-image-src-can-destroy-your-site/&quot;&gt;Empty&amp;nbsp;image&amp;nbsp;src&amp;nbsp;can&amp;nbsp;destroy&amp;nbsp;your&amp;nbsp;site&lt;/a&gt; &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;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;a href=&quot;https://html.spec.whatwg.org/multipage/parsing.html#an-introduction-to-error-handling-and-strange-cases-in-the-parser&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;An&amp;nbsp;introduction&amp;nbsp;to&amp;nbsp;error&amp;nbsp;handling&amp;nbsp;and&amp;nbsp;strange&amp;nbsp;cases&amp;nbsp;in&amp;nbsp;the&amp;nbsp;parser&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&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;&lt;a href=&quot;https://validator.w3.org/unicorn/?ucn_lang=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;W3C 통합 검사기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://validator.w3.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;W3C Markup Validation Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jigsaw.w3.org/css-validator/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;W3C CSS Validation Service&lt;/a&gt;&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;src=&quot;&quot; 를 가진 img 갯수는 중복 스크립트를 찾을 때의 코드를 조금만 수정하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1586367900509&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const imgs = document.getElementsByTagName(&quot;img&quot;);
[...imgs].map(img =&amp;gt; img.src)
  .filter(src =&amp;gt; src === &quot;&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2.2 @import보다 &amp;lt;link&amp;gt; 사용&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; CSS&lt;br /&gt;이전 모범 사례 중 하나는 점진적 렌더링을 허용하기 위해 CSS가 최상위에 있어야 한다는 것이 있었다.&lt;/p&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를 사용하면 CSS를 병렬로 다운로드할 수 없으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IE에서는 페이지 하단에서 @import사용하는 것과 동일하게 작동 하므로 사용하지 않는 것이 가장 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;이러한 @import보다&lt;/p&gt;
&lt;pre id=&quot;code_1585033837302&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* at CSS file */
@import url(&quot;EXAMPLE.css&quot;)&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;lt;link&amp;gt;를 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1585033902631&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- at HTML file --&amp;gt;
&amp;lt;link href=&quot;EXAMPLE.css&quot; rel=&quot;stylesheet&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2.3 미디어 쿼리 사용하기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 조건에서만 필요한 CSS가 있을 때 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미디어 쿼리 구분은 미디어 유형(media-type), 미디어 특성(media-feature-rule), 논리연산자로 이루어져 있다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;all: 모든, 기본값&lt;/li&gt;
&lt;li&gt;print: &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/Paged_Media&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;인쇄&lt;/a&gt; 결과물이나 미리보기시 사용&lt;/li&gt;
&lt;li&gt;screen: 화면&lt;/li&gt;
&lt;li&gt;speech: 음성 합성장치&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;b&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;width/height: 뷰포트 너비/높이&lt;/li&gt;
&lt;li&gt;aspect-ratio: 뷰포트 가로세로비&amp;nbsp;&lt;/li&gt;
&lt;li&gt;orientation: 뷰포트 방향&lt;/li&gt;
&lt;li&gt;resolution: 출력장치의 해상도&lt;/li&gt;
&lt;li&gt;scan: 출력장치의 스캔 방법(초당 60회, 30회 등)&lt;/li&gt;
&lt;li&gt;color: 출력장치의 색상 채널별 비트 수, 흑백은 0&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;,: 논리합, 흔히 생각하는 or과 같다.&lt;/li&gt;
&lt;li&gt;and: 논리곱&lt;/li&gt;
&lt;li&gt;not: 부정, 개별의 쿼리가 아니라 전체에만 적용된다.&lt;/li&gt;
&lt;li&gt;only: 미디어 쿼리를 미지원하는 낡은 브라우저에 대응하여 특정 스타일 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;미디어 쿼리를 사용하는 방법은 CSS 내부와 외부 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;pre id=&quot;code_1586011407673&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* 형식 */
@media 미디어타입 논리연산자 (미디어특성) { ... }

/* 샘플 */
@meida all { ... }
@media print { ... }
@media (orientation: portrait) { ... }
@media (min-width: 30em) and (max-width: 50em) { ... }&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;외부&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1586010252409&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- 형식 --&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;EXAMPLE.css&quot; media=&quot;미디어타입 논리연산자 (미디어특성)&quot;/&amp;gt;

&amp;lt;!-- 샘플 --&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;style.css&quot;/&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;print.css&quot; media=&quot;print&quot; /&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;portrait.css&quot; media=&quot;orientation:portrait&quot; /&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;min_max.css&quot; media=&quot;(min-width: 30em) and (max-width: 50em)&quot; /&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;/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;link&amp;gt;의 미디어 쿼리의 조건이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://scottjehl.github.io/CSS-Download-Tests/&quot;&gt;거짓일지라도 CSS는 다운&lt;/a&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 CSS 파일은 병합하고, CSS 코드 내부에서 분기하는 것이 좋다.&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;2.2.4 리다이렉션 방지&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;리디렉션(재전송)&lt;/a&gt;은 301이나 302 상태 코드를 사용하여 수행한다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 301 응답의 HTTP 헤더 예이다.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077044&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      HTTP/1.1 301 Moved Permanently
      Location: https://example.com/newuri
      Content-Type: text/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;브라우저가 자동으로 사용자를 Location 필드에 지정된 URL로 이동시킨다 .&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;Expires또는 Cache-Control&lt;/span&gt;과 같은 추가 헤더를 제외하고 &lt;span style=&quot;color: #333333;&quot;&gt;301도 302 응답 &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_1585037833467&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;meta http-equiv=&quot;Refresh&quot; content=&quot;0; URL=https://example.com/newuri/&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1585037877418&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;window.location = &quot;https://example.com/newuri/&quot;;&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; 뒤로가기 버튼이 올바르게 작동하도록 표준 3xx HTTP 상태 코드를 사용하는 것이 좋다.&lt;br /&gt;&lt;br /&gt;기억해야 할 것은 리다이렉션이 사용자 경험을 느리게 한다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자와 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;문제는 낭비적인 리다이렉션이 자주 일어나지만 일반적인 개발자는 인식하지 못하는 경우다.&lt;br /&gt;예를들어 URL에서 &lt;a href=&quot;https://djkeh.github.io/articles/Why-do-we-put-slash-at-the-end-of-URL-kor/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;trailing slash&lt;/a&gt; (/)가 누락 된 경우 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;/span&gt;쉽게 설명하면 &lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;http://example.com&quot;&gt;http://example.com&lt;/a&gt;&lt;/span&gt;의 요청시 &lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;http://example.com/&quot;&gt;http://example.com/&lt;/a&gt; (&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;trailing slash 포함)의&lt;/span&gt; 리디렉션을 포함하는 301 응답 결과가 전송된다.&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 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 style=&quot;font-size: 1.12em;&quot; 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;- trailing slash&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이것은 Alias, mod_rewrite, DirectorySlash 지시어를 사용함으로써 Apache에서 해결된다.&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;Redirects&amp;nbsp;사용에&amp;nbsp;대한&amp;nbsp;다른&amp;nbsp;대안은&amp;nbsp;두&amp;nbsp;code&amp;nbsp;경로가&amp;nbsp;같은&amp;nbsp;서버에&amp;nbsp;host되는&amp;nbsp;경우,&amp;nbsp;Alias와&amp;nbsp;mod-rewrite를&amp;nbsp;사용하는&amp;nbsp;것이다.&amp;nbsp;도메인&amp;nbsp;이름변경을&amp;nbsp;위해&amp;nbsp;redirects를&amp;nbsp;사용한다면&amp;nbsp;Alias&amp;nbsp;또는&amp;nbsp;mod_write를&amp;nbsp;결합하여&amp;nbsp;CNAME(DNS&amp;nbsp;record:&amp;nbsp;하나의&amp;nbsp;도메인&amp;nbsp;이름을&amp;nbsp;다른&amp;nbsp;것으로&amp;nbsp;가리키는&amp;nbsp;별칭도메인을&amp;nbsp;생성)를&amp;nbsp;생성하면&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;a href=&quot;https://en.wikipedia.org/wiki/Adaptive_web_design&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;example.com&lt;/li&gt;
&lt;li&gt;example.com -&amp;gt; m.example.com&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;a href=&quot;https://en.wikipedia.org/wiki/Responsive_web_design&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;a href=&quot;https://developers.google.com/search/mobile-sites/mobile-seo/separate-urls&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;별도 URL&lt;/a&gt;, 반응형 웹은&amp;nbsp;&lt;a href=&quot;https://developers.google.com/web/fundamentals/design-and-ux/responsive?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;반응형 웹 디자인 기본 사항&lt;/a&gt;이 입문에 좋은 문서같다. [&lt;a href=&quot;https://github.com/yamoo9/cj-olive-networks/wiki/%EC%A0%81%EC%9D%91%ED%98%95-%EC%9B%B9-%EB%94%94%EC%9E%90%EC%9D%B8-VS-%EB%B0%98%EC%9D%91%ED%98%95-%EC%9B%B9-%EB%94%94%EC%9E%90%EC%9D%B8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;적응형&amp;nbsp;웹&amp;nbsp;디자인&amp;nbsp;VS&amp;nbsp;반응형&amp;nbsp;웹&amp;nbsp;디자인&lt;/a&gt;, 반응형 웹을 위한 레이아웃 설계 방법(&lt;a href=&quot;https://www.samsungsds.com/global/ko/support/insights/Responsive_web_1.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;1편&lt;/a&gt;, &lt;a href=&quot;https://www.samsungsds.com/global/ko/support/insights/Responsive-Web-2.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2편&lt;/a&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;2.2.5 iframe 수를 최소화&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;&amp;nbsp;content&lt;br /&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Iframe&lt;/a&gt;을 사용하면 HTML 문서를 부모 문서에 삽입 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Iframe이 효과적으로 사용되도록 작동하는 방식을 이해하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iframe의 단점은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;비어있더라도 비쌈[&lt;a href=&quot;http://www.stevesouders.com/blog/2009/06/03/using-iframes-sparingly/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Using Iframes Sparingly&lt;/a&gt;]&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;page&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;onload&lt;/a&gt;를&amp;nbsp;차단함&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;대역폭을 메인 페이지와 경쟁&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Non-semantic (비의미론적이다)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기타 보안 사항에 취약&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;308&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mMIcg/btqW8GxDp0k/J7Z7PQwvYb4iKYCJfCM950/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mMIcg/btqW8GxDp0k/J7Z7PQwvYb4iKYCJfCM950/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mMIcg/btqW8GxDp0k/J7Z7PQwvYb4iKYCJfCM950/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/mMIcg/btqW8GxDp0k/J7Z7PQwvYb4iKYCJfCM950/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;308&quot; height=&quot;384&quot; data-origin-width=&quot;308&quot; data-origin-height=&quot;384&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;- Ajax 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/Guide/AJAX&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ajax&lt;/a&gt;를 이용해 데이터를 로드해서 div에 결합할 수 있다.[&lt;a href=&quot;https://stackoverflow.com/questions/43103646/best-approach-to-replace-iframes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Best&amp;nbsp;approach&amp;nbsp;to&amp;nbsp;replace&amp;nbsp;iframes&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;b&gt;- 대체 태그 사용??&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 방식으로 삽입을 하는 것을 생각해보자면&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;object&lt;/a&gt;와 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/embed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;embed&lt;/a&gt;란 태그가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;From object to iframe &amp;mdash; other embedding technologies&lt;/a&gt;, &lt;a href=&quot;https://stackoverflow.com/questions/16660559/difference-between-iframe-embed-and-object-elements&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;difference between iframe, embed and object elements&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://www.quora.com/What-is-the-difference-between-iframe-object-and-embed?share=1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What is the difference between &amp;lt;iframe&amp;gt;, &amp;lt;object&amp;gt; and &amp;lt;embed&amp;gt;?&lt;/a&gt;, &lt;a href=&quot;http://bencreasy.com/object-versus-embed/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lt;iframe&amp;gt; vs &amp;lt;object&amp;gt; vs &amp;lt;embed&amp;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;HTML5의 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;audio&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;video&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;web components&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;구글은 iframe 대신 &lt;a href=&quot;https://wicg.github.io/portals/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;potal&lt;/a&gt;이란 태그를 발표하기도 했지만 이제 막 논의될랑 말랑 하기 때문에 무시해도 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[&lt;a href=&quot;https://www.zdnet.com/article/google-launches-portals-a-new-web-page-navigation-system-for-chrome/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Google launches Portals, a new web page navigation system for Chrome&lt;/a&gt;, &lt;a href=&quot;https://web.dev/hands-on-portals/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hands-on&amp;nbsp;with&amp;nbsp;Portals:&amp;nbsp;seamless&amp;nbsp;navigation&amp;nbsp;on&amp;nbsp;the&amp;nbsp;Web&lt;/a&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;2.2.6 document.write() 사용하지 않기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Javascript&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/write&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;document.write()&lt;/a&gt;는 사이트를 느리게 만들 수 있다. [&lt;a href=&quot;https://developers.google.com/web/updates/2016/08/removing-document-write&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Intervening&amp;nbsp;against&amp;nbsp;document.write()&lt;/a&gt;, &lt;a href=&quot;https://blog.dareboost.com/en/2016/09/avoid-using-document-write-scripts-injection/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Why&amp;nbsp;you&amp;nbsp;should&amp;nbsp;avoid&amp;nbsp;using&amp;nbsp;document.write,&amp;nbsp;specifically&amp;nbsp;for&amp;nbsp;scripts&amp;nbsp;injection&lt;/a&gt;, &lt;a href=&quot;http://www.stevesouders.com/blog/2012/04/10/dont-docwrite-scripts/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Don't docwrite scripts&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;특히 document.write()를 통해 동적으로 스크립트를 삽입한다면 매우 느려질 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1586725577209&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;document.write('&amp;lt;script src=&quot;https://paul.kinlan.me/ad-inject.js&quot;&amp;gt;&amp;lt;/script&amp;gt;');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;HTML 파싱을 중단하고, 리소스가 로드되어 실행 될때까지 기다려야 하기 때문인데, &lt;/span&gt;크롬의 경우 &lt;a href=&quot;https://github.com/WICG/interventions/issues/17#issuecomment-238477265&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;DOM 트리가 만들어진 후, document.write가 사용되면 다시 빌드를 해야하므로 역시 성능에 좋지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;스크립트 로드는 앞서 나온 defer, async로 하며, 굳이 자바스크립트로 해야 하다면 DOM 조작을 통해서 하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1586726387609&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const sNew = document.createElement ( &quot;script&quot;); 
sNew.async = true; 
sNew.src = &quot;https://example.com/script.min.js&quot;; 
const s0 = document.getElementsByTagName ( 'script') [0]; 
s0.parentNode.insertBefore (sNew, s0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2.7 textContent 사용&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Javascript&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 텍스트를 다룰때 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Node/textContent&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;textContent,&lt;/a&gt; &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Node/innerText&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;innerText&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Element/innerHTML&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;innerHTML&lt;/a&gt; 3가지를 생각해볼 수 있다. &lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;https://velog.io/@raram2/%EB%8B%B9%EC%8B%A0%EC%9D%B4-innerHTML%EC%9D%84-%EC%93%B0%EB%A9%B4-%EC%95%88%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0&quot;&gt;당신이 innerHTML을 쓰면 안되는 이유&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&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;이 중 textContent의 성능이 가장 좋은 편이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EHDzo/btqWXafyFsy/baUG9zfcW14XmfRlgESKR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EHDzo/btqWXafyFsy/baUG9zfcW14XmfRlgESKR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EHDzo/btqWXafyFsy/baUG9zfcW14XmfRlgESKR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEHDzo%2FbtqWXafyFsy%2FbaUG9zfcW14XmfRlgESKR1%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;187&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;innerText: CSS를 고려하기 때문에 innerText값을 읽으면 최신 계산값을 반영하기 위해 리플로우가 발생&lt;/li&gt;
&lt;li&gt;innerHTML: HTML로 분석하는 과정 필요&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;특히, innerHTML은 성능이 나쁘고, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%82%AC%EC%9D%B4%ED%8A%B8_%EA%B0%84_%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8C%85&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;XSS(Cross-Site Scripting)&lt;/a&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;2.2.8 CSS 선택자&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS 작성을 효율적으로 하면 스타일 계산을 줄일 수 있다. [&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스타일&amp;nbsp;계산의&amp;nbsp;범위와&amp;nbsp;복잡성&amp;nbsp;줄이기&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 스타일 계산시 50%는 선택자를 매칭하는데 사용하기 때문에 크게 줄일 수 있다. [&lt;a href=&quot;https://docs.google.com/document/d/1vEW86DaeVs4uQzNFI5R-_xS9TcS1Cs_EUsHRSgCHGu8/edit?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Blink에서 스타일 무효화&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;CSS 셀렉터는 오른쪽부터 읽으며, 실패하는게 좋다. (중복 최소화)&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;&lt;b&gt;선택자별 성능차&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셀렉터별로 성능차가 존재한다. [&lt;a href=&quot;https://vanseodesign.com/css/css-selector-performance/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Selectors: Should You Optimize Them To Perform Better?&lt;/a&gt;, &lt;a href=&quot;https://css-tricks.com/efficiently-rendering-css/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Efficiently&amp;nbsp;Rendering&amp;nbsp;CSS&lt;/a&gt;, &lt;a href=&quot;https://web.archive.org/web/20110629085459/https://developer.mozilla.org/en/Writing_Efficient_CSS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Writing&amp;nbsp;Efficient&amp;nbsp;CSS&amp;nbsp;for&amp;nbsp;use&amp;nbsp;in&amp;nbsp;the&amp;nbsp;Mozilla&amp;nbsp;UI&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;id가 가장 빠르고, 가상 클래스가 가장 느리다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;id (#myid)&lt;/li&gt;
&lt;li&gt;class (.myclass)&lt;/li&gt;
&lt;li&gt;tag (div, h1, p)&lt;/li&gt;
&lt;li&gt;adjacent sibling (h1 + p)&lt;/li&gt;
&lt;li&gt;child (ul &amp;gt; li)&lt;/li&gt;
&lt;li&gt;descendent (li a)&lt;/li&gt;
&lt;li&gt;universal (*)&lt;/li&gt;
&lt;li&gt;attribute (a[rel=&amp;rdquo;external&amp;rdquo;])&lt;/li&gt;
&lt;li&gt;pseudo-class and pseudo element (a:hover, li:first)&lt;/li&gt;
&lt;/ol&gt;
&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;예를 들어 다음은 box의 마지막의 $-n+1$번째를 상위요소로 둔 .title 클래스를 고르는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1587093133171&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.box:nth-last-child(-n+1) .title {
  /* styles */
}&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;pre id=&quot;code_1587093278435&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.final-box-title {
  /* styles */
}&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;
&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;구조적으로 CSS를 작성하면 선택의 복잡성이 줄어들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 BEM은 단일 클래스 계층을 가지기 때문.&lt;/p&gt;
&lt;pre id=&quot;code_1587092893705&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.list { }
.list__list-item { }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;BEM 형식의 코드&lt;/p&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 방법론들 [&lt;a href=&quot;https://d0gf00t.tistory.com/19&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[번역] 공룡을 위한 모던 CSS&lt;/a&gt;, &lt;a href=&quot;https://d0gf00t.tistory.com/20&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[번역]&amp;nbsp;CSS개선을&amp;nbsp;위한&amp;nbsp;SEM과&amp;nbsp;BIO의&amp;nbsp;결합&lt;/a&gt;, &lt;a href=&quot;https://medium.com/@albinotonnina/happy-with-your-css-files-in-your-big-app-ca03d51ed5bd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Happy&amp;nbsp;with&amp;nbsp;your&amp;nbsp;CSS&amp;nbsp;files&amp;nbsp;in&amp;nbsp;your&amp;nbsp;big&amp;nbsp;app?&lt;/a&gt;, &lt;a href=&quot;https://github.com/hohoya33/css-methodologies&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS 방법론&lt;/a&gt;, &lt;a href=&quot;https://gael-boyenval.gitbook.io/atomic-design-css-architecture-with-itcss-bem-sass/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Atomic Design System architecture with ITCSS, BEM, SASS&lt;/a&gt;, &lt;a href=&quot;https://medium.com/maintainable-react-apps/journey-to-enjoyable-maintainable-styling-with-react-itcss-and-css-in-js-632cfa9c70d6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Journey&amp;nbsp;to&amp;nbsp;Enjoyable,&amp;nbsp;Maintainable&amp;nbsp;Styling&amp;nbsp;with&amp;nbsp;React,&amp;nbsp;ITCSS,&amp;nbsp;and&amp;nbsp;CSS-in-JS&lt;/a&gt;, &lt;a href=&quot;https://css-tricks.com/methods-organize-css/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Methods&amp;nbsp;to&amp;nbsp;Organize&amp;nbsp;CSS&lt;/a&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;a href=&quot;http://oocss.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OOCSS(Object Oriented CSS)&lt;/a&gt; [&lt;a href=&quot;https://github.com/stubbornella/oocss/wiki&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OOCSS Wiki&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://smacss.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SMACSS(Scalable and Modular Architecture for CSS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.bem.info/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BEM(Block, Element, Modifier)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://itcss.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ITCSS(Inverted Triangle CSS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ecss.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ECSS(Enduring CSS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://acss.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ACSS(Atomic CSS)&lt;/a&gt; [&lt;a href=&quot;https://www.smashingmagazine.com/2013/10/challenging-css-best-practices-atomic-approach/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Challenging&amp;nbsp;CSS&amp;nbsp;Best&amp;nbsp;Practices&lt;/a&gt;, &lt;a href=&quot;https://bradfrost.com/blog/post/extending-atomic-design/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;extending atomic design&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cssinjs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JSS(CSS in JS)&lt;/a&gt; [&lt;a href=&quot;https://blog.vjeux.com/2014/javascript/react-css-in-js-nationjs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React:&amp;nbsp;CSS&amp;nbsp;in&amp;nbsp;JS&amp;nbsp;&amp;ndash;&amp;nbsp;NationJS&lt;/a&gt;, &lt;a href=&quot;https://blog.rhostem.com/posts/2017-06-24-unified-styling-language&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;통합 스타일링 언어&lt;/a&gt;, &lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://ryantsao.com/blog/virtual-css-with-styletron&quot;&gt;Virtual&amp;nbsp;CSS&amp;nbsp;with&amp;nbsp;Styletron&lt;/a&gt;]&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;일단 JSS 계열에서 &lt;a href=&quot;https://github.com/styled-components/styled-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Styled Components&lt;/a&gt;/&lt;a href=&quot;https://github.com/emotion-js/emotion&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Emotion&lt;/a&gt;, &lt;a href=&quot;https://github.com/Khan/aphrodite&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Aphrodite&lt;/a&gt;와 &lt;a href=&quot;https://github.com/styletron/styletron&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Styletron&lt;/a&gt;이 눈에 띄는 것 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YEaDA/btqWXbldlJO/pHOKe5GpyaHwVCuTJ2TBK0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YEaDA/btqWXbldlJO/pHOKe5GpyaHwVCuTJ2TBK0/img.jpg&quot; data-origin-width=&quot;489&quot; data-origin-height=&quot;354&quot; style=&quot;width: 46.2944%; margin-right: 10px;&quot; data-widthpercent=&quot;46.84&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YEaDA/btqWXbldlJO/pHOKe5GpyaHwVCuTJ2TBK0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYEaDA%2FbtqWXbldlJO%2FpHOKe5GpyaHwVCuTJ2TBK0%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;489&quot; height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ekQKgJ/btqW8Hi067V/lDmCopFDmAmL12ltr5kv9k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ekQKgJ/btqW8Hi067V/lDmCopFDmAmL12ltr5kv9k/img.jpg&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;354&quot; style=&quot;width: 52.5428%;&quot; data-widthpercent=&quot;53.16&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ekQKgJ/btqW8Hi067V/lDmCopFDmAmL12ltr5kv9k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FekQKgJ%2FbtqW8Hi067V%2FlDmCopFDmAmL12ltr5kv9k%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;555&quot; height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;일반 CSS in JS vs Styletron&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 Styletron의 atomic 방식은 크기를 줄여줄 수 있어 특이한 듯(대신 셀렉터가 늘어나 렌더링 성능과 트레이드오프)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JS를 이용해 CSS를 생성하는 방식은 런타임시에 영향을 미칠 수 있는데 [&lt;a href=&quot;https://calendar.perfplanet.com/2019/the-unseen-performance-costs-of-css-in-js-in-react-apps/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The unseen performance costs of modern CSS-in-JS libraries in React apps&lt;/a&gt;, &lt;a href=&quot;https://velog.io/@asdhugh1/Styling-with-Linaria&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Styling?&amp;nbsp;with&amp;nbsp;Linaria!&lt;/a&gt;, &lt;a href=&quot;https://callstack.com/blog/how-is-linaria-different-from-emotion-and-styled-components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;is&amp;nbsp;Linaria&amp;nbsp;different&amp;nbsp;from&amp;nbsp;Emotion&amp;nbsp;and&amp;nbsp;Styled&amp;nbsp;Components&lt;/a&gt;, &lt;a href=&quot;https://www.freecodecamp.org/news/the-tradeoffs-of-css-in-js-bee5cf926fdb/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;tradeoffs&amp;nbsp;of&amp;nbsp;CSS-in-JS&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/callstack/linaria&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Linaria&lt;/a&gt;(&lt;a href=&quot;https://github.com/callstack/linaria/blob/master/docs/BENEFITS.md&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;SASS와 PostCSS도 사용가능한 것 같고.&lt;/p&gt;
&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/linkedin/css-blocks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;css-blocks&lt;/a&gt;란 프로젝트를 찾았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS 모듈, BEM, Atomic CSS의 장점을 모두 활용하려는 듯.&lt;/p&gt;
&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/microsoft/griffel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Griffel&lt;/a&gt; 또한 CSS-In-JS, AOT Compile, Atomic CSS를 지원하는 강력한 라이브러리다.&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;2.2.9 IE 독점 CSS&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 IE 독점 CSS 최적화에 관련된 내용이다.&lt;/p&gt;
&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;- CSS 표현식 피하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS 표현식은 CSS 속성을 동적으로 설정하는 강력하고 위험한 방법이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버전 5부터 Internet Explorer에서 지원되었지만 IE8부터는 더 이상 사용되지 않으므로 &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;예를 들어 CSS 표현식을 사용하여 매시간마다 배경색을 번갈아 설정할 수 있는데&lt;/p&gt;
&lt;pre id=&quot;code_1584933077046&quot; class=&quot;css&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;background-color: expression( (new Date()).getHours()%2 ? &quot;#B8D4FF&quot; : &quot;#F08A00&quot; );&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;expression은 JavaScript 표현식을 사용하며 CSS 속성은 JavaScript 표현식을 평가 한 결과로 설정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 expression방법은 다른 브라우저에서 무시되므로 Internet Explorer에서 속성을 설정하여 브라우저간에 일관된 환경을 만드는 데 유용했다.&lt;br /&gt;&lt;br /&gt;expression의 문제점은 대부분의 사람들이 기대하는 것보다 더 자주 평가된다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지가 렌더링되고 크기가 조정될 때뿐만 아니라 페이지가 스크롤 될 때와 사용자가 페이지 위로 마우스를 움직일 때도 평가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS 표현식에 카운터를 추가하면 CSS 표현식이 언제 그리고 얼마나 자주 평가되는지 추적 할 수 있다.&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;&lt;b&gt;- &lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;AlphaImageLoader 필터 피하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;AlphaImageLoader필터는 IE 버전 7이하에서 반투명 트루 컬러 PNG의 문제를 해결하는 것을 목표로 한다.&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;&amp;nbsp;&lt;/span&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: #333333;&quot;&gt;(element)&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;- CSS 표현식 피하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS 표현식의 평가 횟수를 줄이는 한 가지 방법은 일회성 표현식을 사용하는 것이다.&amp;nbsp;&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;&amp;nbsp;&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;CSS 표현식을 사용해야하는 경우 수천 번 평가 될 수 있으며 페이지 성능에 영향을 줄 수 있다는 것을 명심해야 한다.&lt;/p&gt;
&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&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;AlphaImageLoader 필터 피하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가장 좋은 방법은 AlphaImageLoader를 완전히 사용하지 말고, PNG8을 사용하는 것.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;꼭 필요한 경우 hack_filter를 사용하여 IE7 + 사용자에게 불이익을 주지 않도록 해야한다.&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;2.3 효율적 활용&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3.1 Streams&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;Javascript&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Streams_API&quot;&gt;Streams&lt;/a&gt;를 이용하면 성능 향상의 여지가 있다. [&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20160222/&quot;&gt;2016년은&amp;nbsp;웹&amp;nbsp;스트림(web&amp;nbsp;stream)의&amp;nbsp;해다.&lt;/a&gt;, &lt;a href=&quot;https://www.sitepen.com/blog/a-guide-to-faster-web-app-io-and-data-operations-with-streams/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;Faster&amp;nbsp;Web&amp;nbsp;App&amp;nbsp;I/O&amp;nbsp;and&amp;nbsp;Data&amp;nbsp;Operations&amp;nbsp;with&amp;nbsp;Streams&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;특히 커다란 요소를 점진적으로 렌더링을 하거나, 가져와서(fetch) 변환해야 할 때 유용하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGDoGz/btqWWtfn50J/MF1EngoGSKsmtIQuF1MnA0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGDoGz/btqWWtfn50J/MF1EngoGSKsmtIQuF1MnA0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGDoGz/btqWWtfn50J/MF1EngoGSKsmtIQuF1MnA0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cGDoGz/btqWWtfn50J/MF1EngoGSKsmtIQuF1MnA0/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;692&quot; height=&quot;438&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;438&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 style=&quot;font-size: 1.12em;&quot; 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;MDN의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/mdn/dom-examples/tree/master/streams&quot;&gt;stream 예제&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;a href=&quot;https://wiki-offline.jakearchibald.com/&quot;&gt;오프라인 위키피디아 데모&lt;/a&gt;(&lt;a href=&quot;https://github.com/jakearchibald/offline-wikipedia&quot;&gt;깃허브&lt;/a&gt;)에 적용되었다고 하는데 후술할 서비스 워커와 함께 사용해 상당히 좋은 성능을 보여준다. [&lt;a href=&quot;https://developers.google.com/web/updates/2016/06/sw-readablestreams&quot;&gt;Stream Your Way to Immediate Responses&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdBmPE/btqWX6jEjoS/1i5kDdFjuROSAWna35t0hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdBmPE/btqWX6jEjoS/1i5kDdFjuROSAWna35t0hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdBmPE/btqWX6jEjoS/1i5kDdFjuROSAWna35t0hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdBmPE%2FbtqWX6jEjoS%2F1i5kDdFjuROSAWna35t0hk%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;641&quot; height=&quot;220&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;220&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;a href=&quot;https://github.com/samccone/streaming-css&quot;&gt;streaming-css&lt;/a&gt;처럼 점진적으로 CSS를 적용하도록 만들 수도 있긴한데,&amp;nbsp; 전체를 로드하는 시간이 더 빨라 좋은 방법이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React는 &lt;a href=&quot;https://ko.reactjs.org/docs/code-splitting.html#reactlazy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ReactDOMServer&lt;/a&gt;에서 스트림을 지원하는 듯. 조금 오래된 &lt;a href=&quot;https://github.com/aickin/react-dom-stream&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-dom-stream&lt;/a&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;2.3.2 iframe 활용&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iframe은 단점이 많지만 iframe도 장점이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배지(badges)나&amp;nbsp;광고와&amp;nbsp;같이&amp;nbsp;느린&amp;nbsp;third-party&amp;nbsp;content를&amp;nbsp;원활하게&amp;nbsp;함&lt;/li&gt;
&lt;li&gt;Security&amp;nbsp;sandbox&amp;nbsp;(보안&amp;nbsp;sandbox)&lt;/li&gt;
&lt;li&gt;scripts를&amp;nbsp;병렬로&amp;nbsp;다운로드&amp;nbsp;함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;- Non-Blocking 로드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 iframe의 단점의 주요 원인은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;onload 이벤트가 발생하기 전에 iframe 로드&lt;/li&gt;
&lt;li&gt;src 속성은 다운로드 받아야 하는 리소스&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 onload 전에 iframe이 오는 것를 막거나(onload 이벤트 이후 비동기적 로드), src 속성없이 iframe을 사용한다면 성능상 불이익은 없다.&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;[&lt;/span&gt;&lt;a href=&quot;http://programming.oreilly.com/2013/06/using-iframes-to-address-third-party-script-issues-and-boost-performance.html&quot;&gt;Using Iframes to Address Third-Party Script Issues and Boost Performance&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(&lt;/span&gt;&lt;a href=&quot;http://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS5589088797&quot;&gt;번역&lt;/a&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;리소스 힌트가 먹히지 않는 구형 브라우저를 사용한다면 iframe을 이용해 로드를 시도해보자.[&lt;a href=&quot;https://calendar.perfplanet.com/2018/a-csp-compliant-non-blocking-script-loader/&quot;&gt;A CSP Compliant non-blocking script loader&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.akamai.com/tools/boomerang/docs/tutorial-loader-snippet.html&quot;&gt;Non-Blocking Loader Snippet&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript#sandbox_scripts_with_an_iframe%EF%BB%BF&quot;&gt;Loading&amp;nbsp;Third-Party&amp;nbsp;JavaScript&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1586890547259&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script id=&quot;nb-loader-script&quot;&amp;gt;
(function(url) {

  // document.currentScript works on most browsers, but not all
  var where = document.currentScript || document.getElementById(&quot;nb-loader-script&quot;),
      promoted = false,
      LOADER_TIMEOUT = 3000,
      IDPREFIX = &quot;__nb-script&quot;;

  // function to promote a preload link node to an async script node
  function promote() {
    var s;
    s = document.createElement(&quot;script&quot;);
    s.id = IDPREFIX + &quot;-async&quot;;
    
    s.src = url;

    where.parentNode.appendChild(s);
    promoted = true;
  }

  // function to load script in an iframe on browsers that don't support preload hints
  function iframe_loader() {
    promoted = true;
    var win, doc, dom, s, bootstrap, iframe = document.createElement(&quot;iframe&quot;);

    // IE6, which does not support CSP, treats about:blank as insecure content, so we'd have to use javascript:void(0) there
    // In browsers that do support CSP, javascript:void(0) is considered unsafe inline JavaScript, so we prefer about:blank
    iframe.src = &quot;about:blank&quot;;
    
    // We set title and role appropriately to play nicely with screen readers and other assistive technologies
    iframe.title = &quot;&quot;;
    iframe.role = &quot;presentation&quot;;
    
    s = (iframe.frameElement || iframe).style;
    s.width = 0; s.height = 0; s.border = 0; s.display = &quot;none&quot;;
    
    where.parentNode.insertBefore(iframe, where);
    try {
      win = iframe.contentWindow;
      doc = win.document.open();
    }
    catch (e) {
      // document.domain has been changed and we're on an old version of IE, so we got an access denied.
      // Note: the only browsers that have this problem also do not have CSP support.
      
      // Get document.domain of the parent window
      dom = document.domain;
      
      // Set the src of the iframe to a JavaScript URL that will immediately set its document.domain to match the parent.
      // This lets us access the iframe document long enough to inject our script.
      // Our script may need to do more domain massaging later.
      iframe.src = &quot;javascript:var d=document.open();d.domain='&quot; + dom + &quot;';void(0);&quot;;
      win = iframe.contentWindow;
      doc = win.document.open();
    }

    bootstrap = function() {
      // This code runs inside the iframe
      var js = doc.createElement(&quot;script&quot;);
      js.id = IDPREFIX + &quot;-iframe-async&quot;;
      js.src = url;
      doc.body.appendChild(js);
    };
    
    try {
      win._l = bootstrap

      if (win.addEventListener) {
        win.addEventListener(&quot;load&quot;, win._l, false);
      }
      else if (win.attachEvent) {
        win.attachEvent(&quot;onload&quot;, win._l);
      }
    }
    catch (f) {
      // unsafe version for IE8 compatability
      // If document.domain has changed, we can't use win, but we can use doc
      doc._l = function() {
        if (dom) {
          this.domain = dom;
        }
        bootstrap();
      }
      doc.write('&amp;lt;bo' + 'dy onload=&quot;document._l();&quot;&amp;gt;');
    }
    doc.close();
  }

  // We first check to see if the browser supports preload hints via a link element
  var l = document.createElement(&quot;link&quot;);

  if (l.relList &amp;amp;&amp;amp; typeof l.relList.supports === &quot;function&quot; &amp;amp;&amp;amp; l.relList.supports(&quot;preload&quot;) &amp;amp;&amp;amp; (&quot;as&quot; in l)) {
    l.href = url;
    l.rel  = &quot;preload&quot;;
    l.as   = &quot;script&quot;;
    
    // If the link successfully preloads our script, we'll promote it to a script node.
    l.addEventListener(&quot;load&quot;, promote);
    
    // If the preload fails or times out, we'll fallback to the iframe loader
    l.addEventListener(&quot;error&quot;, iframe_loader);
    setTimeout(function() {
        if (!promoted) {
            iframe_loader();
        }
    }, LOADER_TIMEOUT);
    
    where.parentNode.appendChild(l);
  }
  else {
    // If preload hints aren't supported, then fallback to the iframe loader
    iframe_loader();
  }

})(&quot;https://your.script.url/goes/here.js&quot;);
&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;&lt;b&gt;- Iframe + document.write()을 이용한 스트리밍&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 구 브라우저를 위한 트릭.[&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20161212/&quot;&gt;웹&amp;nbsp;페이지에서&amp;nbsp;컨텐츠를&amp;nbsp;빠르게&amp;nbsp;보여주기&amp;nbsp;위한&amp;nbsp;트릭&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 브라우저의 서비스 워커를 사용하면 좋다. [&lt;a href=&quot;https://jakearchibald.github.io/streaming-html/&quot;&gt;streaming-html&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&lt;a href=&quot;https://github.com/jakearchibald/streaming-html&quot;&gt;github&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;모든 내용을 다 받고 나서 보여주기보다는 점진적으로 보여주는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 아래 코드는 page-data.inc의 내용을 다운로드 받을 때까지 기다려야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1586890547259&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ... 브라우저 네비게이션을 구현하기 위한 많은 코드들
const response = await fetch('page-data.inc');
const html = await response.text();
document.querytSelector('.content').innerHTML = 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;iframe과 document.write() 사용하면 다운로드 받는 내용들을 바로 보여줄 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1586890547259&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// iframe을 만든다
const iframe = document.createElement('iframe');

// 문서에 숨겨진 형태로 추가한다.
iframe.style.display = 'none';
document.body.appendChild(iframe);

// iframe이 준비될 때 까지 기다린다
iframe.onload = () =&amp;gt; {
  // 앞으로의 load 이벤트를 무시한다
  iframe.onload = null;

  // 더미 태그를 만든다
  iframe.contentDocument.write('&amp;lt;streaming-element&amp;gt;');

  // 엘리먼트에 대한 참조를 얻는다
  content streamingElement = iframe.contentDocument.querySelector('streaming-element');

  // 해당 엘리먼트를 iframe문서에서 빼고 부모 문서에 추가한다.
  document.body.appendChild(streamingElement);

  // 컨텐츠를 추가한다 (비동기로 작동한다)
  iframe.contentDocument.write('&amp;lt;p&amp;gt;Hello!&amp;lt;/p&amp;gt;');

  // 아래와 같이 컨텐츠를 추가한다. 그러면 끝
  iframe.contentDocument.write('&amp;lt;/streaming-element&amp;gt;');
  iframe.contentDocument.close();
};

// iframe을 초기화한다
iframe.src = '';&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;그러나 document.write()는 성능에 나쁜 요소가 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 생각해볼만한 것은 JSON 형식으로 가져오는 것인데 보통 우리가 생각하는 JSON은 다음과 같이 생겼다.&lt;/p&gt;
&lt;pre id=&quot;code_1586890547259&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;Comments&quot;: [
    {&quot;author&quot;:&quot;Alex&quot;,&quot;body&quot;:&quot;...&quot;},
    {&quot;author&quot;:&quot;Jake&quot;,&quot;body&quot;:&quot;...&quot;}
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 스트리밍에 친화적인 포맷이 아니라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/creationix/jsonparse&quot;&gt;스트리밍 JSON 파서&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;span style=&quot;color: #333333;&quot;&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://specs.okfnlabs.org/ndjson/&quot;&gt;newline-delimited JSON&lt;/a&gt;이라 하여 개행으로 이루어진 JSON을 이용하면 파싱이 훨씬 간단해진다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1586890547260&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{&quot;author&quot;:&quot;Alex&quot;,&quot;body&quot;:&quot;...&quot;}
{&quot;author&quot;:&quot;Jake&quot;,&quot;body&quot;:&quot;...&quot;}&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;splitStream과 parseJSON은 재사용 가능한 변화되는 스트림이며, xhr을 사용할 수도 있다. [&lt;a href=&quot;https://gist.github.com/jakearchibald/c2052ef298459355963b8cfb79c71d1c&quot;&gt;parse-json.js&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/jakearchibald/streaming-html/blob/master/xhr-ndjson.js&quot;&gt;xhr-ndjson&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1586890547260&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;// Sometime in 2017

const response = await fetch('comments.ndjson');
const comments = response.body
  .pipeThrough(new TextDecoder())
  .pipeThrough(splitStream('\n'))
  .pipeThrough(parseJSON());

for await (const comment of comments) {
  addCommentToPage(comment);
}&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;벤치마크 결과를 보면 안티패턴으로 알려진 iframe + document.write()가 의외로 빠르다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IUd4y/btqWX47bbqa/cIw7lh1RIxKM9crKpWnFXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IUd4y/btqWX47bbqa/cIw7lh1RIxKM9crKpWnFXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IUd4y/btqWX47bbqa/cIw7lh1RIxKM9crKpWnFXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIUd4y%2FbtqWX47bbqa%2FcIw7lh1RIxKM9crKpWnFXk%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;652&quot; height=&quot;237&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;237&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;되도록 사용하지 않는&lt;/b&gt;&lt;span&gt;&amp;nbsp;&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;h4 data-ke-size=&quot;size20&quot;&gt;2.3.3&amp;nbsp; 웹 컴포넌트의 최적화 가능성?&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/Web_Components&quot;&gt;웹 컴포넌트&lt;/a&gt;는 3개(Import까지 포함했다면 4가지)로 이루어져 있다. [&lt;a href=&quot;https://d2.naver.com/helloworld/188655&quot;&gt;웹 컴포넌트&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20171215/&quot;&gt;TOAST UI - 웹 컴포넌트 연재&lt;/a&gt;, &amp;nbsp;&lt;a href=&quot;https://css-tricks.com/an-introduction-to-web-components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;An Introduction to Web Components&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Custom elements: HTML 요소 및 해당 동작을 정의 및 확장 [&lt;a href=&quot;https://www.html5rocks.com/ko/tutorials/webcomponents/customelements/&quot;&gt;Custom Elements&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Shadow DOM: 컴포넌트의 스코프를 분리 [&lt;a href=&quot;https://www.html5rocks.com/ko/tutorials/webcomponents/shadowdom/&quot;&gt;Shadow DOM 101&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;HTML Templete: 렌더링된 페이지에 나타나지 않은 마크업으로, 커스텀 엘리먼트 구조를 기반으로 재사용 가능 [&lt;a href=&quot;https://www.html5rocks.com/ko/tutorials/webcomponents/template/&quot;&gt;HTML's New Template Tag&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;HTML Import: 다른 HTML 파일에서 템플릿을 가져올 수 있음 [&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://www.html5rocks.com/ko/tutorials/webcomponents/imports/&quot;&gt;HTML Imports&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://stackoverflow.com/questions/51236699/fast-webpage-loading-using-the-all-new-html-import-draft-in-2018-replacing-re&quot;&gt;Stackoverflow&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;]&lt;br /&gt;단, 현재 분위기상 HTML Import는 제외되는 것 같다.&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 웹 컴포넌트에서 어디가 최적화 가능성이 있을까?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Custom elements: React나 Vue 보다 다운받아야 할 양이 적음&lt;/li&gt;
&lt;li&gt;HTML Templete: 재사용에 특화가 되었고 바로 렌더링되지 않기 때문에 최적화 가능성이 있을 듯.&lt;br /&gt;파싱이 한번만 일어나며 &lt;a href=&quot;https://github.com/lit/lit/wiki/How-it-Works#the-html-template-element&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lit-html에 따르면&lt;/a&gt;, 비활성화된 HTML 콘텐츠로 스크립트가 실행되지 않고 스타일이 적용되지 않으며 Custom elements가 업그레이드 되지 않는다.&lt;/li&gt;
&lt;li&gt;Shadow DOM: 스코프를 분리하기 때문에 CSS 규칙이 간단해져 최적화 가능성이 있음 [&lt;a href=&quot;https://nolanlawson.com/2021/08/15/does-shadow-dom-improve-style-performance/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Does&amp;nbsp;shadow&amp;nbsp;DOM&amp;nbsp;improve&amp;nbsp;style&amp;nbsp;performance?&lt;/a&gt;, &lt;a href=&quot;https://medium.com/8451/make-your-stenciljs-web-components-faster-by-using-shadow-dom-d010a9f0cdda&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Make&amp;nbsp;Your&amp;nbsp;StencilJS&amp;nbsp;Web&amp;nbsp;Components&amp;nbsp;Faster&amp;nbsp;by&amp;nbsp;Using&amp;nbsp;Shadow&amp;nbsp;DOM&lt;/a&gt;(&lt;a href=&quot;https://ichi.pro/ko/shadow-domeul-sayonghayeo-stenciljs-web-guseong-yosoleul-deo-ppaleuge-mandeulgi-228769989184986&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;한글&lt;/a&gt;)]&lt;br /&gt;1.1.1.1 warp처럼 &lt;a href=&quot;https://m.blog.naver.com/nakawony/221858991250&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;느려지지 않기&lt;/a&gt; 위해 사용한다고 생각하면 좋다.&lt;/li&gt;
&lt;li&gt;HTML Import: async 속성을 통해 비동기적으로 가져올 수 있으며, 파싱을 차단하지 않음 [&lt;a href=&quot;https://www.html5rocks.com/ko/tutorials/webcomponents/imports/&quot;&gt;HTML Imports&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://stackoverflow.com/questions/51236699/fast-webpage-loading-using-the-all-new-html-import-draft-in-2018-replacing-re&quot;&gt;Stackoverflow&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안타깝게도 현재는 Native에 비해 느린 편이지만 [&lt;a href=&quot;https://www.smashingmagazine.com/2016/12/styling-web-components-using-a-shared-style-sheet/&quot;&gt;Styling Web Components Using A Shared Style Sheet&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GJIXQ/btqXj7HVorm/WHqLMMipgFB8aZ8jJLJYN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GJIXQ/btqXj7HVorm/WHqLMMipgFB8aZ8jJLJYN1/img.png&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; width=&quot;500&quot; height=&quot;&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;371&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GJIXQ/btqXj7HVorm/WHqLMMipgFB8aZ8jJLJYN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGJIXQ%2FbtqXj7HVorm%2FWHqLMMipgFB8aZ8jJLJYN1%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;590&quot; height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpbFrQ/btqWXberpws/NjY9JbB93XKkvkP7VAikZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpbFrQ/btqWXberpws/NjY9JbB93XKkvkP7VAikZ1/img.png&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; width=&quot;500&quot; height=&quot;&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;371&quot; data-widthpercent=&quot;33.33&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpbFrQ/btqWXberpws/NjY9JbB93XKkvkP7VAikZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpbFrQ%2FbtqWXberpws%2FNjY9JbB93XKkvkP7VAikZ1%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;590&quot; height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqSSd2/btqW1sGHAn9/nvxASi12vO91Zrc7ToAkLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqSSd2/btqW1sGHAn9/nvxASi12vO91Zrc7ToAkLK/img.png&quot; style=&quot;width: 32.5581%;&quot; width=&quot;500&quot; height=&quot;&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;371&quot; data-widthpercent=&quot;33.34&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqSSd2/btqW1sGHAn9/nvxASi12vO91Zrc7ToAkLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqSSd2%2FbtqW1sGHAn9%2FnvxASi12vO91Zrc7ToAkLK%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;590&quot; height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;/div&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://vaadin.com/blog/simplifying-performance-with-web-components&quot;&gt;Simplifying&amp;nbsp;Performance&amp;nbsp;with&amp;nbsp;Web&amp;nbsp;Components&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kZ43b/btqW4gMMsed/EkeYIyYp1AYO3EcF0FJx01/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kZ43b/btqW4gMMsed/EkeYIyYp1AYO3EcF0FJx01/img.webp&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-height=&quot;371&quot; data-image-id=&quot;1*GRA9fz7Cuf6PvS2nZU_Bpg.png&quot; data-width=&quot;600&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;371&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kZ43b/btqW4gMMsed/EkeYIyYp1AYO3EcF0FJx01/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkZ43b%2FbtqW4gMMsed%2FEkeYIyYp1AYO3EcF0FJx01%2Fimg.webp&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;600&quot; height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VIrYi/btqXj63jX6O/ZZAvBmCYDXPrNvHXmriXAk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VIrYi/btqXj63jX6O/ZZAvBmCYDXPrNvHXmriXAk/img.webp&quot; style=&quot;width: 49.4186%;&quot; data-height=&quot;371&quot; data-image-id=&quot;1*BEk1g6B5qmDp8fPUESkGIw.png&quot; data-width=&quot;600&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;371&quot; data-widthpercent=&quot;50&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VIrYi/btqXj63jX6O/ZZAvBmCYDXPrNvHXmriXAk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVIrYi%2FbtqXj63jX6O%2FZZAvBmCYDXPrNvHXmriXAk%2Fimg.webp&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;600&quot; height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;/div&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;/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;a href=&quot;https://blog.bitsrc.io/7-tools-for-developing-web-components-in-2019-1d5b7360654d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;7&amp;nbsp;Tools&amp;nbsp;for&amp;nbsp;Developing&amp;nbsp;Web&amp;nbsp;Components&amp;nbsp;in&amp;nbsp;2019&lt;/a&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;a href=&quot;https://stenciljs.com/&quot;&gt;Stencil&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lit-html.polymer-project.org/&quot;&gt;lit-html&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;amp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lit-element.polymer-project.org/&quot;&gt;LitElement&lt;/a&gt;(최근에는 &lt;a href=&quot;https://lit.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lit&lt;/a&gt;으로 통합관리 되는 듯)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vuejs.org/&quot;&gt;Vue.JS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.salesforce.com/developer-centers/lightning-web-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lighting Web Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/github/github-elements&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;깃허브&lt;/a&gt; [&lt;a href=&quot;https://github.blog/2021-05-04-how-we-use-web-components-at-github/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;도입 이유&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.fast.design/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fast&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등이 있는데 Vue.JS는 최적화가 부족한 모양. [&lt;a href=&quot;https://medium.com/@thangman22/stencil-js-vs-lit-element-vs-vanilla-vs-shadow-dom-vs-vue-js-5d2ade971183&quot;&gt;Stencil.js&amp;nbsp;vs&amp;nbsp;lit-element&amp;nbsp;vs&amp;nbsp;Vanilla&amp;nbsp;vs&amp;nbsp;Shadow&amp;nbsp;DOM&amp;nbsp;vs&amp;nbsp;Vue.js&amp;nbsp;What&amp;nbsp;is&amp;nbsp;the&amp;nbsp;best&amp;nbsp;solution&amp;nbsp;for&amp;nbsp;Web&amp;nbsp;component&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;b&gt;Constructable Stylesheet Objects&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://wicg.github.io/construct-stylesheets/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Constructable Stylesheet Objects&lt;/a&gt;는 최초 한번 파싱 후, 공유하는 규칙들을 Shadow DOM을 이용해 적용(Attach)하는 방식으로 재사용이 가능해 성능에 도움을 줄 수 있다. [&lt;a href=&quot;https://developers.google.com/web/updates/2019/02/constructable-stylesheets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Constructable&amp;nbsp;Stylesheets:&amp;nbsp;seamless&amp;nbsp;reusable&amp;nbsp;styles&lt;/a&gt;, &lt;a href=&quot;https://medium.com/swlh/adopt-a-design-system-inside-your-web-components-with-constructable-stylesheets-dd24649261e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Adopt&amp;nbsp;a&amp;nbsp;Design&amp;nbsp;System&amp;nbsp;inside&amp;nbsp;your&amp;nbsp;Web&amp;nbsp;Components&amp;nbsp;with&amp;nbsp;Constructable&amp;nbsp;Stylesheets&lt;/a&gt;, &lt;a href=&quot;https://blog.bitsrc.io/getting-adoption-for-design-systems-a-practical-guide-cde86ee9bf40&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Getting&amp;nbsp;Adoption&amp;nbsp;for&amp;nbsp;Design&amp;nbsp;Systems&amp;nbsp;&amp;mdash;&amp;nbsp;A&amp;nbsp;Practical&amp;nbsp;Guide&lt;/a&gt;, &lt;a href=&quot;https://dev.to/overrideveloper/a-first-look-at-constructable-stylesheets-3ae&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A Quick Look at Constructable Stylesheets&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;976&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcr6a5/btqWWt7vSIJ/xQ3nIkTBWnYr3noFhKkrb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcr6a5/btqWWt7vSIJ/xQ3nIkTBWnYr3noFhKkrb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcr6a5/btqWWt7vSIJ/xQ3nIkTBWnYr3noFhKkrb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbcr6a5%2FbtqWWt7vSIJ%2FxQ3nIkTBWnYr3noFhKkrb1%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;1280&quot; height=&quot;976&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;976&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;</description>
      <category>프로그래밍/Web</category>
      <category>성능</category>
      <category>웹</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/74</guid>
      <comments>https://black7375.tistory.com/74#entry74comment</comments>
      <pubDate>Sun, 19 Apr 2020 15:54:31 +0900</pubDate>
    </item>
    <item>
      <title>[스압/데이터주의] 웹 최적화 방식 모음 - 1. 다운로드</title>
      <link>https://black7375.tistory.com/73</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/72&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 0. 전반적 원칙과 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/73&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 1. 다운로드(현재)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/74&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 2. 파싱 및 렌더링 트리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/79&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3. Layout 및 렌더링&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/80&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3.3 UX 트릭&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/81&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 4. 로드 후&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/82&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 5. 빌드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 다운로드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자(End-user) 응답시간의 80%는 초기 로딩부분에서 소요된다. 그 중 대부분의 시간은 모든 페이지 구성요소(images, syltesheets, scripts 등)의 다운로드에 소요된다.&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~4가지의 기준으로 나누어볼 수 있다.&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;h3 data-ke-size=&quot;size23&quot;&gt;1.1 용량 줄이기&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: #333333;&quot;&gt;필요한 데이터 양이 초기 혼잡 윈도우(일반적으로 14.6 KB 압축)를 초과하면 서버와 사용자 브라우저 간에 추가 왕복이 필요하기도 하다.&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;&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;1.1.1 디자인 단순화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;개요&lt;/span&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;b&gt;분류&lt;/b&gt;: Content&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;간단히 Dom 요소(element)를 줄이자고 생각해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 페이지는 다운로드시 용량이 더 커지며 Javascript에서 DOM 엑세스 속도도 느려지게 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 이벤트 핸들러를 추가할 때 500 VS 5000개의 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;보통 다음을 넘지 않는 것이 권장사항이다. [&lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/audits/dom-size&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Uses An Excessive DOM Size&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DOM 트리 노드: 1500&lt;/li&gt;
&lt;li&gt;최대 깊이: 32&lt;/li&gt;
&lt;li&gt;자식노드를 가지는 부모노드: 60&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: #333333;&quot;&gt;&lt;a href=&quot;https://yuiblog.com/blog/2007/01/04/performance-research-part-2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Browser Cache Usage - Exposed!&lt;/a&gt; 를 보면 40-60% 의 방문자가 브라우저 캐쉬의 혜택을 보지 못한다고 한다. 따라서 static 파일이라고 해도 그 수를 줄이는 것이 방문자에게 체감속도를 높이는 방법이다.&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;span style=&quot;color: #333333;&quot;&gt;DOM 요소의 수는 웹콘솔에 다음과 같이 입력하면 쉽게 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1584933077018&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;document.getElementsByTagName('*').length&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;레이아웃을 만들기 위해 DOM 요소를 남용했을 수도 있다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 옛날에는 레이아웃을 위한 CSS가 없거나 제대로 적용되지 않는 브라우저가 많았기 때문에 &amp;lt;table&amp;gt;을 사용했었는데 중첩적으로 사용해야 했기 때문에 DOM 요소는 늘어날 수 밖에 없었다.&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://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox&quot;&gt;Flexbox&lt;/a&gt;나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Grids&quot;&gt;Grid&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같이 매우 편리한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout&quot;&gt;CSS Layout&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;b&gt;+. 이외의 &amp;lt;table&amp;gt; 태그의 문제점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;table&amp;gt; 태그는 전체가 하나의 객체이기 때문에 모든 셀(cell)이 로딩되어야만 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;div&amp;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;안드로이드나 IOS의 경우 깊이를 낮추기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.android.com/training/constraint-layout?hl=ko&quot;&gt;Constraint Layout&lt;/a&gt;이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html&quot;&gt;Auto Layout&lt;/a&gt;을 사용하는데 성능에 좋다.[&lt;a href=&quot;https://android.jlelse.eu/constraint-layout-performance-870e5f238100&quot;&gt;Constraint Layout performance&lt;/a&gt;(&lt;a href=&quot;https://abandonia.tistory.com/1&quot;&gt;번역&lt;/a&gt;), &lt;a href=&quot;https://academy.realm.io/kr/posts/exploring-new-android-layouts/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;안드로이드의 새로운 레이아웃 탐구서&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://blog.unsignedusb.com/2017/05/android-layout-measure-linearlayout-vs.html&quot;&gt;안드로이드 Layout별 성능 비교&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2018/220&quot;&gt;High Performace Layout&lt;/a&gt;(&lt;a href=&quot;https://github.com/hcn1519/TILMemo/issues/67&quot;&gt;요약1&lt;/a&gt;, &lt;a href=&quot;https://velog.io/@dev-yong/WWDC-High-Performance-Auto-Layout&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;요약2&lt;/a&gt;),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.researchgate.net/publication/2615412_The_Cassowary_Linear_Arithmetic_Constraint_Solving_Algorithm&quot;&gt;The&amp;nbsp;Cassowary&amp;nbsp;Linear&amp;nbsp;Arithmetic&amp;nbsp;Constraint&amp;nbsp;Solving&amp;nbsp;Algorithm&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;653&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8izfE/btqXYZKBCjY/Niq8I4kpSwgBGta4Dmmvh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8izfE/btqXYZKBCjY/Niq8I4kpSwgBGta4Dmmvh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8izfE/btqXYZKBCjY/Niq8I4kpSwgBGta4Dmmvh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8izfE%2FbtqXYZKBCjY%2FNiq8I4kpSwgBGta4Dmmvh1%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;633&quot; height=&quot;653&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;653&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tiagomnunesdev.medium.com/constraint-layout-vs-flex-layout-no-android-com-beagle-612ada1ecb01&quot;&gt;Flexbox&amp;nbsp;Layout&amp;nbsp;vs&amp;nbsp;Constraint&amp;nbsp;Layout&amp;nbsp;no&amp;nbsp;Android&amp;nbsp;com&amp;nbsp;Beagle&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;제약(Constraint)을 이용하는게 Flexbox방식보다 일반적으로 낫다는 듯? [&lt;a href=&quot;https://github.com/google/flexbox-layout/issues/173&quot;&gt;constraintlayout vs flexbox-layout&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;몇몇 Constraint 관련 프로젝트들 소개.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JS:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/IjzerenHein/autolayout.js&quot;&gt;autolayout.js&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/IjzerenHein/kiwi.js/&quot;&gt;kiwi.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;C++:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/nucleic/kiwi&quot;&gt;kiwi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rust:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/dylanede/cassowary-rs&quot;&gt;Cassowary-rs&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/konstantindt/rust-cassowary&quot;&gt;rust-cassowary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Swift:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/nangege/Cassowary&quot;&gt;Cassowary&lt;/a&gt;&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;Constraint Layout의 적응형을 찾아봤는데 ORCSolver의 알고리즘이 가장 나은 편인 듯 하다. [&lt;a href=&quot;https://dl.acm.org/doi/10.1145/3313831.3376610&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ORCSolver: An Efficient Solver for Adaptive GUI Layout with OR-Constraints&lt;/a&gt;(&lt;a href=&quot;https://github.com/YueJiang-nj/ORCSolver-CHI2020&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github&lt;/a&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;1.1.2 가벼운 라이브러리와 모듈&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt; C&lt;/span&gt;ontent&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;a href=&quot;https://www.mikeperham.com/2016/02/09/kill-your-dependencies/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kill Your Dependencies&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;b&gt;측정방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/&quot;&gt;Github&lt;/a&gt;나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.jsdelivr.com/&quot;&gt;jsDelivr&lt;/a&gt;에서 min을 기준으로 확인해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;앞서 소개한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/webpack-contrib/webpack-bundle-analyzer&quot;&gt;Webpack Bundle Analyzer&lt;/a&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 style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://jquery.com/&quot;&gt;jQuery&lt;/a&gt;를 사용한다면 &lt;a href=&quot;http://youmightnotneedjquery.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;바닐라로 대체&lt;/a&gt;하거나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/kenwheeler/cash&quot;&gt;Cash&lt;/a&gt;(cash-dom, 타입스크립트도 잘 지원), &lt;a href=&quot;https://github.com/therealpineda/dom_helper&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DOM Helper&lt;/a&gt; /&lt;a href=&quot;https://github.com/finom/bala&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;bala&lt;/a&gt;($ 셀렉터만 있는 라이브러리)을 이용할 수 있다. &lt;a href=&quot;https://ko.reactjs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React&lt;/a&gt;라면 &lt;a href=&quot;https://preactjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Preact&lt;/a&gt; 또는 &lt;a href=&quot;https://vuejs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue&lt;/a&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://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt;이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://get.foundation/&quot;&gt;Foundation&lt;/a&gt;을 사용하기 보다&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://bulma.io/&quot;&gt;Bulma&lt;/a&gt;,&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://picturepan2.github.io/spectre/&quot;&gt;Spectre&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;더 가벼운 것을 원한다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://purecss.io/&quot;&gt;Pure CSS&lt;/a&gt;나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://getskeleton.com/&quot;&gt;Skeleton&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;a href=&quot;https://brunch.co.kr/@khross3701/9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;매개변수를 수정&lt;/a&gt;하거나, &lt;a href=&quot;https://github.com/paulirish/lite-youtube-embed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lite-youtube-embed&lt;/a&gt;, &lt;a href=&quot;https://github.com/justinribeiro/lite-youtube&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lite-youtube&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;b&gt;- 필요한 함수만&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1586020065068&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import _ from 'lodash';

_.array(...);
_.object(...);&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;pre id=&quot;code_1586020098156&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import array from 'lodash/array';
import object from 'lodash/fp/object';

array(...);
object(...);&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;h4 data-ke-size=&quot;size20&quot;&gt;1.1.3 중복 스크립트 제거&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;Javascript&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;span style=&quot;color: #333333;&quot;&gt;이 경우 중복 스크립트는 불필요한 HTTP 요청을 생성하고 JavaScript 실행을 낭비하여 성능을 저하시킨다.&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;불필요한 HTTP 요청은 구형 Internet Explorer에서는 발생하지만 최신 브라우저들에서는 발생하지 않는다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;구형 Internet Explorer에서 외부 스크립트가 두 번 포함되고 캐시 할 수없는 경우 페이지로드 중에 두 개의 HTTP 요청이 생성된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;스크립트가 캐시 가능하더라도 사용자가 페이지를 다시로드하면 추가 HTTP 요청이 발생한다는 것.&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;불필요한 HTTP 요청을 생성하는 것 외에도 스크립트를 여러 번 평가하는 데 시간이 낭비된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 중복 JavaScript 실행은 스크립트가 캐시 가능한지 여부에 관계없이 모두에서 발생한다.&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;YDN의 글에 따르면 미국의 상위 10개 사이트 중 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;b&gt;측정방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gtmetrix를 이용해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077020&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const scripts = document.getElementsByTagName(&quot;script&quot;);
const scriptsObj = [...scripts].map(script =&amp;gt; script.src)
  .filter(src =&amp;gt; src !== &quot;&quot;)
  .reduce((obj, value) =&amp;gt; {
    if (obj.hasOwnProperty(value)) {
      obj[value] = obj[value] + 1;
    } else {
      obj[value] = 0;
    }
    return obj;
  }, {});
Object.keys(scriptsObj).forEach(key =&amp;gt; {
  if (scriptsObj[key] &amp;gt; 0) delete scriptsObj[key];
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 웹콘솔에 입력해보아도 &amp;lt;script&amp;gt;의 중복된 갯수를 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;&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;pre id=&quot;code_1584933077021&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script type = &quot;text / javascript&quot;src = &quot;menu_1.0.17.js&quot;&amp;gt; &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;PHP의 대안은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;insertScript&lt;/span&gt;이라는 함수를 만드는 것 이다.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077021&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;? php insertScript ( &quot;menu.js&quot;)?&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;&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;자주 사용하는 함수들은 모듈로 묶어 관리하고, CSS는 SCSS를 사용하면 변수와 믹스인을 사용하여 역시 중복을 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1586019973835&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// foo.js
function filter() { ... }
function map() { ... }

filter();
map();


// bar.js
function filter() { ... }
function find() { ... }

filter();
find();&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;pre id=&quot;code_1586020006527&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// utils.js
export function find() { ... }
export function filter() { ... }
export function map() { ... }


// foo.js
import {filter, map} from 'utils.js'

filter();
map();


// bar.js
import {filter, find} from 'utils.js'

filter();
find();&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;h4 data-ke-size=&quot;size20&quot;&gt;1.1.4 JavaScript 및 CSS등 소스 축소&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;Javascript, CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;축소(Minification)는 코드에서 불필요한 문자를 제거하여 크기를 줄이고 로드 시간을 개선하는 방법이다.&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의 경우 다운로드 한 파일의 크기가 줄어들기&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;난독화(Obfuscation)는 소스 코드에 적용 할 수 있는 또 다른 최적화.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;미국의 상위 10 개 웹 사이트를 대상으로 한 설문 조사에 따르면 축소처리(21%)에 비해 난독처리(25%)의 효율이 좋았다고 한다.&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맹글링(Mangling) 같은 기법을 사용해 최적화를 하는데 최소화보다 복잡하므로 난독화 단계 자체로 인해 버그가 발생할 가능성도 있다는 점은 고려대상.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;function_long_long_name을 fn1 처럼 만들어주어야 하니까.&lt;/p&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;lt;script&amp;gt; 및 &amp;lt;style&amp;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;JavaScript 및 CSS의 사용 및 크기가 증가함에 따라 코드를 축소하여 비용을 절약 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;a href=&quot;https://blog.logrocket.com/uglify-vs-babel-minify-vs-terser-a-mini-battle-royale/&quot;&gt;Uglify&amp;nbsp;vs.&amp;nbsp;Babel-minify&amp;nbsp;vs.&amp;nbsp;Terser:&amp;nbsp;A&amp;nbsp;mini&amp;nbsp;battle&amp;nbsp;royale&lt;/a&gt;라는 글에 따르면 [다음 레포도 참고, &lt;a href=&quot;https://github.com/privatenumber/minification-benchmarks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JS&amp;nbsp;minification&amp;nbsp;benchmarks&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1766&quot; data-origin-height=&quot;698&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmCH6X/btqXb1hdDFl/em3oqSrPgxvrmGKKY9etbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmCH6X/btqXb1hdDFl/em3oqSrPgxvrmGKKY9etbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmCH6X/btqXb1hdDFl/em3oqSrPgxvrmGKKY9etbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmCH6X%2FbtqXb1hdDFl%2Fem3oqSrPgxvrmGKKY9etbK%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;1766&quot; height=&quot;698&quot; data-origin-width=&quot;1766&quot; data-origin-height=&quot;698&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;terser의 성능이 상당히 좋았다.&lt;/p&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의 경우&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://goalsmashers.github.io/css-minification-benchmark/&quot;&gt;CSS Minification Benchmark&lt;/a&gt;에 따르면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/mattbasta/crass&quot;&gt;Crass&lt;/a&gt;나&amp;nbsp;&lt;a href=&quot;https://cssnano.co/&quot;&gt;CSS Nano&lt;/a&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/leeoniya/dropcss&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DropCSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://github.com/uncss/uncss&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;UnCSS&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/purifycss/purifycss&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;PurifyCSS&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;Webpack용 플러그인으로&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/webpack-contrib/terser-webpack-plugin&quot;&gt;Terser Webpack Plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NMFR/optimize-css-assets-webpack-plugin&quot;&gt;Optimize&amp;nbsp;CSS&amp;nbsp;Assets&amp;nbsp;Webpack&amp;nbsp;Plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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에서 작동하는 압축기를 찾아보면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/kangax/html-minifier&quot;&gt;HTMLMinifier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;SVG:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/svg/svgo&quot;&gt;SVGO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;JSON:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/ramtinsoltani/json-mangler&quot;&gt;JSON Mangler&lt;/a&gt;,&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/getify/JSON.minify/tree/node&quot;&gt;JSON-minify&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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://black7375.tumblr.com/post/180878742065/%EC%9B%B9%EC%86%8C%EC%8A%A4-%EC%95%95%EC%B6%95&quot;&gt;https://black7375.tumblr.com/post/180878742065/%EC%9B%B9%EC%86%8C%EC%8A%A4-%EC%95%95%EC%B6%95&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1638182480442&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;웹소스 압축&quot; data-og-description=&quot;거의다 만들고 테스트 중인데, 할 짓이 없어서 압축하는 거나 찾아봤다. 1. HTML. https://rankseotools.com/html-compressor/ https://htmlcompressor.com/compressor/ 2....&quot; data-og-host=&quot;black7375.tumblr.com&quot; data-og-source-url=&quot;https://black7375.tumblr.com/post/180878742065/%EC%9B%B9%EC%86%8C%EC%8A%A4-%EC%95%95%EC%B6%95&quot; data-og-url=&quot;https://black7375.tumblr.com/post/180878742065/%EC%9B%B9%EC%86%8C%EC%8A%A4-%EC%95%95%EC%B6%95&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/180878742065/%EC%9B%B9%EC%86%8C%EC%8A%A4-%EC%95%95%EC%B6%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tumblr.com/post/180878742065/%EC%9B%B9%EC%86%8C%EC%8A%A4-%EC%95%95%EC%B6%95&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;웹소스 압축&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;거의다 만들고 테스트 중인데, 할 짓이 없어서 압축하는 거나 찾아봤다. 1. HTML. https://rankseotools.com/html-compressor/ https://htmlcompressor.com/compressor/ 2....&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;black7375.tumblr.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;JS 코드를 극도로 줄여야 하는 상황이라면 &lt;a href=&quot;https://github.com/lifthrasiir/roadroller&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Roadroller&lt;/a&gt;같은&amp;nbsp;팩커를 찾아보아도 좋다.&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;1.1.5 웹폰트 압축 및 서브셋&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Font&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹폰트 관련 확장기능에 잠시 손을 댄적이 있다보니 관련글도 많이 읽어보고, 실제로 적용도 해봤었다 ㅎㅎ[&lt;a href=&quot;https://d2.naver.com/helloworld/4969726&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹 폰트 사용과 최적화의 최근 동향&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹폰트 최적화&lt;/a&gt;, &lt;a href=&quot;https://wit.nts-corp.com/2017/02/13/4258&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹폰트&amp;nbsp;사용하기&amp;nbsp;(웹폰트&amp;nbsp;101)&lt;/a&gt;]&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;span style=&quot;color: #333333;&quot;&gt;심지어 Noto Sans CJK는 44,683자를 포함하여 15.7MB에 달한다.&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메가만 되도 엄청나게 커다란 용량이니 당연히, 줄이는 것이 필요하며 웹폰트는 CSSOM을 생성하는데 필요하므로 렌더링을 차단하는 현상이 일어난다.&lt;/p&gt;
&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;- Font Face&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@font-face를 통해 폰트 패밀리 명을 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 성능과 관계된 것 위주로 알아보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1586448998001&quot; class=&quot;css&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;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@font-face {
  font-family: NanumSquareWeb;
  src: url(NanumSquareR.eot); /* IE 호환성 보기 */
  src: local(NanumSquareR),
       local(NanumSquare),
       url(NanumSquareR.eot?#iefix) format('embedded-opentype'), /* IE 6 ~ 8 */
       url(NanumSquareR.woff2) format('woff2'),
       url(NanumSquareR.woff) format('woff'),
       url(NanumSquareR.ttf) format('truetype'),
       url(NanumSquareR.svg#NanumSquareR) format('svg'); /* 구 모바일 브라우저 */
  unicode-range: U+0-10FFFF;
}&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;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;- src&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;http://www.w3.org/TR/css3-fonts/#src-desc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;src&lt;/a&gt;에서 local을 사용하면 컴퓨터에 설치된 글꼴로 로드하므로 빠르다.&lt;/li&gt;
&lt;li&gt;url을 설정할 때 format을 사용하면 지원가능한 파일만 다운로드 받으므로 빠르다.&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;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;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Embedded_OpenType&quot;&gt;eot&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(IE 전용),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/TrueType&quot;&gt;ttf&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.w3.org/TR/WOFF2/&quot;&gt;woff2&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.w3.org/Fonts/WG/wiki/images/1/19/WOFF4ATypI.pdf&quot;&gt;woff&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://caniuse.com/svg-fonts&quot;&gt;svg&lt;/a&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;이중 SVG는 거의 사용되지 않으며, eot와 ttf는 기본적으로 압축되지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VmIiX/btqXobQM5nA/7YKts2Rh8NK5t3zmd8G960/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VmIiX/btqXobQM5nA/7YKts2Rh8NK5t3zmd8G960/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VmIiX/btqXobQM5nA/7YKts2Rh8NK5t3zmd8G960/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVmIiX%2FbtqXobQM5nA%2F7YKts2Rh8NK5t3zmd8G960%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;1280&quot; height=&quot;467&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;eot와 ttf는 gzip과 같은 압축을 설정해야 한다.&lt;/li&gt;
&lt;li&gt;Zopfli 압축을 통해 eot, ttf, woff를 5%정도 더 압축 가능&lt;/li&gt;
&lt;li&gt;woff2의 압축률이 가장 높다(30% 이상)[&lt;a href=&quot;https://www.w3.org/TR/WOFF20ER/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WOFF 2.0 Evaluation Report&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;특정 플랫폼에서 필요하지 않은 &lt;a href=&quot;https://en.wikipedia.org/wiki/Font_hinting&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;힌트&lt;/a&gt;나 &lt;a href=&quot;https://en.wikipedia.org/wiki/Kerning&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;커닝&lt;/a&gt;같은 메타데이터에 대해서 최적화 할 수도&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;b&gt;- unicode-range 및 서브셋&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.w3.org/TR/css3-fonts/#descdef-unicode-range&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;unicode-range&lt;/a&gt;를 이용하면 범위 구분값 목록을 지정할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 코드 포인트: 단일 문자를 지정(예: U+416)&lt;/li&gt;
&lt;li&gt;간격 범위: 범위의 시작과 끝 코드 포인트 지정(예: U+400-4ff)&lt;/li&gt;
&lt;li&gt;와일드 카드 범위: ?문자를 이용해 임의의 16진수를 나타냄(예: U+4??)&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;중요한 점은 각 unicode-range마다 폰트파일을 따로 생성해줘야 한다는것.&lt;/p&gt;
&lt;pre id=&quot;code_1586438153086&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* NanumSquareR.woff 원본: 3MB */
@font-face {
  font-family: NanumSquareWeb;
  src: url(NanumSquareR-Arab.woff) format('woff'); /* 나눔스퀘어 아랍어 부분: 15KB */
  unicode-range: U+06??; /* 아랍어 */
}
@font-face {
  font-family: NanumSquareWeb;
  src: url(NanumSquareR-Cambodia.woff) format('woff'); /* 나눔스퀘어 아랍어 부분: 7KB */
  unicode-range: U+1780-17FF; /* 캄보디아어 */
}&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;그럼 알파벳 26자보다 훨씬 크기가 큰 한글은 어떻게, 얼마나 나누는 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 나눔고딕은 한글 11,172자를 포함한다.&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;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;931&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5Nlft/btqW1stbL1X/kp2LQtzukWZfkoh3gD5ntK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5Nlft/btqW1stbL1X/kp2LQtzukWZfkoh3gD5ntK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5Nlft/btqW1stbL1X/kp2LQtzukWZfkoh3gD5ntK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5Nlft%2FbtqW1stbL1X%2Fkp2LQtzukWZfkoh3gD5ntK%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;1280&quot; height=&quot;931&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;931&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://ko.wikipedia.org/wiki/KS_X_1001&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;KS X 1001&lt;/a&gt;은 &quot;정보 교환용 부호계 (한글 및 한자)&quot;라고 하여 자주 쓰이는 글자들을 모아놓았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중 한글은 2350자.&lt;/p&gt;
&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;http://koreantypography.org/blog/archives/4615&quot;&gt;노민지, 윤민구. KS 코드 완성형 한글의 추가 제안&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(224자)를 참고해보아도 좋다. [&lt;/span&gt;&lt;a href=&quot;https://github.com/black7375/Readable_Font/blob/master/Resource/font/korean2574.txt&quot;&gt;총2754자&lt;/a&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;포맷과 subset 변환은 &lt;a href=&quot;https://github.com/behdad/fonttools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;pyftsubset&lt;/a&gt;을 사용하면 된다. [&lt;a href=&quot;https://github.com/black7375/Readable_Font/blob/master/Resource/font/fontsubset.sh&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fontsubset.sh 명령어&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나눔고딕 기준으로 &lt;a href=&quot;https://github.com/black7375/Readable_Font/blob/master/Resource/font/otf/NanumGothic.otf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2.2MB&lt;/a&gt;에서 &lt;a href=&quot;https://github.com/black7375/Readable_Font/blob/master/Resource/font/subset-fonts/NanumGothic.woff2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;267KB&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;a href=&quot;https://googlefonts.github.io/korean/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Google Fonts + 한국어 소개&lt;/a&gt;, &lt;a href=&quot;https://m.etnews.com/20180409000255?obj=Tzo4OiJzdGRDbGFzcyI6Mjp7czo3OiJyZWZlcmVyIjtOO3M6NzoiZm9yd2FyZCI7czoxMzoid2ViIHRvIG1vYmlsZSI7fQ%3D%3D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구글,&amp;nbsp;한글&amp;nbsp;글꼴&amp;nbsp;공식&amp;nbsp;지원...&amp;nbsp;머신러닝으로&amp;nbsp;용량&amp;nbsp;문제&amp;nbsp;해결&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I99x2/btqWWtGsJb4/cTi0qL4X5jkC5BTORfgUy1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I99x2/btqWWtGsJb4/cTi0qL4X5jkC5BTORfgUy1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I99x2/btqWWtGsJb4/cTi0qL4X5jkC5BTORfgUy1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI99x2%2FbtqWWtGsJb4%2FcTi0qL4X5jkC5BTORfgUy1%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;700&quot; height=&quot;467&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Google Fonts는 머신 러닝에 기반을 둔 최적화 기술을 통해 한글 폰트를 동적으로 분할 다운로드합니다. &lt;br /&gt;웹상의 방대한 한국어 문서를 분석한 결과, Google은 주제에 따라 사용되는 글자의 패턴을 발견하고, 패턴에 따라 한글 폰트에 포함된 17,388개의 글리프를 100여 가지 그룹으로 나누었습니다. 여기에 Google Fonts는 사용자가 웹 페이지를 불러올 때, 폰트 전체를 다운로드 하는 대신 내용을 표시하는 데 꼭 필요한 몇 가지 그룹만을 선택적으로 다운로드 하는 방식으로 폰트를 제공합니다. 이 기술을 적용한 Google Font를 사용하면 보다 빠르게 폰트 전체를 다운로드한 것과 다름없는 페이지를 제공할 수 있습니다. &lt;br /&gt;또한 Google Fonts API의 사이트 간 캐싱(cross-site caching)을 통해 해당 폰트가 여러 웹사이트에서 사용될수록 전체 다운로드 시간은 줄어들고, 한글 웹 폰트를 둘러싼 사용자 경험은 그만큼 개선될 것입니다.&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;a href=&quot;https://fonts.googleapis.com/css?family=Nanum+Gothic:400&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;나눔고딕&lt;/a&gt;을 예로 들면&lt;/p&gt;
&lt;pre id=&quot;code_1586448927120&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* [0] */
@font-face {
  font-family: 'Nanum Gothic';
  font-style: normal;
  font-weight: 400;
  src: local('NanumGothic'), url(https://fonts.gstatic.com/s/nanumgothic/v17/PN_3Rfi-oW3hYwmKDpxS7F_z-7rJxHVIsPV5MbNO2rV2_va-Nv6p.0.woff2) format('woff2');
  unicode-range: U+f9ca-fa0b, U+ff03-ff05, U+ff07, U+ff0a-ff0b, U+ff0d-ff19, U+ff1b, U+ff1d, U+ff20-ff5b, U+ff5d, U+ffe0-ffe3, U+ffe5-ffe6;
}
/* [1] */
@font-face {
  font-family: 'Nanum Gothic';
  font-style: normal;
  font-weight: 400;
  src: local('NanumGothic'), url(https://fonts.gstatic.com/s/nanumgothic/v17/PN_3Rfi-oW3hYwmKDpxS7F_z-7rJxHVIsPV5MbNO2rV2_va-Nv6p.1.woff2) format('woff2');
  unicode-range: U+f92f-f980, U+f982-f9c9;
}
/* [2] */
@font-face {
  font-family: 'Nanum Gothic';
  font-style: normal;
  font-weight: 400;
  src: local('NanumGothic'), url(https://fonts.gstatic.com/s/nanumgothic/v17/PN_3Rfi-oW3hYwmKDpxS7F_z-7rJxHVIsPV5MbNO2rV2_va-Nv6p.2.woff2) format('woff2');
  unicode-range: U+d723-d728, U+d72a-d733, U+d735-d748, U+d74a-d74f, U+d752-d753, U+d755-d757, U+d75a-d75f, U+d762-d764, U+d766-d768, U+d76a-d76b, U+d76d-d76f, U+d771-d787, U+d789-d78b, U+d78d-d78f, U+d791-d797, U+d79a, U+d79c, U+d79e-d7a3, U+f900-f909, U+f90b-f92e;
}
...
/* [117] */
@font-face {
  font-family: 'Nanum Gothic';
  font-style: normal;
  font-weight: 400;
  src: local('NanumGothic'), url(https://fonts.gstatic.com/s/nanumgothic/v17/PN_3Rfi-oW3hYwmKDpxS7F_z-7rJxHVIsPV5MbNO2rV2_va-Nv6p.117.woff2) format('woff2');
  unicode-range: U+d, U+48, U+7c, U+ac10, U+ac15, U+ac74, U+ac80, U+ac83, U+acc4, U+ad11, U+ad50, U+ad6d, U+adfc, U+ae00, U+ae08, U+ae4c, U+b0a8, U+b124, U+b144, U+b178, U+b274, U+b2a5, U+b2e8, U+b2f9, U+b354, U+b370, U+b418, U+b41c, U+b4f1, U+b514, U+b798, U+b808, U+b824-b825, U+b8cc, U+b978, U+b9d0, U+b9e4, U+baa9, U+bb3c, U+bc18, U+bc1c, U+bc30, U+bc84, U+bcf5, U+bcf8, U+bd84, U+be0c, U+be14, U+c0b0, U+c0c9, U+c0dd, U+c124, U+c2dd, U+c2e4, U+c2ec, U+c54c, U+c57c-c57d, U+c591, U+c5c5-c5c6, U+c5ed, U+c608, U+c640, U+c6b8, U+c6d4, U+c784, U+c7ac, U+c800-c801, U+c9c1, U+c9d1, U+cc28, U+cc98, U+cc9c, U+ccad, U+cd5c, U+cd94, U+cd9c, U+cde8, U+ce68, U+cf54, U+d0dc, U+d14c, U+d1a0, U+d1b5, U+d2f0, U+d30c, U+d310, U+d398, U+d45c, U+d50c, U+d53c, U+d560, U+d568, U+d589, U+d604, U+d6c4, U+d788;
}
/* [118] */
@font-face {
  font-family: 'Nanum Gothic';
  font-style: normal;
  font-weight: 400;
  src: local('NanumGothic'), url(https://fonts.gstatic.com/s/nanumgothic/v17/PN_3Rfi-oW3hYwmKDpxS7F_z-7rJxHVIsPV5MbNO2rV2_va-Nv6p.118.woff2) format('woff2');
  unicode-range: U+39, U+49, U+4d-4e, U+a0, U+ac04, U+ac1c, U+ac70, U+ac8c, U+acbd, U+acf5, U+acfc, U+ad00, U+ad6c, U+adf8, U+b098, U+b0b4, U+b294, U+b2c8, U+b300, U+b3c4, U+b3d9, U+b4dc, U+b4e4, U+b77c, U+b7ec, U+b85d, U+b97c, U+b9c8, U+b9cc, U+ba54, U+ba74, U+ba85, U+baa8, U+bb34, U+bb38, U+bbf8, U+bc14, U+bc29, U+bc88, U+bcf4, U+bd80, U+be44, U+c0c1, U+c11c, U+c120, U+c131, U+c138, U+c18c, U+c218, U+c2b5, U+c2e0, U+c544, U+c548, U+c5b4, U+c5d0, U+c5ec, U+c5f0, U+c601, U+c624, U+c694, U+c6a9, U+c6b0, U+c6b4, U+c6d0, U+c704, U+c720, U+c73c, U+c740, U+c744, U+c74c, U+c758, U+c77c, U+c785, U+c788, U+c790-c791, U+c7a5, U+c804, U+c815, U+c81c, U+c870, U+c8fc, U+c911, U+c9c4, U+ccb4, U+ce58, U+ce74, U+d06c, U+d0c0, U+d130, U+d2b8, U+d3ec, U+d504, U+d55c, U+d569, U+d574, U+d638, U+d654, U+d68c;
}
/* [119] */
@font-face {
  font-family: 'Nanum Gothic';
  font-style: normal;
  font-weight: 400;
  src: local('NanumGothic'), url(https://fonts.gstatic.com/s/nanumgothic/v17/PN_3Rfi-oW3hYwmKDpxS7F_z-7rJxHVIsPV5MbNO2rV2_va-Nv6p.119.woff2) format('woff2');
  unicode-range: U+20-22, U+27-2a, U+2c-38, U+3a-3b, U+3f, U+41-47, U+4a-4c, U+4f-5d, U+61-7b, U+7d, U+a1, U+ab, U+ae, U+b7, U+bb, U+bf, U+2013-2014, U+201c-201d, U+2122, U+ac00, U+ace0, U+ae30, U+b2e4, U+b85c, U+b9ac, U+c0ac, U+c2a4, U+c2dc, U+c774, U+c778, U+c9c0, U+d558;
}&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;CSS 제공또한 여러개를 하나로 묶어서 받을 수 있는 점은 요청수를 줄인다는 점에서 또 다른 강점.&lt;/p&gt;
&lt;pre id=&quot;code_1586462436687&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 href=&quot;https://fonts.googleapis.com/css2?family=Nanum+Gothic&amp;amp;family=Nanum+Gothic+Coding:wght@400;700&amp;amp;display=swap&quot; rel=&quot;stylesheet&quot;&amp;gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 나눔고딕 400, 나눔고딕 코딩 400과 700. 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;a href=&quot;https://github.com/black7375/font-range&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;font-range&lt;/a&gt;를 사용하면 구글 서브셋이나 미리 정의해놓은 유니코드 레인지로 서브셋 할 수 있다. (예: &lt;a href=&quot;https://github.com/orioncactus/pretendard/blob/e86c0024f631b0fed6b04ac0f5279d5e85dc430d/dynamic-subset.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pretendard&lt;/a&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;1.1.6 이미지 압축&lt;/h4&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;b&gt;분류:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Image&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;widthContent&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIQafj/btqXj7Vsgtj/t8hjLgOxIvTg1pTtX5hns1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIQafj/btqXj7Vsgtj/t8hjLgOxIvTg1pTtX5hns1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIQafj/btqXj7Vsgtj/t8hjLgOxIvTg1pTtX5hns1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIQafj%2FbtqXj7Vsgtj%2Ft8hjLgOxIvTg1pTtX5hns1%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;500&quot; height=&quot;370&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;370&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 압축을 할때 가장 큰 원칙은 &quot;괜찮게 보이는 가장 낮은 품질&quot;로 압축하는 것이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든&amp;nbsp;이미지에&amp;nbsp;대해&amp;nbsp;압축&amp;nbsp;품질을&amp;nbsp;가능한만큼&amp;nbsp;직접&amp;nbsp;튜닝하라.&lt;/li&gt;
&lt;li&gt;나머지는&amp;nbsp;가장&amp;nbsp;높은&amp;nbsp;성능을&amp;nbsp;얻기&amp;nbsp;위해&amp;nbsp;최적화를&amp;nbsp;자동화하라.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;GIF&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;PNG&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JPEG&lt;/b&gt;를 대상으로 아라보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- GIF&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.lcdf.org/gifsicle/&quot;&gt;Gifsicle&lt;/a&gt;가 좋아보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 Gifsicle에 포함된 프로젝트인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://kornel.ski/lossygif&quot;&gt;Giflossy&lt;/a&gt;의 설명에 따르면 다음과 같이 명령어를 실행하면 최적화 할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077026&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gifsicle -O3 --lossy=80 -o RESULT.gif IMAGE.gif&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;- PNG&lt;/b&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;http://optipng.sourceforge.net/&quot;&gt;optipng&lt;/a&gt;, 용량을 중요시하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://pngquant.org/&quot;&gt;pngquant&lt;/a&gt;가 좋다.[&lt;a href=&quot;https://pointlessramblings.com/posts/pngquant_vs_pngcrush_vs_optipng_vs_pngnq/&quot;&gt;pngquant vs pngcrush vs optipng vs pngnq&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://medium.com/open-pbs/experimenting-with-png-and-jpg-optimization-d1428e24928c&quot;&gt;Experimenting&amp;nbsp;with&amp;nbsp;PNG&amp;nbsp;and&amp;nbsp;JPG&amp;nbsp;Optimization&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 YDN에서 소개한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://pngcrush.com/&quot;&gt;pngcrush&lt;/a&gt;는 다음과 같이 실행할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077027&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pngcrush IMAGE.png -rem alla -reduce -brute RESULT.png&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pngquant는 손실 압축이었고, 무손실 압축을 찾는다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/google/zopfli&quot;&gt;Zopfli&lt;/a&gt;(&lt;a href=&quot;https://ariya.io/2016/06/using-zopfli-to-optimize-png-images&quot;&gt;방법1&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://teus.me/411&quot;&gt;방법2&lt;/a&gt;)나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.jonof.id.au/kenutils.html&quot;&gt;PNGOUT&lt;/a&gt;을 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zopfili는 deflate(zip, gzip 등)와 호환성을 보장하는 압축 알고리즘이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 색상 PNG 파일 최적화를 위해서 PLTE(팔렛트) 및 IDAT(이미지 데이터 섹션)과 관련해 최적화를 할 수도 있다. [&lt;a href=&quot;https://www.mjt.me.uk/posts/smallest-png/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;가장 작은 크기의 단색 256x256 PNG 파일, 어디서 봤을까?&lt;/a&gt;(&lt;a href=&quot;https://news.hada.io/topic?id=6432&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;b&gt;- JPEG&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPEG에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/mozilla/mozjpeg&quot;&gt;MozJPEG&lt;/a&gt;가 좋다.[&lt;a href=&quot;https://blarg.co.uk/blog/comparison-of-jpeg-lossless-compression-tools&quot;&gt;Comparison&amp;nbsp;of&amp;nbsp;JPEG&amp;nbsp;Lossless&amp;nbsp;Compression&amp;nbsp;Tools&lt;/a&gt;,&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://gist.github.com/sergejmueller/088dce028b6dd120a16e&quot;&gt;mozjpeg vs libjpeg-turbo&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 YDN의 소개에 나온&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://linux.die.net/man/1/jpegtran&quot;&gt;jpegtran&lt;/a&gt;은 다음처럼 실행가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077028&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;jpegtran -copy none -optimize -perfect IMAGE.jpg RESULT.jpg&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회전(rotation)과 같이 손실 없는 JPEG 작업을 수행하고 최적화를 위한 사용이 가능하며, 이미지들로부터의 다른 쓸모 없는 정보(EXIF 정보와 같은)와 코멘트(comments)를 제거할 수 있다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/google/guetzli&quot;&gt;Guetzli&lt;/a&gt;라고 구글이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://ai.googleblog.com/2017/03/announcing-guetzli-new-open-source-jpeg.html&quot;&gt;2017&lt;/a&gt;년에 발표한 인코더도 있는데&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.pixelz.com/blog/guetzli-mozjpeg-comparison/&quot;&gt;Google Guetzli vs MozJPEG: Why Google&amp;rsquo;s New JPEG Encoder Can&amp;rsquo;t Dethrone the Product Image King&lt;/a&gt;을 보면 품질은 좋으나 매우 느리다. 크기가 매우 크거나 작은 이미지가 아니라면 효율성이 낮기 때문에 쓰지 않는 것이 좋다. 단, 극도의 효율성을 위해서라면 크기가 큰 경우 MozJPEG을 사용한 후 같이 써도 좋은 모양. [&lt;a href=&quot;https://ariya.io/2017/03/squeezing-jpeg-images-with-guetzli&quot;&gt;Squeezing JPEG Images with Guetzli&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://medium.com/@vinhlh/image-compression-benchmarks-6653b3c56767&quot;&gt;Image&amp;nbsp;Compression&amp;nbsp;Benchmarks&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;JPEG의 경우 Progressive를 활성화시키는 것도 좋다.&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;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbqAYe/btqWXazRJHu/fe1BYs26eeZDlSjyjnDFCk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbqAYe/btqWXazRJHu/fe1BYs26eeZDlSjyjnDFCk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbqAYe/btqWXazRJHu/fe1BYs26eeZDlSjyjnDFCk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbqAYe%2FbtqWXazRJHu%2Ffe1BYs26eeZDlSjyjnDFCk%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;1280&quot; height=&quot;377&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;391&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bV90jU/btqXgpoySps/1XJLjiVnTBx2Vw91v9aPsK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bV90jU/btqXgpoySps/1XJLjiVnTBx2Vw91v9aPsK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bV90jU/btqXgpoySps/1XJLjiVnTBx2Vw91v9aPsK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbV90jU%2FbtqXgpoySps%2F1XJLjiVnTBx2Vw91v9aPsK%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;1280&quot; height=&quot;391&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;391&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;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;a href=&quot;https://www.bookofspeed.com/chapter5.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2-10%&lt;/a&gt;)&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;b&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;느린 디코딩(최대 3배)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- EXIF 제거&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Exif를 제거하는 것도 좋은 생각이다.[&lt;a href=&quot;https://www.makeuseof.com/tag/3-ways-to-remove-exif-metadata-from-photos-and-why-you-might-want-to/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What&amp;nbsp;Is&amp;nbsp;EXIF&amp;nbsp;Data?&lt;/a&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;a href=&quot;https://github.com/hMatoba/piexifjs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Piexifjs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/joshbuddy/exif-be-gone&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Exif be gone&lt;/a&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- NodeJS 바인딩&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;GIF:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/gifsicle-bin&quot;&gt;gifsicle-bin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PNG:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/imagemin-optipng&quot;&gt;imagemin-optipng&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/papandreou/node-pngquant&quot;&gt;node-pngquant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;JPEG:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/mozjpeg-bin&quot;&gt;mozjpeg-bin&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/guetzli-bin&quot;&gt;guetzli-bin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1.7 이미지, 영상 포맷&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;Image, Video&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;특히 비효율적인 것으로 유명한 GIF는 최적화의 여지가 크다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/vingle-tech-blog/stop-using-gif-as-animation-3c6d223fd35a&quot;&gt;https://medium.com/vingle-tech-blog/stop-using-gif-as-animation-3c6d223fd35a&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1584933077030&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a href=&quot;https://medium.com/vingle-tech-blog/stop-using-gif-as-animation-3c6d223fd35a&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/TUlmJ/hyFnZZ0g7h/G7TvAKAH6srup8X8rKke30/img.png?width=1200&amp;amp;height=533&amp;amp;face=0_0_1200_533,https://scrap.kakaocdn.net/dn/bRpzqq/hyFn0kiDU2/z7dqzfAmGKUwk2YvwbPgik/img.png?width=60&amp;amp;height=51&amp;amp;face=0_0_60_51,https://scrap.kakaocdn.net/dn/cxXnZI/hyFn9BxtCy/ujwEwhNomaqnoPs3hL5Cb1/img.png?width=60&amp;amp;height=32&amp;amp;face=0_0_60_32');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot; style=&quot;position: relative; flex-grow: 1; height: 130px; padding-left: 40px;&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;line-height: 1.6; color: #000000; font-size: 22px; padding-bottom: 10px; max-width: 467px; text-overflow: ellipsis; white-space: nowrap; margin: 0px; overflow: hidden; font-family: 'Noto Sans', 'Noto Sans KR';&quot; data-ke-size=&quot;size16&quot;&gt;GIF 사용을 멈춰주세요!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;line-height: normal; margin: 0px; max-width: 467px; text-overflow: ellipsis; overflow: hidden; font-family: 'Noto Sans DemiLight', sans-serif; font-size: 14px; font-weight: 300; font-style: normal; font-stretch: normal; letter-spacing: normal; color: #909090; max-height: 42px; -webkit-line-clamp: 2; -webkit-box-orient: vertical; display: -webkit-box;&quot; data-ke-size=&quot;size16&quot;&gt;IMO: Converting video to gif is a terrible hack of convenience&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;line-height: 1.6; margin: 0px; position: absolute; bottom: -8px; font-family: AvenirNext; font-size: 14px; color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;이외 이미지 최적화와 관련된 내용은 다음 글에서 잘 설명해주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.html5rocks.com/ko/tutorials/speed/img-compression/&quot;&gt;https://www.html5rocks.com/ko/tutorials/speed/img-compression/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1584933077030&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a href=&quot;https://www.html5rocks.com/ko/tutorials/speed/img-compression/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c05oqd/hyFodxbX87/tt3Td1knYRr5BV71Pk7WD1/img.png?width=200&amp;amp;height=200&amp;amp;face=40_54_139_163,https://scrap.kakaocdn.net/dn/fzC0M/hyFmFB5spJ/QFDSp7YekyCuBL51kXQ2U1/img.jpg?width=384&amp;amp;height=256&amp;amp;face=0_0_384_256,https://scrap.kakaocdn.net/dn/dofAoa/hyFmL99B96/R38khnobySCgaAba1FP37k/img.jpg?width=497&amp;amp;height=373&amp;amp;face=0_0_497_373');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot; style=&quot;position: relative; flex-grow: 1; height: 130px; padding-left: 40px;&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;line-height: 1.6; color: #000000; font-size: 22px; padding-bottom: 10px; max-width: 467px; text-overflow: ellipsis; white-space: nowrap; margin: 0px; overflow: hidden; font-family: 'Noto Sans', 'Noto Sans KR';&quot; data-ke-size=&quot;size16&quot;&gt;Image Compression for Web Developers - HTML5 Rocks&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;line-height: normal; margin: 0px; max-width: 467px; text-overflow: ellipsis; overflow: hidden; font-family: 'Noto Sans DemiLight', sans-serif; font-size: 14px; font-weight: 300; font-style: normal; font-stretch: normal; letter-spacing: normal; color: #909090; max-height: 42px; -webkit-line-clamp: 2; -webkit-box-orient: vertical; display: -webkit-box;&quot; data-ke-size=&quot;size16&quot;&gt;Reduce your page size by looking under the hood of image compression.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;line-height: 1.6; margin: 0px; position: absolute; bottom: -8px; font-family: AvenirNext; font-size: 14px; color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;www.html5rocks.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1584933077030&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/de3hAj/hyFn5zvWhT/9n8ElksiTRfEjHC6SGXczK/img.png?width=600&amp;amp;height=600&amp;amp;face=0_0_600_600,https://scrap.kakaocdn.net/dn/b87NLQ/hyFodqNhFa/zYsY91XDzaB24GAR9XsByk/img.png?width=600&amp;amp;height=600&amp;amp;face=0_0_600_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot; style=&quot;position: relative; flex-grow: 1; height: 130px; padding-left: 40px;&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;line-height: 1.6; color: #000000; font-size: 22px; padding-bottom: 10px; max-width: 467px; text-overflow: ellipsis; white-space: nowrap; margin: 0px; overflow: hidden; font-family: 'Noto Sans', 'Noto Sans KR';&quot; data-ke-size=&quot;size16&quot;&gt;Image file type and format guide&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;line-height: normal; margin: 0px; max-width: 467px; text-overflow: ellipsis; overflow: hidden; font-family: 'Noto Sans DemiLight', sans-serif; font-size: 14px; font-weight: 300; font-style: normal; font-stretch: normal; letter-spacing: normal; color: #909090; max-height: 42px; -webkit-line-clamp: 2; -webkit-box-orient: vertical; display: -webkit-box;&quot; data-ke-size=&quot;size16&quot;&gt;In this guide, we'll cover the image file types generally supported by web browsers, and provide insights that will help you select the most appropriate formats to use for your site's imagery.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;line-height: 1.6; margin: 0px; position: absolute; bottom: -8px; font-family: AvenirNext; font-size: 14px; color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&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;&lt;b&gt;- 영상&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/Media/Formats/%EB%B9%84%EB%94%94%EC%98%A4%EC%BD%94%EB%8D%B1&quot;&gt;https://developer.mozilla.org/ko/docs/Web/Media/Formats/%EB%B9%84%EB%94%94%EC%98%A4%EC%BD%94%EB%8D%B1&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1584933077030&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/Media/Formats/%EB%B9%84%EB%94%94%EC%98%A4%EC%BD%94%EB%8D%B1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d2Su32/hyFn6yrAcd/H4EnTL67HO99hMVbnG06rk/img.png?width=600&amp;amp;height=600&amp;amp;face=0_0_600_600,https://scrap.kakaocdn.net/dn/lY9Bg/hyFmLJrRWs/xqFFLkoCxpEj6lroggw3g1/img.png?width=600&amp;amp;height=600&amp;amp;face=0_0_600_600,https://scrap.kakaocdn.net/dn/5RIph/hyFnZMQlh7/RckffdejMrvKKLWstOSdh0/img.jpg?width=1024&amp;amp;height=576&amp;amp;face=0_0_1024_576');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot; style=&quot;position: relative; flex-grow: 1; height: 130px; padding-left: 40px;&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;line-height: 1.6; color: #000000; font-size: 22px; padding-bottom: 10px; max-width: 467px; text-overflow: ellipsis; white-space: nowrap; margin: 0px; overflow: hidden; font-family: 'Noto Sans', 'Noto Sans KR';&quot; data-ke-size=&quot;size16&quot;&gt;웹 비디오 코덱 가이드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;line-height: normal; margin: 0px; max-width: 467px; text-overflow: ellipsis; overflow: hidden; font-family: 'Noto Sans DemiLight', sans-serif; font-size: 14px; font-weight: 300; font-style: normal; font-stretch: normal; letter-spacing: normal; color: #909090; max-height: 42px; -webkit-line-clamp: 2; -webkit-box-orient: vertical; display: -webkit-box;&quot; data-ke-size=&quot;size16&quot;&gt;이 문서는 웹에서 흔히 볼 수 있는 비디오 코덱을 소개하고 각각의 기능과 호환성, 사용성에 대해 설명하고 여러분에게 필요한 적절한 코덱을 찾는 법을 안내합니다. MPEG-2 Part 2&amp;nbsp;ITU가 설계한 H.262를 참조하여 MPEG-2 스펙에서 정의한 비디오 포맷이며입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;line-height: 1.6; margin: 0px; position: absolute; bottom: -8px; font-family: AvenirNext; font-size: 14px; color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Audio_codecs&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Audio_codecs&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1584933077031&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Audio_codecs&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ljpul/hyFn2JyTmX/D2c08QlhtQW1I4Gr5dXSf1/img.png?width=600&amp;amp;height=600&amp;amp;face=0_0_600_600,https://scrap.kakaocdn.net/dn/fe4N5/hyFn9onkK5/K0ht1qCv3TQcVAIlqzzyek/img.png?width=600&amp;amp;height=600&amp;amp;face=0_0_600_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot; style=&quot;position: relative; flex-grow: 1; height: 130px; padding-left: 40px;&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;line-height: 1.6; color: #000000; font-size: 22px; padding-bottom: 10px; max-width: 467px; text-overflow: ellipsis; white-space: nowrap; margin: 0px; overflow: hidden; font-family: 'Noto Sans', 'Noto Sans KR';&quot; data-ke-size=&quot;size16&quot;&gt;Web audio codec guide&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;line-height: normal; margin: 0px; max-width: 467px; text-overflow: ellipsis; overflow: hidden; font-family: 'Noto Sans DemiLight', sans-serif; font-size: 14px; font-weight: 300; font-style: normal; font-stretch: normal; letter-spacing: normal; color: #909090; max-height: 42px; -webkit-line-clamp: 2; -webkit-box-orient: vertical; display: -webkit-box;&quot; data-ke-size=&quot;size16&quot;&gt;In this article, we look at audio codecs used on the web to compress and decompress audio, what their capabilities and use cases are, and offer guidance when choosing audio codecs to use for your content.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;line-height: 1.6; margin: 0px; position: absolute; bottom: -8px; font-family: AvenirNext; font-size: 14px; color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&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;&lt;b&gt;측정방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GIF의 경우 이미지 색상들의 숫자에 상응하는 팔레트 크기를 사용하는지&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://imagemagick.org/index.php&quot;&gt;ImageMagick&lt;/a&gt;을 사용하면 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077031&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; 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;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;identify -verbose IMAGE.gif &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;4가지&amp;nbsp;색상과&amp;nbsp;256&amp;nbsp;색상&amp;nbsp;슬롯(slot)을&amp;nbsp;사용하는&amp;nbsp;이미지를&amp;nbsp;보면&amp;nbsp;개선의&amp;nbsp;여지가&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 style=&quot;font-size: 1.12em;&quot; 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;- GIF&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적인 GIF 파일은 PNG로 바꾸어보자.(ImageMagick 기준)&lt;/p&gt;
&lt;pre id=&quot;code_1584933077031&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; 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;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;convert IMAGE.gif IMAGE.png&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: #333333;&quot;&gt;GIF 최적화를 위해 앞서 나온&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.lcdf.org/gifsicle/&quot;&gt;Gifsicle&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;같은 것을 이용할 수도 있다지만..&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적인 GIF 파일이라면 MP4처럼 영상파일로 바꾸는 것이 좋다.(&lt;a href=&quot;https://www.ffmpeg.org/&quot;&gt;ffmpeg&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://gist.github.com/ingramchen/e2af352bf8b40bb88890fba4f47eccd0&quot;&gt;명령어 참고&lt;/a&gt;&amp;nbsp;)&lt;/p&gt;
&lt;pre id=&quot;code_1584933077032&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; 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;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ffmpeg -f gif -i ANIMATE_IMAGE.gif -pix_fmt yuv420p -c:v libx264 -movflags +faststart -filter:v crop='floor(in_w/2)*2:floor(in_h/2)*2' ANIMATE_IMAGE.mp4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GIF는 영상 재생을 위해 나온 포맷이 아니다보니 미디엄 포스트에서 나온 것처럼 10배 가까이 용량차이가 생기기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://gfycat.com&quot;&gt;Gfycat&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://giphy.com/&quot;&gt;Giphy&lt;/a&gt;처럼 GIF를 전문적으로 다루는 사이트나 짤로서 GIF가 많이 이용되는 사이트는 트래픽을 줄이고, 속도를 높이기 위해 영상으로 변환한 것을 자주 볼 수 있다.&lt;/p&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 마크업은 크게 복잡해지지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 자동재생(autoplay), 반복(loop), 소리가 없음(muted)란 gif의 특징은 따라야할 필요가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077032&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; 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;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!--  OLD GIF Markup  --&amp;gt;
&amp;lt;img src=&quot;https://cdn.my-awesome-website.com/images/awesome-animation.gif&quot; alt=&quot;My awesome animated image&quot;&amp;gt;


&amp;lt;!--  NEW Video Markup  --&amp;gt;
&amp;lt;video autoplay loop muted playsinline&amp;gt;
  &amp;lt;!--  Specify video sources  --&amp;gt;
  &amp;lt;source src=&quot;https://cdn.my-awesome-website.com/images/awesome-and-efficient-animation.webm&quot; type=&quot;video/webm&quot;&amp;gt;
  &amp;lt;source src=&quot;https://cdn.my-awesome-website.com/images/awesome-and-efficient-animation.mp4&quot; type=&quot;video/mp4&quot;&amp;gt;
  
  &amp;lt;!--  FALLBACK for legacy browsers!  --&amp;gt;
  &amp;lt;img src=&quot;https://cdn.my-awesome-website.com/images/awesome-animation.gif&quot; alt=&quot;My awesome animated image&quot;&amp;gt;
&amp;lt;/video&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;MP4(H.264) 대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.webmproject.org/&quot;&gt;WebM&lt;/a&gt;을 써도 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;WebM은 효율적인 비디오(&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/VP8&quot;&gt;VP8&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/VP9&quot;&gt;VP9&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/AV1&quot;&gt;AV1&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;)와 오디오(&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Vorbis&quot;&gt;Vorbis&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Opus_(audio_format)&quot;&gt;Opus&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&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;&lt;span style=&quot;color: #333333;&quot;&gt;Imgur의 경우 GIF와 사용경험은 똑같지만 내부는 WebM 또는 MP4로 된 GIFV 포맷을 개발하여 사용하며, Gfycat 또한 마찬가지이다. [&lt;a href=&quot;https://blog.imgur.com/2014/10/09/introducing-gifv/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;INTRODUCING GIFV&lt;/a&gt;, &lt;a href=&quot;https://gfycat.com/about&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;About Gfycat&lt;/a&gt;]&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;&lt;a href=&quot;https://github.com/joeyhoer/gifv&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/joeyhoer/gifv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/joshua-stone/gif2gfy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/joshua-stone/gif2gfy&lt;/a&gt;&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;b&gt;- WebP&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPEG보다 평균 25&amp;ndash;35%, PNG보다 26% 크기가 작을정도로 효율적인 이미지 포맷입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://caniuse.com/#search=webp&quot;&gt;많은 브라우저&lt;/a&gt;에서 지원하므로 충분히 시도해볼만 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T7NKl/btqXj7gQPi3/Jb8tWHOBepXPqjcgfGKMt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T7NKl/btqXj7gQPi3/Jb8tWHOBepXPqjcgfGKMt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T7NKl/btqXj7gQPi3/Jb8tWHOBepXPqjcgfGKMt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT7NKl%2FbtqXj7gQPi3%2FJb8tWHOBepXPqjcgfGKMt0%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;1272&quot; height=&quot;281&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;281&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;WebP를 지원하지 않는 브라우저가(대표적으로 사파리) 존재하기 때문에 생기는 문제는 &amp;lt;picture&amp;gt;태그를 사용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;source중 첫번째로 매칭되는 것(지원하는 것)을 가져오므로 최적화가 된 것을 앞에 두어야 한다.[&lt;a href=&quot;https://html.spec.whatwg.org/multipage/images.html#select-an-image-source&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Selecting an image source&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1586290731633&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;picture&amp;gt;
  &amp;lt;source srcset=&quot;/path/to/image.webp&quot; type=&quot;image/webp&quot;&amp;gt;
  &amp;lt;img src=&quot;/path/to/image.jpg&quot; alt=&quot;&quot;&amp;gt;
&amp;lt;/picture&amp;gt;

&amp;lt;picture&amp;gt;
   &amp;lt;source srcset=&quot;photo.jxr&quot; type=&quot;image/vnd.ms-photo&quot;&amp;gt;
   &amp;lt;source srcset=&quot;photo.jp2&quot; type=&quot;image/jp2&quot;&amp;gt;
   &amp;lt;source srcset=&quot;photo.webp&quot; type=&quot;image/webp&quot;&amp;gt;
   &amp;lt;img src=&quot;photo.jpg&quot; alt=&quot;My beautiful face&quot;&amp;gt;
&amp;lt;/picture&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;- SVG나 CSS&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 이미지를 SVG나 CSS를 사용하면 텍스트로 만들어지기 때문에 큰 폭으로 이미지 크기를 줄일 수 있다.[&lt;a href=&quot;https://medium.com/coding-artist/a-beginners-guide-to-pure-css-images-ef9a5d069dd2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Beginner&amp;rsquo;s&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;Pure&amp;nbsp;CSS&amp;nbsp;Images&lt;/a&gt;, &lt;a href=&quot;https://www.allwebpromotion.com/ways-for-using-css-instead-images-for-design-effects/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;4&amp;nbsp;Ways&amp;nbsp;for&amp;nbsp;Using&amp;nbsp;CSS&amp;nbsp;Instead&amp;nbsp;of&amp;nbsp;Images&amp;nbsp;for&amp;nbsp;Design&amp;nbsp;Effects&lt;/a&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 SVG와 CSS를 비교한 어도비의 문서들이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://theblog.adobe.com/css-vs-svg-graphical-text/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;vs.&amp;nbsp;SVG:&amp;nbsp;Graphical&amp;nbsp;Text&amp;nbsp;Effects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://theblog.adobe.com/css-vs-svg-styling-checkboxes-and-radio-buttons/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;vs&amp;nbsp;SVG:&amp;nbsp;Styling&amp;nbsp;Checkboxes&amp;nbsp;and&amp;nbsp;Radio&amp;nbsp;Buttons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://theblog.adobe.com/css-vs-svg-shapes-and-arbitrarily-shaped-ui-components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;vs.&amp;nbsp;SVG:&amp;nbsp;Shapes&amp;nbsp;and&amp;nbsp;Arbitrarily-Shaped&amp;nbsp;UI&amp;nbsp;Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://theblog.adobe.com/css-vs-svg-the-final-roundup/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS&amp;nbsp;vs&amp;nbsp;SVG:&amp;nbsp;The&amp;nbsp;Final&amp;nbsp;Round(up)&lt;/a&gt;&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;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;개인적으로 AVIF에 기대를 걸고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://flif.info/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FLIF&lt;/a&gt;: 압축률 기준으로 PNG, WebP, BPG등보다 좋다고 주장하는 무손실 포맷 [&lt;a href=&quot;https://github.com/UprootLabs/poly-flif&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Poly-Fill&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mpeg.chiariglione.org/standards/mpeg-h/image-file-format&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HEIF&lt;/a&gt;:&amp;nbsp; 아래나올 HEVC를 이용한 이미지 포맷, &lt;a href=&quot;https://www.cnet.com/news/apple-ios-boosts-heif-photos-over-jpeg-wwdc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;애플이 사용&lt;/a&gt;하는 것으로 유명&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/AV1#AV1_Image_File_Format_(AVIF)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AVIF&lt;/a&gt;: 역시 아래나올 AV1을 이용한 이미지 포맷&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;b&gt;- 영상코덱&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직은 하드웨어 가속이 떨어지기 때문에 H.264를 이용하는 것이 낫겠지만 몇년후 지원기기가 많아지면 효율이 좋은 AV1을 사용해보는 것도 괜찮겠다. AV1 구현중&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/OpenVisualCloud/SVT-AV1&quot;&gt;SVT-AV1&lt;/a&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/OpenVisualCloud/SVT-AV1/tree/master/ffmpeg_plugin&quot;&gt;ffmpeg(플러그인)&lt;/a&gt;에 붙여쓰는 형태가 되지 않을까 싶다. [&lt;a href=&quot;https://www.videoproc.com/media-converter/av1-vs-hevc.htm&quot;&gt;AV1 vs HEVC: Should You Abandon HEVC Now?&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://medium.com/@ewoutterhoeven/av1-is-ready-for-prime-time-svt-av1-beats-x265-and-libvpx-in-quality-bitrate-and-speed-31c1960703db&quot;&gt;AV1&amp;nbsp;is&amp;nbsp;ready&amp;nbsp;for&amp;nbsp;prime&amp;nbsp;time:&amp;nbsp;SVT-AV1&amp;nbsp;beats&amp;nbsp;x265&amp;nbsp;and&amp;nbsp;libvpx&amp;nbsp;in&amp;nbsp;quality,&amp;nbsp;bitrate&amp;nbsp;and&amp;nbsp;speed&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.reddit.com/r/AV1/comments/e65dhl/libaom_vs_rav1e_vs_svtav1_test_results_with/&quot;&gt;Reddit Benchmark1&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.reddit.com/r/AV1/comments/f4mu1u/aom_vs_svtav1_vs_rav1e/&quot;&gt;Reddit Benchmark2&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;b&gt;- NodeJS 바인딩&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;ffmpeg:&amp;nbsp;&lt;a href=&quot;https://github.com/fluent-ffmpeg/node-fluent-ffmpeg&quot;&gt;node-fluent-ffmpeg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;WebP:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/Intervox/node-webp&quot;&gt;node-webp&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/cwebp-bin&quot;&gt;cwebp-bin&lt;/a&gt;&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;이것저것을 찾다보니&amp;nbsp;&lt;b&gt;&lt;a href=&quot;https://github.com/imagemin/imagemin&quot;&gt;imagemin&lt;/a&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;GIF:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/imagemin-gifsicle&quot;&gt;imagemin-gifsicle&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/imagemin-gif2webp&quot;&gt;imagemin-gif2webp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PNG:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/imagemin-optipng&quot;&gt;imagemin-optipng&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/imagemin-pngquant&quot;&gt;imagemin-pngquant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;JPEG:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/imagemin-mozjpeg&quot;&gt;imagemin-mozjpeg&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/imagemin-guetzli&quot;&gt;imagemin-guetzli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SVG:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/imagemin-svgo&quot;&gt;imagemin-svgo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;WebP:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/imagemin/imagemin-webp&quot;&gt;imagemin-webp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1.8 HTML에서 이미지 크기를 조정하지 않기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;Image&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;HTML에서 너비와 높이를 설정할 수 있다고 필요보다 큰 이미지를 사용하지 말자는 것.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1584933077035&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;img width=&quot;100&quot; height=&quot;100&quot; src=&quot;IMAGE.jpg&quot; alt=&quot;IMAGE&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 위와 같은 구문을 원한다면 이미지 (IMAGE.jpg)는 축소된 500x500px 이미지가 아니라 100x100px이어야 한다.&lt;/p&gt;
&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;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;대역폭을 낭비로 HTTP 연결갯수에 제한이 생길 가능성&lt;/li&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;처럼 많은 악영향을 끼친다.&lt;/p&gt;
&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;크기에 꼭 맞게 하라는 말은 반응형 웹의 개념이 필요하다는 뜻이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 각 해상도에 맞는 이미지를 제공해야 한다.[&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN 반응형 이미지&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://developers.google.com/web/fundamentals/design-and-ux/responsive/images&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;a href=&quot;http://usecases.responsiveimages.org/#art-direction&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;아트디렉션&lt;/a&gt;도 고려해야 한다. [&lt;a href=&quot;https://responsiveimages.org/demos/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Response Images Demo&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kPODG/btqWWr2UwQy/dd7gkmdMtKhABLlhLT9lGk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kPODG/btqWWr2UwQy/dd7gkmdMtKhABLlhLT9lGk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kPODG/btqWWr2UwQy/dd7gkmdMtKhABLlhLT9lGk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkPODG%2FbtqWWr2UwQy%2Fdd7gkmdMtKhABLlhLT9lGk%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;1280&quot; height=&quot;580&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;580&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 style=&quot;font-size: 1.12em;&quot; 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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://skia.org/&quot;&gt;Skia&lt;/a&gt;를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://engineering.vcnc.co.kr/2016/05/ondemand-image-resizing/&quot;&gt;이용&lt;/a&gt;해 리사이징을 했지만&amp;nbsp;&lt;a href=&quot;https://github.com/lovell/sharp&quot;&gt;Sharp&lt;/a&gt;란 패키지도 좋은 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 Skia의 성능은 매우 우수해 카이로를 제치고 웹브라우저에서 2D 그래픽용으로 사용되고 있다.&lt;/p&gt;
&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;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Element/img#attr-srcset&quot;&gt;srcset&lt;/a&gt;&amp;nbsp;속성을 사용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1586291992118&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;img srcset=&quot;EXAMPLE-320w.jpg,
             EXAMPLE-480w.jpg 1.5x,
             EXAMPLE-640w.jpg 2x&quot;
     src=&quot;EXAMPLE-640w.jpg&quot; alt=&quot;Example Image!!&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 앞서 나온 &amp;lt;picture&amp;gt;태그처럼 &lt;span style=&quot;color: #333333;&quot;&gt;srcset&lt;/span&gt;을 지원하지 않으면 기본값인 src를 사용한다.&lt;/p&gt;
&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;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Element/img#attr-sizes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sizes&lt;/a&gt; 속성으로 화면 크기에 따라 다른 크기의 이미지를 로드할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1586306569784&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;img srcset=&quot;EXAMPLE-320w.jpg 320w,
             EXAMPLE-480w.jpg 480w,
             EXAMPLE-800w.jpg 800w&quot;
     sizes=&quot;(max-width: 320px) 280px,
            (max-width: 480px) 440px,
            800px&quot;
     src=&quot;EXAMPLE-800w.jpg&quot; alt=&quot;Example Image!!&quot;&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;아트디렉션&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아트디렉션을 사용하기 위해서는 &amp;lt;picture&amp;gt; 태그가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;source에서 media 속성을 사용해 어떠한 이미지를 보여줄지 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미디어 속성은 추후에 등장할 미디어 쿼리에서 더 설명한다.&lt;/p&gt;
&lt;pre id=&quot;code_1586307196929&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;picture&amp;gt;
  &amp;lt;source media=&quot;(max-width: 799px)&quot; srcset=&quot;EXAMPLE-480w-close-portrait.jpg&quot;&amp;gt;
  &amp;lt;source media=&quot;(min-width: 800px)&quot; srcset=&quot;EXAMPLE-800w.jpg&quot;&amp;gt;
  &amp;lt;img src=&quot;EXAMPLE-800w.jpg&quot; alt=&quot;Example Image!!&quot;&amp;gt;
&amp;lt;/picture&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1.9 파비콘을 작고 캐시 가능하게 만들기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;&amp;nbsp;Image&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파비콘(favicon)은 주소창에 표시되는 아이콘으로, 주로 서버의 루트에 위치한다.(&lt;a href=&quot;https://webdir.tistory.com/337&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파비콘(Favicon)의&amp;nbsp;모든&amp;nbsp;것&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn3J8S/btqXoa5qNBI/2r22czK4KRYKeGOWKwLrUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn3J8S/btqXoa5qNBI/2r22czK4KRYKeGOWKwLrUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn3J8S/btqXoa5qNBI/2r22czK4KRYKeGOWKwLrUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn3J8S%2FbtqXoa5qNBI%2F2r22czK4KRYKeGOWKwLrUk%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;450&quot; height=&quot;69&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신경 쓰지 않아도 브라우저가 계속 요청하므로으로 404 Not Found가 아닌 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 동일한 서버에 있기 때문에 쿠키는 요청 될 때마다 전송되며 다운로드 순서를 방해하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(예를 들어, 온로드에서 추가 구성 요소(component)를 요청하면 IE에서 이러한 추가 구성 요소보다 파비콘이 다운로드됩니다).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결방법&lt;/b&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1k 이하로 작게 만들기&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변경설정 후에는 이름변경이 불가능하므로 원하는 시점의 Expires header를 설정.&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아마 미래 시점(약 몇 달 뒤)의 Expires header를 안전하게 설정할 수 있을 것이다. 명확한 결정을 위해 현재 파비콘의 마지막 수정날짜 확인이 가능하다.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://realfavicongenerator.net/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Favicon Generator&lt;/a&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;1.1.10 HTTP 구성요소 압축&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Server&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 응답 구성요소를 압축하여 줄임으로써 응답 시간을 줄일 수 있다.[&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Content Negotiation&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;767&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lYIK1/btqWXaGCePu/AvwjcXspi37Dwqh0kTvMLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lYIK1/btqWXaGCePu/AvwjcXspi37Dwqh0kTvMLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lYIK1/btqWXaGCePu/AvwjcXspi37Dwqh0kTvMLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlYIK1%2FbtqWXaGCePu%2FAvwjcXspi37Dwqh0kTvMLK%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;767&quot; height=&quot;380&quot; data-origin-width=&quot;767&quot; data-origin-height=&quot;380&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;웹 클라이언트는 HTTP 요청에서 Accept-Encoding 헤더를 사용하여 지원하는 압축을 나타낸다.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077037&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      Accept-Encoding: br, gzip, deflate&lt;/code&gt;&lt;/pre&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;웹 서버는 응답의 Content-Encoding 헤더를 통해 웹 클라이언트에게 이를 알린다.&lt;/p&gt;
&lt;pre id=&quot;code_1584933077037&quot; class=&quot;html xml&quot; style=&quot;margin: 20px auto 0px; 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; cursor: default; z-index: 1;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      Content-Encoding: gzip&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;대부분의 웹사이트들은 자신들의 HTML 문서를 압축한다. 그 압축툴은 scripts와 stylesheets를 압축하는 데에도 매우 유용한 것들이지만 많은 웹사이트들은 이 기회를 놓치고 있다. 이미지와 PDF 파일은 이미 압축이 되어있기 때문에 압축할 필요가 없지만 XML이나 JSON을 포함한 텍스트 응답을 압축하는 데에는 유용하다. CPU를 낭비할 뿐 아니라 잠재적으로 파일크기를 증가시킬 수 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가능한 많은 파일 형식을 압축하는 것이 페이지 무게를 줄이고 사용자 경험(UX)을 가속화하는 쉬운 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;a href=&quot;https://github.com/google/brotli&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Brotli&lt;/a&gt;를 적용하는 것이다.[&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/introducing-support-for-brotli-compression/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introducing Support for Brotli Compression&lt;/a&gt;, &lt;a href=&quot;https://engineering.linkedin.com/blog/2017/05/boosting-site-speed-using-brotli-compression&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Boosting&amp;nbsp;Site&amp;nbsp;Speed&amp;nbsp;Using&amp;nbsp;Brotli&amp;nbsp;Compression&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;889&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UUd4x/btqXb1BvDhG/3juYc4hS65kbXAaPQTWTo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UUd4x/btqXb1BvDhG/3juYc4hS65kbXAaPQTWTo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UUd4x/btqXb1BvDhG/3juYc4hS65kbXAaPQTWTo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUUd4x%2FbtqXb1BvDhG%2F3juYc4hS65kbXAaPQTWTo0%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;889&quot; height=&quot;454&quot; data-origin-width=&quot;889&quot; data-origin-height=&quot;454&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://caniuse.com/#search=brotli&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아파치와 엔진엑스 &lt;a href=&quot;https://www.fastfwd.com/improve-http-compression-with-brotli/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;설정법&lt;/a&gt; [Apache: &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_brotli.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;mode_brotli&lt;/a&gt;,&amp;nbsp; NGINX: &lt;a href=&quot;https://docs.nginx.com/nginx/admin-guide/dynamic-modules/brotli/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;brotli&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;웹팩(Webpack)에서 Brotli를 설정하고, Gzip을 Fallback으로 두는 &lt;a href=&quot;https://medium.com/groww-engineering/enable-brotli-compression-in-webpack-with-fallback-to-gzip-397a57cf9fc6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;서버가 php 사용시 다음과 같이 압축된 것을 요구 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1584933077037&quot; class=&quot;html xml&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;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?php if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start(&quot;ob_gzhandler&quot;); else ob_start(); ?&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;Gzip에는 앞서 언급한 Zopfli를 적용해볼 수 있다.(단, 시간이 약간 더 필요하다는 것은 고려대상)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lz4도 성능이 엄청 좋은데..(인코딩, 디코딩, 압축률 모두에서.. 개인 컴퓨터 커널 압축에 써먹는중)&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;h4 data-ke-size=&quot;size20&quot;&gt;1.1.11 클라이언트 힌트로 리소스 선택 자동화&lt;/h4&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; Server&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#Client_hints&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;클라이언트 힌트&lt;/a&gt;를 사용하여 리소스 선택을 자동화 할 수 있다.[&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/client-hints?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Adapting to Users with Client Hints&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/updates/2015/09/automating-resource-selection-with-client-hints&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Automating&amp;nbsp;Resource&amp;nbsp;Selection&amp;nbsp;with&amp;nbsp;Client&amp;nbsp;Hints&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Client_hints&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Client Hints&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;앞선 최적화의 영향으로 우리는 최적화된 이미지 포맷(WebP, JPEG XR, JPEG), 해상도(1x, 1.5x, 2x, 2.5x, 3x), 뷰포트 너비에 따라 제어를 하고 싶어했고 그 결과 아래처럼 거대한 &amp;lt;picture&amp;gt; 태그가 완성된다.&lt;/p&gt;
&lt;pre id=&quot;code_1586308840854&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;picture&amp;gt;
  &amp;lt;!-- serve WebP to Chrome and Opera --&amp;gt;
  &amp;lt;source
    media=&quot;(min-width: 50em)&quot;
    sizes=&quot;50vw&quot;
    srcset=&quot;/image/thing-200.webp 200w, /image/thing-400.webp 400w,
        /image/thing-800.webp 800w, /image/thing-1200.webp 1200w,
        /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w&quot;
    type=&quot;image/webp&quot;&amp;gt;
  &amp;lt;source
    sizes=&quot;(min-width: 30em) 100vw&quot;
    srcset=&quot;/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w,
        /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w,
        /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w&quot;
    type=&quot;image/webp&quot;&amp;gt;
  &amp;lt;!-- serve JPEG to others --&amp;gt;
  &amp;lt;source
    media=&quot;(min-width: 50em)&quot;
    sizes=&quot;50vw&quot;
    srcset=&quot;/image/thing-200.jpg 200w, /image/thing-400.jpg 400w,
        /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w,
        /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w&quot;&amp;gt;
  &amp;lt;source
    sizes=&quot;(min-width: 30em) 100vw&quot;
    srcset=&quot;/image/thing-crop-200.jpg 200w, /image/thing-crop-400.jpg 400w,
        /image/thing-crop-800.jpg 800w, /image/thing-crop-1200.jpg 1200w,
        /image/thing-crop-1600.jpg 1600w, /image/thing-crop-2000.jpg 2000w&quot;&amp;gt;
  &amp;lt;!-- fallback for browsers that don't support picture --&amp;gt;
  &amp;lt;img src=&quot;/image/thing.jpg&quot; width=&quot;50%&quot;&amp;gt;
&amp;lt;/picture&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;/p&gt;
&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;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;CSS&amp;nbsp;에서&amp;nbsp;항목&amp;nbsp;크기&amp;nbsp;조정&lt;/span&gt;&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEQEIR/btqXgo4gvXD/vc5U73k6JKLikilB31zG3k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEQEIR/btqXgo4gvXD/vc5U73k6JKLikilB31zG3k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEQEIR/btqXgo4gvXD/vc5U73k6JKLikilB31zG3k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEQEIR%2FbtqXgo4gvXD%2Fvc5U73k6JKLikilB31zG3k%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;553&quot; height=&quot;313&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;313&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;고유 크기(Intrinsic Size):&lt;/b&gt; CSS등의 영향을 받기 전에 설정된 고유의 크기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;외적인 크기(Extrinsic Size):&lt;/b&gt; CSS등을 사용해 설정한 특정 크기&lt;/li&gt;
&lt;/ul&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;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;밀도가 수정된 고유 크기(&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Density-corrected intrinsic size):&lt;/b&gt; 고유 크기를&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;장치 픽셀 비율&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;로 나눈 값, 픽셀 밀도에 맞춰 수정된 미디어 리소스의 크기.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1586635300330&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;img src=&quot;whats-up-1x.png&quot;
     srcset=&quot;whats-up-2x.png 2x, whats-up-1x.png 1x&quot;
     alt=&quot;I'm that image you wanted.&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고유 크기가 1x지만, 화면의 픽셀 비율이 2x인 장치를 사용하면 2x 이미지가 요청되는 식.&lt;/p&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Viewport:&lt;/b&gt; 브라우저의 페이지에서 가시영역. [&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Mozilla/Mobile/Viewport_meta_tag&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Viewport meta 태그를 이용해 모바일 브라우저상에서 레이아웃 조종하는 법&lt;/a&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;viewport의 width 값에 따라 아트디렉션도 고를 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DPR(Device Pixel Ratio):&lt;/b&gt; 사용자 화면의 물리적 픽셀과 CSS 픽셀의 비율 [&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/DPR&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;devicePixelRatio&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Width:&lt;/b&gt; 이미지 리소스 요청에 대한 힌트가 나타남(예: DPR이 2, CSS의 너비가 320,&amp;nbsp; 뷰포트 너비가 85라면 $(2 \times 320) \times 0.85$&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Content-DPR:&lt;/b&gt; 리소스 자체 픽셀과 CSS 픽셀의 비율, DPR과 Width 헤더를 모두 사용할 때 외적인 크기로 달라질때 유용&lt;/li&gt;
&lt;/ul&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;&lt;b&gt;Device-Memory:&lt;/b&gt; 메모리의 크기를 &lt;a href=&quot;https://www.w3.org/TR/device-memory-1/#sec-device-memory-client-hint-header&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;대략적&lt;/a&gt;(GB 기준)으로 표시. &lt;a href=&quot;https://medium.com/@addyosmani/the-cost-of-javascript-in-2018-7d8950fbb5d4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비용이 비싼 Javascript&lt;/a&gt;를 조절할 때 쓰일 수 있다.&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;네트워크 정보&lt;/a&gt;들의 예.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RTT:&amp;nbsp; RTT 시간(ms)을 대략적(&lt;span style=&quot;color: #333333;&quot;&gt;25ms 반올림)으로 제공&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Downlink: 대역폭의 크기(Mbps)를 대략적(2kb)으로 제공&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;ECT(Effective Connection Types): RTT와 Downlink를 분석해 2g, 3g, 4g등으로 나눔&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Save-Data: 적은 양의 데이터를 보내야 한다는 환경설정&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;- Accept 헤더&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Accept&lt;/a&gt;헤더를 이용하면 브라우저가 컨텐츠 유형을 고를 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1586634094124&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Accept: image/webp,image/apng,image/*,*/*;q=0.8&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;PHP를 사용하면 이를 설정할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1586634061448&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?php
// Check Accept for an &quot;image/webp&quot; substring.
$webp = stristr($_SERVER[&quot;HTTP_ACCEPT&quot;], &quot;image/webp&quot;) !== false ? true : false;

// Set the image URL based on the browser's WebP support status.
$imageFile = $webp ? &quot;whats-up.webp&quot; : &quot;whats-up.jpg&quot;;
?&amp;gt;
&amp;lt;img src=&quot;&amp;lt;?php echo($imageFile); ?&amp;gt;&quot; alt=&quot;I'm an image!&quot;&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;- Accept-CH&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 힌트는 DPR(Device Pixel Rate), Viewport-Width, Width를 서버에 알리도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1586309270272&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;meta http-equiv=&quot;Accept-CH&quot; content=&quot;DPR, Viewport-Width, Width&quot;&amp;gt;
...
&amp;lt;picture&amp;gt;
  &amp;lt;source media=&quot;(min-width: 50em)&quot; sizes=&quot;50vw&quot; srcset=&quot;/image/thing&quot;&amp;gt;
  &amp;lt;img sizes=&quot;100vw&quot; src=&quot;/image/thing-crop&quot;&amp;gt;
&amp;lt;/picture&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;앞선 &amp;lt;picture&amp;gt; 태그보다 훨씬 간단하며 서버나 CDN을 통해 자동적으로 이미지를 다운받도록 만들 수 있다.&lt;/p&gt;
&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;네트워크의 경우 Save-Data가 on인지를 가장 먼저 확인하고, 없다면 &lt;a href=&quot;https://github.com/malchata/client-hints-example/blob/master/includes/functions.php#L8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;네트워크 점수(0~1 사이)&lt;/a&gt;를 내서 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cE88wU/btqW4hdOteo/MZeehWQgh7vN4ikhFAuyG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cE88wU/btqW4hdOteo/MZeehWQgh7vN4ikhFAuyG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cE88wU/btqW4hdOteo/MZeehWQgh7vN4ikhFAuyG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcE88wU%2FbtqW4hdOteo%2FMZeehWQgh7vN4ikhFAuyG1%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;640&quot; height=&quot;463&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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 data-ke-size=&quot;size16&quot;&gt;다음과 같이 Save-Data가 활성화 되었는지 확인할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1586641085826&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (&quot;connection&quot; in navigator) {
    if (navigator.connection.saveData === true) {
        // Implement data saving operations here.
    }
}&lt;/code&gt;&lt;/pre&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;필수적이지 않은 웹폰트 제거&lt;/li&gt;
&lt;li&gt;이미지를 낮은 해상도로&lt;/li&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;기타 코드는 &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/save-data?hl=ko#recipes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Delivering Fast and Light Applications with Save-Data&lt;/a&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;span style=&quot;color: #333333;&quot;&gt;1.1.12 구성 요소를 25K 미만으로 유지&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;개요&lt;/span&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;b&gt;분류:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Mobile&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 제한은 iPhone이 25K보다 큰 구성 요소를 캐시하지 않는다는 연구가 있다. (단, 오래전이라 기준이 달라졌을 수도 있음)&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;span style=&quot;color: #333333;&quot;&gt;gzip이나 brotli등의 압축만으로는 충분하지 않을 수 있다는 뜻이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;자세한&amp;nbsp;내용&amp;nbsp;은&amp;nbsp;Wayne&amp;nbsp;Shea&amp;nbsp;및&amp;nbsp;Tenni&amp;nbsp;Theurer의&amp;nbsp;&quot;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://yuiblog.com/blog/2008/02/06/iphone-cacheability/&quot;&gt;Performance&amp;nbsp;Research,&amp;nbsp;Part&amp;nbsp;5&amp;nbsp;:&amp;nbsp;iPhone&amp;nbsp;Cacheability-Making&amp;nbsp;it&amp;nbsp;Stick&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&quot;을&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;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;+.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP 혼잡 제어 때문에 웹사이트가 14kb 미만인게 좋다. [&lt;a href=&quot;https://news.hada.io/topic?id=7365&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹사이트 크기가 14kB 미만이어야 하는 이유&lt;/a&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;1.1.13 기타 번들러 최적화&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Content, Javascript, CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹팩/바벨등의 &lt;a href=&quot;https://webpack.js.org/configuration/optimization/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;최적화&lt;/a&gt;를 다룬다.[&lt;a href=&quot;https://iamakulov.com/notes/webpack-front-end-size-caching/&quot;&gt;webpack&amp;nbsp;for&amp;nbsp;real&amp;nbsp;tasks:&amp;nbsp;decreasing&amp;nbsp;front-end&amp;nbsp;size&amp;nbsp;and&amp;nbsp;improving&amp;nbsp;caching&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/webpack?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web Performance Optimization with Webpack&lt;/a&gt;, &lt;a href=&quot;https://github.com/iamakulov/awesome-webpack-perf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Awesome Webpack Perf&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;b&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;&lt;a href=&quot;https://webpack.js.org/configuration/mode/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;mode&lt;/a&gt;: production을 고르면 디버깅용 코드 제거, 최적화 설정을 고를 수 있다.[&lt;a href=&quot;http://guswnsxodlf.github.io/production-with-webpack&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;webpack으로&amp;nbsp;development,&amp;nbsp;product&amp;nbsp;환경&amp;nbsp;세팅하기&lt;/a&gt;, &lt;a href=&quot;https://webpack.js.org/plugins/define-plugin/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DefinePlugin&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/tools/setup/setup-preprocessors?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;소스맵&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webpack.js.org/plugins/context-replacement-plugin/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ContextReplacementPlugin&lt;/a&gt;:&amp;nbsp; 디렉토리에서 매칭할 파일의 정규식을 사용&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webpack.js.org/plugins/compression-webpack-plugin/&quot;&gt;CompressionWebpackPlugin&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;:&amp;nbsp; 압축하기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webpack.js.org/guides/code-splitting/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Code Split&lt;/a&gt;: &amp;nbsp;자바스크립트를 청크로 나누기 [&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-javascript/code-splitting?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reduce JavaScript Payloads with Code Splitting&lt;/a&gt;, &lt;a href=&quot;https://medium.com/little-big-programming/spa-%EC%B4%88%EA%B8%B0-%EB%A1%9C%EB%94%A9-%EC%86%8D%EB%8F%84-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0-9db137d25566&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SPA 초기 로딩 속도 개선하기&lt;/a&gt;, &lt;a href=&quot;https://webpack.js.org/plugins/split-chunks-plugin/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SplitChunksPlugin&lt;/a&gt;, &lt;a href=&quot;https://webpack.js.org/plugins/min-chunk-size-plugin/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MinChunkSizePlugin&lt;/a&gt;, &lt;a href=&quot;https://webpack.js.org/plugins/limit-chunk-count-plugin/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LimitChunkCountPlugin&lt;/a&gt;, &lt;a href=&quot;https://blog.kommit.co/a-gentle-introduction-to-code-splitting-with-react-395ddf44b71b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Gentle&amp;nbsp;Introduction&amp;nbsp;to&amp;nbsp;Code&amp;nbsp;Splitting&amp;nbsp;with&amp;nbsp;React&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webpack.js.org/guides/tree-shaking/&quot;&gt;Tree Shaking&lt;/a&gt;: &lt;span style=&quot;color: #333333;&quot;&gt;기법활용[&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reduce JavaScript Payloads with Tree Shaking&lt;/a&gt;, &lt;a href=&quot;https://huns.me/development/2265&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpack 4의 Tree Shaking에 대한 이해&lt;/a&gt;, &lt;a href=&quot;https://medium.com/naver-fe-platform/webpack%EC%97%90%EC%84%9C-tree-shaking-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0-1748e0e0c365&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpack에서 Tree Shaking 적용하기&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://blog.jungbin.kim/web/2019/02/16/js-decreaing-webpack-bundle.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpack&amp;nbsp;bundling&amp;nbsp;파일&amp;nbsp;사이즈&amp;nbsp;줄이기&lt;/a&gt;]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기타: &lt;a href=&quot;https://github.com/iamakulov/awesome-webpack-perf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;awesome-webpack-perf&lt;/a&gt;&lt;/span&gt;&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;b&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;&lt;a href=&quot;https://github.com/babel/babel/tree/master/packages/babel-preset-env&quot;&gt;babel-preset-env&lt;/a&gt;: 지원대상 브라우저를 설정해 최신 브라우저에서 제공하는 기능은 트랜스파일을 하지 않기. Differential serving과 관련된 글 또한 좋다. [&lt;a href=&quot;https://velog.io/@pop8682/%EB%B2%88%EC%97%AD-%EC%99%9C-babel-preset%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%98%EA%B3%A0-%EC%99%9C-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80-yhk03drm7q&quot;&gt;babel-preset-env는&amp;nbsp;무엇이고&amp;nbsp;왜&amp;nbsp;필요한가?&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://velog.io/@vnthf/%EB%AA%A8%EB%8D%98%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%97%90%EB%8F%84-%EA%BC%AD-es5%EB%A5%BC-%EC%8D%A8%EC%95%BC-%ED%95%A0%EA%B9%8C-Differential-Serving&quot;&gt;모던 브라우저에도 꼭 es5를 써야 할까(Differential Serving)&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://css-tricks.com/differential-serving/&quot;&gt;Diffential Serving&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://web.dev/codelab-serve-modern-code/&quot;&gt;Serve modern code to modern browsers for faster page loads&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://medium.com/@imdongchen/differential-serving-vs-polyfill-service-how-to-best-serve-modern-and-legacy-browsers-e5bb40ba73e8&quot;&gt;Differential serving vs polyfill service&lt;/a&gt;]&amp;nbsp;&lt;/li&gt;
&lt;li&gt;컴파일 타임 매크로 활용 [&lt;a href=&quot;https://betterprogramming.pub/an-introduction-to-javascript-compile-time-processing-f77571e71dfd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;An Introduction to JavaScript Compile-Time Processing&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;조건부 컴파일 [&lt;a href=&quot;https://www.npmjs.com/package/babel-plugin-conditional-compile-v2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;babel-plugin-conditional-compile&lt;/a&gt;]&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;b&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;&lt;a href=&quot;https://developers.google.com/closure/compiler&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Closure Compiler&lt;/a&gt;: 데드코드 제거에 탁월한 걸로 유명하다.&lt;br /&gt;&lt;a href=&quot;https://github.com/angular/tsickle&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tsickle&lt;/a&gt;을 쓰면 타입스크립트를 이용해 Advanced 최적화를 할 수 있다. [&lt;a href=&quot;https://appmonet.com/2020/01/20/using-closure-compiler-with-webpack-typescript-via-tsickle/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Using&amp;nbsp;Closure&amp;nbsp;Compiler&amp;nbsp;With&amp;nbsp;Webpack&amp;nbsp;+&amp;nbsp;Typescript&amp;nbsp;via&amp;nbsp;Tsickle&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prepack.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Prepack&lt;/a&gt;: 런타임 최적화에 집중한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 많이 괴랄한 걸로는 Js -&amp;gt; C++ -&amp;gt; LLVM -&amp;gt; Js로 바꾸는 방법도 있다? [&lt;a href=&quot;https://medium.com/leaningtech/a-javascript-optimizing-compiler-3fd3f49bd071&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A JavaScript optimizing compiler&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;b&gt;기타&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://astro.build/blog/introducing-astro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;astro&lt;/a&gt;, &lt;a href=&quot;https://github.com/Morglod/tsts&quot;&gt;tsts&lt;/a&gt; 같은 것을 써볼수도?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외 배송 최적화에 잘 써진 글. [&lt;a href=&quot;https://web.dev/publish-modern-javascript/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Publish, ship, and install modern JavaScript for faster applications&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;참고로 CommonJS 형태의 모듈은 ESM보다 번들링 최적화에서 손해일 수밖에 없다. [&lt;a href=&quot;https://web.dev/commonjs-larger-bundles/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How CommonJS is making your bundles larger&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 각종 JS 모듈 시스템이 궁금하다면 &lt;a href=&quot;https://wormwlrm.github.io/2020/08/12/History-of-JavaScript-Modules-and-Bundlers.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript&amp;nbsp;번들러로&amp;nbsp;본&amp;nbsp;조선시대&amp;nbsp;붕당의&amp;nbsp;이해&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://yeoman.io/blog/performance-optimization.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Grunt And Gulp Tasks For Performance Optimization&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;1.2 요청 줄이기&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: #333333;&quot;&gt;HTTP 1.1의 경우, 한 호스트에서 최대 6개의 리소스만 병렬적으로 가져올 수 있고, 그 이상은 대기한다.[&lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=12066&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Match&amp;nbsp;Firefox's&amp;nbsp;per-host&amp;nbsp;connection&amp;nbsp;limit&amp;nbsp;of&amp;nbsp;15&lt;/a&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;1.2.1 DNS 조회 감소&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DNS (Domain Name System)는 우리가 익히 알다시피 호스트 이름을 IP 주소에 매핑한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DNS 조회에는 시간&lt;span style=&quot;color: #333333;&quot;&gt;(약 20~120ms)&lt;/span&gt;이 드는데&amp;nbsp;DNS 조회가 완료 될 때까지 브라우저는 이 호스트 이름에서 아무것도 다운로드 할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 성능 향상을 위해 DNS 조회 정보가 캐싱된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자의 ISP와 LAN에 의해 유지 관리되는 캐싱 서버말고도 개별 컴퓨터의 운영체제와 브라우저에서도 일어난다.&lt;br /&gt;&lt;br /&gt;클라이언트의 DNS 캐시가 비어있는 경우(브라우저와 운영 체제 모두) DNS 조회 수는 웹 페이지의 고유 호스트 이름 수와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블로그 정보와 글: 티스토리, 이미지: imgur, react: jsDelivr, 부트스트랩: 클라우드 플레어, 폰트: 구글이라면 총 5개의 호스트가 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 페이지 URL에 사용 된 호스트 이름, 이미지, 스크립트 파일, 스타일 시트등이 포함되며 고유 한 호스트 이름 수를 줄이면 DNS 조회 수가 줄어 들 수 있다는 것이다.&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;따라서 DNS 조회가 줄었더라도 병렬 다운로드가 이루어지지 않아 응답 시간이 늘어날 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;호스트 구성 요소를 2~4개로 적절히 분리통합하고 유지하는 것이 좋다.&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;1.2.2 CDN 사용&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Server&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서버에 대한 사용자의 근접성은 응답 시간에 영향을 준다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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 style=&quot;font-size: 1.12em;&quot; 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;이미 잘 분산되어있는 CDN 서비스를 이용하는 것이 좋다.&lt;/p&gt;
&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://www.cdnperf.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.cdnperf.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1584938098300&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;CDNPerf - CDN Performance and Uptime monitoring, comparison and analytics - RUM data&quot; data-og-description=&quot;With CDNPerf you can find the fastest CDN provider in the world or just your country. Get the top CDN by using our data for free.&quot; data-og-host=&quot;www.cdnperf.com&quot; data-og-source-url=&quot;https://www.cdnperf.com/&quot; data-og-url=&quot;http://www.cdnperf.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLFnEC/hyFn5fvFWi/bbw10Os7wsEWxnKbBjBp30/img.png?width=540&amp;amp;height=300&amp;amp;face=0_0_540_300&quot;&gt;&lt;a href=&quot;https://www.cdnperf.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.cdnperf.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLFnEC/hyFn5fvFWi/bbw10Os7wsEWxnKbBjBp30/img.png?width=540&amp;amp;height=300&amp;amp;face=0_0_540_300');&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;CDNPerf - CDN Performance and Uptime monitoring, comparison and analytics - RUM data&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;With CDNPerf you can find the fastest CDN provider in the world or just your country. Get the top CDN by using our data for free.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.cdnperf.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;무료에서는 클라우드 플레어의 &lt;a href=&quot;https://cdnjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CDNjs&lt;/a&gt;와 &lt;a href=&quot;https://www.jsdelivr.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;jsDelivr&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/speed/libraries?hl=ko&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2.3 404 피하기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Content&lt;br /&gt;HTTP 요청은 비용이 많이 들기 때문에 HTTP 요청을 하고 쓸모없는 응답 (예 : 404 찾을 수 없음)을 얻는 것은 완전히 불필요하며 아무런 이점없이 사용자 경험을 느리게 합니다.&lt;br /&gt;&lt;br /&gt;일부 사이트는 404때 &quot;X를 의미 했습니까?&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;외부 JavaScript에 대한 링크가 잘못되고 결과가 404 인 경우 특히 나쁩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 이 다운로드는 병렬 다운로드를 차단하며 브라우저는 JavaScript 코드인 것처럼 404 응답 본문(body)을 구문 분석하여 사용할 수있는 것을 찾으려고 시도 할 수 있습니다.&lt;/p&gt;
&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;a href=&quot;https://github.com/stevenvachon/broken-link-checker&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;broken-link-checker&lt;/a&gt;같은 NodeJS 패키지나 &lt;a href=&quot;https://wummel.github.io/linkchecker/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LinkChecker&lt;/a&gt;, &lt;a href=&quot;http://home.snafu.de/tilman/xenulink.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Xenu&amp;rsquo;s&amp;nbsp;link&amp;nbsp;Sleuth&lt;/a&gt;와 같은 프로그램을 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이트로는 &lt;a href=&quot;https://sitechecker.pro/website-crawler/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sitechecker&lt;/a&gt;, &lt;a href=&quot;https://www.deadlinkchecker.com/website-dead-link-checker.asp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dead Link Checker&lt;/a&gt;, &lt;a href=&quot;https://validator.w3.org/checklink&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;W3C Linkchecker&lt;/a&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;1.2.4 서명된 교환(SXGs, Signed Exchanges)&lt;/h4&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; Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SXG는 리소스가 전달된 방식과 관계없이 출처를 인증할 수 있는 전달 메커니즘이다. [&lt;a href=&quot;https://developers.google.com/search/docs/advanced/experience/signed-exchange&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Get started with signed exchanges on Google Search&lt;/a&gt;, &lt;a href=&quot;https://web.dev/signed-exchanges/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Signed Exchanges (SXGs)&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;특히 구글의 경우는 SXG 캐시를 사용해 콘텐츠를 미리 가져오므로 성능 개선을 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp5PmW/btq5fwBctq8/gYCnjhQrT0D98kQpGtHjqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp5PmW/btq5fwBctq8/gYCnjhQrT0D98kQpGtHjqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp5PmW/btq5fwBctq8/gYCnjhQrT0D98kQpGtHjqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp5PmW%2Fbtq5fwBctq8%2FgYCnjhQrT0D98kQpGtHjqk%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;800&quot; height=&quot;396&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;452&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://github.com/WICG/webpackage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpackage&lt;/a&gt;(&lt;a href=&quot;https://web.dev/web-bundles/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webbundle&lt;/a&gt;&amp;nbsp;포함)도 이를 적극사용 한다. [&lt;a href=&quot;https://github.com/google/webpackager&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpackager&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 개인정보 관련하여 말이 있는 편. [&lt;a href=&quot;https://www.cdn77.com/blog/web-bundles&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Do Web Bundles threaten the Web?&lt;/a&gt;, &lt;a href=&quot;https://brave.com/web-standards-at-brave/3-web-bundles/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WebBundles Harmful to Content Blocking, Security Tools, and the Open Web&lt;/a&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;1.2.5 서버 응답 시간 개선&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Server&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 응답시간이 빠르면 좋으며 일반적으로 200 ms 아래면 좋다고 한다.&lt;/p&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;nbsp;로직,&amp;nbsp;느린&amp;nbsp;데이터베이스&amp;nbsp;쿼리,&amp;nbsp;느린&amp;nbsp;라우팅,&amp;nbsp;프레임워크,&amp;nbsp;라이브러리,&amp;nbsp;리소스&amp;nbsp;CPU&amp;nbsp;부족&amp;nbsp;현상&amp;nbsp;또는&amp;nbsp;메모리&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;&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;a href=&quot;https://rigor.com/blog/best-ways-reduce-server-response-times&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;5&amp;nbsp;Ways&amp;nbsp;to&amp;nbsp;Reduce&amp;nbsp;Server&amp;nbsp;Response&amp;nbsp;Times&amp;nbsp;(TTFB)&lt;/a&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;아파치나 Nginx등 웹서버를 신중히 선택&lt;/li&gt;
&lt;li&gt;웹서버 최적화&lt;/li&gt;
&lt;li&gt;WordPress나 Magento같은 CMS(Content Management System) 사용시 신중히 관리&lt;/li&gt;
&lt;li&gt;DB 최적화 [&lt;a href=&quot;https://hinty.io/devforth/sql-query-optimization-understanding-key-principle/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SQL&amp;nbsp;Query&amp;nbsp;Optimization:&amp;nbsp;Understanding&amp;nbsp;Key&amp;nbsp;Principle&lt;/a&gt;, &lt;a href=&quot;https://use-the-index-luke.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SQL&amp;nbsp;Indexing&amp;nbsp;and&amp;nbsp;Tuning&amp;nbsp;e-Book&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아키텍처 이야기만 해보자면 일반적으로 모놀리식(Monolithic)을 사용해도 상관이 없다. [&lt;a href=&quot;https://www.samsungsds.com/kr/insights/msa.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Do Not Use MSA - 마이크로서비스 아키텍처가 꼭 필요한가요?&lt;/a&gt;, &lt;a href=&quot;https://velog.io/@tedigom/series/MSA-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MSA&amp;nbsp;제대로&amp;nbsp;이해하기&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그러나 서비스가 복잡해지고 트래픽 규모가 커지면 MSA를 도입해볼 가치가 있다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@syleemk/%EB%B0%B0%EB%AF%BC-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%97%AC%ED%96%89%EA%B8%B0-%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;배민&amp;nbsp;MSA&amp;nbsp;여행기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Microservice&amp;nbsp;Architecture&amp;nbsp;and&amp;nbsp;its&amp;nbsp;10&amp;nbsp;Most&amp;nbsp;Important&amp;nbsp;Design&amp;nbsp;Patterns&lt;/a&gt;&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;/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;1.2.6 기타 네트워크 최적화&lt;/h4&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; Server&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hpbn.co/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;High Performance Browser Networking&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;아마 최신 리눅스 커널들을 사용한다면 대부분 활성화 되어있을 것이다.&lt;/p&gt;
&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;a href=&quot;https://engineering.fb.com/android/building-zero-protocol-for-fast-secure-mobile-connections/&quot;&gt;Building&amp;nbsp;Zero&amp;nbsp;protocol&amp;nbsp;for&amp;nbsp;fast,&amp;nbsp;secure&amp;nbsp;mobile&amp;nbsp;connections&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;&lt;b&gt;- Transport &amp;amp; Session&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OSI 7 Layer에서 Transport 계층에 속하는 TCP와 Session에 속하는 TLS에 대해 다루어본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 QUIC를 비롯해 제약이 덜한 UDP를 적극적으로 활용하는 경우가 많이 생기고 있다지만, 제약이 덜하다보니 튜닝 규칙또한 적기가 애매하여 제외하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반기업들은 TCP를 주로 사용하며, UDP에서는 QUIC를 제외하면 적용할 일이 거의 없을만 하기도 하고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Session계층은 Transport보다 Application쪽과 가깝긴 한데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Application에서 HTTP를 중점적으로 다룰 것이며, RTT 개선의 측면에서 Transport와 같이 설명하기 편하므로 묶어서 설명한다.&lt;/p&gt;
&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;TCP&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP 성능 튜닝에 대한 이야기. [&lt;a href=&quot;https://hpbn.co/building-blocks-of-tcp/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Building&amp;nbsp;Blocks&amp;nbsp;of&amp;nbsp;TCP&lt;/a&gt;, &lt;a href=&quot;https://tools.ietf.org/html/draft-stenberg-httpbis-tcp-03&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TCP&amp;nbsp;Tuning&amp;nbsp;for&amp;nbsp;HTTP&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;재밌어서 그림들도 끼워넣으며 설명해본다.&lt;/p&gt;
&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://evan-moon.github.io/2019/11/26/tcp-congestion-control/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;사이&amp;nbsp;좋게&amp;nbsp;네트워크를&amp;nbsp;나눠&amp;nbsp;쓰는&amp;nbsp;방법,&amp;nbsp;TCP의&amp;nbsp;혼잡&amp;nbsp;제어&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기 혼잡 윈도우(Congestion Window, CWND) 크기 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRWSLg/btqXoaYEKzI/W4vL1r1EEq4ASmxCqIKdn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRWSLg/btqXoaYEKzI/W4vL1r1EEq4ASmxCqIKdn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRWSLg/btqXoaYEKzI/W4vL1r1EEq4ASmxCqIKdn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRWSLg%2FbtqXoaYEKzI%2FW4vL1r1EEq4ASmxCqIKdn1%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;625&quot; height=&quot;312&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기 CWND가 크면(약 10 세그먼트) 첫번째 RTT에서 가져갈 수 있는 데이터양이 커지고, 혼잡제어 과정에서 윈도우의 크기를 &lt;span style=&quot;color: #333333;&quot;&gt;빠르게&lt;/span&gt;&amp;nbsp;증가하는 것이 가능하다.&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;Slow-Start 재시작 비활성화&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LFgj6/btqW4gTwTho/XtJTJZobrJuSebroeRDqE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LFgj6/btqW4gTwTho/XtJTJZobrJuSebroeRDqE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LFgj6/btqW4gTwTho/XtJTJZobrJuSebroeRDqE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLFgj6%2FbtqW4gTwTho%2FXtJTJZobrJuSebroeRDqE0%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;922&quot; height=&quot;400&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.slideserve.com/vincent-browning/congestion-control-powerpoint-ppt-presentation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Congestion&amp;nbsp;Control&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일정 유휴시간(Idle)이 생기면 혼잡 윈도우 값을 초기화하여 Slow Start로 재시작 하는 상황이 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Slow-Start 재시작을 비활성화 하면 오래 지속되는 TCP 연결의 성능이 향상된다.&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;윈도우 스케일링&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmVga0/btqXgo4gvIC/ql2HAQ0bhJtkkpkQ1Ico3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmVga0/btqXgo4gvIC/ql2HAQ0bhJtkkpkQ1Ico3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmVga0/btqXgo4gvIC/ql2HAQ0bhJtkkpkQ1Ico3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmVga0%2FbtqXgo4gvIC%2Fql2HAQ0bhJtkkpkQ1Ico3k%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;625&quot; height=&quot;311&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP의 RWND(수신 윈도우) 크기를 알리기 위해 16비트가 할당되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 최대 크기는 $2^{16} = 65,536 \, byte$다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 RWND의 크기를 키우기 위해 윈도우 스케일링(RFC 1323)이 제공되서 1기가까지 키울 수 있고, 대역폭을 최대한 이용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원리는 기존 RWND값에 좌측으로 시프트할 갯수를 전달하는 것.&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;TCP Fast Open&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;455&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDTVyN/btqXobXyjot/0MRf91KK1Ps1YzaZoKICJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDTVyN/btqXobXyjot/0MRf91KK1Ps1YzaZoKICJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDTVyN/btqXobXyjot/0MRf91KK1Ps1YzaZoKICJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDTVyN%2FbtqXobXyjot%2F0MRf91KK1Ps1YzaZoKICJ1%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;516&quot; height=&quot;455&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;455&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://msandbu.org/tcp-fast-open-citrix-netscaler/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;TCP&amp;nbsp;Fast&amp;nbsp;OPEN&amp;nbsp;&amp;ndash;&amp;nbsp;Citrix&amp;nbsp;NetScaler&lt;/span&gt;&lt;/a&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;SYN 패킷에 데이터 전송을 허가해서 대기시간을 제거할 수 있다.&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: #333333;&quot;&gt;구글에 따르면 HTTP 트랜젝션 네트워크 대기시간을 15%, 전체 페이지로드는 10~40%까지도 단축 시킬 수 있다고.&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://ondemand.tistory.com/235&quot;&gt;TCP Fast Open - 보다 빠르게 웹 컨텐츠를 전송하기 위한 기술&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;&lt;span style=&quot;color: #333333;&quot;&gt;2016년쯤에 엣지에 들어간다는 기사를 보고 알았던 것을 생각하면 비교적 최신 기술. [&lt;/span&gt;&lt;a href=&quot;https://www.windowscentral.com/enable-tcp-fast-open-microsoft-edge-faster-page-load-times&quot;&gt;Enable TCP Fast Open in Microsoft Edge for quicker page load times&lt;/a&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;b&gt;UDP&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관심이 있다면 다음을 읽어보자. [&lt;a href=&quot;https://hpbn.co/building-blocks-of-udp/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Building Blocks of UDP&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;b&gt;TLS&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 링크에는 여러가지가 나왔지만 간단하게 3~4개만 다루려한다. [&lt;a href=&quot;https://hpbn.co/transport-layer-security-tls/#optimizing-for-tls&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Transport&amp;nbsp;Layer&amp;nbsp;Security&amp;nbsp;(TLS)&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크에는 대칭키 암호화 사용(공개키 대신), TLS 레코드 크기 최적화, 인증서 체인 최적화, OCSP(Online Certifiate Status Protocol) 스태플링 설정, HSTS(HTTP Strict Transport Security) 사용 등등이 등장한다.&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;연결 재사용 / 구성 세션 캐싱&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP + TLS 연결 설정을 위한 대기시간과 계산 시간 오버헤드를 막기위해 연결 시간 종료값을 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSL2.0에는 TLS 세션 캐싱이 도입되어 더욱 효율적으로 오버헤드를 제거할 수 있다.&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;CDN 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lx16l/btqXgnRNXvL/tLD0R7KA5XEiaGTy9zIY9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lx16l/btqXgnRNXvL/tLD0R7KA5XEiaGTy9zIY9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lx16l/btqXgnRNXvL/tLD0R7KA5XEiaGTy9zIY9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flx16l%2FbtqXgnRNXvL%2FtLD0R7KA5XEiaGTy9zIY9k%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;625&quot; height=&quot;392&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CDN을 활용하면 물리적인 거리를 줄일 수 있기 때문에 유리하다.&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;TLS 1.3 활성화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0-RTT로 오버헤드가 제거되었다. [&lt;a href=&quot;https://b.luavis.kr/server/tls-1.3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;알아두면 쓸데없는 신비한 TLS 1.3&lt;/a&gt;, &lt;a href=&quot;https://blog.cloudflare.com/introducing-0-rtt/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introducing&amp;nbsp;Zero&amp;nbsp;Round&amp;nbsp;Trip&amp;nbsp;Time&amp;nbsp;Resumption&amp;nbsp;(0-RTT)&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhFgIG/btqW4gTwTjO/5j2Xp3WE0Vm7b9FDy7ugv1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhFgIG/btqW4gTwTjO/5j2Xp3WE0Vm7b9FDy7ugv1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhFgIG/btqW4gTwTjO/5j2Xp3WE0Vm7b9FDy7ugv1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhFgIG%2FbtqW4gTwTjO%2F5j2Xp3WE0Vm7b9FDy7ugv1%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;1280&quot; height=&quot;688&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;688&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.cloudflare.com/encryption-week/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Encryption Week&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;b&gt;+.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 사용되지 않는 TLS False Start가 TLS 1.3의 아이디어와 살짝 비슷하다. [&lt;a href=&quot;https://blog.cryptographyengineering.com/2012/04/16/so-long-false-start-we-hardly-knew-ya/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;So&amp;nbsp;long&amp;nbsp;False&amp;nbsp;Start,&amp;nbsp;we&amp;nbsp;hardly&amp;nbsp;knew&amp;nbsp;ye&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ClientKeyExchange를 보내면 이미 암호화키를 알고 있는 것과 다름 없으므로 어플리케이션 데이터를 전송해도 무방하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7lr0k/btqXj63jZ1D/AqKOCnstksrg1nusA3XVSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7lr0k/btqXj63jZ1D/AqKOCnstksrg1nusA3XVSK/img.png&quot; style=&quot;width: 46.1333%; margin-right: 10px;&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;491&quot; data-widthpercent=&quot;46.68&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7lr0k/btqXj63jZ1D/AqKOCnstksrg1nusA3XVSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7lr0k%2FbtqXj63jZ1D%2FAqKOCnstksrg1nusA3XVSK%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;687&quot; height=&quot;491&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by1vX6/btqXb03E1PT/LtG2MsWF9dz1ZPjOx7W1p0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by1vX6/btqXb03E1PT/LtG2MsWF9dz1ZPjOx7W1p0/img.png&quot; style=&quot;width: 52.7039%;&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;391&quot; data-widthpercent=&quot;53.32&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by1vX6/btqXb03E1PT/LtG2MsWF9dz1ZPjOx7W1p0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby1vX6%2FbtqXb03E1PT%2FLtG2MsWF9dz1ZPjOx7W1p0%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;625&quot; height=&quot;391&quot;/&gt;&lt;/span&gt;&lt;/div&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;- Application&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 프로토콜의 최적화를 다루어보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 좋은 것는 1.X보다 2를 3가 보급된다면 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;b&gt;HTTP 1.X&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Keep-Alive, 파이프 라이닝을 다루었다. [&lt;a href=&quot;https://hpbn.co/http1x/&quot;&gt;HTTP/1.X&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Keep-Alive&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/njuW6/btqXb2Arxjp/t5dEto6LnjotkkKp667WNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/njuW6/btqXb2Arxjp/t5dEto6LnjotkkKp667WNK/img.png&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;857&quot; style=&quot;width: 39.1027%; margin-right: 10px;&quot; data-widthpercent=&quot;39.56&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/njuW6/btqXb2Arxjp/t5dEto6LnjotkkKp667WNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnjuW6%2FbtqXb2Arxjp%2Ft5dEto6LnjotkkKp667WNK%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;625&quot; height=&quot;857&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9XPQa/btqWXaGCemK/3MOg6kE55nK4XXCndc8ygK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9XPQa/btqWXaGCemK/3MOg6kE55nK4XXCndc8ygK/img.png&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;561&quot; style=&quot;width: 59.7345%;&quot; data-widthpercent=&quot;60.44&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9XPQa/btqWXaGCemK/3MOg6kE55nK4XXCndc8ygK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9XPQa%2FbtqWXaGCemK%2F3MOg6kE55nK4XXCndc8ygK%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;625&quot; height=&quot;561&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 연결을 다시 하는 것보다 연결을 유지하여 동일한 TCP 연결을 하용하자는 아이디어.&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;HTTP 파이프 라이닝&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWY4ui/btqWWr2UwJ6/t3EeDis5BxwGifMknqbvb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWY4ui/btqWWr2UwJ6/t3EeDis5BxwGifMknqbvb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWY4ui/btqWWr2UwJ6/t3EeDis5BxwGifMknqbvb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWY4ui%2FbtqWWr2UwJ6%2Ft3EeDis5BxwGifMknqbvb1%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;1012&quot; height=&quot;670&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이프라이닝을 활용하면 Keep-Alive를 사용해 응답을 받지 않고도 여러개의 요청을 하는 것이 가능하다. [&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Connection_management_in_HTTP_1.x&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP/1.x의&amp;nbsp;커넥션&amp;nbsp;관리&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc6aCU/btqWWtl6aZh/A4sUqYxhpHxZkruU1NUMgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc6aCU/btqWWtl6aZh/A4sUqYxhpHxZkruU1NUMgk/img.png&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;427&quot; style=&quot;width: 47.3067%; margin-right: 10px;&quot; data-widthpercent=&quot;47.86&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc6aCU/btqWWtl6aZh/A4sUqYxhpHxZkruU1NUMgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc6aCU%2FbtqWWtl6aZh%2FA4sUqYxhpHxZkruU1NUMgk%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;625&quot; height=&quot;427&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL0Iu2/btqW4hkCZdS/7G7psgcEYuKT8ZSKQtLRCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL0Iu2/btqW4hkCZdS/7G7psgcEYuKT8ZSKQtLRCk/img.png&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;392&quot; style=&quot;width: 51.5305%;&quot; data-widthpercent=&quot;52.14&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL0Iu2/btqW4hkCZdS/7G7psgcEYuKT8ZSKQtLRCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL0Iu2%2FbtqW4hkCZdS%2F7G7psgcEYuKT8ZSKQtLRCk%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;625&quot; height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에서 FIFO로 각각이 아니라 병렬처리를 해서 합쳐보내줄 경우 더 단축시키는 것도 가능하다.&lt;/p&gt;
&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;HTTP 2&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글의 &lt;a href=&quot;https://ko.wikipedia.org/wiki/SPDY&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SPDY&lt;/a&gt;에 기반해 만들어진 표준이다. [&lt;a href=&quot;https://hpbn.co/http2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP/2&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/http2?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP/2 소개&lt;/a&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcpDNc/btqW4iKFEua/324tOqg7KJAcNgJEulJm40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcpDNc/btqW4iKFEua/324tOqg7KJAcNgJEulJm40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcpDNc/btqW4iKFEua/324tOqg7KJAcNgJEulJm40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcpDNc%2FbtqW4iKFEua%2F324tOqg7KJAcNgJEulJm40%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;625&quot; height=&quot;526&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;526&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://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HPACK&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdwIbZ/btqXoaqOJnB/u1AlEKfYYZlD2Z6lTGeGik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdwIbZ/btqXoaqOJnB/u1AlEKfYYZlD2Z6lTGeGik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdwIbZ/btqXoaqOJnB/u1AlEKfYYZlD2Z6lTGeGik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdwIbZ%2FbtqXoaqOJnB%2Fu1AlEKfYYZlD2Z6lTGeGik%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;625&quot; height=&quot;321&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l7etD/btqW8FZNAwv/uKcTNJVi4LPEpnLg92f62K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l7etD/btqW8FZNAwv/uKcTNJVi4LPEpnLg92f62K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l7etD/btqW8FZNAwv/uKcTNJVi4LPEpnLg92f62K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl7etD%2FbtqW8FZNAwv%2FuKcTNJVi4LPEpnLg92f62K%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;625&quot; height=&quot;136&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;136&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;멀티플렉싱&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 1.1의 파이프라이닝을 넘어서 다수의 응답과 요청을 동시적으로, 독립적으로 처리할 수 있다. [&lt;a href=&quot;https://kemptechnologies.com/solutions/http2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LoadMaster - HTTP/2&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AWbJu/btqW4gMMuBe/iXFVHAhLFopqOvH12q8AaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AWbJu/btqW4gMMuBe/iXFVHAhLFopqOvH12q8AaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AWbJu/btqW4gMMuBe/iXFVHAhLFopqOvH12q8AaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAWbJu%2FbtqW4gMMuBe%2FiXFVHAhLFopqOvH12q8AaK%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;500&quot; height=&quot;266&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;266&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스트림 우선순위&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CLDw2/btqWXbFuPuE/NwlseiOzOVffiTzImlZKA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CLDw2/btqWXbFuPuE/NwlseiOzOVffiTzImlZKA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CLDw2/btqWXbFuPuE/NwlseiOzOVffiTzImlZKA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCLDw2%2FbtqWXbFuPuE%2FNwlseiOzOVffiTzImlZKA0%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;625&quot; height=&quot;263&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리소스 간 우선순위를 정하여 Critial Rendering Path의 개선에 도움이 된다.&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;widthContent&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVqSYX/btqXb1BvCHY/0qGmmHV7vQg5AURDykSRsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVqSYX/btqXb1BvCHY/0qGmmHV7vQg5AURDykSRsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVqSYX/btqXb1BvCHY/0qGmmHV7vQg5AURDykSRsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVqSYX%2FbtqXb1BvCHY%2F0qGmmHV7vQg5AURDykSRsk%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;625&quot; height=&quot;510&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;510&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버푸시&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트의 요청이 없더라도 서버에서 컨텐츠를 Push할 수 있다. [&lt;a href=&quot;https://www.tutorialdocs.com/article/http2-server-push.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP/2&amp;nbsp;Server&amp;nbsp;Push&amp;nbsp;Tutorial&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uQUcn/btqXoaj2Zh8/Hjkv3Kg6HFPU9jEo498gWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uQUcn/btqXoaj2Zh8/Hjkv3Kg6HFPU9jEo498gWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uQUcn/btqXoaj2Zh8/Hjkv3Kg6HFPU9jEo498gWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuQUcn%2FbtqXoaj2Zh8%2FHjkv3Kg6HFPU9jEo498gWK%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;800&quot; height=&quot;402&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;402&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;243&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2It5S/btqW8GYHmdQ/kJx6Jq3m2ralDTUoCXVZ8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2It5S/btqW8GYHmdQ/kJx6Jq3m2ralDTUoCXVZ8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2It5S/btqW8GYHmdQ/kJx6Jq3m2ralDTUoCXVZ8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2It5S%2FbtqW8GYHmdQ%2FkJx6Jq3m2ralDTUoCXVZ8K%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;625&quot; height=&quot;243&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;243&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HTTP3(실험적, 개발중)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP3는 앞서 소개한 TLS 1.3과 UDP기반 프로토콜인 QUIC로 구성되어 있다. [&lt;a href=&quot;https://blog.cloudflare.com/ko/http3-the-past-present-and-future-ko/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP/3:&amp;nbsp;과거,&amp;nbsp;현재&amp;nbsp;그리고&amp;nbsp;미래&lt;/a&gt;, &lt;a href=&quot;https://http3-explained.haxx.se/ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP/3 explained&lt;/a&gt;, &lt;a href=&quot;https://devahea.github.io/2019/04/30/5G-%EC%B4%88%EC%97%B0%EA%B2%B0%EC%8B%9C%EB%8C%80%EC%97%90-%EC%9B%B9-HTTP%EC%9D%98-%EB%8C%80%EC%95%88%EC%9D%80-QUIC/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;5G 초연결시대에 웹 HTTP의 대안은 QUIC?&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;3004&quot; data-origin-height=&quot;1202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ANCNX/btqXj78ZCN3/4gQbCA23zrc780kEkQV1Ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ANCNX/btqXj78ZCN3/4gQbCA23zrc780kEkQV1Ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ANCNX/btqXj78ZCN3/4gQbCA23zrc780kEkQV1Ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FANCNX%2FbtqXj78ZCN3%2F4gQbCA23zrc780kEkQV1Ak%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;3004&quot; height=&quot;1202&quot; data-origin-width=&quot;3004&quot; data-origin-height=&quot;1202&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;QUIC&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[&lt;a href=&quot;https://blog.cloudflare.com/the-road-to-quic/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Road&amp;nbsp;to&amp;nbsp;QUIC&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;744&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL7JTt/btqWX555yin/Lv3lRYrUwcHBI1Gt35FYHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL7JTt/btqWX555yin/Lv3lRYrUwcHBI1Gt35FYHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL7JTt/btqWX555yin/Lv3lRYrUwcHBI1Gt35FYHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL7JTt%2FbtqWX555yin%2FLv3lRYrUwcHBI1Gt35FYHK%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;1038&quot; height=&quot;744&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;744&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP는 신뢰성을 보장하기 위해 패킷이 손실되면 패킷을 다시 전송하고 목적지를 찾는 동안 전체 TCP 연결이 중단된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;하지만 QUIC는 UDP 기반이기 때문에 다른 스트림은 독립적으로 이루어지므로 모든 스트림의 전속을 막지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1783&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvXGx7/btqWWs8z5Cs/8gjV9Ow1nmtTiKKvgt1w5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvXGx7/btqWWs8z5Cs/8gjV9Ow1nmtTiKKvgt1w5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvXGx7/btqWWs8z5Cs/8gjV9Ow1nmtTiKKvgt1w5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdvXGx7%2FbtqWWs8z5Cs%2F8gjV9Ow1nmtTiKKvgt1w5K%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;1783&quot; height=&quot;330&quot; data-origin-width=&quot;1783&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1783&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/skbfE/btqXoaK616h/YTTWCETULKitMOUP81KcW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/skbfE/btqXoaK616h/YTTWCETULKitMOUP81KcW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/skbfE/btqXoaK616h/YTTWCETULKitMOUP81KcW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FskbfE%2FbtqXoaK616h%2FYTTWCETULKitMOUP81KcW0%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;1783&quot; height=&quot;330&quot; data-origin-width=&quot;1783&quot; data-origin-height=&quot;330&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP Fasct Open과 TLS에서 있던 문제점을 수정,&amp;nbsp;TLS 1.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;b&gt;- 기타&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://hpbn.co/wifi/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WiFi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hpbn.co/optimizing-for-mobile-networks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Optimizing for Mobile Networks&lt;/a&gt;&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;배터리등을 고려하는 것도 있지만 가장 눈에 띄는 것은 Adaptive HTTP Streaming이었다. [&lt;a href=&quot;https://meetup.toast.com/posts/131&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹&amp;nbsp;기술로&amp;nbsp;구현하는&amp;nbsp;Adaptive&amp;nbsp;HTTP&amp;nbsp;Streaming&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEvnpr/btqW4iDRSVi/i67E1KG2kkhW5pyDoPR5nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEvnpr/btqW4iDRSVi/i67E1KG2kkhW5pyDoPR5nk/img.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;257&quot; style=&quot;width: 49.3635%; margin-right: 10px;&quot; data-widthpercent=&quot;49.94&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEvnpr/btqW4iDRSVi/i67E1KG2kkhW5pyDoPR5nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEvnpr%2FbtqW4iDRSVi%2Fi67E1KG2kkhW5pyDoPR5nk%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;600&quot; height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1UcmU/btqW1t6Iu7e/GWYv4kRQC0dcSo7LzUvGx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1UcmU/btqW1t6Iu7e/GWYv4kRQC0dcSo7LzUvGx1/img.png&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;256&quot; style=&quot;width: 49.4737%;&quot; data-widthpercent=&quot;50.06&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1UcmU/btqW1t6Iu7e/GWYv4kRQC0dcSo7LzUvGx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1UcmU%2FbtqW1t6Iu7e%2FGWYv4kRQC0dcSo7LzUvGx1%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;599&quot; height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/div&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;더 많은 해킹을 하고 싶다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오톡의 겁나빠른황소의 Loco 프로토콜처럼 직접 서비스 맞춤형 프로토콜을 만들 수 있고,&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;회사&amp;nbsp;측은&amp;nbsp;&amp;ldquo;패킷&amp;nbsp;사이즈&amp;nbsp;경량화와&amp;nbsp;푸시&amp;nbsp;시스템구조&amp;nbsp;최적화,&amp;nbsp;백엔드&amp;nbsp;시스템&amp;nbsp;성능&amp;nbsp;개선을&amp;nbsp;통해&amp;nbsp;3G&amp;nbsp;네트워크에서도&amp;nbsp;빠르고&amp;nbsp;효율적으로&amp;nbsp;메시지를&amp;nbsp;전달할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;됐다&amp;rdquo;고&amp;nbsp;설명했다.&amp;nbsp;카카오는&amp;nbsp;패킷&amp;nbsp;사이즈를&amp;nbsp;최적화한&amp;nbsp;메시지를&amp;nbsp;여러&amp;nbsp;경로로&amp;nbsp;나누어&amp;nbsp;처리,&amp;nbsp;일&amp;nbsp;6억건에&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;했다.&lt;br /&gt;- &lt;a href=&quot;https://biz.chosun.com/site/data/html_dir/2011/10/04/2011100402364.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;카카오톡, 메시지 전송속도 최고 20배 빨라진다&lt;/a&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bpak.org/blog/2012/12/kakaotalk-loco-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-%EB%B6%84%EC%84%9D-1/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[KakaoTalk+]&amp;nbsp;LOCO&amp;nbsp;프로토콜&amp;nbsp;분석&amp;nbsp;(1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bpak.org/blog/2012/12/kakaotalk-loco-%ed%94%84%eb%a1%9c%ed%86%a0%ec%bd%9c-%eb%b6%84%ec%84%9d-2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[KakaoTalk+] LOCO 프로토콜 분석 (2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bpak.org/blog/2012/12/kakaotalk-loco-%ed%94%84%eb%a1%9c%ed%86%a0%ec%bd%9c-%eb%b6%84%ec%84%9d-3/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[KakaoTalk+] LOCO 프로토콜 분석 (3)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bpak.org/blog/2012/12/kakaotalk-loco-%ed%94%84%eb%a1%9c%ed%86%a0%ec%bd%9c-%eb%b6%84%ec%84%9d-4/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[KakaoTalk+] LOCO 프로토콜 분석 (4)&lt;/a&gt;&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;a href=&quot;https://matrix.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Matrix&lt;/a&gt;란 채팅 프로토콜의 &lt;a href=&quot;https://tools.ietf.org/html/rfc7252&quot;&gt;CoAP&lt;/a&gt;+&lt;a href=&quot;https://tools.ietf.org/html/rfc7049&quot;&gt;CBOR&lt;/a&gt;+&lt;a href=&quot;https://noiseprotocol.org&quot;&gt;Noise&lt;/a&gt;+&lt;a href=&quot;https://golang.org/pkg/compress/flate/&quot;&gt;Flate&lt;/a&gt;+&lt;a href=&quot;https://tools.ietf.org/rfc/rfc768.txt&quot;&gt;UDP&lt;/a&gt;을 이용한 사례를 살펴보자. [&lt;a href=&quot;https://matrix.org/blog/2019/03/12/breaking-the-100-bps-barrier-with-matrix-meshsim-coap-proxy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Breaking the 100bps barrier with Matrix, meshsim &amp;amp; coap-proxy&lt;/a&gt;(&lt;a href=&quot;https://matrix.org/blog/wp-content/uploads/2019/02/2019-02-03-FOSDEM-Low-Bandwidth.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PDF&lt;/a&gt;), &lt;a href=&quot;https://github.com/tsu-iscd/modern-crypto-protocols&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Modern&amp;nbsp;Cryptography&amp;nbsp;Protocols&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JSON =&amp;gt; CBOR [&lt;a href=&quot;https://cbor.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CBOR&lt;/a&gt;, &lt;a href=&quot;http://tutorials.jenkov.com/rion/rion-vs-other-formats.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RION&amp;nbsp;vs.&amp;nbsp;Other&amp;nbsp;Formats&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;HTTP =&amp;gt; CoAP [&lt;a href=&quot;https://en.wikipedia.org/wiki/Constrained_Application_Protocol&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Constrained&amp;nbsp;Application&amp;nbsp;Protocol&lt;/a&gt;, &lt;a href=&quot;https://github.com/matrix-org/go-coap/blob/e156f6bb5d3c728040ceffd09685610128d3c63c/conn.go#L340-L371&quot;&gt;frame the Noise handshake packets as CoAP&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;TLS =&amp;gt; &lt;a href=&quot;https://noiseprotocol.org/noise.html#noise-pipes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nosie Pipe&lt;/a&gt; [&lt;a href=&quot;https://duo.com/labs/tech-notes/noise-protocol-framework-intro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;An&amp;nbsp;Introduction&amp;nbsp;to&amp;nbsp;the&amp;nbsp;Noise&amp;nbsp;Protocol&amp;nbsp;Framework&lt;/a&gt;, &lt;a href=&quot;https://noisesocket.org/post/1/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NoiseSocket instroduction&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://golang.org/pkg/compress/flate/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Flate&lt;/a&gt;를 통한 압축&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;Matrix에 대해 알아보다보니 IOT 프로토콜들도 나온다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@rinu.gour123/4-major-iot-protocols-mqtt-coap-amqp-dds-46016897c3e9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;4&amp;nbsp;Major&amp;nbsp;IoT&amp;nbsp;Protocols&amp;nbsp;&amp;mdash;&amp;nbsp;MQTT,&amp;nbsp;CoAP,&amp;nbsp;AMQP,&amp;nbsp;DDS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.slideshare.net/paolopat/mqtt-iot-protocols-comparison&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MQTT&amp;nbsp;&amp;amp;&amp;nbsp;IoT&amp;nbsp;protocols&amp;nbsp;comparison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.embeddedcomputing.com/technology/software-and-os/which-iot-protocol-should-i-use-for-my-system&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Which&amp;nbsp;IoT&amp;nbsp;protocol&amp;nbsp;should&amp;nbsp;I&amp;nbsp;use&amp;nbsp;for&amp;nbsp;my&amp;nbsp;system?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfwireless-world.com/Terminology/Difference-between-CoAP-and-HTTP.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CoAP&amp;nbsp;vs&amp;nbsp;HTTP&amp;nbsp;|&amp;nbsp;difference&amp;nbsp;between&amp;nbsp;CoAP&amp;nbsp;and&amp;nbsp;HTTP&lt;/a&gt;&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;JSON 대체 포맷들. 포맷마다 장단점과 구현된 언어들의 차이가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://tutorials.jenkov.com/rion/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RION&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cbor.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CBOR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://msgpack.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MessagePack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/protocol-buffers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Protocol Buffers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://capnproto.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cap&amp;rsquo;n&amp;nbsp;Proto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://thrift.apache.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Thrift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bincode-org/bincode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bincode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://microsoft.github.io/bond/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bond&lt;/a&gt;&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;탈 중앙화와 관련된 네트워크 프로토콜인 IPFS도 재밌다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/638857976381325312/ipfs-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-%ED%9D%A5%EB%AF%B8%EB%A1%AD%EB%84%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IPFS&amp;nbsp;프로토콜?&amp;nbsp;흥미롭네.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2.7&amp;nbsp; API 포인트 최적화&lt;/h4&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;span&gt;&amp;nbsp;&lt;/span&gt;Server, Javascript&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 등장한 포맷 뿐만 아니라 API&amp;nbsp; &amp;nbsp;구조도 고민할 수 있다. [&lt;a href=&quot;https://medium.com/devops-dudes/graphql-vs-rest-vs-grpc-411a0a60d18d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GraphQL&amp;nbsp;vs&amp;nbsp;REST&amp;nbsp;vs&amp;nbsp;gRPC&lt;/a&gt;, &lt;a href=&quot;https://www.redhat.com/architect/apis-soap-rest-graphql-grpc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;An Architect's guide to APIs: SOAP, REST, GraphQL, and gRPC&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://www.sensedia.com/post/apis-rest-graphql-or-grpc-who-wins-this-game&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;APIs&amp;nbsp;REST,&amp;nbsp;GraphQL&amp;nbsp;or&amp;nbsp;gRPC&amp;nbsp;&amp;ndash;&amp;nbsp;Who&amp;nbsp;wins&amp;nbsp;this&amp;nbsp;game?&lt;/a&gt;, &lt;a href=&quot;https://cloud.google.com/blog/ko/products/api-management/interacting-with-apis-rest-and-graphql&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GraphQL:&amp;nbsp;API&amp;nbsp;소비자에&amp;nbsp;대한&amp;nbsp;일관된&amp;nbsp;접근방식&amp;nbsp;수립&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;크게 다음처럼 Rest, GraphQL, gRPC정도로 구분할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cd8VBu/btruDDntIKp/PtyxEKrcyLEmHtBJigczD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cd8VBu/btruDDntIKp/PtyxEKrcyLEmHtBJigczD0/img.png&quot; width=&quot;590&quot; height=&quot;248&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;248&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cd8VBu/btruDDntIKp/PtyxEKrcyLEmHtBJigczD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcd8VBu%2FbtruDDntIKp%2FPtyxEKrcyLEmHtBJigczD0%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;590&quot; height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/upVQ1/btrulSmdDZu/1P9v17mTIylJ7NSKo4Sus1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/upVQ1/btrulSmdDZu/1P9v17mTIylJ7NSKo4Sus1/img.png&quot; width=&quot;590&quot; height=&quot;248&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;248&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/upVQ1/btrulSmdDZu/1P9v17mTIylJ7NSKo4Sus1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FupVQ1%2FbtrulSmdDZu%2F1P9v17mTIylJ7NSKo4Sus1%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;590&quot; height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6Qhow/btruxkboLbm/cJ7TgksZD3ZUNjaYMbtlAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6Qhow/btruxkboLbm/cJ7TgksZD3ZUNjaYMbtlAk/img.png&quot; width=&quot;590&quot; height=&quot;248&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;248&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6Qhow/btruxkboLbm/cJ7TgksZD3ZUNjaYMbtlAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6Qhow%2FbtruxkboLbm%2FcJ7TgksZD3ZUNjaYMbtlAk%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;590&quot; height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wOYSc/btruAsmtSPq/vqNqgs3gBrw2XuZX9Nj06k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wOYSc/btruAsmtSPq/vqNqgs3gBrw2XuZX9Nj06k/img.png&quot; width=&quot;1232&quot; height=&quot;653&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;653&quot; data-is-animation=&quot;false&quot; style=&quot;width: 29.8369%; margin-right: 10px;&quot; data-widthpercent=&quot;30.55&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wOYSc/btruAsmtSPq/vqNqgs3gBrw2XuZX9Nj06k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwOYSc%2FbtruAsmtSPq%2FvqNqgs3gBrw2XuZX9Nj06k%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;1232&quot; height=&quot;653&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvOKW5/btrulTrSuY6/UEWIwAXLQkDgO6WHp5tEe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvOKW5/btrulTrSuY6/UEWIwAXLQkDgO6WHp5tEe1/img.png&quot; width=&quot;1232&quot; height=&quot;690&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;690&quot; data-is-animation=&quot;false&quot; style=&quot;width: 28.2369%; margin-right: 10px;&quot; data-widthpercent=&quot;28.91&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvOKW5/btrulTrSuY6/UEWIwAXLQkDgO6WHp5tEe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvOKW5%2FbtrulTrSuY6%2FUEWIwAXLQkDgO6WHp5tEe1%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;1232&quot; height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFHJpn/btruFf7JB9S/DnkGGFtvuq68UT8Py7kW40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFHJpn/btruFf7JB9S/DnkGGFtvuq68UT8Py7kW40/img.png&quot; width=&quot;1232&quot; height=&quot;492&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;492&quot; data-is-animation=&quot;false&quot; style=&quot;width: 39.6006%;&quot; data-widthpercent=&quot;40.54&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFHJpn/btruFf7JB9S/DnkGGFtvuq68UT8Py7kW40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFHJpn%2FbtruFf7JB9S%2FDnkGGFtvuq68UT8Py7kW40%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;1232&quot; height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDNdxr/btruxj4B8JL/CkM964YfrZgk35akMVjt6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDNdxr/btruxj4B8JL/CkM964YfrZgk35akMVjt6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDNdxr/btruxj4B8JL/CkM964YfrZgk35akMVjt6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDNdxr%2Fbtruxj4B8JL%2FCkM964YfrZgk35akMVjt6K%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;960&quot; height=&quot;540&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&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;GraphQL은 쿼리를 보내 필요한 데이터만을 가져오기 때문에 과도한 데이터나 부족한 데이터 호출 응답을 방지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/graphql/dataloader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;dataloader&lt;/a&gt;나 &lt;a href=&quot;https://github.com/joonhocho/batchloader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;batchloader&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;gRPC의 경우 바이너리를 사용하여 크기가 낮은 편이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 HTTP3를 지원하지 않는 모양인데,&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;&lt;a href=&quot;https://github.com/grpc/grpc/issues/19126&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Support gRPC over HTTP/3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/safetycultureengineering/grpc-over-http-3-53f41fc0761e&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gRPC over HTTP/3&lt;/a&gt;&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;b&gt;해결방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상적인 방법은 GraphQL의 편리함과 데이터 로더 + gRPC처럼 가벼운 포맷이라 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 글들은 GraphQL과 가벼운 포맷을 사용하려는 시도.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/swlh/a-proposal-for-graphql-optimization-with-cbor-protocol-buffer-capn-proto-or-another-20e515a2b173&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Proposal&amp;nbsp;for&amp;nbsp;GraphQL&amp;nbsp;Response&amp;nbsp;Optimization&amp;nbsp;With&amp;nbsp;CBOR,&amp;nbsp;Protocol&amp;nbsp;Buffer,&amp;nbsp;Cap&amp;rsquo;n&amp;nbsp;Proto&amp;nbsp;or&amp;nbsp;Another&amp;nbsp;Serialization&amp;nbsp;Format&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://levelup.gitconnected.com/microservices-in-rust-with-graphql-and-capn-proto-e125bec23eae&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Microservices&amp;nbsp;in&amp;nbsp;Rust&amp;nbsp;with&amp;nbsp;GraphQL&amp;nbsp;and&amp;nbsp;Cap&amp;rsquo;n&amp;nbsp;Proto&lt;/a&gt;&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;gRPC의 게이트웨이로 GraphQL을 제공하는 방법도 있는듯하다.&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;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bH1U3K/btruAr18fkr/g2RtBsEzoW71Y08UpFQPy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH1U3K/btruAr18fkr/g2RtBsEzoW71Y08UpFQPy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH1U3K/btruAr18fkr/g2RtBsEzoW71Y08UpFQPy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH1U3K%2FbtruAr18fkr%2Fg2RtBsEzoW71Y08UpFQPy1%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;700&quot; height=&quot;426&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&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;a href=&quot;https://github.com/google/rejoiner&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;google/rejoiner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ysugimoto/grpc-graphql-gateway&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ysugimoto/grpc-graphgl-gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@svengau/when-graphql-meets-grpc-3e9729d32e05&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;When&amp;nbsp;GraphQL&amp;nbsp;meets&amp;nbsp;gRPC&amp;hellip;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.3 합치기&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;h4 data-ke-size=&quot;size20&quot;&gt;1.3.1 파일 결합하기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Content&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;script와 css파일을 합쳐서 요청횟수를 줄이는 것.&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 style=&quot;font-size: 1.12em;&quot; 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;a href=&quot;https://webpack.js.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpack&lt;/a&gt;, &lt;a href=&quot;https://rollupjs.org/guide/en/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rollup&lt;/a&gt;, &lt;a href=&quot;https://ko.parceljs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Parcel&lt;/a&gt;이 존재한다.[&lt;a href=&quot;https://medium.com/better-programming/the-battle-of-bundlers-6333a4e3eda9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비교1&lt;/a&gt;, &lt;a href=&quot;https://medium.com/js-imaginea/comparing-bundlers-webpack-rollup-parcel-f8f5dc609cfd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비교2&lt;/a&gt;, &lt;a href=&quot;https://blog.bitsrc.io/choosing-the-right-javascript-bundler-in-2020-f9b1eae0d12b&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;TOAST UI에서 &lt;a href=&quot;https://ui.toast.com/fe-guide/ko_BUNDLER/&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1.3.2 CSS Sprites&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;개요&lt;/span&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;b&gt;분류:&lt;/b&gt; Image&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1056&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dl0EwH/btqW1r8SiUi/ouy0uGgr1tNnAuRMa6AqrK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dl0EwH/btqW1r8SiUi/ouy0uGgr1tNnAuRMa6AqrK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dl0EwH/btqW1r8SiUi/ouy0uGgr1tNnAuRMa6AqrK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdl0EwH%2FbtqW1r8SiUi%2Fouy0uGgr1tNnAuRMa6AqrK%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;1056&quot; height=&quot;136&quot; data-origin-width=&quot;1056&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&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;배경 이미지들을 단일 이미지로 결합하고, CSS의 background-image와 background-positon속성을 사용해 원하는 이미지 세그먼트를 표시한다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프라이트의&amp;nbsp;이미지를&amp;nbsp;세로가&amp;nbsp;아닌&amp;nbsp;가로로&amp;nbsp;정렬하면&amp;nbsp;파일&amp;nbsp;크기가&amp;nbsp;줄어&amp;nbsp;듭니다.&lt;/li&gt;
&lt;li&gt;스프라이트에&amp;nbsp;유사한&amp;nbsp;색상을&amp;nbsp;결합하면&amp;nbsp;PNG8에&amp;nbsp;맞도록&amp;nbsp;색상&amp;nbsp;수를&amp;nbsp;낮게&amp;nbsp;(256&amp;nbsp;색&amp;nbsp;미만)&amp;nbsp;유지할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/li&gt;
&lt;li&gt;&quot;모바일&amp;nbsp;친화적&quot;으로&amp;nbsp;이미지&amp;nbsp;사이에&amp;nbsp;큰&amp;nbsp;간격을&amp;nbsp;두지&amp;nbsp;마십시오.&amp;nbsp;&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;100x100&amp;nbsp;이미지는&amp;nbsp;1&amp;nbsp;만&amp;nbsp;픽셀이며&amp;nbsp;1000x1000은&amp;nbsp;1&amp;nbsp;백만&amp;nbsp;픽셀입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NHN의 경우 CSM(CSS Sprites Matrix)라는 가이드라인을 통해 최적화를 한다.[&lt;a href=&quot;https://nuli.navercorp.com/sharing/seminar/2012/06&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Front-End 최적화의 끝판왕, CSM + Markup Complexity&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Matrix 배열: 10x10 형태의 이미지 배치, 공간 활용도 향상, 유지보수&lt;/li&gt;
&lt;li&gt;이미지 개수 제한: 페이지당 2개 이하&lt;/li&gt;
&lt;li&gt;해상도 제한: 3메가픽셀(1024x1024)&lt;/li&gt;
&lt;li&gt;PNG 포맷&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;그런데 HTTP/2 에서는 스프라이트가 안티패턴이 될 수 있다는 말이 있어 관련 자료를 찾아보게 되었다. [&lt;a href=&quot;https://dev.zzoman.com/2017/11/29/image-sprite-vs-webpack-string/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모바일 환경에서 이미지 스프라이트가 필요할까?&lt;/a&gt;, &lt;a href=&quot;https://blog.octo.com/en/http2-arrives-but-sprite-sets-aint-no-dead/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTP/2&amp;nbsp;arrives&amp;nbsp;but&amp;nbsp;sprite&amp;nbsp;sets&amp;nbsp;ain&amp;rsquo;t&amp;nbsp;no&amp;nbsp;dead&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;단일 이미지가 낫다!&lt;br /&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;iOS 웹브라우저의 경우 25kb 이상의 요소는 캐싱하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Image Sprite를 써야한다!&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PNG 압축 알고리즘이 여러 개의 단일 이미지보다 한장의 스프라이트 이미지에서 더욱 효율적으로 동작한다.&lt;/li&gt;
&lt;li&gt;HTTP/2는 로드 시간이 현저히 감소하지만 HTTP 프로토콜 향상만으로는 front-end 최적화의 유용성을 충분히 대체하기 어렵다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로 따지면 HTTP/2에서 로드 시간이 확연히 줄어들긴하나 효과는 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XV1Hn/btqWWsOeajj/6sAZwAznGYwlEKyYCdzO8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XV1Hn/btqWWsOeajj/6sAZwAznGYwlEKyYCdzO8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XV1Hn/btqWWsOeajj/6sAZwAznGYwlEKyYCdzO8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXV1Hn%2FbtqWWsOeajj%2F6sAZwAznGYwlEKyYCdzO8K%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;600&quot; height=&quot;416&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;416&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;widthContent&quot; data-origin-width=&quot;86&quot; data-origin-height=&quot;20&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWSx3b/btqWXamh7cv/VXaDUbVNSkvgOkwmgP0HfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWSx3b/btqWXamh7cv/VXaDUbVNSkvgOkwmgP0HfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWSx3b/btqWXamh7cv/VXaDUbVNSkvgOkwmgP0HfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWSx3b%2FbtqWXamh7cv%2FVXaDUbVNSkvgOkwmgP0HfK%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;86&quot; height=&quot;20&quot; data-origin-width=&quot;86&quot; data-origin-height=&quot;20&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 스프라이트화된 이미지를 가지고 네개의 아이콘을 만들고 싶다면 다음과 같이 할 수 있다. [&lt;a href=&quot;http://tcpschool.com/css/css_basic_imageSprites&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS 이미지 스프라이트&lt;/a&gt;]&lt;/p&gt;
&lt;pre id=&quot;code_1584963010341&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.up, .down, .right, .left { background: url(&quot;/examples/images/img_image_sprites.png&quot;) no-repeat; }
.up { width: 21px; height: 20px; background-position: 0 0; }
.down { width: 21px; height: 20px; background-position: -21px 0; }
.right { width: 22px; height: 20px; background-position: -42px 0; }
.left { width: 22px; height: 20px; background-position: -65px 0; }&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;a href=&quot;https://alistapart.com/article/sprites/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Sprites: Image Slicing&amp;rsquo;s Kiss of Death&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Images/Implementing_image_sprites_in_CSS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS로&amp;nbsp;이미지&amp;nbsp;스프라이트&amp;nbsp;구현하기&lt;/a&gt;, &lt;a href=&quot;https://css-tricks.com/css-sprites/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Tricks&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;사실 스프라이트의 가장 큰 단점은 스프라이트 이미지를 만들기 불편하고, 계산해서 쓰기 또한 힘들다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/twolfson/spritesmith&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;spritesmith&lt;/a&gt;(&lt;a href=&quot;https://github.com/mixtur/webpack-spritesmith&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹팩&lt;/a&gt;)가 스프라이트 이미지를 쉽게 만들고 관리할 수 있는 것으로 알려져 있는데 &lt;a href=&quot;https://github.com/vusion/css-sprite-loader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;css-sprite-loader&lt;/a&gt;(Webpack Plugin)를 사용하면 background-size, background-position을 알아서 계산해서 대입해주며 이미지 크기(@2x, @4x...)별로 대응도 가능하다.&lt;/p&gt;
&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_1584965223827&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.foo {
    background: url('../assets/gift.png?sprite');
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 경로 끝에 ?sprite를 넣으면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1584965259360&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.foo {
    background: url(/sprite.png?5d40e339682970eb14baf6110a83ddde) no-repeat;
    background-position: -100px -0px;
}&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;a href=&quot;https://github.com/naver/image-sprite-webpack-plugin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;image-sprite-webpack-plugin&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;SVG의 경우 &lt;a href=&quot;https://github.com/jkphl/svg-sprite&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;svg-sprite&lt;/a&gt;와 JetBrains의 &lt;a href=&quot;https://github.com/JetBrains/svg-sprite-loader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;svg-sprite-loader&lt;/a&gt;를 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SVG &lt;a href=&quot;https://css-tricks.com/svg-use-with-external-reference-take-2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;use&lt;/a&gt;와 &lt;a href=&quot;http://simurai.com/blog/2012/04/02/svg-stacks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;stacks&lt;/a&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;1.3.3 Image maps&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Image&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%B4%EB%AF%B8%EC%A7%80_%EB%A7%B5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이미지 맵&lt;/a&gt;(Image maps)[&lt;a href=&quot;https://www.w3.org/TR/html401/struct/objects.html#h-13.6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;w3.org&lt;/a&gt;]은 클릭 가능한 영역이 여러가지 있는 하나의 이미지이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;70&quot; data-origin-height=&quot;167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p3Mg9/btqW1tZX2P5/p2Ru7e6YwBI6eB8NWPKD70/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p3Mg9/btqW1tZX2P5/p2Ru7e6YwBI6eB8NWPKD70/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p3Mg9/btqW1tZX2P5/p2Ru7e6YwBI6eB8NWPKD70/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp3Mg9%2FbtqW1tZX2P5%2Fp2Ru7e6YwBI6eB8NWPKD70%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;70&quot; height=&quot;167&quot; data-origin-width=&quot;70&quot; data-origin-height=&quot;167&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 오래되어 보이지만.. 위와 같이 통으로 된 이미지에 각 페이지로 이동하는 링크를 달 때 사용할 수 있다.[&lt;a href=&quot;http://www.javascriptkit.com/howto/imagemap.shtml&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Creating&amp;nbsp;HTML&amp;nbsp;Image&amp;nbsp;Maps&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;스프라이트처럼 여러 이미지를 단일 이미지로 결합하여 HTTP 요청 수를 줄인다는 아이디어.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 이미지 맵은 페이지에서 메뉴바(Navigation Bar)처럼 이미지가 인접한 경우에만 작동하며 이미지 맵의 좌표를 정의하는 것은 지루하고 오류가 발생하기 쉽고 접근성이 떨어진다.&lt;/p&gt;
&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;a href=&quot;https://github.com/n-peugnet/image-map-creator&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image Map Creator&lt;/a&gt;나 다양한 생성기(&lt;a href=&quot;https://www.image-map.net/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image Map Generator&lt;/a&gt;, &lt;a href=&quot;https://imagemap.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image map org&lt;/a&gt;, &lt;a href=&quot;https://www.image-maps.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;image maps com&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;a href=&quot;https://12oss.github.io/linkresponsively/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Responsive Image Map Generator1&lt;/a&gt;, &lt;a href=&quot;https://www.zaneray.com/responsive-image-map/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Responsive Image Map Generator2&lt;/a&gt;, &lt;a href=&quot;https://image-map.weebly.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Responsive&amp;nbsp;Image&amp;nbsp;Map&amp;nbsp;Creator&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://github.com/clarketm/image-map&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image-Map&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://github.com/davidjbradshaw/image-map-resizer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image Map Resize&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://github.com/stowball/jQuery-rwdImageMaps&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;jQuery RWD Image Maps&lt;/a&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;1.3.4 인라인 인코딩&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Content, Image&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 인코딩(Inline Encoding)은 &lt;a href=&quot;https://tools.ietf.org/html/rfc2397&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;data: URL scheme&lt;/a&gt;를 &lt;span style=&quot;color: #333333;&quot;&gt;바이너리 표현(&lt;/span&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%B2%A0%EC%9D%B4%EC%8A%A464&quot;&gt;Base64&lt;/a&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;CSS파일의 크기가 커질 수 있지만 인라인 이미지를 (캐시된) 스타일 시트에 결합하면 HTTP 요청을 줄이고 페이지 크기를 늘리지 않을 수 있다.&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;이미지는 랜더링을 막지 않지만 CSS의 해석시 렌더링을 막으며 캐시 가능성이 떨어진다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;파일의 크기가 증가하고 항상 이미지를 로드하며, 이미지 프리로드 등의 기술도 못쓴다는 점도 고려대상.[&lt;a href=&quot;https://csswizardry.com/2017/02/base64-encoding-and-performance/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Base64 Encoding &amp;amp; Performance&lt;/a&gt;, &lt;a href=&quot;https://hyeonseok.com/soojung/dev/2017/02/20/811.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Base64 인코딩과 성능&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;베이스64 인코딩 하기 귀찮은 것도 문제. [&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/Data_URIs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Data URIs&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;NodeJS에서는 &lt;a href=&quot;https://www.base64encoder.io/node-js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Base64&amp;nbsp;Encoding&amp;nbsp;in&amp;nbsp;Node.js,&lt;/a&gt; &lt;a href=&quot;https://riyadhalnur.github.io/node-base64-image/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;node-base64-image&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://riyadhalnur.github.io/node-base64-image/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;base64-img&lt;/a&gt;등을 참고바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹팩의 경우&amp;nbsp;&lt;a href=&quot;https://github.com/webpack-contrib/url-loader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;url-loader&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;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;@2x, @4x같이 해상도를 대응할 필요가 없고, 용량도 아낄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터 그래픽이라면 SVG와 아이콘 폰트, CSS라는 세가지 선택지가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, 가능하면 CSS로 작성하고, SVG와 아이콘 폰트에 대해 고민할 수 있는데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에는 SVG를 사용하는 것을 선호하는 편이다.&amp;nbsp;[&lt;a href=&quot;https://css-tricks.com/icon-fonts-vs-svg/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Inline SVG vs Icon Fonts&lt;/a&gt;, &lt;a href=&quot;https://www.keycdn.com/blog/icon-fonts-vs-svgs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Icon Fonts vs SVGs - Which One Should You Use in 2018?&lt;/a&gt;, &lt;a href=&quot;https://www.lambdatest.com/blog/its-2019-lets-end-the-debate-on-icon-fonts-vs-svg-icons/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;It&amp;rsquo;s 2019! Let&amp;rsquo;s End The Debate On Icon Fonts vs SVG Icons&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;React의 경우 SVG를 컴포넌트처럼 다룰 수 있기도 하고.&lt;/p&gt;
&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;10k 미만으로 작으면서 항상 불러와야 하는 이미지라면 Base64로 인코딩해서 사용하는 것도 괜찮다.&lt;/p&gt;
&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;다양한 색상의 이미지들을 항상 불러와야 한다면 Image Sprite로 묶는다.&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;움직이는 GIF는 ffmpeg를 이용해 영상으로 변환하고 나머지 일반 이미지는 WebP를 사용하면 좋다.&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;1.3.5 다중문서에 구성요소들을 묶기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;&amp;nbsp;Mobile&lt;br /&gt;이메일의&amp;nbsp;첨부파일과&amp;nbsp;같이&amp;nbsp;다중문서&lt;span style=&quot;color: #333333;&quot;&gt;(Multipart Document)&lt;/span&gt;에 구성요소들을 묶는 것은 한 개의 HTTP 요청에 여러 개의 구성요소들을 불러오는데 도움이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 요청들이 비용(시간&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;YDN에서 다중문서라 하길래 도대체 무엇인가 하니..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/MHTML&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MHTML&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;일반 웹문서가 HTML코드와 참조하는 별도 파일들(이미지, 음성, 영상)으로 구성된다면 MHTML은 &lt;a href=&quot;https://ko.wikipedia.org/wiki/MIME&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MIME&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.4 나누기&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;h4 data-ke-size=&quot;size20&quot;&gt;1.4.1 구성요소들을 도메인별로 분리&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt; C&lt;/span&gt;ontent&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;727&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ecwrnA/btqWX5LO5ZE/nVrVX4471QZWGlGOjaD0F1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ecwrnA/btqWX5LO5ZE/nVrVX4471QZWGlGOjaD0F1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ecwrnA/btqWX5LO5ZE/nVrVX4471QZWGlGOjaD0F1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FecwrnA%2FbtqWX5LO5ZE%2FnVrVX4471QZWGlGOjaD0F1%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;463&quot; height=&quot;727&quot; data-origin-width=&quot;463&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;DNS 요청을 줄이라는 원칙에서 언급했듯 요소들을 분할하는 것은 병렬 다운로드를 극대화할 수 있다.(HTTP 1.1 기준 한 도메인에서 6개가 최대)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DNS 조회의 불이익 때문에 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;span&gt;&amp;nbsp;&lt;/span&gt;www.example.org에서&amp;nbsp;HTML과&amp;nbsp;동적&amp;nbsp;콘텐츠를&amp;nbsp;호스트할&amp;nbsp;수&amp;nbsp;있고,&amp;nbsp;static1.example.org와&amp;nbsp;static2.example.org&amp;nbsp;사이의&amp;nbsp;정적&amp;nbsp;구성&amp;nbsp;요소를&amp;nbsp;분할할&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;&lt;br /&gt;자세한&amp;nbsp;내용은&amp;nbsp;Tenni&amp;nbsp;Theurer와&amp;nbsp;Patty&amp;nbsp;Chi의&amp;nbsp;&quot;&lt;a href=&quot;http://yuiblog.com/blog/2007/04/11/performance-research-part-4/&quot;&gt;Maximizing&amp;nbsp;Parallel&amp;nbsp;Downloads&amp;nbsp;in&amp;nbsp;the&amp;nbsp;Carpool&amp;nbsp;Lane&lt;/a&gt;&quot;를&amp;nbsp;참조해라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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개의 도메인에서 모두 다 서비스하고 있다면 라이브러리는 CDN을 사용해보는 것이 어떨까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 HTTP 1.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;1.4.2 JavaScript와 CSS를 외부로 두기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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; Javascript, CSS&lt;br /&gt;&lt;br /&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 및 CSS가 외부 파일에 포함되어야 할까? 아니면 페이지 자체에 인라인되는 것이 좋을까?&lt;/p&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 및 CSS 파일이 브라우저에 의해 캐시되므로 일반적으로 더 빠른 페이지를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 문서에 인라인 된 JavaScript 및 CSS는 HTML 문서가 요청 될 때마다 다운로드된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게하면 필요한 HTTP 요청 수가 줄어들지만 HTML 문서의 크기는 커진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, JavaScript 및 CSS가 브라우저에 의해 캐시 된 외부 파일에 있으면 HTTP 요청 수를 늘리지 않고 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 문서 수와 관련하여 외부 JavaScript 및 CSS 구성 요소가 캐시되는 빈도이다.&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;이러한 사이트의 경우 가장 좋은 해결책은 일반적으로 JavaScript 및 CSS를 외부 파일로 배포하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인을 선호하는 유일한 예외는 Yahoo! 의 첫 페이지 및 My Yahoo! 처럼 세션 당 페이지 뷰가 거의없는 (아마도 하나만) 홈 페이지는 JavaScript 및 CSS를 인라인하면 최종 사용자 응답 시간이 더 빨라질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 많은 페이지뷰 중 첫 번째인 프론트 페이지에는 인라인이 제공하는 HTTP 요청 감소와 외부 파일을 사용하여 얻을 수있는 캐싱 이점을 활용하는 기술이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 기술 중 하나는 프론트 페이지에서 JavaScript 및 CSS를 인라인하는 것이지만, 페이지 로드가 완료된 후 동적으로 외부 파일을 다운로드하는 것이다.&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 style=&quot;font-size: 1.12em;&quot; 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;h4 data-ke-size=&quot;size20&quot;&gt;1.4.3 이미지 타일링&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; 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;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;Image&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://en.wikipedia.org/wiki/Tiled_web_map&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tiled web map&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.openstreetmap.org/wiki/Vector_tiles&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vector tiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bachasoftware.com/what-is-tile-and-differentiate-between-raster-tile-and-vector-tile/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What is tile and differentiate between raster tile and vector tile&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>프로그래밍/Web</category>
      <category>성능</category>
      <category>웹</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/73</guid>
      <comments>https://black7375.tistory.com/73#entry73comment</comments>
      <pubDate>Sat, 4 Apr 2020 09:36:02 +0900</pubDate>
    </item>
    <item>
      <title>[스압/데이터주의] 웹 최적화 방식 모음 - 0. 전반적 원칙과 원리</title>
      <link>https://black7375.tistory.com/72</link>
      <description>&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;이 문서는 완전히 완성된 상태가 아니라 시간이 나면 업데이트 중.&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;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;블로그 스킨을 React 기반으로 클린룸 구현해볼까 생각 중이라 더 열심히 하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트, PWA, 웹컴포넌트 등 파워풀한 것을 모두 넣어서 가볍고 빠르고 생산성까지 잡으며 아름답게 만드는 것이 목표 ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/72&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 0. 전반적 원칙과 원리(현재)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/73&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 1. 다운로드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/74&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 2. 파싱 및 렌더링 트리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/79&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3. Layout 및 렌더링&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/80&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 3.3 UX 트릭&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/81&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 4. 로드 후&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tistory.com/82&quot;&gt;[스압/데이터주의] 웹 최적화 방식 모음 - 5. 빌드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 전반적 원칙과 원리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 긴 글을 읽기 귀찮다면 TOAST UI팀이 작성한 &lt;a href=&quot;https://ui.toast.com/fe-guide/ko_PERFORMANCE/&quot;&gt;성능 최적화&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;h3 data-ke-size=&quot;size23&quot;&gt;0.1 이 글의 원칙&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;하지만, 이 글은 알고리즘과 자료구조를 소개하는 글은 아니므로 제외.&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: #333333;&quot;&gt;최신 기술인 SPA나 웹번들러 관련 기법들은 가장 보편적인 리엑트, 웹팩 기준으로 서술한다.&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: #333333;&quot;&gt;+.&lt;/span&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;a href=&quot;https://en.wikipedia.org/wiki/Decomposition_(computer_science)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;프로그램 분해&lt;/a&gt;(Program Decomposition, 뭐라 번역해야 할지 모르겠다): 작업을 객체 계층, 함수 등의 흐름으로 나누는 것을 의미.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;코딩 효율성(언어 의존적, 중저수준)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언어구조: 파이썬의 GIL처럼 커다란 부분부터, C++의 Try-Catch 예외 발생같이 작은 부분까지 언어 특성을 고려&lt;/li&gt;
&lt;li&gt;시스템 아키텍처: 프로세서, 메모리 용량과 접근, OS등에 따라 성능특성이 달라짐&lt;/li&gt;
&lt;li&gt;라이브러리: 사용하는 라이브러리에 따라 달라짐&lt;/li&gt;
&lt;li&gt;컴파일러 / VM 최적화: 컴파일러가 인라인 함수, 분기예측, VM의 GC 등에 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;0.2 원리&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;0.2.1 네트워크 동작&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 동작은 네트워크 시간에 흔히 배우는 DNS 개념과 TCP/IP에 대한 개념(주로 핸드쉐이크)에 대한 개념이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hpbn.co/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;High Performance Browser Networking&lt;/a&gt;와 &lt;a href=&quot;https://maxkim-j.github.io/posts/packet-travel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;브라우저 주소창에 URL을 치면 일어나는 일들&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;b&gt;- DNS&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I4Ciz/btqDaiwMe4p/ib1nQAzZCHcILeO3tM6Y8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I4Ciz/btqDaiwMe4p/ib1nQAzZCHcILeO3tM6Y8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I4Ciz/btqDaiwMe4p/ib1nQAzZCHcILeO3tM6Y8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI4Ciz%2FbtqDaiwMe4p%2Fib1nQAzZCHcILeO3tM6Y8k%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;445&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;445&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://aws.amazon.com/ko/route53/what-is-dns/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DNS란 무엇입니까?&lt;/a&gt;란 글이 쉽게 설명해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 자세한 글을 원한다면 &lt;a href=&quot;https://www.cloudflare.com/ko-kr/learning/dns/what-is-dns/&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;브라우저에서 www.example.com 같은 도메인 이름을 입력&lt;/li&gt;
&lt;li&gt;ISP가 운영하는 DNS Resolver(또는 Local DNS)로 쿼리를 수신&lt;/li&gt;
&lt;li&gt;Local DNS에 IP주소가 있다면 전달, 아니라면 루트 DNS 서버에 전달&lt;/li&gt;
&lt;li&gt;.com, .net, .kr처럼 공통 도메인 확장자를 관리하는 TLD(Top-Level Domain) 서버에 전달&lt;/li&gt;
&lt;li&gt;&amp;nbsp;TLD 서버는 example.com을 관리하는 DNS 서버에 요청&lt;/li&gt;
&lt;li&gt;IP를 전달 받고&lt;/li&gt;
&lt;li&gt;브라우저에게 알려줌&lt;/li&gt;
&lt;li&gt;전달받은 IP주소를 기반으로 요청&lt;/li&gt;
&lt;li&gt;www.example.com이 해당되는 웹페이지 반환&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- TCP/IP 연결&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqBwDc/btqDcxG5v2d/9hHzDGA3LZPXX6dTFXMRl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqBwDc/btqDcxG5v2d/9hHzDGA3LZPXX6dTFXMRl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqBwDc/btqDcxG5v2d/9hHzDGA3LZPXX6dTFXMRl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqBwDc%2FbtqDcxG5v2d%2F9hHzDGA3LZPXX6dTFXMRl1%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;687&quot; height=&quot;491&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hpbn.co/transport-layer-security-tls/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TLS&amp;nbsp;(Transport&amp;nbsp;Layer&amp;nbsp;Security)&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;TCP는 흔히 알다시피&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SYN&lt;/li&gt;
&lt;li&gt;SYN ACK&lt;/li&gt;
&lt;li&gt;ACK&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3 handshake로 이루어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 보안에 필요한 TLS까지 사용한다면 몇단계가 더 추가된다. [&lt;a href=&quot;https://www.cloudflare.com/learning/ssl/what-happens-in-a-tls-handshake/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;What Happens in a TLS Handshake?&lt;/a&gt;, &lt;a href=&quot;https://kthan.tistory.com/entry/TLS-%ED%95%B8%EB%93%9C%EC%89%90%EC%9D%B4%ED%81%AC-Handshake-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-%EB%B6%84%EC%84%9D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TLS 핸드쉐이크 (Handshake) 프로토콜 분석&lt;/a&gt;, &lt;a href=&quot;https://tls.ulfheim.net/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The&amp;nbsp;Illustrated&amp;nbsp;TLS&amp;nbsp;Connection&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;b&gt;- HTTP&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헤더를 한번 쯤 살펴보길 바란다. [&lt;a href=&quot;https://httptoolkit.tech/blog/http-wtf/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HTTPWTF&lt;/a&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;0.2.2 브라우저 동작&lt;/h4&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;다음 글은 브라우저가 어떻게 동작하는지 잘 설명해주고 있다.&lt;/span&gt;&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;&lt;a href=&quot;https://d2.naver.com/helloworld/59361&quot;&gt;브라우저는 어떻게 동작하는가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/web-god-mode/how-web-browsers-work-behind-the-scene-architecture-technologies-and-internal-working-fec601488bfa&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How Web Browsers Work &amp;mdash; Behind the scene Architecture, Technologies, and Internal Working&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.logrocket.com/how-browser-rendering-works-behind-the-scenes-6782b0e8fb10/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How broser rendering works &amp;mdash; Behind the scenes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cresumerjang.github.io/2019/06/24/critical-rendering-path/&quot;&gt;웹 브라우저는 렌더링 프로세스 -&amp;nbsp;&amp;nbsp;웹 성능 최적화에 필요한 브라우저의 모든 것&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bitsofco.de/understanding-the-critical-rendering-path/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Understanding the Critical Rendering Path&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Performance/How_browsers_work&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Populating the page: how browsers work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oncrawl.com/technical-seo/how-does-a-browser-create-a-web-page/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;does&amp;nbsp;a&amp;nbsp;browser&amp;nbsp;create&amp;nbsp;a&amp;nbsp;web&amp;nbsp;page?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에는 아예&amp;nbsp;&lt;a href=&quot;https://browser.engineering/&quot;&gt;Web Browser Engineering&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zLJ5W/btqCNGYfwvO/tXzGzocgdlSiXwFZU7jgQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zLJ5W/btqCNGYfwvO/tXzGzocgdlSiXwFZU7jgQk/img.png&quot; style=&quot;width: 49.504%; margin-right: 10px;&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;289&quot; data-widthpercent=&quot;50.09&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zLJ5W/btqCNGYfwvO/tXzGzocgdlSiXwFZU7jgQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzLJ5W%2FbtqCNGYfwvO%2FtXzGzocgdlSiXwFZU7jgQk%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;625&quot; height=&quot;289&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUy50B/btqCO1HmwS9/7QPKzhZ43akPCoLKr7AV2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUy50B/btqCO1HmwS9/7QPKzhZ43akPCoLKr7AV2K/img.png&quot; style=&quot;width: 49.3333%;&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;290&quot; data-widthpercent=&quot;49.91&quot; data-is-animation=&quot;false&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUy50B/btqCO1HmwS9/7QPKzhZ43akPCoLKr7AV2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUy50B%2FbtqCO1HmwS9%2F7QPKzhZ43akPCoLKr7AV2K%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;625&quot; height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/div&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhUNYA/btqCUcxf58C/kQDMFIL74iBty3qVKHeNek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhUNYA/btqCUcxf58C/kQDMFIL74iBty3qVKHeNek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhUNYA/btqCUcxf58C/kQDMFIL74iBty3qVKHeNek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhUNYA%2FbtqCUcxf58C%2FkQDMFIL74iBty3qVKHeNek%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;615&quot; height=&quot;230&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;다운로드 - 파싱 - 스타일링 - 레이아웃 - 페인트 -합성&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;이중 주목할 것은 Layout과 Paint에서 많은 리소스가 필요하다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 돔 조작을 줄이기 위해 Virtual 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;이번에는 조금 다른 방향으로 들어가서 자바스크립트 엔진의 소개글을 읽어볼 수도 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@godori/JavaScript-engine-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript 엔진 톺아보기 (1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@godori/JavaScript-%EC%97%94%EC%A7%84-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0-2-pujpqum2ji&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript&amp;nbsp;엔진&amp;nbsp;톺아보기&amp;nbsp;(2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://engineering.huiseoul.com/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94%EA%B0%80-v8-%EC%97%94%EC%A7%84%EC%9D%98-%EB%82%B4%EB%B6%80-%EC%B5%9C%EC%A0%81%ED%99%94%EB%90%9C-%EC%BD%94%EB%93%9C%EB%A5%BC-%EC%9E%91%EC%84%B1%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8B%A4%EC%84%AF-%EA%B0%80%EC%A7%80-%ED%8C%81-6c6f9832c1d9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자바스크립트는 어떻게 작동하는가: V8 엔진의 내부 + 최적화된 코드를 작성을 위한 다섯 가지 팁&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자바스크립트의 메모리 관리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kkangdda.tistory.com/78?category=830981&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;움짤로 보는 자바스크립트 동작 원리&lt;/a&gt;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/614865618634768384/%EB%AA%A8%EB%8D%98-%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%93%A4%EC%97%AC%EB%8B%A4%EB%B3%B4%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모던 웹 브라우저 들여다보기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/168413516690/firefox-performance-article&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Firefox Performance Article&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 읽어보길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 메인 쓰레드, 컴포지터 쓰레드, GPU 가속등으로 처리를 나누어 사용하고, 서비스 워커와 웹 어셈블리가 생겨났는지 이유를 찾을 수 있다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@cwdoh/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%81%AC%EB%A1%AC-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%84%B1%EB%8A%A5-%EC%9D%B8%EC%9E%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-4c9e4d715638&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;프론트엔드&amp;nbsp;개발자를&amp;nbsp;위한&amp;nbsp;크롬&amp;nbsp;렌더링&amp;nbsp;성능&amp;nbsp;인자&amp;nbsp;이해하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mrale.ph/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;letter-spacing: 0px; -webkit-text-stroke-width: 0.04px;&quot;&gt;mraleph - a compiler engineer that loves giving talks.&lt;/span&gt;&lt;/a&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://caniuse.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://caniuse.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1586433462489&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Can I use... Support tables for HTML5, CSS3, etc&quot; data-og-description=&quot;About &amp;quot;Can I use&amp;quot; provides up-to-date browser support tables for support of front-end web technologies on desktop and mobile web browsers. The site was built and is maintained by Alexis Deveria, with occasional updates provided by the web development commu&quot; data-og-host=&quot;caniuse.com&quot; data-og-source-url=&quot;https://caniuse.com/&quot; data-og-url=&quot;https://caniuse.com/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://caniuse.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://caniuse.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;Can I use... Support tables for HTML5, CSS3, etc&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;About &quot;Can I use&quot; provides up-to-date browser support tables for support of front-end web technologies on desktop and mobile web browsers. The site was built and is maintained by Alexis Deveria, with occasional updates provided by the web development commu&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;caniuse.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;h4 data-ke-size=&quot;size20&quot;&gt;0.2.3 측정 및 해석&lt;/h4&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;TOAST UI팀이 작성한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://ui.toast.com/fe-guide/ko_PERFORMANCE/&quot;&gt;성능 최적화&lt;/a&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Performance/Navigation_and_resource_timings&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Navigation and resource timings&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;415&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7erRl/btqDp0Wt1p2/eaGo7KHSZXWlr2c2iU3n60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7erRl/btqDp0Wt1p2/eaGo7KHSZXWlr2c2iU3n60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7erRl/btqDp0Wt1p2/eaGo7KHSZXWlr2c2iU3n60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7erRl%2FbtqDp0Wt1p2%2FeaGo7KHSZXWlr2c2iU3n60%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;690&quot; height=&quot;415&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;415&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://developers.google.com/web/tools/chrome-devtools?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Chrome DevTools&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Tools&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Firefox 개발자 도구&lt;/a&gt;, &lt;a href=&quot;https://support.apple.com/ko-kr/guide/safari-developer/welcome/mac&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Safari Developer Help&lt;/a&gt;, &lt;a href=&quot;https://docs.microsoft.com/en-us/microsoft-edge/devtools-guide&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Microsoft Edge(EdgeHTML) Developer Tools&lt;/a&gt;, &lt;a href=&quot;https://www.brendangregg.com/flamegraphs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Flame Graph&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;span style=&quot;color: #333333;&quot;&gt;크로미움(Blink), 파이어폭스(Getko), 미도리(Webkit2GTK)의 프로파일링 모습.&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-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ws7KV/btqDaWmJTYq/tuUzpSuDMi82Ya4hDpsMc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ws7KV/btqDaWmJTYq/tuUzpSuDMi82Ya4hDpsMc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ws7KV/btqDaWmJTYq/tuUzpSuDMi82Ya4hDpsMc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWs7KV%2FbtqDaWmJTYq%2FtuUzpSuDMi82Ya4hDpsMc0%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;1921&quot; height=&quot;670&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzq8XE/btqDbElzsNA/sSyHyo9kRuob7nOuI5KP41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzq8XE/btqDbElzsNA/sSyHyo9kRuob7nOuI5KP41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzq8XE/btqDbElzsNA/sSyHyo9kRuob7nOuI5KP41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzq8XE%2FbtqDbElzsNA%2FsSyHyo9kRuob7nOuI5KP41%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;1921&quot; height=&quot;667&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U6AOs/btqDbFx1VfU/CCMCE2MfKeP1jhrD7kvzMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U6AOs/btqDbFx1VfU/CCMCE2MfKeP1jhrD7kvzMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U6AOs/btqDbFx1VfU/CCMCE2MfKeP1jhrD7kvzMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU6AOs%2FbtqDbFx1VfU%2FCCMCE2MfKeP1jhrD7kvzMK%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;1921&quot; height=&quot;667&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&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;&lt;span style=&quot;color: #333333;&quot;&gt;하드웨어나 각 모듈, 이벤트별로 꼼꼼하게 리소스 소모/부하 및 UX적으로 느끼는 향상까지 전반적으로 다룰 수 있기 때문이다.&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;FPS, CPU, &lt;span style=&quot;color: #333333;&quot;&gt;GPU,&lt;/span&gt; Network,&amp;nbsp; Compositor, Service Worker, &lt;span style=&quot;color: #333333;&quot;&gt;자바스크립트 프레임 차트&lt;/span&gt;등 다양한 부하&lt;/li&gt;
&lt;li&gt;스크린샷, 매 프레임의 시각화&lt;/li&gt;
&lt;li&gt;또한 점진적 렌더링과 사용자 기준의 성능측정 기준인 FP(First Paint), FCP(First Contentful Paint), FMP(First Meaningful Paint)등의 이벤트 시간&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에 어플리케이션 탭에서 PWA 수준까지 정보 제공, Audits에 내장된 구글 라이트하우스 프로파일링 등 매우매우 강력한 디버깅을 제공한다.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;setTimeout, 이벤트 핸들러, 함수호출 등의 자바스크립트&lt;/li&gt;
&lt;li&gt;마이너 GC, 비증가형 GC, 사이틀 콜렉션등 자바스크립트 엔진&lt;/li&gt;
&lt;li&gt;스타일 재계산, 변경적용, 레이아웃등의 CSS&lt;/li&gt;
&lt;li&gt;페인트&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 위에서 적었다시피 정보가 너무 부족;;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특이한 것은 레이어를 볼 수 있다는 것 정도?(아마 Graphics Layer를 뜻하는 듯 하다, 그래픽 가속에서 살짝 다룸)&lt;/p&gt;
&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;widthContent&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kXvPg/btqDc3EY9Gp/usAV6R4skUJ7vgeqj7S7HK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kXvPg/btqDc3EY9Gp/usAV6R4skUJ7vgeqj7S7HK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kXvPg/btqDc3EY9Gp/usAV6R4skUJ7vgeqj7S7HK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkXvPg%2FbtqDc3EY9Gp%2FusAV6R4skUJ7vgeqj7S7HK%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;1921&quot; height=&quot;667&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwGVaP/btqC855VeDZ/bKnUKYlDISukzU3QhPuFF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwGVaP/btqC855VeDZ/bKnUKYlDISukzU3QhPuFF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwGVaP/btqC855VeDZ/bKnUKYlDISukzU3QhPuFF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwGVaP%2FbtqC855VeDZ%2FbKnUKYlDISukzU3QhPuFF0%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;1921&quot; height=&quot;667&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;widthContent&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BqQNh/btqC9OvXvor/la2py6FKZrzuY3xh2WIdBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BqQNh/btqC9OvXvor/la2py6FKZrzuY3xh2WIdBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BqQNh/btqC9OvXvor/la2py6FKZrzuY3xh2WIdBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBqQNh%2FbtqC9OvXvor%2Fla2py6FKZrzuY3xh2WIdBk%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;1921&quot; height=&quot;667&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAT7uI/btqDaVnVYei/m4bbZD3DZRuSbyxNtrSBY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAT7uI/btqDaVnVYei/m4bbZD3DZRuSbyxNtrSBY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAT7uI/btqDaVnVYei/m4bbZD3DZRuSbyxNtrSBY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAT7uI%2FbtqDaVnVYei%2Fm4bbZD3DZRuSbyxNtrSBY0%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;1921&quot; height=&quot;667&quot; data-origin-width=&quot;1921&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;엄청나게 직관적인 CSS 플렉스 박스와 그리드 다루기, 폰트, 애니메이션 등등의 기능&lt;/p&gt;
&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://dev.to/composite/-4675&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;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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React Developer Tools[&lt;a href=&quot;https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;크롬&lt;/a&gt;, &lt;a href=&quot;https://addons.mozilla.org/ko/firefox/addon/react-devtools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파이어폭스&lt;/a&gt;] - &lt;a href=&quot;https://addyosmani.com/blog/profiling-react-js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Profiling React.js Performance&amp;nbsp;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Vue.js devtools[&lt;a href=&quot;https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;크롬&lt;/a&gt;, &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파이어폭스&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Angular Angury[&lt;a href=&quot;https://chrome.google.com/webstore/detail/augury/elgalmkoelokbchhkhacckoklkejnhcd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;크롬&lt;/a&gt;, &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/angular-augury/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파이어폭스&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Svelte Devtools[&lt;a href=&quot;https://chrome.google.com/webstore/detail/svelte-devtools/ckolcbmkjpjmangdbmnkpjigpkddpogn?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;크롬&lt;/a&gt;, &lt;a href=&quot;https://addons.mozilla.org/ko/firefox/addon/svelte-devtools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파이어폭스&lt;/a&gt;]&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;Redux나 MobX같은 상태관리 라이브러리도 개발자 도구를 지원한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redux DevTools[&lt;a href=&quot;https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;크롬&lt;/a&gt;, &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파이어폭스&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;MobX Developer Tools[&lt;a href=&quot;https://chrome.google.com/webstore/detail/mobx-developer-tools/pfgnfdagidkfgccljigdamigbcnndkod&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;크롬&lt;/a&gt;, &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/mobx-devtools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파이어폭스&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;a href=&quot;https://github.com/webpack-contrib/webpack-bundle-analyzer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webapck Bundle Anlayzer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;마지막으로 React의 경우, &lt;a href=&quot;https://github.com/welldone-software/why-did-you-render&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Why Did You Render&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;&lt;b&gt;- JS 성능 측정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 실행시간을 측정하는 방법에 대해 다룬다. [&lt;a href=&quot;https://stackoverflow.com/questions/313893/how-to-measure-time-taken-by-a-function-to-execute&quot;&gt;How to measure time taken by a function to execute&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://gomakethings.com/how-to-test-vanilla-js-performance/&quot;&gt;How to test vanilla JS performance&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developers.google.com/web/tools/chrome-devtools/console/track-executions?hl=ko&quot;&gt;실행 측정 및 계산&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;자바스크립트에서 성능을 측정하는 방법은 보통 3가지(&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Date&quot;&gt;new Date&lt;/a&gt;[&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime&quot;&gt;getTime&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Date/now&quot;&gt;now&lt;/a&gt;],&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Console/time&quot;&gt;console.time&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Performance/now&quot;&gt;performance.now&lt;/a&gt;)가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613289717880&quot; class=&quot;javascript&quot; style=&quot;margin: 20px auto 0px; 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; 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: 0.04px; text-decoration-thickness: initial; 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;// 1. new Date
const start = new Date(); // or Date.now();
doSomething();
const end = new Date();
console.log((end - start) / 1000);

// 2. console.time - 문자열이 같아야 함.
console.time('Time');
console.timeEnd('Time');

// 3. performance.now - 베스트
const start = performance.now();
doSomething();
const end = performance.now();
console.log((end - start) / 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중에서는 performance.now를 사용하는게 가장 나은 방식.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안타까운점은 Spectre와 같은 공격 때문에 정밀도가 줄어들었다. [&lt;a href=&quot;https://blog.mozilla.org/security/2018/01/03/mitigations-landing-new-class-timing-attack/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mitigations&amp;nbsp;landing&amp;nbsp;for&amp;nbsp;new&amp;nbsp;class&amp;nbsp;of&amp;nbsp;timing&amp;nbsp;attack&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;JS 엔진에서 나왔던 &quot;hot code&quot;의 warm up이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API&quot;&gt;User Timing&lt;/a&gt;(&lt;a href=&quot;https://www.w3.org/TR/user-timing/&quot;&gt;W3C&lt;/a&gt;)/&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Navigation_timing&quot;&gt;Navigation Timing&lt;/a&gt;정도는 고려해야 한다. [&lt;a href=&quot;https://www.codentalks.com/t/topic/550&quot;&gt;코드성능측정에서 고려해야할 부분들&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://calendar.perfplanet.com/2010/bulletproof-javascript-benchmarks/&quot;&gt;Bulletproof&amp;nbsp;JavaScript&amp;nbsp;benchmarks&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://ko.javascript.info/date#ref-534&quot;&gt;Date 객체와 날짜 - 벤치마크&lt;/a&gt;, &lt;a href=&quot;https://stackoverflow.com/questions/32629779/define-number-of-cycles-benchmark-js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Define number of cycles - Benchmark.js&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2012/08/When-milliseconds-are-not-enough-performance-now&quot;&gt;When milliseconds are not enough: performance.now&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.html5rocks.com/ko/tutorials/webperformance/usertiming/&quot;&gt;User Timing API: Understanding your Web App - HTML5 Rocks&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벤치마크 프레임워크들이 놓치는 점(파싱 및 컴파일등)도 고려해야 한다. [&lt;a href=&quot;https://benediktmeurer.de/2016/12/16/the-truth-about-traditional-javascript-benchmarks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The truth about traditional JavaScript benchmarks&lt;/a&gt;, &lt;a href=&quot;https://browserbench.org/Speedometer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Speedometer&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기타 마이크로 벤치마크에서 주의할 사항 [&lt;a href=&quot;https://tomdale.net/2017/07/adventures-in-microbenchmarking/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Adventures in Microbenchmarking&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;a href=&quot;https://github.com/bestiejs/benchmark.js&quot;&gt;benchmark.js&lt;/a&gt;, &lt;a href=&quot;https://github.com/dynatrace/zakzak&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;zakzak&lt;/span&gt;&lt;/a&gt;)나 사이트(&lt;a href=&quot;https://jsperf.com/&quot;&gt;jsperf&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://jsben.ch/&quot;&gt;jsben&lt;/a&gt;)를 사용해보도록 하자. [&lt;a href=&quot;https://stackoverflow.com/questions/44612083/which-js-benchmark-site-is-correct&quot;&gt;Which&amp;nbsp;JS&amp;nbsp;benchmark&amp;nbsp;site&amp;nbsp;is&amp;nbsp;correct?&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;a href=&quot;https://github.com/ksen007/jalangi2analyses&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Jalangi2Analyses&lt;/a&gt;란 툴을 사용하면 JIT 최적화 관련 룰을 프로파일링 할 수 있나보다.&lt;/p&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;a href=&quot;https://developers.google.com/speed/pagespeed/insights/?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights&lt;/a&gt;와&amp;nbsp;&lt;a href=&quot;https://developers.google.com/web/tools/lighthouse?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;라이트하우스(Lighthouse)&lt;/a&gt;다. [&lt;a href=&quot;https://bitsofco.de/web-performance-metrics-cheatsheet/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web&amp;nbsp;Performance&amp;nbsp;Metrics&amp;nbsp;Cheatsheet&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20200116/&quot;&gt;라이트하우스의 진화: CI, 새로운 성능 지표&lt;/a&gt;, &lt;a href=&quot;https://web.dev/user-centric-performance-metrics/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;User-centric&amp;nbsp;performance&amp;nbsp;metrics&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라이트하우스 부가기능[&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/google-lighthouse/&quot;&gt;파이어폭스&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk&quot;&gt;크롬&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;라이트하우스 플러그인[&lt;a href=&quot;https://github.com/treosh/lighthouse-plugin-field-performance&quot;&gt;Field Performance&lt;/a&gt;, &lt;a href=&quot;https://github.com/ampproject/amp-toolbox/tree/master/packages/lighthouse-plugin-amp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMP&lt;/a&gt;, &lt;a href=&quot;https://github.com/exterkamp/lighthouse-plugin-cinememe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cinememe&lt;/a&gt;, &lt;a href=&quot;https://github.com/googleads/publisher-ads-lighthouse-plugin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Publisher&amp;nbsp;Ads&amp;nbsp;Lighthouse&amp;nbsp;Plugin&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&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://wit.nts-corp.com/2020/12/28/6240&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;새로운&amp;nbsp;웹페이지&amp;nbsp;성능&amp;nbsp;측정&amp;nbsp;지표&amp;nbsp;CLS(Cumulative&amp;nbsp;Layout&amp;nbsp;Shift)&lt;/a&gt;가 흥미로웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.outsider.ne.kr/1548&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;실제 웹사이트에서 Web Vitals 디버깅하기&lt;/a&gt;는 CLS 개선시에 도움이 될만한 글.&lt;/p&gt;
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://waterfaller.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Waterfaller&lt;/a&gt;: Pagespeed Insights와 비슷하지만 해결책을 제시해줌&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webhint.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webhint&lt;/a&gt;: 마이크로소프트가 만든 Light House 비슷한 프로젝트. 일각고래가 귀엽다 ㅇㅅㅇ!!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yellowlab.tools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Yellow Lab Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.keycdn.com/blog/website-speed-test-tools&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Top&amp;nbsp;15&amp;nbsp;Free&amp;nbsp;Website&amp;nbsp;Speed&amp;nbsp;Test&amp;nbsp;Tools&amp;nbsp;of&amp;nbsp;2018&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dareboost.com/en&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DareBoost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.octagate.com/service/SiteTimer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Octagate - SiteTimer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;SPA앱은 초기로딩 후 업데이트를 하는 형식이기 때문에 재렌더링 시의 성능등도 고려해야 할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엠버(링크드인)의 글이 도움이 될 수도. [&lt;a href=&quot;https://engineering.linkedin.com/blog/2017/02/measuring-and-optimizing-performance-of-single-page-applications&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Measuring&amp;nbsp;and&amp;nbsp;Optimizing&amp;nbsp;Performance&amp;nbsp;of&amp;nbsp;Single-Page&amp;nbsp;Applications&amp;nbsp;(SPA)&amp;nbsp;Using&amp;nbsp;RUM&lt;/a&gt;, &lt;a href=&quot;https://engineering.linkedin.com/blog/2017/10/sleek-and-fast--speeding-up-your-fat-web-client&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sleek&amp;nbsp;and&amp;nbsp;Fast:&amp;nbsp;Speeding&amp;nbsp;Up&amp;nbsp;your&amp;nbsp;Fat&amp;nbsp;Web&amp;nbsp;Client&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;b&gt;++&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글의&amp;nbsp;&lt;a href=&quot;https://support.google.com/webmasters/answer/9205520?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Search Console 속도 보고서&lt;/a&gt;를 보면 성능 측정 후 적용/활용에 대한 이해에 조금이나마 도움이 되지 않을까 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날에 &lt;a href=&quot;https://yslow.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Yslow&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qICEh/btrpYmrCHts/BvTnAsz5lBIIHRrctDHFo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qICEh/btrpYmrCHts/BvTnAsz5lBIIHRrctDHFo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qICEh/btrpYmrCHts/BvTnAsz5lBIIHRrctDHFo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqICEh%2FbtrpYmrCHts%2FBvTnAsz5lBIIHRrctDHFo0%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;800&quot; height=&quot;349&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 672px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;메트릭&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot;&gt;분류&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot; colspan=&quot;2&quot;&gt;설명&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot;&gt;기준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 63px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 63px;&quot;&gt;최초 바이트까지 시간 (TTFB, Time to First Byte)&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 63px;&quot;&gt;진행 여부&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 63px;&quot; colspan=&quot;2&quot;&gt;서버에서 처음으로 정보가 도착할 때까지 걸리는 시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 63px;&quot;&gt;&amp;lt;600ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 63px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 63px;&quot;&gt;최초 페인트 (FP, First Paint)&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 63px;&quot;&gt;진행 여부&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 63px;&quot; colspan=&quot;2&quot;&gt;배경의 첫 번째 픽셀이 렌더링될 때까지 걸리는 시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 63px;&quot;&gt;&amp;lt;1.8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 42px;&quot;&gt;&lt;span style=&quot;background-color: #efefef;&quot;&gt;최초 컨텐츠 포함된 페인트(FCP, First Contentful Paint)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 42px;&quot;&gt;진행여부&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 42px;&quot; colspan=&quot;2&quot;&gt;콘텐츠 렌더링이 시작될 때까지 걸리는 시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 42px;&quot;&gt;&amp;lt;1.8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 84px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 84px;&quot;&gt;&lt;span style=&quot;background-color: #efefef;&quot;&gt;가장 큰 컨텐츠가 포함된 페인트 (LCP, Largest Contentful Paint)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot;&gt;유용성, 중요함&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot; colspan=&quot;2&quot;&gt;가장 큰 텍스트 블록, 이미지 또는 비디오가 렌더링을 시작할 때까지 걸리는 시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot;&gt;&amp;lt;2.5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;&lt;span style=&quot;background-color: #efefef;&quot;&gt;시각적 완성 (VC, Visually Complete)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot;&gt;유용성&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot; colspan=&quot;2&quot;&gt;컨텐츠가 완전히 렌더링 되는 시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot;&gt;&amp;lt;3.4s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;&lt;span style=&quot;background-color: #efefef;&quot;&gt;속도 지수 (SI, Speed Index)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot;&gt;유용성&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot; colspan=&quot;2&quot;&gt;뷰포트내 컨텐츠가 눈에 띄게 채워지는 속도&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot;&gt;&amp;lt;3.4s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 84px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 84px;&quot;&gt;&lt;span style=&quot;background-color: #efefef;&quot;&gt;최초 입력 지연 (FID, First Input Delay)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot;&gt;사용 가능 여부, 중요함&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot; colspan=&quot;2&quot;&gt;사용자가 상호작용을 한 후 웹 브라우저가 상호작용을 처리할 때까지 걸리는 시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot;&gt;&amp;lt;100ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;&lt;span style=&quot;background-color: #efefef;&quot;&gt;최초 잠재적 첫번째 입력 지연 (mFID, Max Potential First Input Delay)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot;&gt;사용 가능 여부&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot; colspan=&quot;2&quot;&gt;가장 긴 작업의 지속 시간을 기반으로 가능한 최대 첫번째 입력 지연&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot;&gt;&amp;lt;130ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 84px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 84px;&quot;&gt;&lt;span style=&quot;background-color: #efefef;&quot;&gt;총 차단시간 (TBT, Total Blocking Time)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot;&gt;사용 가능 여부&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot; colspan=&quot;2&quot;&gt;메인 스레드가 입력 응답을 막을만큼 차단했을 때 FCP와 TTI 사이의 총 시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot;&gt;&amp;lt;200ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 63px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 63px;&quot;&gt;&lt;span style=&quot;background-color: #efefef;&quot;&gt;상호작용 까지의 시간 (TTI, Time to Interactive)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 63px;&quot;&gt;사용 가능 여부&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 63px;&quot; colspan=&quot;2&quot;&gt;사용자 입력에 안정적으로 응답할 때까지 걸리는 시간&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 63px;&quot;&gt;&amp;lt;3.8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 84px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 84px;&quot;&gt;&lt;span style=&quot;background-color: #efefef;&quot;&gt;누적 레이아웃 변경 (CLS, Cumulative Layout Shift)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot;&gt;쾌적함, 중요함&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot; colspan=&quot;2&quot;&gt;컨텐츠가 동적으로 크기 조정을 할 때 엔드유저가 예기치 않은 레이아웃 이동(변화)의 누적 점수&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 84px;&quot;&gt;&amp;lt;0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;&lt;span style=&quot;background-color: #efefef;&quot;&gt;프레임 레이트 (FR, Frame Rate)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot;&gt;쾌적함&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot; colspan=&quot;2&quot;&gt;1초에 보여주는 화면의 수&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 21px;&quot;&gt;60 FPS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;li&gt;쾌적함: 상호작용이 부드럽고 자연스러우며, 지연과 버벅임이 없는지&lt;/li&gt;
&lt;/ul&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;참고&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;&lt;b&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;&lt;a href=&quot;https://developers.google.com/speed/docs/insights/rules&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights Rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/speed/docs/insights/v5/get-started&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights Rules 시작하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/why-performance-matters?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web Fundamentals - Performance Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/fast/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web.Dev - Fast Load Times&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amp.dev/about/how-amp-works/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How&amp;nbsp;AMP&amp;nbsp;works&lt;/a&gt;&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;b&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;&lt;a href=&quot;https://developer.yahoo.com/performance/rules.html#cookie_size&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Best Practices for Speeding Up Your Web Site&lt;/a&gt; [&lt;a href=&quot;https://webhosting.gabia.com/feature/selfdoctor/yslow_detail#&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;가비아 번역&lt;/a&gt;, &lt;a href=&quot;https://xe1.xpressengine.com/tip/22330022&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Xpress Engine 번역&lt;/a&gt;, &lt;a href=&quot;https://bearjin90.tistory.com/21&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;티스토리 번역&lt;/a&gt;]&lt;br /&gt;&lt;a href=&quot;https://www.sitepoint.com/web-site-optimization-steps/3/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web Site Optimization: 13 Simple Steps Article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&amp;amp;mallGb=KOR&amp;amp;barcode=9788990758965&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹사이트 최적화 기법 - UI 개발자를 위한 필수 지침서&lt;/a&gt; [&lt;a href=&quot;https://blog.outsider.ne.kr/218&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;요약&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://yuiblog.com/blog/category/performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;YUI Performance Posts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yuiblog.com/blog/2006/11/28/performance-research-part-1/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Performance&amp;nbsp;Research,&amp;nbsp;Part&amp;nbsp;1:&amp;nbsp;What&amp;nbsp;the&amp;nbsp;80/20&amp;nbsp;Rule&amp;nbsp;Tells&amp;nbsp;Us&amp;nbsp;about&amp;nbsp;Reducing&amp;nbsp;HTTP&amp;nbsp;Requests&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://yuiblog.com/blog/2007/01/04/performance-research-part-2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Performance&amp;nbsp;Research,&amp;nbsp;Part&amp;nbsp;2:&amp;nbsp;Browser&amp;nbsp;Cache&amp;nbsp;Usage&amp;nbsp;-&amp;nbsp;Exposed!&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://yuiblog.com/blog/2007/03/01/performance-research-part-3/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Performance&amp;nbsp;Research,&amp;nbsp;Part&amp;nbsp;3:&amp;nbsp;When&amp;nbsp;the&amp;nbsp;Cookie&amp;nbsp;Crumbles&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://yuiblog.com/blog/2007/04/11/performance-research-part-4/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Performance&amp;nbsp;Research,&amp;nbsp;Part&amp;nbsp;4:&amp;nbsp;Maximizing&amp;nbsp;Parallel&amp;nbsp;Downloads&amp;nbsp;in&amp;nbsp;the&amp;nbsp;Carpool&amp;nbsp;Lane&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://yuiblog.com/blog/2008/02/06/iphone-cacheability/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Performance&amp;nbsp;Research,&amp;nbsp;Part&amp;nbsp;5:&amp;nbsp;iPhone&amp;nbsp;Cacheability&amp;nbsp;-&amp;nbsp;Making&amp;nbsp;It&amp;nbsp;Stick&lt;/a&gt;d&lt;br /&gt;&lt;a href=&quot;https://yuiblog.com/blog/2008/07/21/performance-research-part-6/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Performance&amp;nbsp;Research,&amp;nbsp;Part&amp;nbsp;6:&amp;nbsp;Less&amp;nbsp;is&amp;nbsp;More&amp;nbsp;&amp;mdash;&amp;nbsp;Serving&amp;nbsp;Files&amp;nbsp;Faster&amp;nbsp;by&amp;nbsp;Combining&amp;nbsp;Them&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yuiblog.com/blog/2008/10/29/imageopt-1/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image&amp;nbsp;Optimization&amp;nbsp;Part&amp;nbsp;1:&amp;nbsp;The&amp;nbsp;Importance&amp;nbsp;of&amp;nbsp;Images&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://yuiblog.com/blog/2008/11/04/imageopt-2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image&amp;nbsp;Optimization&amp;nbsp;Part&amp;nbsp;2:&amp;nbsp;Selecting&amp;nbsp;the&amp;nbsp;Right&amp;nbsp;File&amp;nbsp;Format&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://yuiblog.com/blog/2008/11/14/imageopt-3/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image&amp;nbsp;Optimization&amp;nbsp;Part&amp;nbsp;3:&amp;nbsp;Four&amp;nbsp;Steps&amp;nbsp;to&amp;nbsp;File&amp;nbsp;Size&amp;nbsp;Reduction&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://yuiblog.com/blog/2008/12/05/imageopt-4/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image&amp;nbsp;Optimization&amp;nbsp;Part&amp;nbsp;4:&amp;nbsp;Progressive&amp;nbsp;JPEG...Hot&amp;nbsp;or&amp;nbsp;Not?&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://yuiblog.com/blog/2008/12/08/imageopt-5/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Image&amp;nbsp;Optimization,&amp;nbsp;Part&amp;nbsp;5:&amp;nbsp;AlphaImageLoader&lt;/a&gt;&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;b&gt;TOAST UI&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;a href=&quot;https://ui.toast.com/weekly-pick/ko_20191204/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;반응형&amp;nbsp;시스템&amp;nbsp;개선하기(feat.&amp;nbsp;TOAST&amp;nbsp;UI&amp;nbsp;Grid)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20161212/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹&amp;nbsp;페이지에서&amp;nbsp;컨텐츠를&amp;nbsp;빠르게&amp;nbsp;보여주기&amp;nbsp;위한&amp;nbsp;트릭&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20170728/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;웹&amp;nbsp;어셈블리를&amp;nbsp;보다&amp;nbsp;쉽게&amp;nbsp;웹&amp;nbsp;어플리케이션에&amp;nbsp;적용하는&amp;nbsp;방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20200128/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코드&amp;nbsp;스플리팅을&amp;nbsp;통해&amp;nbsp;사이트의&amp;nbsp;효율성을&amp;nbsp;높이는&amp;nbsp;방법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://meetup.toast.com/posts/110&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React 렌더링과 성능 알아보기&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20160523/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;리액트 렌더링 최적화&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20180911/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이벤트 리스너 캐시를 이용한 React 성능 향상&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20190725/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;리액트&amp;nbsp;렌더러를&amp;nbsp;최적화하는&amp;nbsp;간단한&amp;nbsp;트릭&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20190731/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React.memo() 현명하게 사용하기&lt;/a&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MDN&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Author_fast-loading_HTML_pages&quot;&gt;Tips for authoring fast-loading HTML pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Performance_best_practices_for_Firefox_fe_engineers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Performance best practices for Firefox front-end engineers&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Performance&lt;/a&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&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;&lt;a href=&quot;https://www.oreilly.com/library/view/high-performance-javascript/9781449382308/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;High Performance Javascript&lt;/a&gt; (TOC 부분에서 Show More 버튼을 누르면 볼 수 있다.)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.slideshare.net/NHNFORWARD/2018-130108045&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[2018]&amp;nbsp;프런트엔드&amp;nbsp;성능&amp;nbsp;최적화&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@shlee1353/%EC%9B%B9%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94-%EB%84%A4%EC%9D%B4%EB%B2%84-ui%EA%B0%9C%EB%B0%9C-21f44bf6a792&quot;&gt;웹성능&amp;nbsp;최적화&amp;nbsp;네이버&amp;nbsp;UI개발&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.pagespeedguide.com/best-practises&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PageSpeedGuide - Web performance best practises&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sitepoint.com/10-ways-minimize-reflows-improve-performance/?utm_source=webopsweekly&amp;amp;utm_medium=email&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;10 Ways to Minimize Reflows and Improve Performance&lt;/a&gt; [&lt;a href=&quot;https://medium.com/@dewey.k/10-ways-to-minimize-reflows-and-improve-performance-%EC%9A%94%EC%95%BD-59f6ac7963ea&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;요약&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kyu.io/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EC%8B%9C%EB%B8%8C-%EC%9B%B9%EC%95%B1-%EC%84%B1%EB%8A%A5%EC%97%90-%EB%8C%80%ED%95%9C-%EC%BC%80%EC%9D%B4%EC%8A%A4-%EC%8A%A4%ED%84%B0%EB%94%94-treebo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;프로그래시브 웹앱 성능에 대한 리엑트, 프리엑트 케이스 스터디 : Treebo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/wiki/JavaScript_best_practices&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JavaScript best practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.creativebloq.com/html5/25-html5-speed-tips-11135419&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;25&amp;nbsp;HTML5&amp;nbsp;speed&amp;nbsp;tips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ilikekillnerds.com/2015/02/stop-writing-slow-javascript/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Stop&amp;nbsp;Writing&amp;nbsp;Slow&amp;nbsp;Javascript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sitepoint.com/optimizing-css-performance/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;20 Tips for Optimizing CSS Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2020/01/front-end-performance-checklist-2020-pdf-pages/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Front-End Performance Checklist 2020&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20160319115329/http://www.mobify.com/blog/beginners-guide-to-perceived-performance/&quot;&gt;A Beginner's Guide to Perceived Performance: 4 Ways to Make Your Mobile Site Feel Like a Native App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://craigwoollard.com/6-tips-applications-feel-faster&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;6 Tips to Make Applications Feel Faster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.websiteoptimization.com/secrets/toc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Website Optimization Secrets&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/previous-versions/windows/apps/hh781219(v=win.10)?redirectedfrom=MSDN&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Writing efficient JavaScript (HTML)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.diva-portal.org/smash/get/diva2:766086/FULLTEXT01.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Faster loading of websites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.patterns.dev/posts/#performance-patterns&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Performance Patterns&lt;/a&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Other Platform&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;a href=&quot;https://docs.microsoft.com/ko-kr/dotnet/framework/wpf/advanced/optimizing-wpf-application-performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WPF 애플리케이션 성능 최적화&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/ko-kr/windows/uwp/debug-test-perf/performance-and-xaml-ui&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;UWP 성능&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/ko-kr/xamarin/xamarin-forms/deploy-test/performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Xamarin.Forms 앱 성능 향상&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.qt.io/qt-5/qtquick-performance.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;QT - Performance&amp;nbsp;Considerations&amp;nbsp;And&amp;nbsp;Suggestions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.android.google.cn/guide/topics/ui/declaring-layout&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;안드로이드 레이아웃&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/hongbeomi-dev/%EB%B2%88%EC%97%AD-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%ED%8D%BC%ED%8F%AC%EB%A8%BC%EC%8A%A4-%EC%98%AC%EB%A6%AC%EA%B8%B0-8fe2cbb9931&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[번역] 레이아웃 퍼포먼스 올리기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure style=&quot;width: 1px; height: 1px; position: fixed; overflow: hidden; top: 50%;&quot;&gt;
&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <category>성능</category>
      <category>웹</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/72</guid>
      <comments>https://black7375.tistory.com/72#entry72comment</comments>
      <pubDate>Tue, 17 Mar 2020 15:56:16 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트와 함수형 프로그래밍.</title>
      <link>https://black7375.tistory.com/71</link>
      <description>&lt;p&gt;React Native에서 사용하는 React는 함수형 프로그래밍의 철학을 받아들여 만들어졌습니다.&lt;/p&gt;
&lt;p&gt;React를 처음 접하는 이들을 위한 문서에서도 함수형 프로그래밍의 특징중 하나라는 &lt;b&gt;불변성&lt;/b&gt;을 강조하고 있을 정도 입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.reactjs.org/tutorial/tutorial.html&quot;&gt;자습서: React 시작하기 - React&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1583588004068&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;자습서: React 시작하기 &amp;ndash; React&quot; data-og-description=&quot;A JavaScript library for building user interfaces&quot; data-og-host=&quot;ko.reactjs.org&quot; data-og-source-url=&quot;https://ko.reactjs.org/tutorial/tutorial.html&quot; data-og-url=&quot;https://ko.reactjs.org/tutorial/tutorial.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kETyO/hyFdB5Tz4m/U6bl8vxvBGXTMFHTpMRTZK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/nCRQI/hyFdATr6Pm/9oo9LK2xSSlafEuCDKLPY0/img.png?width=364&amp;amp;height=457&amp;amp;face=0_0_364_457,https://scrap.kakaocdn.net/dn/uEVDH/hyFdAFUVje/o9qisGlHJhhOetPnBHoaWK/img.png?width=270&amp;amp;height=296&amp;amp;face=0_0_270_296&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/tutorial/tutorial.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.reactjs.org/tutorial/tutorial.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kETyO/hyFdB5Tz4m/U6bl8vxvBGXTMFHTpMRTZK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/nCRQI/hyFdATr6Pm/9oo9LK2xSSlafEuCDKLPY0/img.png?width=364&amp;amp;height=457&amp;amp;face=0_0_364_457,https://scrap.kakaocdn.net/dn/uEVDH/hyFdAFUVje/o9qisGlHJhhOetPnBHoaWK/img.png?width=270&amp;amp;height=296&amp;amp;face=0_0_270_296');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;자습서: React 시작하기 &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;A JavaScript library for building user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;ko.reactjs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서 React Native로 프로그래밍을 하기 위해서는 함수형 프로그래밍에 대해 알아두는 것이 좋습니다.&lt;/p&gt;
&lt;p&gt;함수형 프로그래밍이란 패러다임은 람다대수에 기반하여 만들어졌고, 람다대수와 가장 가까운 프로그래밍 언어는 Lisp입니다.&lt;/p&gt;
&lt;p&gt;따라서 함수형 프로그래밍 개념은 Lisp 계열로 이해하는 것이 가장 효율적이라 생각합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Lisp는 전위 표현식으로 이루어진 언어로,&lt;/p&gt;
&lt;pre class=&quot;scheme&quot;&gt;&lt;code&gt;(함수 인자1 인자2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;와 같은 형태를 띄고 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아래의 링크는 Lisp의 방언중 하나인 Racket이란 언어로 소개한 함수형 프로그래밍 입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/62&quot;&gt;내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1583588046275&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.&quot; data-og-description=&quot;내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비. 2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로그..&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/62&quot; data-og-url=&quot;https://black7375.tistory.com/62&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XSScr/hyFdztttVP/lhHdkrnzTPsTzMG5PVHJt0/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/evTYmS/hyFdv5GfIz/D6bu1USRfgqfGpb0agt2O1/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/etv0pP/hyFbQKmY3D/okozar2bVMyK4GOLRO6hg0/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/62&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XSScr/hyFdztttVP/lhHdkrnzTPsTzMG5PVHJt0/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/evTYmS/hyFdv5GfIz/D6bu1USRfgqfGpb0agt2O1/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612,https://scrap.kakaocdn.net/dn/etv0pP/hyFbQKmY3D/okozar2bVMyK4GOLRO6hg0/img.png?width=792&amp;amp;height=612&amp;amp;face=0_0_792_612');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비. 2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로그..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;black7375.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;매우 긴 내용이었지만 정리해봅시다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;함수형 프로그래밍은 결과값 말고 다른 상태를 변경시키지 않는 순수 함수를 사용한다.
&lt;ul&gt;
&lt;li&gt;다른 상태를 변경시키는 것을 부작용(Side Effect)라 부르며 랜덤, I/O작업등도 포함된다.&lt;/li&gt;
&lt;li&gt;부작용이 있으면 상태에 따라 연산의 결과가 달라져, 최적화(예: 메모이제이션)와 버그추척이 힘들다.&lt;/li&gt;
&lt;li&gt;숨겨진 상태변화를 없애려면 명시적으로 매개변수와 출력값을 지정하면 되며, I/O 작업의 경우 모나드를 도입해 순수함수를 보장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;람다 대수는 튜링완전하며 표현식(Expression), 함수(Fuction), 적용(Application)으로 이루어진다.
&lt;ul&gt;
&lt;li&gt;식별자의 이름(Name)은 자리 표시자(Place Holder)의 역할만 하며 치환(&amp;alpha;-reduction)이 가능하다. 이 때문에 람다함수는 익명함수라 부르기도 한다.&lt;/li&gt;
&lt;li&gt;축약(&amp;beta;-reduction)되었을 때 축약대상은 종속변수, 남는 것은 자유변수로 생각할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;함수형 프로그래밍(람다대수)의 함수는 일급 객체다.
&lt;ul&gt;
&lt;li&gt;커링(Curring)을 사용하면 함수의 실행을 늦추거나(lazy evaluation), 재사용성을 늘릴 수 있다.&lt;/li&gt;
&lt;li&gt;열린 함수(자유변수가 존재)을 닫힌 함수로 만들어주는 것이 클로저며, 내부함수가 외부함수의 context에 접근할 수 있다.&lt;/li&gt;
&lt;li&gt;하나 이상의 함수를 인자로 받거나 결과로 반환하는 것이 고차함수며 &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt; 등이 존재하며 매우 편리하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;결론적으로 보자면,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;객체지향 프로그래밍: '상태'를 나누어 관리&lt;/li&gt;
&lt;li&gt;함수형 프로그래밍: '상태'를 변경하지 않고, 드러내며 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;자바스크립트의 화살표 함수는 람다 함수에 거부감을 줄이기 위해 만든 이름이다.&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;h2&gt;람다의 장점&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;짧은 함수&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const a = [
  &quot;Hydrogen&quot;,
  &quot;Helium&quot;,
  &quot;Lithium&quot;,
  &quot;Beryl&amp;shy;lium&quot;
];

const a2 = a.map(function(s) { return s.length; }); //일반
const a3 = a.map( s =&amp;gt; s.length );                  //람다&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;일반적인 함수보다 람다를 사용한 코드가 간결하다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;까다로운 &lt;code&gt;this&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;자바스크립트의 객체를 다룰때 사용하는 문법인 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this&quot;&gt;this&lt;/a&gt;는 Lexical Scope(정의하는 곳에 따라 결정)이 아니라 Dynamic Scope(불려지는 곳에 따라 결정)되며 &lt;code&gt;&quot;use strict&quot;&lt;/code&gt; (&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Strict_mode&quot;&gt;엄격모드&lt;/a&gt;) 사용여부에 따라 달라지기도 한다.&lt;/p&gt;
&lt;p&gt;따라서 사용하는 입장에서는 까다롭게 느껴진다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예를 들어 다음 코드는 &lt;b&gt;동작하지 않는다&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;첫번째 this는 Person, 두번째 this는 전역이 대상이기 때문이다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function Person1() {
  this.age = 0;

  setInterval(function growUp() {
    this.age++;
  }, 1000);
}
const p1 = new Person1();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 코드를 동작 가능하게 고쳐보자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;변수에 할당&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;self&lt;/code&gt;란 변수에 &lt;code&gt;this&lt;/code&gt;를 대입하여 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function Person2() {
  var self = this;
  self.age = 0;

  setInterval(function growUp() {
    self.age++;
  }, 1000);
}
const p2 = new Person2();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bind&lt;/code&gt; &lt;b&gt;사용&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;this&lt;/code&gt;값이 &lt;code&gt;growUp&lt;/code&gt;함수에 전달되도록 바인딩을 할 수도 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function Person3() {
  this.age = 0;

  setInterval(function growUp() {
    this.age++;
  }.bind(this), 1000);
}
const p3 = new Person3();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;람다&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;람다를 사용하면 Lexical Scope로 처리되기 때문에 골머리를 앓을 필요가 없다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function Person4() {
  this.age = 0;

  setInterval(() =&amp;gt; {
    this.age++;
  }, 1000);
}
const p4 = new Person4();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;다른 언어&lt;/h3&gt;
&lt;p&gt;다른 언어로는 역시 OOP의 대표적인 언어인 자바를 살펴보자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;일반적인 클래스와 인터페이스&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;인터페이스의 함수를 오버라이드한 후 사용한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class JButtonTest_General extends JFrame implements ActionListener {
...
    JButtonTest_General() {
        ...

        //Set Button
        button = new JButton(&quot;Button&quot;);
        button.setActionCommand(button.getText());
        button.addActionListener(this);
        add(button);
        ...
    }

...
    @Override
    public void actionPerformed(java.awt.event.ActionEvent e) {
        if (e.getActionCommand().equals(button.getText())) {
            label.setText(button.getText());
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;익명 클래스&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;클래스 단위로 인터페이스를 상속받는 대신, 함수내부에서 인터페이스를 사용한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class JButtonTest_Anonymous extends JFrame {
...
    JButtonTest_Anonymous() {
        ...
        //Set Button
        button = new JButton(&quot;Input&quot;);
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                label.setText(button.getText());
            }
        });
        add(button);
        ...
    }
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;람다&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;인터페이스의 인스턴스화, 함수 오버라이드 표시 없이 바로 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;람다는 '익명'함수이기 가능한 일이다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class JButtonTest_Lambda extends JFrame {
...
    JButtonTest_Lambda() {
        ...
        //Set Button
        button = new JButton(&quot;Input&quot;);
        button.addActionListener((e) -&amp;gt; {
            label.setText(button.getText());
        });
        add(button);
        ...
    }
...
}&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;클로저의 활용&lt;/h2&gt;
&lt;p&gt;오직 하나의 메소드를 가지고 있는 객체를 일반적으로 사용하는 모든 곳에 클로저를 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;특히 웹은 사용자의 이벤트에 의한 콜백으로 사용하는 경우가 많기 때문에 클로저는 유용하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;기초 예시.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;글씨 크기를 사용자의 클릭에 따라 바꾸고 싶다고 생각해보자.&lt;/p&gt;
&lt;p&gt;우선 다음과 같은 HTML의 링크를 준비했다.&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;a href=&quot;#&quot; id=&quot;size-12&quot;&amp;gt;12&amp;lt;/a&amp;gt; 
&amp;lt;a href=&quot;#&quot; id=&quot;size-14&quot;&amp;gt;14&amp;lt;/a&amp;gt; 
&amp;lt;a href=&quot;#&quot; id=&quot;size-16&quot;&amp;gt;16&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;클로저를 이용하면 간단하게 각 이벤트에 해당하는 콜백함수를 만들어서 적용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function makeSizer(size) {
  return () =&amp;gt; {
    document.body.style.fontSize = size + 'px';
  };
}

const size12 = makeSizer(12);
const size14 = makeSizer(14);
const size16 = makeSizer(16);

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;객체지향 따라하기.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;객체지향에서 중요한 개념중 하나는 은닉화/캡슐화를 하는 것이다.&lt;/p&gt;
&lt;p&gt;자바스크립트는 태생적으로 은닉화를 지원하지 않지만 클로저를 활용한다면 &lt;code&gt;private&lt;/code&gt; 메소드를 만들 수 있다!!&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const counter = (() =&amp;gt; {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment() {
      changeBy(1);
    },
    decrement() {
      changeBy(-1);
    },
    value() {
      return privateCounter;
    }
  };
})();

console.log(counter.value()); // logs 0
counter.increment();
counter.increment();
console.log(counter.value()); // logs 2
counter.decrement();
console.log(counter.value()); // logs 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 코드에서 privateCounter과 changeBy는 private의 형태로 쓰이고 있다는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;클로저와 성능&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;새로운 객체/클래스를 생성 할 때, 메소드는 일반적으로 객체 생성자에 정의되기보다는 객체의 프로토타입에 연결되어야 좋다.&lt;/p&gt;
&lt;p&gt;생성자가 호출(개체가 생성) 될 때마다 메서드가 다시 할당되어 성능과 메모리를 낭비할 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서 이 코드는&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
  this.getName = function() {
    return this.name;
  };

  this.getMessage = function() {
    return this.message;
  };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음과 같이 고쳐볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function MyObject(name, message) {
    this.name = name.toString();
    this.message = message.toString();
}
(function() {
    this.getName = function() {
        return this.name;
    };
    this.getMessage = function() {
        return this.message;
    };
}).call(MyObject.prototype);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MDN&lt;br /&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions&lt;/a&gt; &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Closures&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Closures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;자바 익명클래스와 람다식&lt;br /&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/168099931290/자바-익명클래스와-람다식&quot;&gt;https://black7375.tumblr.com/post/168099931290/자바-익명클래스와-람다식&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;라이브러리&lt;/h2&gt;
&lt;p&gt;함수형 프로그래밍을 위한 라이브러리로 &lt;a href=&quot;https://lodash.com/&quot;&gt;Lodash&lt;/a&gt;나 &lt;a href=&quot;http://ramdajs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ramda.js&lt;/a&gt;, &lt;a href=&quot;https://github.com/selfrefactor/rambda&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rambda.js&lt;/a&gt;가 유명하며 앞서 소개한 고차함수등을 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;단, 네이티브 함수와 비교를 해보고 사용하길 바란다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20190515/&quot;&gt;Lodash의 대체재로서의 순수 자바스크립트 함수&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1583590471389&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Lodash의 대체재로서의 순수 자바스크립트 함수&quot; data-og-description=&quot;이 포스트는 가장 널리 사용되고있는 라이브러리인 Lodash / Underscore.js 의 유틸리티 함수들을 순수 자바스크립트를 통해 어느 정도로 대체해 줄 수 있는지 이해를 돕기 위해 정리된 내용이다.&quot; data-og-host=&quot;ui.toast.com&quot; data-og-source-url=&quot;https://ui.toast.com/weekly-pick/ko_20190515/&quot; data-og-url=&quot;https://ui.toast.com/weekly-pick/ko_20190515/undefined/weekly-pick/ko_20190515&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/zJfyg/hyFbVLH5S8/Vij7nSRIkaW0kThAYdazEK/img.png?width=800&amp;amp;height=255&amp;amp;face=0_0_800_255,https://scrap.kakaocdn.net/dn/gPYaR/hyFbPdDQJr/Lbd3bTc7Kn8WObd8ANK9K0/img.png?width=1600&amp;amp;height=456&amp;amp;face=0_0_1600_456,https://scrap.kakaocdn.net/dn/q1t28/hyFdAlDc73/dJdin0HuzQtmnWdWKFmecK/img.png?width=1414&amp;amp;height=340&amp;amp;face=0_0_1414_340&quot;&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20190515/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ui.toast.com/weekly-pick/ko_20190515/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/zJfyg/hyFbVLH5S8/Vij7nSRIkaW0kThAYdazEK/img.png?width=800&amp;amp;height=255&amp;amp;face=0_0_800_255,https://scrap.kakaocdn.net/dn/gPYaR/hyFbPdDQJr/Lbd3bTc7Kn8WObd8ANK9K0/img.png?width=1600&amp;amp;height=456&amp;amp;face=0_0_1600_456,https://scrap.kakaocdn.net/dn/q1t28/hyFdAlDc73/dJdin0HuzQtmnWdWKFmecK/img.png?width=1414&amp;amp;height=340&amp;amp;face=0_0_1414_340');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Lodash의 대체재로서의 순수 자바스크립트 함수&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;이 포스트는 가장 널리 사용되고있는 라이브러리인 Lodash / Underscore.js 의 유틸리티 함수들을 순수 자바스크립트를 통해 어느 정도로 대체해 줄 수 있는지 이해를 돕기 위해 정리된 내용이다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;ui.toast.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/@deptno/ramda-js-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EB%8F%84%EC%9E%85-e18ab3fab478&quot;&gt;Ramda.js, 자바스크립트 함수형 프로그래밍 라이브러리 도입&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1583590866093&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Ramda.js, 자바스크립트 함수형 프로그래밍 라이브러리 도입&quot; data-og-description=&quot;Ramda.js 적용기&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@deptno/ramda-js-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EB%8F%84%EC%9E%85-e18ab3fab478&quot; data-og-url=&quot;https://medium.com/@deptno/ramda-js-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EB%8F%84%EC%9E%85-e18ab3fab478&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Zy1vG/hyFdCwZaso/uYB1xtmcLYYXviqd4SCYJK/img.png?width=1200&amp;amp;height=1238&amp;amp;face=0_0_1200_1238,https://scrap.kakaocdn.net/dn/eB3Hg/hyFdz1knZk/9aZ2QPftkdIq0MzkgJaJf1/img.png?width=58&amp;amp;height=59&amp;amp;face=0_0_58_59,https://scrap.kakaocdn.net/dn/GVM3G/hyFbShahWq/YQjvWjSpLIkzKKhepauSI1/img.png?width=60&amp;amp;height=50&amp;amp;face=0_0_60_50&quot;&gt;&lt;a href=&quot;https://medium.com/@deptno/ramda-js-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EB%8F%84%EC%9E%85-e18ab3fab478&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@deptno/ramda-js-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EB%8F%84%EC%9E%85-e18ab3fab478&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Zy1vG/hyFdCwZaso/uYB1xtmcLYYXviqd4SCYJK/img.png?width=1200&amp;amp;height=1238&amp;amp;face=0_0_1200_1238,https://scrap.kakaocdn.net/dn/eB3Hg/hyFdz1knZk/9aZ2QPftkdIq0MzkgJaJf1/img.png?width=58&amp;amp;height=59&amp;amp;face=0_0_58_59,https://scrap.kakaocdn.net/dn/GVM3G/hyFbShahWq/YQjvWjSpLIkzKKhepauSI1/img.png?width=60&amp;amp;height=50&amp;amp;face=0_0_60_50');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Ramda.js, 자바스크립트 함수형 프로그래밍 라이브러리 도입&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Ramda.js 적용기&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://engineering.huiseoul.com/%EB%9E%8C%EB%8B%A4-ramda-%EC%99%80-%EB%A1%9C%EB%8B%A4%EC%8B%9C-lodash-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-709ef969c9a5&quot;&gt;람다(Ramda)와 로다시(Lodash) 그리고 함수형 프로그래밍&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1583590865906&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;람다(Ramda)와 로다시(Lodash) 그리고 함수형 프로그래밍&quot; data-og-description=&quot;What is good code?&quot; data-og-host=&quot;engineering.huiseoul.com&quot; data-og-source-url=&quot;https://engineering.huiseoul.com/%EB%9E%8C%EB%8B%A4-ramda-%EC%99%80-%EB%A1%9C%EB%8B%A4%EC%8B%9C-lodash-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-709ef969c9a5&quot; data-og-url=&quot;https://engineering.huiseoul.com/%EB%9E%8C%EB%8B%A4-ramda-%EC%99%80-%EB%A1%9C%EB%8B%A4%EC%8B%9C-lodash-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-709ef969c9a5&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/GIAbu/hyFbQjleEJ/FjaPwrhOtsEXSRwbZOnPc1/img.png?width=1200&amp;amp;height=733&amp;amp;face=0_0_1200_733,https://scrap.kakaocdn.net/dn/lruIo/hyFdsVrnfQ/HE60KFKCbckumUOylgPevK/img.png?width=60&amp;amp;height=36&amp;amp;face=0_0_60_36&quot;&gt;&lt;a href=&quot;https://engineering.huiseoul.com/%EB%9E%8C%EB%8B%A4-ramda-%EC%99%80-%EB%A1%9C%EB%8B%A4%EC%8B%9C-lodash-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-709ef969c9a5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://engineering.huiseoul.com/%EB%9E%8C%EB%8B%A4-ramda-%EC%99%80-%EB%A1%9C%EB%8B%A4%EC%8B%9C-lodash-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-709ef969c9a5&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/GIAbu/hyFbQjleEJ/FjaPwrhOtsEXSRwbZOnPc1/img.png?width=1200&amp;amp;height=733&amp;amp;face=0_0_1200_733,https://scrap.kakaocdn.net/dn/lruIo/hyFdsVrnfQ/HE60KFKCbckumUOylgPevK/img.png?width=60&amp;amp;height=36&amp;amp;face=0_0_60_36');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;람다(Ramda)와 로다시(Lodash) 그리고 함수형 프로그래밍&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;What is good code?&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;engineering.huiseoul.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://survivejs.com/blog/rambda-interview/&quot;&gt;Rambda - Faster and Smaller Alternative to Ramda - Interview with Dejan Toteff (survivejs.com)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1613904443471&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Rambda - Faster and Smaller Alternative to Ramda - Interview with Dejan Toteff&quot; data-og-description=&quot;Even though you can get far with JavaScript's native functionality, eventually you'll find yourself&amp;hellip;&quot; data-og-host=&quot;survivejs.com&quot; data-og-source-url=&quot;https://survivejs.com/blog/rambda-interview/&quot; data-og-url=&quot;https://survivejs.com/blog/rambda-interview/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://survivejs.com/blog/rambda-interview/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://survivejs.com/blog/rambda-interview/&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;&gt;Rambda - Faster and Smaller Alternative to Ramda - Interview with Dejan Toteff&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Even though you can get far with JavaScript's native functionality, eventually you'll find yourself&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;survivejs.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;TS를 사용한다면 fp-ts를 사용해보자.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gcanti.github.io/fp-ts/&quot;&gt;https://gcanti.github.io/fp-ts/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610255232339&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Introduction - fp-ts&quot; data-og-description=&quot;Typed functional programming in TypeScript fp-ts provides developers with popular patterns and reliable abstractions from typed functional languages in TypeScript. Disclaimer. Teaching functional programming is out of scope of this project, so the document&quot; data-og-host=&quot;gcanti.github.io&quot; data-og-source-url=&quot;https://gcanti.github.io/fp-ts/&quot; data-og-url=&quot;https://gcanti.github.io/fp-ts/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/e4ZTm/hyIS9MK1Xg/M9jHqi4n4k8iZE2JLKiRx0/img.png?width=360&amp;amp;height=366&amp;amp;face=0_0_360_366&quot;&gt;&lt;a href=&quot;https://gcanti.github.io/fp-ts/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gcanti.github.io/fp-ts/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/e4ZTm/hyIS9MK1Xg/M9jHqi4n4k8iZE2JLKiRx0/img.png?width=360&amp;amp;height=366&amp;amp;face=0_0_360_366');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Introduction - fp-ts&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Typed functional programming in TypeScript fp-ts provides developers with popular patterns and reliable abstractions from typed functional languages in TypeScript. Disclaimer. Teaching functional programming is out of scope of this project, so the document&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;gcanti.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;모나드??&lt;/h2&gt;
&lt;p&gt;모나드 이야기가 나온김에 아주 간단한 형태만 이해해보도록 한다.&lt;/p&gt;
&lt;p&gt;모나드를 이해할때는 Haskell이 가장 효율적이므로 Haskell로 된 코드를 사용해보자.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://edykim.com/ko/post/javascript-monad/&quot;&gt;자바스크립트&lt;/a&gt;로도 설명할 수 있지만 이해하기에 코드가 깔끔하진 않다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음은 하스켈의 간단한 입출력 예제다.&lt;/p&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;main = do
    putStrLn  &quot;Input: &quot;
    x &amp;lt;- getLine
    putStrLn (&quot;The Input was &quot; ++ x)&lt;/code&gt;&lt;/pre&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;&lt;a href=&quot;https://black7375.tistory.com/69?category=270745&quot;&gt;간단한 모나드 설명과 예제&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1583590890959&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;간단한 모나드 설명과 예제&quot; data-og-description=&quot;리엑트 네이티브 스터디 때문에 시작한 글이었는데 생각보다 길어져서 분리하게 되었다. 자바스크립트 관련 코드는 해당 스터디쪽 문서에 올릴 예정. 역시 모나드를 이해할때는 Haskell이 가장 효율적이므로 Haske..&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/69?category=270745&quot; data-og-url=&quot;https://black7375.tistory.com/69&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cUDIoP/hyFbYIs6dS/YDzi4lC29s6SabdZNwspfk/img.png?width=176&amp;amp;height=194&amp;amp;face=0_0_176_194,https://scrap.kakaocdn.net/dn/exKzDP/hyFbTAm6Nd/6U1A9KDtJIE7kwMt2MGaBk/img.png?width=176&amp;amp;height=194&amp;amp;face=0_0_176_194,https://scrap.kakaocdn.net/dn/b2eMV1/hyFbYuTetp/xExcbxh1jCLichHpTwxes1/img.png?width=1920&amp;amp;height=1693&amp;amp;face=0_0_1920_1693&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/69?category=270745&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/69?category=270745&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cUDIoP/hyFbYIs6dS/YDzi4lC29s6SabdZNwspfk/img.png?width=176&amp;amp;height=194&amp;amp;face=0_0_176_194,https://scrap.kakaocdn.net/dn/exKzDP/hyFbTAm6Nd/6U1A9KDtJIE7kwMt2MGaBk/img.png?width=176&amp;amp;height=194&amp;amp;face=0_0_176_194,https://scrap.kakaocdn.net/dn/b2eMV1/hyFbYuTetp/xExcbxh1jCLichHpTwxes1/img.png?width=1920&amp;amp;height=1693&amp;amp;face=0_0_1920_1693');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;간단한 모나드 설명과 예제&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;리엑트 네이티브 스터디 때문에 시작한 글이었는데 생각보다 길어져서 분리하게 되었다. 자바스크립트 관련 코드는 해당 스터디쪽 문서에 올릴 예정. 역시 모나드를 이해할때는 Haskell이 가장 효율적이므로 Haske..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;black7375.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;읽기 전에 꼭 알아두어야 할 것이 있다면 모나드의 설명의 &lt;code&gt;return&lt;/code&gt; 과 &lt;code&gt;bind&lt;/code&gt;는 자바스크립트의 &lt;code&gt;return&lt;/code&gt; , &lt;code&gt;Fuction.prototype.bind&lt;/code&gt; 와 다르다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Javascript에서의 모나드.&lt;/h3&gt;
&lt;p&gt;링크의 글을 읽어보면 알겠지만, Promise와 Async/Await가 대표적인 예이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Promise&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;비동기 작업의 최종 완료 또는 실패를 나타낸다.&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; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HE7gp/btqCy4LQUU9/GWJ6h8CNIx0QQClHuEKup0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HE7gp/btqCy4LQUU9/GWJ6h8CNIx0QQClHuEKup0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HE7gp/btqCy4LQUU9/GWJ6h8CNIx0QQClHuEKup0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHE7gp%2FbtqCy4LQUU9%2FGWJ6h8CNIx0QQClHuEKup0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;프로미스의 상태는 3가지로 나눌 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;대기(Pending): 이행, 거부가 일어나지 않은 초기 상태.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;이행(Fulfilled): 연산이 성공적으로 완료됨.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;거부(Rejected): 연산이 실패함.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function imgLoad(url) {
  return new Promise((resolve, reject) =&amp;gt; {
    const request = new XMLHttpRequest();
    request.open('GET', url);
    request.responseType = 'blob';
    request.onload = function() {
      if (request.status === 200) {
        resolve(request.response);
      } else {
        reject(Error('Image didn\'t load successfully; error code:' + request.statusText));
      }
    };
    request.onerror = function() {
      reject(Error('There was a network error.'));
    };
    request.send();
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;현대적인 함수나 API들은 프로미스를 통해 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Run-to-completion&quot;&gt;콜스택이 완료됨&lt;/a&gt;을 보장해준다.&lt;/p&gt;
&lt;p&gt;그리고 다음과 같이 고전적인 API를 Wrapping 해볼 수도 있겠다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function successCallback(result) {
  console.log(&quot;Audio file ready at URL: &quot; + result);
}

function failureCallback(error) {
  console.log(&quot;Error generating audio file: &quot; + error);
}

// 옛날: 콜백을 전달
createAudioFileAsync(audioSettings, successCallback, failureCallback);

// 프로미스: 콜백 첨부
const createAudioFilePromise = (audioSettings) =&amp;gt; new Promise(
  (resolve, reject) =&amp;gt; { createAudioFileAsync(audioSettings, resolve, reject); }
);
createAudioFilePromise(audioSettings)
  .then(successCallback, failureCallback);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;모나드 링크에서 봤던 것처럼 콜백을 개선해볼 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.then&lt;/code&gt;과 &lt;code&gt;.catch&lt;/code&gt; 메서드 반환 값은 프로미스이므로 Chaining이 가능하기 때문.&lt;/p&gt;
&lt;p&gt;그리고 Async/Await는 이를 더 간단하게 만드는 것이 가능하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Async/Await&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Async/Await는 Promise를 명령형처럼 사용하게 만들어주며 Promise로 반환한다.&lt;/p&gt;
&lt;p&gt;다음은 콜백, 프로미스를 Async/Await로 바꾼 예.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function callbackHell() {
  doSomething(function(result) {
    doSomethingElse(result, function(newResult) {
      doThirdThing(newResult, function(finalResult) {
        console.log('Got the final result: ' + finalResult);
      }, failureCallback);
    }, failureCallback);
  }, failureCallback);
}

function usePromise() {
  return doSomething()
    .then(result      =&amp;gt; doSomethingElse(result))
    .then(newResult   =&amp;gt; doThirdThing(newResult))
    .then(finalResult =&amp;gt; {
      console.log(`Got the final result: ${finalResult}`);
    })
    .catch(failureCallback);
}

async function useAsync() {
  try {
    const result      = await doSomething();
    const newResult   = await doSomethingElse(result);
    const finalResult = await doThirdThing(newResult);
    console.log(`Got the final result: ${finalResult}`);
  } catch (err) {
    failureCallback(err);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기타 프로미스와 비교할 만한 장점은 아래 링크에서 확인 가능하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/@constell99/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-async-await-%EA%B0%80-promises%EB%A5%BC-%EC%82%AC%EB%9D%BC%EC%A7%80%EA%B2%8C-%EB%A7%8C%EB%93%A4-%EC%88%98-%EC%9E%88%EB%8A%94-6%EA%B0%80%EC%A7%80-%EC%9D%B4%EC%9C%A0-c5fe0add656c&quot;&gt;자바스크립트의 Async/Await 가 Promises를 사라지게 만들 수 있는 6가지 이유&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1583596253962&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;자바스크립트의 Async/Await 가 Promises를 사라지게 만들 수 있는 6가지 이유&quot; data-og-description=&quot;이글은 6 Reasons Why JavaScript&amp;rsquo;s Async/Await Blows Promises Away (Tutorial)에 대한 번역입니다.&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@constell99/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-async-await-%EA%B0%80-promises%EB%A5%BC-%EC%82%AC%EB%9D%BC%EC%A7%80%EA%B2%8C-%EB%A7%8C%EB%93%A4-%EC%88%98-%EC%9E%88%EB%8A%94-6%EA%B0%80%EC%A7%80-%EC%9D%B4%EC%9C%A0-c5fe0add656c&quot; data-og-url=&quot;https://medium.com/@constell99/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-async-await-%EA%B0%80-promises%EB%A5%BC-%EC%82%AC%EB%9D%BC%EC%A7%80%EA%B2%8C-%EB%A7%8C%EB%93%A4-%EC%88%98-%EC%9E%88%EB%8A%94-6%EA%B0%80%EC%A7%80-%EC%9D%B4%EC%9C%A0-c5fe0add656c&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cbPhVy/hyFdsuoVVw/0ECNpulhkPZyg7MikKw2B1/img.png?width=928&amp;amp;height=328&amp;amp;face=0_0_928_328,https://scrap.kakaocdn.net/dn/Pvctl/hyFbW4XPAJ/n6KCY9SIx1StlLKfXzNER1/img.png?width=60&amp;amp;height=21&amp;amp;face=0_0_60_21,https://scrap.kakaocdn.net/dn/tkyEC/hyFbT8dZz8/J8KFDJ2LRuKh2QL5RN22I1/img.png?width=60&amp;amp;height=20&amp;amp;face=0_0_60_20&quot;&gt;&lt;a href=&quot;https://medium.com/@constell99/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-async-await-%EA%B0%80-promises%EB%A5%BC-%EC%82%AC%EB%9D%BC%EC%A7%80%EA%B2%8C-%EB%A7%8C%EB%93%A4-%EC%88%98-%EC%9E%88%EB%8A%94-6%EA%B0%80%EC%A7%80-%EC%9D%B4%EC%9C%A0-c5fe0add656c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@constell99/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-async-await-%EA%B0%80-promises%EB%A5%BC-%EC%82%AC%EB%9D%BC%EC%A7%80%EA%B2%8C-%EB%A7%8C%EB%93%A4-%EC%88%98-%EC%9E%88%EB%8A%94-6%EA%B0%80%EC%A7%80-%EC%9D%B4%EC%9C%A0-c5fe0add656c&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cbPhVy/hyFdsuoVVw/0ECNpulhkPZyg7MikKw2B1/img.png?width=928&amp;amp;height=328&amp;amp;face=0_0_928_328,https://scrap.kakaocdn.net/dn/Pvctl/hyFbW4XPAJ/n6KCY9SIx1StlLKfXzNER1/img.png?width=60&amp;amp;height=21&amp;amp;face=0_0_60_21,https://scrap.kakaocdn.net/dn/tkyEC/hyFbT8dZz8/J8KFDJ2LRuKh2QL5RN22I1/img.png?width=60&amp;amp;height=20&amp;amp;face=0_0_60_20');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;자바스크립트의 Async/Await 가 Promises를 사라지게 만들 수 있는 6가지 이유&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;이글은 6 Reasons Why JavaScript&amp;rsquo;s Async/Await Blows Promises Away (Tutorial)에 대한 번역입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Do / Binding&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;아직도 모나드가 어렵나요?&lt;/p&gt;
&lt;p&gt;그렇다면 JS에 바인딩 연산자와 Do Notation, 커링을 지원하는 함수가 있다고 가정하고 일반 함수와 비교해봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1610255664052&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 일반 함수
getFoo(&quot;/api/foo&quot;).chain(foo =&amp;gt; {
  return getBar(&quot;/api/bar&quot;).chain(bar =&amp;gt; {
    const lol = bar.name;
    return getBaz(&quot;/api/baz/&quot; + lol).map(baz =&amp;gt; {
      return foo + bar + baz;
    });
  });
});

// 바인딩 연산자
getFoo(&quot;/api/foo&quot;)   &amp;gt;&amp;gt;= (foo) =&amp;gt;
  getBar(&quot;/api/bar&quot;) &amp;gt;&amp;gt;= (bar) =&amp;gt; {
    const lol = bar.name;
    return map(getBaz(&quot;/api/baz/&quot; + lol)) &amp;gt;&amp;gt;= (baz) =&amp;gt; foo + bar + baz;
  };

// Do 문법
do {
  foo &amp;lt;&amp;lt; getFoo(&quot;/api/foo&quot;);
  bar &amp;lt;&amp;lt; getBar(&quot;/api/bar&quot;);
  const lol = bar.name;
  baz &amp;lt;&amp;lt; getBaz(&quot;/api/baz/&quot; + lol);

  foo + bar + baz;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;방금전에 봤던 Callback -&amp;gt; Promise -&amp;gt; Async/Await의 예와 비슷하게 느껴지지 않나요?&lt;/p&gt;
&lt;p&gt;어렵다고 하는데, 엄청나게 어렵진 않은 것 같습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;참고.&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MDN&lt;br /&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises&lt;/a&gt; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&lt;/a&gt; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Github&lt;br /&gt;&lt;a href=&quot;https://github.com/mdn/js-examples/tree/master/promises-test&quot;&gt;https://github.com/mdn/js-examples/tree/master/promises-test&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://github.com/pfgray/babel-plugin-monadic-do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/pfgray/babel-plugin-monadic-do&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://github.com/gajus/babel-plugin-transform-function-composition&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/gajus/babel-plugin-transform-function-composition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Developers Google&lt;br /&gt;&lt;a href=&quot;https://developers.google.com/web/fundamentals/primers/async-functions?hl=ko&quot;&gt;https://developers.google.com/web/fundamentals/primers/async-functions?hl=ko&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Faster async funtions and promises(V8 Blog)&amp;nbsp;&lt;br /&gt;&lt;a style=&quot;letter-spacing: 0px; -webkit-text-stroke-width: 0.04px;&quot; href=&quot;https://v8.dev/blog/fast-async&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://v8.dev/blog/fast-async&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Awesomely Descriptive Javascript with Monads&lt;br /&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://www.slideshare.net/wicherrr/awesomely-descriptive-javascript-with-monads&quot;&gt;https://www.slideshare.net/wicherrr/awesomely-descriptive-javascript-with-monads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;React와 모나드.&lt;/h3&gt;
&lt;p&gt;리엑트의 &lt;code&gt;hooks&lt;/code&gt;와도 깊은 연관성을 가지므로 읽어볼만 하다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.freecodecamp.org/news/when-to-use-react-suspense-vs-react-hooks-f66ef94cb54f/&quot;&gt;When to use React Suspense vs React Hooks&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1583596266497&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;When to use React Suspense vs React Hooks&quot; data-og-description=&quot;React Suspense is to a Monad as Hooks are to Applicative Notation Monads and Applicative Functors are extensively used in functional programming. There is a relationship between them and React Suspense for Data Fetching and React Hooks APIs. This is a quic&quot; data-og-host=&quot;www.freecodecamp.org&quot; data-og-source-url=&quot;https://www.freecodecamp.org/news/when-to-use-react-suspense-vs-react-hooks-f66ef94cb54f/&quot; data-og-url=&quot;https://www.freecodecamp.org/news/when-to-use-react-suspense-vs-react-hooks-f66ef94cb54f/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b91wDv/hyFdp5vVFO/jJvMH0i101zKsS4Nsp5Dlk/img.png?width=526&amp;amp;height=329&amp;amp;face=0_0_526_329,https://scrap.kakaocdn.net/dn/JfJW9/hyFdnNoik9/wLQHkDkhur3MFoVFsS5axK/img.png?width=526&amp;amp;height=329&amp;amp;face=0_0_526_329&quot;&gt;&lt;a href=&quot;https://www.freecodecamp.org/news/when-to-use-react-suspense-vs-react-hooks-f66ef94cb54f/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.freecodecamp.org/news/when-to-use-react-suspense-vs-react-hooks-f66ef94cb54f/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b91wDv/hyFdp5vVFO/jJvMH0i101zKsS4Nsp5Dlk/img.png?width=526&amp;amp;height=329&amp;amp;face=0_0_526_329,https://scrap.kakaocdn.net/dn/JfJW9/hyFdnNoik9/wLQHkDkhur3MFoVFsS5axK/img.png?width=526&amp;amp;height=329&amp;amp;face=0_0_526_329');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;When to use React Suspense vs React Hooks&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;React Suspense is to a Monad as Hooks are to Applicative Notation Monads and Applicative Functors are extensively used in functional programming. There is a relationship between them and React Suspense for Data Fetching and React Hooks APIs. This is a quic&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.freecodecamp.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;참고로 Functor, Applicative, Monad에 대해 쉽게 설명하자면&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; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKQbKp/btqCynSwMgP/HvVcINEoVDsk9s2w0kHjWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKQbKp/btqCynSwMgP/HvVcINEoVDsk9s2w0kHjWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKQbKp/btqCynSwMgP/HvVcINEoVDsk9s2w0kHjWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKQbKp%2FbtqCynSwMgP%2FHvVcINEoVDsk9s2w0kHjWk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;figure class=&quot;imageblock alignCenter&quot; width=&quot;900&quot; height=&quot;506&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dz5mnS/btqCynSwNdI/fxC6xaee2VU0Bra1swUJXK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dz5mnS/btqCynSwNdI/fxC6xaee2VU0Bra1swUJXK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dz5mnS/btqCynSwNdI/fxC6xaee2VU0Bra1swUJXK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dz5mnS/btqCynSwNdI/fxC6xaee2VU0Bra1swUJXK/img.gif&quot; width=&quot;900&quot; height=&quot;506&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;ul&gt;
&lt;li&gt;&lt;b&gt;Functor&lt;/b&gt;: 함수를 &lt;code&gt;포장된&lt;/code&gt; 값에 적용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Applicative&lt;/b&gt;: &lt;code&gt;포장된&lt;/code&gt; 함수를 &lt;code&gt;포장된&lt;/code&gt; 값에 적용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Monad&lt;/b&gt;: &lt;code&gt;포장된&lt;/code&gt; 값을 리턴하는 함수를 &lt;code&gt;포장된&lt;/code&gt; 값에 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;리엑티브 프로그래밍.&lt;/h3&gt;
&lt;p&gt;모나드 설명을 보면 알 수 있듯, Rx에서 쓰이는 &lt;code&gt;Observable&lt;/code&gt;, &lt;code&gt;Maybe&lt;/code&gt;등은 모나드의 한 예시이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;특히 Observable의 경우 다음처럼 생각하면 이해하기 쉽다.&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; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OZoPD/btqCzAqfX21/UeKdCUVH6OXdgHknrL9otk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OZoPD/btqCzAqfX21/UeKdCUVH6OXdgHknrL9otk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OZoPD/btqCzAqfX21/UeKdCUVH6OXdgHknrL9otk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOZoPD%2FbtqCzAqfX21%2FUeKdCUVH6OXdgHknrL9otk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Rx가 세상에 나오게된 이유는 다음 글이 잘 소개하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://huns.me/development/2051&quot;&gt;MS는 ReactiveX를 왜 만들었을까? (feat. RxJS)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1583588109233&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;MS는 ReactiveX를 왜 만들었을까? (feat. RxJS)&quot; data-og-description=&quot;김코딩 님이 잘하고 싶어서 만든 블로그&quot; data-og-host=&quot;huns.me&quot; data-og-source-url=&quot;https://huns.me/development/2051&quot; data-og-url=&quot;https://coderk.github.io/development/2051&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/55Kkz/hyFbYazUpd/xJY2m3vOmaKRy0YUkyFVK0/img.png?width=1024&amp;amp;height=640&amp;amp;face=0_0_1024_640,https://scrap.kakaocdn.net/dn/cbDJZT/hyFbY2IwpH/DdirtjDNIYVcrkruL2iBh1/img.jpg?width=1024&amp;amp;height=576&amp;amp;face=412_97_484_175,https://scrap.kakaocdn.net/dn/dbP8sb/hyFduTeQJg/CQ8A6BUPQJ7YakSMG1Pc40/img.png?width=871&amp;amp;height=397&amp;amp;face=755_76_784_108&quot;&gt;&lt;a href=&quot;https://huns.me/development/2051&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://huns.me/development/2051&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/55Kkz/hyFbYazUpd/xJY2m3vOmaKRy0YUkyFVK0/img.png?width=1024&amp;amp;height=640&amp;amp;face=0_0_1024_640,https://scrap.kakaocdn.net/dn/cbDJZT/hyFbY2IwpH/DdirtjDNIYVcrkruL2iBh1/img.jpg?width=1024&amp;amp;height=576&amp;amp;face=412_97_484_175,https://scrap.kakaocdn.net/dn/dbP8sb/hyFduTeQJg/CQ8A6BUPQJ7YakSMG1Pc40/img.png?width=871&amp;amp;height=397&amp;amp;face=755_76_784_108');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;MS는 ReactiveX를 왜 만들었을까? (feat. RxJS)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;김코딩 님이 잘하고 싶어서 만든 블로그&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;huns.me&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;RxJS는 또 다른 웹 프레임워크인 Angular에서 통합되어 쓰이고 있다.&lt;/p&gt;
&lt;figure id=&quot;og_1583588109604&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Angular RxJS | PoiemaWeb&quot; data-og-description=&quot;리액티브(Reactive, 반응형) 프로그래밍은 비동기 데이터 스트림(Asynchronous data stream)에 기반을 둔 프로그래밍 패러다임이다. 데이터 스트림이란 연속된 데이터의 흐름을 말하며 리액티브 프로그래밍은 기본적으로 모든 것을 연속성을 갖는 데이터의 흐름인 스트림으로 본다.&quot; data-og-host=&quot;poiemaweb.com&quot; data-og-source-url=&quot;https://poiemaweb.com/angular-rxjs&quot; data-og-url=&quot;https://poiemaweb.com/angular-rxjs&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/FVe9z/hyFdorW0Tb/tBJZi1tKGcvZwkYSwmTa8K/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bPrMIl/hyFdpqRg0z/H2fzDksdJxTvQc4y5zGWgK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bl9ygB/hyFdzfWjT6/YNohsDZ6PJ56zvo1zanm60/img.png?width=2342&amp;amp;height=1260&amp;amp;face=0_0_2342_1260&quot;&gt;&lt;a href=&quot;https://poiemaweb.com/angular-rxjs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://poiemaweb.com/angular-rxjs&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/FVe9z/hyFdorW0Tb/tBJZi1tKGcvZwkYSwmTa8K/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bPrMIl/hyFdpqRg0z/H2fzDksdJxTvQc4y5zGWgK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bl9ygB/hyFdzfWjT6/YNohsDZ6PJ56zvo1zanm60/img.png?width=2342&amp;amp;height=1260&amp;amp;face=0_0_2342_1260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Angular RxJS | PoiemaWeb&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;리액티브(Reactive, 반응형) 프로그래밍은 비동기 데이터 스트림(Asynchronous data stream)에 기반을 둔 프로그래밍 패러다임이다. 데이터 스트림이란 연속된 데이터의 흐름을 말하며 리액티브 프로그래밍은 기본적으로 모든 것을 연속성을 갖는 데이터의 흐름인 스트림으로 본다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;poiemaweb.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1583588110903&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Angular 환경에서 RxJS 100% 활용하기&quot; data-og-description=&quot;이번 블로그에서는 RxJS가 무엇이며, Angular 환경에서 RxJS를 최대한 활용할 수 있는 pattern을 공유하고자 합니다.&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/coinone-official/angular-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-rxjs-100-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0-afe43c434c8&quot; data-og-url=&quot;https://medium.com/coinone-official/angular-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-rxjs-100-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0-afe43c434c8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/tN9RZ/hyFdpdj7XB/vudhoBwfdQVr0k84nu4NY1/img.png?width=782&amp;amp;height=719&amp;amp;face=0_0_782_719,https://scrap.kakaocdn.net/dn/bd9oQ6/hyFbOluSsC/AKs0rj701XsK6O56rCKzG1/img.png?width=60&amp;amp;height=55&amp;amp;face=0_0_60_55,https://scrap.kakaocdn.net/dn/AU6fI/hyFbUlGHlm/2i7fOdbN4viCw8DcwSclQk/img.png?width=60&amp;amp;height=55&amp;amp;face=0_0_60_55&quot;&gt;&lt;a href=&quot;https://medium.com/coinone-official/angular-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-rxjs-100-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0-afe43c434c8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/coinone-official/angular-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-rxjs-100-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0-afe43c434c8&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/tN9RZ/hyFdpdj7XB/vudhoBwfdQVr0k84nu4NY1/img.png?width=782&amp;amp;height=719&amp;amp;face=0_0_782_719,https://scrap.kakaocdn.net/dn/bd9oQ6/hyFbOluSsC/AKs0rj701XsK6O56rCKzG1/img.png?width=60&amp;amp;height=55&amp;amp;face=0_0_60_55,https://scrap.kakaocdn.net/dn/AU6fI/hyFbUlGHlm/2i7fOdbN4viCw8DcwSclQk/img.png?width=60&amp;amp;height=55&amp;amp;face=0_0_60_55');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Angular 환경에서 RxJS 100% 활용하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;이번 블로그에서는 RxJS가 무엇이며, Angular 환경에서 RxJS를 최대한 활용할 수 있는 pattern을 공유하고자 합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;React와 섞어쓰기 위해서라면 다음을,&lt;/p&gt;
&lt;figure id=&quot;og_1583597002230&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;React Hooks + RxJS or How React Is Meant to Be&quot; data-og-description=&quot;In this article, we will explore how the&amp;nbsp;RxJS and React combo allows for better readability and less boilerplate. Additionally, we will examine how they allow the&amp;nbsp;the same functionality as the popular state management frameworks even though they aren't fra&quot; data-og-host=&quot;blog.soshace.com&quot; data-og-source-url=&quot;https://blog.soshace.com/react-hooks-rxjs-or-how-react-is-meant-to-be/&quot; data-og-url=&quot;https://blog.soshace.com/react-hooks-rxjs-or-how-react-is-meant-to-be/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eIp0z/hyFdyOVB4J/bDH2ek6AdVkg11yQVGdwK0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bpr8ZH/hyFbNGXmHp/ByFb1k1H68FTOaJ9PE2Z5k/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://blog.soshace.com/react-hooks-rxjs-or-how-react-is-meant-to-be/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.soshace.com/react-hooks-rxjs-or-how-react-is-meant-to-be/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eIp0z/hyFdyOVB4J/bDH2ek6AdVkg11yQVGdwK0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bpr8ZH/hyFbNGXmHp/ByFb1k1H68FTOaJ9PE2Z5k/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;React Hooks + RxJS or How React Is Meant to Be&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;In this article, we will explore how the&amp;nbsp;RxJS and React combo allows for better readability and less boilerplate. Additionally, we will examine how they allow the&amp;nbsp;the same functionality as the popular state management frameworks even though they aren't fra&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;blog.soshace.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1583597006998&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Reactive Redux state with RxJS&quot; data-og-description=&quot;If you're like me, you're using Redux every day, to manage your state, probably with React, or any other view library or framework. You definitely know how hard is when it comes to handling async code and side effects. I know that very well, been there, tr&quot; data-og-host=&quot;ivanjov.com&quot; data-og-source-url=&quot;https://ivanjov.com/reactive-redux-state-with-rxjs/&quot; data-og-url=&quot;http://ivanjov.com/reactive-redux-state-with-rxjs/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pnHQk/hyFbNAbw8i/Dtmk3e38xrnlURS8wQ5g2K/img.png?width=1000&amp;amp;height=350&amp;amp;face=0_0_1000_350,https://scrap.kakaocdn.net/dn/cgyAeF/hyFdz1mwOZ/oKejJ5CJmcbaWpmYx2fl3K/img.png?width=1000&amp;amp;height=350&amp;amp;face=0_0_1000_350,https://scrap.kakaocdn.net/dn/m0AQQ/hyFdwcu3Vb/pr4IztkSNfvO7CdICmiT10/img.png?width=3000&amp;amp;height=2278&amp;amp;face=1373_1251_1560_1457&quot;&gt;&lt;a href=&quot;https://ivanjov.com/reactive-redux-state-with-rxjs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ivanjov.com/reactive-redux-state-with-rxjs/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pnHQk/hyFbNAbw8i/Dtmk3e38xrnlURS8wQ5g2K/img.png?width=1000&amp;amp;height=350&amp;amp;face=0_0_1000_350,https://scrap.kakaocdn.net/dn/cgyAeF/hyFdz1mwOZ/oKejJ5CJmcbaWpmYx2fl3K/img.png?width=1000&amp;amp;height=350&amp;amp;face=0_0_1000_350,https://scrap.kakaocdn.net/dn/m0AQQ/hyFdwcu3Vb/pr4IztkSNfvO7CdICmiT10/img.png?width=3000&amp;amp;height=2278&amp;amp;face=1373_1251_1560_1457');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Reactive Redux state with RxJS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;If you're like me, you're using Redux every day, to manage your state, probably with React, or any other view library or framework. You definitely know how hard is when it comes to handling async code and side effects. I know that very well, been there, tr&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;ivanjov.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;RxJS 자체를 배우고 싶다면 아래를 참고해보아도 좋다.&lt;/p&gt;
&lt;figure id=&quot;og_1583588112569&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ReactiveX&quot; data-og-description=&quot;CROSS-PLATFORM Available for idiomatic Java, Scala, C#, C++, Clojure, JavaScript, Python, Groovy, JRuby, and others&quot; data-og-host=&quot;reactivex.io&quot; data-og-source-url=&quot;http://reactivex.io/&quot; data-og-url=&quot;http://reactivex.io/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;http://reactivex.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://reactivex.io/&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;&gt;ReactiveX&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;CROSS-PLATFORM Available for idiomatic Java, Scala, C#, C++, Clojure, JavaScript, Python, Groovy, JRuby, and others&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;reactivex.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1583588114899&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Introduction&quot; data-og-description=&quot; &quot; data-og-host=&quot;www.learnrxjs.io&quot; data-og-source-url=&quot;https://www.learnrxjs.io/&quot; data-og-url=&quot;https://www.learnrxjs.io/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cj8x9i/hyFdmVcLhM/7JGUXJH5uVrdSKyIJ2GyK0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.learnrxjs.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.learnrxjs.io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cj8x9i/hyFdmVcLhM/7JGUXJH5uVrdSKyIJ2GyK0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Introduction&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.learnrxjs.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1583588116682&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;RxJS 간단정리&quot; data-og-description=&quot;RxJS의 개념을 간단하게 정리한다.&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@pks2974/rxjs-%EA%B0%84%EB%8B%A8%EC%A0%95%EB%A6%AC-41f67c37e028&quot; data-og-url=&quot;https://medium.com/@pks2974/rxjs-%EA%B0%84%EB%8B%A8%EC%A0%95%EB%A6%AC-41f67c37e028&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://medium.com/@pks2974/rxjs-%EA%B0%84%EB%8B%A8%EC%A0%95%EB%A6%AC-41f67c37e028&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@pks2974/rxjs-%EA%B0%84%EB%8B%A8%EC%A0%95%EB%A6%AC-41f67c37e028&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;&gt;RxJS 간단정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;RxJS의 개념을 간단하게 정리한다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <category>react</category>
      <category>rx</category>
      <category>모나드</category>
      <category>자바스크립트</category>
      <category>함수형</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/71</guid>
      <comments>https://black7375.tistory.com/71#entry71comment</comments>
      <pubDate>Sat, 7 Mar 2020 22:36:33 +0900</pubDate>
    </item>
    <item>
      <title>Readable Font 설계 및 기획 PPT 공개</title>
      <link>https://black7375.tistory.com/70</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/67&quot;&gt;https://black7375.tistory.com/67&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1582113182887&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;BlaCk Void Zsh 설계 및 기획 문서 공개&quot; data-og-description=&quot;정말 오랜만에 쓰는 글이네요. 이 많은 내용을 임시저장 없이 2/3까지 써놨는데 이미지 편집기능에서 무한로딩 걸려서 처음부터 다시 씁니다. ㅠㅠ 오픈소스, 개발하고자 하면 온갖내용들을 참고하고 가격이나 제..&quot; data-og-host=&quot;black7375.tistory.com&quot; data-og-source-url=&quot;https://black7375.tistory.com/67&quot; data-og-url=&quot;https://black7375.tistory.com/67&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/oKqLw/hyEZG182pc/SIbFU2WZN9MAiczvt2xgzk/img.png?width=800&amp;amp;height=214&amp;amp;face=0_0_800_214,https://scrap.kakaocdn.net/dn/w2SO6/hyEZz21fQj/FcklGMMKDvVrARSCHJ7pj1/img.png?width=800&amp;amp;height=214&amp;amp;face=0_0_800_214,https://scrap.kakaocdn.net/dn/bDGjnM/hyEZKQ0hs4/jy7rb4NK50j7Ul3IWzFkq0/img.png?width=822&amp;amp;height=705&amp;amp;face=0_0_822_705&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/67&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tistory.com/67&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/oKqLw/hyEZG182pc/SIbFU2WZN9MAiczvt2xgzk/img.png?width=800&amp;amp;height=214&amp;amp;face=0_0_800_214,https://scrap.kakaocdn.net/dn/w2SO6/hyEZz21fQj/FcklGMMKDvVrARSCHJ7pj1/img.png?width=800&amp;amp;height=214&amp;amp;face=0_0_800_214,https://scrap.kakaocdn.net/dn/bDGjnM/hyEZKQ0hs4/jy7rb4NK50j7Ul3IWzFkq0/img.png?width=822&amp;amp;height=705&amp;amp;face=0_0_822_705');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;BlaCk Void Zsh 설계 및 기획 문서 공개&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;정말 오랜만에 쓰는 글이네요. 이 많은 내용을 임시저장 없이 2/3까지 써놨는데 이미지 편집기능에서 무한로딩 걸려서 처음부터 다시 씁니다. ㅠㅠ 오픈소스, 개발하고자 하면 온갖내용들을 참고하고 가격이나 제..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;black7375.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;에 이어 공개하는 기획글입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/black7375/Readable_Font&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/black7375/Readable_Font&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2018년 말에 만들었던 확장기능인데..&lt;/p&gt;
&lt;p&gt;이거 만들어본다고 자바스크립트를 처음 이용해봤기 때문에..&lt;/p&gt;
&lt;p&gt;코드는 딱히 도움안될겁니다.&lt;/p&gt;
&lt;p&gt;지금 보니 처음부터 다시 만들어야 될 것 같다는ㅋㅋㅋ&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그냥 순수한 기획용으로만 참고했으면.&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/dGYqAq/btqB8mZY1hw/LM21KzQRbgAKtTXRW6XGeK/ReadableFont.pdf?attach=1&amp;amp;knm=tfile.pdf&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;ReadableFont.pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;3.41MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;s&gt;교내 공모전에서 돈을 받기 위해 만들었던&lt;/s&gt;&amp;nbsp;PPT 파일 입니다.&lt;/p&gt;
&lt;p&gt;아래 글은 PPT에 대한 부연설명을 달아놓았습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;폰트 관련 확장기능이라 타이포그래피 위주로 디자인이 되어 있어요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-01.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bflXOe/btqB5Fz9nhA/6Kj81TbxKVLMjd2hk6X9MK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bflXOe/btqB5Fz9nhA/6Kj81TbxKVLMjd2hk6X9MK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bflXOe/btqB5Fz9nhA/6Kj81TbxKVLMjd2hk6X9MK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbflXOe%2FbtqB5Fz9nhA%2F6Kj81TbxKVLMjd2hk6X9MK%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-01.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-02.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/THxtA/btqB6JvkyWN/sJIZVg69CUecJ6Agz1TTxk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/THxtA/btqB6JvkyWN/sJIZVg69CUecJ6Agz1TTxk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/THxtA/btqB6JvkyWN/sJIZVg69CUecJ6Agz1TTxk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTHxtA%2FbtqB6JvkyWN%2FsJIZVg69CUecJ6Agz1TTxk%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-02.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;만들게된 동기는 우연히 크로미움 계열 브라우저를 써봤더니 파이어폭스에 Custom CSS를 적용한것과 렌더링 차이가 많이나서 였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-03.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0YyWO/btqB5GlzFmO/VAGZ5AkEA8UpyUJyk2ogS1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0YyWO/btqB5GlzFmO/VAGZ5AkEA8UpyUJyk2ogS1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0YyWO/btqB5GlzFmO/VAGZ5AkEA8UpyUJyk2ogS1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0YyWO%2FbtqB5GlzFmO%2FVAGZ5AkEA8UpyUJyk2ogS1%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-03.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;/p&gt;
&lt;p&gt;그래서 사람들이 많이쓰는 윈도우 기준으로 크롬, 엣지, 파이어폭스로 테스트 해보았답니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blYWTR/btqB5id8wAe/YLzQKLU3aKVPlsNUBXMsT1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blYWTR/btqB5id8wAe/YLzQKLU3aKVPlsNUBXMsT1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blYWTR/btqB5id8wAe/YLzQKLU3aKVPlsNUBXMsT1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblYWTR%2FbtqB5id8wAe%2FYLzQKLU3aKVPlsNUBXMsT1%2Fimg.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;/p&gt;
&lt;p&gt;이에 대해서는 뒷부분에서 확대 해보며 이야기해봅시다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;동일한 방식으로 렌더링을 확인해보았을 때 OS에서는 윈도우 &amp;lt; 리눅스 &amp;lt; 맥의 렌더링이 좋다는 것을 확인해볼 수 있었습니다.&lt;/p&gt;
&lt;p&gt;만약 윈도우 크롬을 맥의 파이어폭스처럼 보여줄 수 있다면 최고라 할 수 있겠습니다. ㅎㅎ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yOqoM/btqB8ojfwlh/3mjlMKru3BxgIKFC7Wq541/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yOqoM/btqB8ojfwlh/3mjlMKru3BxgIKFC7Wq541/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yOqoM/btqB8ojfwlh/3mjlMKru3BxgIKFC7Wq541/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyOqoM%2FbtqB8ojfwlh%2F3mjlMKru3BxgIKFC7Wq541%2Fimg.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;크롬의 글씨를 파이어폭스처럼 만들어볼 때 고려해볼 수 있는 것은 글씨를 '진하게' 만들어보는 겁니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그런데 폰트를 조금이라도 다루어본적이 있는 사람이라면 Office 같은 곳에서 제공하는 '진하게' 기능은 사용하지 않고 전용 Weight를 사용합니다.&lt;/p&gt;
&lt;p&gt;그 이유는 다음 그림에서 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-06.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pimvl/btqB8nklYLv/J3Z5sUi5YA8q32K5cFK4Uk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pimvl/btqB8nklYLv/J3Z5sUi5YA8q32K5cFK4Uk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pimvl/btqB8nklYLv/J3Z5sUi5YA8q32K5cFK4Uk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpimvl%2FbtqB8nklYLv%2FJ3Z5sUi5YA8q32K5cFK4Uk%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-06.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;조형적 문제(업 1번)가 생기거나, 띄어져야 할 곳이 붙어있는(업 2번, 짰 1, 2, 3번)등의 문제가 발생합니다.&lt;/p&gt;
&lt;p&gt;큰 글자라면 어색함이 덜하겠지만, 글씨가 작아지면 어색함과 가독성 문제가 속출하기 시작합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서 신중하게 설계된 폰트들의 굵기변화는 함부로 건들 것이 아니란 원칙을 세워볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhYQE9/btqB6idHivn/PlTMjX7nIL4OdUHkzzJKf1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhYQE9/btqB6idHivn/PlTMjX7nIL4OdUHkzzJKf1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhYQE9/btqB6idHivn/PlTMjX7nIL4OdUHkzzJKf1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhYQE9%2FbtqB6idHivn%2FPlTMjX7nIL4OdUHkzzJKf1%2Fimg.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;우선, 글씨의 굵기변화를 건들이지 않고 할 수 있는 작업은 2가지가 있습니다.&lt;/p&gt;
&lt;p&gt;바로 Kerning과 Ligature입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-08.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bauQat/btqB6ix016f/xlUjlABNjVKHykPGbep7U1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bauQat/btqB6ix016f/xlUjlABNjVKHykPGbep7U1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bauQat/btqB6ix016f/xlUjlABNjVKHykPGbep7U1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbauQat%2FbtqB6ix016f%2FxlUjlABNjVKHykPGbep7U1%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-08.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;Kerning은 글자사이의 &lt;b&gt;간격을 조정&lt;/b&gt;하여 가독성을 향상 시키는 것, Ligature은 합자를 만들어 가독성을 향상시키는 기법입니다. 보통 Ligature은 &lt;b&gt;글씨가 작아 뭉쳐보일때&lt;/b&gt; 합쳐서 가독성이 향상시키는 것이 유리하며 약 20pt아래일때 적용이 되는 것으로 알고 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;흠.. 그런데 글자를 아예 건들이면 안되는 걸까요?&lt;/p&gt;
&lt;p&gt;발표시간이 5분이라 못넣었던 이론들을 토대로 알아봅시다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;앞선 '작업' 중 '업'자 만 확대시켜보았습니다.&lt;/p&gt;
&lt;p&gt;'ㅇ'의 곡선, 'ㅂ'과 'ㅓ'의 직선을 조화롭게 확인할 수 있을 거라 생각합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dez7uJ/btqB8mMs50X/7y9sWyV96Jakx0k3XNu8M1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dez7uJ/btqB8mMs50X/7y9sWyV96Jakx0k3XNu8M1/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 33.2235%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dez7uJ/btqB8mMs50X/7y9sWyV96Jakx0k3XNu8M1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdez7uJ%2FbtqB8mMs50X%2F7y9sWyV96Jakx0k3XNu8M1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wq6wy/btqB6ZraWHy/VwRkMDZpsgTTy5K66q66h1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wq6wy/btqB6ZraWHy/VwRkMDZpsgTTy5K66q66h1/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 33.3874%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wq6wy/btqB6ZraWHy/VwRkMDZpsgTTy5K66q66h1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWq6wy%2FbtqB6ZraWHy%2FVwRkMDZpsgTTy5K66q66h1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUpJFX/btqB5g1Gfsf/CKKYGSmnRjNtXIoCJUgqxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUpJFX/btqB5g1Gfsf/CKKYGSmnRjNtXIoCJUgqxK/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 31.0635%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUpJFX/btqB5g1Gfsf/CKKYGSmnRjNtXIoCJUgqxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUpJFX%2FbtqB5g1Gfsf%2FCKKYGSmnRjNtXIoCJUgqxK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;파이어폭스의 글씨가 더 진한 것을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그렇다면 우리가 생각하는 '진하게'란 무엇을 뜻할까요?&amp;nbsp;&lt;/p&gt;
&lt;p&gt;각 'ㅓ'의 오른쪽 부분의 컬러코드[Hex, HSL]를 확인해보도록 합시다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;크롬: &lt;span style=&quot;background-color: #abe5ff;&quot;&gt;#ABE5FF&lt;/span&gt; | (141, 255, 213)&lt;/li&gt;
&lt;li&gt;엣지: &lt;span style=&quot;background-color: #9cdbff;&quot;&gt;#9CDBFF&lt;/span&gt; | (143, 255, 206)&lt;/li&gt;
&lt;li&gt;파폭: &lt;span style=&quot;background-color: #317fd3;&quot;&gt;#317FD3&lt;/span&gt; | (150, 165, 130)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;첫번째의 Hex는 RGB를 의미하고 많이 접하기 때문에 익숙합니다.&lt;/p&gt;
&lt;p&gt;두번째 HSL은 색상(Hue), 채도(Saturation), 명도(Luminance)로 이루어집니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/HSL_and_HSV&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://en.wikipedia.org/wiki/HSL_and_HSV&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1582115147066&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;HSL and HSV - Wikipedia&quot; data-og-description=&quot;From Wikipedia, the free encyclopedia Jump to navigation Jump to search Alternative representations of the RGB color model HSL (hue, saturation, lightness) and HSV (hue, saturation, value) are alternative representations of the RGB color model, designed in&quot; data-og-host=&quot;en.wikipedia.org&quot; data-og-source-url=&quot;https://en.wikipedia.org/wiki/HSL_and_HSV&quot; data-og-url=&quot;https://en.wikipedia.org/wiki/HSL_and_HSV&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QYg4c/hyEZCFsXLL/vpc23DtMkkCUIjkdOg3IH0/img.png?width=300&amp;amp;height=452&amp;amp;face=0_0_300_452&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/HSL_and_HSV&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://en.wikipedia.org/wiki/HSL_and_HSV&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QYg4c/hyEZCFsXLL/vpc23DtMkkCUIjkdOg3IH0/img.png?width=300&amp;amp;height=452&amp;amp;face=0_0_300_452');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;HSL and HSV - Wikipedia&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;From Wikipedia, the free encyclopedia Jump to navigation Jump to search Alternative representations of the RGB color model HSL (hue, saturation, lightness) and HSV (hue, saturation, value) are alternative representations of the RGB color model, designed in&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;en.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;전 사람이 색보다 밝기 변화에 민감하다는 점을 주목했습니다.&lt;/p&gt;
&lt;p&gt;배경이 하얀색일 경우 밝기가 낮을수록, 배경이 검은색일 경우 밝을수록 글자가 '선명'하게 여길 것이라는 거죠.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;원추&amp;nbsp;세포에서&amp;nbsp;만들어진&amp;nbsp;전기&amp;nbsp;신호들은&amp;nbsp;다시&amp;nbsp;밝고&amp;nbsp;어두운&amp;nbsp;정도를&amp;nbsp;나타내는&amp;nbsp;밝기(achromatic)&amp;nbsp;신호,&amp;nbsp;빨강-초록(redness-&amp;nbsp;greenness)&amp;nbsp;정도를&amp;nbsp;나타내는&amp;nbsp;신호,&amp;nbsp;노랑-파랑(yellowness-blueness)&amp;nbsp;정도를&amp;nbsp;나타&amp;nbsp;내는&amp;nbsp;신호&amp;nbsp;이렇게&amp;nbsp;세&amp;nbsp;가지의&amp;nbsp;대응색&amp;nbsp;신호(Opponent-&amp;nbsp;signal)로&amp;nbsp;바뀐다.&amp;nbsp;대응색&amp;nbsp;신호들&amp;nbsp;중&amp;nbsp;&lt;b&gt;밝기(achromatic)&amp;nbsp;신호는&amp;nbsp;가장&amp;nbsp;공간해상도가&amp;nbsp;높고&lt;/b&gt;&amp;nbsp;노랑-파랑&amp;nbsp;정보들의&amp;nbsp;공간해상도는&amp;nbsp;가장&amp;nbsp;낮다.&amp;nbsp;즉&amp;nbsp;노랑-파랑&amp;nbsp;&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;/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;lsquo;색&amp;rsquo;으로&amp;nbsp;인지되게&amp;nbsp;된다.&lt;/blockquote&gt;
&lt;figure id=&quot;og_1582116795255&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;사람이 보는 색을 기계로 측정한다 | 과학포털 사이언스올&quot; data-og-description=&quot;사람이 보는 색을 기계로 측정한다 10월 06, 2014 곽영신 부교수|UNIST 디자인 및 인간공학부 스마트폰을 이용해 사진을 찍을 때 화면에 보이는 색과 실제 색이 달라보였던 적은 있지 않았나? 백화점이나 대형 마트의 전자제품 코너에서 TV들이 화려한 색감을 자랑하는 동영상들을 보여주고 있을 때 왜 동일한 동영상인데 화면마다 이렇게 색깔이 다르게 보일까 하고 궁금했던 적은? 아니면 인터넷 쇼핑이나 홈 쇼핑을 통해 색이 마음에 들어 옷을 구입 했는데 실&quot; data-og-host=&quot;www.scienceall.com&quot; data-og-source-url=&quot;https://www.scienceall.com/%EA%B3%BC%ED%95%99%EA%B3%BC-%EC%9D%B8%EB%AC%B8%EC%98%88%EC%88%A0-%E2%91%A0-%EC%82%AC%EB%9E%8C%EC%9D%B4-%EB%B3%B4%EB%8A%94-%EC%83%89%EC%9D%84-%EA%B8%B0%EA%B3%84%EB%A1%9C-%EC%B8%A1%EC%A0%95%ED%95%9C/&quot; data-og-url=&quot;https://www.scienceall.com/%EA%B3%BC%ED%95%99%EA%B3%BC-%EC%9D%B8%EB%AC%B8%EC%98%88%EC%88%A0-%E2%91%A0-%EC%82%AC%EB%9E%8C%EC%9D%B4-%EB%B3%B4%EB%8A%94-%EC%83%89%EC%9D%84-%EA%B8%B0%EA%B3%84%EB%A1%9C-%EC%B8%A1%EC%A0%95%ED%95%9C/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bnXdgr/hyEZHfLgYk/SHMdkzrF3NBhSUH8us7yIk/img.png?width=1299&amp;amp;height=436&amp;amp;face=0_0_1299_436,https://scrap.kakaocdn.net/dn/ba3py9/hyEZIlqO6V/SmmQzgN6tANMrfLt5aTbe1/img.png?width=495&amp;amp;height=558&amp;amp;face=0_0_495_558,https://scrap.kakaocdn.net/dn/brJXqD/hyEZMai4R1/huMf3X0xE98pbRJjHexfZK/img.png?width=520&amp;amp;height=321&amp;amp;face=0_0_520_321&quot;&gt;&lt;a href=&quot;https://www.scienceall.com/%EA%B3%BC%ED%95%99%EA%B3%BC-%EC%9D%B8%EB%AC%B8%EC%98%88%EC%88%A0-%E2%91%A0-%EC%82%AC%EB%9E%8C%EC%9D%B4-%EB%B3%B4%EB%8A%94-%EC%83%89%EC%9D%84-%EA%B8%B0%EA%B3%84%EB%A1%9C-%EC%B8%A1%EC%A0%95%ED%95%9C/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.scienceall.com/%EA%B3%BC%ED%95%99%EA%B3%BC-%EC%9D%B8%EB%AC%B8%EC%98%88%EC%88%A0-%E2%91%A0-%EC%82%AC%EB%9E%8C%EC%9D%B4-%EB%B3%B4%EB%8A%94-%EC%83%89%EC%9D%84-%EA%B8%B0%EA%B3%84%EB%A1%9C-%EC%B8%A1%EC%A0%95%ED%95%9C/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bnXdgr/hyEZHfLgYk/SHMdkzrF3NBhSUH8us7yIk/img.png?width=1299&amp;amp;height=436&amp;amp;face=0_0_1299_436,https://scrap.kakaocdn.net/dn/ba3py9/hyEZIlqO6V/SmmQzgN6tANMrfLt5aTbe1/img.png?width=495&amp;amp;height=558&amp;amp;face=0_0_495_558,https://scrap.kakaocdn.net/dn/brJXqD/hyEZMai4R1/huMf3X0xE98pbRJjHexfZK/img.png?width=520&amp;amp;height=321&amp;amp;face=0_0_520_321');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;사람이 보는 색을 기계로 측정한다 | 과학포털 사이언스올&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;사람이 보는 색을 기계로 측정한다 10월 06, 2014 곽영신 부교수|UNIST 디자인 및 인간공학부 스마트폰을 이용해 사진을 찍을 때 화면에 보이는 색과 실제 색이 달라보였던 적은 있지 않았나? 백화점이나 대형 마트의 전자제품 코너에서 TV들이 화려한 색감을 자랑하는 동영상들을 보여주고 있을 때 왜 동일한 동영상인데 화면마다 이렇게 색깔이 다르게 보일까 하고 궁금했던 적은? 아니면 인터넷 쇼핑이나 홈 쇼핑을 통해 색이 마음에 들어 옷을 구입 했는데 실&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.scienceall.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;또한 가장자리의 밝기는 커다란 영향을 미치기도 합니다.&lt;/p&gt;
&lt;p&gt;방송자막이나 유튜브들 썸네일 글씨들의 가장자리 처리를 확인해보도록 합시다.&lt;/p&gt;
&lt;p&gt;밝기 변화를 확실히 주어 돋보이게 만든 것이 보일꺼에요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4315842/&quot;&gt;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4315842/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1582117795969&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Brightness&amp;ndash;Color Interactions in Human Early Visual Cortex&quot; data-og-description=&quot;The interaction between brightness and color causes there to be different color appearance when one and the same object is viewed against surroundings of different brightness. Brightness contrast causes color to be desaturated, as has been found in percept&quot; data-og-host=&quot;www.ncbi.nlm.nih.gov&quot; data-og-source-url=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4315842/&quot; data-og-url=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4315842/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bigRdV/hyEZIMvhEh/TOcuRa5S7v8qclSRff0Dy1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4315842/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4315842/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bigRdV/hyEZIMvhEh/TOcuRa5S7v8qclSRff0Dy1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Brightness&amp;ndash;Color Interactions in Human Early Visual Cortex&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;The interaction between brightness and color causes there to be different color appearance when one and the same object is viewed against surroundings of different brightness. Brightness contrast causes color to be desaturated, as has been found in percept&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.ncbi.nlm.nih.gov&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&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&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;특히 밝은 영역보다 어두운 영역에서의 밝기 차이를 더 민감하게 여기므로 다크모드에서 효용이 커질것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://ledshield.files.wordpress.com/2012/11/brightness_perception.png?w=604&amp;amp;amp;h=349 604w, https://ledshield.files.wordpress.com/2012/11/brightness_perception.png?w=150&amp;amp;amp;h=87 150w, https://ledshield.files.wordpress.com/2012/11/brightness_perception.png?w=300&amp;amp;amp;h=174 300w, https://ledshield.files.wordpress.com/2012/11/brightness_perception.png 608w&quot; width=&quot;604&quot; height=&quot;349&quot; data-attachment-id=&quot;530&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;509&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nxeik/btqB5hsKIrK/VIeJBnaBaMowQyTYRk3IZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nxeik/btqB5hsKIrK/VIeJBnaBaMowQyTYRk3IZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nxeik/btqB5hsKIrK/VIeJBnaBaMowQyTYRk3IZk/img.png&quot; srcset=&quot;https://ledshield.files.wordpress.com/2012/11/brightness_perception.png?w=604&amp;amp;h=349 604w, https://ledshield.files.wordpress.com/2012/11/brightness_perception.png?w=150&amp;amp;h=87 150w, https://ledshield.files.wordpress.com/2012/11/brightness_perception.png?w=300&amp;amp;h=174 300w, https://ledshield.files.wordpress.com/2012/11/brightness_perception.png 608w&quot; width=&quot;604&quot; height=&quot;349&quot; data-attachment-id=&quot;530&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;509&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://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;'가장자리 처리'라 하면 우리 컴공인들은 당연히 떠오르는 기술이 있습니다.&lt;/p&gt;
&lt;p&gt;바로 안티얼라이싱(Antialiasing)!!&lt;/p&gt;
&lt;p&gt;안티얼라이싱은 글씨를 부드럽고 매끄럽게 만들어주죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-09.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coLuzH/btqB8ndA39b/7JJ8wJLgeFkqilIAxn2tz1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coLuzH/btqB8ndA39b/7JJ8wJLgeFkqilIAxn2tz1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coLuzH/btqB8ndA39b/7JJ8wJLgeFkqilIAxn2tz1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoLuzH%2FbtqB8ndA39b%2F7JJ8wJLgeFkqilIAxn2tz1%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-09.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그런데 글씨에 사용하는 안티얼라이싱 기술은 크게 2가지로 나눠볼 수 있습니다.&lt;/p&gt;
&lt;p&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;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Font_rasterization&quot;&gt;https://en.wikipedia.org/wiki/Font_rasterization&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1582120366330&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Font rasterization - Wikipedia&quot; data-og-description=&quot;Font rasterization is the process of converting text from a vector description (as found in scalable fonts such as TrueType fonts) to a raster or bitmap description. This often involves some anti-aliasing on screen text to make it smoother and easier to re&quot; data-og-host=&quot;en.wikipedia.org&quot; data-og-source-url=&quot;https://en.wikipedia.org/wiki/Font_rasterization&quot; data-og-url=&quot;https://en.wikipedia.org/wiki/Font_rasterization&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Font_rasterization&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://en.wikipedia.org/wiki/Font_rasterization&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;&gt;Font rasterization - Wikipedia&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Font rasterization is the process of converting text from a vector description (as found in scalable fonts such as TrueType fonts) to a raster or bitmap description. This often involves some anti-aliasing on screen text to make it smoother and easier to re&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;en.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;저는 요즘 디스플레이들의 특성상 Grayscale을 기본값으로 적용했습니다.&lt;/p&gt;
&lt;p&gt;단, 옵션으로 서브픽셀렌더링을 적용하도록 나두었습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그러나 문제가 한가지 있습니다.&lt;/p&gt;
&lt;p&gt;다음은 미적용, 그레이스케일, 서브픽셀 렌더링의 모습입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byIpha/btqB7cjw4ys/imcWV3BuTii14jhNXFdRNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byIpha/btqB7cjw4ys/imcWV3BuTii14jhNXFdRNK/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byIpha/btqB7cjw4ys/imcWV3BuTii14jhNXFdRNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyIpha%2FbtqB7cjw4ys%2FimcWV3BuTii14jhNXFdRNK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5jjTa/btqB7OvX68w/1jkhSNT7CNgV7KjqP4545k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5jjTa/btqB7OvX68w/1jkhSNT7CNgV7KjqP4545k/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5jjTa/btqB7OvX68w/1jkhSNT7CNgV7KjqP4545k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5jjTa%2FbtqB7OvX68w%2F1jkhSNT7CNgV7KjqP4545k%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qc3Xy/btqB7OW3jDW/N3i9nvfNYwuyrG5R9WLT6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qc3Xy/btqB7OW3jDW/N3i9nvfNYwuyrG5R9WLT6k/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 32.5581%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qc3Xy/btqB7OW3jDW/N3i9nvfNYwuyrG5R9WLT6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQc3Xy%2FbtqB7OW3jDW%2FN3i9nvfNYwuyrG5R9WLT6k%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;보다시피 부드러워지고 원형에 가까운 형태를 보여주기는 하나 '진하게', '선명하게'와는 거리가 생긴다는 거죠.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;border&quot;&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;힌팅에 대해서&lt;/p&gt;
&lt;p&gt;위키피디아를 보면 힌팅에 관련된 이야기가 나오기도 하는데 대부분의 폰트에 이미 힌팅정보가 포함되어 있으므로 건들일 필요가 없습니다.&lt;/p&gt;
&lt;p&gt;하지만 혹여나 힌팅이 필요하다면 아래 링크를 참고해보세요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.freetype.org/ttfautohint/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.freetype.org/ttfautohint/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1582122132163&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ttfautohint&quot; data-og-description=&quot;&quot; data-og-host=&quot;www.freetype.org&quot; data-og-source-url=&quot;https://www.freetype.org/ttfautohint/&quot; data-og-url=&quot;https://www.freetype.org/ttfautohint/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.freetype.org/ttfautohint/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.freetype.org/ttfautohint/&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;&gt;ttfautohint&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.freetype.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서 저는 안티얼라이싱을 보완하는 작업을 실행했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-10.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbs7Sc/btqB7PIpFNO/Qyk6YvVW4nP4qQkuHGJkiK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbs7Sc/btqB7PIpFNO/Qyk6YvVW4nP4qQkuHGJkiK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbs7Sc/btqB7PIpFNO/Qyk6YvVW4nP4qQkuHGJkiK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbs7Sc%2FbtqB7PIpFNO%2FQyk6YvVW4nP4qQkuHGJkiK%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-10.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;/p&gt;
&lt;p&gt;그래서 그림자와 스트로크의 약한 변화를 주어 가장자리 픽셀이 진하게 보이게 만들었습니다.&lt;/p&gt;
&lt;p&gt;그림자의 색은 중성적인 회색(&lt;span style=&quot;background-color: #acacac;&quot;&gt;#ACACAC&lt;/span&gt;)을 채택하여 배경이 밝으나 어두우나 큰 영향이 미치지 않도록 했습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;자, 이제 결과를 보도록 합시다.&lt;/p&gt;
&lt;p&gt;순정에 아주 약한 튜닝을 가해 원본을 해치지 않으면서도 나아졌다는 것이 느껴지십니까?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kCqIz/btqB6Ja6bh1/eOFKvnY7dAoHecRkW9sujk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kCqIz/btqB6Ja6bh1/eOFKvnY7dAoHecRkW9sujk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kCqIz/btqB6Ja6bh1/eOFKvnY7dAoHecRkW9sujk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkCqIz%2FbtqB6Ja6bh1%2FeOFKvnY7dAoHecRkW9sujk%2Fimg.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아까처럼 글씨를 확대시켜봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-12.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYCLkW/btqB5GlDrtw/XiPjEKPepd8ctqaWf4hXq1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYCLkW/btqB5GlDrtw/XiPjEKPepd8ctqaWf4hXq1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYCLkW/btqB5GlDrtw/XiPjEKPepd8ctqaWf4hXq1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYCLkW%2FbtqB5GlDrtw%2FXiPjEKPepd8ctqaWf4hXq1%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-12.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;/p&gt;
&lt;p&gt;생김새는 같지만 색이 훨씬 진해졌다는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCiost/btqB6Jvom3Q/9piygRIdWvsWymTkrLz6LK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCiost/btqB6Jvom3Q/9piygRIdWvsWymTkrLz6LK/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 50.491%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCiost/btqB6Jvom3Q/9piygRIdWvsWymTkrLz6LK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCiost%2FbtqB6Jvom3Q%2F9piygRIdWvsWymTkrLz6LK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eqAV96/btqB6h6X2BU/kWqGySTHTc1GvUjSK3EzF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eqAV96/btqB6h6X2BU/kWqGySTHTc1GvUjSK3EzF1/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 48.3462%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eqAV96/btqB6h6X2BU/kWqGySTHTc1GvUjSK3EzF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeqAV96%2FbtqB6h6X2BU%2FkWqGySTHTc1GvUjSK3EzF1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;기존&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;크롬:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #abe5ff;&quot;&gt;#ABE5FF&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;| (141, 255, 213)&lt;/li&gt;
&lt;li&gt;엣지:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #9cdbff;&quot;&gt;#9CDBFF&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;| (143, 255, 206)&lt;/li&gt;
&lt;li&gt;파폭:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #317fd3;&quot;&gt;#317FD3&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;| (150, 165, 130)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;적용&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;크롬: &lt;span style=&quot;background-color: #84d1ff;&quot;&gt;#84D1FF&lt;/span&gt; | (143, 255, 193)&lt;/p&gt;
&lt;p&gt;파폭: &lt;span style=&quot;background-color: #939393;&quot;&gt;#939393&lt;/span&gt; | (0, 0, 147)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;발표에서 프리젠터로는 색차이를 비교하기 힘들기 때문에 같다고 해놨지만,&lt;/p&gt;
&lt;p&gt;수치적으로 비교해보았을 때, 크롬이 원래 엣지보다 근소하게 낫다는 것 또한 확인해볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;단, 정확히 그레이스케일로 렌더링이 되는 것은 파이어폭스 뿐이었네요.&lt;/p&gt;
&lt;p&gt;덕분에 향상폭이 가장 컸습니다. (대신 윈도우에서 맥느낌을 낼 수 있어졌죠)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;연속된 글로 비교해보면 효과적으로 느껴질 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pOOR0/btqB5hTTxzw/6BBhvSyt0KMHfMPMI96xuk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pOOR0/btqB5hTTxzw/6BBhvSyt0KMHfMPMI96xuk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pOOR0/btqB5hTTxzw/6BBhvSyt0KMHfMPMI96xuk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpOOR0%2FbtqB5hTTxzw%2F6BBhvSyt0KMHfMPMI96xuk%2Fimg.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음으로 생각이 났던건 바로 폰트 종류였습니다.&lt;/p&gt;
&lt;p&gt;한국 인터넷을 돌아다니다보면 굴림체가 많이 보입니다.&lt;/p&gt;
&lt;p&gt;그리고 굴림체, Comic Sans같은 폰트는 썩그리 좋은 글꼴이 아닙니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-14.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EBXsK/btqB6YsmUHf/DjcBxZfwkfqaIy8gyeQ3n1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EBXsK/btqB6YsmUHf/DjcBxZfwkfqaIy8gyeQ3n1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EBXsK/btqB6YsmUHf/DjcBxZfwkfqaIy8gyeQ3n1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEBXsK%2FbtqB6YsmUHf%2FDjcBxZfwkfqaIy8gyeQ3n1%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-14.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-15.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dc0QMH/btqB8PAY2kp/ybrKfMt8HGDKjyhTtbtjM0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dc0QMH/btqB8PAY2kp/ybrKfMt8HGDKjyhTtbtjM0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dc0QMH/btqB8PAY2kp/ybrKfMt8HGDKjyhTtbtjM0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdc0QMH%2FbtqB8PAY2kp%2FybrKfMt8HGDKjyhTtbtjM0%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-15.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이외에 윈도우즈의 굴림, 돋움, 바탕등을 애용하는 사이트들이 많습니다.&lt;/p&gt;
&lt;p&gt;대표적인게 네이버, 다음카페, DC 인사이드, MBL Park, 더쿠, 인벤 등등.&lt;/p&gt;
&lt;p&gt;나름 유명한 사이트들이 품질이 좋지 않은 폰트들을 애용하고 있었습니다.(2018년 말 기준)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-16.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blz41o/btqB6XGYTFI/f38ctGOo2nKyGVh6PI5Dsk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blz41o/btqB6XGYTFI/f38ctGOo2nKyGVh6PI5Dsk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blz41o/btqB6XGYTFI/f38ctGOo2nKyGVh6PI5Dsk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fblz41o%2FbtqB6XGYTFI%2Ff38ctGOo2nKyGVh6PI5Dsk%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-16.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;우리의 목표는 총 2개.&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;br /&gt;특히 리눅스의 경우 오픈소스 프로젝트다보니 상용 폰트가 없어 다른 운영체제와 매우 다른 글꼴을 보여주기도 하기에 넣게 되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-17.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DDrms/btqB6XGYTKs/Hp29lV7ZhfNftzFbitLSM1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DDrms/btqB6XGYTKs/Hp29lV7ZhfNftzFbitLSM1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DDrms/btqB6XGYTKs/Hp29lV7ZhfNftzFbitLSM1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDDrms%2FbtqB6XGYTKs%2FHp29lV7ZhfNftzFbitLSM1%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-17.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서 다음과 같이 리스트를 작성할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-18.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qfsxM/btqB7PBGJCP/vSXkCj4TZS7wVBpsRXE1g1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qfsxM/btqB7PBGJCP/vSXkCj4TZS7wVBpsRXE1g1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qfsxM/btqB7PBGJCP/vSXkCj4TZS7wVBpsRXE1g1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqfsxM%2FbtqB7PBGJCP%2FvSXkCj4TZS7wVBpsRXE1g1%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-18.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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-filename=&quot;ReadableFont - 복사본-19.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzN9tI/btqB8QNrf5W/M1LSVuJTYBRkNEpVEL72MK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzN9tI/btqB8QNrf5W/M1LSVuJTYBRkNEpVEL72MK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzN9tI/btqB8QNrf5W/M1LSVuJTYBRkNEpVEL72MK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzN9tI%2FbtqB8QNrf5W%2FM1LSVuJTYBRkNEpVEL72MK%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-19.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그런데 문제는 44개(패밀리를 따로 따로 계산)나 되는 폰트를 내장하려다보니 350MB가 넘는 흉악한 용량을 자랑하게 되었습니다.&lt;/p&gt;
&lt;p&gt;따라서 용량을 줄여야 했습니다.&lt;/p&gt;
&lt;p&gt;제작할 확장기능은 모던 브라우저용이라 woff2 포맷을 지원하여 압축율이 높은 woff2 포맷을 채택하였고, 폰트 서브셋을 통해 약 25배까지 용량을 낮출 수 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-20.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBpdT2/btqB5EH6TEd/09VEDUfrItOZ51kuK7KTL0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBpdT2/btqB5EH6TEd/09VEDUfrItOZ51kuK7KTL0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBpdT2/btqB5EH6TEd/09VEDUfrItOZ51kuK7KTL0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBpdT2%2FbtqB5EH6TEd%2F09VEDUfrItOZ51kuK7KTL0%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-20.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-21.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EgziJ/btqB7a683Ga/i6FIp1tbKzHHsxq7afZB31/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EgziJ/btqB7a683Ga/i6FIp1tbKzHHsxq7afZB31/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EgziJ/btqB7a683Ga/i6FIp1tbKzHHsxq7afZB31/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEgziJ%2FbtqB7a683Ga%2Fi6FIp1tbKzHHsxq7afZB31%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-21.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-22.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lVhCa/btqB6X1iwSS/DcAkikBk1uVpGw9OwFYKmK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lVhCa/btqB6X1iwSS/DcAkikBk1uVpGw9OwFYKmK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lVhCa/btqB6X1iwSS/DcAkikBk1uVpGw9OwFYKmK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlVhCa%2FbtqB6X1iwSS%2FDcAkikBk1uVpGw9OwFYKmK%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-22.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;당시에 마지막으로 넣었던 기능인 수식표현입니다.&lt;/p&gt;
&lt;p&gt;크롬은 MathML을 지원하지 않아 수식이 풀어져보입니다.&lt;/p&gt;
&lt;p&gt;반면 파이어폭스는 제대로 보이죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-23.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y3UPh/btqB6JCdk8G/LVj65eymcFuktgDJ3G7DI1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y3UPh/btqB6JCdk8G/LVj65eymcFuktgDJ3G7DI1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y3UPh/btqB6JCdk8G/LVj65eymcFuktgDJ3G7DI1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy3UPh%2FbtqB6JCdk8G%2FLVj65eymcFuktgDJ3G7DI1%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-23.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;알고보니 파이어폭스와 사파리만 지원하는 브라우저였고, 제가 이 둘만 써왔기 때문에 몰랐던 것이었습니다..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-24.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZW2Eb/btqB6YeRcfV/kNoxvv5EHmpVrslmfKsIUk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZW2Eb/btqB6YeRcfV/kNoxvv5EHmpVrslmfKsIUk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZW2Eb/btqB6YeRcfV/kNoxvv5EHmpVrslmfKsIUk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZW2Eb%2FbtqB6YeRcfV%2FkNoxvv5EHmpVrslmfKsIUk%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-24.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그래서 수식표현을 강화할 방법을 찾았습니다.&lt;/p&gt;
&lt;p&gt;첫번째는 크롬을 위해 MathML이 있으면 MathJax 라이브러리를 동적으로 로드.&lt;/p&gt;
&lt;p&gt;두번째는 파이어폭스를 위해 STIX란 수식용 폰트를 내장하는 것.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-25.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVPYgR/btqB6XtqCTz/OM0B5U6W8MdbTyE4mJjbS1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVPYgR/btqB6XtqCTz/OM0B5U6W8MdbTyE4mJjbS1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVPYgR/btqB6XtqCTz/OM0B5U6W8MdbTyE4mJjbS1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVPYgR%2FbtqB6XtqCTz%2FOM0B5U6W8MdbTyE4mJjbS1%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-25.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이를 적용하면 크롬에서도 잘 보이는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-26.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwA2nJ/btqB7cjAAIy/M1RqxUPbpeWR6mi7hdyZT1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwA2nJ/btqB7cjAAIy/M1RqxUPbpeWR6mi7hdyZT1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwA2nJ/btqB7cjAAIy/M1RqxUPbpeWR6mi7hdyZT1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwA2nJ%2FbtqB7cjAAIy%2FM1RqxUPbpeWR6mi7hdyZT1%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-26.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;마지막으로 디자인인데 ㅋㅋㅋ&lt;/p&gt;
&lt;p&gt;심사하는 사람들도 공돌이라 디자인은 잘 모르고 저도 잘 모르기 때문에&lt;/p&gt;
&lt;p&gt;아무말이나 넣었습니다.&lt;/p&gt;
&lt;p&gt;&lt;s&gt;선명하게 글씨가 삐뚤어진거 불-편해져랐!!&lt;/s&gt; 원본 PPT파일이 날라가서 못고치는거 양해부탁드립니다.(포함된 폰트들 때문에 용량이 너무 커서 그런지 백업이 제대로 안되었었던..)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-27.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/spdDb/btqB7bSzf9n/BdSvobLtouJFKlu0eVKfW0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/spdDb/btqB7bSzf9n/BdSvobLtouJFKlu0eVKfW0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/spdDb/btqB7bSzf9n/BdSvobLtouJFKlu0eVKfW0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FspdDb%2FbtqB7bSzf9n%2FBdSvobLtouJFKlu0eVKfW0%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-27.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;span style=&quot;color: #333333;&quot;&gt;가장 어려웠던 것은 '선명하게', '글꼴치환', '수식표현'처럼 글자수를 맞추면서 의도한 바를 전달하는 표현을 찾는 것.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;만든지 약 10개월정도 쯤 교내 대회가 열려서&lt;/p&gt;
&lt;p&gt;확인을 해봤더니 생각보다 많은 분들이 쓰셨더군요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-28.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m1tw8/btqB8QzVwG8/EuCYAsXENk6dfx4vmPS9LK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m1tw8/btqB8QzVwG8/EuCYAsXENk6dfx4vmPS9LK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m1tw8/btqB8QzVwG8/EuCYAsXENk6dfx4vmPS9LK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm1tw8%2FbtqB8QzVwG8%2FEuCYAsXENk6dfx4vmPS9LK%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-28.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-29.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxvz40/btqB5F8bPXe/RqTYIHJjypnncobjPYwYkK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxvz40/btqB5F8bPXe/RqTYIHJjypnncobjPYwYkK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxvz40/btqB5F8bPXe/RqTYIHJjypnncobjPYwYkK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxvz40%2FbtqB5F8bPXe%2FRqTYIHJjypnncobjPYwYkK%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-29.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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-filename=&quot;ReadableFont - 복사본-30.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/daZ5Lb/btqB797KyzV/e4I6lPYE2OUUQbQN9KQ7QK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/daZ5Lb/btqB797KyzV/e4I6lPYE2OUUQbQN9KQ7QK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/daZ5Lb/btqB797KyzV/e4I6lPYE2OUUQbQN9KQ7QK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdaZ5Lb%2FbtqB797KyzV%2Fe4I6lPYE2OUUQbQN9KQ7QK%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-30.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;파워포인트 인공지능이 만들어준 이미지인데 의외로 이뻐서&lt;/p&gt;
&lt;p&gt;그냥 마지막으로 넣어본것.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ReadableFont - 복사본-31.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZDlXL/btqB8QzVwLv/nA0krkHD0PkuTkzG1yXMBK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZDlXL/btqB8QzVwLv/nA0krkHD0PkuTkzG1yXMBK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZDlXL/btqB8QzVwLv/nA0krkHD0PkuTkzG1yXMBK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZDlXL%2FbtqB8QzVwLv%2FnA0krkHD0PkuTkzG1yXMBK%2Fimg.jpg&quot; data-filename=&quot;ReadableFont - 복사본-31.jpg&quot; data-origin-width=&quot;2667&quot; data-origin-height=&quot;1500&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;</description>
      <category>IT/UX</category>
      <category>font</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/70</guid>
      <comments>https://black7375.tistory.com/70#entry70comment</comments>
      <pubDate>Wed, 19 Feb 2020 21:44:36 +0900</pubDate>
    </item>
    <item>
      <title>간단한 모나드 설명과 예제</title>
      <link>https://black7375.tistory.com/69</link>
      <description>&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;리엑트 네이티브 스터디 때문에 시작한 글이었는데 생각보다 길어져서 분리하게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;자바스크립트 관련 코드는 해당 스터디쪽 문서에 올릴 예정.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;역시 모나드를 이해할때는 Haskell이 가장 효율적이므로 Haskell로 된 코드를 사용해보자.&lt;/p&gt;
&lt;p&gt;자바스크립트로도 설명할 수 있지만(모나드 섹션 하단의 링크 참조) 이해하기에 코드가 깔끔하진 않다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하스켈의 간단한 입출력 예제다.&lt;/p&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;main = do
    putStrLn  &quot;Input: &quot;
    x &amp;lt;- getLine
    putStrLn (&quot;The Input was &quot; ++ x)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;모나드가 적용되어 있지만 그리 어렵진 않다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;모나드의 정의&lt;/h2&gt;
&lt;p&gt;그럼 차근차근 모나드에 대해 알아보도록 하자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;모나드의 조건은 람다대수 BNF처럼 간단하다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;타입 생성자 &lt;code&gt;M&lt;/code&gt;&lt;br /&gt;원래 하스켈에서는 &lt;code&gt;m&lt;/code&gt;라고 표시하지만 가독성을 위해 &lt;code&gt;M&lt;/code&gt; 이라 표시했다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;return&lt;/code&gt; 함수&lt;/li&gt;
&lt;li&gt;바인드(bind) 연산자 &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;타입 생성자 &lt;code&gt;M&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;타입 생성자는 C++의 &lt;code&gt;templete&lt;/code&gt; 와 유사하여 다른 타입을 인자로 받는다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;완전히 같진 않지만 아래와 같이 대응된다고 생각하면 된다.&lt;/p&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;-- Haskell
myFunc :: Int -&amp;gt; Int
data MyData t = MyData t             -- 형태: * -&amp;gt; *
data MyData t1 t2 = MyData t1 t2     -- 형태: * -&amp;gt; * -&amp;gt; *
data MyData tmpl = MyData (tmpl Int) -- 형태: (* -&amp;gt; *) -&amp;gt; *&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;c++ cpp arduino&quot; data-ke-language=&quot;c++&quot;&gt;&lt;code&gt;// C++
int myFunc(int a);
template &amp;lt;typename t&amp;gt; class MyData;
template &amp;lt;typename t1, typename t2&amp;gt; class MyData;
template &amp;lt;template &amp;lt;typename t&amp;gt; class tmpl&amp;gt; class MyData;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;return&lt;/code&gt; 함수&lt;/h3&gt;
&lt;p&gt;하나 주의할 것이 있다면 &lt;code&gt;return&lt;/code&gt;의 의미가 살짝 다르다.&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;return :: a -&amp;gt; M a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;return&lt;/code&gt; 함수는 타입 &lt;code&gt;a&lt;/code&gt;를 받아 &lt;code&gt;M&amp;lt;a&amp;gt;&lt;/code&gt;방식으로 반환해주는 것이기 때문이다.&lt;/p&gt;
&lt;p&gt;그냥 타입 생성자로 감싸주는 것이라 생각하자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;바인드(bind) 연산자&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;gt;&amp;gt;=&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;176&quot; data-origin-height=&quot;194&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5uzq4/btqBXV9TQfy/tJwdvJ6v9fH35ElkOSKagK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5uzq4/btqBXV9TQfy/tJwdvJ6v9fH35ElkOSKagK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5uzq4/btqBXV9TQfy/tJwdvJ6v9fH35ElkOSKagK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5uzq4%2FbtqBXV9TQfy%2FtJwdvJ6v9fH35ElkOSKagK%2Fimg.png&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;176&quot; data-origin-height=&quot;194&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;pre class=&quot;livescript&quot;&gt;&lt;code&gt;(&amp;gt;&amp;gt;=):: M a -&amp;gt; (a -&amp;gt; M b) -&amp;gt; M b&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;는&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M&amp;lt;a&amp;gt;&lt;/code&gt;타입의 생성자가 있을 때.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt; 타입의 값을 받고, &lt;code&gt;M&amp;lt;b&amp;gt;&lt;/code&gt;타입을 반환하는 함수를 받아&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M&amp;lt;b&amp;gt;&lt;/code&gt;타입의 값을 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;바인드 연산자를 사용하면 서로 다른 타입인 &lt;code&gt;a&lt;/code&gt; 와 &lt;code&gt;b&lt;/code&gt;를 &lt;b&gt;결합&lt;/b&gt;할 수 있게 만들어 주는 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;모나드, 바인드 연산자 그리고 순수함수&lt;/h3&gt;
&lt;p&gt;그렇다면 도대체 어떻게 모나드를 이용하면 부작용(Side Effect)가 없는 함수, 즉 순수함수를 만들 수 있다는 것인가?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;답은 간단하다.&lt;/p&gt;
&lt;p&gt;외부 상태를 인수로 전달하고, 결과로 상태값을 반환하면 된다.&lt;/p&gt;
&lt;p&gt;흔히 볼 수 있는 순수함수의 설명이랄까?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이제 모나드를 이용하여 간단한 예를 들어보자.&lt;/p&gt;
&lt;p&gt;외부상태의 타입을 &lt;code&gt;State&lt;/code&gt; , 함수 &lt;code&gt;f&lt;/code&gt;와 &lt;code&gt;g&lt;/code&gt;가 있다면 다음처럼 나타낼 수 있다.&lt;/p&gt;
&lt;p&gt;(&lt;code&gt;a&lt;/code&gt;와 &lt;code&gt;b&lt;/code&gt;는 또다른 결과값)&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;f:: State -&amp;gt; (a, State)
g:: State -&amp;gt; (b, State)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그런데, 함수를 합성(&lt;code&gt;g(f(x))&lt;/code&gt;)해야 할 일이 생긴다면??&lt;/p&gt;
&lt;p&gt;&lt;code&gt;f&lt;/code&gt;의 출력과 &lt;code&gt;g&lt;/code&gt;의 입력이 맞지 않는다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 해결방안이 바로 바인드 연산자(&lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;)다.&lt;/p&gt;
&lt;p&gt;바인드 연산자는&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled 1.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1693&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mVJuT/btqBZfs4hs8/moXQkAKQKHEmp7X6dE3Kc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mVJuT/btqBZfs4hs8/moXQkAKQKHEmp7X6dE3Kc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mVJuT/btqBZfs4hs8/moXQkAKQKHEmp7X6dE3Kc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmVJuT%2FbtqBZfs4hs8%2FmoXQkAKQKHEmp7X6dE3Kc1%2Fimg.png&quot; data-filename=&quot;Untitled 1.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1693&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;ul&gt;
&lt;li&gt;&lt;code&gt;f&lt;/code&gt;의 결과값을 &lt;code&gt;a&lt;/code&gt;와 &lt;code&gt;State&lt;/code&gt;로 분리하고,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt;는 &lt;code&gt;g&lt;/code&gt;와 결합해 새로운 함수 &lt;code&gt;g'&lt;/code&gt;를 만들어 주며&lt;/li&gt;
&lt;li&gt;&lt;code&gt;State&lt;/code&gt;를 &lt;code&gt;g'&lt;/code&gt;에 전달해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;바인드 연산자가 만들어준 새로운 함수 &lt;code&gt;g'&lt;/code&gt;는&lt;/p&gt;
&lt;pre class=&quot;sml&quot;&gt;&lt;code&gt;g':: State -&amp;gt; (b, State)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;의 형태가 되도록 2개의 함수가 합쳐진 것이다!!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;합성함수를 다른 관점에서 살펴보면 &lt;code&gt;State&lt;/code&gt;값이 &lt;code&gt;f&lt;/code&gt;와 &lt;code&gt;g&lt;/code&gt;함수를 '&lt;b&gt;연속적&lt;/b&gt;'으로 거친 것이라 생각할수도 있는데 Chaining이라 부른다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이제 다시 한번 바인드 연산자의 정의를 보자.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;(&amp;gt;&amp;gt;=):: M a -&amp;gt; (a -&amp;gt; M b) -&amp;gt; M b&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이해가 가는가?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음은 차례대로 &lt;b&gt;쓰기&lt;/b&gt;, &lt;b&gt;읽기&lt;/b&gt;, &lt;b&gt;상태 변화&lt;/b&gt;를 모나드로 어떻게 처리하는지에 대한 그림이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;쓰기&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled 2.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;585&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bP6zfQ/btqBWsgyzPG/Ts3tbCHoevAqDbMJ1hoUt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bP6zfQ/btqBWsgyzPG/Ts3tbCHoevAqDbMJ1hoUt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bP6zfQ/btqBWsgyzPG/Ts3tbCHoevAqDbMJ1hoUt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbP6zfQ%2FbtqBWsgyzPG%2FTs3tbCHoevAqDbMJ1hoUt0%2Fimg.png&quot; data-filename=&quot;Untitled 2.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;585&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;ul&gt;
&lt;li&gt;읽기&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled 3.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;438&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6Uzr0/btqBWsHDhC8/nFg4J2AUKhMhHVKPY6fCr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6Uzr0/btqBWsHDhC8/nFg4J2AUKhMhHVKPY6fCr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6Uzr0/btqBWsHDhC8/nFg4J2AUKhMhHVKPY6fCr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6Uzr0%2FbtqBWsHDhC8%2FnFg4J2AUKhMhHVKPY6fCr1%2Fimg.png&quot; data-filename=&quot;Untitled 3.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;438&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;ul&gt;
&lt;li&gt;상태&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled 4.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;257&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eHXLZw/btqBYeVJenG/hCIdQbOgRPmwpzopiru2rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eHXLZw/btqBYeVJenG/hCIdQbOgRPmwpzopiru2rK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eHXLZw/btqBYeVJenG/hCIdQbOgRPmwpzopiru2rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeHXLZw%2FbtqBYeVJenG%2FhCIdQbOgRPmwpzopiru2rK%2Fimg.png&quot; data-filename=&quot;Untitled 4.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;257&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;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;바인드 연산자와 &lt;code&gt;do&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;다시 처음으로 돌아와서 &lt;code&gt;do&lt;/code&gt; 연산자를 봐보자.&lt;/p&gt;
&lt;p&gt;사실 do는 &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;(바인드 연산자)의 연속된 형태인데..&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;do&lt;/code&gt;의 문법은 바인드 연산자를 쉽게 쓰도록 만든 Syntax Sugar다.&lt;/p&gt;
&lt;pre class=&quot;elm&quot;&gt;&lt;code&gt;e1 &amp;gt;&amp;gt;= \p -&amp;gt; e2   -- 바인드 연산자
do p &amp;lt;- e1; e2    -- Do 연산자&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;바인드 연산자 사용 예제와 &lt;code&gt;do&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;(&amp;gt;&amp;gt;=):: [a] -&amp;gt; (a -&amp;gt; [b]) -&amp;gt; [b]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그럼 바인드 연산자가 리스트 형태로 묶어서 리턴한다고 가정해보자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;우리의 목표는 아래와 같은 리스트 컴프레션을 만드는 것.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;[(x,y) | x &amp;lt;- [1,2,3] , y &amp;lt;- [1,2,3], x /= y]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;결과&lt;/b&gt;: &lt;code&gt;[(1,2),(1,3),(2,1),(2,3),(3,1),(3,2)]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/=&lt;/code&gt;는 &lt;code&gt;==&lt;/code&gt;의 반대로, 다를 때 &lt;code&gt;True&lt;/code&gt; 같으면 &lt;code&gt;False&lt;/code&gt;를 리턴한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;바인드 연산자를 이용하면 다음과 같이 구현한다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;[1,2,3] &amp;gt;&amp;gt;= (\ x -&amp;gt; [1,2,3]       &amp;gt;&amp;gt;=
            (\ y -&amp;gt; return (x/=y) &amp;gt;&amp;gt;=
   (\r -&amp;gt; case r of True -&amp;gt; return (x,y)
                    _    -&amp;gt; fail &quot;&quot;)
            ))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고, &lt;code&gt;do&lt;/code&gt;를 사용하면 매우 간단하게 표현할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;do x &amp;lt;- [1,2,3]
   y &amp;lt;- [1,2,3]
   True &amp;lt;- return (x /= y)
   return (x,y)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;do&lt;/code&gt; 모나드를 보고 나면 연속적으로 적용한다는 chaining 또한 쉽게 이해가 될 것이라 생각한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;모나드 활용예시&lt;/h2&gt;
&lt;p&gt;모나드 활용을 2가지 예로 알아보자.&lt;/p&gt;
&lt;p&gt;보편적으로 사용해서 사람들이 많이 알지만, 언어 설계상 함수형과는 거리가 멀기로 유명한 자바로 사용해봤다.&lt;/p&gt;
&lt;p&gt;OOP로만 유명한 언어에서도 잘 써먹을 수 있다는 것을 보여줄 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;NULL 문제 해결&lt;/h3&gt;
&lt;p&gt;Null값과 관련된 NullPointerException은 정말 자바에서 유서깊고 익숙한 버그다.&lt;/p&gt;
&lt;p&gt;자바로 어느정도 코딩을 해본적이 있는 사람이라면 안만난적이 없을 것이라 장담한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Null Pointer를 처음 생각해낸 토니 호어 아저씨도 후회한다구..&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/&quot;&gt;https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1581500396200&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Null References: The Billion Dollar Mistake&quot; data-og-description=&quot;Tony Hoare introduced Null references in ALGOL W back in 1965 &amp;quot;simply because it was so easy to implement&amp;quot;, says Mr. Hoare. He talks about that decision considering it &amp;quot;my billion-dollar mistake&amp;quot;.&quot; data-og-host=&quot;www.infoq.com&quot; data-og-source-url=&quot;https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/&quot; data-og-url=&quot;https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bz8xpR/hyEVqcDzt5/jKkRwnfRltjkpsIYkhfqb1/img.jpg?width=270&amp;amp;height=200&amp;amp;face=101_44_149_97,https://scrap.kakaocdn.net/dn/bOAhOJ/hyEUdTvO40/lsufp8eAgLkhqAKU7insN1/img.jpg?width=270&amp;amp;height=200&amp;amp;face=101_44_149_97&quot;&gt;&lt;a href=&quot;https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bz8xpR/hyEVqcDzt5/jKkRwnfRltjkpsIYkhfqb1/img.jpg?width=270&amp;amp;height=200&amp;amp;face=101_44_149_97,https://scrap.kakaocdn.net/dn/bOAhOJ/hyEUdTvO40/lsufp8eAgLkhqAKU7insN1/img.jpg?width=270&amp;amp;height=200&amp;amp;face=101_44_149_97');&quot; title=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Null References: The Billion Dollar Mistake&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Tony Hoare introduced Null references in ALGOL W back in 1965 &quot;simply because it was so easy to implement&quot;, says Mr. Hoare. He talks about that decision considering it &quot;my billion-dollar mistake&quot;.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.infoq.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;물론 자바는 타입 안정성(Type Safty)를 보장하지 않기 때문에 수많은 익셥션과 런타임 에러처리에 많은 노력을 들이고, 코드가 이상해진다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하지만, 방금 배운 모오오나드를 사용하면 우아하게 해결할 수 있다.&lt;/p&gt;
&lt;p&gt;타입스크립트, 스위프트 사용자라면 &lt;code&gt;?&lt;/code&gt;기호로, 하스켈이라면 &lt;code&gt;Maybe&lt;/code&gt;로 유명한 그것.&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; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8rMmA/btqBVf2KPFG/vPd1czkwI6iyxmpV28PXXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8rMmA/btqBVf2KPFG/vPd1czkwI6iyxmpV28PXXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8rMmA/btqBVf2KPFG/vPd1czkwI6iyxmpV28PXXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8rMmA%2FbtqBVf2KPFG%2FvPd1czkwI6iyxmpV28PXXK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Null값과 아닌 것을 구분하는 똑똑한 타입이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;697&quot; height=&quot;163&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q5Kjh/btqBVL77YbL/nxVx90dvDg072Rm6pjAN20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q5Kjh/btqBVL77YbL/nxVx90dvDg072Rm6pjAN20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q5Kjh/btqBVL77YbL/nxVx90dvDg072Rm6pjAN20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq5Kjh%2FbtqBVL77YbL%2FnxVx90dvDg072Rm6pjAN20%2Fimg.png&quot; width=&quot;697&quot; height=&quot;163&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;pre class=&quot;haskell&quot;&gt;&lt;code&gt;M &amp;gt;&amp;gt;= g = case M of
             Just x  -&amp;gt; g x
             Nothing -&amp;gt; Nothing&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Maybe 모나드가 유용한 상황을 알아보기 위해 우선 간단한 예제를 만들어봤다.&lt;/p&gt;
&lt;pre id=&quot;code_1581500772000&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class FamilyTree {
    @Getter
    @AllArgsConstructor
    class Person {
        private String relation;
        private Person father;
        private Person mother;
    }

    Person createFamilyTree() {
        return new Person(&quot;Me&quot;,
                new Person(&quot;Father&quot;,
                        new Person(&quot;GrandFather&quot;,
                                new Person(null,                null, null),
                                new Person(&quot;Great-GrandMother&quot;, null, null)),
                        new Person(&quot;GrandMother&quot;, null, null)),
                new Person(&quot;Mother&quot;,
                        new Person(&quot;Maternal GrandFather&quot;, null, null),
                        new Person(&quot;Maternal GrandMother&quot;, null, null)));
    }

    Person person;
    FamilyTree() {
        this.person = createFamilyTree();
    }
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;보다시피 아래와 같이 이루어진 가계도란 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;사람(Person)&lt;br /&gt;관계, 아버지, 어머니 정보를 가진다.&lt;/li&gt;
&lt;li&gt;생성자로 생성된 사람한계&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;친가: 친증조할아버지(이름 누락), 친증조할머니&lt;/li&gt;
&lt;li&gt;외가: 외할아버지, 외할머니&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그럼 여기에서 친증조할아버지와 외할머니를 찾아보자.&lt;/p&gt;
&lt;pre id=&quot;code_1581550578649&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void find1() {
    if ( person.getFather() != null ) {
        Person father = person.getFather();
        if ( father.getFather() != null ) {
            Person grandFather = father.getFather();
            if ( grandFather.getFather() != null ) {
                Person greatGrandFather = grandFather.getFather();
                if ( greatGrandFather.getRelation() != null )
                    System.out.println( &quot;1-1: &quot; + greatGrandFather.getRelation() );
                else
                    System.out.println( &quot;1-1: Failed&quot; );
            } else {
                System.out.println( &quot;1-1: Failed&quot; );
            }
        }  else {
            System.out.println( &quot;1-1: Failed&quot; );
        }
    } else {
        System.out.println( &quot;1-1: Failed&quot; );
    }

    if ( person.getMother() != null ) {
        Person mother = person.getMother();
        if ( mother.getMother() != null ) {
            Person maternalGrandMother = mother.getMother();
            if ( maternalGrandMother.getRelation() != null )
                System.out.println( &quot;1-2: &quot; + maternalGrandMother.getRelation() );
            else
                System.out.println( &quot;1-2: Failed&quot; );
        } else {
            System.out.println( &quot;1-2: Failed&quot; );
        }
    } else {
        System.out.println( &quot;1-1: Failed&quot; );
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예제용으로 만들었기 때문에 약간 과장되어 있다.&lt;/p&gt;
&lt;p&gt;위 코드는 재귀로 나타나면 간결하게 만들수 있겠지만 현실에서는 복잡한 처리를 원해서 재귀나 반복문을 쓰기 힘들 수도 있다.&lt;/p&gt;
&lt;p&gt;(예를 들어 Person 만으로 이루어지지 않았거나 나, 아빠, 할아버지등에 모두 다른 처리가 필요하다거나..)&lt;/p&gt;
&lt;p&gt;그래서 If문을 사용해서 Null값을 확인해야 한다면 자바스크립트 콜백지옥을 보는 느낌이 나는건 여전할 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이번에는 자바에서 Maybe 역할을 하는 Optional을 사용해서 처리해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1581550924362&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void find2() {
    Optional.of( person )
        .map( Person::getFather   )
        .map( Person::getFather   )
        .map( Person::getFather   )
        .map( Person::getRelation )
        .ifPresentOrElse(
            info -&amp;gt; System.out.println( &quot;2-1: &quot; + info ),
            ()   -&amp;gt; System.out.println( &quot;2-1: Failed&quot;  )
        );

    Optional.of( person )
        .map( Person::getMother   )
        .map( Person::getMother   )
        .map( Person::getRelation )
        .ifPresentOrElse(
            info -&amp;gt; System.out.println( &quot;2-2: &quot; + info ),
            ()   -&amp;gt; System.out.println( &quot;2-2: Failed&quot;  )
        );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;간결하고, 우아하다.&lt;/p&gt;
&lt;p&gt;직접적으로 null을 다루지 않으면서 처리를 할 수 있다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Optional.of()는 Optional 타입 모나트 생성자 역할로 person을 감싸준다. (타입 생성자, return)&lt;/li&gt;
&lt;li&gt;map 함수를 연속적으로 적용 또는 합성한다. (바인드 연산자, chaining)&lt;/li&gt;
&lt;li&gt;마지막으로 Optional 타입을 이용해서 Null값 여부를 확인한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;영락없는 모나드의 형태며,&amp;nbsp; 적용되는 것을 보면 do 연산자를 보는 느낌이 든다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;요즘 유행하는&amp;nbsp;&lt;a href=&quot;http://reactivex.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rx&lt;/a&gt;를(여기서는 &lt;a href=&quot;https://github.com/ReactiveX/RxJava&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RxJava&lt;/a&gt;) 사용해도 비슷하게 구성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1581551601155&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void find3() {
    Maybe.just( person )
        .map( Person::getFather   )
        .map( Person::getFather   )
        .map( Person::getFather   )
        .map( Person::getRelation )
        .subscribe(
            info -&amp;gt; System.out.println( &quot;3-1: &quot; + info ),
            e    -&amp;gt; System.out.println( &quot;3-1: Failed&quot;  )
        );

    Maybe.just(person)
        .map( Person::getMother   )
        .map( Person::getMother   )
        .map( Person::getRelation )
        .subscribe(
            info -&amp;gt; System.out.println( &quot;3-2: &quot; + info ),
            e    -&amp;gt; System.out.println( &quot;3-2: Failed&quot;  )
        );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Try 문제 해결&lt;/h3&gt;
&lt;p&gt;자바를 쓰다보면 생각나는 또다른 문제는 바로 Try-Catch다.&lt;/p&gt;
&lt;p&gt;NullPointerExteption의 연장선상으로 논할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그럼 Try-Catch의 단점을 생각해보자면 역시&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;본문과 동떨어져 있다는 특성 때문에 Goto 문법을 쓰는 느낌&lt;/li&gt;
&lt;li&gt;그러다 보니 예외처리를 중복으로 할 수도 있고 유지보수가 힘듦&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 가장 큰 단점이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 역시 모나드를 사용하면 깔끔하게 해결이 가능하다.&lt;/p&gt;
&lt;p&gt;대략 아래 그림처럼 예외처리가 가능해진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjY6Bf/btqBWDog687/SLzetbFW5mJmt4xSxaXUs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjY6Bf/btqBWDog687/SLzetbFW5mJmt4xSxaXUs0/img.png&quot; width=&quot;320&quot; height=&quot;193&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 47.5979%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjY6Bf/btqBWDog687/SLzetbFW5mJmt4xSxaXUs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjY6Bf%2FbtqBWDog687%2FSLzetbFW5mJmt4xSxaXUs0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HHu6o/btqBWZYY4pu/HusPdt5JJYPLba2RZwX0X0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HHu6o/btqBWZYY4pu/HusPdt5JJYPLba2RZwX0X0/img.png&quot; width=&quot;320&quot; height=&quot;180&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 51.2393%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HHu6o/btqBWZYY4pu/HusPdt5JJYPLba2RZwX0X0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHHu6o%2FbtqBWZYY4pu%2FHusPdt5JJYPLba2RZwX0X0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;스칼라의 Try와 Promise&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Maybe 모나드를 사용할 때와 비슷~&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;역시 Try를 쓰는 예제를 만들어봤다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;0으로 나누기를 하면 ArithmeticException이 발생한다는 것에 착안해 만들었으며&amp;nbsp;&lt;/span&gt;null을 다루는 예제보다 훨씬 간단하다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1581562370975&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void divide1( int divide_num ) {
    try {
        System.out.println( &quot;1: &quot; + ( num / divide_num ) );
    } catch ( ArithmeticException e ) {
        System.out.println( &quot;1: Can't divide by 0&quot; );
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기서는 요구사항이 간단해 그다지 헷갈리지 않지만,&lt;/p&gt;
&lt;p&gt;코드가 복잡해질수록 가독성이 나빠질 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그래서 다른 방법을 생각해보자면&lt;/p&gt;
&lt;p&gt;아까도 썼었던 Rx의 경우 &lt;a href=&quot;http://reactivex.io/documentation/operators/subscribe.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;subscribe&lt;/a&gt;를 주목할 필요가 있다.&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; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zTweo/btqBZfT75Wc/tJHMHs27Azm19ZUkQo9Is0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zTweo/btqBZfT75Wc/tJHMHs27Azm19ZUkQo9Is0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zTweo/btqBZfT75Wc/tJHMHs27Azm19ZUkQo9Is0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzTweo%2FbtqBZfT75Wc%2FtJHMHs27Azm19ZUkQo9Is0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;subscribe를 사용하면 정상적일 때와 에러가 났을 때를 구분할 수 있기 때문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1581570290642&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void divide2( int divide_num ) {
    SingleJust.just( num )
        .map( num -&amp;gt; num / divide_num )
        .subscribe(
            result -&amp;gt; System.out.println( &quot;2: &quot; + result         ),
            e      -&amp;gt; System.out.println( &quot;2: Can't divide by 0&quot; )
        );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;subscribe를 이용하면 자연스럽게 성공, 실패를 구분하는 것이 가능하며 가독성도 그대로 살릴 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그렇다면 Optional, Maybe처럼 Try 타입은 없는가?&lt;/p&gt;
&lt;p&gt;대답을 하자면&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.vavr.io&quot;&gt;vavr&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.vavr.io/vavr-docs/#_try&quot;&gt;Try&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입을 사용해볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1581570188241&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void divide3( int divide_num ) {
    Try.of( () -&amp;gt; num / divide_num )
        .onSuccess( result -&amp;gt; System.out.println( &quot;3: &quot; + result         ) )
        .onFailure( e      -&amp;gt; System.out.println( &quot;3: Can't divide by 0&quot; ) );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;개인적으로는 Rx가 함수형 개념을 훌륭히 버무렸다고 생각해서 선호한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;후기.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;원래 설계용으로 강좌를 쓰던 Lisp(Racket)로 쓸까말까 고민하다 하스켈 위주로 설명해서 올렸다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Lisp로 모나드를 구현 한 코드를 보면 합쳐서 300라인 정도라 짧다!!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tonyg/racket-monad&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/tonyg/racket-monad&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1581572843946&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;tonyg/racket-monad&quot; data-og-description=&quot;Monads for Racket (!). Contribute to tonyg/racket-monad development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/tonyg/racket-monad&quot; data-og-url=&quot;https://github.com/tonyg/racket-monad&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/emR2qW/hyEUawbJy0/OAtmL0lnZwuPHoa1oOkOd0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://github.com/tonyg/racket-monad&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/tonyg/racket-monad&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/emR2qW/hyEUawbJy0/OAtmL0lnZwuPHoa1oOkOd0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;tonyg/racket-monad&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Monads for Racket (!). Contribute to tonyg/racket-monad development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;리스프를 좋아하는 사람이라면 볼만한듯.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;매크로를 이용해 아예 방언으로 만든 구현체도 있는데&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.racket-lang.org/heresy/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.racket-lang.org/heresy/index.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1581572934660&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;The Heresy Programming Language&quot; data-og-description=&quot;7.5 The Heresy Programming Language source code: https://github.com/jarcane/heresy The Heresy language is a functional Lisp/Scheme dialect implemented in Racket, with syntax inspired by the BASIC family of programming languages. Its principle goals are to &quot; data-og-host=&quot;docs.racket-lang.org&quot; data-og-source-url=&quot;https://docs.racket-lang.org/heresy/index.html&quot; data-og-url=&quot;https://docs.racket-lang.org/heresy/index.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.racket-lang.org/heresy/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.racket-lang.org/heresy/index.html&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;&gt;The Heresy Programming Language&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;7.5 The Heresy Programming Language source code: https://github.com/jarcane/heresy The Heresy language is a functional Lisp/Scheme dialect implemented in Racket, with syntax inspired by the BASIC family of programming languages. Its principle goals are to&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;docs.racket-lang.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아름답게 융합된 모습을 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1581573222303&quot; class=&quot;hy&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(is-none? (maybe-do
           (a &amp;lt;- (some 5) )
           (b &amp;lt;-     None )
           (c =   (+ a b) )
           (yield       c )))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;마지막으로 원 코드는 아래에 올려놨으니까 참고할 사람은 참고하시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/black7375/JavaMonad&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/black7375/JavaMonad&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1581575663290&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;black7375/JavaMonad&quot; data-og-description=&quot;Contribute to black7375/JavaMonad development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/black7375/JavaMonad&quot; data-og-url=&quot;https://github.com/black7375/JavaMonad&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b78Ukx/hyEVmhwLlv/cA9KrRRPvrOzhqdBVKDYXK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=116_158_218_269&quot;&gt;&lt;a href=&quot;https://github.com/black7375/JavaMonad&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/black7375/JavaMonad&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b78Ukx/hyEVmhwLlv/cA9KrRRPvrOzhqdBVKDYXK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=116_158_218_269');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;black7375/JavaMonad&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Contribute to black7375/JavaMonad development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.haskell.org/tutorial/monads.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Haskell Tutoral - Monad&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lazyswamp.tistory.com/entry/functorsapplicativesandmonadsinpictures&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;그림으로 설명하는 펑터, 어플리커티브, 모나드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Wikibooks - Haskell&lt;br /&gt;&lt;a href=&quot;https://en.wikibooks.org/wiki/Haskell/Understanding_monads#Definition&quot;&gt;https://en.wikibooks.org/wiki/Haskell/Understanding_monads#Definition&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://en.wikibooks.org/wiki/Haskell/Understanding_monads/State&quot;&gt;https://en.wikibooks.org/wiki/Haskell/Understanding_monads/State&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://en.wikibooks.org/wiki/Haskell/Kinds&quot;&gt;https://en.wikibooks.org/wiki/Haskell/Kinds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://adit.io/posts/2013-06-10-three-useful-monads.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Three Useful Monads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.seulgi.kim/2015/07/what-is-monad.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Monad는 무엇인가&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.seulgi.kim/2015/09/monad-promise.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Promise: 비동기 코드 작성하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kdata.or.kr/info/info_04_view.html?field=&amp;amp;keyword=&amp;amp;type=techreport&amp;amp;page=12&amp;amp;dbnum=185839&amp;amp;mode=detail&amp;amp;type=techreport&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RxAndroid로 반응형 앱 개발하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://namu.wiki/w/Haskell#s-3.7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Haskell - 모나드(나무위키)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.codewars.com/kata/monads-the-maybe-monad&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Monads: The Maybe Monad&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;참고할 만한것&lt;/b&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://1ambda.github.io/haskell/intro-to-haskell-5/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;하스켈로 배우는 함수형 언어 - IO 모나드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://edykim.com/ko/post/javascript-monad/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모나드와 자바스크립트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tech.kakao.com/2016/03/03/monad-programming-with-scala-future/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Monad Programming with Scala Future&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://evan-moon.github.io/2020/01/27/safety-function-composition/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;어떻게 하면 안전하게 함수를 합성할 수 있을까?&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pnurep.github.io/functional%20programming/functors-applicatives-monads/#&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Functor, Applicative, Monad&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.haskell.org/Functor-Applicative-Monad_Proposal&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Functor-Applicative-Monad Proposal&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@lettier/your-easy-guide-to-monads-applicatives-functors-862048d61610&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Your easy guide to Monads, Applicatives, &amp;amp; Functors&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hackernoon.com/functor-applicative-and-monads-fp1e32eh&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Functor Applicative and Monads&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;a href=&quot;https://softwareengineering.stackexchange.com/questions/202908/how-do-functional-languages-handle-random-numbers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How do functional languages handle random numbers?&lt;/a&gt; [번역(?): &lt;/span&gt;&lt;a href=&quot;https://qastack.kr/software/202908/how-do-functional-languages-handle-random-numbers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;함수형 언어는 난수를 어떻게 처리합니까?&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini&quot; class=&quot;s3gt_translate_tooltip_mini_box&quot; style=&quot;background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 293px; top: 854px; opacity: 0.75;&quot;&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_logo&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Translate selected text&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_sound&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Play&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_copy&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Copy text to Clipboard&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/설계</category>
      <category>모나드</category>
      <category>하스켈</category>
      <category>함수형</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/69</guid>
      <comments>https://black7375.tistory.com/69#entry69comment</comments>
      <pubDate>Tue, 11 Feb 2020 13:57:29 +0900</pubDate>
    </item>
    <item>
      <title>모바일 디자인</title>
      <link>https://black7375.tistory.com/68</link>
      <description>&lt;p&gt;우리 이쁜 쓰레기가 사라진다니 마음이 아픕니다 ㅠㅠㅠㅠ&lt;/p&gt;
&lt;p&gt;블랙베리가 역사속으로 사라지는 것을 기념해서 마음에 드는 디자인을 모아봤어요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://news.v.daum.net/v/20200204074213772&quot;&gt;https://news.v.daum.net/v/20200204074213772&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1582733094736&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;키보드 탑재 폰 '블랙베리' 사라진다&quot; data-og-description=&quot;핸드폰에 키보드가 탑재돼 눈길을 끌었던 '블랙베리' 스마트폰이 사실상 단종된다. 그간 블랙베리 스마트폰 생산과 디자인, 판매 등을 맡아온 중국 가전업체 TCL이 오는 8월31일부터 블랙베리폰에서 손을 떼기 때문이다. IT 전문매체 '안드로이드 오쏘리티(Android Authority)'는 4일(현지시간) &amp;quot;TCL 커뮤니케이션이 공식 트위터를 통해 향후 블랙&quot; data-og-host=&quot;news.v.daum.net&quot; data-og-source-url=&quot;https://news.v.daum.net/v/20200204074213772&quot; data-og-url=&quot;https://news.v.daum.net/v/20200204074213772&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fqMT6/hyE5bNTRWs/DKu9dp1d5h0skKeqJy2UJ0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/l7UwO/hyE5gVXTMs/Q7FnF6OUYOAHnjQhhCfho1/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/czqKkU/hyE5eDQeFa/gRHWIB1cYdExpaSjpuHZlK/img.jpg?width=620&amp;amp;height=646&amp;amp;face=0_0_620_646&quot;&gt;&lt;a href=&quot;https://news.v.daum.net/v/20200204074213772&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://news.v.daum.net/v/20200204074213772&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fqMT6/hyE5bNTRWs/DKu9dp1d5h0skKeqJy2UJ0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/l7UwO/hyE5gVXTMs/Q7FnF6OUYOAHnjQhhCfho1/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/czqKkU/hyE5eDQeFa/gRHWIB1cYdExpaSjpuHZlK/img.jpg?width=620&amp;amp;height=646&amp;amp;face=0_0_620_646');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;키보드 탑재 폰 '블랙베리' 사라진다&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;핸드폰에 키보드가 탑재돼 눈길을 끌었던 '블랙베리' 스마트폰이 사실상 단종된다. 그간 블랙베리 스마트폰 생산과 디자인, 판매 등을 맡아온 중국 가전업체 TCL이 오는 8월31일부터 블랙베리폰에서 손을 떼기 때문이다. IT 전문매체 '안드로이드 오쏘리티(Android Authority)'는 4일(현지시간) &quot;TCL 커뮤니케이션이 공식 트위터를 통해 향후 블랙&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;news.v.daum.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;블랙베리(BlackBerry)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmx00s/btqCje83Cfs/8MgDMxk2mX0DsWJ4g4hha0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmx00s/btqCje83Cfs/8MgDMxk2mX0DsWJ4g4hha0/img.png&quot; width=&quot;2000&quot; height=&quot;600&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 36.1996%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmx00s/btqCje83Cfs/8MgDMxk2mX0DsWJ4g4hha0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdmx00s%2FbtqCje83Cfs%2F8MgDMxk2mX0DsWJ4g4hha0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNPiEg/btqCe5rSDRS/BTQW73VBpT6eUI3IEM3RoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNPiEg/btqCe5rSDRS/BTQW73VBpT6eUI3IEM3RoK/img.png&quot; width=&quot;2000&quot; height=&quot;345&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 62.6376%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNPiEg/btqCe5rSDRS/BTQW73VBpT6eUI3IEM3RoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNPiEg%2FbtqCe5rSDRS%2FBTQW73VBpT6eUI3IEM3RoK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;블랙베리 850(1999)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;블랙베리 특유의 키보드 느낌은 이때부터.&lt;/p&gt;
&lt;p&gt;스타텍과 함께 90년대 플라스틱 감성.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;1409&quot; height=&quot;1012&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSFt90/btqCjeH1Ou1/Kd8HcgNSJuk0nSQdl4dxBk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSFt90/btqCjeH1Ou1/Kd8HcgNSJuk0nSQdl4dxBk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSFt90/btqCjeH1Ou1/Kd8HcgNSJuk0nSQdl4dxBk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSFt90%2FbtqCjeH1Ou1%2FKd8HcgNSJuk0nSQdl4dxBk%2Fimg.jpg&quot; width=&quot;1409&quot; height=&quot;1012&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;b&gt;블랙베리 Quark 6210(2003)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;다마고치가 떠오르는 귀여운 디자인 ㅎ&lt;/p&gt;
&lt;p&gt;블랙베리 커브까지 그대로 상속된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://memeburn.com/gearburn/wp-content/uploads/sites/3/2016/02/blackberry-6210.jpg 376w, https://memeburn.com/gearburn/wp-content/uploads/sites/3/2016/02/blackberry-6210-208x300.jpg 208w&quot; width=&quot;376&quot; height=&quot;543&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEFLsG/btqCeuMctIe/Z5Hb5D5kI4kx6dXVW3A6x1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEFLsG/btqCeuMctIe/Z5Hb5D5kI4kx6dXVW3A6x1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEFLsG/btqCeuMctIe/Z5Hb5D5kI4kx6dXVW3A6x1/img.jpg&quot; srcset=&quot;https://memeburn.com/gearburn/wp-content/uploads/sites/3/2016/02/blackberry-6210.jpg 376w, https://memeburn.com/gearburn/wp-content/uploads/sites/3/2016/02/blackberry-6210-208x300.jpg 208w&quot; width=&quot;376&quot; height=&quot;543&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pJ77s/btqCeu6Dlbg/Hk05c7Wl2jV1w00GBsSejK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pJ77s/btqCeu6Dlbg/Hk05c7Wl2jV1w00GBsSejK/img.jpg&quot; data-alt=&quot;비슷함이 느껴지는가? ㅎㅎ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pJ77s/btqCeu6Dlbg/Hk05c7Wl2jV1w00GBsSejK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpJ77s%2FbtqCeu6Dlbg%2FHk05c7Wl2jV1w00GBsSejK%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;조금 더 전통적인 맛을 보고 싶다면&lt;/p&gt;
&lt;p&gt;블랙베리 5810(2002)가 있겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-src=&quot;//w.namu.la/s/c99c131e30cc443e31f71b9bd7bfcd12df16e8ec4fffffe34bc33120e9afa3cd4f2d5183feb4a98f9e0f8b51c381a78b3445c8ef363d114194d1527335efa9e30eb3c6ca3ed6e58b7d7bb160cd75cc0417cbe3626f9903e9ada83b97fea46bae&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mgchN/btqCgRz03CF/4LoyL0O1JlvLmszVdvOtQk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mgchN/btqCgRz03CF/4LoyL0O1JlvLmszVdvOtQk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mgchN/btqCgRz03CF/4LoyL0O1JlvLmszVdvOtQk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmgchN%2FbtqCgRz03CF%2F4LoyL0O1JlvLmszVdvOtQk%2Fimg.jpg&quot; data-src=&quot;//w.namu.la/s/c99c131e30cc443e31f71b9bd7bfcd12df16e8ec4fffffe34bc33120e9afa3cd4f2d5183feb4a98f9e0f8b51c381a78b3445c8ef363d114194d1527335efa9e30eb3c6ca3ed6e58b7d7bb160cd75cc0417cbe3626f9903e9ada83b97fea46bae&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;블랙베리 Pearl 8100(2008)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;새로로 길쭉한 블랙베리에서는 흔치않은 디자인.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GAS3q/btqCim7ptJF/4J13g09GHRWbu1bAEiklXK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GAS3q/btqCim7ptJF/4J13g09GHRWbu1bAEiklXK/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 49.515%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GAS3q/btqCim7ptJF/4J13g09GHRWbu1bAEiklXK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGAS3q%2FbtqCim7ptJF%2F4J13g09GHRWbu1bAEiklXK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ASC2Y/btqCkQNplH8/clSwTYrRUeSVllrBKV2xt0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ASC2Y/btqCkQNplH8/clSwTYrRUeSVllrBKV2xt0/img.jpg&quot; data-src=&quot;https://cf5.s3.souqcdn.com/item/2013/04/07/48/03/14/item_XXL_480314_1802218.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 49.3222%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ASC2Y/btqCkQNplH8/clSwTYrRUeSVllrBKV2xt0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FASC2Y%2FbtqCkQNplH8%2FclSwTYrRUeSVllrBKV2xt0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;요것을 기반해서 만든 Pearl Flip &lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;8220&lt;/span&gt;(2008)도 나름 이쁜편.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqBDL8/btqCiojLhGd/U72YKt2Ax13kDqFnurZOt1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqBDL8/btqCiojLhGd/U72YKt2Ax13kDqFnurZOt1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqBDL8/btqCiojLhGd/U72YKt2Ax13kDqFnurZOt1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqBDL8%2FbtqCiojLhGd%2FU72YKt2Ax13kDqFnurZOt1%2Fimg.webp&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;블랙베리 Curve 8900(2008)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;블랙베리 디자인이 거의 확립되어 간다.&lt;/p&gt;
&lt;p&gt;아이콘도 블베 감성이.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YWiF7/btqCjSxVZks/HSnjY6IkPcSJdCFdIiJFfK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YWiF7/btqCjSxVZks/HSnjY6IkPcSJdCFdIiJFfK/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 50.5117%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YWiF7/btqCjSxVZks/HSnjY6IkPcSJdCFdIiJFfK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYWiF7%2FbtqCjSxVZks%2FHSnjY6IkPcSJdCFdIiJFfK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw3WZh/btqCjdCiGUB/X09Rhii8D1S0e3NsAO8MAK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw3WZh/btqCjdCiGUB/X09Rhii8D1S0e3NsAO8MAK/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 48.3255%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw3WZh/btqCjdCiGUB/X09Rhii8D1S0e3NsAO8MAK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcw3WZh%2FbtqCjdCiGUB%2FX09Rhii8D1S0e3NsAO8MAK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;블랙베리 Style 9670(2010)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;유선형이 인상깊은&amp;nbsp;&lt;/span&gt;가장 블랙베리 답지 않은 폰이다.&lt;/p&gt;
&lt;p&gt;그나저나 Style의 보라색은 모토로라에서 나올법만 한데 ㅋㅋ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-src=&quot;https://static.turbosquid.com/Preview/2014/05/17__04_40_00/BlackBerry_Style_9670_Red_004.jpg6b8886d8-2ffb-465f-8251-b436c2018829Default.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJFMeD/btqCjR6TiBR/Nshm4KJbX9kAETcCiD6zg0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJFMeD/btqCjR6TiBR/Nshm4KJbX9kAETcCiD6zg0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJFMeD/btqCjR6TiBR/Nshm4KJbX9kAETcCiD6zg0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJFMeD%2FbtqCjR6TiBR%2FNshm4KJbX9kAETcCiD6zg0%2Fimg.jpg&quot; data-src=&quot;https://static.turbosquid.com/Preview/2014/05/17__04_40_00/BlackBerry_Style_9670_Red_004.jpg6b8886d8-2ffb-465f-8251-b436c2018829Default.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;블랙베리 Bold 9900(2011)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;블랙베리 최고의 디자인이자 블랙베리를 하면 떠오르는 디자인.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-src=&quot;https://static.turbosquid.com/Preview/2014/07/07__08_04_51/000.jpga55e0474-750e-4458-b842-8f6be84b27d4Original.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beNXyn/btqCkQfyeS1/PGqurj9CoCzHkaTe7UIxXk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beNXyn/btqCkQfyeS1/PGqurj9CoCzHkaTe7UIxXk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beNXyn/btqCkQfyeS1/PGqurj9CoCzHkaTe7UIxXk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeNXyn%2FbtqCkQfyeS1%2FPGqurj9CoCzHkaTe7UIxXk%2Fimg.jpg&quot; data-src=&quot;https://static.turbosquid.com/Preview/2014/07/07__08_04_51/000.jpga55e0474-750e-4458-b842-8f6be84b27d4Original.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이걸 기반으로&lt;/p&gt;
&lt;p&gt;P'9981(2011)와 클래식(2014)이란 또다른 명작이 나타난다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;615&quot; height=&quot;397&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zHy5p/btqCgmttc75/a3h4dGWFkgkSdXn6Oc7Rp1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zHy5p/btqCgmttc75/a3h4dGWFkgkSdXn6Oc7Rp1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zHy5p/btqCgmttc75/a3h4dGWFkgkSdXn6Oc7Rp1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzHy5p%2FbtqCgmttc75%2Fa3h4dGWFkgkSdXn6Oc7Rp1%2Fimg.jpg&quot; width=&quot;615&quot; height=&quot;397&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkBYGh/btqCjRFQe9H/7WLoMNC58scYMwQ3vlGSzk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkBYGh/btqCjRFQe9H/7WLoMNC58scYMwQ3vlGSzk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkBYGh/btqCjRFQe9H/7WLoMNC58scYMwQ3vlGSzk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkBYGh%2FbtqCjRFQe9H%2F7WLoMNC58scYMwQ3vlGSzk%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;블랙베리 Passport(2014)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;넓적한 디자인이 특징.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xlU8T/btqCjeadNFD/ziUy9JPMCMpR0Ub0KhY0T0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xlU8T/btqCjeadNFD/ziUy9JPMCMpR0Ub0KhY0T0/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 35.6959%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xlU8T/btqCjeadNFD/ziUy9JPMCMpR0Ub0KhY0T0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxlU8T%2FbtqCjeadNFD%2FziUy9JPMCMpR0Ub0KhY0T0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l10Gc/btqChFlOvGn/qguvwx34SRAx6PeUWsdmBK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l10Gc/btqChFlOvGn/qguvwx34SRAx6PeUWsdmBK/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 63.1413%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l10Gc/btqChFlOvGn/qguvwx34SRAx6PeUWsdmBK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl10Gc%2FbtqChFlOvGn%2Fqguvwx34SRAx6PeUWsdmBK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;블랙베리 KeyOne(2017)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;TCL에서 라이센스 받아 만들어진 거라 진퉁 블랙베리는 아니지만.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://d1izl1w6yvptqw.cloudfront.net/wp-content/uploads/sites/5/2018/03/30112020/KEYone.jpg 840w, https://d1izl1w6yvptqw.cloudfront.net/wp-content/uploads/sites/5/2018/03/30112020/KEYone-288x300.jpg 288w, https://d1izl1w6yvptqw.cloudfront.net/wp-content/uploads/sites/5/2018/03/30112020/KEYone-768x800.jpg 768w, https://d1izl1w6yvptqw.cloudfront.net/wp-content/uploads/sites/5/2018/03/30112020/KEYone-96x100.jpg 96w, https://d1izl1w6yvptqw.cloudfront.net/wp-content/uploads/sites/5/2018/03/30112020/KEYone-600x625.jpg 600w&quot; width=&quot;840&quot; height=&quot;875&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRueM2/btqCeuZSvV9/GG2lHeMROkxAoSbavjN0f1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRueM2/btqCeuZSvV9/GG2lHeMROkxAoSbavjN0f1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRueM2/btqCeuZSvV9/GG2lHeMROkxAoSbavjN0f1/img.jpg&quot; srcset=&quot;https://d1izl1w6yvptqw.cloudfront.net/wp-content/uploads/sites/5/2018/03/30112020/KEYone.jpg 840w, https://d1izl1w6yvptqw.cloudfront.net/wp-content/uploads/sites/5/2018/03/30112020/KEYone-288x300.jpg 288w, https://d1izl1w6yvptqw.cloudfront.net/wp-content/uploads/sites/5/2018/03/30112020/KEYone-768x800.jpg 768w, https://d1izl1w6yvptqw.cloudfront.net/wp-content/uploads/sites/5/2018/03/30112020/KEYone-96x100.jpg 96w, https://d1izl1w6yvptqw.cloudfront.net/wp-content/uploads/sites/5/2018/03/30112020/KEYone-600x625.jpg 600w&quot; width=&quot;840&quot; height=&quot;875&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;풀터치폰들은 왜 없냐고 물을 수 있는데&lt;/p&gt;
&lt;p&gt;그놈의 감성이 문제다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;직접보자.&lt;/p&gt;
&lt;p&gt;Storm2 9550(2009), Torch 9800(2011), Z30(2013), Evolve X(2018)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ljeaA/btqCjQz8NEG/kB72lVgh1GwOjyos8QHrjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ljeaA/btqCjQz8NEG/kB72lVgh1GwOjyos8QHrjK/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 46.8948%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ljeaA/btqCjQz8NEG/kB72lVgh1GwOjyos8QHrjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FljeaA%2FbtqCjQz8NEG%2FkB72lVgh1GwOjyos8QHrjK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLNuWV/btqCly6Qtp1/jVdjcQC5YFr7CuK2ktv0j1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLNuWV/btqCly6Qtp1/jVdjcQC5YFr7CuK2ktv0j1/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 19.3%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLNuWV/btqCly6Qtp1/jVdjcQC5YFr7CuK2ktv0j1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLNuWV%2FbtqCly6Qtp1%2FjVdjcQC5YFr7CuK2ktv0j1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bi8N3F/btqCkQfyRTF/DmU1iz4aDkV5LIlOXUMWs1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bi8N3F/btqCkQfyRTF/DmU1iz4aDkV5LIlOXUMWs1/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 31.4796%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bi8N3F/btqCkQfyRTF/DmU1iz4aDkV5LIlOXUMWs1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbi8N3F%2FbtqCkQfyRTF%2FDmU1iz4aDkV5LIlOXUMWs1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kL7pH/btqCjdh72rL/eFkOJeQ6psdmlHbiFvorx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kL7pH/btqCjdh72rL/eFkOJeQ6psdmlHbiFvorx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kL7pH/btqCjdh72rL/eFkOJeQ6psdmlHbiFvorx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkL7pH%2FbtqCjdh72rL%2FeFkOJeQ6psdmlHbiFvorx0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;Evolve X는 라이센스 받아 만들어진 것.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.pocket-lint.com/phones/news/137319-farewell-blackberry-os-here-are-the-23-best-blackberry-phones-that-changed-the-world&quot;&gt;https://www.pocket-lint.com/phones/news/137319-farewell-blackberry-os-here-are-the-23-best-blackberry-phones-that-changed-the-world&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1582756333895&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;The history of Blackberry: The best BlackBerry phones&quot; data-og-description=&quot;BlackBerry was once a super-power in the smartphone market, here are some of the best phones to ever bear the iconic brand name.&quot; data-og-host=&quot;www.pocket-lint.com&quot; data-og-source-url=&quot;https://www.pocket-lint.com/phones/news/137319-farewell-blackberry-os-here-are-the-23-best-blackberry-phones-that-changed-the-world&quot; data-og-url=&quot;https://www.pocket-lint.com/phones/news/137319-farewell-blackberry-os-here-are-the-23-best-blackberry-phones-that-changed-the-world&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/hBgSg/hyE5c0uCE4/NuAbK2e5g235knmg4A3P1k/img.jpg?width=945&amp;amp;height=630&amp;amp;face=0_0_945_630,https://scrap.kakaocdn.net/dn/HFG96/hyE5movw2H/og7IluytvA9eWviMTPhuXK/img.jpg?width=970&amp;amp;height=647&amp;amp;face=0_0_970_647&quot;&gt;&lt;a href=&quot;https://www.pocket-lint.com/phones/news/137319-farewell-blackberry-os-here-are-the-23-best-blackberry-phones-that-changed-the-world&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.pocket-lint.com/phones/news/137319-farewell-blackberry-os-here-are-the-23-best-blackberry-phones-that-changed-the-world&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/hBgSg/hyE5c0uCE4/NuAbK2e5g235knmg4A3P1k/img.jpg?width=945&amp;amp;height=630&amp;amp;face=0_0_945_630,https://scrap.kakaocdn.net/dn/HFG96/hyE5movw2H/og7IluytvA9eWviMTPhuXK/img.jpg?width=970&amp;amp;height=647&amp;amp;face=0_0_970_647');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;The history of Blackberry: The best BlackBerry phones&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;BlackBerry was once a super-power in the smartphone market, here are some of the best phones to ever bear the iconic brand name.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.pocket-lint.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;팜(Palm)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WERLA/btqCkQzUhKo/Lab66t9w4UAAKuNLTbw8TK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WERLA/btqCkQzUhKo/Lab66t9w4UAAKuNLTbw8TK/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 27.7233%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WERLA/btqCkQzUhKo/Lab66t9w4UAAKuNLTbw8TK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWERLA%2FbtqCkQzUhKo%2FLab66t9w4UAAKuNLTbw8TK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbtgZo/btqCjQ1erMA/zqZLoeeMLKYNFCl7OROCxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbtgZo/btqCjQ1erMA/zqZLoeeMLKYNFCl7OROCxK/img.png&quot; width=&quot;2000&quot; height=&quot;782&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 71.1139%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbtgZo/btqCjQ1erMA/zqZLoeeMLKYNFCl7OROCxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbtgZo%2FbtqCjQ1erMA%2FzqZLoeeMLKYNFCl7OROCxK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;PDA의 명가.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;스마트폰 시대에 저문 또 다른 위대한 선구자다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;팜 Pilot 1000(1996)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;전자수첩 같은 심플한 디자인.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LjHbA/btqClxz5N1O/gkT6KBWq6yAnq3obdBkTBK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LjHbA/btqClxz5N1O/gkT6KBWq6yAnq3obdBkTBK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LjHbA/btqClxz5N1O/gkT6KBWq6yAnq3obdBkTBK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLjHbA%2FbtqClxz5N1O%2FgkT6KBWq6yAnq3obdBkTBK%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;이 디자인을 기반으로 Palm Pilot Professional(1997), Palm IIIx(1999), Palm VII(1999) 등이 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IU71a/btqCgSZ2heq/thRFkLvfw5QEPFQEJ1Ugmk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IU71a/btqCgSZ2heq/thRFkLvfw5QEPFQEJ1Ugmk/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 31.2953%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IU71a/btqCgSZ2heq/thRFkLvfw5QEPFQEJ1Ugmk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIU71a%2FbtqCgSZ2heq%2FthRFkLvfw5QEPFQEJ1Ugmk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NBTFH/btqCgodNlRY/HWBzMOzSN6ynKOgyTqnRwk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NBTFH/btqCgodNlRY/HWBzMOzSN6ynKOgyTqnRwk/img.jpg&quot; width=&quot;240&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 31.1327%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NBTFH/btqCgodNlRY/HWBzMOzSN6ynKOgyTqnRwk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNBTFH%2FbtqCgodNlRY%2FHWBzMOzSN6ynKOgyTqnRwk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckeZBT/btqCinZyhm7/E4Y7JaL9CDFZ4Xog2pllbk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckeZBT/btqCinZyhm7/E4Y7JaL9CDFZ4Xog2pllbk/img.jpg&quot; width=&quot;600&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 35.2465%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckeZBT/btqCinZyhm7/E4Y7JaL9CDFZ4Xog2pllbk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckeZBT%2FbtqCinZyhm7%2FE4Y7JaL9CDFZ4Xog2pllbk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;조금 특이한 바리에이션을 원한다면 투명 플라스틱을 이용한 스페셜 에디션.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;760&quot; height=&quot;1012&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kRsvx/btqCjdiahC1/3yps1ikKOGNNsVR2ACLS9k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kRsvx/btqCjdiahC1/3yps1ikKOGNNsVR2ACLS9k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kRsvx/btqCjdiahC1/3yps1ikKOGNNsVR2ACLS9k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkRsvx%2FbtqCjdiahC1%2F3yps1ikKOGNNsVR2ACLS9k%2Fimg.jpg&quot; width=&quot;760&quot; height=&quot;1012&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;핸드스프링 Visor Prism(2000)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;팜에 인수된 핸드스프링(Handspring)에서 만든 제품이다.&lt;/p&gt;
&lt;p&gt;Metallic Cobalt란 색이라는데 참 매력적이며 컬러액정을 지원한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eelSma/btqCjeaeP7Q/ILxxc3Gzu8sdgbK9ywxXq1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eelSma/btqCjeaeP7Q/ILxxc3Gzu8sdgbK9ywxXq1/img.gif&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 54.9981%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eelSma/btqCjeaeP7Q/ILxxc3Gzu8sdgbK9ywxXq1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeelSma%2FbtqCjeaeP7Q%2FILxxc3Gzu8sdgbK9ywxXq1%2Fimg.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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DffJe/btqCkQUijlc/ipaTCrW73YrVGQRphKlXm1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DffJe/btqCkQUijlc/ipaTCrW73YrVGQRphKlXm1/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 43.8391%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DffJe/btqCkQUijlc/ipaTCrW73YrVGQRphKlXm1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDffJe%2FbtqCkQUijlc%2FipaTCrW73YrVGQRphKlXm1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; srcset=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Handspring_Prism_Visorphone_Smartphone.jpg/675px-Handspring_Prism_Visorphone_Smartphone.jpg 1.5x, https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Handspring_Prism_Visorphone_Smartphone.jpg/900px-Handspring_Prism_Visorphone_Smartphone.jpg 2x&quot; width=&quot;450&quot; height=&quot;600&quot; data-file-width=&quot;1500&quot; data-file-height=&quot;2000&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn2gHL/btqCgSMCout/JkCvRKcnm1M5BULCiMw3Sk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn2gHL/btqCgSMCout/JkCvRKcnm1M5BULCiMw3Sk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn2gHL/btqCgSMCout/JkCvRKcnm1M5BULCiMw3Sk/img.jpg&quot; srcset=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Handspring_Prism_Visorphone_Smartphone.jpg/675px-Handspring_Prism_Visorphone_Smartphone.jpg 1.5x, https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Handspring_Prism_Visorphone_Smartphone.jpg/900px-Handspring_Prism_Visorphone_Smartphone.jpg 2x&quot; width=&quot;450&quot; height=&quot;600&quot; data-file-width=&quot;1500&quot; data-file-height=&quot;2000&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;600&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;핸드스프링 Treo 270(2002)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;역시 핸드스프링에서 시작했으며 바 모델을 맡고 있다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMLq4Y/btqClzdC8eB/S8JUcohoQ0NsYBGSQXTsL0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMLq4Y/btqClzdC8eB/S8JUcohoQ0NsYBGSQXTsL0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMLq4Y/btqClzdC8eB/S8JUcohoQ0NsYBGSQXTsL0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMLq4Y%2FbtqClzdC8eB%2FS8JUcohoQ0NsYBGSQXTsL0%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;팜 Tungsten TX(2005)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;메탈 소재가 특징.&lt;/p&gt;
&lt;p&gt;파일럿 시리즈를 깔끔하게 만들었다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kTjWw/btqCjQtrFQu/c9Obl4LKmqVpOnCoanW9Ik/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kTjWw/btqCjQtrFQu/c9Obl4LKmqVpOnCoanW9Ik/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kTjWw/btqCjQtrFQu/c9Obl4LKmqVpOnCoanW9Ik/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkTjWw%2FbtqCjQtrFQu%2Fc9Obl4LKmqVpOnCoanW9Ik%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;팜 Centro(2007)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Treo 계열의 완성형.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;P자 모양으로 숫자를 배치했다.&lt;/span&gt;&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZzN9v/btqCevqVHbF/d07xrat0UiqXpTKJg2JUx0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZzN9v/btqCevqVHbF/d07xrat0UiqXpTKJg2JUx0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZzN9v/btqCevqVHbF/d07xrat0UiqXpTKJg2JUx0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZzN9v%2FbtqCevqVHbF%2Fd07xrat0UiqXpTKJg2JUx0%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;팜 프리(2009)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;몽글몽글하니 귀엽다. &amp;gt;&amp;lt;&lt;/p&gt;
&lt;p&gt;또한 웹 OS의 유리가 떠오르는 듯한 느낌은 언제봐도 유려하다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lgYZm/btqCjeagikQ/6KvpkOrr5rwQMoJdv8Dhk0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lgYZm/btqCjeagikQ/6KvpkOrr5rwQMoJdv8Dhk0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lgYZm/btqCjeagikQ/6KvpkOrr5rwQMoJdv8Dhk0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlgYZm%2FbtqCjeagikQ%2F6KvpkOrr5rwQMoJdv8Dhk0%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;트레오의 자판을 가져왔고, 터치스톤(Touchstone)은 파일럿을 떠오르게 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cywkF5/btqCgRGNbZc/C74UX2DKUyK4dkVdYL30xK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cywkF5/btqCgRGNbZc/C74UX2DKUyK4dkVdYL30xK/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 35.7695%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cywkF5/btqCgRGNbZc/C74UX2DKUyK4dkVdYL30xK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcywkF5%2FbtqCgRGNbZc%2FC74UX2DKUyK4dkVdYL30xK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPPXkx/btqCkQfBrTT/eNk3UJi8DDlbakK6Cy6WAk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPPXkx/btqCkQfBrTT/eNk3UJi8DDlbakK6Cy6WAk/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 63.0677%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPPXkx/btqCkQfBrTT/eNk3UJi8DDlbakK6Cy6WAk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPPXkx%2FbtqCkQfBrTT%2FeNk3UJi8DDlbakK6Cy6WAk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;라이센스를 받아 만드는 Palm(2018)도 비슷한 특징을 가져간다.&lt;/p&gt;
&lt;p&gt;Gesture Pad 기능은 그래피티(Graffiti)가 생각난다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p2LqG/btqCjRlBCRz/huxkp5hK40QAUsMvt8i13K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p2LqG/btqCjRlBCRz/huxkp5hK40QAUsMvt8i13K/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 48.6156%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p2LqG/btqCjRlBCRz/huxkp5hK40QAUsMvt8i13K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp2LqG%2FbtqCjRlBCRz%2Fhuxkp5hK40QAUsMvt8i13K%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ednxl/btqCjQG1pQS/9g9lle4vOoxpAz1hw1crv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ednxl/btqCjQG1pQS/9g9lle4vOoxpAz1hw1crv1/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 50.2216%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ednxl/btqCjQG1pQS/9g9lle4vOoxpAz1hw1crv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEdnxl%2FbtqCjQG1pQS%2F9g9lle4vOoxpAz1hw1crv1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;참고로 후면을 안보여주는데에는 이유가 다 있다.&lt;/p&gt;
&lt;p&gt;전면 디자인들만 기억하자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;팜의 역사는&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://in.pcmag.com/smartphones/28167/rip-palm-a-history-of-the-smartphonepda-pioneer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://in.pcmag.com/smartphones/28167/rip-palm-a-history-of-the-smartphonepda-pioneer&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1582767895316&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;R.I.P. Palm: A History of the Smartphone/PDA Pioneer&quot; data-og-description=&quot;PC Magazine is your complete guide to computers, phones, tablets, peripherals and more. We test and review the latest gadgets, products and services, report technology news and trends, and provide shopping advice and price comparisons.&quot; data-og-host=&quot;in.pcmag.com&quot; data-og-source-url=&quot;https://in.pcmag.com/smartphones/28167/rip-palm-a-history-of-the-smartphonepda-pioneer&quot; data-og-url=&quot;https://in.pcmag.com/smartphones/28167/rip-palm-a-history-of-the-smartphonepda-pioneer&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cTJ7Uf/hyE5bm9blV/w0NWMaHwXYKO7KBMSXwCJk/img.jpg?width=220&amp;amp;height=296&amp;amp;face=0_0_220_296,https://scrap.kakaocdn.net/dn/dqkOs1/hyE5lQPqv9/W3Iosbxg1jQI0H4ZgQ4o31/img.jpg?width=220&amp;amp;height=296&amp;amp;face=0_0_220_296&quot;&gt;&lt;a href=&quot;https://in.pcmag.com/smartphones/28167/rip-palm-a-history-of-the-smartphonepda-pioneer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://in.pcmag.com/smartphones/28167/rip-palm-a-history-of-the-smartphonepda-pioneer&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cTJ7Uf/hyE5bm9blV/w0NWMaHwXYKO7KBMSXwCJk/img.jpg?width=220&amp;amp;height=296&amp;amp;face=0_0_220_296,https://scrap.kakaocdn.net/dn/dqkOs1/hyE5lQPqv9/W3Iosbxg1jQI0H4ZgQ4o31/img.jpg?width=220&amp;amp;height=296&amp;amp;face=0_0_220_296');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;R.I.P. Palm: A History of the Smartphone/PDA Pioneer&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;PC Magazine is your complete guide to computers, phones, tablets, peripherals and more. We test and review the latest gadgets, products and services, report technology news and trends, and provide shopping advice and price comparisons.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;in.pcmag.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://www.technobuffalo.com/palm-the-rise-and-fall-of-a-legend&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.technobuffalo.com/palm-the-rise-and-fall-of-a-legend&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1582767899432&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Palm: The Rise and Fall of a Legend&quot; data-og-description=&quot;I was there, when the Pilot landed. It was the summer of 1996, and the US Robotics Pilot 5000 had just arrived in the bootLab (&amp;lsquo;boot Magazine&amp;rsquo; was the then-newly-launched precursor to Maximum PC). With unprecedented ferocity, we editors were fighting gladi&quot; data-og-host=&quot;www.technobuffalo.com&quot; data-og-source-url=&quot;https://www.technobuffalo.com/palm-the-rise-and-fall-of-a-legend&quot; data-og-url=&quot;https://www.technobuffalo.com/palm-the-rise-and-fall-of-a-legend&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/yLVPp/hyE5kdkuTk/69ywD0Sjq47tkHQTCUH7E1/img.jpg?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/cwcEIz/hyE5dFhunt/XPnBSkUIRred0KHmVLYcgK/img.jpg?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/bObvot/hyE5dkYomq/2yKqqXjJ2J94jTYgMzDIR0/img.png?width=3&amp;amp;height=4&amp;amp;face=0_0_3_4&quot;&gt;&lt;a href=&quot;https://www.technobuffalo.com/palm-the-rise-and-fall-of-a-legend&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.technobuffalo.com/palm-the-rise-and-fall-of-a-legend&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/yLVPp/hyE5kdkuTk/69ywD0Sjq47tkHQTCUH7E1/img.jpg?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/cwcEIz/hyE5dFhunt/XPnBSkUIRred0KHmVLYcgK/img.jpg?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/bObvot/hyE5dkYomq/2yKqqXjJ2J94jTYgMzDIR0/img.png?width=3&amp;amp;height=4&amp;amp;face=0_0_3_4');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Palm: The Rise and Fall of a Legend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;I was there, when the Pilot landed. It was the summer of 1996, and the US Robotics Pilot 5000 had just arrived in the bootLab (&amp;lsquo;boot Magazine&amp;rsquo; was the then-newly-launched precursor to Maximum PC). With unprecedented ferocity, we editors were fighting gladi&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.technobuffalo.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;가 볼만하다.&lt;/p&gt;</description>
      <category>IT/견물생심</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/68</guid>
      <comments>https://black7375.tistory.com/68#entry68comment</comments>
      <pubDate>Wed, 5 Feb 2020 04:29:15 +0900</pubDate>
    </item>
    <item>
      <title>BlaCk Void Zsh 설계 및 기획 문서 공개</title>
      <link>https://black7375.tistory.com/67</link>
      <description>&lt;p&gt;정말 오랜만에 쓰는 글이네요.&lt;/p&gt;
&lt;p&gt;이 많은 내용을 임시저장 없이 2/3까지 써놨는데 이미지 편집기능에서 무한로딩 걸려서 처음부터 다시 씁니다. ㅠㅠ&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;오픈소스, 개발하고자 하면 온갖내용들을 참고하고 가격이나 제한도 덜한 편이라 참 좋습니다.&lt;/p&gt;
&lt;p&gt;하지만 사용법에 대한 문서는 충실하게 있는 반면, 설계와 기획에 대한 문서는 거의 없다시피 한것도 현실입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그래서 프로그램 개발자, 기획자들에게 조금의 도움이라도 되시라&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccatGi/btqAQ4nOzNY/adSjxkHqhv5BykcxxwzDS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccatGi/btqAQ4nOzNY/adSjxkHqhv5BykcxxwzDS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccatGi/btqAQ4nOzNY/adSjxkHqhv5BykcxxwzDS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccatGi%2FbtqAQ4nOzNY%2FadSjxkHqhv5BykcxxwzDS1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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/black7375/BlaCk-Void-Zsh&quot;&gt;https://github.com/black7375/BlaCk-Void-Zsh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;공개 SW 대회에 나갔던 제 오픈소스 프로젝트의 설계 및 기획문서를 깃허브 스타 100개, 신년 주말을 맞아 공개하려 합니다.&lt;/p&gt;
&lt;h2&gt;0. PDF 문서&lt;/h2&gt;
&lt;p&gt;깔끔하니 보기 좋은 PDF 문서입니다.&lt;/p&gt;
&lt;p&gt;당시 급하게 만든거라 오타나 미흡한 점들이 많습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;한컴 PDF&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;원본 PDF에서 개인정보나 표지는 뺀 버전입니다.&lt;/p&gt;
&lt;p&gt;목차가 생성되어있어 보기 좋지만, 일부 이미지가 압축과정에서 깨져보입니다.&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/JAThv/btqAVGLWAz9/bUaIR4ancyDYtgdl6Tfgy1/2019%20%EA%B3%B5%EA%B0%9CSW%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8C%80%ED%9A%8C%20%EA%B2%B0%EA%B3%BC%EB%B3%B4%EA%B3%A0%EC%84%9C_TerminalUX%28%EC%9C%A4%EB%AF%BC%EC%84%9D%29-%EC%9D%B4%EB%AF%B8%EC%A7%80%EA%B9%A8%EC%A7%90_%EC%B2%AB%EC%9E%A5%EC%A0%9C%EC%99%B8.pdf?attach=1&amp;amp;knm=tfile.pdf&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;2019 공개SW개발자대회 결과보고서_TerminalUX(윤민석)-이미지깨짐_첫장제외.pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;6.87MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;가상 프린터&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;이미지가 깨진 것이 보완된 버전입니다.&lt;/p&gt;
&lt;p&gt;단 목차가 없고, 용량이 커서 분할압축되어 있어요.&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/bNtaJI/btqAVGSIkur/Bs1ZNzvWw3YARzmqeLHKj0/2019%20%EA%B3%B5%EA%B0%9CSW%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8C%80%ED%9A%8C%20%EA%B2%B0%EA%B3%BC%EB%B3%B4%EA%B3%A0%EC%84%9C_TerminalUX%28%EC%9C%A4%EB%AF%BC%EC%84%9D%29-%EB%AA%A9%EC%B0%A8%EB%A7%81%ED%81%AC%EB%B9%84%EC%9E%91%EB%8F%99_%EC%B2%AB%EC%9E%A5%EC%A0%9C%EC%99%B8.z01?attach=1&amp;amp;knm=tfile.z01&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;2019 공개SW개발자대회 결과보고서_TerminalUX(윤민석)-목차링크비작동_첫장제외.z01&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;10.00MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/behPsS/btqARizgHWU/IrUW2FWEMqKhBhZjtPdAe1/2019%20%EA%B3%B5%EA%B0%9CSW%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8C%80%ED%9A%8C%20%EA%B2%B0%EA%B3%BC%EB%B3%B4%EA%B3%A0%EC%84%9C_TerminalUX%28%EC%9C%A4%EB%AF%BC%EC%84%9D%29-%EB%AA%A9%EC%B0%A8%EB%A7%81%ED%81%AC%EB%B9%84%EC%9E%91%EB%8F%99_%EC%B2%AB%EC%9E%A5%EC%A0%9C%EC%99%B8.z02?attach=1&amp;amp;knm=tfile.z02&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;2019 공개SW개발자대회 결과보고서_TerminalUX(윤민석)-목차링크비작동_첫장제외.z02&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;10.00MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/cvo0jj/btqARX9cM7X/Gxy5iOnr5g4kwzMiAhoNR1/2019%20%EA%B3%B5%EA%B0%9CSW%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8C%80%ED%9A%8C%20%EA%B2%B0%EA%B3%BC%EB%B3%B4%EA%B3%A0%EC%84%9C_TerminalUX%28%EC%9C%A4%EB%AF%BC%EC%84%9D%29-%EB%AA%A9%EC%B0%A8%EB%A7%81%ED%81%AC%EB%B9%84%EC%9E%91%EB%8F%99_%EC%B2%AB%EC%9E%A5%EC%A0%9C%EC%99%B8.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;2019 공개SW개발자대회 결과보고서_TerminalUX(윤민석)-목차링크비작동_첫장제외.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;4.27MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;웹 버전의 경우 일부 내용은 URL로 대체되고, 이미지나 오타가 바뀌었습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;1. 개발배경 및 목적&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;출품작명: BlaCk Void Zsh&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;프로그램 등록 URL: &lt;a href=&quot;https://github.com/black7375/BlaCk-Void-Zsh&quot;&gt;https://github.com/black7375/BlaCk-Void-Zsh&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;출품작 소개(요약): 명령어 인터페이스(CLI)를 위한 UI/UX를 정립하고, 설치, 사용 및 커스텀이 쉽게 만들어진 Zsh 스타터 킷.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;많은 개발자들은 &lt;b&gt;다양한 이유&lt;/b&gt;로 &lt;b&gt;터미널&lt;/b&gt;을 사용하게 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;차지하는 &lt;b&gt;리소스&lt;/b&gt;가 GUI에 비하면 적으며 &lt;b&gt;반복적인 일&lt;/b&gt;을 해야 하는 작업에서 특유의 &lt;b&gt;효율성&lt;/b&gt;을 발휘하기 때문에 애용하는 사람들이 있지만 어쩔 수 없는 이유로 사용하는 사람들 또한 존재합니다. 윈도우, 맥, 리눅스 등 &lt;b&gt;다양한 개발환경&lt;/b&gt;에 맞추다 보면 가장 &lt;b&gt;공통&lt;/b&gt;으로 적용할 수 &lt;b&gt;해결책&lt;/b&gt;이 명령어이기 때문입니다. 특히 리눅스의 경우 제가 알고 있는 데스크톱 환경만 10가지(Unity, KDE, Gnome, XFCE, LXDE, Cinammon, Mate, Budgie, Enlightenment, Pantheon 등)가 넘으며, &lt;b&gt;서버&lt;/b&gt;에서는 리소스 관리나 보안상 데스크톱 환경을 사용하지 않는 경향이 짙으므로 설정에 들어가서 &amp;lsquo;~~메뉴&amp;rsquo;를 찾아보라는 말은 통용되기가 어렵습니다. 따라서 각종 &lt;b&gt;문제를 해결&lt;/b&gt;하기 위해 검색하면 터미널 명령어가 많이 나오며 &lt;b&gt;반강제적&lt;/b&gt;으로 사용하게 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;그럼 현재 &lt;b&gt;CUI&lt;/b&gt;의 환경은 어떨지 &lt;b&gt;GUI&lt;/b&gt;와 비교해보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;GUI의 변화를 나타낸 하단 표와 스크린 캡처들처럼 &lt;b&gt;많은 변화&lt;/b&gt;가 있었습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;&quot; style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;2000년대&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;2019년&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;도구 모음&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;툴바&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;리본&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;메뉴 펼치기&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;드롭다운&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;메가 드롭다운&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;콘텐츠 표시&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;리스트&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;카드뷰&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;디자인 트렌드&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;스큐어모피즘&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;플랫&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2uvzx/btqATfO6dtq/RTCjtcVLzkDamHAeKrKrQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2uvzx/btqATfO6dtq/RTCjtcVLzkDamHAeKrKrQk/img.png&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;131&quot; data-filename=&quot;blob&quot; style=&quot;width: 50.8284%; margin-right: 10px;&quot; width=&quot;465&quot; height=&quot;370&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2uvzx/btqATfO6dtq/RTCjtcVLzkDamHAeKrKrQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2uvzx%2FbtqATfO6dtq%2FRTCjtcVLzkDamHAeKrKrQk%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;465&quot; height=&quot;131&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oEODo/btqARh1q40T/jSkDAxuKEXdyUh1SypTQq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oEODo/btqARh1q40T/jSkDAxuKEXdyUh1SypTQq1/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 48.0088%;&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oEODo/btqARh1q40T/jSkDAxuKEXdyUh1SypTQq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoEODo%2FbtqARh1q40T%2FjSkDAxuKEXdyUh1SypTQq1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;툴바와 리본&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/diCPK5/btqAQ3oPuPx/CwU8eHMpsG5GrzTDFPdhP1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/diCPK5/btqAQ3oPuPx/CwU8eHMpsG5GrzTDFPdhP1/img.gif&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 51.3318%; margin-right: 10px;&quot; width=&quot;465&quot; height=&quot;370&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/diCPK5/btqAQ3oPuPx/CwU8eHMpsG5GrzTDFPdhP1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdiCPK5%2FbtqAQ3oPuPx%2FCwU8eHMpsG5GrzTDFPdhP1%2Fimg.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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kCF7v/btqARxiJToL/9INgt1vNbrOK5l4TXyr0h0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kCF7v/btqARxiJToL/9INgt1vNbrOK5l4TXyr0h0/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 47.5054%;&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kCF7v/btqARxiJToL/9INgt1vNbrOK5l4TXyr0h0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkCF7v%2FbtqARxiJToL%2F9INgt1vNbrOK5l4TXyr0h0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;드롭다운과 메가드롭다운&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U2eD8/btqAQNGuN9M/o1FAeTY26xusDQSnQozNUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U2eD8/btqAQNGuN9M/o1FAeTY26xusDQSnQozNUK/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 63.2526%; margin-right: 10px;&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U2eD8/btqAQNGuN9M/o1FAeTY26xusDQSnQozNUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU2eD8%2FbtqAQNGuN9M%2Fo1FAeTY26xusDQSnQozNUK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsxhZx/btqAUvc8c6l/8YkdQWgkv4ZePTumNk827k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsxhZx/btqAUvc8c6l/8YkdQWgkv4ZePTumNk827k/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 35.5846%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsxhZx/btqAUvc8c6l/8YkdQWgkv4ZePTumNk827k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsxhZx%2FbtqAUvc8c6l%2F8YkdQWgkv4ZePTumNk827k%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;리스트와 카드뷰&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vdlmr/btqARxwdtG6/NCQ9QtIlc5scVlCNfUnzAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vdlmr/btqARxwdtG6/NCQ9QtIlc5scVlCNfUnzAk/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 49.3918%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vdlmr/btqARxwdtG6/NCQ9QtIlc5scVlCNfUnzAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVdlmr%2FbtqARxwdtG6%2FNCQ9QtIlc5scVlCNfUnzAk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bicWPA/btqARYNPVUl/CoaC6gquz1HfdSgndvzFHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bicWPA/btqARYNPVUl/CoaC6gquz1HfdSgndvzFHk/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 49.4454%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bicWPA/btqARYNPVUl/CoaC6gquz1HfdSgndvzFHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbicWPA%2FbtqARYNPVUl%2FCoaC6gquz1HfdSgndvzFHk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;스큐어모피즘의&amp;nbsp;대표인&amp;nbsp;&lt;a href=&quot;https://ko.wikipedia.org/wiki/IOS_6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IOS6&lt;/a&gt;와&amp;nbsp;플랫의&amp;nbsp;대표인&amp;nbsp;&lt;a href=&quot;https://ko.wikipedia.org/wiki/IOS_7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IOS7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;하지만 CUI의 경우, &lt;b&gt;1970&lt;/b&gt;년대의 CP/M이나 &lt;b&gt;2019&lt;/b&gt;년의 Powershell, Bash를 &lt;b&gt;비교&lt;/b&gt;해보면 크게 &lt;b&gt;다르지 않습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qKKSG/btqARYf0nY0/CKwTltQWpGbrLWhlakgwL0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qKKSG/btqARYf0nY0/CKwTltQWpGbrLWhlakgwL0/img.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 53.0058%; margin-right: 10px;&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qKKSG/btqARYf0nY0/CKwTltQWpGbrLWhlakgwL0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqKKSG%2FbtqARYf0nY0%2FCKwTltQWpGbrLWhlakgwL0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be6voq/btqAU7iM6jy/lNpTIMi0koR3QVtcw82kpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be6voq/btqAU7iM6jy/lNpTIMi0koR3QVtcw82kpk/img.png&quot; data-origin-width=&quot;751&quot; data-origin-height=&quot;564&quot; data-filename=&quot;blob&quot; style=&quot;width: 45.8314%;&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be6voq/btqAU7iM6jy/lNpTIMi0koR3QVtcw82kpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe6voq%2FbtqAU7iM6jy%2FlNpTIMi0koR3QVtcw82kpk%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;751&quot; height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;&lt;code&gt;dir&lt;/code&gt;를&amp;nbsp;실행한&amp;nbsp;1970년대의&amp;nbsp;&lt;a href=&quot;https://home.bt.com/tech-gadgets/computing/windows-10/what-would-the-world-be-like-without-bill-gates-11364008291876&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CP/M&lt;/a&gt;과&amp;nbsp;2019년의&amp;nbsp;Powershell&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;저는 리눅스를 주로 사용하는데 &lt;b&gt;빈번한 사용&lt;/b&gt;에 비해 너무나 &lt;b&gt;불편&lt;/b&gt;하고 &lt;b&gt;정적&lt;/b&gt;인 터미널 &lt;b&gt;환경&lt;/b&gt;이 불만이었습니다. 따라서 색, 아이콘, 동적 기능 등 &lt;b&gt;그래픽 요소&lt;/b&gt;를 도입하고 &lt;b&gt;강력한 추천&lt;/b&gt;과 &lt;b&gt;자동 완성&lt;/b&gt; 등으로 편리했으면 하는 생각이 들었습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;물론, 이러한 시도가 없지 않았습니다. 대표적인 것이 21세기의 터미널 에뮬레이터라 주장하는 &lt;b&gt;&lt;a href=&quot;https://github.com/railsware/upterm&quot;&gt;Upterm&lt;/a&gt;&lt;/b&gt;(Black Screen)입니다. &lt;b&gt;자동 완성&lt;/b&gt;, &lt;b&gt;상태 표시줄&lt;/b&gt;, &lt;b&gt;에러표시&lt;/b&gt; 등 편리한 기능을 제공했지만, 현재 메인테이너가 &lt;b&gt;없어지고&lt;/b&gt;, 터미널 에뮬레이터에 강제로 구현했기에 기존 Shell 환경과의 &lt;b&gt;호환성&lt;/b&gt;, &lt;b&gt;커스텀&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-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbF5vH/btqASynRG4t/KBQy4N4hehgXTQSydKtTFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbF5vH/btqASynRG4t/KBQy4N4hehgXTQSydKtTFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbF5vH/btqASynRG4t/KBQy4N4hehgXTQSydKtTFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbF5vH%2FbtqASynRG4t%2FKBQy4N4hehgXTQSydKtTFK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;Upterm에서 자동 완성과 상태 표시줄을 보여주는 사진&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;그 후 찾게 된 것이 바로 &lt;a href=&quot;https://www.zsh.org/&quot;&gt;&lt;b&gt;Zsh&lt;/b&gt;&lt;/a&gt;인데, 제가 원하는 요소 대부분이 있었습니다.&lt;/p&gt;
&lt;p&gt;특히 Shell의 오른쪽에 정보를 표시할 수 있는 &lt;b&gt;RPROMPT&lt;/b&gt;와 바로 선택이 가능한 &lt;b&gt;자동 완성&lt;/b&gt;, 다양한 플러그인 &lt;b&gt;생태계&lt;/b&gt;(&lt;a href=&quot;https://github.com/ohmyzsh/ohmyzsh&quot;&gt;Oh-My-Zsh&lt;/a&gt;, &lt;a href=&quot;https://github.com/sorin-ionescu/prezto&quot;&gt;Prezto&lt;/a&gt; 등)가 매력적이었습니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XR1Mp/btqAUvjS9JF/HpDqoCsyFXtsQmnvwcZOe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XR1Mp/btqAUvjS9JF/HpDqoCsyFXtsQmnvwcZOe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XR1Mp/btqAUvjS9JF/HpDqoCsyFXtsQmnvwcZOe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXR1Mp%2FbtqAUvjS9JF%2FHpDqoCsyFXtsQmnvwcZOe1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMWXw8/btqATgtJWi8/sOftmD5U9sOoCMQ20OiRL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMWXw8/btqATgtJWi8/sOftmD5U9sOoCMQ20OiRL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMWXw8/btqATgtJWi8/sOftmD5U9sOoCMQ20OiRL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMWXw8%2FbtqATgtJWi8%2FsOftmD5U9sOoCMQ20OiRL0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;RPROMPT가&amp;nbsp;없고,&amp;nbsp;자동완성&amp;nbsp;키를&amp;nbsp;누를시&amp;nbsp;리스트만&amp;nbsp;보여주는&amp;nbsp;것이&amp;nbsp;끝인&amp;nbsp;Bash와&amp;nbsp;RPROMPT를&amp;nbsp;지원하며&amp;nbsp;바로&amp;nbsp;선택이&amp;nbsp;가능한&amp;nbsp;Zsh&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;하지만 대부분의 OS에서 조금이라도 꾸밈, 설정을 제공하는 Bash(위 스크린 캡처는 Manjaro의 기본 설정 상태인 Bash, Zsh)와 달리 &lt;b&gt;황량한 모습&lt;/b&gt;입니다. 즉, 기본 구성 자체가 다른 shell과 다를 바 없거나 오히려 나쁜 모습으로 &lt;b&gt;매력이 없었&lt;/b&gt;습니다.&lt;/p&gt;
&lt;p&gt;다행히 Oh-My-Zsh, Prezto와 같은 &lt;b&gt;프레임워크&lt;/b&gt;는 좋은 기본 테마를 제공해주고 플러그인들은 많았지만, 편리하기 사용하기 위해서는 사용자의 &lt;b&gt;설정을 강요&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-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVZldc/btqATf2EbxU/7zDTpvHY5KxkuVktsXRmMk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVZldc/btqATf2EbxU/7zDTpvHY5KxkuVktsXRmMk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVZldc/btqATf2EbxU/7zDTpvHY5KxkuVktsXRmMk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVZldc%2FbtqATf2EbxU%2F7zDTpvHY5KxkuVktsXRmMk%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;Oh-My-Zsh의 기본 테마인 &lt;a href=&quot;https://github.com/ohmyzsh/ohmyzsh/wiki/Themes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;robbyrussell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;&lt;b&gt;Emacs&lt;/b&gt;&lt;/a&gt;의 기본 구성은 단출하지만 좋은 설계와 &lt;b&gt;UI/UX&lt;/b&gt; 설정으로 입문을 돕는 &lt;a href=&quot;https://www.spacemacs.org&quot;&gt;Spacemacs&lt;/a&gt;, &lt;a href=&quot;https://github.com/hlissner/doom-emacs&quot;&gt;Doom Emacs&lt;/a&gt;와는 같은 Unix 기반 툴이었지만 &lt;b&gt;대조적&lt;/b&gt;이었습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/conuSa/btqATfO6rfK/zybk7ikIRiaKNBuvFrSesK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/conuSa/btqATfO6rfK/zybk7ikIRiaKNBuvFrSesK/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 43.8764%; margin-right: 10px;&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/conuSa/btqATfO6rfK/zybk7ikIRiaKNBuvFrSesK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FconuSa%2FbtqATfO6rfK%2Fzybk7ikIRiaKNBuvFrSesK%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QKieX/btqAU7bYY8f/R4wkYvokCT11SaZNw8ni01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QKieX/btqAU7bYY8f/R4wkYvokCT11SaZNw8ni01/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; title=&quot;&quot; style=&quot;width: 54.9608%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QKieX/btqAU7bYY8f/R4wkYvokCT11SaZNw8ni01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQKieX%2FbtqAU7bYY8f%2FR4wkYvokCT11SaZNw8ni01%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Gnu&amp;nbsp;Emacs와&amp;nbsp;Spacemacs&amp;nbsp;공식&amp;nbsp;이미지&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;실제로 좋은 Zsh관련 List를 만들어 놓은 Awesome Zsh Plugins의 Tutorial을 보면 대부분 설정을 하는 방법에 대한 것이고, &lt;b&gt;스타터 킷&lt;/b&gt;이라 불릴만한 설정은 부족합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;애플이 없던 &lt;b&gt;스마트폰&lt;/b&gt;을 만든 것이 아니라 &lt;b&gt;기존에 존재&lt;/b&gt;하던 것들을 잘 조합하여 &lt;b&gt;아이폰&lt;/b&gt;을 만들었고 기능을 넣을 때도 똑같은 태도를 보였지만 엄청난 인기를 유지하는 것처럼, 기능을 최초로 만들거나 시도하지 않더라도 엔드유저를 위한 &lt;b&gt;완성된 경험&lt;/b&gt;을 제공하는 것은 매우 중요합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;CLI는 기본적으로 유닉스의 영역이기 때문에, &lt;b&gt;유닉스의 철학&lt;/b&gt;을 살려 &lt;b&gt;외부의 모듈&lt;/b&gt;을 잘 활용해 가볍고, &lt;b&gt;텍스트 파일&lt;/b&gt;을 이용한 설정을 제공하고자 합니다.&lt;/p&gt;
&lt;h2&gt;2. 개발환경 및 개발언어&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;리눅스가 깔린 노트북 2대(쿠분투, 만자로)에서 Emacs를 이용하여 작업하였습니다.언어는 &lt;b&gt;Zsh Shell Script&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;테스트용으로 High Sierra가 깔린 맥을 사용했습니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dq3dfP/btqAQN7zon6/QrXUYf63m0f5XMimQkqVr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dq3dfP/btqAQN7zon6/QrXUYf63m0f5XMimQkqVr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dq3dfP/btqAQN7zon6/QrXUYf63m0f5XMimQkqVr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdq3dfP%2FbtqAQN7zon6%2FQrXUYf63m0f5XMimQkqVr0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;Emacs에서&amp;nbsp;개발하는&amp;nbsp;모습&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;3. 시스템 구성 및 아키텍처&lt;/h2&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 설정 파일 로딩 순서&lt;/p&gt;
&lt;p&gt;&amp;nbsp;설정 파일 &lt;b&gt;로딩 순서&lt;/b&gt;는 &lt;b&gt;Zsh&lt;/b&gt;가 파일을 읽는 순서에 &lt;b&gt;의존&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p&gt;파일을 읽는 순서에 따라 Path 설정 후 사용 가능한 &lt;b&gt;명령어를 결정&lt;/b&gt;하고, &lt;b&gt;성능&lt;/b&gt;과 밀접하기에 Zsh가 파일을 로드하는 &lt;b&gt;순서&lt;/b&gt;를 아는 것은 &lt;b&gt;중요&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-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y9dVF/btqAVH5c5zR/KsDe8KIbxupf7vHh11vMQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y9dVF/btqAVH5c5zR/KsDe8KIbxupf7vHh11vMQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y9dVF/btqAVH5c5zR/KsDe8KIbxupf7vHh11vMQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy9dVF%2FbtqAVH5c5zR%2FKsDe8KIbxupf7vHh11vMQ0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Shell&amp;nbsp;들이&amp;nbsp;파일을&amp;nbsp;로드하는&amp;nbsp;순서[&lt;a href=&quot;https://blog.flowblok.id.au/2013-02/shell-startup-scripts.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Shell&amp;nbsp;Startup&amp;nbsp;Scripts&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Zsh가 로드하는 파일들에 대한 &lt;b&gt;설명&lt;/b&gt;과 &lt;b&gt;용도&lt;/b&gt;입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/etc/zshenv&lt;/code&gt;&lt;br /&gt;시스템에서 제공하는 &lt;b&gt;환경변수&lt;/b&gt;들, 항상 로드&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.zshenv&lt;/code&gt;&lt;br /&gt;사용자가 사용하는 &lt;b&gt;환경변수&lt;/b&gt;들, 항상 로드&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.zprofile&lt;/code&gt;&lt;br /&gt;메인 설정 파일인 &lt;code&gt;.zshrc&lt;/code&gt;를 &lt;b&gt;로드 직전&lt;/b&gt;에 로드, 로그인 시 로드 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.zshrc&lt;/code&gt;&lt;br /&gt;&lt;b&gt;메인 설정&lt;/b&gt; 파일이며 shell 모듈 로드 가능, 로그인 및 대화형일 때 로드 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.zlogin&lt;/code&gt;&lt;br /&gt;&lt;b&gt;로그인&lt;/b&gt; shell을 시작할 때 로드(X-Window를 로드 기능이 필요하면 여기에 설정), 로그인 시 로드&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.zlogout&lt;/code&gt;&lt;br /&gt;정리 및 재설정 용도, &lt;b&gt;로그아웃&lt;/b&gt; 시 로드&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;제 프로젝트의 로드 구성과 역할입니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VSsAP/btqAQOyB3HT/H6yz3b3X9Kyb29wpMfvCr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VSsAP/btqAQOyB3HT/H6yz3b3X9Kyb29wpMfvCr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VSsAP/btqAQOyB3HT/H6yz3b3X9Kyb29wpMfvCr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVSsAP%2FbtqAQOyB3HT%2FH6yz3b3X9Kyb29wpMfvCr0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;로드 순서&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;BlaCk-Void.zshenv&lt;/code&gt;&lt;br /&gt;홈 디렉터리에 있을 법만 한 것들(Application, bin, .local/bin, ..etc)과 패키지 매니저인 &lt;code&gt;cargo&lt;/code&gt;, &lt;code&gt;linux brew&lt;/code&gt;, &lt;code&gt;snap&lt;/code&gt; 등의 &lt;code class=&quot;&quot;&gt;&lt;b&gt;PATH&lt;/b&gt;&lt;/code&gt;를 확인하고 추가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;BlaCk-Void.zshrc&lt;/code&gt;&lt;br /&gt;역시 &lt;b&gt;메인 설정&lt;/b&gt; 파일&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;autoload/*&lt;/code&gt;&lt;br /&gt;각종 함수들이며 &lt;code&gt;BlaCk-Void.zshrc&lt;/code&gt;를 부른 직후에 &lt;b&gt;lazy 로드&lt;/b&gt;되도록 설정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;~/.ztheme&lt;/code&gt; or &lt;code&gt;BlaCk-Void.ztheme&lt;/code&gt;&lt;br /&gt;커스텀 가능한 &lt;b&gt;테마설정&lt;/b&gt; 파일, 일반 플러그인 로드 전에 로드&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;lib/*&lt;/code&gt;&lt;br /&gt;&lt;code&gt;BlaCk-Void.zshrc&lt;/code&gt;의 마지막에 로드&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;completion/*&lt;/code&gt;&lt;br /&gt;&lt;code&gt;lib/completion&lt;/code&gt;에서 &lt;code&gt;fpath&lt;/code&gt;에 추가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;BlaCk-Void.zlogin&lt;/code&gt;&lt;br /&gt;바이트 컴파일을 백그라운드로 진행하는 등 &lt;b&gt;최적화&lt;/b&gt; 관련 설정&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;BlaCk-Void-Zsh.sh&lt;/code&gt; &amp;amp;&amp;amp; &lt;code&gt;install_font.sh&lt;/code&gt;&lt;br /&gt;&lt;b&gt;설치&lt;/b&gt; 시 사용되는 파일&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;README.org&lt;/code&gt; &amp;amp;&amp;amp;　&lt;code&gt;LICENSE&lt;/code&gt;&lt;br /&gt;깃허브 README와 라이센스 내용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- ztheme 커스텀 구성&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tpVmP/btqATgAt3tj/9MK9MqrLcsCrjlSslGla91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tpVmP/btqATgAt3tj/9MK9MqrLcsCrjlSslGla91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tpVmP/btqATgAt3tj/9MK9MqrLcsCrjlSslGla91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtpVmP%2FbtqATgAt3tj%2F9MK9MqrLcsCrjlSslGla91%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;ztheme의 구조&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;테마는 &lt;code&gt;Color Mode&lt;/code&gt;, &lt;code&gt;Icon Mode&lt;/code&gt;, &lt;code&gt;Theme Mode&lt;/code&gt;로 이루어져 있습니다.&lt;/p&gt;
&lt;p&gt;Color Definition과 Icon Definition은 &lt;b&gt;즉시&lt;/b&gt; 실행되며, Apply to Theme는 &lt;b&gt;Theme Definition&lt;/b&gt;이 실행될 때 실행됩니다.&lt;/p&gt;
&lt;p&gt;일종의 객체지향처럼 &lt;b&gt;상속&lt;/b&gt;된다고 생각하면 됩니다.&lt;/p&gt;
&lt;h2&gt;4. 프로젝트 주요기능&lt;/h2&gt;
&lt;p&gt;CLI 경험을 향상 시키기 위해 &lt;b&gt;유형&lt;/b&gt;을 나눴습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;테마와 커스텀: 현재 디렉토리와 시스템의 &lt;b&gt;&amp;lsquo;상태&amp;rsquo;&lt;/b&gt;를 어떻게 보여주는가&lt;/li&gt;
&lt;li&gt;쉬운 입력: 명령어를 어떻게 해야 &lt;b&gt;&amp;lsquo;편하게&amp;rsquo;&lt;/b&gt; 칠 수 있는가&lt;/li&gt;
&lt;li&gt;유틸리티: 강력하고 다양한 &lt;b&gt;&amp;lsquo;기능&amp;rsquo;&lt;/b&gt;의 유틸리티가 있는가&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;가. 테마와 커스텀&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;oh-my-zsh의 내장, 외장테마들을 탐색결과 테마는 크게 두 종류로 나눌 수 있었습니다.&lt;/p&gt;
&lt;p&gt;배경색이 있고 &amp;lsquo;&amp;gt;&amp;rsquo;표시로 세그먼트를 구분하는 &lt;b&gt;파워라인&lt;/b&gt;과 우리가 보통 사용하는 &lt;b&gt;일반 배경&lt;/b&gt;의 테마입니다.(이하 심플테마)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-canonical-src=&quot;https://raw.github.com/b-ryan/powerline-shell/master/bash-powerline-screenshot.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NmxMc/btqAQ2KglQs/7YQXCXkxGVHTI7x6N3HQY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NmxMc/btqAQ2KglQs/7YQXCXkxGVHTI7x6N3HQY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NmxMc/btqAQ2KglQs/7YQXCXkxGVHTI7x6N3HQY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNmxMc%2FbtqAQ2KglQs%2F7YQXCXkxGVHTI7x6N3HQY1%2Fimg.png&quot; data-canonical-src=&quot;https://raw.github.com/b-ryan/powerline-shell/master/bash-powerline-screenshot.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot;&gt;파워라인 테마 &lt;a href=&quot;https://github.com/b-ryan/powerline-shell&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;예시&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;기본으로 주어지는 파워라인 테마는 &lt;b&gt;커스텀&lt;/b&gt;이 힘들었으므로, 충분한 커스텀 &lt;b&gt;옵션&lt;/b&gt;을 제공하는 테마를 찾아다녔습니다. 약간의 시간을 쓴 후 찾은 &lt;a href=&quot;https://github.com/Powerlevel9k/powerlevel9k&quot;&gt;Powerlevel9k&lt;/a&gt;란 테마 입니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byuosG/btqARYAkjQC/tAm4E3gwpNfLDlkmo11s7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byuosG/btqARYAkjQC/tAm4E3gwpNfLDlkmo11s7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byuosG/btqARYAkjQC/tAm4E3gwpNfLDlkmo11s7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyuosG%2FbtqARYAkjQC%2FtAm4E3gwpNfLDlkmo11s7k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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-canonical-src=&quot;http://bhilburn.org/content/images/2015/01/pl9k-improved.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb2P9r/btqAQOyB6Zv/LkaPtSPBGBA7QwCEmSKy9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb2P9r/btqAQOyB6Zv/LkaPtSPBGBA7QwCEmSKy9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb2P9r/btqAQOyB6Zv/LkaPtSPBGBA7QwCEmSKy9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb2P9r%2FbtqAQOyB6Zv%2FLkaPtSPBGBA7QwCEmSKy9K%2Fimg.png&quot; data-canonical-src=&quot;http://bhilburn.org/content/images/2015/01/pl9k-improved.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;Powerlevel9k&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;Powerlevel9k는 &lt;b&gt;다양한&lt;/b&gt; 세그먼트를 지원할 뿐만 아니라 &lt;a href=&quot;https://github.com/Powerlevel9k/powerlevel9k/wiki/Stylizing-Your-Prompt&quot;&gt;꾸미는 방법&lt;/a&gt;, &lt;a href=&quot;https://github.com/Powerlevel9k/powerlevel9k/wiki/Show-Off-Your-Config&quot;&gt;예시&lt;/a&gt;, &lt;a href=&quot;https://github.com/Powerlevel9k/powerlevel9k/wiki/User-Segments&quot;&gt;유저 세그먼트&lt;/a&gt;등의 문서화가 잘되어 &lt;b&gt;커스텀&lt;/b&gt;하기 편합니다.&lt;/p&gt;
&lt;h4&gt;1) 테마모드 소개&lt;/h4&gt;
&lt;p&gt;기본 파워라인 테마입니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxthvw/btqARx3Z3U7/JiHuQSFnxbVyp6HT77PPok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxthvw/btqARx3Z3U7/JiHuQSFnxbVyp6HT77PPok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxthvw/btqARx3Z3U7/JiHuQSFnxbVyp6HT77PPok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxthvw%2FbtqARx3Z3U7%2FJiHuQSFnxbVyp6HT77PPok%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;기본 테마(Powerline)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;프롬프트를 목적에 따라 &lt;b&gt;상하좌우&lt;/b&gt;로 분류하고, &lt;b&gt;대칭적&lt;/b&gt;으로 보이게 만들어 &lt;b&gt;안정적&lt;/b&gt;으로 보이게 만들었습니다. &lt;b&gt;윗줄&lt;/b&gt;은 &lt;b&gt;정보&lt;/b&gt;를 표시하고, &lt;b&gt;아랫줄&lt;/b&gt;은 &lt;b&gt;명령어&lt;/b&gt;를 입력하는 공간입니다. 또한, &lt;b&gt;왼쪽&lt;/b&gt;은 &lt;b&gt;사용자&lt;/b&gt;와 관련된 정보(계정, 루트 여부, SSH 사용 여부, 디렉토리 위치, 쓰기 권한, Git 등의 VCS 정보, 명령어 입력)를 표시하고, &lt;b&gt;오른쪽&lt;/b&gt;은 &lt;b&gt;시스템&lt;/b&gt;과 관련된 정보(명령 결과, 백그라운드 작업, 작업)를 표시해 줍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;윗줄의 파워라인은 &lt;b&gt;강렬한 원색계열&lt;/b&gt;(파란색, 초록색, 빨간색, 노란색)과 &lt;a href=&quot;https://github.com/ryanoasis/nerd-fonts&quot;&gt;Nerd Font&lt;/a&gt;의 아이콘으로 &lt;b&gt;시인성&lt;/b&gt;이 좋게 디자인하였습니다. 아랫줄은 명령어를 입력해야 하므로 IDE에서 코딩할 때처럼 &lt;a href=&quot;https://github.com/zsh-users/zsh-autosuggestions&quot;&gt;&lt;b&gt;자동추천&lt;/b&gt;&lt;/a&gt;(&amp;rarr;키로 완성), &lt;a href=&quot;https://github.com/zdharma/fast-syntax-highlighting&quot;&gt;&lt;b&gt;문법강조&lt;/b&gt;&lt;/a&gt; 기능을 사용했습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;두 번째 테마는 심플 테마 입니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg923v/btqARhAn9YN/5k65CawOysEhTWK38vKvF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg923v/btqARhAn9YN/5k65CawOysEhTWK38vKvF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg923v/btqARhAn9YN/5k65CawOysEhTWK38vKvF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg923v%2FbtqARhAn9YN%2F5k65CawOysEhTWK38vKvF1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;심플(Simple) 테마&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;심플한 테마들 중 주목할 만한 것은 &lt;a href=&quot;https://github.com/sindresorhus/pure&quot;&gt;Pure&lt;/a&gt;와 &lt;a href=&quot;https://github.com/denysdovhan/spaceship-prompt&quot;&gt;Spaceship&lt;/a&gt;이 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IGs8D/btqAUvqFbT9/okOkUQar4i6hZSt4DoFA2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IGs8D/btqAUvqFbT9/okOkUQar4i6hZSt4DoFA2K/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; title=&quot;&quot; style=&quot;width: 51.7101%; margin-right: 10px;&quot; width=&quot;864&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IGs8D/btqAUvqFbT9/okOkUQar4i6hZSt4DoFA2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIGs8D%2FbtqAUvqFbT9%2FokOkUQar4i6hZSt4DoFA2K%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYxuLI/btqATgAt6Mz/YcKilMQhgjBOusK2CwFUC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYxuLI/btqATgAt6Mz/YcKilMQhgjBOusK2CwFUC0/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 47.1271%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYxuLI/btqATgAt6Mz/YcKilMQhgjBOusK2CwFUC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYxuLI%2FbtqATgAt6Mz%2FYcKilMQhgjBOusK2CwFUC0%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Pure, Spaceship 테마&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;저는 둘 중 완전히 미니멀한 &lt;b&gt;Pure&lt;/b&gt; 테마에 매료되었습니다.&lt;/p&gt;
&lt;p&gt;다음은 Pure 테마가 보여주는 장점입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;입력 화살표의 색이 명령 성공/실패 여부에 따라 바뀜&lt;/li&gt;
&lt;li&gt;쓰기 권한과 루트 권한을 자물쇠로 표시&lt;/li&gt;
&lt;li&gt;SSH와 루트 유저일 때 사용자 정보 표시&lt;/li&gt;
&lt;li&gt;쓸모없는 아이콘들은 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;Pure 테마는 디자인상 &lt;b&gt;추상화를 극대화&lt;/b&gt;했고, &lt;b&gt;모든 정보를 강조&lt;/b&gt;해 보여주자는 파워라인 테마와 대조적입니다. 두 테마를 선택할 수 있게 하면 사용자들이 &lt;b&gt;원하는 경험&lt;/b&gt;을 &lt;b&gt;선택&lt;/b&gt;할 수 있을거라 예상했고, Powerlevel9k 커스텀 기능으로 &lt;b&gt;포팅&lt;/b&gt;한 것이 Simple 테마입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;마지막은 파워라인과 심플테마를 &lt;b&gt;1줄짜리&lt;/b&gt;로 만든 것들입니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Avt6p/btqATf9tDXL/1jV5l1whdeeVQJsYb9VKYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Avt6p/btqATf9tDXL/1jV5l1whdeeVQJsYb9VKYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Avt6p/btqATf9tDXL/1jV5l1whdeeVQJsYb9VKYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAvt6p%2FbtqATf9tDXL%2F1jV5l1whdeeVQJsYb9VKYK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLuOHK/btqAQ4nRs3G/26WSvGRZmSLD5bakWpUnz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLuOHK/btqAQ4nRs3G/26WSvGRZmSLD5bakWpUnz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLuOHK/btqAQ4nRs3G/26WSvGRZmSLD5bakWpUnz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLuOHK%2FbtqAQ4nRs3G%2F26WSvGRZmSLD5bakWpUnz0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;Powerline-Single, Simple-Single&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;각각 Oh-My-Zsh 내장 테마인 &lt;a href=&quot;https://github.com/ohmyzsh/ohmyzsh/wiki/themes#agnoster&quot;&gt;Agnoster&lt;/a&gt;와 &lt;a href=&quot;https://github.com/ohmyzsh/ohmyzsh/wiki/themes#fishy&quot;&gt;Fishy&lt;/a&gt;의 영향을 받았으며 &lt;b&gt;한 줄&lt;/b&gt;이기에 정보를 너무 많이 보여주면 명령어를 치는데 방해가 되므로, Simple 테마의 디자인 철학과 포팅했던 경험을 살렸습니다. &lt;b&gt;쓸데없는 정보&lt;/b&gt;들을 줄이고 오른쪽에 표시되도록 했습니다. 다만, Powerline-Single의 경우 RPROMPT의 색이 너무 강해(기본 테마에서는 Load의 녹색이 균형을 잡아줬었음), 명령어에 집중해야 할 사용자의 시&lt;b&gt;선을 분산&lt;/b&gt;시키므로 추후 &lt;b&gt;색을 조정&lt;/b&gt;할 예정입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;2) 컬러모드 소개&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;&lt;b&gt;Flex&lt;/b&gt;와 &lt;b&gt;Fixed&lt;/b&gt;모드로 나뉘어집니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;Flex 모드는 터미널 컬러 스킴(&lt;a href=&quot;https://github.com/mbadolato/iTerm2-Color-Schemes&quot;&gt;예시&lt;/a&gt;)을 따라가는 &lt;b&gt;유동적인 색감&lt;/b&gt;을 보여주고, Fixed는 제가 미리 설정해둔 색을 최대한 보여줄 수 있는 &lt;b&gt;고정된 색&lt;/b&gt; 모드로 제가 애용하고 있는 KDE에 내장된 Breeze 스킴을 기준으로 만들어졌습니다.&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;1082&quot; data-origin-height=&quot;211&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t0ron/btqARXIcY3l/ovKIMRlq4FFWjDSFOSHPNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t0ron/btqARXIcY3l/ovKIMRlq4FFWjDSFOSHPNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t0ron/btqARXIcY3l/ovKIMRlq4FFWjDSFOSHPNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft0ron%2FbtqARXIcY3l%2FovKIMRlq4FFWjDSFOSHPNK%2Fimg.png&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;211&quot; data-filename=&quot;blob&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;1081&quot; data-origin-height=&quot;210&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UNyEs/btqASz782EQ/ZAzDcNz4Krmop2NkUXxn51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UNyEs/btqASz782EQ/ZAzDcNz4Krmop2NkUXxn51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UNyEs/btqASz782EQ/ZAzDcNz4Krmop2NkUXxn51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUNyEs%2FbtqASz782EQ%2FZAzDcNz4Krmop2NkUXxn51%2Fimg.png&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;210&quot; data-filename=&quot;blob&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: center;&quot;&gt;Breeze 스킴에서 보여주는 Flex와 Fixed 모드&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;1073&quot; data-origin-height=&quot;216&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rglRs/btqARxwdMzY/HYw4pIWfKrf9Lj1AToKfG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rglRs/btqARxwdMzY/HYw4pIWfKrf9Lj1AToKfG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rglRs/btqARxwdMzY/HYw4pIWfKrf9Lj1AToKfG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrglRs%2FbtqARxwdMzY%2FHYw4pIWfKrf9Lj1AToKfG1%2Fimg.png&quot; data-origin-width=&quot;1073&quot; data-origin-height=&quot;216&quot; data-filename=&quot;blob&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;1074&quot; data-origin-height=&quot;206&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by5Glu/btqAQ3CkK6e/6Vr6jRnit10NkflIFIbuxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by5Glu/btqAQ3CkK6e/6Vr6jRnit10NkflIFIbuxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by5Glu/btqAQ3CkK6e/6Vr6jRnit10NkflIFIbuxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby5Glu%2FbtqAQ3CkK6e%2F6Vr6jRnit10NkflIFIbuxK%2Fimg.png&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;206&quot; data-filename=&quot;blob&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: center;&quot;&gt;Linux 스킴에서 보여주는 Flex와 Fixed 모드.&lt;br /&gt;Fixed 모드의 색은 거의 일정하다는 것을 알 수 있다&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;3) 아이콘모드 소개&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;아이콘 모드는 &lt;b&gt;Nerd&lt;/b&gt;와 &lt;b&gt;Powerline&lt;/b&gt;이 있습니다.&lt;/p&gt;
&lt;p&gt;이 둘은 앞서 &lt;b&gt;테마&lt;/b&gt;에서 나왔었는데 Nerd 폰트는 유니코드 폰트의 개인영역에 Powerline, Powerline Extra Symbols, Font Awesome, Font Awesome Extension, Devicons, Weather Icons, Material Design 등등 &lt;b&gt;3,693 개&lt;/b&gt;를 추가한 것입니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVfJnD/btqATf2Erv7/gIRKzfkyTLpBbLJm1u47s0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVfJnD/btqATf2Erv7/gIRKzfkyTLpBbLJm1u47s0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVfJnD/btqATf2Erv7/gIRKzfkyTLpBbLJm1u47s0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVfJnD%2FbtqATf2Erv7%2FgIRKzfkyTLpBbLJm1u47s0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;Nerd Fonts 구성&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;Powerline Symbol들은 코딩용 폰트에 기본적으로 &lt;b&gt;내장&lt;/b&gt;되어 있는 경우가 많지만, Nerd Font에 들어가는 아이콘들은 따로 &lt;b&gt;패치&lt;/b&gt;를 하거나 &lt;b&gt;패치된 폰트&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-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8vZsD/btqAVHjPFDd/EIUZY3fZmbl1D3Y1pMso3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8vZsD/btqAVHjPFDd/EIUZY3fZmbl1D3Y1pMso3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8vZsD/btqAVHjPFDd/EIUZY3fZmbl1D3Y1pMso3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8vZsD%2FbtqAVHjPFDd%2FEIUZY3fZmbl1D3Y1pMso3k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WhcXu/btqASyuDihW/qt44D8sc9uLWikUsnw6cWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WhcXu/btqASyuDihW/qt44D8sc9uLWikUsnw6cWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WhcXu/btqASyuDihW/qt44D8sc9uLWikUsnw6cWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWhcXu%2FbtqASyuDihW%2Fqt44D8sc9uLWikUsnw6cWK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;Nerd와 Powerline 모드&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;4) Auto모드 소개&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;제가 사용하는 X-Window나 Mac GUI 터미널 에뮬레이터들에서는 제대로 동작하지만, Xterm 256색을 &lt;b&gt;지원하지 않는&lt;/b&gt; 터미널을 사용하거나 SSH 환경에서 Nerd Font를 사용하도록 하는 것은 다른 사용자들에게 &lt;b&gt;피해가 갈 수&lt;/b&gt; 있으므로(깨져 보임) &lt;b&gt;자동으로 표현&lt;/b&gt;해줘야 할 필요가 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 테마&lt;/p&gt;
&lt;p&gt;기본값은 &lt;b&gt;많은 정보&lt;/b&gt;를 보여줄 수 있는 &lt;code&gt;Powerline&lt;/code&gt;이지만, Xterm 256 컬러를 지원하지 않으면 파워라인의 &lt;b&gt;시인성&lt;/b&gt;이 급격히 떨어지므로, &lt;code&gt;Simple&lt;/code&gt; 테마를 사용합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 컬러&lt;/p&gt;
&lt;p&gt;기본값은 &lt;b&gt;동일한&lt;/b&gt; 사용자 경험을 제공해주기 위해 &lt;code&gt;Fixed&lt;/code&gt;이지만, Xterm 256 &lt;b&gt;컬러가 없다&lt;/b&gt;면 &lt;code&gt;Fixed&lt;/code&gt; 모드 자체를 쓸 수 없으므로, &lt;code&gt;Flex&lt;/code&gt; 모드로 전환됩니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ssww3/btqARi68D3K/ZFKir1B2AyheWxMe1aihNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ssww3/btqARi68D3K/ZFKir1B2AyheWxMe1aihNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ssww3/btqARi68D3K/ZFKir1B2AyheWxMe1aihNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fssww3%2FbtqARi68D3K%2FZFKir1B2AyheWxMe1aihNk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;머터리얼 스킴&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Flex&amp;nbsp;모드는&amp;nbsp;일부&amp;nbsp;스킴에서&amp;nbsp;내용이&amp;nbsp;잘&amp;nbsp;안&amp;nbsp;보이는&amp;nbsp;일도&amp;nbsp;있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 아이콘&lt;/p&gt;
&lt;p&gt;기본값은 &lt;b&gt;이쁘고 많은&lt;/b&gt; 아이콘 들을 보여줄 수 있는 &lt;code&gt;Nerd&lt;/code&gt;이지만, ssh나 root일 경우 폰트 &lt;b&gt;설치문제&lt;/b&gt;로 &lt;code&gt;Powerline&lt;/code&gt; 모드를 사용했습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;5. 커스텀 하기&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 커스텀 시작&lt;/p&gt;
&lt;p&gt;ztheme 파일을 &lt;b&gt;홈으로 복사&lt;/b&gt;한 후 작업하면 되는 간단한 방식입니다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;cp $BVZSH/BlaCk-Void.ztheme ~/.ztheme&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;보통 유닉스 프로그램들이 &lt;code&gt;~/&lt;/code&gt;또는 &lt;code&gt;~/.config&lt;/code&gt;에 설정 파일을 복사하면 &lt;b&gt;사용자 설정&lt;/b&gt;을 사용하는 것과 같습니다. Zsh가 &lt;code&gt;~/&lt;/code&gt;에서 &lt;code&gt;.zshrc&lt;/code&gt;, &lt;code&gt;.zshenv&lt;/code&gt; 등을 로드 하므로 저도 &lt;code&gt;~/&lt;/code&gt;에서 설정하도록 했습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 커스텀 적용&lt;/p&gt;
&lt;p&gt;터미널을 &lt;b&gt;다시 시작&lt;/b&gt;하거나, &lt;b&gt;새로운 세션&lt;/b&gt;을 시작하면 됩니다.&lt;/p&gt;
&lt;p&gt;사용하는 도중에 적용하는 것은 테마 &lt;b&gt;캐싱 문제&lt;/b&gt;로 지원하지 않습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;6. 유용한 문서와 명령어들&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 기본&lt;/p&gt;
&lt;p&gt;각종 &lt;b&gt;모드 전환&lt;/b&gt;은 &lt;b&gt;상수&lt;/b&gt;들을 바꿔주기만 하면 됩니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;테마(BVZSH_THEME): &lt;code&gt;auto&lt;/code&gt;, &lt;code&gt;powerline&lt;/code&gt;, &lt;code&gt;simple&lt;/code&gt;, &lt;code&gt;powerline-single&lt;/code&gt;, &lt;code&gt;simple-single&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;컬러(BVZSH_COLOR): &lt;code&gt;auto&lt;/code&gt;, &lt;code&gt;flex&lt;/code&gt;, &lt;code&gt;fixed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;아이콘(BVZSH_ICON): &lt;code&gt;auto&lt;/code&gt;, &lt;code&gt;nerd&lt;/code&gt;, &lt;code&gt;powerline&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 테마&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Powerlevel9k와 호환되므로 Powerlevel9k의 문서들(&lt;a href=&quot;https://github.com/Powerlevel9k/powerlevel9k/blob/master/README.md&quot;&gt;README&lt;/a&gt;, &lt;a href=&quot;https://github.com/Powerlevel9k/powerlevel9k/wiki/Show-Off-Your-Config&quot;&gt;예시&lt;/a&gt;, &lt;a href=&quot;https://github.com/Powerlevel9k/powerlevel9k/wiki/Stylizing-Your-Prompt&quot;&gt;꾸미는 방법&lt;/a&gt;, &lt;a href=&quot;https://github.com/Powerlevel9k/powerlevel9k/wiki/User-Segments&quot;&gt;사용자 세그먼트&lt;/a&gt;) 활용&lt;/li&gt;
&lt;li&gt;Powerlevel10k의 &lt;a href=&quot;https://github.com/romkatv/powerlevel10k/tree/master/config&quot;&gt;설정들&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/black7375/BlaCk-Void-Zsh/blob/master/BlaCk-Void.ztheme&quot;&gt;ztheme&lt;/a&gt; &lt;b&gt;파일 내부&lt;/b&gt;에 들어있는 문서&lt;/li&gt;
&lt;li&gt;Oh-My-Zsh에 있는 &lt;a href=&quot;https://github.com/ohmyzsh/ohmyzsh/wiki/Themes&quot;&gt;내부테마&lt;/a&gt;, &lt;a href=&quot;https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes&quot;&gt;외부테마&lt;/a&gt; &lt;b&gt;디자인&lt;/b&gt;들&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 컬러&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;아치위키의 Zsh 문서 중 &lt;a href=&quot;https://wiki.archlinux.org/index.php/Zsh#Colors&quot;&gt;Colors&lt;/a&gt;나 또 다른 &lt;a href=&quot;https://jonasjacek.github.io/colors/&quot;&gt;Xterm Color&lt;/a&gt; 설명&lt;/li&gt;
&lt;li&gt;유용한 명령어 리스트
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;for code ({000..255}) print -P -- &quot;$code: %F{$code}This is how your text would look like%f&quot;&lt;/code&gt; : Xterm &lt;b&gt;256 Color&lt;/b&gt;를 보여준다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getColorCode forground&lt;/code&gt;: &lt;b&gt;글씨&lt;/b&gt;에 색들이 적용된 것을 보여준다.&lt;br /&gt;&lt;code&gt;getColorCode background&lt;/code&gt;: &lt;b&gt;배경&lt;/b&gt;에 색들이 적용된 것을 보여준다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POWERLEVEL9K_{ELEMENT}_FOREGROUND=COLOR&lt;/code&gt;: 테마의 &lt;b&gt;글씨&lt;/b&gt;에 색 적용&lt;br /&gt;&lt;code&gt;POWERLEVEL9K_{ELEMENT}_BACKGROUND=COLOR&lt;/code&gt;: 테마의 &lt;b&gt;배경&lt;/b&gt;에 색 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 아이콘&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nerdfonts.com/&quot;&gt;Nerd Font&lt;/a&gt;, &lt;a href=&quot;https://github.com/ryanoasis/powerline-extra-symbols&quot;&gt;Powerline Extra Symbols&lt;/a&gt;, &lt;a href=&quot;https://unicode-table.com/&quot;&gt;Unicode Table&lt;/a&gt;, &lt;a href=&quot;https://getemoji.com/&quot;&gt;Emoji&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;유용한 명령어 리스트
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get_icon_names&lt;/code&gt;: 적용된 아이콘 &lt;b&gt;내역&lt;/b&gt;을 보여준다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POWERLEVEL9K_{ICONNAME}_ICON=ICON&lt;/code&gt;: 아이콘을 테마에 &lt;b&gt;적용&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;7) VCS 변경 시 프롬프트&lt;/h4&gt;
&lt;p&gt;마지막으로 Git 같은 VCS가 변경되었을 때 &lt;b&gt;프롬프트의 변화&lt;/b&gt;를 보여주고자 합니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d0kGMh/btqAVIiJZRl/Kve6MPMPl2J9Y360K6buBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d0kGMh/btqAVIiJZRl/Kve6MPMPl2J9Y360K6buBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d0kGMh/btqAVIiJZRl/Kve6MPMPl2J9Y360K6buBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd0kGMh%2FbtqAVIiJZRl%2FKve6MPMPl2J9Y360K6buBK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;원본상태&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-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JSX0j/btqASynR5Ic/K9hSP0rbCV4lRUakUSlkfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JSX0j/btqASynR5Ic/K9hSP0rbCV4lRUakUSlkfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JSX0j/btqASynR5Ic/K9hSP0rbCV4lRUakUSlkfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJSX0j%2FbtqASynR5Ic%2FK9hSP0rbCV4lRUakUSlkfk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;아무&amp;nbsp;파일/디렉토리&amp;nbsp;추가&amp;nbsp;&amp;ndash;&amp;nbsp;&lt;b&gt;물음표&lt;/b&gt;가&amp;nbsp;생긴다&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dY1nOL/btqATg1Cqx1/nCJXjgV2NbybMFiTWIGKK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dY1nOL/btqATg1Cqx1/nCJXjgV2NbybMFiTWIGKK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dY1nOL/btqATg1Cqx1/nCJXjgV2NbybMFiTWIGKK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdY1nOL%2FbtqATg1Cqx1%2FnCJXjgV2NbybMFiTWIGKK0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;파일&amp;nbsp;수정&amp;nbsp;&amp;ndash;&amp;nbsp;&lt;b&gt;&amp;lsquo;o&amp;rsquo;표시&lt;/b&gt;와&amp;nbsp;함께&amp;nbsp;&lt;b&gt;주황색&lt;/b&gt;으로&amp;nbsp;바뀐다&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5eLGg/btqAQ2DrGhz/myrdEwOTNUJMTr8aKfjsi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5eLGg/btqAQ2DrGhz/myrdEwOTNUJMTr8aKfjsi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5eLGg/btqAQ2DrGhz/myrdEwOTNUJMTr8aKfjsi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5eLGg%2FbtqAQ2DrGhz%2FmyrdEwOTNUJMTr8aKfjsi0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;스태이징&amp;nbsp;-&amp;nbsp;&lt;b&gt;&amp;lsquo;+&amp;rsquo;&lt;/b&gt;로&amp;nbsp;변경된다&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBu8Na/btqARXIc4Vz/7nroOutfaI3A5sZ8KmzI3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBu8Na/btqARXIc4Vz/7nroOutfaI3A5sZ8KmzI3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBu8Na/btqARXIc4Vz/7nroOutfaI3A5sZ8KmzI3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBu8Na%2FbtqARXIc4Vz%2F7nroOutfaI3A5sZ8KmzI3K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;커밋&amp;nbsp;&amp;ndash;&amp;nbsp;&lt;b&gt;초록색&lt;/b&gt;으로&amp;nbsp;변하고&amp;nbsp;&lt;b&gt;위쪽&amp;nbsp;화살표&lt;/b&gt;가&amp;nbsp;뜬다&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgWfeQ/btqAU6xqcSI/vqbeLsCPa8byEFZZbo3Mt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgWfeQ/btqAU6xqcSI/vqbeLsCPa8byEFZZbo3Mt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgWfeQ/btqAU6xqcSI/vqbeLsCPa8byEFZZbo3Mt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgWfeQ%2FbtqAU6xqcSI%2FvqbeLsCPa8byEFZZbo3Mt0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;푸시&amp;nbsp;&amp;ndash;&amp;nbsp;&lt;b&gt;화살표&lt;/b&gt;가&amp;nbsp;사라진다&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;나. 쉬운 입력&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;IDE와 GUI 프로그램 등에서 적용할만한 &lt;b&gt;다양한&lt;/b&gt; 방법을 통해 입력하는 방식을 편하게 만들고자 했습니다. 대표적인 예가 테마에서도 등장했던 &lt;b&gt;자동추천&lt;/b&gt;과 &lt;b&gt;문법강조&lt;/b&gt; 기능입니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRgwnl/btqAQ2XMYiX/ynwvesS1bzLPPLYIrAZLm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRgwnl/btqAQ2XMYiX/ynwvesS1bzLPPLYIrAZLm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRgwnl/btqAQ2XMYiX/ynwvesS1bzLPPLYIrAZLm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRgwnl%2FbtqAQ2XMYiX%2FynwvesS1bzLPPLYIrAZLm1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;자동추천과 문법강조&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;1) 자동 짝맞춤&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;IDE를 사용할 때 가장 편한 기능 중 하나는 &amp;ldquo;&amp;rdquo;, &amp;lsquo;&amp;rsquo;, ``, {}, [], ()등 &lt;b&gt;짝&lt;/b&gt;으로 쓰는 것들을 같이 입력해주는 것입니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JVRfb/btqASyBoBfJ/28JTObyi2SKGjI8dKy5k01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JVRfb/btqASyBoBfJ/28JTObyi2SKGjI8dKy5k01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JVRfb/btqASyBoBfJ/28JTObyi2SKGjI8dKy5k01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJVRfb%2FbtqASyBoBfJ%2F28JTObyi2SKGjI8dKy5k01%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://github.com/hlissner/zsh-autopair&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;zsh-autopair&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;2) 자동 수정&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;명령어가 틀렸을 때 &lt;b&gt;자동&lt;/b&gt;으로 제안해주며, 명령이 실패할 때 &lt;b&gt;&lt;code class=&quot;&quot;&gt;fuck&lt;/code&gt;&lt;/b&gt;을 입력하면 &lt;b&gt;수정&lt;/b&gt;된 명령어를 제안해줍니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2oraM/btqAThMYifm/hl8WEPWzIj8WCglUBauU3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2oraM/btqAThMYifm/hl8WEPWzIj8WCglUBauU3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2oraM/btqAThMYifm/hl8WEPWzIj8WCglUBauU3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2oraM%2FbtqAThMYifm%2Fhl8WEPWzIj8WCglUBauU3K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/command-not-found&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Command Not Found&lt;/a&gt;, &lt;a href=&quot;https://github.com/nvbn/thefuck&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Thefuck&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;3) 제안&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;명령어를 치고 난 후 &lt;b&gt;단축어&lt;/b&gt;를 알려줄 수 있고,&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDgnbt/btqAQ3PTuK9/c0FwKjbC6Klxo0fJJBAWxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDgnbt/btqAQ3PTuK9/c0FwKjbC6Klxo0fJJBAWxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDgnbt/btqAQ3PTuK9/c0FwKjbC6Klxo0fJJBAWxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDgnbt%2FbtqAQ3PTuK9%2Fc0FwKjbC6Klxo0fJJBAWxk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://github.com/djui/alias-tips&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Alias tip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;명령어를 치는 도중 &lt;b&gt;&amp;lt;TAB&amp;gt;&lt;/b&gt;을 누르면 정보를 보여주는 completion 기능이 있습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;아래의 예시 2가지를 보면 정말 많은 정보를 그룹별로 묶어 &lt;b&gt;직관적&lt;/b&gt;으로 표시해줍니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rC9Yk/btqARh1rAyI/cAQ1CorHzWlrF8ZvqoFjNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rC9Yk/btqARh1rAyI/cAQ1CorHzWlrF8ZvqoFjNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rC9Yk/btqARh1rAyI/cAQ1CorHzWlrF8ZvqoFjNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrC9Yk%2FbtqARh1rAyI%2FcAQ1CorHzWlrF8ZvqoFjNK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RVgLq/btqARi0j0Pq/cvka1KkMLfdQ5AwuIbXfXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RVgLq/btqARi0j0Pq/cvka1KkMLfdQ5AwuIbXfXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RVgLq/btqARi0j0Pq/cvka1KkMLfdQ5AwuIbXfXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRVgLq%2FbtqARi0j0Pq%2Fcvka1KkMLfdQ5AwuIbXfXK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Git 관련 자동완성&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;원래 있던 자동완성보다 &lt;b&gt;편의성&lt;/b&gt;이 훨씬 올라간 것을 볼 수 있습니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMWXw8/btqATgtJWi8/sOftmD5U9sOoCMQ20OiRL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMWXw8/btqATgtJWi8/sOftmD5U9sOoCMQ20OiRL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMWXw8/btqATgtJWi8/sOftmD5U9sOoCMQ20OiRL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMWXw8%2FbtqATgtJWi8%2FsOftmD5U9sOoCMQ20OiRL0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;원래의 자동완성 기능&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;4) 히스토리 검색&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;전에 쳤던 명령어로 이동하는 키는 bash, zsh 모두 위쪽 화살표(&amp;uarr;)입니다. 치고 있던 명령어를 기반으로 결과를 얻고 싶다면, 그저 치던 도중 &lt;b&gt;위쪽 화살표(&amp;uarr;)&lt;/b&gt;를 누르면 됩니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAkJZA/btqAQOZInAK/SOEO5nIGu9RAamjL1VqGQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAkJZA/btqAQOZInAK/SOEO5nIGu9RAamjL1VqGQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAkJZA/btqAQOZInAK/SOEO5nIGu9RAamjL1VqGQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAkJZA%2FbtqAQOZInAK%2FSOEO5nIGu9RAamjL1VqGQ1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OwKC3/btqAU6EaWm7/EywqXo2ZOGdi8CTuOkVtc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OwKC3/btqAU6EaWm7/EywqXo2ZOGdi8CTuOkVtc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OwKC3/btqAU6EaWm7/EywqXo2ZOGdi8CTuOkVtc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOwKC3%2FbtqAU6EaWm7%2FEywqXo2ZOGdi8CTuOkVtc1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;&lt;a href=&quot;https://github.com/zsh-users/zsh-history-substring-search&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;zsh-history-substring-search&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;5) Fzf와 통합&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;터미널용 증분 검색기인 &lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;Fzf&lt;/a&gt;와 통합되었습니다.&lt;/p&gt;
&lt;p&gt;Fzf가 도대체 무엇이냐면, 아래 스크린 캡처처럼 동적인 필터로 &lt;b&gt;검색기능&lt;/b&gt;을 제공합니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UiEAL/btqAQ3bhCgI/U9jxgczSkhgR1rMsizkbm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UiEAL/btqAQ3bhCgI/U9jxgczSkhgR1rMsizkbm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UiEAL/btqAQ3bhCgI/U9jxgczSkhgR1rMsizkbm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUiEAL%2FbtqAQ3bhCgI%2FU9jxgczSkhgR1rMsizkbm1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;Fzf&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;색은 테마, 자동완성과 &lt;b&gt;일관성&lt;/b&gt;을 갖추기 위해 빨간색과 노란색으로 이루어져 있습니다. 이미 선택된 오브젝트는 강조를 줄이기 위해 일반 텍스트 색과 동일하게 만들었습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;Fzf를 이용할만한 &lt;b&gt;작업들&lt;/b&gt;은 무엇이 있을까요?&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;리스트&lt;/b&gt;로 찾아야 하는 &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;kill&lt;/code&gt;, &lt;code&gt;history&lt;/code&gt; 등 수많은 작업들을 빠르게 할 수 있습니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zkHRx/btqAQ3oPYhX/IeaYgRiWGruo9F1OtEbTqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zkHRx/btqAQ3oPYhX/IeaYgRiWGruo9F1OtEbTqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zkHRx/btqAQ3oPYhX/IeaYgRiWGruo9F1OtEbTqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzkHRx%2FbtqAQ3oPYhX%2FIeaYgRiWGruo9F1OtEbTqK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ew05D/btqAUvqFrWB/1Gun9jtYTfGKBEGYc4puP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ew05D/btqAUvqFrWB/1Gun9jtYTfGKBEGYc4puP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ew05D/btqAUvqFrWB/1Gun9jtYTfGKBEGYc4puP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEw05D%2FbtqAUvqFrWB%2F1Gun9jtYTfGKBEGYc4puP0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Phdnd/btqARjruyPI/EAcKWk43wKPRWlhGZCtYH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Phdnd/btqARjruyPI/EAcKWk43wKPRWlhGZCtYH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Phdnd/btqARjruyPI/EAcKWk43wKPRWlhGZCtYH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPhdnd%2FbtqARjruyPI%2FEAcKWk43wKPRWlhGZCtYH1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nNQsa/btqARxwd49m/yt7q9Ck63pzc2wlTr9vYp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nNQsa/btqARxwd49m/yt7q9Ck63pzc2wlTr9vYp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nNQsa/btqARxwd49m/yt7q9Ck63pzc2wlTr9vYp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnNQsa%2FbtqARxwd49m%2Fyt7q9Ck63pzc2wlTr9vYp0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;심지어 커밋 내역을 &lt;b&gt;GUI&lt;/b&gt;처럼 보면서 작업하는 것도 가능해집니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3Wz39/btqAUurJCgc/YKJCSBvWqieaOSPpCt7KW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3Wz39/btqAUurJCgc/YKJCSBvWqieaOSPpCt7KW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3Wz39/btqAUurJCgc/YKJCSBvWqieaOSPpCt7KW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3Wz39%2FbtqAUurJCgc%2FYKJCSBvWqieaOSPpCt7KW0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://github.com/wfxr/forgit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;forgit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;터미널을 &lt;b&gt;마법&lt;/b&gt;의 공간으로 만드는 공신이라 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;그럼 &lt;b&gt;모든 곳&lt;/b&gt;에 Fzf를 적용시키는 것이 좋을까요?&lt;/p&gt;
&lt;p&gt;그렇지는 않습니다. Fzf가 우리에게 보여주는 정보는 &lt;b&gt;선형적&lt;/b&gt;입니다. 따라서 평소에는 여러 가지 그룹으로 나누어 보여줄 수 있는 &lt;b&gt;자동완성&lt;/b&gt;을 사용하고, 정보들의 &lt;b&gt;차이가 없거나 양들이 많을 때&lt;/b&gt; 사용하는 것이 좋다고 생각합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;6) 기타&lt;/h4&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 편리한 Git&lt;/p&gt;
&lt;p&gt;사용아주 간단하게 git을 사용할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;c&lt;/code&gt;: commit&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt;: add&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p&lt;/code&gt;: push&lt;/li&gt;
&lt;li&gt;&lt;code&gt;u&lt;/code&gt;: pull(update)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt;: remote&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt;: status&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 디렉토리 이동&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coZ89Z/btqAUvRJSR9/jn8Iu1xFvzr6EEsplIkjmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coZ89Z/btqAUvRJSR9/jn8Iu1xFvzr6EEsplIkjmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coZ89Z/btqAUvRJSR9/jn8Iu1xFvzr6EEsplIkjmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoZ89Z%2FbtqAUvRJSR9%2Fjn8Iu1xFvzr6EEsplIkjmk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;디렉토리 이동 관련 기능&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bookmark [mark]&lt;/code&gt;: &lt;code&gt;[mark]&lt;/code&gt;를 &lt;b&gt;북마크&lt;/b&gt;로 저장한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jump [mark]&lt;/code&gt;: &lt;code&gt;[mark]&lt;/code&gt;된 곳으로 &lt;b&gt;이동&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;showmarks [mark]&lt;/code&gt;: &lt;code&gt;[mark]&lt;/code&gt;된 디렉토리들을 &lt;b&gt;보여&lt;/b&gt;준다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deletemark [mark]&lt;/code&gt;: &lt;code&gt;[mark]&lt;/code&gt;를 &lt;b&gt;지운&lt;/b&gt;다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd &amp;lt;dots&amp;gt;&lt;/code&gt; : &lt;code&gt;&amp;lt;dots&amp;gt;&lt;/code&gt;의 개수만큼 &lt;b&gt;상위 디렉토리&lt;/b&gt;로 이동한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;j [keyword]&lt;/code&gt;: &lt;code&gt;[keyword]&lt;/code&gt;와 비슷한 &lt;b&gt;디렉토리로 이동&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;다. 유틸리티&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;유틸리티에서는 터미널에서 사용할 수 있는 기타 유용한 도구들을 다룹니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- h&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNMErw/btqAQ2KgEPJ/EHqDbm5QBSGYvy3FNrdOM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNMErw/btqAQ2KgEPJ/EHqDbm5QBSGYvy3FNrdOM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNMErw/btqAQ2KgEPJ/EHqDbm5QBSGYvy3FNrdOM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNMErw%2FbtqAQ2KgEPJ%2FEHqDbm5QBSGYvy3FNrdOM0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://github.com/paoloantinori/hhighlighter&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;hhighlighter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;여러 가지 문자를 강조해줍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 인터넷 유틸리티&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l4Pw0/btqAU5yucom/VWcicgd3e7HH0Qq2lkExtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l4Pw0/btqAU5yucom/VWcicgd3e7HH0Qq2lkExtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l4Pw0/btqAU5yucom/VWcicgd3e7HH0Qq2lkExtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl4Pw0%2FbtqAU5yucom%2FVWcicgd3e7HH0Qq2lkExtK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;&lt;a href=&quot;https://github.com/denilsonsa/prettyping&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;prettyping&lt;/a&gt;, ip-info&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그래픽이 포함된 &lt;b&gt;핑&lt;/b&gt;과 &lt;b&gt;ip&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-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7b6Ni/btqARxJMOzv/HeZfRSX6ucjEmCd53sCLdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7b6Ni/btqARxJMOzv/HeZfRSX6ucjEmCd53sCLdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7b6Ni/btqARxJMOzv/HeZfRSX6ucjEmCd53sCLdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7b6Ni%2FbtqARxJMOzv%2FHeZfRSX6ucjEmCd53sCLdK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/urltools&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;urltools&lt;/a&gt; + urlshort&lt;/p&gt;
&lt;p&gt;&lt;b&gt;URL&lt;/b&gt;의 인코딩, 디코딩, 축약을 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 이미지 뷰어&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://w3m.sourceforge.net/&quot;&gt;w3m&lt;/a&gt;이라는 터미널용 브라우저에서 이미지를 출력해주는 것을 보고 만들었습니다.&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;624&quot; height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SUgJJ/btqAU6YsJ5Q/2MhQ2JPhVEKKUD6O7UWfg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SUgJJ/btqAU6YsJ5Q/2MhQ2JPhVEKKUD6O7UWfg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SUgJJ/btqAU6YsJ5Q/2MhQ2JPhVEKKUD6O7UWfg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSUgJJ%2FbtqAU6YsJ5Q%2F2MhQ2JPhVEKKUD6O7UWfg0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;624&quot; height=&quot;411&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: center;&quot;&gt;w3m &lt;a href=&quot;https://www.howtogeek.com/103574/how-to-browse-from-the-linux-terminal-with-w3m/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구동화면&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;w3m-img란 라이브러리의 wrapper라 생각하면 됩니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xbu8h/btqASzUGN2E/sXsYjE8KRHVxDf8ZY516b0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xbu8h/btqASzUGN2E/sXsYjE8KRHVxDf8ZY516b0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xbu8h/btqASzUGN2E/sXsYjE8KRHVxDf8ZY516b0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxbu8h%2FbtqASzUGN2E%2FsXsYjE8KRHVxDf8ZY516b0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;구동화면&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;명령어&lt;/b&gt;: &lt;code&gt;img 파일이름 보여줄시간(옵션)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다만 문제는 터미널 에뮬레이터들을 조금 가립니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;지원&lt;/b&gt;: Konsole, Xterm, Urxvt, Terminology, Yakuake, Terminal.app&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비지원&lt;/b&gt;: Terminator, Hyper, Tilix, gnome terminal, Guake, LXterminal, Putty, Alacritty&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;지원하지 않는 터미널은 &lt;a href=&quot;https://github.com/radare/tiv&quot;&gt;tiv&lt;/a&gt; 또는 &lt;a href=&quot;https://www.nongnu.org/fbi-improved/&quot;&gt;fim&lt;/a&gt;를 사용하면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 날씨&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wttr.in/&quot;&gt;https://wttr.in/&lt;/a&gt;이라는 사이트에서 보여주는 내용을 &lt;b&gt;터미널&lt;/b&gt;에서도 볼 수 있도록 하며, 자동으로 &lt;b&gt;언어를 설정&lt;/b&gt;해주는 wrapper입니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Sy430/btqARiTBcvo/RZe6QnkZuDNf7JLWtcHktK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Sy430/btqARiTBcvo/RZe6QnkZuDNf7JLWtcHktK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Sy430/btqARiTBcvo/RZe6QnkZuDNf7JLWtcHktK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSy430%2FbtqARiTBcvo%2FRZe6QnkZuDNf7JLWtcHktK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;명령어&lt;/b&gt;: &lt;code&gt;weather&lt;/code&gt; 또는 &lt;code&gt;weather 지역 언어(옵션)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;기본 언어&lt;/b&gt;는 시스템의 설정입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 지도&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl4581/btqAVGrHLa3/UauKYNxILKyXma5p4LkKG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl4581/btqAVGrHLa3/UauKYNxILKyXma5p4LkKG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl4581/btqAVGrHLa3/UauKYNxILKyXma5p4LkKG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl4581%2FbtqAVGrHLa3%2FUauKYNxILKyXma5p4LkKG0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;한국을 보여주는 중&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;명령어&lt;/b&gt;: &lt;code&gt;map&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- BVZSH 시스템 유틸&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;zsh-help&lt;/code&gt;: &lt;b&gt;도움&lt;/b&gt;이 되는 메시지들을 출력&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zsh-update&lt;/code&gt;: 설정, 플러그인을 &lt;b&gt;업데이트&lt;/b&gt; 하고 파일을 정리&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zsh-compile&lt;/code&gt;: BVZSH를 &lt;b&gt;컴파일&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-update&lt;/code&gt;: &lt;b&gt;nerdfont&lt;/b&gt;를 업데이트합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;history-clear&lt;/code&gt;: Zsh &lt;b&gt;history&lt;/b&gt; 파일을 &lt;b&gt;백업&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;histoty-restore&lt;/code&gt;: &lt;b&gt;history&lt;/b&gt; 파일을 &lt;b&gt;복원&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;- 기타 내장 유틸&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ex FILE_NAME&lt;/code&gt;: 파일 &lt;b&gt;압축 해제&lt;/b&gt;(FILE_NAME)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;numfiles [DIRECTORY]&lt;/code&gt;: 디렉토리에 존재하는 &lt;b&gt;파일 개수&lt;/b&gt; 출력&lt;/li&gt;
&lt;li&gt;&lt;code&gt;repeat NUM COMMAND&lt;/code&gt;: NUM번만큼 명령어 &lt;b&gt;반복&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/junegunn/fzf/wiki/Examples&quot;&gt;fzf utils&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vg&lt;/code&gt; with line number -&amp;gt; &lt;code&gt;vgl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tm&lt;/code&gt; -&amp;gt; &lt;code&gt;ftm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;install&lt;/code&gt;(homebrew cask) -&amp;gt; &lt;code&gt;bcip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unstall&lt;/code&gt;(homebrew cask) -&amp;gt; &lt;code&gt;bccp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;라. 설치&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;매우 &lt;b&gt;간단&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p&gt;간단히 설치 가능해야 &lt;b&gt;보급&lt;/b&gt;이 가능하기 때문에 &lt;b&gt;스타터 킷&lt;/b&gt;이라면 반드시 갖춰야 한다고 생각합니다. &lt;b&gt;bash&lt;/b&gt;만 있으면 되며, &lt;b&gt;Debian&lt;/b&gt;기반(우분투, 데비안, 민트), &lt;b&gt;RPM기반&lt;/b&gt;(페도라, CentOS, 레드햇), &lt;b&gt;Pacman&lt;/b&gt;(아치, 만자로, 안테르고스), &lt;b&gt;맥&lt;/b&gt;, &lt;b&gt;FreeBSD&lt;/b&gt;기반을 지원합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- 설치법&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;git clone [https://github.com/black7375/BlaCk-Void-Zsh.git](https://github.com/black7375/BlaCk-Void-Zsh.git) ~/.zsh
bash ~/.zsh/BlaCk-Void-Zsh.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;단, &lt;b&gt;터미널 폰트&lt;/b&gt;는 Nerd Font로 설정하는 것을 &lt;b&gt;추천&lt;/b&gt;(설치 중 1번 옵션은 &lt;code&gt;hack nerd font&lt;/code&gt;)하며, 다시 시작하면 적용됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;메뉴얼 설치법은 다음 링크 참조.&lt;/p&gt;
&lt;p&gt;내장된 기능들이 많아서 의존성이 있는 편입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/black7375/BlaCk-Void-Zsh#22-others&quot;&gt;https://github.com/black7375/BlaCk-Void-Zsh#22-others&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마. 성능&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;여러 가지 &lt;b&gt;플러그인&lt;/b&gt;들을 많이 설치 하다보면 느려지게 되는데 웹페이지의 경우 잠깐의 시간이 페이지뷰에 미치는 영향을 생각하면 &lt;b&gt;매우 중요&lt;/b&gt;한 요소입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;1) 테마 변경&lt;/h4&gt;
&lt;p class=&quot;&quot;&gt;우선 가장 커다란 &lt;b&gt;병목현상&lt;/b&gt;을 일으켰던 &lt;b&gt;테마&lt;/b&gt;를 &lt;a href=&quot;https://github.com/romkatv/powerlevel10k&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Powerlevel10k&lt;/a&gt;로 바꿨습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;Powerlevel10k는 Powerlevel9k와 100% &lt;b&gt;호환&lt;/b&gt;이 되면서도 성능을 잡았습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;메인테이너인 romkatv는 기존에 떨어졌던 성능을 향상시키기 위해 정말로 다양한 노력을 했습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;가장 큰 영향을 미쳤던 git과 관련해 &lt;a href=&quot;https://www.reddit.com/r/zsh/comments/awkyf4/powerlevel10k_a_10x_faster_fork_of_powerlevel9k/&quot;&gt;캐싱&lt;/a&gt;, &lt;a href=&quot;https://www.reddit.com/r/zsh/comments/azuzcq/additional_4x_git_prompt_speedup_in_powerlevel10k/&quot;&gt;패치&lt;/a&gt; 작업&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/zsh/comments/ay6ny7/powerlevel10k_goes_instant_50_times_faster_than/&quot;&gt;비동기&lt;/a&gt; 프롬프트 지원&lt;/li&gt;
&lt;li&gt;그 외 &lt;a href=&quot;https://www.reddit.com/r/zsh/comments/b1xxuj/abusing_zsh_parameter_expansion_for_fun_and/&quot;&gt;각종&lt;/a&gt; &lt;a href=&quot;https://www.reddit.com/r/linux/comments/b0suyu/powerlevel10k_the_fastest_zsh_theme_with_git_in/&quot;&gt;트릭&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그 결과 엄청난 성능을 보여줍니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1iUwV/btqAUwiM86g/O8TfRr5ZBWuqEjYdCYh6zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1iUwV/btqAUwiM86g/O8TfRr5ZBWuqEjYdCYh6zk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1iUwV/btqAUwiM86g/O8TfRr5ZBWuqEjYdCYh6zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1iUwV%2FbtqAUwiM86g%2FO8TfRr5ZBWuqEjYdCYh6zk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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: center;&quot;&gt;Powerlevel10k 성능&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;2) 플러그인 매니저 변경&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;&lt;a href=&quot;https://github.com/zsh-users/antigen&quot;&gt;Antigen&lt;/a&gt;에서 &lt;a href=&quot;https://github.com/zdharma/zplugin&quot;&gt;&lt;b&gt;Zplugin&lt;/b&gt;&lt;/a&gt;이라는 플러그인 매니저로 변경했습니다.&lt;/p&gt;
&lt;p&gt;zplugin은 프롬프트가 로딩 된 후, &lt;b&gt;비동기 로드&lt;/b&gt;가 가능한 유일한 플러그인 매니저며, 매니저 자신과 플러그인들을 바이트 컴파일 해주므로 매우 빠릅니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;로드가 되는 순서를 체계적으로 정해 체감 속도가 빠르도록 만들었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;일반로드: &lt;b&gt;무조건&lt;/b&gt; 빨리 보여야 하는 테마와 관련된 것&lt;/li&gt;
&lt;li&gt;0a: 사용자가 &lt;b&gt;입력할 때 항상&lt;/b&gt; 보여주어야 하는 것&lt;/li&gt;
&lt;li&gt;0b: 사용자가 입력 시 사용빈도가 &lt;b&gt;매우 높은&lt;/b&gt; 것&lt;/li&gt;
&lt;li&gt;0c: 사용자가 입력 시 사용빈도가 &lt;b&gt;상당히 높은&lt;/b&gt; 것&lt;/li&gt;
&lt;li&gt;1a: 사용자가 명령 &lt;b&gt;실행 시 사용빈도가 높은&lt;/b&gt; 것&lt;/li&gt;
&lt;li&gt;1b: 사용자가 입력 시 사용빈도가 &lt;b&gt;높은&lt;/b&gt; 것&lt;/li&gt;
&lt;li&gt;1c: oh-my-zsh 로드&lt;/li&gt;
&lt;li&gt;2: 나머지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;3) 제가 시도한 것&lt;/h4&gt;
&lt;p&gt;저도 자체적으로 성능 향상을 시도했습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;함수들을 &lt;b&gt;Autoload&lt;/b&gt;(Lazyload) 되게 하여 시작성능 향상&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/black7375/zsh-lazyenv&quot;&gt;&lt;b&gt;zsh-lazyenv&lt;/b&gt;&lt;/a&gt;로 nvm, rvm 같은 버전 관리 매니저가 시작할 때 필요한 코드를 Hook만 걸어 놓는 형태로 lazyload 되게 구성 및 &lt;b&gt;eval&lt;/b&gt; 명령어는 &lt;b&gt;캐싱&lt;/b&gt;되도록 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Completion&lt;/b&gt; 요소들을 캐싱, 덤프 후 $fpath에 추가&lt;/li&gt;
&lt;li&gt;Fzf &lt;b&gt;필터&lt;/b&gt;로 grep 대신 ripgrep 사용&lt;/li&gt;
&lt;li&gt;Zsh 설정을 &lt;b&gt;바이트코드&lt;/b&gt; 컴파일&lt;/li&gt;
&lt;li&gt;기타: 파이프라인으로 실행되는 &lt;b&gt;외부 프로세스&lt;/b&gt;를 줄이고, 여러번 실행되어야 하는 명령어는 &lt;b&gt;변수&lt;/b&gt;로 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;4) 기타&lt;/h4&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/zsh-users/zsh-syntax-highlighting&quot;&gt;Zsh Syntax Highlighting&lt;/a&gt; 대신 &lt;b&gt;&lt;a href=&quot;https://github.com/zdharma/fast-syntax-highlighting&quot;&gt;Fast Syntax Highlighting&lt;/a&gt;&lt;/b&gt;으로 빠른 문법강조를 하도록 했습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이렇게 성능향상을 위한 다양한 노력을 통해, 일반적으로 사용해도 무리가 없을만한 성능을 확보할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;5. 기대효과 및 활용분야&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.zsh.org/&quot;&gt;Zsh&lt;/a&gt;는 최신 SW를 권장하고 업데이트가 빠른 운영체제로 유명한 &lt;a href=&quot;https://www.archlinux.org/&quot;&gt;Arch Linux&lt;/a&gt;에서 인스톨러용 기본 Shell로 &lt;a href=&quot;https://www.reddit.com/r/archlinux/comments/6q19g4/arch_live_media_uses_zsh_as_its_default_shell/&quot;&gt;사용&lt;/a&gt;하고, 최근에는 MacOS가 기본 쉘로 &lt;a href=&quot;https://www.zdnet.co.kr/view/?no=20190605141758&quot;&gt;변경&lt;/a&gt;되는 등 점점 보급되는 추세입니다. 따라서 점점 많은 사람이 Zsh를 사용하고, 관심을 두게 될 것입니다. 이때 훌륭한 스타터 킷을 제공할 수 있다면 훨씬 나은 생산성과 효율성으로 시간을 아낄 수 있을 것이라 기대합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;6. 향후 계획&lt;/h2&gt;
&lt;p&gt;기능과 성능으로 나뉘어져 있는데, 아래 링크를 참조해주세요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/black7375/BlaCk-Void-Zsh/projects&quot;&gt;https://github.com/black7375/BlaCk-Void-Zsh/projects&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;7. 프로젝트 관리와 오픈소스&lt;/h2&gt;
&lt;p&gt;오픈소스 프로젝트인 만큼 프로젝트 관리와 오픈소스에 대한 내용을 넣었습니다.&lt;/p&gt;
&lt;h3&gt;가. 프로젝트 관리&lt;/h3&gt;
&lt;h4&gt;1) 브랜치&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgZA5x/btqAQ4gXjsL/yRy9Srrp7bmB6W4PU26Db1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgZA5x/btqAQ4gXjsL/yRy9Srrp7bmB6W4PU26Db1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgZA5x/btqAQ4gXjsL/yRy9Srrp7bmB6W4PU26Db1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgZA5x%2FbtqAQ4gXjsL%2FyRy9Srrp7bmB6W4PU26Db1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;사용자 릴리즈용 master와 개발용 dev로 나누어 사용하고 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;기타 브랜치 관리(Dev-Staging-Master)는 아래에서.&lt;/p&gt;
&lt;p&gt;&lt;a title=&quot;&quot; href=&quot;https://black7375.tumblr.com/post/185730065470/%EB%82%98%EC%9D%98-%EA%B9%83%EB%B8%8C%EB%9E%9C%EC%B9%98-%EA%B4%80%EB%A6%AC-%EC%A0%84%EB%9E%B5&quot;&gt;https://black7375.tumblr.com/post/185730065470/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1578157779926&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;나의 깃브랜치 관리 전략&quot; data-og-description=&quot;보통의 Git-Flow라 하면 를 떠올린다. 하지만 너무나 복잡한 것. 그래서 대칭적이면서 직관적이도록 약간의 수정을 가했다. 리브레 오피스로 그린거라 레이아웃은 안맞음.. 소규모의 경우 dev-master만 운영하고, 커밋 메세지에 &amp;quot;Add: Fix: Doc: Feature:&amp;rdquo;과 같은 식으로 일종의 태그를 달아서 관리한다. 굳이 복잡하게 할 필요는...&quot; data-og-host=&quot;black7375.tumblr.com&quot; data-og-source-url=&quot;https://black7375.tumblr.com/post/185730065470/%EB%82%98%EC%9D%98-%EA%B9%83%EB%B8%8C%EB%9E%9C%EC%B9%98-%EA%B4%80%EB%A6%AC-%EC%A0%84%EB%9E%B5&quot; data-og-url=&quot;https://black7375.tumblr.com/post/185730065470/%EB%82%98%EC%9D%98-%EA%B9%83%EB%B8%8C%EB%9E%9C%EC%B9%98-%EA%B4%80%EB%A6%AC-%EC%A0%84%EB%9E%B5&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cFk7d0/hyEsYnm9pi/2lnYj7NKy5zC8rASRozvxK/img.png?width=820&amp;amp;height=1103&amp;amp;face=0_0_820_1103,https://scrap.kakaocdn.net/dn/IhEPT/hyEqZOYYeJ/yHYt2aeHpp6eakY8KU4dvK/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/DhlP3/hyEsRBMwFj/Ndt22Y52r3CZOEZaJKnbe1/img.png?width=1000&amp;amp;height=1075&amp;amp;face=0_0_1000_1075&quot;&gt;&lt;a title=&quot;&quot; href=&quot;https://black7375.tumblr.com/post/185730065470/%EB%82%98%EC%9D%98-%EA%B9%83%EB%B8%8C%EB%9E%9C%EC%B9%98-%EA%B4%80%EB%A6%AC-%EC%A0%84%EB%9E%B5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://black7375.tumblr.com/post/185730065470/%EB%82%98%EC%9D%98-%EA%B9%83%EB%B8%8C%EB%9E%9C%EC%B9%98-%EA%B4%80%EB%A6%AC-%EC%A0%84%EB%9E%B5&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cFk7d0/hyEsYnm9pi/2lnYj7NKy5zC8rASRozvxK/img.png?width=820&amp;amp;height=1103&amp;amp;face=0_0_820_1103,https://scrap.kakaocdn.net/dn/IhEPT/hyEqZOYYeJ/yHYt2aeHpp6eakY8KU4dvK/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/DhlP3/hyEsRBMwFj/Ndt22Y52r3CZOEZaJKnbe1/img.png?width=1000&amp;amp;height=1075&amp;amp;face=0_0_1000_1075');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; title=&quot;&quot;&gt;나의 깃브랜치 관리 전략&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; title=&quot;&quot;&gt;보통의 Git-Flow라 하면 를 떠올린다. 하지만 너무나 복잡한 것. 그래서 대칭적이면서 직관적이도록 약간의 수정을 가했다. 리브레 오피스로 그린거라 레이아웃은 안맞음.. 소규모의 경우 dev-master만 운영하고, 커밋 메세지에 &quot;Add: Fix: Doc: Feature:&amp;rdquo;과 같은 식으로 일종의 태그를 달아서 관리한다. 굳이 복잡하게 할 필요는...&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;black7375.tumblr.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;2) 커밋&lt;/h4&gt;
&lt;p&gt;또한, 커밋의 맨 앞에 분류할 수 있도록 머리말을 달아놓고 있습니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zsWoP/btqAVGrHRzI/dCGuPmYg48nejIKZUs36m0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zsWoP/btqAVGrHRzI/dCGuPmYg48nejIKZUs36m0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zsWoP/btqAVGrHRzI/dCGuPmYg48nejIKZUs36m0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzsWoP%2FbtqAVGrHRzI%2FdCGuPmYg48nejIKZUs36m0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;ul&gt;
&lt;li&gt;&lt;code&gt;Add&lt;/code&gt;: 기능 &lt;b&gt;추가&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Fix&lt;/code&gt;: 버그, 옵션&lt;b&gt;수정&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Doc&lt;/code&gt;: &lt;b&gt;문서&lt;/b&gt;화, 리소스&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Clean&lt;/code&gt;: 코드를 &lt;b&gt;깔끔히&lt;/b&gt; 다듬었을 때&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Feature&lt;/code&gt;: &lt;b&gt;커다란&lt;/b&gt; 기능을 만들어 변경사항이 클 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;3) 글로벌 타겟&lt;/h4&gt;
&lt;p&gt;제 깃허브의 커밋 내역, README, 위키를 보면 모두 영어로 구성되어 있습니다.&lt;/p&gt;
&lt;p&gt;그래서 깃허브의 스타내역을 보면 외국인의 비율이 상당함을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;나. 오픈소스 커뮤니티와 소통&lt;/h3&gt;
&lt;h4&gt;1) 빠른 이슈처리&lt;/h4&gt;
&lt;p&gt;버그 제보나 질문이 들어오면 가능한 선에서 최대한 빠르게 처리하고 있습니다.&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;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KbQIv/btqARwRzfXV/EIH6Z43w0StgkZ3ywwHx9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KbQIv/btqARwRzfXV/EIH6Z43w0StgkZ3ywwHx9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KbQIv/btqARwRzfXV/EIH6Z43w0StgkZ3ywwHx9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKbQIv%2FbtqARwRzfXV%2FEIH6Z43w0StgkZ3ywwHx9K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;메인테이너가 이슈를 어떻게 관리하느냐는 오픈소스 세계에서 굉장히 중요하다고 생각합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;2) 공헌&lt;/h4&gt;
&lt;p&gt;제가 마음에 들었던 프로젝트들에 이슈 리포트를 보내거나, 아이디어 제공, 문서 편집 등으로 공헌 했습니다.&lt;/p&gt;
&lt;p&gt;이건 너무 소소한 것들이라 부끄러워서 링크를 안달...&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;무튼 도움이 되는 분들이 있었으면 좋겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;참고: &lt;a href=&quot;https://www.papercheck.com/microsoft-word-track-changes/2003-microsoft-word-track-changes-instructions/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2003&amp;nbsp;Microsoft&amp;nbsp;Word&amp;nbsp;Track&amp;nbsp;Changes&amp;nbsp;Instructions&lt;/a&gt;&lt;/p&gt;</description>
      <category>IT/UX</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/67</guid>
      <comments>https://black7375.tistory.com/67#entry67comment</comments>
      <pubDate>Sun, 5 Jan 2020 02:13:14 +0900</pubDate>
    </item>
    <item>
      <title>5G 관련 산업에 대하여</title>
      <link>https://black7375.tistory.com/65</link>
      <description>&lt;p class=&quot;&quot;&gt;학교 보고서인데 평가용으로 쓰고 버리기 아까워서 올려본다.&lt;/p&gt;
&lt;p&gt;'코리아&amp;nbsp;5G+&amp;nbsp;핵심산업&amp;nbsp;&amp;amp;&amp;nbsp;킬러&amp;nbsp;서비스&amp;nbsp;빅콘서트&amp;nbsp;2019'라는 세미나에 다녀온 후 쓴 것.&lt;/p&gt;
&lt;p&gt;뭐.. 당시에 워낙 바뻐서 대충대충 휘갈겨썼고 쪽수 제한이 있어서 딱히 특별한 내용은 없지만 전반적인 맥락을 짚어주기엔 좋은듯.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예를 들어 스타디아에 관련된 예측은 정확히 맞아 떨어졌다.&lt;/p&gt;
&lt;p&gt;4K용 정액제+별도의 게임비용. 완전 미친짓이자 기술적 기만이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;1. 개요.&lt;/h3&gt;
&lt;p&gt;5G는&amp;nbsp;2Gbps의&amp;nbsp;속도,&amp;nbsp;1ms의&amp;nbsp;지연,&amp;nbsp;백만&amp;nbsp;개/㎢의&amp;nbsp;연결을&amp;nbsp;가질&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;통신&amp;nbsp;방식이다.&lt;br /&gt;따라서&amp;nbsp;용량이&amp;nbsp;큰&amp;nbsp;4K나&amp;nbsp;VR,&amp;nbsp;AR&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;IOT&amp;nbsp;기기들을&amp;nbsp;이용한&amp;nbsp;스마트팩토리와&amp;nbsp;스마트시티가&amp;nbsp;탄생할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buKVaO/btqxJap5Kky/JWpmUtt8khAVJjVgNgpdN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buKVaO/btqxJap5Kky/JWpmUtt8khAVJjVgNgpdN1/img.png&quot; data-alt=&quot;5G 주요 내용과 산업&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buKVaO/btqxJap5Kky/JWpmUtt8khAVJjVgNgpdN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuKVaO%2FbtqxJap5Kky%2FJWpmUtt8khAVJjVgNgpdN1%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;5G 주요 내용과 산업&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;2. 미디어.&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k9IKG/btqxITB7oJ0/aastvfOrwfDSYNufVGgTa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k9IKG/btqxITB7oJ0/aastvfOrwfDSYNufVGgTa1/img.png&quot; data-alt=&quot;5G 킬러콘텐츠 후보와 현 상황&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k9IKG/btqxITB7oJ0/aastvfOrwfDSYNufVGgTa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk9IKG%2FbtqxITB7oJ0%2FaastvfOrwfDSYNufVGgTa1%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;5G 킬러콘텐츠 후보와 현 상황&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;VR과&amp;nbsp;AR은&amp;nbsp;하드웨어(디스플레이),&amp;nbsp;자율주행은&amp;nbsp;안전성,&amp;nbsp;IOT는&amp;nbsp;보급,&amp;nbsp;드론은&amp;nbsp;관련&amp;nbsp;프로토콜개발&amp;nbsp;등의&amp;nbsp;한계&amp;nbsp;때문에&amp;nbsp;현&amp;nbsp;상황에서&amp;nbsp;5G의&amp;nbsp;장점을&amp;nbsp;바로&amp;nbsp;흡수할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;것은&amp;nbsp;게임이라고&amp;nbsp;한다.&lt;br /&gt;그렇다면&amp;nbsp;&lt;b&gt;모든&amp;nbsp;실시간&amp;nbsp;게임&lt;/b&gt;을&amp;nbsp;하기&amp;nbsp;좋은가?&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;제&amp;nbsp;결론은&amp;nbsp;그렇지&amp;nbsp;않다.&lt;br /&gt;특히&amp;nbsp;커스텀&amp;nbsp;요소가&amp;nbsp;많은&amp;nbsp;게임일수록&amp;nbsp;힘들&amp;nbsp;것이라고&amp;nbsp;예상한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&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;비효율적)&lt;br /&gt;그런데&amp;nbsp;오버헤드&amp;nbsp;작업(TCP로&amp;nbsp;치면&amp;nbsp;RTT)이&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;60Hz(1프레임당&amp;nbsp;16.666ms)&amp;nbsp;모니터도&amp;nbsp;느리게&amp;nbsp;보인다며&amp;nbsp;144Hz(이론상&amp;nbsp;1프레임당&amp;nbsp;6.944ms,&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;FPS&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;br /&gt;사실&amp;nbsp;특수상대성이론을&amp;nbsp;따라&amp;nbsp;빛은&amp;nbsp;우주의&amp;nbsp;최고속도인데(지구&amp;nbsp;한&amp;nbsp;바퀴에&amp;nbsp;133.333ms)&amp;nbsp;4개의&amp;nbsp;권역으로&amp;nbsp;나뉘어&amp;nbsp;서비스해도&amp;nbsp;33.25ms의&amp;nbsp;지연시간을&amp;nbsp;가질&amp;nbsp;수밖에&amp;nbsp;없으므로&amp;nbsp;물리적으로도&amp;nbsp;한계가&amp;nbsp;존재한다고&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;&lt;br /&gt;구글의&amp;nbsp;스타디아가&amp;nbsp;4K&amp;nbsp;60프레임을&amp;nbsp;지원한다고&amp;nbsp;광고하지만&amp;nbsp;5G가&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;돌아온다.&lt;br /&gt;&lt;br /&gt;대신,&amp;nbsp;강연자는&amp;nbsp;다른&amp;nbsp;대안을&amp;nbsp;제안했다.&lt;br /&gt;2G&amp;nbsp;때는&amp;nbsp;벨소리와&amp;nbsp;컬러링,&amp;nbsp;3G&amp;nbsp;때는&amp;nbsp;사진,&amp;nbsp;4G는&amp;nbsp;영상이&amp;nbsp;콘텐츠를&amp;nbsp;주도했다면&amp;nbsp;5G&amp;nbsp;시대는&amp;nbsp;AI를&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;들었다.&lt;br /&gt;&lt;br /&gt;따라서&amp;nbsp;작곡,&amp;nbsp;작문&amp;nbsp;등을&amp;nbsp;보조해주는&amp;nbsp;AI가&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;AI&amp;nbsp;기술이&amp;nbsp;가능성&amp;nbsp;있다고&amp;nbsp;생각합니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;3. 양자통신과 기술.&lt;/h3&gt;
&lt;p&gt;5G의&amp;nbsp;구현방식&amp;nbsp;중&amp;nbsp;New&amp;nbsp;Radio는&amp;nbsp;보안이&amp;nbsp;약하다는&amp;nbsp;말이&amp;nbsp;많아&amp;nbsp;양자암호를&amp;nbsp;적용하는&amp;nbsp;실험&amp;nbsp;중이라&amp;nbsp;연관이&amp;nbsp;있었다.&lt;br /&gt;양자역학의&amp;nbsp;성질인&amp;nbsp;중첩성(0,&amp;nbsp;1이&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;4가지&amp;nbsp;특성&amp;nbsp;때문에&amp;nbsp;일어나는&amp;nbsp;일들이다.&lt;br /&gt;&lt;br /&gt;양자&amp;nbsp;컴퓨터부터&amp;nbsp;차근차근&amp;nbsp;알아보자.&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;0과&amp;nbsp;1의&amp;nbsp;상태를&amp;nbsp;가진다.&amp;nbsp;따라서&amp;nbsp;비트&amp;nbsp;수($n$)가&amp;nbsp;증가할수록 $2n$으로&amp;nbsp;처리할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;명령어가&amp;nbsp;증가한다.&amp;nbsp;그러나&amp;nbsp;양자&amp;nbsp;컴퓨터의&amp;nbsp;큐비트는&amp;nbsp;중첩&amp;nbsp;가능하므로 $2^n$으로&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;위험해진다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bryqe8/btqxISQNHbD/b621vpDP4UR65HR6YSEMUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bryqe8/btqxISQNHbD/b621vpDP4UR65HR6YSEMUk/img.png&quot; data-alt=&quot;양자암호 통신 구성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bryqe8/btqxISQNHbD/b621vpDP4UR65HR6YSEMUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbryqe8%2FbtqxISQNHbD%2Fb621vpDP4UR65HR6YSEMUk%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;양자암호 통신 구성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;그럼&amp;nbsp;무결성을&amp;nbsp;가질만한&amp;nbsp;암호기술은&amp;nbsp;없을까?&lt;br /&gt;역시&amp;nbsp;양자의&amp;nbsp;특성에&amp;nbsp;해법은&amp;nbsp;숨어있다.&amp;nbsp;우선&amp;nbsp;양자의&amp;nbsp;스핀은&amp;nbsp;8가지&amp;nbsp;위상($x$, $y$, $z$축으로 $+-$)이&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;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;1번뿐이다.&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;SKT의&amp;nbsp;경우&amp;nbsp;세종시-SKT&amp;nbsp;대전사옥,&amp;nbsp;서울과&amp;nbsp;대전의&amp;nbsp;5G망에&amp;nbsp;양자&amp;nbsp;통신망을&amp;nbsp;적용한&amp;nbsp;상태다.&lt;br /&gt;&lt;br /&gt;또&amp;nbsp;다른&amp;nbsp;양자기술을&amp;nbsp;이용한&amp;nbsp;보안기술에는&amp;nbsp;양자난수생성기가&amp;nbsp;있다.&lt;br /&gt;LED&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;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;4. 커넥티드카.&lt;/h3&gt;
&lt;p&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;자율주행(Level&amp;nbsp;4)을&amp;nbsp;구현할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjZp4g/btqxI9LuIqw/9fXYRV3TmzEFkYNr8Nhfzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjZp4g/btqxI9LuIqw/9fXYRV3TmzEFkYNr8Nhfzk/img.png&quot; data-alt=&quot;자율주행을 위한 통신&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjZp4g/btqxI9LuIqw/9fXYRV3TmzEFkYNr8Nhfzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjZp4g%2FbtqxI9LuIqw%2F9fXYRV3TmzEFkYNr8Nhfzk%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;자율주행을 위한 통신&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&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;때문이다.&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;(서비스업)&lt;br /&gt;&lt;br /&gt;SW(유료&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;lsquo;타다&amp;rsquo;처럼&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;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXRiUS/btqxKrxE9hP/qymCXdtLzCE4VaQdIbYp50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXRiUS/btqxKrxE9hP/qymCXdtLzCE4VaQdIbYp50/img.png&quot; data-alt=&quot;스마트팩토리에서 장소 스캔 중&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXRiUS/btqxKrxE9hP/qymCXdtLzCE4VaQdIbYp50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXRiUS%2FbtqxKrxE9hP%2FqymCXdtLzCE4VaQdIbYp50%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;스마트팩토리에서 장소 스캔 중&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;커넥티드카에&amp;nbsp;사용되는&amp;nbsp;자율주행기술의&amp;nbsp;완성&amp;nbsp;전에&amp;nbsp;스마트팩토리에서&amp;nbsp;상용화할&amp;nbsp;수&amp;nbsp;있다.&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;받는다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;5. IOT와 엣지 컴퓨팅.&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFv4QN/btqxJk0jbta/VxN4ZkvkfVGBDiCbmJ7UPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFv4QN/btqxJk0jbta/VxN4ZkvkfVGBDiCbmJ7UPK/img.png&quot; data-alt=&quot;IOT와 MEC&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFv4QN/btqxJk0jbta/VxN4ZkvkfVGBDiCbmJ7UPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFv4QN%2FbtqxJk0jbta%2FVxN4ZkvkfVGBDiCbmJ7UPK%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;IOT와 MEC&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;아마존&amp;nbsp;대시나&amp;nbsp;스마트&amp;nbsp;홈스피커&amp;nbsp;같은&amp;nbsp;것만&amp;nbsp;아니라&amp;nbsp;앞서&amp;nbsp;다룬&amp;nbsp;자율주행에서도&amp;nbsp;각종&amp;nbsp;IOT&amp;nbsp;센서가&amp;nbsp;쓰일&amp;nbsp;예정이다.&lt;br /&gt;5G의&amp;nbsp;초연결성&amp;nbsp;덕에&amp;nbsp;많은&amp;nbsp;IOT가&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;4000GB)&amp;nbsp;그래서&amp;nbsp;엣지(가장자리)&amp;nbsp;단에서&amp;nbsp;데이터들을&amp;nbsp;처리할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;엣지&amp;nbsp;컴퓨팅이&amp;nbsp;주목받고&amp;nbsp;있다.&lt;br /&gt;&lt;br /&gt;MEC(Multi-Access&amp;nbsp;Edge&amp;nbsp;Computing)&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;가진다.&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;한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;6. 소감.&lt;/h3&gt;
&lt;p&gt;단순히&amp;nbsp;5G에&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;/p&gt;</description>
      <category>IT</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/65</guid>
      <comments>https://black7375.tistory.com/65#entry65comment</comments>
      <pubDate>Sun, 25 Aug 2019 16:57:59 +0900</pubDate>
    </item>
    <item>
      <title>내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.</title>
      <link>https://black7375.tistory.com/62</link>
      <description>&lt;p&gt;내 맘대로 하는 프로그램 설계 시리즈.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Chapter1 - 간단한 데이터 처리(4섹션)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/31&quot;&gt;2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비.&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;http://black7375.tistory.com/32&quot;&gt;2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 2. - 데이터 타입.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/34&quot;&gt;2018/01/16 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 3. - 함수와 변수.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/36&quot;&gt;2018/05/29 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 4. - 고정 크기 데이터.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/6&quot;&gt;2017/06/30 - [프로그래밍/설계] - 프로그래밍과 추상화에 대하여.[부록]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;Chapter2 - 임의의 데이터 처리&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/38&quot;&gt;2018/06/10 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 5. - 리스트와 재귀.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/61&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2019/05/20 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 6. - 데이터구조와 알고리즘[연재예정].&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Chapter3 - 추상화&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2019/05/20 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 7. - 함수형 프로그래밍(현재).&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;1. 시작하기.&lt;/h2&gt;
&lt;p&gt;우리가 사용하고 있는 Racket은 첫시간에도 언급했듯이 함수형 프로그래밍 패러다임을 따르고 있다.&lt;/p&gt;
&lt;p&gt;각종 프로그래밍 패러다임은 프로그램을 추상화 시켜 사람들이 다루기 편하도록 만들어주는 역할을 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그 첫번째로, Racket &amp;amp;&amp;amp; Lisp의 대표적 패러다임인 함수형 프로그래밍을 간단히 다루어보고자 한다.&lt;/p&gt;
&lt;p&gt;다음은 위키피디아에서 나온 함수형 패러다임의 정의다.&lt;/p&gt;
&lt;blockquote&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;1930년대에&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;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;함수형 프로그래밍의 핵심은 '상태변화'를 억제하는 것이다.&lt;/p&gt;
&lt;p&gt;따라서 인수에만&amp;nbsp;의존하고, 인수 $x$에&amp;nbsp;같은&amp;nbsp;값을&amp;nbsp;넣고&amp;nbsp;함수 $f$를&amp;nbsp;호출하면&amp;nbsp;항상 $f(x)$라는&amp;nbsp;결과가&amp;nbsp;나온다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아래는 C언어 코드로 상태변화의 대표적인 예시다.&lt;/p&gt;
&lt;pre id=&quot;code_1558315110399&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5987027010882783&quot;&gt;&lt;code&gt;int a = 0;
int b = 2;
a = 1;
a = b;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Racket으로는 요랬던 코드..&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.1&lt;/p&gt;
&lt;pre id=&quot;code_1558315347219&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9622259578348872&quot;&gt;&lt;code&gt;(define a 0)
(define b 2)
(set! a 1)
(set! a b)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;보다시피 변수 'a'의 상태가 $0 \to 1 \to 2(b의 상태)$처럼 변화하고 있다.&lt;/p&gt;
&lt;p&gt;이 사이에 $a+1$라는 연산이 있다면 결과가 달라지는 것이다!!&lt;/p&gt;
&lt;p&gt;프로그램의 상태에 따라 연산의 결과가 달라진다면, 프로그램의 디버깅시 변수추적이 까다로워진다.(특히 병렬 프로그래밍)&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;h3&gt;2. 순수 함수(Pure Fuction).&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/34&quot;&gt;2018/01/16 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 3. - 함수와 변수.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;시간에 부작용(Side Effect)에 대하여 언급한 적이 있다.&lt;/p&gt;
&lt;blockquote&gt;컴퓨터 과학쪽에서는 함수가 결과값말고 다른 상태를 변경시키면 부작용(Side Effect, 보통 사이드 이펙트라 부름)이 생겼다고 한다. 사이트 이펙트가 생기면, 예측되지 못한 값이 나올 확률이 올라가 버그가 나오기 쉽고, 컴파일러가 최적화를 하기 힘들어진다.&lt;br /&gt;근삿값이 정확한 값과 함께 계산하면 근삿값이 나오듯이 사이드 이펙트도 사이드 이펙트가 일어난 함수가 사용되면 퍼져나간다.&lt;/blockquote&gt;
&lt;p&gt;순수 함수는 부작용이 없는 함수를 말한다.(참조 투명성을 가진다고도 함)&lt;/p&gt;
&lt;p&gt;즉, 상태변화가 없다는 것!!&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;h4&gt;2.1 최적화와 Random.&lt;/h4&gt;
&lt;p class=&quot;&quot;&gt;우선 $add1$은 순수 함수이다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;들어가는 인수값과 상관없이 항상 $+ 1$을 한 결과를 돌려주기 때문이다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;순수한 형태인 함수 $add1$은 다음과 같이 최적화를 할 수 있다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Code 7.2&lt;/p&gt;
&lt;pre id=&quot;code_1558317575670&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.13652365351345963&quot;&gt;&lt;code&gt;;;Original Pure
(define pure (* (add1 a)
                (add1 a)))

;;Optimize Pure
(define pure-temp (add1 a))
(define pure-opti (* pure-temp
                     pure-temp))

(= pure pure-opti)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: #true&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;처음 함수인 Pure은 (add1 a)을 두번 계산했지만,&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;두번째 pure-opti는 (add1 a)의 값을 저장(pure-temp)하고 그 값을 곱함으로서 add1 연산을 한번 줄일 수가 있었다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그리고, 이 값들은 &lt;u&gt;&lt;span style=&quot;background-color: #ffe999;&quot;&gt;항상&lt;/span&gt;&lt;/u&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt; &lt;/span&gt;같습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그럼 랜덤에서 성립하나 생각 해봅시다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Code 7.3&lt;/p&gt;
&lt;pre id=&quot;code_1558318950461&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5437372441972029&quot;&gt;&lt;code&gt;;; original
(define side (* (random)
                (random)))

;; optimize??
(define side-temp (random))
(define side-opti (* side-temp
                     side-temp))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;random이란 함수는 난수 값을 반환해주는 함수.&lt;/p&gt;
&lt;p&gt;따라서 실행할 때 마다 결과값이 달라지게 되고, side-opti는 원래의 의도에서 달라지게 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;여기에서 random은 부작용(side-effect)를 일으키는 함수고, 부작용은 최적화에 악영향을 줄 수 있다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;2.2 숨겨진 상태변화.&lt;/h4&gt;
&lt;p&gt;다음 함수는 stack에 특정한 값을 집어넣는(push)하는 함수이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.4&lt;/p&gt;
&lt;pre id=&quot;code_1558320523353&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9353116148305403&quot;&gt;&lt;code&gt;(define stack (make-stack val))
(define (stack-push val)
  (push stack val))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;여기에 상태변화가 존재하는가?&lt;/p&gt;
&lt;p&gt;그렇다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;stack에 값이 들어와 상태가 변화되었다.&lt;/p&gt;
&lt;p&gt;stack이란 입력이 숨겨졌다고 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;숨겨진 상태변화를 없에려면 명시적으로 매개변수와 출력값을 지정해주면 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.5&lt;/p&gt;
&lt;pre id=&quot;code_1558321206441&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.050000232448049076&quot;&gt;&lt;code&gt;(define (stack-push-noside stack val)
  (push stack val))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;약간 복잡해보이긴 하지만,&amp;nbsp; 보편적인 함수가 되었고 명시적이라 디버깅시 값추적이 편해진다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;또 다른 숨겨진 상태변화의 예로는 키보드 입력이나 모니터 출력 같은 IO(Input/Output) 작업들을 꼽을 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;border&quot;&gt;
&lt;p&gt;하스켈은 IO 작업에서도 함수형으로 다루기 위해 모나드를 도입했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.haskell.org/Monad&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;하스켈 위키&lt;/a&gt;가 가장 좋겠지만..&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lazyswamp.tistory.com/entry/functorsapplicativesandmonadsinpictures&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;그림으로 설명하는 펑터, 아플리커티브, 모나드&lt;/a&gt; 또는 &lt;a href=&quot;https://1ambda.github.io/haskell/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;INTRODUCTION TO FUNCTIONAL PROGRAMMING USING HASKELL&lt;/a&gt; (한글이에요 ㅋㅋ)의 &lt;a href=&quot;https://1ambda.github.io/haskell/intro-to-haskell-4/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모나드&lt;/a&gt;, &lt;a href=&quot;https://1ambda.github.io/haskell/intro-to-haskell-5/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IO Monad&lt;/a&gt;를 참고하기 바란다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;여담으로 &lt;a href=&quot;http://reactivex.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reactive 프로그래밍&lt;/a&gt;에서 Observable이란 것도 모나드의 형태다.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;3. 람다대수(Lambda Calculus).&lt;/h3&gt;
&lt;h4&gt;3.1 정의.&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/43&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2018/07/22 - [수학] - 무한, 집합, 그리고 수에 대해서.&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&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;증명했다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;따라서 수학자들은 '계산 가능한 문제'에 관심을 가졌고 그 결과로 나온 것이 튜링머신(Turing Machine), $\lambda$-대수(Lambda Calculus),&amp;nbsp; 포스트 시스템(Post&amp;nbsp;canonical&amp;nbsp;system)이며, 모두 튜링 완전하다는 것이 증명되고 역도 성립한다고 한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이에 대한 내용은 추후에 따로 다루어보도록 한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;기계어-어셈블리-C언어와 같은 명령형 언어 계보는 튜링머신을, Lisp-Racket, ML-Haskell등 함수형 언어의 계보는 람다대수로부터 아이디어를 가져왔다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;장황한 설명을 보니 엄청나게 복잡한 체계인것 같은데...&lt;/p&gt;
&lt;p&gt;람다대수의 정의는 BNF로 보면 의외로 간단하다.&lt;/p&gt;
&lt;pre id=&quot;code_1558338297941&quot; class=&quot;bnf&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6117523653116125&quot;&gt;&lt;code&gt;&amp;lt; expression &amp;gt; := &amp;lt; name &amp;gt;|&amp;lt; function &amp;gt;|&amp;lt; application &amp;gt; 
&amp;lt; function &amp;gt; := &amp;lambda; &amp;lt; name &amp;gt; . &amp;lt; expression &amp;gt;
&amp;lt; application &amp;gt; :=  &amp;lt; expression &amp;gt;&amp;lt; expression &amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/45&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2018/07/31 - [수학/이산수학] - 기초: 논리와 증명.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;를 보면 BNF를 이해할 수 있다!!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BNF를 해석해보면 람다대수는&lt;/p&gt;
&lt;p&gt;- 표현식은 변수, 함수, 적용&lt;/p&gt;
&lt;p&gt;- 함수는 매개변수와 표현식&lt;/p&gt;
&lt;p&gt;- 적용은 표현식들&lt;/p&gt;
&lt;p&gt;로 이루어져 있다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;3.2 기초 사용법.&lt;/h4&gt;
&lt;p&gt;람다 대수에서 표현식의 표기를 명확히 하기 위해 괄호를 사용하며, 함수의 적용은 왼쪽으로 결합한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$$E_1E_2E_3...E_n&amp;nbsp;\equiv (...((E_1E_2)E_3)...E_n))$$&lt;/p&gt;
&lt;p&gt;요거요거 어디서 많이 보던 형태 아닌가?????&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그렇다!!&lt;/p&gt;
&lt;p&gt;바로 우리가 Racket에서 지금까지 써오던 방식과 동일!! (처음 배울때 여기서 감동 먹었던)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;람다 함수의 형태도 같다.&lt;/p&gt;
&lt;p&gt;$$\lambda x.x \equiv (\lambda x.x)$$&lt;/p&gt;
&lt;p&gt;$\lambda$다음 첫번째로 등장하는 $x$는 식별자로 불리며, 프로그래밍 함수에서는 매개변수로 생각할 수 있다.&lt;/p&gt;
&lt;p&gt;$.$이후에 등장하는 $x$는 함수의 본문(Body)다.&lt;/p&gt;
&lt;p&gt;즉, 위 함수는 항등함수인 $f(x)=x$와 같다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이제 앞서 나왔던 평가방법대로 적용(Application)해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J0wu4/btqvs04x6Mu/D8z9DSg9VfqPRAJvkKloyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J0wu4/btqvs04x6Mu/D8z9DSg9VfqPRAJvkKloyk/img.png&quot; data-filename=&quot;blob&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; title=&quot;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J0wu4/btqvs04x6Mu/D8z9DSg9VfqPRAJvkKloyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ0wu4%2Fbtqvs04x6Mu%2FD8z9DSg9VfqPRAJvkKloyk%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E0QFL/btqvrDoT7Vt/AiSCkquQQD1FYUwWPbCps1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E0QFL/btqvrDoT7Vt/AiSCkquQQD1FYUwWPbCps1/img.png&quot; data-filename=&quot;lam2_1.png&quot; style=&quot;width: 49.4186%;&quot; title=&quot;&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E0QFL/btqvrDoT7Vt/AiSCkquQQD1FYUwWPbCps1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE0QFL%2FbtqvrDoT7Vt%2FAiSCkquQQD1FYUwWPbCps1%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;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;평가방법&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$$(\lambda x.x)y \to [y/x]x \to y$$&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$x$가 $y$로 치환됨을 볼 수 있다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;코드로 나타내도 거의 똑같다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Code 7.6&lt;/p&gt;
&lt;pre id=&quot;code_1558359361079&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9623719650576281&quot;&gt;&lt;code&gt;(lambda (x) x)
((lambda (x) x) 1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: (lambda&amp;nbsp;(a1)&amp;nbsp;...), 1&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Code 7.7&lt;/p&gt;
&lt;pre id=&quot;code_1558406557559&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6366926182121561&quot;&gt;&lt;code&gt;(define x 1)
(define y (lambda (y) y))

x
(y x)
(y 2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 1, 1, 2&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;단, 람다 대수에서 중요한 것이 있다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;식별자의 이름(name)은 자리표시자(place holder)일 뿐이라는 거.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;따라서 아래 표현은 모두 같은 함수다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$$(\lambda z.z) \equiv (\lambda y.y) \equiv (\lambda t.t) \equiv (\lambda u.u)$$&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;순수한 알파벳 치환은 $\alpha$-reduction이라 불림.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;3.3 자유 변수와 종속 변수(Free Variable and Bound Variable).&lt;/h4&gt;
&lt;p&gt;앞서 나온 $\lambda x.x$의 모든 이름은 지역변수(loacal variable)이다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;따라서 $x$는 본문에 출현한 이후에 $\lambda x$가 있으므로 종속(Bound)되었다 부른다.&lt;/p&gt;
&lt;p&gt;반대로 $\lambda$로 시작하지 않는 이름은 자유변수나 비지역 변수라 한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;간단히 예를 들어보면&lt;/p&gt;
&lt;p&gt;$$(\lambda x.x)(\lambda y.yx)$$&lt;/p&gt;
&lt;p&gt;첫번째 본문의 $x$는 종속 되었지만, 두번째 함수 본문의 $x$는 자유 변수다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;lamb3_1.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DZwtZ/btqvtPhaj6X/ZzrnHLHmXBGD1yCgKojQX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DZwtZ/btqvtPhaj6X/ZzrnHLHmXBGD1yCgKojQX0/img.png&quot; data-alt=&quot;축약하는 과정을 $\beta$-reduction이라 한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DZwtZ/btqvtPhaj6X/ZzrnHLHmXBGD1yCgKojQX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDZwtZ%2FbtqvtPhaj6X%2FZzrnHLHmXBGD1yCgKojQX0%2Fimg.png&quot; data-filename=&quot;lamb3_1.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;축약하는 과정을 $\beta$-reduction이라 한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.8&lt;/p&gt;
&lt;pre id=&quot;code_1558406818569&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7198380668282734&quot;&gt;&lt;code&gt;((lambda (x) x) ((lambda (y) (+ x y)) 1))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 2&lt;/p&gt;
&lt;p&gt;$\lambda y. x+y$에서 $x$는 Code 7.7에서 정의된 자유변수이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이제 우리는&amp;nbsp;&amp;lt;name&amp;gt;에 대하여 자유변수와 종속변수의 정의를 알 수 있다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- 자유변수&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;name&amp;gt;은 &amp;lt;name&amp;gt;의 자유 변수.[예: $a$는 $a$의 자유변수]&lt;/li&gt;
&lt;li&gt;&amp;lt;name&amp;gt;은 $\lambda$&amp;lt;name1&amp;gt;의 자유 변수(&amp;lt;name&amp;gt;$\neq$&amp;lt;name1&amp;gt;인 표현식이고, 표현식에서 자유변수 일 때)[예: $\lambda x.y$의 $y$]&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&amp;lt;name&amp;gt;은 $E_1E_2$의 자유 변수($E_1$ 또는 $E_2$에서 자유변수 일 때. [예: $(\lambda x.x) x$])&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- 종속변수&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;lt;name&amp;gt;은 $\lambda$&amp;lt;name1&amp;gt;의 종속 변수(&amp;lt;name&amp;gt;$=$&amp;lt;name1&amp;gt;인 표현식이고, 표현식에서 종속변수 일 때) [예: $( \lambda y.(\lambda x.x))$]&lt;/li&gt;
&lt;li&gt;&amp;lt;name&amp;gt;은 $E_1E_2$의 자유 변수($E_1$ 또는 $E_2$에서 종속변수 일 때.)[예: $(\lambda x.x) x$]&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3.4 다중 적용.&lt;/h4&gt;
&lt;p&gt;$$(\lambda x.(\lambda y.xy)y)$$&lt;/p&gt;
&lt;p&gt;는&lt;/p&gt;
&lt;p&gt;$$(\lambda xy.xy)$$&lt;/p&gt;
&lt;p&gt;로 줄일 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.9&lt;/p&gt;
&lt;pre id=&quot;code_1558417802492&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9106555070196947&quot;&gt;&lt;code&gt;((lambda (x) ((lambda (y) (+ x y)) 2)) 1)
((lambda (x y) (+ x y)) 1 2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 3, 3&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;4. 일급 객체, 커링, 클로저(First Class Citizen, Curring, Closure).&lt;/h3&gt;
&lt;h4&gt;4.1 일급 객체.&lt;/h4&gt;
&lt;p&gt;다음은 1급 객체의 정의이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변수나&amp;nbsp;데이터&amp;nbsp;구조안에&amp;nbsp;담을&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;li&gt;파라미터로&amp;nbsp;전달&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;li&gt;반환값(return&amp;nbsp;value)으로&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;li&gt;할당에&amp;nbsp;사용된&amp;nbsp;이름과&amp;nbsp;관계없이&amp;nbsp;고유한&amp;nbsp;구별이&amp;nbsp;가능하다.&lt;/li&gt;
&lt;li&gt;동적으로&amp;nbsp;프로퍼티&amp;nbsp;할당이&amp;nbsp;가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;람다대수를 공부하며 코드를 봤겠지만, Racket에서 함수는 모두 가능하다!!&lt;/p&gt;
&lt;p&gt;일급 객체에 함수가 속하는 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서 다음 함수는 같다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.10&lt;/p&gt;
&lt;pre id=&quot;code_1581373112600&quot; class=&quot;scheme&quot; data-ke-language=&quot;codeblock&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(define  (func1 num)
  (+ num 3))

(define func2
  (lambda (num)
    (+ num 3)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;4.2 커링.&lt;/h4&gt;
&lt;p&gt;함수를 파라미터로 전달하고, 반환할 수 있다면 커링(Curring)이라는 것이 가능해진다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;다중&amp;nbsp;인수를 가진 함수를&amp;nbsp;단일&amp;nbsp;인수를&amp;nbsp;갖는&amp;nbsp;함수들의&amp;nbsp;함수열로&amp;nbsp;바꾸는&amp;nbsp;것을&amp;nbsp;말한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;2개와 3개로 커리 함수를 만들어보자.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Code 7.11&lt;/p&gt;
&lt;pre id=&quot;code_1558360038725&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5709261350419931&quot;&gt;&lt;code&gt;(define (curry2 f)
  (lambda(x)
    (lambda(y)
      (f x y))))

(define (curry3 f)
  (lambda(x)
    (lambda(y)
      (lambda(z)
       (f x y z)))))

(((curry2
   +) 1) 2)
((((curry3
    +) 1) 2) 3)&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;&quot;&gt;결과: 3, 6&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;사용하는 방법이 괴랄해보인다 ㅋㅋㅋ&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;하지만&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Code 7.12&lt;/p&gt;
&lt;pre id=&quot;code_1558362509610&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.46284888457686546&quot;&gt;&lt;code&gt;(define curry-temp ((curry2 +) 1))
(curry-temp 2)&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;&quot;&gt;결과: 3&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;인수를 부분적으로&amp;nbsp;받고 함수의&amp;nbsp;실행을&amp;nbsp;늦추거나, curry를 이용해 함수를 정의하여 재사용성을 늘릴 수도 있다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;4.3 클로저.&lt;/h4&gt;
&lt;p class=&quot;&quot;&gt;클로저를 배우기 전에 중요한 개념 두가지를 짚고 넘어가고자 한다.&lt;/p&gt;
&lt;p class=&quot;&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;Lexical Scope&lt;br /&gt;함수&amp;nbsp;본문은&amp;nbsp;함수가 불려지는 것이 아닌 정의된&amp;nbsp;범위의&amp;nbsp;모든&amp;nbsp;바인딩을&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;닫힌(Closed) 람다식과 열린(Open) 람다식&lt;br /&gt;변수들이&amp;nbsp;모두&amp;nbsp;묶인&amp;nbsp;변수일&amp;nbsp;때&amp;nbsp;닫힌&amp;nbsp;람다식.&lt;br /&gt;사용하는&amp;nbsp;변수들&amp;nbsp;중&amp;nbsp;하나라도&amp;nbsp;자유&amp;nbsp;변수가&amp;nbsp;있을&amp;nbsp;때&amp;nbsp;열린&amp;nbsp;람다식.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;&quot;&gt;클로저는 열린 함수를 닫힌 함수로 만들어주는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/44&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2018/07/30 - [수학] - 집합(위상)과 극한에 대하여[일부 내용 펌].&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;를 보고 오면 편할 것이다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이제 클로저 사용하는 예제를 봐보자.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;단, Code 7.7이 미리 실행되어 있다고 가정한다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Code 7.13&lt;/p&gt;
&lt;pre id=&quot;code_1558424848162&quot; class=&quot;lisp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.4446143572242126&quot;&gt;&lt;code&gt;(define f (lambda (y) (+ x y)))
(define z (let ([x 2]
                [y 3])
            (f (+ x y))))

z&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;&quot;&gt;결과: 6&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이번에 처음보는 let 함수는 지역 변수를 만들어주는 함수다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Code 7.14&lt;/p&gt;
&lt;pre id=&quot;code_1558425300740&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.2536359801925788&quot;&gt;&lt;code&gt;(let ([x 1]) x)&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;&quot;&gt;결과: 1&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;code&gt;z&lt;/code&gt;가 호출될 때 내부에서 &lt;code&gt;[(x 2) [y 3]]&lt;/code&gt; 때문에 &lt;code&gt;(f (+ x y))&lt;/code&gt; =&amp;gt; &lt;code&gt;(f (+ 2 3))&lt;/code&gt; =&amp;gt; &lt;code&gt;(f 5)&lt;/code&gt;로 계산하게 된다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이때 f가 클로저 대상이 되는 함수다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그럼 어떻게 계산되는지 계속 살펴보자.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;함수 &lt;code&gt;f&lt;/code&gt;의 식별자를 보면 &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;가 존재한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;code&gt;x&lt;/code&gt;는 자유변수, &lt;code&gt;y&lt;/code&gt;는 종속변수로&amp;nbsp; 이루어져 있는데 &lt;code&gt;y&lt;/code&gt;는 입력받은 값 5가 된다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;자유변수인 &lt;code&gt;x&lt;/code&gt;가 어디에 정의되었나 봤더니 외부(Code 7.7)에서 정의된 &lt;code&gt;x&lt;/code&gt;값(1)이었다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;따라서 함수 &lt;code&gt;f&lt;/code&gt;의 범위가 결정되어 닫힌 상태로 전환되었다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그 후 $1+5=6$으로 결과가 완결났다는 것을 알 수 있다.&lt;/p&gt;
&lt;h3&gt;5. 고차함수(High-Order Function).&lt;/h3&gt;
&lt;p&gt;이제 고차함수를 알아보고 다루어보자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하나 이상의 함수를&amp;nbsp;인자로&amp;nbsp;받거나, 결과로&amp;nbsp;반환하는&amp;nbsp;함수를&amp;nbsp;고차함수(High-Order Function)라고 한다.&lt;/p&gt;
&lt;p&gt;다른 모든 함수들은 일차함수(First-Order Function)이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;형식 람다&amp;nbsp;대수에서&amp;nbsp;모든&amp;nbsp;함수들은&amp;nbsp;고차&amp;nbsp;함수.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;고차함수의 예를 들어보자.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.15&lt;/p&gt;
&lt;pre id=&quot;code_1558363654441&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.2640080047498984&quot;&gt;&lt;code&gt;(define (add x y) (+ x y))
(define (g x)
  (lambda (y) (+ x y)))
((g 3) 7)
(add 3 7)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 10, 10&lt;/p&gt;
&lt;p&gt;함수 g는 커링이 된 형태인데 함수를 반환하므로, 고차함수라 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이제 유명한 고차함수 5가지만 알아두고, 이번 섹션을 마치도록 합시다.&lt;/p&gt;
&lt;p&gt;아래에서 소개하는 함수만 잘 써도 인생이 풍요로워집니다.&lt;/p&gt;
&lt;p&gt;마치 엑셀의 &lt;code&gt;vlookup&lt;/code&gt;, &lt;code&gt;index&lt;/code&gt;, &lt;code&gt;match&lt;/code&gt;같은 함수들이랄까?&lt;/p&gt;
&lt;h4&gt;5.1 for-each.&lt;/h4&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.16&lt;/p&gt;
&lt;pre id=&quot;code_1558363918808&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5765633982331831&quot;&gt;&lt;code&gt;(define (my-for-each func list)
  (unless (null? list)
    (begin
      (func (car list))
      (my-for-each func (cdr list)))))
 
(my-for-each print '(1 2 3 4 5))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 12345&lt;/p&gt;
&lt;p&gt;리스트 값들을 하나씩 대입해주는 함수다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;5.2 map.&lt;/h4&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.17&lt;/p&gt;
&lt;pre id=&quot;code_1558363987914&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.10658095067016748&quot;&gt;&lt;code&gt;(define (my-map func list)
  (if (null? list)
      '()
      (cons (func (car list)) (my-map func (cdr list)))))

(my-map curry-temp '(1 2 3 4 5))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: '(2 3 4 5 6)&lt;/p&gt;
&lt;p&gt;리스트 값에 전달받은 함수의 계산결과 새로운 리스트를 만들어 내는 함수다.&lt;/p&gt;
&lt;p&gt;여기에서 커링(Currying)은 인자값을 자동으로 전달 받을 수 있다는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;5.3 reduce.&lt;/h4&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.18&lt;/p&gt;
&lt;pre id=&quot;code_1558364128548&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.9345770831492002&quot;&gt;&lt;code&gt;(define (my-reduce func list)
  (if (null? (cdr list))
             (car list)
             (func (car list) (my-reduce func (cdr list)))))

(my-reduce + '(1 2 3 4 5))
(my-reduce (lambda (x y) (* x y)) '(1 2 3))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 15,&amp;nbsp; 6&lt;/p&gt;
&lt;p&gt;전해받은 리스트 결과에 연산을 적용하여 하나의 결과로 수렴해내는 함수다.&lt;/p&gt;
&lt;p&gt;특정 로직을 한번만 사용할 경우 람다 함수를 사용하면 된다는 것도 이 예제를 통해 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;5.4 filter.&lt;/h4&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.19&lt;/p&gt;
&lt;pre id=&quot;code_1558364157153&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.638326461715985&quot;&gt;&lt;code&gt;(define (my-filter func list)
  (if (null? list)
      '()
      (if (func (car list))
          (cons (car list) (my-filter func (cdr list)))
          (my-filter func (cdr list)))))

(my-filter positive? '(1 -2 3 4 -5))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: '(1 3 4)&lt;/p&gt;
&lt;p&gt;특정 결과에 해당하는 것만 리스트로 만들어 반환한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;5.5 find.&lt;/h4&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 7.20&lt;/p&gt;
&lt;pre id=&quot;code_1558364218056&quot; class=&quot;scheme&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6645569434079005&quot;&gt;&lt;code&gt;(define (my-find func list)
  (if (null? list)
      #false
      (if (func (car list))
          (car list)
          (my-find func (cdr list)))))

(my-find   integer? '(1.1 2.1 3 4 5.1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 3&lt;/p&gt;
&lt;p&gt;첫번째로 조건에 만족하는 것을 찾아 반환한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;참고: 위키백과(&lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98%ED%98%95_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;함수형 프로그래밍&lt;/a&gt; , &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B8%89_%EA%B0%9D%EC%B2%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;일급 객체&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B3%A0%EC%B0%A8_%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;고차 함수&lt;/a&gt;), &lt;a href=&quot;https://arxiv.org/pdf/1503.09060.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;Tutorial&amp;nbsp;Introduction&amp;nbsp;to&amp;nbsp;the&amp;nbsp;LambdaCalculus&lt;/a&gt;,&lt;/p&gt;</description>
      <category>프로그래밍/설계</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/62</guid>
      <comments>https://black7375.tistory.com/62#entry62comment</comments>
      <pubDate>Tue, 21 May 2019 17:07:47 +0900</pubDate>
    </item>
    <item>
      <title>내 맘대로 프로그램 설계 6. - 데이터구조와 알고리즘.</title>
      <link>https://black7375.tistory.com/61</link>
      <description>&lt;p&gt;내 맘대로 하는 프로그램 설계 시리즈.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Chapter1 - 간단한 데이터 처리(4섹션)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/31&quot;&gt;2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비.&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;http://black7375.tistory.com/32&quot;&gt;2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 2. - 데이터 타입.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/34&quot;&gt;2018/01/16 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 3. - 함수와 변수.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/36&quot;&gt;2018/05/29 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 4. - 고정 크기 데이터.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/6&quot;&gt;2017/06/30 - [프로그래밍/설계] - 프로그래밍과 추상화에 대하여.[부록]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;Chapter2 - 임의의 데이터 처리&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/38&quot;&gt;2018/06/10 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 5. - 리스트와 재귀.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/61&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2019/05/20 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 6. - 데이터구조와 알고리즘(현재).&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Chapter3 - 추상화&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2019/05/20 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;1. 시작.&lt;/h3&gt;
&lt;p&gt;리스트와 재귀를 배웠으니 본격적으로 자료구조를 배워보도록 합시다.&lt;/p&gt;
&lt;p&gt;자료구조는 자료에 대해 효율적으로 접근하고 수정하기 위해 만들어진 개념입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;모든 물건을 집에 늘어놓고 쓰는 것이 아니라 책장, 서랍, 상자등에 보관하면 보기에 깔끔한 것이 아니라 찾기에도 편하잖아요??&lt;/p&gt;
&lt;p&gt;자료구조는 책장, 서랍, 상자처럼 데이터를 깔끔하게 묶어주고 빠르고 편하게 사용할 수 있도록 도와줍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;자료구조 중 가장 기초적인 형태는 링크드 리스트(Linked List)입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Singly_linked_list.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baJNc7/btqwulZVoNH/UQdTXqrQ4qs1Ksl4AAM7uk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baJNc7/btqwulZVoNH/UQdTXqrQ4qs1Ksl4AAM7uk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baJNc7/btqwulZVoNH/UQdTXqrQ4qs1Ksl4AAM7uk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaJNc7%2FbtqwulZVoNH%2FUQdTXqrQ4qs1Ksl4AAM7uk%2Fimg.png&quot; data-filename=&quot;Singly_linked_list.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;링크드 리스트(Linked List) [from &lt;a href=&quot;https://ko.wikipedia.org/wiki/연결_리스트&quot;&gt;Wikipedia&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;전 시간에 다루었던 리스트와 유사하죠??&lt;/p&gt;
&lt;p&gt;사실 링크드 리스트를 구현하려면 전 리스트와 후 리스트를 연결하는 과정에서 'C언어의 포인터' 개념이 필요한데..&lt;/p&gt;
&lt;p&gt;포인터는 초보자들이 다루기 어려운걸로 유명합니다.&lt;/p&gt;
&lt;p&gt;이하 각 리스트는 노드(Node)라 부르도록 합시다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서 자료구조의 개념을 잡는 것이 아니라 컴퓨터구조에 대해 공부해야하는 목적과 수단이 역전되는 상황이 나오기도 합니다.&lt;/p&gt;
&lt;p&gt;리스트를 기본적으로 제공하는 것은 제가 Racket이라는 언어를 고른 이유들 중 하나입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Racket이 리스트를 대상으로 제공하는 4가지의 연산을 알아볼까요?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.1&lt;/p&gt;
&lt;pre id=&quot;code_1562002606107&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5116223006551275&quot;&gt;&lt;code&gt;(length   '(1 2 3 4 5))
(reverse  '(1 2 3 4 5))
(list-ref '(1 2 3 4 5) 2)
(append '(1 2 3) '(4 5))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 5, (list 5 4 3 2 1), 3, (list 1 2 3 4 5)&lt;/p&gt;
&lt;p&gt;각각 리스트의 크기(길이), 거꾸로된 리스트, 3번째 값(0부터 시작), 합쳐진 리스트를 반환합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그럼 위의 함수를 활용하든, 재귀를 사용하든 마지막 노드 값을 반환하는 함수를 짜봅시다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Code 6.2&lt;/p&gt;
&lt;pre id=&quot;code_1562004350848&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.0536754236414676&quot;&gt;&lt;code&gt;;;last-node: list -&amp;gt; node
;;Return list's last element
(define (last-node1 list)
  (car (reverse list)))

(define (last-node2 list)
  (list-ref list (- (length list) 1)))

(define (last-node3 list) 
   (if (zero? (length (cdr list)))
      (car list) 
      (last-node3 (cdr list))))

(define (last-node4 list)
  (if (null? (cdr list))
     (car list)
     (last-node4 (cdr list))))

(check-expect (last-node1 '(1 2 3 4 5)) 5)
(check-expect (last-node2 '(1 2 3 4 5)) 5)
(check-expect (last-node3 '(1 2 3 4 5)) 5)
(check-expect (last-node4 '(1 2 3 4 5)) 5)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 4개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;일부로 다양한 방식을 보여주고 싶어서 4가지 방식으로 구현해봤습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li class=&quot;&quot;&gt;1번째는 리스트를 거꾸로 뒤집고, 첫번째 노드를 반환합니다.&lt;/li&gt;
&lt;li&gt;2번째는 리스트의 크기 - 1 번째의 노드를 반환합니다.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;3번째는 다음 리스트의 길이가 0일 경우 노드를 반환하고 아니라면, 다음 리스트에 대해 재귀적으로 수행합니다.&lt;/li&gt;
&lt;li&gt;4번째는 다음 리스트가 비었을 경우(null값) 노드를 반환하고 아니라면, 다음 리스트에 대해 재귀적으로 수행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아무래도 간결한 1번째나 두번째 코드가 마음에 들죠? ㅎㅎ&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그런데 &lt;code&gt;'()&lt;/code&gt;를 입력하면 &lt;code&gt;car&lt;/code&gt;나 &lt;code&gt;cdr&lt;/code&gt;을 수행할 수 없다는 에러가 뜹니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;저는 &lt;code&gt;ERROR&lt;/code&gt;를 표시하도록 수정하겠습니다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;Code 6.3&lt;/p&gt;
&lt;pre id=&quot;code_1562005820366&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.36586288978541903&quot;&gt;&lt;code&gt;(define (last-node list)
  (if (null? list)
     &quot;ERROR&quot;
     (car (reverse list))))

(check-expect (last-node '()) &quot;ERROR&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;&quot;&gt;결과: 모든 1개 테스트 통과함!&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;항상 말하지만 항상 경계값에 대해 테스트하고, 예외처리하는 습관을 들입시다.&lt;/p&gt;
&lt;p&gt;본격적으로 자료구조를 배워보도록 합시다!!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;2. 자료구조.&lt;/h3&gt;
&lt;p class=&quot;&quot; style=&quot;font-size: 1.12em;&quot;&gt;&lt;b&gt;- 자료구조의 종류&lt;/b&gt;&lt;/p&gt;
&lt;p&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;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;리스트&lt;/li&gt;
&lt;li&gt;스택&lt;/li&gt;
&lt;li&gt;큐&lt;/li&gt;
&lt;li&gt;덱&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비선형구조
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;트리&lt;/li&gt;
&lt;li&gt;그래프&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위에 나온 데이터구조들을 간단히 알아보고 구현해볼꺼에요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;font-size: 1.12em;&quot;&gt;&lt;b&gt;- 추상 데이터 타입(ADT, Abstract Data Type)&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그전에 추상 데이터 타입의 개념에 대해 숙지하고 넘어갑시다.&lt;/p&gt;
&lt;p&gt;ADT는 구체적인 구현에 앞서 데이터와 연산의 특징과 연산자가 어떤 기능을 하는지 알려주는 명세입니다.&lt;/p&gt;
&lt;p&gt;우리가 지금껏 배워왔던 계약, 목적과 비슷하니 적응하기 쉬울겁니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;리스트의 ADT&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;데이터:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트 형태인 $L$은 요소들이 순서대로 정렬된 것입니다. &lt;br /&gt;$&amp;lt;x_0, x_1, x_2, ... , x_{n-2}, x_{n-1}&amp;gt;$처럼 말이죠.&lt;/li&gt;
&lt;li&gt;리스트의 길이는 $|L|=n$이고, $n=0$일 경우 $L$은 빈 리스트입니다.&lt;/li&gt;
&lt;li&gt;$N$은 노드를 나타냅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;연산:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;list-length($L$): $|L|$를 반환합니다.&lt;/li&gt;
&lt;li&gt;list-empty?($L$): 리스트가 비어있는지에 따라 true/false 값을 반환합니다.&lt;/li&gt;
&lt;li&gt;list-get-first($L$): 리스트의 첫번째 요소를 반환합니다.&lt;/li&gt;
&lt;li&gt;list-get-last($L$): 리스트의 마지막 요소를 반환합니다.&lt;/li&gt;
&lt;li&gt;list-get($L$, i): $L[i]$를 반환합니다. 0보다 작거나 $|L|$일 경우, 에러를 반환합니다.&lt;/li&gt;
&lt;li&gt;list-set($L$, i, $N$): $L[i]$을 $N$값으로 바꿈니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;쉬운 것부터 하나씩 구현해봅시다.&lt;/p&gt;
&lt;p&gt;처음 배우는 사람에게 마지막 set부분 코드는 조금 어려울 수 있으니 다 이해하지 못해도 상관없습니다.&lt;/p&gt;
&lt;p&gt;리스트와 그 뒤에 나오는 스택, 큐와 같은 자료구조의 개념을 잡는 것이 가장 중요합니다.&lt;/p&gt;
&lt;p&gt;구현은 개념 이해를 탄탄히 하기위해 하는 과정일 뿐입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- list-length &amp;amp;&amp;amp; list-empty?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.4&lt;/p&gt;
&lt;pre id=&quot;code_1562165887396&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.2256824401703108&quot;&gt;&lt;code&gt;;;list-length: list -&amp;gt; int
;;List's length
(define (list-length lst)
  (length lst))

(check-expect (list-length '())          0)
(check-expect (list-length '(1 2 3 4 5)) 5)

;;list-empty?: list -&amp;gt; boolean
;;Check list is empty
(define (list-empty? lst)
  (null? lst))

(check-expect (list-empty? '())          #true )
(check-expect (list-empty? '(1 2 3 4 5)) #false)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 4개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;list-length&lt;/code&gt;와 &lt;code&gt;list-empty&lt;/code&gt;는 &lt;code&gt;length&lt;/code&gt;와 &lt;code&gt;null?&lt;/code&gt;의 사용과 같아 쉽게 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- list-get-first &amp;amp;&amp;amp; list-get-last&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.4&lt;/p&gt;
&lt;pre id=&quot;code_1562165912833&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.029387740667654816&quot;&gt;&lt;code&gt;(define E-list-smaller
  &quot;ERROR: index smaller than 0&quot;)
(define E-list-larger
  &quot;ERROR: index larger than list length&quot;)

;;list-get-first: list -&amp;gt; node
;;Return list's first element
(define (list-get-first lst)
  (if (null? lst)
     E-list-smaller
     (car lst)))

(check-expect (list-get-first '()) E-list-smaller)
(check-expect (list-get-first '(1 2 3 4 5)) 1)

;;list-get-last: list -&amp;gt; node
;;Return list's last element
(define (list-get-last lst)
  (if (null? lst)
     E-list-smaller
     (car (reverse lst))))

(check-expect (list-get-last '()) E-list-smaller)
(check-expect (list-get-last '(1 2 3 4 5)) 5)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 4개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;list-get-first&lt;/code&gt;는 &lt;code&gt;car&lt;/code&gt;에 예외처리를 더한것 뿐이고, &lt;code&gt;list-get-last&lt;/code&gt;는 앞서 만든 &lt;code&gt;last-node&lt;/code&gt;와 동일하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- list-get&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.4&lt;/p&gt;
&lt;pre id=&quot;code_1562090131582&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.19521800100192432&quot;&gt;&lt;code&gt;;;list-get: list index -&amp;gt; node
;;Return list's &quot;index&quot;th element
(define (list-get lst index)
  (cond
    [(&amp;lt;  index 0)             E-list-smaller]
    [(&amp;gt;= index (length lst))  E-list-larger ]
    [else                     (list-ref lst index)]))

(check-expect (list-get '(1 2 3 4 5) -1) E-list-smaller)
(check-expect (list-get '(1 2 3 4 5) 6)  E-list-larger )
(check-expect (list-get '(1 2 3 4 5) 2)  3)&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;&quot;&gt;결과:&amp;nbsp; 모든 3개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;우리가 원하는 값을 잘 알려주고 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- list-set&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.4&lt;/p&gt;
&lt;pre id=&quot;code_1562098799721&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.41566194540927826&quot;&gt;&lt;code&gt;;;list-set: list index node -&amp;gt; void
;;Set list's &quot;index&quot;th element to node
(define (list-set lst index node)
  (append (list-take lst (- index 1))
          (list node)
          (list-drop lst index)))

;;list-take: list index -&amp;gt; list
;;Split list to&quot;index&quot;th
(define (list-take lst index)
  (cond
   [(=  index 0)            '()]
   [(&amp;lt;  index 0)            E-list-smaller]
   [(&amp;gt; index (length lst))  E-list-larger ]
   [else                    (cons (car lst)
                                  (list-take (cdr lst) (- index 1)))]))

;;list-drop: list index -&amp;gt; list
;;Split list after &quot;index&quot;th
(define (list-drop lst index)
  (cond
    [(= index 0)            lst             ]
    [(&amp;lt; index 0)            E-list-smaller]
    [(&amp;gt; index (length lst)) E-list-larger ]
    [else                   (list-drop (cdr lst) (- index 1))]))

;;(check-expect (list-set  '(1 2 3 4 5) 0  10) ERROR)
;;(check-expect (list-set  '(1 2 3 4 5) -1 10) ERROR)
;;(check-expect (list-set  '(1 2 3 4 5) 6  10) ERROR)
(check-expect (list-set  '(1 2 3 4 5) 5  10) '(1 2 3 4 10))
(check-expect (list-take '(1 2 3 4 5) 0 ) '()   )
(check-expect (list-take '(1 2 3 4 5) -1) E-list-smaller)
(check-expect (list-take '(1 2 3 4 5) 6 ) E-list-larger )
(check-expect (list-take '(1 2 3 4 5) 5 ) '(1 2 3 4 5))
(check-expect (list-drop '(1 2 3 4 5) 0 ) '(1 2 3 4 5))
(check-expect (list-drop '(1 2 3 4 5) -1) E-list-smaller)
(check-expect (list-drop '(1 2 3 4 5) 6 ) E-list-larger )
(check-expect (list-drop '(1 2 3 4 5) 5 ) '())&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: &quot;ERROR:&amp;nbsp;index&amp;nbsp;smaller&amp;nbsp;than&amp;nbsp;0&quot; &quot;ERROR:&amp;nbsp;index&amp;nbsp;larger&amp;nbsp;than&amp;nbsp;list&amp;nbsp;length&quot; &quot;ERROR:&amp;nbsp;index&amp;nbsp;smaller&amp;nbsp;than&amp;nbsp;0&quot; &quot;ERROR:&amp;nbsp;index&amp;nbsp;larger&amp;nbsp;than&amp;nbsp;list&amp;nbsp;length&quot; 모든 9개&amp;nbsp;테스트&amp;nbsp;통과함!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;index의 앞과 뒷부분의 list를 반환해주는 &lt;code&gt;list-take&lt;/code&gt;와 &lt;code&gt;list-drop&lt;/code&gt;을 만들었다.&lt;/p&gt;
&lt;p&gt;그리고 &lt;code&gt;list-set&lt;/code&gt;에서 &lt;code&gt;list-take&lt;/code&gt;, &lt;code&gt;node&lt;/code&gt;, &lt;code&gt;drop&lt;/code&gt; 순으로 새로운 리스트를 만들어 반환해준다.&lt;/p&gt;
&lt;p&gt;테스트코드에서 3개를 주석처리해둔 것은 자동으로 에러로 인식해주기 때문이다&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;2.1 스택(Stack)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8xavl/btqwvrtpYm9/QI7RYUyk6G6br8wfY0VG50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8xavl/btqwvrtpYm9/QI7RYUyk6G6br8wfY0VG50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8xavl/btqwvrtpYm9/QI7RYUyk6G6br8wfY0VG50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8xavl%2FbtqwvrtpYm9%2FQI7RYUyk6G6br8wfY0VG50%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;쌓여진 상자[from &lt;a href=&quot;https://doc.rust-lang.org/cargo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Cargo Book&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;스택은 마치 상자를 사용하는 방법과 같다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;나중에 들어온 것이 먼저 나가는 후입선출(LIFO, Last In First Out)라 불리는 형태의 자료구조이다.&lt;/p&gt;
&lt;p&gt;[먼저 들어온 것은 나중에, 나중에 들어온 것은 먼저 나간다]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;게임으로 치면 트위치의 패시브 스킬 같은거??&lt;/p&gt;
&lt;p&gt;&lt;video style=&quot;margin: 0 auto;&quot; poster=&quot;https://lolstatic-a.akamaihd.net/champion-abilities/images/0029_01.jpg&quot; preload=&quot;none&quot; controls=&quot;controls&quot; width=&quot;348&quot; height=&quot;196&quot; data-setup=&quot;{}&quot;&gt;
                        &lt;source src=&quot;https://lolstatic-a.akamaihd.net/champion-abilities/videos/mp4/0029_01.mp4&quot; type=&quot;video/mp4&quot; /&gt;
                        &lt;source src=&quot;https://lolstatic-a.akamaihd.net/champion-abilities/videos/webm/0029_01.webm&quot; type=&quot;video/webm&quot; /&gt;
                        &lt;source src=&quot;https://lolstatic-a.akamaihd.net/champion-abilities/videos/ogv/0029_01.ogv&quot; type=&quot;video/ogg&quot; /&gt;
&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;트위치 맹독[from &lt;a href=&quot;https://gameinfo.leagueoflegends.co.kr/ko/game-info/champions/twitch/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LOL&lt;/a&gt;]&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;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;300&quot; height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjIjVg/btqwxR5BMY4/FKiCTHhzc45oP2r9pZTZt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjIjVg/btqwxR5BMY4/FKiCTHhzc45oP2r9pZTZt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjIjVg/btqwxR5BMY4/FKiCTHhzc45oP2r9pZTZt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjIjVg%2FbtqwxR5BMY4%2FFKiCTHhzc45oP2r9pZTZt1%2Fimg.png&quot; width=&quot;300&quot; height=&quot;216&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;스택[from &lt;a href=&quot;https://www.wikiwand.com/ko/%EC%8A%A4%ED%83%9D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;스택의 ADT&lt;/b&gt;&lt;/p&gt;
&lt;p&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;br /&gt;리스트의 마지막. 즉, 스택의 윗부분을 TOP이라 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;연산:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li class=&quot;&quot;&gt;stack-push($L$, $N$): 노드 $N$을 TOP에 추가한다.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;stack-top($L$): TOP을 반환한다.(비어있으면 에러)&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;stack-pop($L$): TOP을 제거하고 반환합니다.(역시 비어있으면 에러)&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;stack-empty?($L$): 스택이 비었는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;복잡한 것은 최대한 없애고, 간단하게만 구현하겠습니다.&lt;/p&gt;
&lt;p&gt;원래 쓸만하게 짰었는데 초보자에게 어려울거 같아서 다 지워쓔ㅠㅠㅠㅠㅠㅠㅠ&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- stack-empty?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.5&lt;/p&gt;
&lt;pre id=&quot;code_1562188335749&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.009123402911850875&quot;&gt;&lt;code&gt;;;stack-empty?: stack -&amp;gt; boolean
;;Check stack is empty
(define (stack-empty? lst)
  (null? lst))

(check-expect (stack-empty? '())  #true )
(check-expect (stack-empty? '(1)) #false)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 2개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;그냥 null값인지만 확인하면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- stack-top &amp;amp;&amp;amp; stack-pop&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.5&lt;/p&gt;
&lt;pre id=&quot;code_1562190836519&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.45552120603320145&quot;&gt;&lt;code&gt;(define E-stack-empty
  &quot;ERROR: stack is empty&quot;)

;;stack-top: stack -&amp;gt; node
;;Return stack's TOP
(define (stack-top lst)
  (if (stack-empty? lst)
     E-stack-empty
     (car lst)))

(check-expect (stack-top '()) E-stack-empty)
(check-expect (stack-top '(3 2 1)) 3)

;;stack-pop: stack -&amp;gt; stack
;;Return stack excluding Top
(define (stack-pop lst)
  (if (stack-empty? lst)
     E-stack-empty
     (cdr lst)))

(check-expect (stack-pop '()) E-stack-empty)
(check-expect (stack-pop '(3 2 1)) '(2 1))&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;&quot;&gt;결과: 모든 4개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;stack-top은 스택이 비었는지 확인하고 아니면 car값을 반환해주면 됩니다.&lt;/p&gt;
&lt;p&gt;stack-pop은 스택이 비었는지 확인하고 아니면 cdr값을 반환해주면 됩니다.&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;- stack-push&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.5&lt;/p&gt;
&lt;pre id=&quot;code_1562192898263&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8600575599766309&quot;&gt;&lt;code&gt;;;stack-push: stack node -&amp;gt; stack
;;Return add node to end of list(stack's TOP)
(define (stack-push lst node)
  (cons node lst))

(check-expect (stack-push '() 1) '(1))
(check-expect (stack-push (stack-push '() 1) 2) '(2 1))
(check-expect (stack-push '(2 1) 3) '(3 2 1))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 3개 테스트 통과함!&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;쉽죠??&lt;/p&gt;
&lt;p&gt;앞서 말했지만 쉽게 만들려고 set!을 이용한 코드 다 갈아 엎었어요ㅠㅠ&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;스택은 어떨 때 쓰일까요?&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;재귀에서 1번-2번-3번(종료)-2번-1번처럼 '돌아올때' 쓰일 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이 말은 괄호 체크 (((예시))), 컨트롤-z(취소하기)등에 쓸 수 있다는 것이겠죠.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;2.2 큐(Queue)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;440&quot; height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbFJRU/btqwulnaoMc/wncayufCbMjpv6TdXqGkJK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbFJRU/btqwulnaoMc/wncayufCbMjpv6TdXqGkJK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbFJRU/btqwulnaoMc/wncayufCbMjpv6TdXqGkJK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbFJRU%2FbtqwulnaoMc%2FwncayufCbMjpv6TdXqGkJK%2Fimg.jpg&quot; width=&quot;440&quot; height=&quot;345&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;냉장고[from &lt;a href=&quot;http://www.carrier.co.kr/CarrierRef/products/openshowcase_details.asp?pro_code=1005&amp;amp;pro_num=223489&amp;amp;detail=feature&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;carrier&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;큐는 스택과 달리 선입선출(FIFO, First In First Out)방식이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;음식을 저장하는 방식과 같다.&lt;/p&gt;
&lt;p&gt;가정에서는 냉장고에 음식을 넣을때 유통기한이나 사온 순서를 생각하지 않고 넣는 경우가 많지만, 마트나 편의점 같은 곳의 냉장고와 진열대를 봐보자.&lt;/p&gt;
&lt;p&gt;대부분 유통기한이 짧은 것(먼저 생산된 것)이 앞으로 와있을 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그냥 버스나 지하철을 타려고 줄을 서는 것이라 생각해도 좋다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;300&quot; height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9cDOZ/btqwvrAmNxs/3bEWOesLEaN9iBhMXIF9B0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9cDOZ/btqwvrAmNxs/3bEWOesLEaN9iBhMXIF9B0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9cDOZ/btqwvrAmNxs/3bEWOesLEaN9iBhMXIF9B0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9cDOZ%2FbtqwvrAmNxs%2F3bEWOesLEaN9iBhMXIF9B0%2Fimg.png&quot; width=&quot;300&quot; height=&quot;196&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: center;&quot;&gt;큐[from &lt;a class=&quot;&quot; href=&quot;https://www.wikiwand.com/en/Queue_(abstract_data_type)&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;큐의 ADT&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;데이터:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li class=&quot;&quot;&gt;리스트와 동일하다.&lt;br /&gt;큐의 입구를 Back(또는 rear), 출구를 Front라 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;연산:&lt;/p&gt;
&lt;ul class=&quot;&quot; style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;queue-enqueue($L$, $N$): 노드 $N$을 Back에 추가한다.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;queue-dequeue($L$): Front를 제거하고 반환합니다.(비어있으면 에러)&lt;/li&gt;
&lt;li&gt;queue-front($L$): Front을 반환한다.(비어있으면 에러)&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;queue-empty?($L$): 큐가 비었는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;스택과 거의 비슷하니 여러분이 구현해보고 코드를 보세요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- queue-empty?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.6&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1562197349014&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.808562624652165&quot;&gt;&lt;code&gt;;;queue-empty?: queue -&amp;gt; boolean
;;Check queue is empty
(define (queue-empty? lst)
  (null? lst))

(check-expect (queue-empty? '())  #true )
(check-expect (queue-empty? '(1)) #false)&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;&quot;&gt;결과: 모든 2개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- queue-front &amp;amp;&amp;amp; queue-dequeue&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.6&lt;/p&gt;
&lt;pre id=&quot;code_1562197587085&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.6762035517700794&quot;&gt;&lt;code&gt;(define E-queue-empty
  &quot;ERROR: queue is empty&quot;)

;;queue-front: queue -&amp;gt; node
;;Return queue's front
(define (queue-front lst)
  (if (queue-empty? lst)
     E-queue-empty
     (car lst)))

(check-expect (queue-front '()) E-queue-empty)
(check-expect (queue-front '(1 2 3)) 1)

;;queue-dequeue: queue -&amp;gt; queue
;;Return queue excluding front
(define (queue-dequeue lst)
  (if (queue-empty? lst)
     E-queue-empty
     (cdr lst)))

(check-expect (queue-dequeue '()) E-queue-empty)
(check-expect (queue-dequeue '(1 2 3)) '(2 3))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 4개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- queue-enqueue&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.6&lt;/p&gt;
&lt;pre id=&quot;code_1562197666683&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.7121027710322918&quot;&gt;&lt;code&gt;;;queue-enqueue: queue node -&amp;gt; queue
;;Return add node to back
(define (queue-enqueue lst node)
  (append lst (list node)))

(check-expect (queue-enqueue '() 1) '(1))
(check-expect (queue-enqueue (queue-enqueue '() 1) 2) '(1 2))
(check-expect (queue-enqueue '(1 2) 3) '(1 2 3))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 3개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;enqueue때 append를 사용한 것과 순서차이를 빼면 별차이 없죠?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;큐는 어떨 때 쓰일까요?&lt;/p&gt;
&lt;p&gt;우선순위처럼 '순서대로' 처리할 때 쓰일 수 있습니다.&lt;/p&gt;
&lt;p&gt;이 말은 프로세스 관리, 출력 메세지 처리등에 쓸 수 있다는 것이겠죠.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;2.3 덱(Deque)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;694&quot; height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZzchM/btqwuyfyhxj/PQlHjnoRLm4HuRsxf0dK8k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZzchM/btqwuyfyhxj/PQlHjnoRLm4HuRsxf0dK8k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZzchM/btqwuyfyhxj/PQlHjnoRLm4HuRsxf0dK8k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZzchM%2Fbtqwuyfyhxj%2FPQlHjnoRLm4HuRsxf0dK8k%2Fimg.jpg&quot; width=&quot;694&quot; height=&quot;521&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 class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;1차선 터널[from &lt;a href=&quot;https://noproblemyourlife.tistory.com/872&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;여행이 좋다&lt;/a&gt;]&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;덱(Deque)은 double-ended&amp;nbsp;queue의 약어로서 front와 end에 추가/삭제가 자유롭다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;742&quot; height=&quot;221&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ban7VW/btqwvrtudTE/Td9dSjET2h1w8csOIZR10k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ban7VW/btqwvrtudTE/Td9dSjET2h1w8csOIZR10k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ban7VW/btqwvrtudTE/Td9dSjET2h1w8csOIZR10k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fban7VW%2FbtqwvrtudTE%2FTd9dSjET2h1w8csOIZR10k%2Fimg.png&quot; width=&quot;742&quot; height=&quot;221&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: center;&quot;&gt;덱[from &lt;a href=&quot;https://www.geeksforgeeks.org/implementation-deque-using-circular-array/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Geeksforgeeks&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;덱의 ADT&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;데이터:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li class=&quot;&quot;&gt;덱과 동일하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;연산:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;deque-add-front($L$, $N$): 노드 $N$을 front에 추가한다.&lt;/li&gt;
&lt;li&gt;deque-add-back($L$, $N$): 노드 $N$을 back에 추가한다.&lt;/li&gt;
&lt;li&gt;deque-delete-front($L$): Front를 제거하고 반환합니다.(비어있으면 에러)&lt;/li&gt;
&lt;li&gt;deque-delete-back($L$): Back을 제거하고 반환합니다.(비어있으면 에러)&lt;/li&gt;
&lt;li&gt;deque-front($L$): Front을 반환한다.(비어있으면 에러)&lt;/li&gt;
&lt;li&gt;deque-back($L$): Back을 반환한다.(비어있으면 에러)&lt;/li&gt;
&lt;li&gt;deque-empty?($L$): 덱이 비었는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- deque-empty?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.7&lt;/p&gt;
&lt;pre id=&quot;code_1562201171878&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.5735828704526326&quot;&gt;&lt;code&gt;;;deque-empty?: deque -&amp;gt; boolean
;;Check deque is empty
(define (deque-empty? lst)
  (null? lst))

(check-expect (deque-empty? '())  #true )
(check-expect (deque-empty? '(1)) #false)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 2개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- deque-front &amp;amp;&amp;amp; deque-back&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.7&lt;/p&gt;
&lt;pre id=&quot;code_1562201351784&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.8568804064178441&quot;&gt;&lt;code&gt;(define E-deque-empty
  &quot;ERROR: deque is empty&quot;)

;;deque-front: deque -&amp;gt; node
;;Return deque's front
(define (deque-front lst)
  (if (deque-empty? lst)
     E-deque-empty
     (car lst)))

(check-expect (deque-front '()) E-deque-empty)
(check-expect (deque-front '(1 2 3)) 1)

;;deque-back: deque -&amp;gt; node
;;Return deque's back
(define (deque-back lst)
  (if (deque-empty? lst)
     E-deque-empty
     (car (reverse lst))))

(check-expect (deque-back '()) E-deque-empty)
(check-expect (deque-back '(1 2 3)) 3)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 4개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;deque-back은 list-last-node와 같죠?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- deque-delete-front &amp;amp;&amp;amp; deque-delete-back&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.7&lt;/p&gt;
&lt;pre id=&quot;code_1562201483114&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.12139059385346351&quot;&gt;&lt;code&gt;;;deque-delete-front: deque -&amp;gt; deque
;;Return deque excluding front
(define (deque-delete-front lst)
  (if (deque-empty? lst)
     E-deque-empty
     (cdr lst)))

(check-expect (deque-delete-front '()) E-deque-empty)
(check-expect (deque-delete-front '(1 2 3)) '(2 3))

;;deque-delete-back: deque -&amp;gt; deque
;;Return deque excluding back
(define (deque-delete-back lst)
  (if (deque-empty? lst)
     E-deque-empty
     (list-take lst (- (length lst) 1))))

(check-expect (deque-delete-back '()) E-deque-empty)
(check-expect (deque-delete-back '(1 2 3)) '(1 2))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 4개 테스트 통과함!&lt;/p&gt;
&lt;p&gt;deque-delete-back은 전에 만들어둔 list-take를 쓰면 됩니다.&lt;/p&gt;
&lt;p&gt;예제코드를 보여주는 것이라 가능한 전에 만들었던 함수를 쓰지 않으려 하는데 이 경우는 list-take를 쓰는게 훨씬 이득이라..&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- deque-add-front &amp;amp;&amp;amp; deque-add-back&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.7&lt;/p&gt;
&lt;pre id=&quot;code_1562201812714&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot; data-tc-id=&quot;w-0.17956759784636434&quot;&gt;&lt;code&gt;;;deque-add-front: deque node -&amp;gt; deque
;;Return add node to front
(define (deque-add-front lst node)
  (append (list node) lst))

(check-expect (deque-add-front '() 1) '(1))
(check-expect (deque-add-front (deque-add-front '() 1) 2) '(2 1))
(check-expect (deque-add-front '(2 1) 3) '(3 2 1))

;;deque-add-back: deque node -&amp;gt; deque
;;Return add node to back
(define (deque-add-back lst node)
  (append lst (list node)))

(check-expect (deque-add-back '() 1) '(1))
(check-expect (deque-add-back (deque-add-back '() 1) 2) '(1 2))
(check-expect (deque-add-back '(1 2) 3) '(1 2 3))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 모든 6개 테스트 통과함!&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;hr /&gt;
&lt;p&gt;드디어 선형 자료구조가 끝났습니다!!&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;생각한 것보다 어렵지 않죠?&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;비선형 자료구조는 설명할 것이 조금 많습니다 ^^&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;시작해볼까요?&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;2.4 트리(Tree)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2r4tl/btqwATDbdML/pdBoEsE1lVUnor2MgdcCnK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2r4tl/btqwATDbdML/pdBoEsE1lVUnor2MgdcCnK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2r4tl/btqwATDbdML/pdBoEsE1lVUnor2MgdcCnK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2r4tl%2FbtqwATDbdML%2FpdBoEsE1lVUnor2MgdcCnK%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;몬드리안 회색나무[from &lt;a href=&quot;https://www.wikiwand.com/en/Piet_Mondrian&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;여러&amp;nbsp;노드가&amp;nbsp;한&amp;nbsp;노드를&amp;nbsp;가리킬&amp;nbsp;수&amp;nbsp;없는&amp;nbsp;구조로 계층적인 데이터를 표현하는데 유리하다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;나무 모양이 보이는지 그림으로 봐보자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsab93/btqwCqHFDkb/BxhY00Pd4L66lqPDa5xSPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsab93/btqwCqHFDkb/BxhY00Pd4L66lqPDa5xSPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsab93/btqwCqHFDkb/BxhY00Pd4L66lqPDa5xSPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbsab93%2FbtqwCqHFDkb%2FBxhY00Pd4L66lqPDa5xSPk%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;생물 계통 분류[from &lt;a href=&quot;https://www.wikiwand.com/ko/%EC%83%9D%EB%AC%BC_%EB%B6%84%EB%A5%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;트리는 각 데이터를 나타내는 노드(Node)와 간선(Edge)으로 이루어진다.&lt;/p&gt;
&lt;p&gt;트리의 정상에는 한개의 노드가 있고, 이를 루트(Root)라 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;트리의 정의&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;...더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p&gt;트리는 다음과 같이 재귀적으로 정의할 수 있다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxEGTg/btqwBYq3isG/7MlMfDGFKgY9VuJKyTHD6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxEGTg/btqwBYq3isG/7MlMfDGFKgY9VuJKyTHD6k/img.png&quot; data-alt=&quot;트리 정의[Data Structure &amp;amp;amp;amp; Their Algorithms, 99P]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxEGTg/btqwBYq3isG/7MlMfDGFKgY9VuJKyTHD6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxEGTg%2FbtqwBYq3isG%2F7MlMfDGFKgY9VuJKyTHD6k%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;트리 정의[Data Structure &amp;amp; Their Algorithms, 99P]&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;
&lt;li&gt;간선이 없는 하나의 특별한 노드가 존재하며 트리이다.루트(Root)를 뜻함.&lt;/li&gt;
&lt;li&gt;$T_1, ..., T_k (k \geq 1)$는 공통된 노드가 없는 트리, $r_1, ..., r_k$는 각 트리의 루트며 $r$은 새로운 노드라 가정하자.트리 $T$는 $T_1, ..., T_k$의 노드와 간선, 새로운 노드 $r$와 새로운 간선 $&amp;lt;r,r_1&amp;gt;, ..., &amp;lt;r, r_k&amp;gt;$로 구성된다.$T$의 루트는 $r$이며 $T_1, ..., T_k$는 $T$의 서브트리(Subtree)라 불린다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;트리는 아무래도 구조적으로 복잡하기 때문에 용어도 다양하다.&lt;/p&gt;
&lt;p&gt;그 중 중요한 것만 몇개 소개한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부모(Parent), 자식(Child), 형제(Brother)&lt;br /&gt;트리 정의 그림에서 $C$는 자식 $A$, $B$를 가지고 있는 부모이다.&lt;br /&gt;$A$와 $B$는 형제 노드다.&lt;/li&gt;
&lt;li&gt;말단(Terminal) or 리프(Leaf)&lt;br /&gt;자식이 없는 노드. $A$, $B$, $D$, $E$ 노드가 해당된다.&lt;/li&gt;
&lt;li&gt;깊이(Depth)와 높이(Height)&lt;br /&gt;깊이는 루트로부터 거친 길이. $C$는 2, $A$는 3다.&lt;br /&gt;높이는 가장 긴 깊이. 여기선 3.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;트리 중 자식노드를 2개까지만 가질 수 있는 것을 이진트리(Binary Tree)라 부른다.&lt;/p&gt;
&lt;p&gt;여러개의 자식을 가지면 다루기가 까다로우므로 이진트리를 사용하는 경우가 많다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;200&quot; height=&quot;167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEOK4w/btqwCQ7aZ9k/YmudnUB55fzajqya8C7pdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEOK4w/btqwCQ7aZ9k/YmudnUB55fzajqya8C7pdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEOK4w/btqwCQ7aZ9k/YmudnUB55fzajqya8C7pdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEOK4w%2FbtqwCQ7aZ9k%2FYmudnUB55fzajqya8C7pdk%2Fimg.png&quot; width=&quot;200&quot; height=&quot;167&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: center;&quot;&gt;이진트리[from &lt;a href=&quot;https://www.wikiwand.com/ko/%ED%8A%B8%EB%A6%AC_%EA%B5%AC%EC%A1%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;트리의 순회&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;각각의&amp;nbsp;노드를&amp;nbsp;정확히&amp;nbsp;한&amp;nbsp;번만,&amp;nbsp;체계적인&amp;nbsp;방법으로&amp;nbsp;방문하는&amp;nbsp;과정을&amp;nbsp;말한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;방식으로는 전위, 중위, 후위, 레벨 순회가 존재한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;전위, 중위, 후위는 한번 들어본적 있죠?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/32&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 2. - 데이터 타입.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;시간에 Racket이란 언어는 전위 표기법을 이용한 언어라면서&lt;/p&gt;
&lt;p&gt;&lt;a title=&quot;&quot; href=&quot;https://black7375.tumblr.com/post/169264990885/전위-중위-후위-표기법&quot;&gt;https://black7375.tumblr.com/post/169264990885/전위-중위-후위-표기법&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1562697411551&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a title=&quot;&quot; href=&quot;https://black7375.tumblr.com/post/169264990885/%EC%A0%84%EC%9C%84-%EC%A4%91%EC%9C%84-%ED%9B%84%EC%9C%84-%ED%91%9C%EA%B8%B0%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-original-url=&quot;https://black7375.tumblr.com/post/169264990885/전위-중위-후위-표기법&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/suozs/hyBWxe0ny3/EPkIWYEGPGKMjufnbm6OJ1/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/byBdvd/hyBWvnYIyN/fikzPkEn3UkX88P1B3yI80/img.png?width=820&amp;amp;height=1103&amp;amp;face=0_0_820_1103,https://scrap.kakaocdn.net/dn/cBvC5k/hyBUZ5kSw2/XIJ6h8NNBq7Pv5emZWPXjK/img.png?width=1280&amp;amp;height=837&amp;amp;face=0_0_1280_837');&quot; title=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot; title=&quot;&quot;&gt;
&lt;p class=&quot;og-title&quot; title=&quot;&quot;&gt;전위, 중위, 후위 표기법.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; title=&quot;&quot;&gt;이글을 제대로 보기위해서는 링크로 들어가시기를 권합니다. 연산자의 위치에 따라 전위, 중위 후위 표기법으로 분류가 된다. 1. 전위 표기법. $$\text{연산자 피연산자 피연산자}$$ 방식으로 표기한다. 일반 폴란드 표기법(NPN), 루카쉐비치 표기법, 바르샤바 표기법, 폴란드 접두사 표기법이라고도 한다. 특징. 쉽게 결정되는 연산순서. 연산자의 순서만...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; title=&quot;&quot;&gt;black7375.tumblr.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p class=&quot;&quot;&gt;을 소개한 적이 있다. 읽고 오자.&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;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A0RFU/btqwFBnIAbU/AehIUBYyaPIGNkA4T9lBFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A0RFU/btqwFBnIAbU/AehIUBYyaPIGNkA4T9lBFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A0RFU/btqwFBnIAbU/AehIUBYyaPIGNkA4T9lBFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA0RFU%2FbtqwFBnIAbU%2FAehIUBYyaPIGNkA4T9lBFk%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그럼, 전위 중위 후위 순회방식을 그림을 통해 비교해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9X8f5/btqwDIIt5kH/86TV9fyUa97ljfxFEuhNa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9X8f5/btqwDIIt5kH/86TV9fyUa97ljfxFEuhNa1/img.png&quot; data-alt=&quot;전위 중위 후위&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9X8f5/btqwDIIt5kH/86TV9fyUa97ljfxFEuhNa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9X8f5%2FbtqwDIIt5kH%2F86TV9fyUa97ljfxFEuhNa1%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;전위 중위 후위&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;2에서 1을 빼고 싶다 가정할 때&lt;/p&gt;
&lt;p&gt;전위는 $-\; 2\; 1$, 중위는 $2\; -\; 1$ 후위는 $2\; 1\; -$ 방식으로 순회한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;완전히 같진 않지만.. 삼각함수를 떠올리면 의외로 쉽게 익힐 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CqZUf/btqwDuReQYJ/jI44NIC2NmRV7FT4cm1TKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CqZUf/btqwDuReQYJ/jI44NIC2NmRV7FT4cm1TKK/img.png&quot; data-alt=&quot;코사인, 사인, 탄젠트(sin의 방향은 주의하세요!!)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CqZUf/btqwDuReQYJ/jI44NIC2NmRV7FT4cm1TKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCqZUf%2FbtqwDuReQYJ%2FjI44NIC2NmRV7FT4cm1TKK%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;/&gt;&lt;/span&gt;&lt;figcaption&gt;코사인, 사인, 탄젠트(sin의 방향은 주의하세요!!)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;전위, 중위, 후위 방식으로 복잡한 트리를 순회해보면 다음과 같이 나타난다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0eozi/btqwD3Mtygc/UZJn0MHkEK2TlOZdafafkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0eozi/btqwD3Mtygc/UZJn0MHkEK2TlOZdafafkK/img.png&quot; style=&quot;width: 32.1784%;&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0eozi/btqwD3Mtygc/UZJn0MHkEK2TlOZdafafkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0eozi%2FbtqwD3Mtygc%2FUZJn0MHkEK2TlOZdafafkK%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sKl3P/btqwFQlhNWB/mVEFmKYrSivaw4clk1wh6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sKl3P/btqwFQlhNWB/mVEFmKYrSivaw4clk1wh6k/img.png&quot; style=&quot;width: 32.0145%;&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sKl3P/btqwFQlhNWB/mVEFmKYrSivaw4clk1wh6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsKl3P%2FbtqwFQlhNWB%2FmVEFmKYrSivaw4clk1wh6k%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bh8lOk/btqwDtEMQZy/5ArFaskQctr1Z7js50cxi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bh8lOk/btqwDtEMQZy/5ArFaskQctr1Z7js50cxi1/img.png&quot; style=&quot;width: 31.1559%;&quot; title=&quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bh8lOk/btqwDtEMQZy/5ArFaskQctr1Z7js50cxi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbh8lOk%2FbtqwDtEMQZy%2F5ArFaskQctr1Z7js50cxi1%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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;전위, 중위, 후위 순회&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;레벨 순회는 높이대로 돌면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JOmUa/btqwGi9GCSu/C269ZtKlOhgLrb17Y9iaa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JOmUa/btqwGi9GCSu/C269ZtKlOhgLrb17Y9iaa1/img.png&quot; data-alt=&quot;레벨 순회&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JOmUa/btqwGi9GCSu/C269ZtKlOhgLrb17Y9iaa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJOmUa%2FbtqwGi9GCSu%2FC269ZtKlOhgLrb17Y9iaa1%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;/&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;그럼 코드로 트리를 표현해보자.&lt;/p&gt;
&lt;p&gt;놀랍게도 달랑 이게 끝이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 6.8&lt;/p&gt;
&lt;pre id=&quot;code_1562712206376&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'(+ (/ (* 4 (+ 3 (- 2 1)))
       1)
    (* 2 3))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;racket은 코드가 데이터, 데이터가 코드가 될 수 있으므로 가능한 일!!&lt;/p&gt;
&lt;p&gt;이제 왜 생소한 racket을 강좌 언어로 택했는지 이해가 가길 시작할 것이다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;놀라긴 아직 이르지만 ㅎㅎㅎ&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1줄 짜리 리스트의 형태로도 표현이 가능하지만(레벨 순회를 그대로 나타낸 것) 보다시피 공간낭비가 심하고, 직관적이지 않다.&lt;/p&gt;
&lt;pre id=&quot;code_1562714322390&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'(+
  / *
  * 1 2 3
  4 + '() '() '() '() '() '()
  '() '() 3 - ...)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;+.&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;참조: &lt;a href=&quot;https://en.wikipedia.org/wiki/Book:Fundamental_Data_Structures&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fundamental&amp;nbsp;Data&amp;nbsp;Structures&lt;/a&gt;, &lt;a href=&quot;https://en.wikibooks.org/wiki/Data_Structures&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Data&amp;nbsp;Structures&lt;/a&gt;, Data Structures &amp;amp; Their Algorithms(Harry R. Lewis, 1991), Introduction&amp;nbsp;to&amp;nbsp;Algorithms(Thomas&amp;nbsp;H.&amp;nbsp;Cormen, 2013)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/설계</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/61</guid>
      <comments>https://black7375.tistory.com/61#entry61comment</comments>
      <pubDate>Mon, 20 May 2019 09:53:19 +0900</pubDate>
    </item>
    <item>
      <title>초기 컴퓨터 역사</title>
      <link>https://black7375.tistory.com/60</link>
      <description>&lt;p&gt;컴퓨터는 사람대신 계산을 편리하게 만들어주기 위해 만들어진 장치이다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;여기서 간략한 역사를 알아보자.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;0. 초기.&lt;/h2&gt;&lt;p&gt;아날로그 형식의 계산기를 소개한다.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;0.1 주판.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;기원전 2700–2300년에 바빌로니아 인들이 만들어졌다고 알려져있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;현대의 주판의 형태를 만든 것은 바로 기원전 2세기 중국인들이었다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 247px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999CDC4F5C8A665C10&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999CDC4F5C8A665C10&quot; width=&quot;247&quot; height=&quot;145&quot; filename=&quot;Abacus_Chinese.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;5진법에 기반해 만들어진 주판(2:5)으로, 위칸의 구슬 1개는 아래 구슬 5개를 의미했다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;또 위칸의 구슬 2개를 내리면 10을 의미하고, 왼쪽 아랫칸의 구슬을 올리는 식이었다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일본인들은 이를 계량해 1:4 주판을 만들었다.&lt;/p&gt;&lt;p&gt;굳이 윗줄 2개를 비운뒤 왼쪽 아래줄을 하나 올리거나 아랫줄 5개를 비우고 윗줄 1개를 추가하지 않아도 된다는 것을 깨달았기 때문이다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;원래 작성하려고 했으나 시간 관계상? 생략한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://namu.wiki/w/%EC%A3%BC%ED%8C%90&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;나무위키 - 주판&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;참고.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;0.2 네이피어의 봉.&lt;/h3&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 421px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996DF3405C902F532A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996DF3405C902F532A&quot; width=&quot;421&quot; height=&quot;389&quot; filename=&quot;네이피어봉.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;로그로 유명한 수학자, 네이피어다.&lt;/p&gt;&lt;p&gt;Cheet Sheet처럼 간단하게 적어놓은 네이피어 봉이 곱셈을 쉽게 도와주었다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Napier's_bones&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;위키백과&lt;/a&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Napier's_bones&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt; - Napier's Bones&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;네이피어 봉이 발전하여 &lt;a href=&quot;https://en.wikipedia.org/wiki/Slide_rule&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;계산자&lt;/a&gt;의 형태가 된다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9997593F5C90381F32&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9997593F5C90381F32&quot; width=&quot;800&quot; height=&quot;449&quot; filename=&quot;Sliderule.PickettN902T.agr.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://namu.wiki/w/%EA%B3%84%EC%82%B0%EC%9E%90&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;나무위키 - 계산자&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;0.3 파스칼의 톱니바퀴 계산기.&lt;/h3&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 330px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998F263F5C901E3B1A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998F263F5C901E3B1A&quot; width=&quot;330&quot; height=&quot;220&quot; filename=&quot;Pascaline-CnAM_823-1-IMG_1506-black.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 330px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F65B3A5C901E3E1B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F65B3A5C901E3E1B&quot; width=&quot;330&quot; height=&quot;276&quot; filename=&quot;330px-Pascaline_-_top_view_and_mechanism.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;기계식 수동 계산기이다.&lt;/p&gt;&lt;p&gt;6개의 각 다이얼은 누산기와 값을 저장하는 두 개의 톱니바퀴로 이루어져 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;참고.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Pascal's_calculator&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;위키백과 - Pascal's calculator&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;0.4 재쿼드의 방직기&lt;/h3&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9961DF385C90203C1A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9961DF385C90203C1A&quot; width=&quot;700&quot; height=&quot;467&quot; filename=&quot;jaquardmp3gallery.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;직물을 짜기 위한 방직기.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;섬유 패턴과 색을 자동으로 짜넣기 위해 천공카드를 이용했다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F3AC455C90209622&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F3AC455C90209622&quot; width=&quot;700&quot; height=&quot;1050&quot; filename=&quot;daughersofdecay-punchcards_700x1050.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;동작.&lt;/b&gt;&lt;/p&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/OlJns3fPItE?rel=0&quot; width=&quot;560&quot; height=&quot;420&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Jacquard_loom&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;위키백과 - Jacquard Loom.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;계산기는 아니지만, 천공카드는 초기 컴퓨터 역사에서 큰 역할을 했으니 알아두자.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;0.5 배비지의 기관들.&lt;/h3&gt;&lt;h4&gt;차분기관&lt;/h4&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9942FD355C9031622C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9942FD355C9031622C&quot; width=&quot;800&quot; height=&quot;698&quot; filename=&quot;Difference_engine.JPG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;다항함수를 계산하기 위한 기계식 디지털 계산기.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;재쿼드와 함께 차분기관을 만들었다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;이론적 배경.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Difference_engine&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;위키백과 - &lt;/a&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Difference_engine&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Difference E&lt;/a&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Difference_engine&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;ngine&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;동작.&lt;/b&gt;&lt;/p&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/BlbQsKpq3Ak?rel=0&quot; width=&quot;560&quot; height=&quot;420&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;19세기 기술로 만들 수 있나 갑론을박이 많았는데, 재현에 성공.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;해석기관.&lt;/h4&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997D11475C9045AC14&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997D11475C9045AC14&quot; width=&quot;800&quot; height=&quot;1066&quot; filename=&quot;Analytical_Engine_(2290032530).jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;튜링 완전하고, 프로그래밍이 가능한 기관이다.&lt;/p&gt;&lt;p&gt;증기기관과 천공카드를 이용하도록 설계되었는데 이건 재현되지 않았고  &lt;a href=&quot;https://www.plan28.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Plan 28&lt;/a&gt;이라고 만드는 프로젝트가 있긴하다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;기타정보.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Analytical_Engine&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;위키백과 - Analytical &lt;/a&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Analytical_Engine&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Engine&lt;/a&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;0.6 홀러리스의 천공카드&lt;/h3&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991E673F5C9044A00A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991E673F5C9044A00A&quot; width=&quot;800&quot; height=&quot;600&quot; filename=&quot;HollerithMachine.CHM.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;IBM의 창시자로서, &lt;a href=&quot;https://en.wikipedia.org/wiki/Punched_card&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;천공카드&lt;/a&gt;를 이용한 &lt;a href=&quot;https://en.wikipedia.org/wiki/Tabulating_machine&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;일괄처리 시스템&lt;/a&gt;(타뷸레이팅)을 만들었다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이 기계를 이용해서 빠르게 통계를 낼 수 있었다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/9HXjLW7v-II?rel=0&quot; width=&quot;560&quot; height=&quot;420&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;기타 출처.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.cha.go.kr/cop/bbs/selectBoardArticle.do?nttId=22052&amp;amp;bbsId=BBSMSTR_1008&amp;amp;mn=NS_01_09_01&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;어려운 계산도 척척 동양의 지혜‘주산’&lt;/a&gt; , &lt;a href=&quot;https://www.nms.ac.uk/jacquardloom&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;National Museum of Scotland(J&lt;/a&gt;&lt;a href=&quot;https://www.nms.ac.uk/jacquardloom&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;acquard L&lt;/a&gt;&lt;a href=&quot;https://www.nms.ac.uk/jacquardloom&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;oom&lt;/a&gt;&lt;a href=&quot;https://www.nms.ac.uk/jacquardloom&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;)&lt;/a&gt;, &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>IT</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/60</guid>
      <comments>https://black7375.tistory.com/60#entry60comment</comments>
      <pubDate>Fri, 15 Mar 2019 00:01:51 +0900</pubDate>
    </item>
    <item>
      <title>ZSH 설정  소개</title>
      <link>https://black7375.tistory.com/59</link>
      <description>&lt;p&gt;학교 가는 걸 예상 못했고, 부전공에 자격증 공부까지 하게 생긴지라(올 전공 과목만 듣는다니 ㅠㅠ)&lt;/p&gt;
&lt;p&gt;올해에는 안그래도 뜸했던 블로그 글의 주기가 더 길어질 것으로 예측된다.&lt;/p&gt;
&lt;p&gt;TMI: 7수강(1청강), 6전공, 5팀플이라 한다.&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;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/15&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2017/08/24 - [컴퓨터/리눅스] - 리눅스에서 터미널 생활 즐기기.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;에서 간단히만 소개했던 내 Zsh 설정에 대해 소개하고자 한다.&lt;/p&gt;
&lt;p&gt;소스는 아래에서 볼 수 있다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;멀티플랫폼(우분투 말고, 레드햇, 아치, 맥, FreeBSD 대응 중)이니 조금만 기다려보세요ㅋㅋ&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;대응완료.&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;blockquote class=&quot;embedly-card&quot;&gt;
&lt;h4&gt;&lt;a href=&quot;https://github.com/black7375/BlaCk-Void-Zsh&quot;&gt;BlaCk-Void-Zsh&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Awesome Zsh Setting&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/996344435C76D27404?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/996344435C76D27404?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996344435C76D27404&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996344435C76D27404&quot; width=&quot;800&quot; height=&quot;440&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;h2&gt;1. 기능 소개.&lt;/h2&gt;
&lt;h3&gt;1.1 강력한 보기.&lt;/h3&gt;
&lt;h4&gt;- 프롬프트.&lt;/h4&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99673C3D5C7706BC18?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99673C3D5C7706BC18?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99673C3D5C7706BC18&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99673C3D5C7706BC18&quot; width=&quot;800&quot; height=&quot;592&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;프롬프트는 두가지 줄로 이루어진다.&lt;/p&gt;
&lt;p&gt;윗줄은 정보 표시, 아랫줄은 명령어를 적는 용도다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;윗줄.&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;왼쪽&lt;/b&gt;: 계정 정보, root 유저, ssh 사용, 디렉토리 위치, 쓰기 권한, VCS 정보&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;오른쪽&lt;/b&gt;: 결과 상태, 배경 작업, 명령 수행 시간, 내역, zsh 로딩 시간&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;을 제공한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;아랫줄.&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li class=&quot;&quot;&gt;문법 강조, 자동 추천을 해준다.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;자동 추천이 뜰 때 &lt;b&gt;오른쪽 방향키($\rightarrow$)&lt;/b&gt;로 완성할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;심플 테마&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;bvzsh-pure.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cE5cpO/btqtXBKSbLw/H2h7xuw6Cz6xDIbJjWP41K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cE5cpO/btqtXBKSbLw/H2h7xuw6Cz6xDIbJjWP41K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cE5cpO/btqtXBKSbLw/H2h7xuw6Cz6xDIbJjWP41K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcE5cpO%2FbtqtXBKSbLw%2FH2h7xuw6Cz6xDIbJjWP41K%2Fimg.png&quot; data-filename=&quot;bvzsh-pure.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;윗줄.&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;디렉토리 위치, VCS 정보, 계정 정보, 쓰기 권한, root 유저, 명령 수행 시간&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;아랫줄.&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;왼쪽&lt;/b&gt;: 프롬프트 상태, 명령어 입력&lt;/li&gt;
&lt;ul&gt;
&lt;li class=&quot;&quot;&gt;문법 강조, 자동 추천을 해준다.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;자동 추천이 뜰 때 &lt;b&gt;오른쪽 방향키($\rightarrow$)&lt;/b&gt;로 완성할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;오른쪽&lt;/b&gt;:&amp;nbsp; 배경 작업, 결과 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;[실험적] 커스텀 또는 테마 전환 방법.&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;&quot;&gt;홈으로 파일 복사.&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cp $BVZSH/BlaCk-Void.ztheme ~/.ztheme&lt;/code&gt; 커스텀하기!!&lt;/li&gt;
&lt;li&gt;&lt;code&gt;export BVZSH_THEME=&amp;rsquo;THEME MODE&amp;rsquo;&lt;/code&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;제약사항: &lt;code&gt;~/.ztheme&lt;/code&gt;에서만 동작.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;code&gt;THEME MODE&lt;/code&gt; 리스트: &lt;code&gt;auto&lt;/code&gt;, &lt;code&gt;powerline&lt;/code&gt;, &lt;code&gt;simple&lt;/code&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auto&lt;/code&gt;: 기본값은 파워라인.&lt;br /&gt;xter이나 256색을 지원하지 않으면, simple 테마가 활성화 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;FAQ: 왜 &lt;code&gt;zsh-theme&lt;/code&gt;는 더이상 지원하지 않습니까? || 사용하는 도중 바꿀 수 있나요?&lt;br /&gt;&lt;a href=&quot;https://github.com/romkatv/powerlevel10k#i-am-getting-an-error-zsh-bad-math-expression-operand-expected-at-end-of-string&quot;&gt;powerlevel10k&lt;/a&gt;가 지원하지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p class=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;- Git&lt;/h4&gt;
&lt;p&gt;Git과의 상호작용은 파일 관리자와 비교하면서 쉽게 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/999AF13A5C770BC416&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/999AF13A5C770BC416&quot; title=&quot;&quot; style=&quot;width: 31.7829%;&quot; width=&quot;266&quot; height=&quot;209&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999AF13A5C770BC416&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999AF13A5C770BC416&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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9926FD385C770BC418&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9926FD385C770BC418&quot; title=&quot;&quot; style=&quot;width: 31.7829%;&quot; width=&quot;266&quot; height=&quot;209&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9926FD385C770BC418&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9926FD385C770BC418&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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/996EE4475C770BC417&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/996EE4475C770BC417&quot; title=&quot;&quot; style=&quot;width: 31.7829%;&quot; width=&quot;266&quot; height=&quot;209&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996EE4475C770BC417&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996EE4475C770BC417&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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99FC0D3C5C770BC419&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99FC0D3C5C770BC419&quot; title=&quot;&quot; style=&quot;width: 31.7829%;&quot; width=&quot;266&quot; height=&quot;209&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FC0D3C5C770BC419&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FC0D3C5C770BC419&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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9983EE4A5C770BC417&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9983EE4A5C770BC417&quot; title=&quot;&quot; style=&quot;width: 31.7829%;&quot; width=&quot;266&quot; height=&quot;209&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9983EE4A5C770BC417&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9983EE4A5C770BC417&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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99D3E44B5C770BC319&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99D3E44B5C770BC319&quot; title=&quot;&quot; style=&quot;width: 31.7829%;&quot; width=&quot;266&quot; height=&quot;209&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D3E44B5C770BC319&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D3E44B5C770BC319&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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;차례대로&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;&lt;i&gt;원본 - 아무 파일 추가 - 파일 수정&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;&lt;i&gt;스태이징 - 커밋 - 푸시&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;를 진행한 상태.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;깃에 대해 알고 싶다면 아래 글을 참조.&lt;/p&gt;
&lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/163759962440&quot; data-did=&quot;59c64e01875be0b31c70782b9ea96e3166929afe&quot;&gt;&lt;a title=&quot;&quot; href=&quot;https://black7375.tumblr.com/post/163759962440/누구나-쉽게-이해할-수-있는-git-입문-버전-관리를-완벽하게-이용해보자&quot;&gt;https://black7375.tumblr.com/post/163759962440/누구나-쉽게-이해할-수-있는-git-입문-버전-관리를-완벽하게-이용해보자&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
&lt;script src=&quot;https://assets.tumblr.com/post.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;1.2 쉬운 명령어 입력.&lt;/h3&gt;
&lt;h4&gt;- 자동 짝 맞추기.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99B9F1455C7A329B30?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99B9F1455C7A329B30?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B9F1455C7A329B30&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B9F1455C7A329B30&quot; width=&quot;800&quot; height=&quot;530&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;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;- 고치기.&lt;/h4&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;571&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/991580505C771CEA20?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/991580505C771CEA20?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991580505C771CEA20&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991580505C771CEA20&quot; width=&quot;800&quot; height=&quot;571&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;/p&gt;
&lt;p&gt;실행이 제대로 안될 경우, 그냥 &lt;code&gt;fuck&lt;/code&gt;이라 치면 제안해준다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;- 정보 표시.&lt;/h4&gt;
&lt;div class=&quot;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99AC8A435C77E6E611?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99AC8A435C77E6E611?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99AC8A435C77E6E611&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99AC8A435C77E6E611&quot; width=&quot;800&quot; height=&quot;521&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;code class=&quot;none&quot;&gt;&lt;span style=&quot;color: #3daee9;&quot;&gt;Alias tip&lt;/span&gt;&lt;/code&gt;으로 표시해준다.&lt;/div&gt;
&lt;div class=&quot;&quot;&gt;명령어를 치는 도중 '&lt;b&gt;탭&amp;lt;TAB&amp;gt;&lt;/b&gt;'을 누르면 분류별로 나누어 추천해준다.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9998DE4F5C77DF4711&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9998DE4F5C77DF4711&quot; title=&quot;&quot; style=&quot;width: 48.8372%;&quot; width=&quot;400&quot; height=&quot;273&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9998DE4F5C77DF4711&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9998DE4F5C77DF4711&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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/996005405C77DF482D&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/996005405C77DF482D&quot; title=&quot;&quot; style=&quot;width: 48.8372%;&quot; width=&quot;400&quot; height=&quot;273&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996005405C77DF482D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996005405C77DF482D&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;&quot; height=&quot;&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;위쪽($\uparrow$) 방향키&lt;/b&gt;를 누르면 예전에 입력했던 명령어(history) 중에서 검색할 수 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h4&gt;- Fzf 통합.&lt;/h4&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;547&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/994190345C77E27D06?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/994190345C77E27D06?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994190345C77E27D06&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994190345C77E27D06&quot; width=&quot;800&quot; height=&quot;547&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;Ctrl+t&lt;/b&gt;: 파일과 디렉토리 선택.&lt;br /&gt;&lt;b&gt;&amp;lt;TAB&amp;gt;&lt;/b&gt;으로 여러 개를 선택 가능.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;Ctrl+r&lt;/b&gt;: history 선택.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;Alt+c&lt;/b&gt;: 디렉토리 선택.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;code&gt;명령어 **&lt;/code&gt;&lt;b&gt; + &amp;lt;TAB&amp;gt;&lt;/b&gt;: &lt;code&gt;vi **&lt;/code&gt;처럼 입력 후 선택.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ssh&lt;/code&gt;, &lt;code&gt;telnet&lt;/code&gt;, &lt;code&gt;kill&lt;/code&gt;, &lt;code&gt;unset&lt;/code&gt;, &lt;code&gt;export&lt;/code&gt; 등과 결합.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;이 부분은 &lt;a class=&quot;tx-link&quot; href=&quot;https://github.com/junegunn/fzf#key-bindings-for-command-line&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fzf&lt;/a&gt; 참고.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;- Git.&lt;/h4&gt;
&lt;p&gt;매우 간단하게 git을 사용할 수 있도록 해준다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;code&gt;c&lt;/code&gt;: commit&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt;: add&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p&lt;/code&gt;: push&lt;/li&gt;
&lt;li&gt;&lt;code&gt;u&lt;/code&gt;: pull&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt;: remote&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt;: status&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Git X Fzf&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;code&gt;ga&lt;/code&gt;: git add&lt;/li&gt;
&lt;li&gt;&lt;code&gt;glo&lt;/code&gt;: git log&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gi&lt;/code&gt;: gitignore&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gd&lt;/code&gt;: git diff&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gcf&lt;/code&gt;: git checkout&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gss&lt;/code&gt;: git stash&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gclean&lt;/code&gt;: git clean&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;- 기타.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99C61C3E5C77F13313?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99C61C3E5C77F13313?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C61C3E5C77F13313&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C61C3E5C77F13313&quot; width=&quot;800&quot; height=&quot;521&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;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;code&gt;bookmark [mark]&lt;/code&gt;:[mark]로 북마크.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jump [mark]&lt;/code&gt;: [mark]의 디렉토리로 이동.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;showmarks [mark]&lt;/code&gt;: [mark]의 디렉토리를 보여줌.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deletemark [mark]&lt;/code&gt;: [mark] 제거.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd dots..&lt;/code&gt;: &amp;lt;dots&amp;gt; 갯수만큼 상위폴더로 이동.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;j [keyword]&lt;/code&gt;: [keyword]와 유사한 디렉토리로 이동.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;1.3 터미널 유틸리티.&lt;/h3&gt;
&lt;h4&gt;- 인터넷 도구들.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/996266435C76D27404?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/996266435C76D27404?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996266435C76D27404&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996266435C76D27404&quot; width=&quot;800&quot; height=&quot;458&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;code&gt;prettyping&lt;/code&gt;: 알흠다운 핑을 보여준다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip-info&lt;/code&gt;: IP정보를 알려준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;- 터미널 이미지 뷰어.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9965A1505C78114F2E?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9965A1505C78114F2E?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9965A1505C78114F2E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9965A1505C78114F2E&quot; width=&quot;800&quot; height=&quot;521&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 class=&quot;&quot;&gt;프리뷰처럼 이미지를 보여줍니다.&lt;/p&gt;
&lt;p&gt;명령어 &lt;code&gt;img&lt;/code&gt;로 쓰면 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;사용법&lt;/b&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;img FILE_NAME TIME(option)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;i&gt;TIME 기본값은 2초&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;지원 터미널&lt;/b&gt;: Konsole, Xterm, Urxvt, Terminology, Yakuake, Terminal.app&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;미지원 터미널&lt;/b&gt;: Terminator, Hyper, Tilix, Gnome Terminal, Guake, LXterminal, Putty, Alacritty&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;미지원 터미널들을 위해서.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://github.com/radare/tiv&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;tiv&lt;/a&gt; or &lt;a class=&quot;tx-link&quot; href=&quot;https://www.nongnu.org/fbi-improved/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fim&lt;/a&gt;를 사용하면 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;- 날씨.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99D1213C5C7814AF2F?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99D1213C5C7814AF2F?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D1213C5C7814AF2F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D1213C5C7814AF2F&quot; width=&quot;800&quot; height=&quot;636&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;사용법&lt;/b&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;weather&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;또는&lt;/p&gt;
&lt;p&gt;&lt;code&gt;weather LOCALE LANGUAGE(option)&lt;/code&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;i&gt;기본 언어: 시스템 언어.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;- 지도.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;800&quot; height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/995DCE405C78208603?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/995DCE405C78208603?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995DCE405C78208603&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995DCE405C78208603&quot; width=&quot;800&quot; height=&quot;636&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;사용법:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;map&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;2. 설치.&lt;/h2&gt;
&lt;h3&gt;2.1 지원 플랫폼.&lt;/h3&gt;
&lt;ul&gt;
&lt;li class=&quot;&quot;&gt;리눅스&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;데비안-기반(우분투, 데비안, 민트 ..), RPM-기반(페도라, CentOS, 레드햇..), 팩맨-기반(아치, 만자로 ..)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;타 OS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;맥, Free-BSD 기반&lt;/p&gt;
&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;요구사항
&lt;ul&gt;
&lt;li&gt;bash&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;설치&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;pre class=&quot;crmsh&quot; data-tc-id=&quot;w-0.3303722198068211&quot;&gt;&lt;code&gt;git clone https://github.com/black7375/BlaCk-Void-Zsh.git ~/.zsh
bash ~/.zsh/BlaCk-Void-Zsh.sh&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li class=&quot;&quot;&gt;터미널 설정.&lt;br /&gt;Nerd Fonts 중 하나를 터미널 폰트로 지정하고 재시작.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;만약 멋진 Tmux도 원한다면&amp;nbsp; &lt;a class=&quot;tx-link&quot; href=&quot;https://github.com/black7375/BlaCk-Void-Tmux/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BlaCk-Void-Tmux&lt;/a&gt;도 확인해보세요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 class=&quot;&quot;&gt;2.2 다른 OS.&lt;/h2&gt;
&lt;p&gt;요구사항&lt;/p&gt;
&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.zsh.org/&quot; rel=&quot;nofollow&quot;&gt;zsh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;fzf&lt;/a&gt;[통합]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;ripgrep&lt;/a&gt;[fzf 필터]&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/powerline/powerline&quot;&gt;powerline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ryanoasis/nerd-fonts&quot;&gt;powerline support font&lt;/a&gt;(아래 문단에서 설명 예정.)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://w3m.sourceforge.net&quot; rel=&quot;nofollow&quot;&gt;w3m-img&lt;/a&gt;(터미널 이미지 뷰어를 위한 옵션)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wting/autojump&quot;&gt;Autojump&lt;/a&gt;(&lt;code&gt;j&lt;/code&gt;를 위한 옵션)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://beyondgrep.com/&quot; rel=&quot;nofollow&quot;&gt;ack&lt;/a&gt;(&lt;a href=&quot;https://github.com/paoloantinori/hhighlighter&quot;&gt;h&lt;/a&gt;를 위한 옵션) | 할일: ack를 ripgrep으로 포팅.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;
&lt;p&gt;설치&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Git Clone&lt;br /&gt;&lt;code&gt;git clone https://github.com/black7375/BlaCk-Void-Zsh.git ~/.zsh &amp;amp;&amp;amp; cd ~/.zsh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;zplugin(antigen 대체)&lt;br /&gt;&lt;code&gt;sh -c &quot;$(curl -fsSL https://raw.githubusercontent.com/zdharma/zplugin/master/doc/install.sh)&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;nerdfont(powerline 지원 폰트)
&lt;pre class=&quot;vim&quot; data-tc-id=&quot;w-0.5876459455644001&quot;&gt;&lt;code&gt;git clone https://github.com/ryanoasis/nerd-fonts.git
cd nerd-fonts &amp;amp;&amp;amp; ./install.sh
cd ..
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;.zshrc에 추가&lt;/p&gt;
&lt;p&gt;파일 읽기[추천]&lt;br /&gt;&lt;code&gt;echo &quot;source BlaCk-Void.zshrc&quot; &amp;gt;&amp;gt; ~/.zshrc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;또는 링크&lt;br /&gt;&lt;code&gt;ln -svf BlaCk-Void.zshrc ~/.zshrc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;또는 복사(&lt;code&gt;zsh-update&lt;/code&gt; 불가)&lt;br /&gt;&lt;code&gt;cp -v BlaCk-Void.zshrc  ~/.zshrc&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Zsh 쉘 설정.&lt;br /&gt;&lt;code&gt;sudo chsh -s /usr/bin/zsh&lt;/code&gt;
&lt;p class=&quot;&quot;&gt;또는&lt;br /&gt;&lt;code&gt;sudo chsh -s $(which zsh)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;터미널 설정.&lt;br /&gt;&lt;a href=&quot;https://github.com/ryanoasis/nerd-fonts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nerd Fonts&lt;/a&gt; 중 하나를 터미널 폰트로 지정하고 재시작.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;2.3 업데이트.&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;zsh-update&lt;/code&gt;: BVZSH, 플러그인 매니저, 플러그인 업데이트.&lt;br /&gt;&lt;code&gt;font-update&lt;/code&gt;: Nerdfont 업데이트.&lt;/p&gt;
&lt;h1 class=&quot;&quot;&gt;3. 정보.&lt;/h1&gt;
&lt;h2&gt;3.1 테마.&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/romkatv/powerlevel10k&quot;&gt;Powerlevel10k&lt;/a&gt;(powerline theme, Really Fast and 100% replaceable &lt;a href=&quot;https://github.com/bhilburn/powerlevel9k&quot;&gt;Powerlevel9k&lt;/a&gt;)&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Simple theme based on &lt;a href=&quot;https://github.com/romkatv/dotfiles-public/blob/master/.purepower&quot;&gt;Purepower&lt;/a&gt;, inspired by &lt;a href=&quot;https://github.com/sindresorhus/pure&quot;&gt;Pure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2 class=&quot;&quot;&gt;3.2 플러그인.&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;플러그인 매니저&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zdharma/zplugin&quot;&gt;Zplugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;기본 저장소 (&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh&quot;&gt;robbyrussell&amp;rsquo;s oh-my-zsh&lt;/a&gt;).&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/autojumpp&quot;&gt;Autojump&lt;/a&gt;: homebrew, macports 또는 데비안/우분투 패키지로 설치된 &lt;a href=&quot;https://github.com/wting/autojump&quot;&gt;Autojump&lt;/a&gt; 활성화&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/command-not-found&quot;&gt;Command Not Found&lt;/a&gt;: 명령어가 없을때 command-not-found를 이용해 제안.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/fzf&quot;&gt;FZF&lt;/a&gt;: Fzf의 자동완성과 단축키를 활성화.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/wiki/Plugin:git&quot;&gt;Git&lt;/a&gt;: Git을 이용한 alias, 각종 함수들을 추가.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/pip&quot;&gt;Pip&lt;/a&gt;: pip의 자동완성 활성화.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/sudo&quot;&gt;Sudo&lt;/a&gt;: ESC를 두번 눌러 sudo 권한 실행.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/thefuck&quot;&gt;Thefuck&lt;/a&gt;: &lt;a href=&quot;https://github.com/nvbn/thefuck&quot;&gt;The Fuck&lt;/a&gt; 플러그인 &amp;mdash; 이전 콘솔 명령을 수정.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/tmux&quot;&gt;Tmux&lt;/a&gt;: &lt;a href=&quot;https://github.com/tmux/tmux&quot;&gt;Tmux&lt;/a&gt;를 위한 aliases 제공&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/tmuxinator&quot;&gt;Tmuxinator&lt;/a&gt;:&amp;nbsp; &lt;a href=&quot;https://github.com/achiu/terminitor&quot;&gt;tmuxinator&lt;/a&gt; 자동완성.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/urltools&quot;&gt;Urltools&lt;/a&gt;: URL 인코드(&lt;code&gt;urlencode&lt;/code&gt;)와 URL 디코드(&lt;code&gt;urldecode&lt;/code&gt;) 기능 제공.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;커스텀 저장소&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/chrissicool/zsh-256color&quot;&gt;Zsh 256 Color&lt;/a&gt;: 256 색으로 터미널 환경을 향상.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/djui/alias-tips&quot;&gt;Alias Tips&lt;/a&gt;: 셸 alias와 git alias를 기억하는 데 도움.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zsh-users/zsh-autosuggestions&quot;&gt;Zsh Autosuggestions&lt;/a&gt;: &lt;a href=&quot;https://fishshell.com/&quot; rel=&quot;nofollow&quot;&gt;Fish&lt;/a&gt;같이 빠르고 거를리지 않는 자동완성.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/hlissner/zsh-autopair&quot;&gt;Zsh Autopair&lt;/a&gt;: 일치하는 구분 기호를 자동으로 닫고, 삭제하고 뛰어넘기 제공.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/unixorn/autoupdate-antigen.zshplugin&quot;&gt;Autoupdate Antigen&lt;/a&gt;: Antigen과 bundle의 자동 업데이트.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/zsh-users/zsh-completions&quot;&gt;Zsh Completions&lt;/a&gt;: Zsh를 위한 추가적인 자동완성.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/b4b4r07/enhancd&quot;&gt;Enhancd&lt;/a&gt;: 대화형 필터를 사용하는 차세대 cd 명령어.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/zdharma/fast-syntax-highlighting&quot;&gt;Fast Syntax Highlighting&lt;/a&gt;: Zsh를 위한 빠르고 풍부한 문법강조.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/wfxr/forgit&quot;&gt;Forgit&lt;/a&gt;: Fzf를 이용해 Git 작업을 향상 시키는 도구.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ytet5uy4/fzf-widgets&quot;&gt;Fzf Widgets&lt;/a&gt;: FZF의 ZLE 위젯들.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/seletskiy/zsh-git-smart-commands&quot;&gt;Zsh Git Smart Commands&lt;/a&gt;: 효율적을 사용하도록 만든 Git의 alias 랩퍼.&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/smallhadroncollider-deprecated/antigen-git-store&quot;&gt;Git Store&lt;/a&gt;: Git의 현재 작업 디렉토리를 저장.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zsh-users/zsh-history-substring-search&quot;&gt;Zsh History Substring Search&lt;/a&gt;: &lt;a href=&quot;https://fishshell.com/&quot; rel=&quot;nofollow&quot;&gt;Fish&lt;/a&gt;같은 history 검색기능.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/changyuheng/zsh-interactive-cd&quot;&gt;Zsh Interactive Cd&lt;/a&gt;:&amp;nbsp; &amp;lt;TAB&amp;gt;을 누르면 fzf와 함께 자동완성을 도외줌.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/peterhurford/up.zsh&quot;&gt;up&lt;/a&gt;: &amp;lt;dots&amp;gt; 갯수대로 상위 디렉토리로 이동.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;3.3 내 터미널 환경.&lt;/h2&gt;
&lt;p&gt;혹시 궁금해하는 사람이 있을까봐 적는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;OS&lt;/b&gt;: Kubuntu 18.10&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;Terminal&lt;/b&gt;: Konsole&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;Font&lt;/b&gt;: Hack Nerd Font&lt;/li&gt;
&lt;li class=&quot;&quot;&gt;&lt;b&gt;Color Scheme&lt;/b&gt;: Breeze&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>컴퓨터/리눅스</category>
      <category>fzf</category>
      <category>linux</category>
      <category>shell</category>
      <category>zsh</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/59</guid>
      <comments>https://black7375.tistory.com/59#entry59comment</comments>
      <pubDate>Thu, 28 Feb 2019 02:36:26 +0900</pubDate>
    </item>
    <item>
      <title>윾씨 총정리. - 부제) 윾튜브 님 죄송합니다.</title>
      <link>https://black7375.tistory.com/58</link>
      <description>&lt;p class=&quot;&quot;&gt;원래 &lt;a href=&quot;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=63420&amp;amp;exception_mode=recommend&amp;amp;page=1&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;디시에만 적었던 글&lt;/a&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_1&quot; id=&quot;footnote_link_58_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 1)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;인데, 해외에서 디시 못본다는 말이 있어서 그 요청에 블로그에 옮겨본다.&lt;/p&gt;
&lt;p&gt;기술관련만 적는 블로그였는데 ㅠㅠㅠ&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;논란이 되고 있는 그 유튜버 윾씨를 알아보자.&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_2&quot; id=&quot;footnote_link_58_2&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 2)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 2)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;2&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;지금 보고 계시는 이 글 부제목&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;'윾튜브 님 죄송합니다'&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p class=&quot;&quot;&gt;원래 제가 쓰려던 제목은 이게 아니었어요.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;훨씬 더 길었는데 너무 길면은 제목이 제대로 안보이니까 뒷부분을 잘랐습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;원래 제목은 글 끝날 때 말씀 드릴게요.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 330px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DBE34E5C4763D508&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DBE34E5C4763D508&quot; width=&quot;330&quot; height=&quot;313&quot; filename=&quot;프로필.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;한 줄 정리.&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;윾튜브는 소아성애+대구지하철, 세월호와 천안함등의 고인, 성폭력 피해자들을 모욕한 진성 일베.. 악마를 보았다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;border&quot;&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;배경지식&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;다음은 모두 동일인물입니다.&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;윾튜브(유튜브)&lt;/li&gt;&lt;li class=&quot;&quot;&gt; jungsachun(유튜브)&lt;br /&gt;네이트 아이디인 wjdtkcns은 정사춘[jungsachun]을 쿼티 자반으로 적어 놓은 것.&lt;/li&gt;&lt;li&gt;김윾머(페이스북)&lt;/li&gt;&lt;li&gt;유머저장소(페이스북)&lt;/li&gt;&lt;li&gt;풍동(디시, 던파)&lt;/li&gt;&lt;li class=&quot;&quot;&gt;로이더(일베)&lt;br /&gt;&lt;a href=&quot;https://namu.wiki/thread/X6yHP7x2zKTPmHEv4BqhpJ&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;나무위키 토론&lt;/a&gt;을 보니 일베의 댓글이 일부 박제되어있더군요.&lt;br /&gt;옛날부터 일베쪽 유저들은 풍동이 윾튜브인지 알았던것 같습니다.&lt;br /&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994FAD465C508F0401&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994FAD465C508F0401&quot; width=&quot;800&quot; height=&quot;757&quot; filename=&quot;Screenshot_2019-01-30 유머저장소 (토론) - 유머저장소 = 일베 뭔 소리입니까 이게 - 나무위키.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;dcpungdong(네이버)&lt;/li&gt;&lt;li class=&quot;&quot;&gt;wjdtkcns(네이트)&lt;br /&gt;&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot; title=&quot;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C9AE455C47927716&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C9AE455C47927716&quot; width=&quot;800&quot; height=&quot;381&quot; filename=&quot;Screenshot_2019-01-23 정봉주, 수감되면서도 'BBK' '병적 집착' .png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href=&quot;https://news.nate.com/view/20111227n13763&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;정봉주, 수감되면서도 'BBK'..'병적 집착'?&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ZMrbUlvk2ig&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;스스로 인정&lt;/a&gt;했습니다.&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_3&quot; id=&quot;footnote_link_58_3&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 3)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 3)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;3&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;iframe width=&quot;640&quot; height=&quot;360&quot; src=&quot;//play-tv.kakao.com/embed/player/cliplink/v8aecAQAgDXDFrs5igLAgJ5@my?service=daum_tistory&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;
&lt;p class=&quot;&quot;&gt;저는 &lt;strike&gt;&lt;span class=&quot;&quot;&gt;조회수 늘려주기 싫으니 안보는 걸로 하구&lt;/span&gt;&lt;/strike&gt;,&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_4&quot; id=&quot;footnote_link_58_4&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 4)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 4)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;4&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt; 본론으로 들어갑시다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1. 성적 발언.&lt;/h2&gt;&lt;p&gt;우선 알아두어야 할 것.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990B9A335C4873D11A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990B9A335C4873D11A&quot; width=&quot;800&quot; height=&quot;1295&quot; filename=&quot;성희롱.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;맞는 말을 하기도 했다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그러나....&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.1 성적 취향.&lt;/h3&gt;&lt;div&gt;이것만 봐도 보통 사람은 아니라는 걸 알 수 있음.&lt;/div&gt;&lt;div&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995714435C47644308&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995714435C47644308&quot; width=&quot;800&quot; height=&quot;358&quot; filename=&quot;여친.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9966314D5C47644908&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9966314D5C47644908&quot; width=&quot;800&quot; height=&quot;787&quot; filename=&quot;대.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99575A435C47645208&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99575A435C47645208&quot; width=&quot;400&quot; height=&quot;273&quot; filename=&quot;딸.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99113B4E5C4874C225&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99113B4E5C4874C225&quot; width=&quot;400&quot; height=&quot;230&quot; filename=&quot;던.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 704px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A6424C5C4875F52B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A6424C5C4875F52B&quot; width=&quot;704&quot; height=&quot;692&quot; filename=&quot;유토피아.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;뭐;;; 가학적이고 이상한 것 같긴 하지만 범죄까지는 아니니 넘어가자.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.2 성희롱&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;그런데 연예인 및 아동 성희롱 발언..&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9956C24A5C47648409&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9956C24A5C47648409&quot; width=&quot;400&quot; height=&quot;511&quot; filename=&quot;연예인.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FB6C415C47649009&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FB6C415C47649009&quot; width=&quot;400&quot; height=&quot;691&quot; filename=&quot;추.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 480px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D76B4E5C4B411817&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D76B4E5C4B411817&quot; width=&quot;480&quot; height=&quot;853&quot; filename=&quot;딸2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;참고로 알리는 &lt;b&gt;&lt;a href=&quot;http://news.mk.co.kr/newsRead.php?year=2011&amp;amp;no=812309&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;성폭행 피해자&lt;/a&gt;&lt;/b&gt;임.&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9957124A5C4764BD09&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9957124A5C4764BD09&quot; width=&quot;400&quot; height=&quot;524&quot; filename=&quot;알1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99132F495C4764BD08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99132F495C4764BD08&quot; width=&quot;400&quot; height=&quot;597&quot; filename=&quot;알2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;백지영도 비슷한 상황.&lt;/div&gt;&lt;div&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A4714A5C4B41F313&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A4714A5C4B41F313&quot; width=&quot;800&quot; height=&quot;1644&quot; filename=&quot;백.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;+. &lt;br /&gt;&lt;/h4&gt;&lt;p class=&quot;&quot;&gt;김연아 소치 올림픽가지고 패드립.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 338px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C6504F5C4764EF08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C6504F5C4764EF08&quot; width=&quot;338&quot; height=&quot;531&quot; filename=&quot;김연아소치.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;도끼 어머니께 패드립.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D21C4E5C478C9816&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D21C4E5C478C9816&quot; width=&quot;800&quot; height=&quot;560&quot; filename=&quot;도끼.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.3 소아 성애 및 폭력적 성향. &lt;br /&gt;&lt;/h3&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99AB6D3E5C47651B07&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99AB6D3E5C47651B07&quot; width=&quot;800&quot; height=&quot;684&quot; filename=&quot;소아.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; class=&quot;&quot;&gt;BL+소아성애..&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; class=&quot;&quot;&gt;이것도 BL은 그렇다 치자. 동성애자들도 존중 받을 필요가 있고, 그런 사회가 되어야 한다고 생각하기에.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FCE4425C47652B09&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FCE4425C47652B09&quot; width=&quot;800&quot; height=&quot;925&quot; filename=&quot;BL.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9953CF435C47652B09&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9953CF435C47652B09&quot; width=&quot;800&quot; height=&quot;275&quot; filename=&quot;BL2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99230D385C47652B09&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99230D385C47652B09&quot; width=&quot;800&quot; height=&quot;533&quot; filename=&quot;BL3.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;수위가 좀 쎄서 올릴까 말까 고민을 많이 한 사진입니다.&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E7D4375C4DC1C72A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E7D4375C4DC1C72A&quot; width=&quot;400&quot; height=&quot;416&quot; filename=&quot;소아2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99AA91405C50C66B14&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99AA91405C50C66B14&quot; width=&quot;400&quot; height=&quot;280&quot; filename=&quot;강간범.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999C50385C4885BE15&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999C50385C4885BE15&quot; width=&quot;400&quot; height=&quot;808&quot; filename=&quot;폭력.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DA21475C4885C32B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DA21475C4885C32B&quot; width=&quot;400&quot; height=&quot;931&quot; filename=&quot;중딩.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;p&gt;...공연성과 특정성이 만족하는 상황에서 욕은 못하니&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F85C415C4DC40D23&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F85C415C4DC40D23&quot; width=&quot;500&quot; height=&quot;192&quot; filename=&quot;그룻.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;2. 각종 사고시 발언.&lt;/h2&gt;&lt;p&gt;위에 있는 것들도 문제지만, 일베충이라는 것을 여과없이 보여준다.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.1 대구 지하철&lt;br /&gt;&lt;/h3&gt;&lt;/div&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999954365C4765E308&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999954365C4765E308&quot; width=&quot;400&quot; height=&quot;530&quot; filename=&quot;대1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991397355C4765E308&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991397355C4765E308&quot; width=&quot;400&quot; height=&quot;278&quot; filename=&quot;대2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C2BB455C4765E309&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C2BB455C4765E309&quot; width=&quot;800&quot; height=&quot;1010&quot; filename=&quot;대구4.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997120335C4765F008&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997120335C4765F008&quot; width=&quot;800&quot; height=&quot;881&quot; filename=&quot;대3.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;마지막 짤의 이해를 돕자면,&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;타요버스라는 애니메이션을 이용한 &lt;a href=&quot;https://namu.wiki/w/%EC%8B%A4%EC%82%AC%ED%8C%90%20%ED%83%80%EC%9A%94%20%EB%B2%84%EC%8A%A4&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;서울의 버스&lt;/a&gt;가 성공하자 요리사에 방화범의 얼굴을 합성시킨 후 대구 타요전철(화재)을 만든 건 명확하다는 발언이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.2 세월호&lt;/h3&gt;&lt;p&gt;우선 윾씨가 말한 내용부터 보자.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F03B3F5C47662608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F03B3F5C47662608&quot; width=&quot;800&quot; height=&quot;218&quot; filename=&quot;세8.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 750px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990BC83B5C47662B08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990BC83B5C47662B08&quot; width=&quot;750&quot; height=&quot;1334&quot; filename=&quot;세7.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996B4B4D5C47662F08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996B4B4D5C47662F08&quot; width=&quot;800&quot; height=&quot;2389&quot; filename=&quot;Screenshot_2019-01-23 [개추요청] 그 하회탈 세월호 당일 소름돋는 이중성 - 유튜브 갤러리 .jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;매우 정상적인&lt;/b&gt; 사람이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그런데!!!!!!!&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 748px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99EBC53A5C47665709&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99EBC53A5C47665709&quot; width=&quot;748&quot; height=&quot;348&quot; filename=&quot;등등2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot; class=&quot;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 752px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9954AB435C47665709&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9954AB435C47665709&quot; width=&quot;752&quot; height=&quot;536&quot; filename=&quot;등등.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;당일과 다음날 쓴 글의 제목만 봐도 장난이 아니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;당연히 내용을 보면 더 가관.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99060A425C4766DB09&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99060A425C4766DB09&quot; width=&quot;800&quot; height=&quot;502&quot; filename=&quot;세1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot; title=&quot;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 787px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99CE0D4F5C4766DB08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99CE0D4F5C4766DB08&quot; width=&quot;787&quot; height=&quot;447&quot; filename=&quot;세2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;아이들이 물(水)에 빠져 죽은 것을 조롱하는 내용.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot; title=&quot;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 785px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DB114E5C4766DC09&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DB114E5C4766DC09&quot; width=&quot;785&quot; height=&quot;962&quot; filename=&quot;세3.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993017385C4766DB08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993017385C4766DB08&quot; width=&quot;800&quot; height=&quot;379&quot; filename=&quot;세4.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99306D385C4766DB08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99306D385C4766DB08&quot; width=&quot;400&quot; height=&quot;371&quot; filename=&quot;세5.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997D41375C4766DC08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997D41375C4766DC08&quot; width=&quot;400&quot; height=&quot;475&quot; filename=&quot;세6.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99CF8F4D5C4A3F311B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99CF8F4D5C4A3F311B&quot; width=&quot;400&quot; height=&quot;348&quot; filename=&quot;세10.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99520A475C4A3F311B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99520A475C4A3F311B&quot; width=&quot;400&quot; height=&quot;299&quot; filename=&quot;세11.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그리고.. 그의 온갖 편견과 잔인함이 단번에 드러나는 짤.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;백청강이 조선족 출신인데 2012년에 벌어진 오원춘(조선족)의 &lt;a href=&quot;https://namu.wiki/w/수원 토막 살인 사건&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;수원 토막 살인 사건&lt;/a&gt;에서 인육의혹을 묶음.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;+&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;인육으로 물만두(물에 빠져 죽어간 것)되었다 조롱하는 것.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;=&amp;gt;요약. 인육 물만두.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994BEE365C4A19E60C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994BEE365C4A19E60C&quot; width=&quot;800&quot; height=&quot;1264&quot; filename=&quot;세9.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이건 설명을 보고나서야 알았는데 정말 정상적인 사고방식은 아닌것 같다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.3 천안함.&lt;/h3&gt;&lt;div class=&quot;&quot;&gt;자칭 '보수' 유튜버라는 사람이 말하는 내용입니다.&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99203F3D5C47671B15&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99203F3D5C47671B15&quot; width=&quot;800&quot; height=&quot;277&quot; filename=&quot;천.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.4 연평도 포격.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;항상 흐름은 같다.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 650px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DB99425C487D8A14&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DB99425C487D8A14&quot; width=&quot;650&quot; height=&quot;1693&quot; filename=&quot;연평1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;겉으론 정상적인 척을 하지만, 뒤로는&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9992B94F5C487DB32A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9992B94F5C487DB32A&quot; width=&quot;800&quot; height=&quot;521&quot; filename=&quot;연평2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.5 한동대.&lt;/h3&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px; outline: red dashed 1px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996A79465C48CE1B10&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996A79465C48CE1B10&quot; width=&quot;400&quot; height=&quot;711&quot; filename=&quot;한동1.jpg&quot; filemime=&quot;image/jpeg&quot; style=&quot;outline: red dashed 1px;&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99353B435C48CE1B10&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99353B435C48CE1B10&quot; width=&quot;400&quot; height=&quot;648&quot; filename=&quot;한동2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 class=&quot;&quot;&gt;2.6 5.18 &amp;amp;&amp;amp; 노무현 &amp;amp;&amp;amp; 지역비하 발언.&lt;/h3&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99395D4C5C47677B0A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99395D4C5C47677B0A&quot; width=&quot;800&quot; height=&quot;59&quot; filename=&quot;518.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 312px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A2C9505C47678109&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A2C9505C47678109&quot; width=&quot;312&quot; height=&quot;253&quot; filename=&quot;노무현.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; class=&quot;&quot;&gt;네이트 댓글에&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; class=&quot;&quot;&gt;&lt;a href=&quot;https://comm.news.nate.com/comment/userComment/list?user_cmn=1da9776358d8a107288dc735b40130b1&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://comm.news.nate.com/comment/userComment/list?user_cmn=1da9776358d8a107288dc735b40130b1&lt;/a&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; class=&quot;&quot;&gt;즉시 계엄령을 선포하고 폭도들을 살육해야 한다&lt;br /&gt;전문시위꾼 2000명 사형시키고 나머지 죄질이 흉악하거나&lt;br /&gt;시위꾼 중 주소가 전라도로 되어있는 자 모두 무기징역 때려야함&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;라고 했다고 함.&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td title=&quot;&quot; style=&quot;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99CEA24D5C4A3D551A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99CEA24D5C4A3D551A&quot; width=&quot;400&quot; height=&quot;618&quot; filename=&quot;전1.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996E9F3B5C4A3D551A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996E9F3B5C4A3D551A&quot; width=&quot;400&quot; height=&quot;626&quot; filename=&quot;전2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FF1D485C47850712&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FF1D485C47850712&quot; width=&quot;400&quot; height=&quot;711&quot; filename=&quot;네이트.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99808B345C4B560E06&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99808B345C4B560E06&quot; width=&quot;400&quot; height=&quot;371&quot; filename=&quot;전3.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;2.7 부산외대 리조트 사고&lt;/h3&gt;&lt;p&gt;경주 마우나오션리조트 체육관 붕괴 사고는 2014년 2월 17일 대한민국 경상북도 경주시 마우나오션리조트에서 발생한 사고이다. 이 사고로 체육관에서 신입생 환영회 행사를 진행중이던 부산외국어대학교 학생 9명과 이벤트업체 직원 1명 총 10명이 사망하였다.&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FD11485C4767BA0A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FD11485C4767BA0A&quot; width=&quot;400&quot; height=&quot;371&quot; filename=&quot;부1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992AFD385C4767BB09&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992AFD385C4767BB09&quot; width=&quot;400&quot; height=&quot;685&quot; filename=&quot;부2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.7 성재기.&lt;/h3&gt;&lt;p&gt;'안티 페미'로 활동하시는 분께서 쓴 글.&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997C08345C48C79B0E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997C08345C48C79B0E&quot; width=&quot;400&quot; height=&quot;998&quot; filename=&quot;재기1.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99479E395C48C79B0C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99479E395C48C79B0C&quot; width=&quot;400&quot; height=&quot;295&quot; filename=&quot;재기2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.8 미선 효순 장갑차 사고&lt;/h3&gt;&lt;p&gt;미군 장갑차에 의한 중학생 압사 사건(美軍裝甲車-依-中學生壓死事件)은 2002년 6월 13일 당시 조양중학교 2학년이던 신효순, 심미선이 경기도 양주군 광적면 효촌리 소재 국가지원지방도 제56호선에서 갓길을 걷다 주한 미군 미 보병 2사단 대대 전투력 훈련을 위해 이동 중이던 부교 운반용 장갑차에 깔려 현장에서 숨진 사건이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 397px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99EC5D3F5C4767E409&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99EC5D3F5C4767E409&quot; width=&quot;397&quot; height=&quot;605&quot; filename=&quot;미선효순장갑차.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.9 부산 편의점 분신.&lt;br /&gt;&lt;/h3&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995220385C4A3C6D1B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995220385C4A3C6D1B&quot; width=&quot;800&quot; height=&quot;450&quot; filename=&quot;편1.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998CEB395C4A3C6D1A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998CEB395C4A3C6D1A&quot; width=&quot;400&quot; height=&quot;351&quot; filename=&quot;편3.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992BFF335C4A3C9017&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992BFF335C4A3C9017&quot; width=&quot;400&quot; height=&quot;548&quot; filename=&quot;편4.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 372px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994DD7475C4A3C6D1A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994DD7475C4A3C6D1A&quot; width=&quot;372&quot; height=&quot;139&quot; filename=&quot;편2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;3. 기타.&lt;/h2&gt;&lt;h3&gt;3.1 게임&lt;br /&gt;&lt;/h3&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 480px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998060375C477C8F0D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998060375C477C8F0D&quot; width=&quot;480&quot; height=&quot;360&quot; filename=&quot;던.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;던전앤파이터라는 게임에서 '풍동교주'라는닉네임으로&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;누구 허락 받고 장사함&lt;/p&gt;
&lt;p&gt;제 허락 받았음&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;저한테 보호비 낸적 있음?&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;조폭들이 하는 것처럼 선량한 유저들에게 강도짓.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 class=&quot;&quot;&gt;3.2 조롱하는 컨텐츠.&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;김대중 전대통령 조롱 및 전두환 찬양을 일삼고 있는 유튜브.(댓글제보)&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/29cEh2ve-x8?rel=0&quot; width=&quot;560&quot; height=&quot;420&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;정봉주의원 역시 조롱하는 컨텐츠도 만들었죠.(역시 댓글제보)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992F7B4C5C47B61E32&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992F7B4C5C47B61E32&quot; width=&quot;800&quot; height=&quot;597&quot; filename=&quot;노래2.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;아 물론 아 물론 영상 두개다 백업되어 있습니다.&lt;/p&gt;
&lt;p&gt;관련인들께서 자료제공 요청하시면 드리겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;3.3 또 다른 조롱글.&lt;/h3&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td title=&quot;&quot; style=&quot;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9977CE455C49033C2A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9977CE455C49033C2A&quot; width=&quot;400&quot; height=&quot;711&quot; filename=&quot;헬1.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997F3D345C49033C2A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997F3D345C49033C2A&quot; width=&quot;400&quot; height=&quot;712&quot; filename=&quot;헬2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px; outline: red dashed 1px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9987FE375C486CCF0A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9987FE375C486CCF0A&quot; width=&quot;400&quot; height=&quot;822&quot; filename=&quot;일1.jpg&quot; filemime=&quot;image/jpeg&quot; style=&quot;outline: red dashed 1px;&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F52A365C486CCF45&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F52A365C486CCF45&quot; width=&quot;400&quot; height=&quot;822&quot; filename=&quot;일2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E7FA3B5C4B592F07&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E7FA3B5C4B592F07&quot; width=&quot;400&quot; height=&quot;442&quot; filename=&quot;일베.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px; outline: red dashed 1px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9998A6365C4B592F07&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9998A6365C4B592F07&quot; width=&quot;400&quot; height=&quot;300&quot; filename=&quot;패드립1.jpg&quot; filemime=&quot;image/jpeg&quot; style=&quot;outline: red dashed 1px;&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9984CF365C5079AE07&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9984CF365C5079AE07&quot; width=&quot;400&quot; height=&quot;665&quot; filename=&quot;패드립2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9947A63A5C50C5ED14&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9947A63A5C50C5ED14&quot; width=&quot;400&quot; height=&quot;591&quot; filename=&quot;상담.jpeg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9940513A5C48F5061B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9940513A5C48F5061B&quot; width=&quot;400&quot; height=&quot;628&quot; filename=&quot;애니.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9909E3505C48F5061B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9909E3505C48F5061B&quot; width=&quot;400&quot; height=&quot;561&quot; filename=&quot;애니2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;위에서 미스터초밥왕이라는 동인지 보던데..&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;태극기 집회를 좋게 보지는 않지만 부상당한 뉴스에&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 480px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F6533B5C49EE022C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F6533B5C49EE022C&quot; width=&quot;480&quot; height=&quot;634&quot; filename=&quot;태극기.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;엠티에서 강.제.로 초코파이 빨리먹기 하다가 죽은 일반인에게&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F22A455C49EE2E09&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F22A455C49EE2E09&quot; width=&quot;800&quot; height=&quot;351&quot; filename=&quot;몽쉘.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E29B445C4A3DB01D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E29B445C4A3DB01D&quot; width=&quot;800&quot; height=&quot;1128&quot; filename=&quot;삼.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;이하 자료는 양이 너무 길어 더보기 처리합니다.&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;btn_more&quot; id=&quot;more58_0&quot; data-id=&quot;58_0&quot;&gt;더보기&lt;/button&gt;&lt;div class=&quot;moreless_content&quot; id=&quot;content58_0&quot; style=&quot;display: none;&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;btn_less&quot; id=&quot;less58_0&quot; data-id=&quot;58_0&quot;&gt;&lt;span class=&quot;txt_fold&quot;&gt;접기&lt;/span&gt;&lt;/button&gt;
  &lt;p class=&quot;txt_view&quot;&gt;&lt;h4&gt;1) 일반인 허위사실 유포 및 조롱.&lt;br /&gt;&lt;/h4&gt;&lt;div class=&quot;&quot;&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D61B465C4B5BF707&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D61B465C4B5BF707&quot; width=&quot;800&quot; height=&quot;2092&quot; filename=&quot;누나3.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D207495C4B5BF607&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D207495C4B5BF607&quot; width=&quot;400&quot; height=&quot;231&quot; filename=&quot;누나4.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997C67345C4B5BF609&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997C67345C4B5BF609&quot; width=&quot;400&quot; height=&quot;541&quot; filename=&quot;누나5.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99486B505C4B5BF608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99486B505C4B5BF608&quot; width=&quot;400&quot; height=&quot;587&quot; filename=&quot;누나6.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DB79485C4B5BF608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DB79485C4B5BF608&quot; width=&quot;400&quot; height=&quot;780&quot; filename=&quot;누나7.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994419405C4B5BF609&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994419405C4B5BF609&quot; width=&quot;400&quot; height=&quot;582&quot; filename=&quot;누나8.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99CAC3425C4B5BF608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99CAC3425C4B5BF608&quot; width=&quot;400&quot; height=&quot;581&quot; filename=&quot;누나9.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99220D4B5C4B5BF608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99220D4B5C4B5BF608&quot; width=&quot;400&quot; height=&quot;440&quot; filename=&quot;누나10.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995CBC4F5C4B5BF609&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995CBC4F5C4B5BF609&quot; width=&quot;400&quot; height=&quot;369&quot; filename=&quot;누나11.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 770px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994867505C4B5BF608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994867505C4B5BF608&quot; width=&quot;770&quot; height=&quot;960&quot; filename=&quot;누나12.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DB8D485C4B5BF608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DB8D485C4B5BF608&quot; width=&quot;800&quot; height=&quot;161&quot; filename=&quot;누나13.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995E55475C4B5BF608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995E55475C4B5BF608&quot; width=&quot;400&quot; height=&quot;711&quot; filename=&quot;누나14.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BC5D385C4B5BF708&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BC5D385C4B5BF708&quot; width=&quot;400&quot; height=&quot;711&quot; filename=&quot;누나15.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 540px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995E59475C4B5BF708&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995E59475C4B5BF708&quot; width=&quot;540&quot; height=&quot;960&quot; filename=&quot;누나16.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9994C63F5C4B5BF709&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9994C63F5C4B5BF709&quot; width=&quot;800&quot; height=&quot;386&quot; filename=&quot;누나17.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;h4&gt;2) 일베라는 것이 탄로나자 반대로 몰고가기.&lt;/h4&gt;&lt;div class=&quot;&quot;&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99ABB3445C4B492801&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99ABB3445C4B492801&quot; width=&quot;400&quot; height=&quot;485&quot; filename=&quot;몰기1.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999C5B415C4B492801&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999C5B415C4B492801&quot; width=&quot;400&quot; height=&quot;406&quot; filename=&quot;몰기2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9965EB4F5C4B492801&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9965EB4F5C4B492801&quot; width=&quot;400&quot; height=&quot;400&quot; filename=&quot;몰기3.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BE9C355C4B492801&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BE9C355C4B492801&quot; width=&quot;400&quot; height=&quot;516&quot; filename=&quot;몰기4.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993B08455C4B492801&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993B08455C4B492801&quot; width=&quot;400&quot; height=&quot;400&quot; filename=&quot;몰기5.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993D374E5C4B492802&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993D374E5C4B492802&quot; width=&quot;400&quot; height=&quot;468&quot; filename=&quot;몰기6.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9977CD345C4B492801&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9977CD345C4B492801&quot; width=&quot;400&quot; height=&quot;400&quot; filename=&quot;몰기7.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9945F5405C4B492801&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9945F5405C4B492801&quot; width=&quot;400&quot; height=&quot;400&quot; filename=&quot;몰기8.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 600px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DCB1435C4B492801&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DCB1435C4B492801&quot; width=&quot;600&quot; height=&quot;600&quot; filename=&quot;몰기9.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;h4&gt;3) 시위 조롱.&lt;/h4&gt;&lt;div class=&quot;&quot;&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9929364B5C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9929364B5C4B4C2D02&quot; width=&quot;800&quot; height=&quot;11630&quot; filename=&quot;광1.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999C25415C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999C25415C4B4C2D02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A89D335C4B4C2D03&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A89D335C4B4C2D03&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광3.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DF49435C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DF49435C4B4C2D02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광4.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E86E3B5C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E86E3B5C4B4C2D02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광5.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B019385C4B4C2D03&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B019385C4B4C2D03&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광6.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9942194E5C4B4C2D03&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9942194E5C4B4C2D03&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광7.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B025385C4B4C2D03&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B025385C4B4C2D03&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광8.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998B634D5C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998B634D5C4B4C2D02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광9.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E8B03B5C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E8B03B5C4B4C2D02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광10.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F5C5395C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F5C5395C4B4C2D02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광11.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F7B04C5C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F7B04C5C4B4C2D02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광12.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999B0F4A5C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999B0F4A5C4B4C2D02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광13.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9941C54E5C4B4C2D03&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9941C54E5C4B4C2D03&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광14.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999A4B365C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999A4B365C4B4C2D02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광15.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997EA3375C4B4C2D02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997EA3375C4B4C2D02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광16.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9946C0405C4B4C2E02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9946C0405C4B4C2E02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광17.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F5C9395C4B4C2E02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F5C9395C4B4C2E02&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광18.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9997B73F5C4B4C2E03&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9997B73F5C4B4C2E03&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;광19.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999AD9365C4B4C2E02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999AD9365C4B4C2E02&quot; width=&quot;800&quot; height=&quot;450&quot; filename=&quot;광20.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;동행자라는 사람의 정체는 윤서인.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D582495C4B4D3202&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D582495C4B4D3202&quot; width=&quot;800&quot; height=&quot;1422&quot; filename=&quot;광21.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;h4&gt;4) 엑소(EXO) 카이&lt;/h4&gt;&lt;div class=&quot;&quot;&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 580px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E8E33A5C4B574D07&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E8E33A5C4B574D07&quot; width=&quot;580&quot; height=&quot;463&quot; filename=&quot;엑1.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 580px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E9133B5C4B574D06&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E9133B5C4B574D06&quot; width=&quot;580&quot; height=&quot;1006&quot; filename=&quot;엑2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F310395C4B574D07&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F310395C4B574D07&quot; width=&quot;400&quot; height=&quot;182&quot; filename=&quot;엑3.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9997CD415C4B574D07&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9997CD415C4B574D07&quot; width=&quot;400&quot; height=&quot;533&quot; filename=&quot;엑4.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;button type=&quot;button&quot; class=&quot;btn_less&quot; id=&quot;less58_0&quot; data-id=&quot;58_0&quot;&gt;&lt;span class=&quot;txt_fold&quot;&gt;접기&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;으휴 &lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;photos&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F85C415C4DC40D23&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F85C415C4DC40D23&quot; width=&quot;500&quot; height=&quot;192&quot; filename=&quot;그룻.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F85C415C4DC40D23&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F85C415C4DC40D23&quot; width=&quot;500&quot; height=&quot;192&quot; filename=&quot;그룻.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F85C415C4DC40D23&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F85C415C4DC40D23&quot; width=&quot;500&quot; height=&quot;192&quot; filename=&quot;그룻.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F85C415C4DC40D23&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F85C415C4DC40D23&quot; width=&quot;500&quot; height=&quot;192&quot; filename=&quot;그룻.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F85C415C4DC40D23&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F85C415C4DC40D23&quot; width=&quot;500&quot; height=&quot;192&quot; filename=&quot;그룻.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F85C415C4DC40D23&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F85C415C4DC40D23&quot; width=&quot;500&quot; height=&quot;192&quot; filename=&quot;그룻.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h2&gt;4. 반응. &lt;br /&gt;&lt;/h2&gt;&lt;p&gt;그분의 반응을 봅시다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;위와 같은 발언을 서슴치 않게 하는 사람이 마음의 빚???&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9939554B5C47681B0E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9939554B5C47681B0E&quot; width=&quot;800&quot; height=&quot;775&quot; filename=&quot;자아.jpg&quot; filemime=&quot;image/jpeg&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;과거의 자신과 아무 상관 없는냥 3인칭 유체이탈 화법으로 말하기. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B9E7465C47685E09&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B9E7465C47685E09&quot; width=&quot;800&quot; height=&quot;1423&quot; filename=&quot;3인칭.png&quot; filemime=&quot;image/png&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;기억 안나는척&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9995F7365C47683A09&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9995F7365C47683A09&quot; width=&quot;800&quot; height=&quot;478&quot; filename=&quot;자아2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: left;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: left;&quot;&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;640&quot; height=&quot;360&quot; src=&quot;//play-tv.kakao.com/embed/player/cliplink/v1588RMdoE0MRo30JAVdduu@my?service=daum_tistory&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;또 기억이 안나?????&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;누군가에게 피눈물을 흘리게 하는 것이 &lt;b&gt;평소 생각, 평소 생활, 평소 일상&lt;/b&gt;이었으니까 알 수가 없지.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;지금은 사람들이 화를 내니 물러나는 척을 하는 거고.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991E36355C486F6B35&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991E36355C486F6B35&quot; width=&quot;800&quot; height=&quot;447&quot; filename=&quot;Screenshot_2019-01-23 계정 해지 - YouTube 고객센터.png&quot; filemime=&quot;image/png&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;계정 해지가 되면 다른 YouTube 채널을 &lt;b&gt;&lt;span style=&quot;background-color: rgb(255, 228, 0);&quot; class=&quot;&quot;&gt;이용하거나 소유하거나 새로 만들지 못할 수&lt;/span&gt;&lt;/b&gt; 있습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/R79MDmP6nPw?rel=0&quot; width=&quot;560&quot; height=&quot;420&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;&lt;/p&gt;&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999E97405C51E85D04&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999E97405C51E85D04&quot; width=&quot;800&quot; height=&quot;781&quot; filename=&quot;복귀.png&quot; filemime=&quot;image/png&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;1월 30일 부로 몇일 못참고 복귀영상을 찍었다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;유튜브 부계정인&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCL_ZTbD-Qd47Sv1VD9gYHlw&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;윾튜브 순한맛&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/user/jungsachun&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;jungsachun&lt;/a&gt; &lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;신고합시다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;strike class=&quot;&quot;&gt;&lt;a href=&quot;https://www.youtube.com/channel/UC8xvpncEPMuQ1-PlUYlBO1Q&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;윾튜브 매운맛&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/channel/UCywcMTOsytzmY41TTpVFw2g&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;윾튜브 최강매운맛&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/channel/UCgOMXtw8GWXQB-ipofdIHPg&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;윾튜브 약간매운맛&lt;/a&gt;&lt;/strike&gt;&lt;span class=&quot;&quot;&gt;은 가짜라고 한다&lt;/span&gt;&lt;strike class=&quot;&quot;&gt;. &lt;br /&gt;&lt;/strike&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그래도 친구는 잘 뒀는지&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_5&quot; id=&quot;footnote_link_58_5&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 5)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 5)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;5&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt; 해명 라이브 방송에서 후원도 해주는 사람도 있고&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_6&quot; id=&quot;footnote_link_58_6&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 6)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 6)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;6&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;&quot;&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997D4C405C47689D0A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997D4C405C47689D0A&quot; width=&quot;800&quot; height=&quot;269&quot; filename=&quot;손절.png&quot; filemime=&quot;image/png&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;button type=&quot;button&quot; class=&quot;btn_more&quot; id=&quot;more58_1&quot; data-id=&quot;58_1&quot;&gt;쉴드 더보기&lt;/button&gt;&lt;div class=&quot;moreless_content&quot; id=&quot;content58_1&quot; style=&quot;display: none;&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;btn_less&quot; id=&quot;less58_1&quot; data-id=&quot;58_1&quot;&gt;&lt;span class=&quot;txt_fold&quot;&gt;접기&lt;/span&gt;&lt;/button&gt;
  &lt;p class=&quot;txt_view&quot;&gt;&lt;p&gt;사건 터지고 친구 중 제일 먼저 라이브 방송 킨 윤서인 방송에서도 후원에&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996B58345C4DCE8A32&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996B58345C4DCE8A32&quot; width=&quot;800&quot; height=&quot;1422&quot; filename=&quot;민호1.jpeg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;초밥 먹으러 가자고 친목 후 통한의 쉴드 ㅋㅋㅋ&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9952303D5C4DCF0A24&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9952303D5C4DCF0A24&quot; width=&quot;800&quot; height=&quot;14780&quot; filename=&quot;민호2.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이 정도는 쉽게 쉽게 의도를 읽을 수 있겠죠?&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;요약.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;윾튜브 손절 안함.(잘해줬걸랑)&lt;/li&gt;&lt;li&gt;윾튜브 반성 중임.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;나 싫으면 보지마라.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;button type=&quot;button&quot; class=&quot;btn_less&quot; id=&quot;less58_1&quot; data-id=&quot;58_1&quot;&gt;&lt;span class=&quot;txt_fold&quot;&gt;접기&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;인스타 DM 주고받고 '&lt;a href=&quot;https://masayu.me/29&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;집까지 빌려줬지만&lt;/a&gt;' 잘모르는 사이며, '틀렸지만' 인간관계로 인정해주는 사람도 있어서 좋겠더라.&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_7&quot; id=&quot;footnote_link_58_7&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 7)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 7)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;7&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_8&quot; id=&quot;footnote_link_58_8&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 8)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 8)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;8&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/BrBdWHNrvZs?rel=0&quot; width=&quot;560&quot; height=&quot;420&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;이해가 잘 안되는 분들은 &lt;a href=&quot;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=84146&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;해석본&lt;/a&gt;(역시 터짐. &lt;a href=&quot;https://www.evernote.com/l/AUXUQA8-XORFWYnBluw7kmwvOooq7p5MgYw/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;아카이브&lt;/a&gt;)&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_9&quot; id=&quot;footnote_link_58_9&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 9)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 9)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;9&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt; 보세요.&lt;br /&gt;&lt;/p&gt;&lt;button type=&quot;button&quot; class=&quot;btn_more&quot; id=&quot;more58_2&quot; data-id=&quot;58_2&quot;&gt;쉴드 더보기&lt;/button&gt;&lt;div class=&quot;moreless_content&quot; id=&quot;content58_2&quot; style=&quot;display: none;&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;btn_less&quot; id=&quot;less58_2&quot; data-id=&quot;58_2&quot;&gt;&lt;span class=&quot;txt_fold&quot;&gt;접기&lt;/span&gt;&lt;/button&gt;
  &lt;p class=&quot;txt_view&quot;&gt;&lt;p class=&quot;&quot;&gt;잘 모르는 사이라고 하지만 알만한 기회가 너무 많았다.&lt;/p&gt;&lt;h4 class=&quot;&quot;&gt;0) 깊어보이는 윾튜브와의 친목.&lt;/h4&gt;&lt;p class=&quot;&quot;&gt;자세한 사항은 &lt;a href=&quot;https://masayu.me/29&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;인기 유튜버 JM과 윾튜브(윾머, 풍동)의 친분&lt;/a&gt;을 확인.&lt;br /&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99838F495C4E141811&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99838F495C4E141811&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;윾.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992FF5475C4E141A0F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992FF5475C4E141A0F&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;윾3.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991F3F3B5C4E141B11&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991F3F3B5C4E141B11&quot; width=&quot;400&quot; height=&quot;226&quot; filename=&quot;윾2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td title=&quot;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994F1F3C5C4E141911&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994F1F3C5C4E141911&quot; width=&quot;400&quot; height=&quot;225&quot; filename=&quot;윾4.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;요약하자면&lt;br /&gt; &lt;p class=&quot;&quot;&gt;- 윾머(윾튜브)와 윤서인이 함께 도쿄에 갔다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 평소 JM을 존경해왔음 + 도쿄에 감 + 뽱갑습니다 인트로 + 빨간 빈백 + 벽의 구조&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;=&amp;gt; 12월 초(12/4~6)도쿄에 간 김에 윾튜브가 JM의 자택에 방문해서 영상을 찍은 것 같다는 킹리적 갓심.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;1) 철구 구독 및 윾튜브와 친목과 프로필 작가 공유.&lt;br /&gt;&lt;/h4&gt;&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://namu.wiki/w/%EC%B2%A0%EA%B5%AC(BJ)/%EB%85%BC%EB%9E%80%20%EB%B0%8F%20%EC%82%AC%EA%B1%B4%EC%82%AC%EA%B3%A0&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;철구&lt;/a&gt; 구독&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_10&quot; id=&quot;footnote_link_58_10&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 10)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 10)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;10&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;, 윾튜브 또는 윾튜브 패밀리와 대놓고 친목질은 물론&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D42C485C4DD74809&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D42C485C4DD74809&quot; width=&quot;400&quot; height=&quot;798&quot; filename=&quot;JM3.jpeg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;썸네일 작가마저 공유하자&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995EC1365C4DD68F25&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995EC1365C4DD68F25&quot; width=&quot;400&quot; height=&quot;392&quot; filename=&quot;JM1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E535385C4E174412&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E535385C4E174412&quot; width=&quot;400&quot; height=&quot;186&quot; filename=&quot;12-27.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;구독자들이 반발했다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그러자 사과영상을 올리는데..(2018. 12. 19)&lt;/p&gt;&lt;hr&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/RhGOG0ZwFLk?rel=0&quot; width=&quot;560&quot; height=&quot;420&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;해석본.&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;반갑습니다, 여러분.&lt;br /&gt;지난 이틀간 제 썸네일에 관한 의견 굉장히 많이 주셨어요, 감사합니다.&lt;br /&gt;=&amp;gt; 지난 이틀간 썸네일에 대해 귀찮게시리 말이 많네.&lt;br /&gt;&lt;br /&gt;아, 첫 번째로는 저는 제 유튜브 채널로 인해서 누구도 불편하게 하고 싶지 않습니다.&lt;br /&gt;하지만 본의 아니게 누군가가 불편함을 느꼈다면, 사과드릴게요. (꾸벅) 죄송합니다.&lt;br /&gt;=&amp;gt; 가장 좋은건 조용했으면 좋았을텐데.&lt;br /&gt;하지만 예상과 다르게 시끄러우니 일단 미안~&lt;br /&gt;&lt;br /&gt;하지만 오늘 제가 어떤 말을 해도 이미 제가 싫어진 분들의 마음을 돌릴 수는 없습니다.&lt;br /&gt;제가 아무리 설명을 해도 마음 안 바뀔 거 제가 알아요.&lt;br /&gt;그래서 제가 사실 뭐 댓글이나 혹은 이전에 있었던 저에 대한 논란에 대해서 말을 좀 많이 아꼈습니다만은,&lt;br /&gt;오늘, 이전에 있었던 논란까지 다같이 한번 말씀을 드려볼게요.&lt;br /&gt;=&amp;gt; 하지만, 어떤말을 해도 내 마음은 돌릴수는 없어.&lt;br /&gt;아무리 설명을 해도 마음 안 바뀔거 내가 알아.(나니까)&lt;br /&gt;그래서 따로 영상을 안찍으려고 했는데,&lt;br /&gt;(구독자가 떨어질 수 있으니) 오늘, 이전에 있던 논란까지 한번에 정리하자.&lt;br /&gt;&lt;br /&gt;첫 번째, 제가 가장 좋아하고 오래 했었던 커뮤니티 사이트 중에 클리앙이라고 하는 사이트가 있습니다.&lt;br /&gt;하루는 거기에서 한 게시물을 봤는데 제 욕을 엄청 하고 있어요.&lt;br /&gt;그 댓글에도 밑에 줄줄이 구독 취소합니다, 손절합니다, 엄청나게 달려있어요.&lt;br /&gt;=&amp;gt; 첫 번째, 가장 구독자를 많이 늘려주고 오래 꿀빨았던 클리앙부터 깔께.ㅇㅇ&lt;br /&gt;내가 거기 엄청 까기 시작할거임.&lt;br /&gt;댓글들로 밑에 줄줄이 클리앙 좀 까줘라.ㅠㅠㅠ 무셔웠엉ㅠㅠ&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;뭐지, 내가 뭘 잘못했지, 하고 내용을 봤습니다.&lt;br /&gt;보니까, 내가 철구를 구독을 했대. 어, 철구를 구독한 게 왜 문제지?&lt;br /&gt;열심히 검색을 해봤더니 무슨 518에 대한 발언을 했대요.&lt;br /&gt;=&amp;gt; 뭐를 잘못했지 내용을 보자.&lt;br /&gt;내가 철구를 구독했대. 어, 철구를 구독한게 왜 문제지?(진지)&lt;br /&gt;무슨 5.18같은거 관심없어~~ 알게 뭐야.&lt;br /&gt;&lt;br /&gt;여러분 제가 구독하고 있는 채널의 개수가 805개고요. 그중에 철구님 채널에 올라와있는 동영상 개수가 7000개 가까이 됩니다.&lt;br /&gt;제가 철구님 처음 구독한 게 2014년으로 알고 있는데, 그때는 유튜브에 한국어 콘텐츠가 별로 없어가지고, 한국인 채널만 있으면 바로 구독을 눌렀었어요.&lt;br /&gt;제가 그분 영상을 지난 4년동안 뭐 많이 봤으면 한 5개 봤나?&lt;br /&gt;근데 클리앙에서는 내가 철구 구독되어 있으니까, 나 보고 나쁜놈이래요.&lt;br /&gt;=&amp;gt; (5.18 이야기 나오면 민감하니 화재 전환 *뿅뿅*)&lt;br /&gt;내가 구독하고 있는 채널도 많고, 철구 영상갯수도 많은데 어떻게 다 아냐?&lt;br /&gt;2014년에 한국어 채널 별로 없길래 걍 구독한거고 보지도 않았어.&lt;br /&gt;아무것도 모르는ㅠㅠㅠㅠㅠ 내가 왜 나쁜놈이냐?&lt;br /&gt;&lt;br /&gt;제가 구독하고 있는 805개 채널의 크리에이터들이 어떠한 발언을 하고 있는지 전부 다 모니터링할 수는 없어요, 제가.&lt;br /&gt;근데 그 게시물을 본 지인이 왜 구독한 리스트를 공개로 해놨냐고 해요.&lt;br /&gt;저는 일부러 공개해놨어요.&lt;br /&gt;제가 구독하고 있는 채널 리스트만 보고 저를 싫어할 분이라면, 이후에도 내가 뭐가 싫어도 싫어서 떠날 분들이라고 저는 생각을 해요.&lt;br /&gt;=&amp;gt; 내가 어떻게 다 아냐? 아무것도 모른다니까.&lt;br /&gt;왜 공개로 해놨을까. 일부러 했다 치자.(역공 개시^^)&lt;br /&gt;걍 내가 마음에 안들어서 꼬투리 잡고 공격하는거 아냐?&lt;br /&gt;가든가 말든가~~&lt;br /&gt;&lt;br /&gt;그래서 계속 일부러 철구님 채널도 구독을 해놨고, 구독 리스트도 계속 공개로 놔뒀습니다.&lt;br /&gt;앞으로도 제가 구독해놓은 채널 리스트만 보고 떠나실 분들은 떠나셔도 괜찮아요.&lt;br /&gt;=&amp;gt; 5.18 아무튼 관심없고, 철구 구독할거임.&lt;br /&gt;철구로 꼬투리 잡을 사람들은 가라. 가라고.&lt;br /&gt;&lt;br /&gt;또 두 번째, 일본 올 때 직장 동료가 일본에서 집 구할 때까지 있을 호텔을 예약을 해줬는데, 그게 아파호텔이었어요.&lt;br /&gt;난 아무것도 모르고 자고 영상 찍고 그러는데, 클리앙이나 제 채널에서 개쌍욕들이 달립니다.&lt;br /&gt;우익호텔인데 너 왜 거기서 자냐고 막 막말이 달려요.&lt;br /&gt;=&amp;gt; 둘째 직장 동료가 호텔 예약 해줬는데 아파호텔이네.&lt;br /&gt;난 아무것도 모른다니까ㅠㅠㅠㅠㅠ 그런데 개쌍욕을 하네?&lt;br /&gt;우익호텔에서 잔다고 욕먹을 일이냐?&lt;br /&gt;&lt;br /&gt;아니, 나는 그냥 다른 사람이 예약해준 호텔에서 잤을 뿐인데, 거기 우익호텔인데 너 왜 거기 가서 자냐고 엄청나게 막말을 해요.&lt;br /&gt;우익인지 뭔지는 모르겠는데, 아파호텔은 집이 없는 저에게 만족스러운 방과 서비스를 제공했습니다.&lt;br /&gt;일본 동료는 저 대신에 귀찮은 호텔 예약을 도와줬습니다.&lt;br /&gt;그리고 아파호텔에서 잤다는 이유만으로 저한테 쌍욕을 합니다.&lt;br /&gt;=&amp;gt; 아무것도 모르고 잔 것 만으로 욕먹네?&lt;br /&gt;우익인것도 알바 아냐~~ 내가 만족스럽기만 되지.&lt;br /&gt;(욕먹을거 같으니까 남탓하자) 어쩔 수 없었다니까. 일본 동료 성의 무시하는거임??&lt;br /&gt;잔것만으로 욕먹는거 빡치네?&lt;br /&gt;&lt;br /&gt;우익인지 뭔지는 모르지만, 최소한 저한테는 이 사람보다는 아파호텔이 훨씬 더 좋고 고맙습니다.&lt;br /&gt;역시 제가 살면서 구입하는 제품, 사용하는 서비스, 모든 기업들의 역사와 배경, 정치 성향까지 알아보고서 물건을 살 수는 없습니다.&lt;br /&gt;그런 것들로 제가 싫어질 분들이라면, 미리 구독 취소하세요.&lt;br /&gt;예, 죄송합니다.&lt;br /&gt;=&amp;gt; 우익 관심없구, 좋고 고마운 아파호텔 또 가고 싶당.&lt;br /&gt;역시 역사와 배경, 정치 성향은 알아도 모르고 몰라도 모를 예정이니&lt;br /&gt;이딴걸로 시비걸거면 가라.&lt;br /&gt;응, 미안^^&lt;br /&gt;&lt;br /&gt;또 요즘 유튜브를 보니까 썸네일을 만화로 쓰는 분들이 굉장히 많습니다.&lt;br /&gt;그래서 그중에 유일하게 내가 아는 분한테 이거 어떻게 하신 거예요? 물어봤더니 작가님이 따로 계시대요.&lt;br /&gt;그 작가님이 벌써 유튜버 네다섯 명은 이미 썸네일을 그려주고 계시대.&lt;br /&gt;=&amp;gt; 요즘 윾튜브 패밀리 썸네일에 관심이 굉장히 많아.&lt;br /&gt;그래서 윾튜브한테 물어보니까 작가가 따로 있더라고.&lt;br /&gt;윾튜브 말고도 썸네일 그려주는 사람이 있으니 나중에 빠져나갈 구명 발견!!&lt;br /&gt;&lt;br /&gt;그래서 작가님, 저도 이거 테스트로 한번 해볼 수 있을까요? 그랬더니 가능하대요.&lt;br /&gt;근데 이 테스트라는 게 한두 개만 해가지고는 조회수가 잘 나오든, 안 나오든 이게 썸네일 빨인지, 아니면 소재 빨인지 알 수가 없잖아요.&lt;br /&gt;그래서 아, 그래도 효과를 제대로 알려면 최소한 일이주는 해봐야 되지 않을까?&lt;br /&gt;그래서 일이주를 테스트를 하기로 했습니다.&lt;br /&gt;=&amp;gt; 윾튜브 프로필처럼 하면 잘나가겠지?&lt;br /&gt;최소 일이주는 실험해보자.&lt;br /&gt;&lt;br /&gt;그랬더니 사람들이 엄청나게 화가 났어요.&lt;br /&gt;물론 그림 썸네일 자체가 싫은 분들도 계시지만은, 대부분의 분들은 그 작가님이 작업해주시는 여러 사람들 중에 한 사람이 싫대요.&lt;br /&gt;근데 여러분, 명함을 이 명함제작자가 어떠한 정치성향과 사상을 가지고 있는지, 또 어떠한 사람들을 고객으로 두고 있는지, 또 이 고객들의 정치성향과 사상은 어떠한지.&lt;br /&gt;이런 거 따져가면서 명함 만드나요?&lt;br /&gt;=&amp;gt; 그랬더니 사람들이 화났네?(왜 또 그런대..)&lt;br /&gt;그림 썸네일보다는 내 친구 윾튜브가 싫대.&lt;br /&gt;근데 여러분 난 정치성향, 사상, 고객, 고객의 정치성향, 사상 관심없다니까?&lt;br /&gt;&lt;br /&gt;어떤 사람이 명함을 갖고 있는데 예뻐, 이거 어디서 만든 거예요?&lt;br /&gt;가서 그냥 만든 거예요.&lt;br /&gt;=&amp;gt; 내 마음대로 할거임.&lt;br /&gt;&lt;br /&gt;내가 오죽하면 그 댓글들을 보고 작가님한테 작가님, 정치성향은 어떠세요?&lt;br /&gt;어느 정당 지지하세요? 이렇게 실제로 물어봤습니다.&lt;br /&gt;어찌 보면 제가 굉장한 실례를 한 거죠.&lt;br /&gt;=&amp;gt; 변명거리 만들어야 하니 정치성향, 사상 물어봤지 ㅎㅎ&lt;br /&gt;아니 진짜라니까.&lt;br /&gt;댓글러들아 실례한거에 미안해해라.&lt;br /&gt;&lt;br /&gt;그랬더니 본인은 정치에 관심도 없고, 무슨 당이 뭔지도 모르겠대요. 좌파가 뭐고, 우파가 뭔지도 그런 것도 하나도 모르겠대.&lt;br /&gt;근데 내가 거기서 거짓말하지 마세요. 그 고객 중에 한 분이 정치색이 굉장히 뚜렷하시던데 작가님도 그쪽 성향 아니에요?&lt;br /&gt;이렇게 물어볼까요? 전 그런 거 알고 싶지도 않아요.&lt;br /&gt;=&amp;gt; 나두 아무것도 몰라~~&lt;br /&gt;댓글러들이 하는 것처럼 그쪽 성향 아니라고 물어보리?&lt;br /&gt;그런 거 하지 좀 마라.&lt;br /&gt;&lt;br /&gt;저는 그냥 그 그림이 귀여워서 작가님한테 그냥 썸네일 테스트를 그냥 하고 싶었을 뿐이거든요.&lt;br /&gt;나도 정치에 별 관심도 없고 거기에 대해서 무슨 의견 표명 같은 거 하고 싶지도 않아요.&lt;br /&gt;난 그냥 전자제품이나 신기한 물건 이런 거 좋아하고, 그냥 장가가 마려운 34살 아저씨예요.&lt;br /&gt;=&amp;gt; 난 그 그림이 귀여워서 써보고 싶었던거야.&lt;br /&gt;정치 관심없다니까?&lt;br /&gt;난 넘나 순수한 사람 ♡♡&lt;br /&gt;&lt;br /&gt;그래서 뭐 이런 핸드폰 같은 거나 찍어서 올리고 그러는데, 보면서 굳이 이 새끼 이거 전자제품이 좋다고 올리고는 있지만, 정치성향은 뭘까, 이 싹일까 저 싹일까.&lt;br /&gt;어디 보자, 어 얘 철구 구독했네. 여러분, 이거 보세요. 이 사람 철구 구독했어요.&lt;br /&gt;얘 정치성향이 있네. 어, 아파호텔에서 잤네. 여러분, 얘 극우기업 이용하는 친일파예요. &lt;br /&gt;어, 이 사람 썸네일을 만화로 그리네. 근데 내가 싫어하는 사람하고 같은 그림체네.&lt;br /&gt;왜 자꾸 그렇게 논란있는 분하고 친해지려고 그러세요?&lt;br /&gt;난 내가 몰랐던 것도 사람들이 만들어서 그렇게 몰아가더라고.&lt;br /&gt;=&amp;gt; 난 순수한 사람인데, 보면서 굳이 정치성향이니 극우니, 싫어하는 사람 때문에 왕따 시키려 하지 좀 마.&lt;br /&gt;난 아무것도 모르는 선량한 피해자야ㅠㅠㅠㅠㅠ&lt;br /&gt;&lt;br /&gt;물론 내가 구독정보도 전부 다 정리하고, 호텔 갈 때마다 이 기업의 사상과 성향을 알아보고,&lt;br /&gt;또 한 다리 걸쳐서라도 이슈가 있을 만한 사람하고 조금이라고 연관이 되어있으면 아예 그냥 상종도 하지 말고.&lt;br /&gt;그렇게 했으면 뭐 이런 욕 안 먹었을 수도 있겠죠. 근데 저는 그러고 싶지는 않아요, 그렇게 할 수도 없고.&lt;br /&gt;=&amp;gt; 니들이 원하는 대로하면 욕은 안먹겠지만 싫어.&lt;br /&gt;윾튜브 갸꿀이걸랑 ♡♡&lt;br /&gt;&lt;br /&gt;그래요, 오늘의 결론.&lt;br /&gt;정치나 사상하고 관련 1도 없는 얘기하고 있는데, 굳이 썸네일 작가의 고객 중 한 명의 사상이나 정치성향까지 분석해가지고&lt;br /&gt;그거 가지고 불편해하지 마시고, 우리가 좋아하는 관심사 얘기하고 정보 공유하고 그렇게 놀자고요.&lt;br /&gt;=&amp;gt; 오늘의 결론.&lt;br /&gt;난 정치나 사상은 모르니까 불편해하지 말고, 잠자코 보기나 해라.&lt;br /&gt;&lt;br /&gt;그럼 오늘도 영상 봐주셔서 감사하고,&lt;br /&gt;저는 또 다음 비디오 때 뵙도록 하겠습니다.&lt;br /&gt;들어가세요.&lt;br /&gt;=&amp;gt; 갈놈들 가고, 다음주에 또 봐.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;요약.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;윾튜브 손절 안함.(잘해줬걸랑)&lt;/li&gt;&lt;li class=&quot;&quot;&gt;나 싫으면 보지마라.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;난 아무 잘못 없음.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;나 대신 때려줘.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;hr&gt;&lt;p class=&quot;&quot;&gt;내가 꼬인 사람인걸까.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;최근 일까지 보고나니 이렇게 밖에 해석이 안된다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;당연히 &lt;a href=&quot;https://www.youtube.com/watch?v=RhGOG0ZwFLk&amp;amp;feature=youtu.be&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;댓글&lt;/a&gt;은 난리.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99ABD9415C4E105B0F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99ABD9415C4E105B0F&quot; width=&quot;800&quot; height=&quot;1883&quot; filename=&quot;jm4.png&quot; filemime=&quot;image/png&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;극우 호텔이든, 일베 컨텐츠 제작자이든 당연히 모든것을 알 수는 없다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그런데 최소한의 역사, 도덕, 윤리적인 의식이 있다면 극우 호텔인 것을 알고, 5.18을 폭동이라 매도하는 사람, 일베성향인 유머저장소라는 것을 운영하는 사람이라는 것을 안 순간&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p class=&quot;&quot;&gt;다음부터는 안가도록 노력해봐야겠다&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;다음부터는 조금 더 조심히 사람을 만나야겠다.(인연 끊기는 어렵다니까)&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p class=&quot;&quot;&gt;등등 반성 및 재발방지에 대한 약속은 할 수 있지 않을까?&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;윾튜브가 아무것도 모르고 이 페이지에 있는 악행을 저질렀다고 가정하면 봐주어야 하는 것일까?&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;또 자신의 편을 들어주는 댓글에만 좋아요를 눌러준다는건 반성하고 있다고 도저히 볼 수가 없다.&lt;/p&gt;&lt;br /&gt;&lt;p class=&quot;&quot;&gt;찾아보니 JM은 나름 인생조언들을 해줄 정도로&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F7BE345C4E189010&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F7BE345C4E189010&quot; width=&quot;800&quot; height=&quot;850&quot; filename=&quot;인생꿀팁.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;삶에 대한 고민이 있는 사람이더라.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그런데 구독자들이 비인륜적인 사람과 얽히지 마라고 사정하는 말을 하나도 듣지 않았다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;오히려 외부의 적이자 내부의 희생양을 앞세워 코어 구독자들의 결집력을 높히는 한편 자신에 대한 관심과 비판을 돌리려는 행동은 엄청나게 정치적인 행보였다.&lt;br /&gt;&lt;/p&gt;&lt;h4 class=&quot;&quot;&gt;2. 드디어 다가온 황혼의 시간.&lt;br /&gt;&lt;/h4&gt;&lt;p class=&quot;&quot;&gt;윾튜브의 정체가 본격적으로 드러나니 당연히 구독자들은 2019. 01. 22의 미친드립ㅋㅋㅋㅋ라는 영상에 몰려가 뭐라고 한다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997B7B405C4E19F612&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997B7B405C4E19F612&quot; width=&quot;800&quot; height=&quot;1845&quot; filename=&quot;jm5.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;물론 윾 패밀리와의 친목은 잊지 않고 틈틈히 했다.(Jo Jo는 윤서인 부인)&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F23B355C4E1D0913&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F23B355C4E1D0913&quot; width=&quot;800&quot; height=&quot;1096&quot; filename=&quot;조조.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;3) 윾튜브와 나. - 궁색한 변명.&lt;/h4&gt;&lt;p&gt;마침내 2019. 01. 23에 영상을 올리는데&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/BrBdWHNrvZs?rel=0&quot; width=&quot;560&quot; height=&quot;420&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://www.evernote.com/l/AUXUQA8-XORFWYnBluw7kmwvOooq7p5MgYw/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;해석본 아카이브&lt;/a&gt;를 바탕으로 수정했다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;해석본.&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;반갑습니다 여러분.&lt;br /&gt;제가 얘기를 사실은 안 하려고 했는데 윾튜브님 채널이 삭제가 되면서 저한테 많이들 물어보세요.&lt;br /&gt;그래서 제가 오늘 살짝 언급하고 하겠습니다.&lt;br /&gt;=&amp;gt; 당연히 해명했어야 하긴 하지만 괜히 욕먹을까봐 그냥 조용히 묻어갈려고 했는데, 어쩔 수 없네.&lt;br /&gt;&lt;br /&gt;자, 맨 처음에 유머 저장소, 윾머님은 제 영상이 좋았다고 합니다. 어떻게 보면 영상 너무 재밌게 만드는 제 잘못이죠 죄송합니다.&lt;br /&gt;꽤 오래전에 제 라이브에서 채팅을 많이 치셔가지고 그때 처음으로 알게 됐고&lt;br /&gt;뭐 다른 분들이 페이스북에서 엄청 큰 페이지를 운영하신다고 해 가지고 그냥 그런가보다 하고 말았어요.&lt;br /&gt;=&amp;gt; 윾튜브가 먼저 접근한 거임. 내 영상 잘만들었긴 하잖아 ㅋ&lt;br /&gt;내잘못이라고 한다면 영상 잘만든 거? 그거말곤 없어~ 진지한 태도? 그딴 거 해야함?ㅋ 니네 걍 잘 넘어갔잖아 항상 ㅋ&lt;br /&gt;난 몰랐던 사람임 어떤 사람인지 몰랐음 알 노력도 하기 싫었고 아무튼 윾튜브가 먼저 접근한거임.&lt;br /&gt;&lt;br /&gt;제가 원래 남자한테 관심이 없으니까 그 때는 그분이 유튜브로 하지도 않을 때 였어요.&lt;br /&gt;근데 저한테 메세지도 굉장히 많이 보내시고 그래가지고 아 이 분이 나랑 굉장히 친해지고 싶어 하시는구나 라는 느낌을 받았습니다.&lt;br /&gt;=&amp;gt; (물어본 적도 없지만) 응 나 남자한테 관심없어 ㅠㅠ 나 게이아니야 ㅠㅠ 나 게이아니야 ㅠㅠ&lt;br /&gt;이거 봐 윾튜브가 먼저 접근했다니까? 계속 치근덕댔다고!!!&lt;br /&gt;&lt;br /&gt;저도 뭐 라이브 채팅 치실 때마다 막 사람들이 막 술렁술렁거리고 sns 에서 그렇게 큰 영향력 있는 사람이라면&lt;br /&gt;나도 뭔가 배울 점이 있지 않을까 싶어 가지고 인스타 dm 으로 메시지를 주고받고는 했어요.&lt;br /&gt;=&amp;gt; 알고보니까 SNS에서 잘나갔네?&lt;br /&gt;당시 구독자 수도 정체기인데 뭔가 콩고물이라도 떨어지지 않을까 싶어서 인스타 다이렉트 메세지로 사적인 대화를 나눴다.&lt;br /&gt;&lt;br /&gt;사실 지금도 그렇지만 저는 몇 년 전부터 페이스북 앱 자체를 삭제를 해 가지고 페북 하지도 않고 그래가지고, 정확하게 어떤 글을 쓰시는 줄은 몰랐습니다.&lt;br /&gt;한 두번씩 메세지도 오고가고 하다 보니까 그 분 페이지를 보게 되는데 아주 옛날 글들은 제가 못 봤지만&lt;br /&gt;그래도 최근 글들을 보면서 아 이분은 뭔가 강한 언어로 자기 주장을 확실히 하시는 분이기 때문에 호불호가 굉장히 갈리겠구나 라는 생각을 했습니다.&lt;br /&gt;=&amp;gt; 인스타 DM도 주고받은 사이지만 무슨 페이지 운영하는지 들어가본 적도 없다고 암튼 몰랑! 나 페북할줄몰라! 구독자들이 말해준 거? 그거 내가 들어야함? 암튼 모른다고~&lt;br /&gt;응? 방금까지는 본 적 없다고 말했는데 아무튼 갑자기 본 적 있는 걸로 말바꿀거임. 옛날 문제되는 글 본 적도 없고 암튼 아몰랑 난 모른다고. &lt;br /&gt;&lt;br /&gt;그리고 나서 그 분이 유튜브도 시작하셨는데 이건 뭐 나중에 들은 얘기지만 그 분이 가장 존경하는 유튜버가 jm 이고, jm 때문에 유튜브를 시작했다.&lt;br /&gt;라고 말씀을 하시더라고요 이건 뭐놀랄 일은 아니죠 사실은.&lt;br /&gt;그리고 나서 뭐 사회 이슈나 이런저런 얘기를 하면서 정말 어마어마한 속도로 성장을 했습니다.&lt;br /&gt;=&amp;gt; 윾튜브가 먼저 접근한 거고 그렇게 잘나가던 윾튜브가 나를 존경했었고 나 때문에 유튜브를 시작할 정도였어~&lt;br /&gt;나 완전 잘나가지? 놀랄 것도 없지 이젠?&lt;br /&gt;윾튜브가 잘 크더라고. 나도 꿀 좀 빨았지.&lt;br /&gt;&lt;br /&gt;하지만 여러분들은 어떻게 느끼셨는지 모르겠지만 저는 이 분과 친분이 있다는 걸 굳이 막 드러내고 싶지도 않았고, 애써서 막 감추고 싶지도 않았어요.&lt;br /&gt;왜냐하면 예를 들어서 이분이 이쪽 성향을 가지고 있다고 쳐봐요.&lt;br /&gt;내가 일부러 막 거리를 두는 순간 나는 반대쪽 성향의 사람이 되는 거고 그렇다고 내가 막 대놓고 이러면 나는 자동적으로 이쪽 사람이 되는 거예요.&lt;br /&gt;물론 그렇게 판단 하지 않을 사람들이 대부분이지만 이런 걸 가지고서 꼭 사상 검증 하려고 하는 사람 있어요.&lt;br /&gt;=&amp;gt; 구독자들 생각은 필요없고, 윾튜브랑 친목한 적 없어^^&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C7C73E5C4E1EDC13&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C7C73E5C4E1EDC13&quot; width=&quot;800&quot; height=&quot;2767&quot; filename=&quot;이말년.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;(부드럽게 논란을 넘어간 말년이형 베껴야지)&lt;/p&gt;
&lt;p class=&quot;&quot;&gt; 성향 차이일 뿐이야. 난 그분이랑 성향이 다른 거 뿐임 ㅎ&lt;br /&gt;근데 불편러들 사삼검증 하려는 놈들 너무 싫다.ㅠㅠㅠㅠㅠ&lt;br /&gt;* 성향: 근친상간, 소아성애, 세월호, 천안함 드립 등등&lt;br /&gt;&lt;br /&gt;또 가끔 보면 이쪽 노선을 타 가지고 이 쪽 구독자를 빨아 먹으려는 심상이다 라는 사람들도 있어요.&lt;br /&gt;근데 그건 유튜브를 정말 모르는 사람들이 하는 소리고요.&lt;br /&gt;내가 진짜 거기서 구독자 빨아먹으려고 했으면 동조하는 영상도 많이 올리고 더 합방도 하고 친한 티 팍팍 냈겠죠.&lt;br /&gt;하지만 실제로는 제가 뭐 친분을 굳이 감추려고도 하지도 않았지만 그렇다고 뭐 친한티를 엄청 내거나, 콜라보레이션 영상을 찍는다거나 그런 것도 없어요.&lt;br /&gt;=&amp;gt; 꿀빨았지만 암튼 윾한테 도움받으려고 한 거 아니야! 암튼 아님!&lt;br /&gt;응 이미 일본 우리집까지 찾아와서 영상 찍고 자고 갔지만 아무튼 친한 거 아님.&lt;br /&gt;댓글로 서로 물고빨고 난리였지만 암튼 친한 티 낸 적 없어~ 합방안하면 친한티 낸 거 아니잖아 ㅋㅋ 친한 티 내는 기준은 무조건 합방이다 그치?&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998ACF495C4E1F4413&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998ACF495C4E1F4413&quot; width=&quot;800&quot; height=&quot;180&quot; filename=&quot;jm 합방.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;[실제로 합방까지 하려고 했었구나??? ㅋㅋㅋㅋ]&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;여러분이 유튜브로 시작했는데 보겸 님이 여러분 채널을 맨날 맨날 언급해 준다고 금방 클 것 같아요?&lt;br /&gt;절대 그렇지 않습니다.&lt;br /&gt;물론 저는 그분을 제대로 알기 전부터 저를 꾸준히 언급을 해 줘 가지고 제가 버프는 굉장히 많이 받았습니다.&lt;br /&gt;감사하게 생각하는 부분이지만 저 개인적으로는 남의 버프를 받아가지고 클 수도 없다고 생각하고, 그렇게 크고 싶지도 않습니다.&lt;br /&gt;=&amp;gt; 너네같은 얘들은 보겸이 키워줘도 안 돼 ㅋㅋ 너네 수준이랑 내 수준이랑 달라 ㅋㅋㅋㅋ&lt;br /&gt;응 니네는 안 되는데 나는 돼 ^^ 응 나는 버프받을 능력 있어 니네같은 얘들은 어림도 없다만 난 그럴 능력 돼 ^^&lt;br /&gt;(적당히 선그어야지) 방금전에는 버프받아서 컸다고 했지만 윾 도움 받은거 아니옄ㅋㅋ 상관없다니까&lt;br /&gt;&lt;br /&gt;또 그 분 영상의 조회수가 굉장히 잘 나왔지만 저는 이 영상을 보는 모든 사람들이 다 그 분이 하시는 말씀에 동의 할 거라고는 생각하지 않아요.&lt;br /&gt;저도 그 분의 영상 중에 동의 하는 부분이 있고 동의하지 않는 부분이 있습니다.&lt;br /&gt;근데 제가 거기 동의하고 말고를 떠나서 어떤 사람이 어떠한 성향이 있다고 해 가지고 일부러 멀리해야 된다면 앞으로는 어느 쪽 이든 성향이 있는 사람하고는 다 가까이 지내면 안되겠네.&lt;br /&gt;=&amp;gt; 그분의 높은 조회수에서 넘어온 사람들이 있지만, 너희도 윾 묻은거 암튼 아니잖아? 그치??&lt;br /&gt;근친상간, 소아성애, 세월호, 천안함 드립은 성향 차이라니까.&lt;br /&gt;윾이랑 일부러 멀리해야 될 정도라면 사회생활 포기해야지. 너희도 똑같잖아.&lt;br /&gt;&lt;br /&gt;우리 편 성향 하고는 친하게 지내도 되고 다른 편 성향 하고는 친하게 지내면 안되고 이렇게 이중 잣대로 보시진 않을 거 아니에요.&lt;br /&gt;또 이 사람의 성향을 모른 채 친해진 사람이라 하더라도 이후에 아 이 사람이 어떤 성향이 있었네 라는 걸 알게 된 순간 무조건 손절을 해야 된다?&lt;br /&gt;약간 이런 논리잖아요.&lt;br /&gt;근데 여러분 사람의 성향이라는게 한둘입니까?&lt;br /&gt;=&amp;gt; 겨우 '성향'차이로 흑백논리, 내로남불짓 할거니?&lt;br /&gt;니들 이런 논리잖아.&lt;br /&gt;반인륜적 패륜짓거리도 그냥 성향 중 하나임 암튼 난 그냥 성향존중하는 사람임 ㅋㅋ 난 잘못없다 ㅋㅋㅋ&lt;br /&gt;&lt;br /&gt;정치적으로 뭐 대표적으로 진보와 보수가 있겠지만&lt;br /&gt;그 내부에서도 친 페미니스트, 반페미니스트 ,종교에 관한 생각, 동성애에 관한 생각, 삼성에 대한 찬반 있고, 또 애플에 대한 찬반 있고 윈도우 pc와 맥북에 찬반도 있습니다.&lt;br /&gt;또 뭐 택배 기사님들 파업에 대한 의견도 가지가지고, 또 뭐 진보 보수를 떠나서 한의학을 좋아하는 분들도 계시고 안 좋아 하는 분들도 계세요.&lt;br /&gt;=&amp;gt; (진보와 보수 프레임으로 물타기 해야지)&lt;br /&gt;윾튜브가 한 짓거리도 삼성과 애플, 윈도우와 맥 고르는 수준이랑 비슷한 수준이라니까.&lt;br /&gt;난 윾튜브처럼 페미, 동성애, 한의사 싫어하는 사람 아님.&lt;br /&gt;&lt;br /&gt;또 뭐 살인 용의자 인터뷰를 보고 아 사람은 나쁜 사람이다, 이 사람은 측은한 사람이다, 여러가지 의견이 있어요.&lt;br /&gt;자 여러분, 앞으로 나와 생각이 100% 같은 사람을 만날 수가 있어요?&lt;br /&gt;저는 우리 친 가족하고도 생각하는 사고방식이 조금 조금씩 다릅니다.&lt;br /&gt;=&amp;gt; 살인마도 나쁜 사람이다, 측은한 사람이다 의견이 갈리는 판에 윾은 안그러겠냐. [윾도 사람마다 의견이 갈림. 윾튜브 구독자님들 아시죠??]&lt;br /&gt;자 여러분, 내가 어떻게 생각이 같은 사람이랑 만납니까. 가족끼리도 다른데.&lt;br /&gt;&lt;br /&gt;다만 저도 이번에 새로 알았지만, 그 분이 아주 옛날에 썼던 글 들은 생각이 다르다기 보다는 틀린 게 맞아요.&lt;br /&gt;그 분도 크게 반성을 하고 있고요.&lt;br /&gt;근데 앞으로도 내 주변에 누군가가 다른 생각, 혹은 틀린 생각을 할 때마다 절교를 하고 예전에 했던 잘못들을 발견할 때마다 손절을 해야 되나?&lt;br /&gt;=&amp;gt; 일단 내가 못본(오래된)글들은 틀린거 맞음.ㅇㅇ(선은 확 그었다?)&lt;br /&gt;일 터지고도 윾튜브랑 연락했다.(ㄷㄷ) 윾튜브 크게 반성하고 있으니까 함 봐줘라~&lt;br /&gt;그런데 윾튜브가 쓰레기짓 많이 했지만 암튼 손절안해 ^^.&lt;br /&gt;&lt;br /&gt;저희가 손절을 하지 않았다고 비난을 하시는 분들은 그런 게 가능 하실 지 모르겠지만 저는 그런 게 힘듭니다.&lt;br /&gt;자. 이제 그분 채널도 없어졌는데 제가 정말로 기회주의자 였다면, 이 때야 말로 손절 할 절호의 타이밍 아닙니까?&lt;br /&gt;이제 더 이상 받을 버프도 없으니까.&lt;br /&gt;=&amp;gt; 비난하는 놈들아 너네는 그런 거 가능하냐? 니들부터 잘해라(가능하긴 하냐). 응 그리고 난 힘들어 난 손절 안할래~&lt;br /&gt;내가 진짜 기회주의자여서 윾튜브 꿀 빨아먹으려고 했으면 이미 손절했다니까.(이게 바로 진실한 우정이여)&lt;br /&gt;윾튜브야 고마웠어.♡♡ (난 니편이다 알지?)&lt;br /&gt;&lt;br /&gt;하지만 그런 건 아니에요.&lt;br /&gt;저는 누군가를 사귈 때 이 사람과의 관계에서 얻는 득과 실을 계산 하기 보다는 큰 계산 없이 그냥 누가 됐더라도 그냥 두루두루 잘 지내고 싶은 마음 뿐 이였어요.&lt;br /&gt;=&amp;gt; 난 기회주의자 따위가 아냐.&lt;br /&gt;내 실책은 두루두루 잘 지내는 것 밖에 없어ㅠㅠㅠ 그게 내 잘못?ㅠㅠ&lt;br /&gt;그리고 아깐 SNS에서 영향력이 큰 사람이라 알게 되었고 만난 건데 아무튼 난 지금와서는 그런거 안 중요하다니까?ㅠㅠ 내가 그렇게 속물로 보여?&lt;br /&gt;(물론 두루두루 꿀빠는게 쵝오지.)&lt;br /&gt;&lt;br /&gt;그래요, 그럼 오늘도 영상 봐주셔서 감사하고 전 또 다음 비디오 때 뵙도록 하겠습니다 여러분.&lt;br /&gt;들어가세요&lt;br /&gt;=&amp;gt; 나중에 또 봐.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;요약.&lt;/b&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;윾튜브 손절 안함.(잘해줬걸랑)&lt;/li&gt;&lt;li&gt;윾튜브 반성 중임.&lt;/li&gt;&lt;li&gt;난 아무 잘못 없음.&lt;/li&gt;&lt;li&gt;나 싫으면 보지마라.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;hr&gt;&lt;p class=&quot;&quot;&gt;으음.. 요약을 보니 어디서 많이 보던거 아닌가?&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그렇다. 민호타우르스와 동일한 말을 이리저리 돌려서 해놓은 것이다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이쯤되면 생각나는 영화 대사가 있다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 570px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9918C34D5C4E219E16&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9918C34D5C4E219E16&quot; width=&quot;570&quot; height=&quot;690&quot; filename=&quot;개돼지.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center;&quot;&gt;대중들이란? [from &lt;a href=&quot;http://www.pressm.kr/news/articleView.html?idxno=8001&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;프레스맨 카드뉴스&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이 글의 독자들은 부디 알아서 현명한 판단을 내리길 바란다.&lt;br /&gt;&lt;/p&gt;&lt;/p&gt;
&lt;button type=&quot;button&quot; class=&quot;btn_less&quot; id=&quot;less58_2&quot; data-id=&quot;58_2&quot;&gt;&lt;span class=&quot;txt_fold&quot;&gt;접기&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;알츠하이머 걸렸지만 골프 점수 계산 잘하시는 의학계의 빛&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_11&quot; id=&quot;footnote_link_58_11&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 11)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 11)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;11&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;처럼 주변사람 관리 잘해야 나쁜짓 해도 오래오래 가지.&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;주변 인들도 직접 경험 했을 때 나쁘지 않은 사람이었던 프로 계산러가 자신에게 훨씬 더 좋은 사람이고, 계산러보다 계산러 싫어하는 사람들한테 피해본게 많다 그래서 계산러는 딱히 싫지 않은데 계산러를 싫어하는사람이 더 싫은 거겠지.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h2&gt;5. 해주고 싶은 말&lt;/h2&gt;&lt;p class=&quot;&quot;&gt;도대체 어떤 짓을 했길래 7년동안이나 복수를 준비하는 몽테크리스토 백작을 만드냐? &lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;&quot;&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99271B3E5C4DCB2C2B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99271B3E5C4DCB2C2B&quot; width=&quot;800&quot; height=&quot;1844&quot; filename=&quot;고맙다.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이거 말고도 폐인처럼 됐다가 망했다는 소식을 듣고 그렇게 기뻐하는 걸 처음봤다는 반응도 있었어.(당사자가 아닌 지인이 몰래 올린 게시물이라 따로 박제하진 않았습니다)&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;어찌되었건 60만에서 떨어진것 축하.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 495px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C05B455C4768840A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C05B455C4768840A&quot; width=&quot;495&quot; height=&quot;270&quot; filename=&quot;결과.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;계정해지된 것도 축하.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990CD74F5C48731019&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990CD74F5C48731019&quot; width=&quot;700&quot; height=&quot;525&quot; filename=&quot;계정해지.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;얼마전까지 잘 놀았지만&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_12&quot; id=&quot;footnote_link_58_12&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 12)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 12)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;12&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991744425C49FA2E02&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991744425C49FA2E02&quot; width=&quot;400&quot; height=&quot;533&quot; filename=&quot;준1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9915CF3D5C49FA2E01&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9915CF3D5C49FA2E01&quot; width=&quot;400&quot; height=&quot;505&quot; filename=&quot;준2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A35C3B5C4DD14034&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A35C3B5C4DD14034&quot; width=&quot;400&quot; height=&quot;780&quot; filename=&quot;준5.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995FE5505C4DD1400D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995FE5505C4DD1400D&quot; width=&quot;400&quot; height=&quot;615&quot; filename=&quot;준6.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;앞으로 뒤돌아서는 사람이 더욱 많이 생길 예정이라는 거.&lt;/div&gt;&lt;div&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99EDA1405C49FA9302&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99EDA1405C49FA9302&quot; width=&quot;400&quot; height=&quot;257&quot; filename=&quot;준3.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9974F13A5C49FA9302&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9974F13A5C49FA9302&quot; width=&quot;400&quot; height=&quot;473&quot; filename=&quot;준4.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://blog.naver.com/asdfg3663/221448916750&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;고소미&lt;/a&gt;도 먹으면 좋구.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;수입 줄어들었을텐데 배고프잖아.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99185A4C5C48EA421A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99185A4C5C48EA421A&quot; width=&quot;800&quot; height=&quot;757&quot; filename=&quot;Screenshot_2019-01-24 이번 윾튜브 사건이 우리에게 주는 교훈 네이버 블로그.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그나마 좋은 소식이 하나 있다면,&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;공중파에도 진출하더라고.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;크~ 영향력 있어서 부럽다야.&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993108435C48EE221C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993108435C48EE221C&quot; width=&quot;400&quot; height=&quot;194&quot; filename=&quot;kbs.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99AC584F5C48EE221A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99AC584F5C48EE221A&quot; width=&quot;400&quot; height=&quot;224&quot; filename=&quot;sbs.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p class=&quot;&quot;&gt;이거이거 나중에 &quot;충격적 60만 유튜버의 실체&quot;로 해서 나오는거 아닐까 싶어.&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;사과영상 올렸던데,&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99AE394B5C48733515&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99AE394B5C48733515&quot; width=&quot;800&quot; height=&quot;2952&quot; filename=&quot;윾머사과요약떴다.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;킹니갓사의 황혼의 승리가 되길 바란다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 600px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993DEF355C48F6281E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993DEF355C48F6281E&quot; width=&quot;600&quot; height=&quot;371&quot; filename=&quot;애니3.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그 제가 이 글 부제는 원래 더 길었는데 짧게 줄였다고 했죠?&lt;/p&gt;
&lt;p&gt;원래 글 부제는&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;&lt;b&gt;'윾튜브 님 죄송합니다&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;라고 한 번 해보세요 그러면 혹시 또 누가 압니까?&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;제가 불쌍하다고 한번 봐줄지'&lt;/b&gt;&lt;/p&gt;&lt;/blockquote&gt;


&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 640px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99851A375C4768EA08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99851A375C4768EA08&quot; width=&quot;640&quot; height=&quot;360&quot; filename=&quot;조언.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C1D34F5C4768EC0A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C1D34F5C4768EC0A&quot; width=&quot;800&quot; height=&quot;416&quot; filename=&quot;반응.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;b&gt;한 줄 정리.&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;윾튜브는 소아성애+대구지하철, 세월호와 천안함등의 고인, 성폭력 피해자들을 모욕한 진성 일베.. 악마를 보았다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;P.S&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;내가 메갈쪽 세력이라 윾튜브를 음해하는거 아니냐 할 수 있다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;하지만 난 메갈계열은&lt;/p&gt;
&lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/181215022185&quot; data-did=&quot;7c6945f7e1876250138d06258cad8db390a480b6&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/181215022185/여성폭력방지법-왜-문제인가&quot; title=&quot;&quot; style=&quot;&quot;&gt;https://black7375.tumblr.com/post/181215022185/여성폭력방지법-왜-문제인가&lt;/a&gt;&lt;/div&gt;&lt;script async=&quot;&quot; src=&quot;https://assets.tumblr.com/post.js&quot;&gt;&lt;/script&gt;
&lt;p class=&quot;&quot;&gt;처럼 아주 긴 분석글을 썼을 정도로 싫어한다.&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_13&quot; id=&quot;footnote_link_58_13&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 13)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 13)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;13&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;일베가 극우라 싫어하는 것처럼 메갈도 극좌라 싫다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;사람들의 분노를 먹고사는 괴물들일 뿐.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이 쯤하면 나와야할 유명한 명문.&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p class=&quot;&quot;&gt;괴물과 싸우는 사람은 자신이 이 과정에서 괴물이 되지 않도록 조심해야 한다. 만일 네가 괴물의 심연을 오랫동안 들여다보고 있으면, 심연도 네 안으로 들어가 너를 들여다본다. &lt;br /&gt;&lt;/p&gt;&lt;footer&gt;Friedrich Wilhelm Nietzsche&lt;/footer&gt;&lt;/blockquote&gt;&lt;p class=&quot;&quot;&gt;윾튜브 본인이나 누군가가 내가 이 글을 썼다는 명목으로 비난, 고소&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_14&quot; id=&quot;footnote_link_58_14&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 14)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 14)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;14&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;하지 않는한 이 글을 마지막으로 윾튜브에 대한건 끝.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;손에 똥을 그만 묻히고 싶다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;가장 하고픈 말중에 하나.&lt;/p&gt;
&lt;p&gt;정치는 결국 명분싸움인데, 진성 일베인 윾튜브가 메갈을 비판하는 것은 보통사람들에게&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p class=&quot;&quot;&gt;일베라 메갈을 공격하네??&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;라는 생각을 심어줄 수 밖에 없다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;진영논리를 상당히 싫어하긴 하지만..&lt;br /&gt;관심이 적은 사람들은 그렇게 생각하고 오해할 수 밖에.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;진보가 되고 싶으면 메갈을, 보수가 되고 싶으면 일베에서 벗어나야 한다.&lt;/p&gt;
&lt;p&gt;아니, 사람이라면 둘다에서 벗어나야 한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;p class=&quot;&quot;&gt;영상컨텐츠는 별로 좋아하지 않지만 일부 사람들이 논점 흐리는 것을 보고 적는다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;b&gt;정상과 비정상.&lt;/b&gt;&lt;br /&gt;정상이라 하면 $(1+2)\times 3=9$, 비정상은 $(1+2)\times 3=3$이라 주장하는 거와 같다.&lt;/p&gt;
&lt;p&gt;위에서 계속 언급해온 윾이나 일베, 메갈, 나치등은 비정상에 속한다고 할 수 있다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;자신은 자유롭게 말하는 것 뿐이라지만 자신을 넘어서 타인의 자유를 심각하게 속박&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_15&quot; id=&quot;footnote_link_58_15&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 15)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 15)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;15&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;하면 올바른 것이 아니기 때문이다.&lt;/p&gt;
&lt;p&gt;올바르지 않은 것은 배제시키는 것이 맞다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;타인을 심각히 망가뜨리는 자유는 일부 속박하는 것이 맞다는 것을 의미한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;힘에는 책임이 따르는법.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이건 민심이니, 제 3자니 따질 문제가 전~~~혀 아니다. 나쁜 사람과 연을 끊겠다고 기회주의자니 뭐니가 절대 아니라는 뜻.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;많이 양보해서 혼자나 둘이서, 또는 한 가정에서만 세상을 살아가면 '일개 개인'의 선택이며 책임지는 것은 오롯이 당사자들에게만 있기 때문에 문제 될 것은 없다. 그러나 사회는 수많은 사람들과 같이 살아가는 것이므로 신경써야할 문제다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;b&gt;성향&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;정상이어야 답(올바름)이 나오고, 비로소 성향의 차이를 말해볼 수 있다.&lt;/p&gt;
&lt;p&gt;누구는 $(1+2)$를 먼저 계산할 수도 있고, 다른 누군가는 $1\times 3, 2\times 3$처럼 곱하기를 먼저 계산할 수도 있듯 말이다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;여기선 덧셈을 먼저 계산하면 2단계로 끝나서 효율적&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_58_16&quot; id=&quot;footnote_link_58_16&quot; onmouseover=&quot;tistoryFootnote.show(this, 58, 16)&quot; onmouseout=&quot;tistoryFootnote.hide(58, 16)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;16&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;이긴 하지만 곱셈을 먼저 계산했다고 틀린건 아니다.&lt;/p&gt;
&lt;p&gt;진보와 보수도 그렇다.&lt;/p&gt;
&lt;p&gt;그때 그때 효율적인 방식을 선택하는게 옳은 방향이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;b&gt;기계적 중립.&lt;/b&gt;&lt;br /&gt;그래서 내가 하고 싶은 말이 무엇인가?&lt;/p&gt;
&lt;p&gt;기계적 중립은 하지 말자는것.&lt;/p&gt;
&lt;p&gt;정상과 비정상의 경계를 모호하게 만들기 때문이다.&lt;/p&gt;
&lt;p&gt;이를테면 다음과 같다.&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;살인마에게도 인간답게 살아갈 권리가 있으니 감옥에 가면 안된다구욧!!! 감옥은 인간의 자유를 심각하게 훼손하는 장소입니다.&lt;br /&gt;지구 평평설, 창조론등의 가설도 틀리긴 했지만, 과학계에서 존중하여 학술적 교류를 해야 한다는 의견을 욕하는 것은 전체주의적 발상 이라구욧!!&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;윾튜브가 차마 입에 담기도 싫은 행위를 했지만, 손절하는 건 크리에이터님 마음이라구욧!!&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;가족이나 회사의 상사, 독재정권같이 필연적 관계 또는 억압적인 관계에서야 올바른 행동을 하기 힘들 수 있지만, 수평적 관계에서는 의지가 있다면 충분히 행할 수 있다. 특히 성인이 된 후에 알게 된 사람이라면.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;사실 공감능력이니 뭐니 따질 필요도 없는 명확한 문제다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;참고로, 뉴미디어는 컨텐츠 생산자와 소비자가 수직적인 관계가 아니라 수평적인 관계로 같이 컨텐츠를 만들어가는 거라고 생각한다.(후원이나 댓글이 하나의 컨텐츠가 되기도 하고.)&lt;/p&gt;
&lt;p&gt;예전의 TV처럼 일방통행의 컨텐츠 생산이라면 모를까 뉴미디어를 다루는 사람은 구독자는 동업자이기에 조금 더 신경쓰고 존중해야할 필요가 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이런 지적을 하는 것에 대해&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p class=&quot;&quot;&gt;니는 안그러냐, 너도 내로남불이네.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;를 시전할 만한 사람들도 있는데..&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;미리 답해두자면,&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;난 윾이나 그렇게 생각하는 사람처럼 안하니까 걱정마?^^&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;출처.&lt;/h4&gt;&lt;p class=&quot;&quot;&gt;자료가 너무 많아서 더보기 처리 합니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;단, 출처의 관리자가 삭제하여 상당수 사라진 점은 고려.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 732px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992B49435C4B452F08&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992B49435C4B452F08&quot; width=&quot;732&quot; height=&quot;678&quot; filename=&quot;삭제.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;button type=&quot;button&quot; class=&quot;btn_more&quot; id=&quot;more58_3&quot; data-id=&quot;58_3&quot;&gt;더보기&lt;/button&gt;&lt;div class=&quot;moreless_content&quot; id=&quot;content58_3&quot; style=&quot;display: none;&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;btn_less&quot; id=&quot;less58_3&quot; data-id=&quot;58_3&quot;&gt;&lt;span class=&quot;txt_fold&quot;&gt;접기&lt;/span&gt;&lt;/button&gt;
  &lt;p class=&quot;txt_view&quot;&gt;&lt;p class=&quot;&quot;&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=48651&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=50979&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=54622&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=55872&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=56659&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=57020&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=58074&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=60331&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=60335&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=60588&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=61192&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=61233&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=61279&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=62114&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=62118&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=62244&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=62267&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=62361&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=66813&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=66881&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=69703&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=73403&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=73466&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=73502&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=73754&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=73769&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=75430&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=78814&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=80906&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=82451&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=82473&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=82519&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=84972&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=86448&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=87669&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=93970&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=94713&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=98463&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=109472&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=117005&lt;br /&gt;http://gall.dcinside.com/mgallery/board/view/?id=youtube&amp;amp;no=117006&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;
http://gall.dcinside.com/board/view/?id=baseball_new7&amp;amp;no=12149074&lt;br /&gt;http://gall.dcinside.com/board/view/?id=baseball_new7&amp;amp;no=12169176&lt;br /&gt;http://gall.dcinside.com/board/view/?id=baseball_new7&amp;amp;no=12171583&lt;br /&gt;http://gall.dcinside.com/board/view/?id=baseball_new7&amp;amp;no=12171720&lt;br /&gt;http://gall.dcinside.com/board/view/?id=comic_new1&amp;amp;no=3771781&lt;br /&gt;https://orbi.kr/00020966546&lt;br /&gt;https://news.sbs.co.kr/news/endPage.do?news_id=N1004500503&lt;br /&gt;http://mlbpark.donga.com/mp/b.php?p=1&amp;amp;b=bullpen&amp;amp;id=201810300024864092&lt;br /&gt;http://mlbpark.donga.com/mp/b.php?m=search&amp;amp;p=91&amp;amp;b=bullpen&amp;amp;id=201901230027327755&lt;br /&gt;http://web.humoruniv.com/board/humor/read.html?table=pds&amp;amp;number=644539&lt;br /&gt;https://bbs.ruliweb.com/community/board/300143/read/40840258&lt;br /&gt;https://www.fmkorea.com/best/969873679&lt;br /&gt;https://www.fmkorea.com/best/973368128&lt;br /&gt;https://www.fmkorea.com/best/1552116534&lt;br /&gt;https://blog.naver.com/jw120799/221412658909&lt;br /&gt;https://masayu.me/29&lt;br /&gt;&lt;/p&gt;&lt;/p&gt;
&lt;button type=&quot;button&quot; class=&quot;btn_less&quot; id=&quot;less58_3&quot; data-id=&quot;58_3&quot;&gt;&lt;span class=&quot;txt_fold&quot;&gt;접기&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;댓글제보 내용도 추가합니다.&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol class=&quot;footnotes&quot;&gt;
    &lt;li id=&quot;footnote_58_1&quot;&gt;현재 사라짐.&lt;br&gt;이유는 출처 참고. &lt;a href=&quot;#footnote_link_58_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_2&quot;&gt;너무 길다 싶은 사람을 위해 1줄 요약도 준비!! &lt;a href=&quot;#footnote_link_58_2&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_3&quot;&gt;내용보니 '나의 투쟁'에서 따왔나 싶던? &lt;a href=&quot;#footnote_link_58_3&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_4&quot;&gt;제가 백업해놓은 영상입니다.&lt;br&gt;
로딩이 안된다면 광고차단 프로그램에서 imasdk.googleapis.com가 로드되도록 하세요. &lt;a href=&quot;#footnote_link_58_4&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_5&quot;&gt;아마 첫번째 영상에서 위로해주었다던 사람들 이것지? &lt;a href=&quot;#footnote_link_58_5&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_6&quot;&gt;통한의 &lt;a href=&quot;https://bbs.ruliweb.com/community/board/300143/read/40840258&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;쉴드&lt;/a&gt;와 합리화에 실패해서 구독자 수(돈)가 떨어지는 것을 보고 그러는거 겠지만 일단 해명 영상을 올렸다. &lt;br&gt;남탓하는 해명이라 마음에 쏙 들지 않지만 그 정도는 사람의 방어기제라 이해해준답치고, 댓글로라도 피드백을 열심히 하려는 모습을 보이는 분이라 그나마라도 긍정적으로 본다. 물론 손절한다는 이야기는 없다.&lt;br&gt;&lt;div class=&quot;tt-youtube-plugin&quot; style=&quot;text-align: center&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/lW4-BOtQs1M?rel=0&quot; width=&quot;560&quot; height=&quot;420&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt; &lt;a href=&quot;#footnote_link_58_6&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_7&quot;&gt;좀 찾아보니 JM은 독일에서도 살아서 이런 발언들을 어떻게 다루는지(ex 독일 형법 제130조) 알만할텐데? &lt;a href=&quot;#footnote_link_58_7&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_8&quot;&gt;사건 터지고 친히 대화해서 윾튜브가 '반성'하고 있다고 알려주는 것도 고맙곸ㅋㅋㅋㅋㅋㅋ &lt;a href=&quot;#footnote_link_58_8&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_9&quot;&gt;분명히 밝혀두자면 내가 작성한 글은 아님.&lt;br&gt;쭉 보면 알겠지만 내 스타일은 비꼬기는 하더라도 ~~슬람 같은 어휘는 사용하지 않는다.&lt;br&gt;기본적으로 세속주의(secularism)를 주장하는 사람이고, 개인적인 성향은 라이시스트(laïciste)이기 때문이다. &lt;a href=&quot;#footnote_link_58_9&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_10&quot;&gt;보면 알겠지만 일베성향이 짙기로 유명한 사람이다. &lt;a href=&quot;#footnote_link_58_10&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_11&quot;&gt;물론 정확히 누군였는지까지는 기억이 잘 나지 않는다. &lt;a href=&quot;#footnote_link_58_11&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_12&quot;&gt;굳이 같이 섞여노는 사람들을 열거하고 싶지 않으니 왠만한 사람들이 알만한 사람 한명만 나열한다. &lt;a href=&quot;#footnote_link_58_12&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_13&quot;&gt;링크로 들어가보면 알겠지만, 법 전문을 분석해놨다. &lt;a href=&quot;#footnote_link_58_13&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_14&quot;&gt;사실적시 명예훼손 이외에는 될거 없다고 봄 &lt;a href=&quot;#footnote_link_58_14&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_15&quot;&gt;범죄 같은것 &lt;a href=&quot;#footnote_link_58_15&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_58_16&quot;&gt;곱셈은 3단계 &lt;a href=&quot;#footnote_link_58_16&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description>
      <category>기타 정보</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/58</guid>
      <comments>https://black7375.tistory.com/58#entry58comment</comments>
      <pubDate>Wed, 23 Jan 2019 04:04:51 +0900</pubDate>
    </item>
    <item>
      <title>2분만에 Vim 에디터 모드의 이해.</title>
      <link>https://black7375.tistory.com/57</link>
      <description>&lt;p&gt;원래 텀블러에 올려야 할 글인데.. 사진이 10장을 넘는 바람에 티스토리에 올린다.&lt;/p&gt;&lt;h2&gt;1. 개요 및 개념.&lt;/h2&gt;&lt;p&gt;개발자들은 Vim 키맵을 사용하는 경우가 많다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;왜냐!!&lt;/p&gt;
&lt;p&gt;텍스트를 다루기 편하기 때문에.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;하지만 처음에 약간의 학습 곡선이 있다고, 포기하는 경우 또한 많다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;내가 생각할 때 포기하는 이유는 딱 두개.&lt;/p&gt;
&lt;p&gt;익숙치 않은 것, 일부 단축키 (Ctrl+c, Ctrl+v, Ctrl+z 등).&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;나
같은 경우 단축키는 설정을 통해 Ctrl+Shift+c, Ctrl+Shift+v, Ctrl+Shift+z로 쓰고 있다.(보통의 
터미널들도 Ctrl+Shift+c, Ctrl+Shift+v로 복붙을 지원하니 나름 일관성 있고 좋음)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그럼 익숙치 않은 것은 어떻게 하면 빨리 이해할 수 있을까?&lt;/p&gt;
&lt;p&gt;답은 터치스크린이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;Vim의 편집 방법은 터치스크린을 사용하는 것과 유사하다.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;2. 이해법.&lt;/h2&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9943664A5C2D3D6E17&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9943664A5C2D3D6E17&quot; width=&quot;800&quot; height=&quot;449&quot; filename=&quot;Vim-Mode.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Vim의 4개 모드[from &lt;a href=&quot;http://gracefulprograming.tistory.com/30&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;VIM 모드 이해&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Vim은 크게 일반, 입력, 비주얼, 명령행이란 4개의 모드를 갖는다.&lt;/p&gt;
&lt;p&gt;차례대로 비교해봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.1 일반(Normal) 모드.&lt;/h3&gt;&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;우선 일반 보드부터 알아봅시다.&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9997633F5C2D46381C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9997633F5C2D46381C&quot; width=&quot;400&quot; height=&quot;383&quot; filename=&quot;Vim-Normal.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px; width: 200px; height: 355px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9960A9475C2D462F1B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9960A9475C2D462F1B&quot; width=&quot;200&quot; height=&quot;355&quot; filename=&quot;Touch-Normal.PNG&quot; filemime=&quot;image/png&quot; style=&quot;width: 200px; height: 355px;&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;일반 모드는 커서 이동, 복사 및 붙여넣기, 삭제 같은 동작을 하는 모드다.&lt;/p&gt;
&lt;p&gt;스마트폰에서 커서 이동은 가능해도 붙여넣기 같은 건 어찌 가능하냐고?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;짜잔~&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px; width: 200px; height: 355px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998E65495C2D3D5819&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998E65495C2D3D5819&quot; width=&quot;200&quot; height=&quot;355&quot; filename=&quot;Touch-Noral2.PNG&quot; filemime=&quot;image/png&quot; style=&quot;width: 200px; height: 355px;&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px; width: 200px; height: 355px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99709E485C2D3D5818&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99709E485C2D3D5818&quot; width=&quot;200&quot; height=&quot;355&quot; filename=&quot;Touch-Normal3.PNG&quot; filemime=&quot;image/png&quot; style=&quot;width: 200px; height: 355px;&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;보다시피 이동 및 삭제가 가능하다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;한'문단'을 하나의 '객체'로 취급한다는 아이디어인데, Vim의 일반모드에서 yy(복사)나 dd(삭제)도 한'줄'을 하나의 '객체'로 취급한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.2 입력(Insert) 모드.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;입력 모드는 참 쉽다&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B721395C2D3D6E19&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B721395C2D3D6E19&quot; width=&quot;400&quot; height=&quot;383&quot; filename=&quot;Vim-Insert.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px; width: 200px; height: 355px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B295435C2D3D5817&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B295435C2D3D5817&quot; width=&quot;200&quot; height=&quot;355&quot; filename=&quot;Touch-Insert.PNG&quot; filemime=&quot;image/png&quot; style=&quot;width: 200px; height: 355px;&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그냥 키보드로 입력하는 것.&lt;/p&gt;
&lt;p&gt;일반적인 에디터나 워드프로세서는 입력모드가 기본이라 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.3 비주얼(Visual) 모드.&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;이번엔 비주얼 모드다.&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B779395C2D3D6F19&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B779395C2D3D6F19&quot; width=&quot;400&quot; height=&quot;383&quot; filename=&quot;Vim-Visual.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px; width: 200px; height: 355px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998F963C5C50AA160A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998F963C5C50AA160A&quot; width=&quot;200&quot; height=&quot;355&quot; filename=&quot;Touch-Visual.PNG&quot; filemime=&quot;image/png&quot; style=&quot;width: 200px; height: 355px;&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p class=&quot;&quot;&gt;비주얼 모드는 드래그로 선택한 것과 같은 효과다.&lt;/p&gt;
&lt;p&gt;블록된 곳은&amp;nbsp;복사, 잘라내기등의 동작을 실행할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.4 명령행(Command Line) 모드.&lt;/h3&gt;&lt;p&gt;마지막은 명령행 모드다.&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 355px; width: 355px; height: 340px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9977D3465C2D3D6E15&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9977D3465C2D3D6E15&quot; width=&quot;355&quot; height=&quot;340&quot; filename=&quot;Vim-Ex.png&quot; filemime=&quot;image/png&quot; style=&quot;width: 355px; height: 340px;&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99EEC8385C2D3D5719&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99EEC8385C2D3D5719&quot; width=&quot;200&quot; height=&quot;355&quot; filename=&quot;Touch-Ex.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9961EE475C2D3D5818&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9961EE475C2D3D5818&quot; width=&quot;200&quot; height=&quot;355&quot; filename=&quot;Touch-Ex2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;명령행 모드는 일종의 메뉴이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;터치스크린과 다른점은 메뉴의 수가 매우 많다는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;메뉴 답게 검색 같은 것도 수행할 수 있다.&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F049385C2D3D6E18&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F049385C2D3D6E18&quot; width=&quot;400&quot; height=&quot;383&quot; filename=&quot;Vim-Ex2.png&quot; filemime=&quot;image/png&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px; width: 200px; height: 355px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B68A395C2D3D5819&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B68A395C2D3D5819&quot; width=&quot;200&quot; height=&quot;355&quot; filename=&quot;Touch-Ex3.PNG&quot; filemime=&quot;image/png&quot; style=&quot;width: 200px; height: 355px;&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;+.&lt;/h3&gt;&lt;p&gt;왜 이런 결과를 불러오게 된 걸까?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;옛날 컴퓨터는 GUI 환경이 제공되지 않았으므로(마우스 사용 불가) '키보드만'을 사용해서 편집해야 했지만, 요즘 스마트폰 또한 버튼이 적어 '스크린만'을 이용해서 편집해야 하는 것에서 비슷해보이는 결과를 낳았다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;하나의 인터페이스 만을 사용해 많은 양의 도구를 다룰 때 모드의 변경을 통해 접근하는 방식은 최선이자 불가피한 방식이다.&lt;br /&gt;&lt;/p&gt;</description>
      <category>IT/UX</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/57</guid>
      <comments>https://black7375.tistory.com/57#entry57comment</comments>
      <pubDate>Thu, 3 Jan 2019 07:54:58 +0900</pubDate>
    </item>
    <item>
      <title>웹브라우저 확장기능 개발.</title>
      <link>https://black7375.tistory.com/56</link>
      <description>&lt;p&gt;요렇게 스토어 등록했습니다.&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_56_1&quot; id=&quot;footnote_link_56_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 56, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(56, 1)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;blockquote class=&quot;embedly-card&quot;&gt;&lt;h4&gt;&lt;a href=&quot;https://addons.mozilla.org/ko/firefox/addon/readable-font/&quot; class=&quot;&quot;&gt;Readable Font - Get this Extension for   Firefox (ko)&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Download Readable Font for Firefox. 가독성 좋은 글씨를 보여줍니다.&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote class=&quot;embedly-card&quot;&gt;&lt;h4&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/readable-font/ckgoimpkejadjkjfpemacjpeimdgmdpk?hl=ko&quot;&gt;Readable Font&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;가독성 좋은 글씨를 보여줍니다.&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote class=&quot;embedly-card&quot;&gt;&lt;h4&gt;&lt;a href=&quot;https://store.whale.naver.com/detail/ckhloeobmonbhapgmfcbobacadkjckbi&quot;&gt;Readable Font - 웨일 스토어&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;가독성 좋은 글씨를 보여줍니다.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class=&quot;&quot;&gt;웹브라우저 폰트 관련 확장기능을 만들었는데, 그 과정을 공유해서 아이디어는 있는데 개발을 어떻게 해야할지 우왕좌왕 싶은 분들에게 일종의 가이드(?)를 해주려 합니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;* 확장기능은 부기기능, 확장앱, Addon, Extension 등으로도 부릅니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;처음 만들어봤는데 생각보다 쉬워요^^&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_56_2&quot; id=&quot;footnote_link_56_2&quot; onmouseover=&quot;tistoryFootnote.show(this, 56, 2)&quot; onmouseout=&quot;tistoryFootnote.hide(56, 2)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;2&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;단, 제가 하는 강좌는 HTML, CSS, Javascript 강좌가 아니고 저도 막 익숙하다고 말하기가 그래서.. 해당 내용에 대한 설명은 넘어가는걸루.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;전체 코드가 담긴 깃허브를 참고하면서 보세요.&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;embedly-card&quot;&gt;&lt;h4&gt;&lt;a href=&quot;https://github.com/black7375/Readable_Font&quot;&gt;black7375/Readable_Font&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;View Pretty Font on Web Browser!! Contribute to black7375/Readable_Font development by creating an account on GitHub.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;참고로 이 글에서 보여주는 코드는 릴리즈 1.1.0 기준입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;code&gt;src/Readable Font/&lt;/code&gt;를 참고.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 참고 할 만한 문서 및 예제.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;문서: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;MDN&lt;/a&gt;, &lt;a href=&quot;https://developer.chrome.com/home&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Chrome,&lt;/a&gt; &lt;a href=&quot;https://dev.opera.com/extensions/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Opera&lt;/a&gt;, &lt;a href=&quot;https://developers.whale.naver.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Whale&lt;/a&gt;(한글), &lt;a href=&quot;https://docs.microsoft.com/en-us/microsoft-edge/extensions/guides/creating-an-extension&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Edge&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;예제: &lt;a href=&quot;https://github.com/mdn/webextensions-examples&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;파이어폭스&lt;/a&gt;, &lt;a href=&quot;https://github.com/orbitbot/chrome-extensions-examples&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;크롬&lt;/a&gt;, &lt;a href=&quot;https://dev.opera.com/extensions/extension-samples/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Opera&lt;/a&gt;, &lt;a href=&quot;https://github.com/MicrosoftEdge/MicrosoftEdge-Extensions-Demos&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Edge&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;0. 아이디어.&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;무언가를 만들려면 아이디어와 목표, 기획이 있어야겠죠?&lt;/p&gt;
&lt;p&gt;저희의 목표는 요렇게 만드는 것입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994E15425C2914F609&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994E15425C2914F609&quot; width=&quot;800&quot; height=&quot;1400&quot; filename=&quot;ReadableFont.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;제가 만든 블로그 스킨(&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR', serif;&quot; class=&quot;&quot;&gt;Letter - Enhanced&lt;/span&gt;&lt;/b&gt;)과 디자인이 유사합니다.ㅎ&lt;/p&gt;
&lt;p&gt;블로그 스킨에 들어가는 기능과 부가기능에 들어가는 기능은 서로 영향을 주고 받으며 클거에요.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;들어가는 기능들을 살펴보자면&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9933964E5C291E280B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9933964E5C291E280B&quot; width=&quot;800&quot; height=&quot;500&quot; filename=&quot;setting.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992CD93D5C291E280E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992CD93D5C291E280E&quot; width=&quot;800&quot; height=&quot;500&quot; filename=&quot;sharpen.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997952375C291E280D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997952375C291E280D&quot; width=&quot;800&quot; height=&quot;500&quot; filename=&quot;better.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F9F5345C291E280D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F9F5345C291E280D&quot; width=&quot;800&quot; height=&quot;500&quot; filename=&quot;MathML.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1. 디자인 구현하기.&lt;/h2&gt;&lt;p&gt;제 성격 탓인지, 일단 눈에 보이는 것을 어느 정도 만들어놓고, 기능을 추가해야&amp;nbsp; 속이 편하더군요.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;무언가를 했다는 성취감이 그나마 듭니다. ㅋㅋ&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우선 토글 버튼부터 만들어봅시다.&lt;/p&gt;
&lt;p&gt;토글 버튼의 정체가 과연 뭘까요?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;바로 체크박스 입니다.&lt;/p&gt;
&lt;p&gt;체크를 했다(ON), 풀었다(OFF) 상태를 오가죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우선 팝업을 만들테니, popup.html을 생성해봅시다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;popup.html&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt; !doctype html&amp;gt; &lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;  &amp;lt;title&amp;gt;Toogle Design&amp;lt;/title&amp;gt;&lt;br /&gt;  &amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;&lt;br /&gt;  &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;./toggle.css&quot; type=&quot;text/css&quot; /&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;  &amp;lt;h1&amp;gt;Toogle Design&amp;lt;/h1&amp;gt;&lt;br /&gt;  &amp;lt;div class=&quot;toggle&quot;&amp;gt;&lt;br /&gt;    &amp;lt;h2&amp;gt;설정내용.&lt;br /&gt;      &amp;lt;input type=&quot;checkbox&quot; class=&quot;toggle_checkbox&quot;&amp;gt;&amp;lt;/h2&amp;gt;&lt;br /&gt;  &amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;웹브라우저로 켜서 확인해보면 황량하기 그지 없습니다 ㅠㅠㅠ&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;무슨 오류인지는 모르겠는데 첫줄에 &amp;lt;표시 후에 바로 문자가 있으면 빈줄로 표시되네요.&lt;/p&gt;
&lt;p&gt;그래서 한칸씩 띕니다.&lt;br /&gt;&lt;/p&gt;&lt;style type=&quot;text/css&quot; media=&quot;print&quot;&gt;#s3gt_translate_tooltip_mini { display: none !important; }&lt;/style&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 357px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A41B3F5C291F710C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A41B3F5C291F710C&quot; width=&quot;357&quot; height=&quot;201&quot; filename=&quot;Toogle Design1.png&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;span class=&quot;cap1&quot; style=&quot;display: block; max-width:100%; &quot;&gt;이걸로 뭐하라고..&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이때 필요한 것이 바로바로 CSS입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;CSS를 적용해서 꾸며야 하는데, 체크박스를 바로 꾸밀 수 있는가?&lt;/p&gt;
&lt;p&gt;아닙니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그래서 저희는 &lt;code&gt;label&lt;/code&gt;을 통해 우회적으로 돌아갑니다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;&amp;lt; body&amp;gt;
&amp;lt;h1&amp;gt;Toogle Design&amp;lt;/h1&amp;gt;&lt;br /&gt;  &amp;lt;div class=&quot;toggle&quot;&amp;gt;&lt;br /&gt;    &amp;lt;h2&amp;gt;설정내용.&lt;br /&gt;      &amp;lt;input type=&quot;checkbox&quot; id=&quot;setting&quot; class=&quot;toggle_checkbox&quot;&amp;gt;&lt;br /&gt;      &amp;lt;label class=&quot;toggle_btn&quot; for=&quot;setting&quot;&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/h2&amp;gt;&lt;br /&gt;  &amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;for&lt;/code&gt;을 통해 체크박스의 &lt;code&gt;id&lt;/code&gt;를 공유함으로서 라벨을 누르면 체크박스를 누르는 것과 같은 효과가 생깁니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그 후, CSS를 적용해봅니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;toggle.css&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* =====================================================&lt;br /&gt; Toggle Button's CSS&lt;br /&gt; ===================================================== */&lt;br /&gt;*,&lt;br /&gt;*::before,&lt;br /&gt;*::after&lt;br /&gt;{&lt;br /&gt;  box-sizing: border-box;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.toggle&lt;br /&gt;{&lt;br /&gt;  display:     block;&lt;br /&gt;  margin-top:  40px;&lt;br /&gt;  user-select: none;&lt;br /&gt;  position:    relative;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.toggle_checkbox&lt;br /&gt;{&lt;br /&gt;  display: none;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.toggle_btn&lt;br /&gt;{&lt;br /&gt;  display:          inline-block;&lt;br /&gt;  float:            right;&lt;br /&gt;  font-size:        1.4em;&lt;br /&gt;  transition:       all 350ms ease-in;&lt;br /&gt;  position:         relative;&lt;br /&gt;  height:           35px;&lt;br /&gt;  width:            60px;&lt;br /&gt;  border-radius:    70px;&lt;br /&gt;  background-color: #e25d5d;&lt;br /&gt;  border:           5px solid #ad1000;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.toggle_btn:hover&lt;br /&gt;{&lt;br /&gt;  cursor: pointer;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.toggle_btn,&lt;br /&gt;.toggle_checkbox,&lt;br /&gt;.toggle_feature,&lt;br /&gt;.toggle_btn:before,&lt;br /&gt;.toggle_checkbox:before,&lt;br /&gt;.toggle_feature:before,&lt;br /&gt;.toggle_btn:after,&lt;br /&gt;.toggle_checkbox:after,&lt;br /&gt;.toggle_feature:after&lt;br /&gt;{&lt;br /&gt;  transition: all 250ms ease-in;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.toggle_btn:before,&lt;br /&gt;.toggle_checkbox:before,&lt;br /&gt;.toggle_feature:before,&lt;br /&gt;.toggle_btn:after,&lt;br /&gt;.toggle_checkbox:after,&lt;br /&gt;.toggle_feature:after&lt;br /&gt;{&lt;br /&gt;  content: '';&lt;br /&gt;  display: block;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.toggle_btn:before&lt;br /&gt;{&lt;br /&gt;  position:         absolute;&lt;br /&gt;  width:            25px;&lt;br /&gt;  height:           25px;&lt;br /&gt;  border-radius:    50%;&lt;br /&gt;  background-color: #f2dd68;&lt;br /&gt;  border:           5px solid #e5ce5e;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.toggle_checkbox:checked+.toggle_btn&lt;br /&gt;{&lt;br /&gt;  border: 5px solid #0865b0;&lt;br /&gt;  background-color: #3498db;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.toggle_checkbox:checked+.toggle_btn:before&lt;br /&gt;{&lt;br /&gt;  transform: translate(25px, 0);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;엄청 간단하게 설명하자면,&lt;/p&gt;
&lt;p&gt;체크박스는 안보이게 숨겨놓고, 빨간 배경에 노란 원을 띄우다가 라벨을 눌러 체크박스가 체크된 상태라면 배경은 파란색으로 바뀌고 노란 원은 오른쪽으로 25px만큼 움직이라는 뜻입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990427435C292E9C11&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990427435C292E9C11&quot; width=&quot;800&quot; height=&quot;160&quot; filename=&quot;Toogle Design2.jpg&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;휴.. 이제 마음의 안정이 찾아왔습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;본격적으로 개발에 들어가보도록 하죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 class=&quot;&quot;&gt;2. 매니페스트(Manifest) 작성.&lt;br /&gt;&lt;/h2&gt;&lt;p class=&quot;&quot;&gt;매니페스트는 확장기능의 이름, 버전, 아이콘 등의 메타 데이터,&amp;nbsp; 동작을 위한 설정, 권한등을 적어놓는 JSON파일입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;주요 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;manifest.json&lt;/a&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_56_3&quot; id=&quot;footnote_link_56_3&quot; onmouseover=&quot;tistoryFootnote.show(this, 56, 3)&quot; onmouseout=&quot;tistoryFootnote.hide(56, 3)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;3&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt; 구조는 다음과 같습니다.(모든 것을 살펴보려면 링크로)&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code class=&quot;json&quot;&gt;{&lt;br /&gt;  //==========설명==========&lt;br /&gt;  //필수&lt;br /&gt;  &quot;name&quot;: &quot;확장기능 이름&quot;,&lt;br /&gt;  &quot;version&quot;: &quot;버전&quot;,&lt;br /&gt;  &quot;manifest_version&quot;: 2,&lt;br /&gt;&lt;br /&gt;  //기타설명&lt;br /&gt;  &quot;description&quot;: &quot;확장기능 설명&quot;,&lt;br /&gt;  &quot;icons&quot;: {&lt;br /&gt;    &quot;16&quot;:  &quot;아이콘1&quot;,&lt;br /&gt;    &quot;48&quot;:  &quot;아이콘2&quot;,&lt;br /&gt;    &quot;128&quot;: &quot;아이콘3&quot;&lt;br /&gt;  },&lt;br /&gt;  &quot;homepage_url&quot;: &quot;https://example.org/my-addon&quot;,&lt;br /&gt;&lt;br /&gt;  //==========기능==========&lt;br /&gt;  //주요기능&lt;br /&gt;  &quot;browser_action&quot;: {&lt;br /&gt;    &quot;default_title&quot;: &quot;제목&quot;,&lt;br /&gt;    &quot;default_popup&quot;: &quot;팝업.html&quot;,&lt;br /&gt;    &quot;default_icon&quot;:  &quot;아이콘&quot;&lt;br /&gt;  },&lt;br /&gt; &lt;br /&gt;  &quot;page_action&quot;: {&lt;br /&gt;    &quot;default_title&quot;: &quot;제목&quot;,&lt;br /&gt;    &quot;default_icon&quot;:  &quot;아이콘&quot;,&lt;br /&gt;    &quot;default_popup&quot;: &quot;팝업.html&quot;,&lt;br /&gt;    &quot;browser_style&quot;: true&lt;br /&gt;  },&lt;br /&gt;&lt;br /&gt;  &quot;sidebar_action&quot;: {&lt;br /&gt;    &quot;default_title&quot;: &quot;제목&quot;,&lt;br /&gt;    &quot;default_icon&quot;:  &quot;아이콘&quot;,&lt;br /&gt;    &quot;default_panel&quot;: &quot;사이드바.html&quot;,&lt;br /&gt;    &quot;open_at_install&quot;:true&lt;br /&gt;  },&lt;br /&gt;&lt;br /&gt;  //선택기능&lt;br /&gt;  &quot;background&quot;: {&lt;br /&gt;    //둘중 하나&lt;br /&gt;    &quot;scripts&quot;: [&quot;스크립트1.js&quot;, &quot;스크립트2.js&quot;, ...],&lt;br /&gt;    &quot;page&quot;: &quot;페이지.html&quot;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  &quot;content_scripts&quot;: [{&lt;br /&gt;    &quot;matches&quot;: [&quot;*://*.mozilla.org/*&quot;, ...],&lt;br /&gt;    &quot;css&quot;: [&quot;컨텐츠1.css&quot;, &quot;컨텐츠2.css&quot;, ...],&lt;br /&gt;    &quot;js&quot;: [&quot;컨텐츠1.js&quot;, &quot;컨텐츠2.js&quot;, ...],&lt;br /&gt;    &quot;run_at&quot;: &quot;실행시점 - 아래서 설명&quot;&lt;br /&gt;  }],&lt;br /&gt;&lt;br /&gt;  &quot;options_ui&quot;: {&lt;br /&gt;    &quot;page&quot;: &quot;옵션.html&quot;&lt;br /&gt;  },&lt;br /&gt;&lt;br /&gt;  //==========권한==========&lt;br /&gt;  &quot;permissions&quot;: [&lt;br /&gt;    &quot;storage&quot;,&lt;br /&gt;    &quot;*://developer.mozilla.org/*&quot;&lt;br /&gt;  ],&lt;br /&gt;&lt;br /&gt;  &quot;web_accessible_resources&quot;: [&quot;리소스1&quot;, &quot;리소스2&quot;, ...]&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;원래 json 파일엔 주석표시(&lt;code&gt;//&lt;/code&gt;)는 없어야 정상이지만.. 설명하려는 거니까 .&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.1 설명.&lt;/h3&gt;&lt;p&gt;필수적으로 필요한 것은 확장기능의 이름, 버전, 매니페스트 버전입니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;매니페스트 버전은 그냥 &lt;code&gt;2&lt;/code&gt;고정으로 사용하면 됩니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아이콘은 대부분 16x16, 48x48, 128x128 3개를 사용하는데, 32x32, 64x64를 사용하는 경우도 있습니다. 알아서 만드세요 ㅋㅋ&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;전 이렇게 만들었습니다.(16x16, 32x32, 128x128)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 16px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993B45335C2A912E13&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993B45335C2A912E13&quot; width=&quot;16&quot; height=&quot;16&quot; filename=&quot;icon@16.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 32px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994D71485C2A912E16&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994D71485C2A912E16&quot; width=&quot;32&quot; height=&quot;32&quot; filename=&quot;icon@32.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 128px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99506B375C2A912E12&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99506B375C2A912E12&quot; width=&quot;128&quot; height=&quot;128&quot; filename=&quot;icon@128.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.2 기능.&lt;/h3&gt;&lt;h4&gt;2.2.1 주요기능.&lt;br /&gt;&lt;/h4&gt;&lt;p class=&quot;&quot;&gt;주요기능은 &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_action&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;browser_action&lt;/a&gt;&lt;/code&gt;, &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/page_action&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;page_action&lt;/a&gt;&lt;/code&gt;, &lt;code class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/sidebar_action&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;sidebar_action&lt;/a&gt;&lt;/code&gt;으로 나뉘어져 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;브라우저 액션은 툴바에. &lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999EBE3F5C2945DE1A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999EBE3F5C2945DE1A&quot; width=&quot;700&quot; height=&quot;364&quot; filename=&quot;browser-action.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Browser Action[from&amp;nbsp; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;User interface&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;페이지 액션은 주소창에.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99AC8A3C5C2947331B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99AC8A3C5C2947331B&quot; width=&quot;700&quot; height=&quot;348&quot; filename=&quot;address_bar_button.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Page Action[from&amp;nbsp; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;User interface&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;사이드바 액션은 사이드바로.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 700px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A0163F5C29475E1B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A0163F5C29475E1B&quot; width=&quot;700&quot; height=&quot;846&quot; filename=&quot;bookmarks-sidebar.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; class=&quot;&quot;&gt;Sidebar Action[from&amp;nbsp; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;User interface&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;아! &lt;code&gt;default_popup&lt;/code&gt;대신 버튼처럼 사용해도 되는거 아시죠?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.2.2 선택기능.&lt;/h4&gt;&lt;div class=&quot;&quot;&gt;&lt;b&gt;- Background&lt;/b&gt;&lt;br /&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;&lt;code class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/background&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;background&lt;/a&gt;&lt;/code&gt;는 특정한 페이지(탭)이나 윈도우(창)에 묶이지 않는 백그라운드 프로세스를 생성하는 것으로 창과 독립적으로 장기적인 작업을 할 때 어울리는 기능입니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;scripts&lt;/code&gt; 또는 &lt;code&gt;page&lt;/code&gt; 중 하나를 선택해야 하는데 &lt;code&gt;page&lt;/code&gt;의 경우 ES6를 지원한다는 장점이 있다.&lt;/p&gt;
&lt;p&gt;* 모든 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Web Extension API&lt;/a&gt;를 사용할 수 있음.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;-&amp;nbsp;Content Scripts&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt; &lt;code class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;content_scripts&lt;/a&gt;&lt;/code&gt;는 웹페이지에 주입하기 위한 기능입니다.&lt;/p&gt;
&lt;p&gt;DOM 조작이 가능하지만, 삽입된 웹 페이지 내에 정의된 JS 변수, 함수에 접근할 수 없고 API에는 제한이 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;사용가능한 API 목록.&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/i18n&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;i18n.*&lt;/a&gt; (모두)&lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;storage.*&lt;/a&gt; (모두)&lt;/li&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;runtime&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/id&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;runtime.id&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/lastError&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;runtime.lastError&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/connect&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;runtime.connect()&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getURL&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;runtime.getURL()&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getManifest&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;runtime.getManifest()&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;runtime.sendMessage()&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onConnect&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;runtime.onConnect&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;runtime.onMessage&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extension&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;extension&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extension/getURL&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;extension.getURL()&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extension/inIncognitoContext&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;extension.inIncognitoContext&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus/getTargetElement&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;menus.getTargetElement()&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot;&gt;접근할 수 없는 API에는 &lt;code&gt;background&lt;/code&gt;와의 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#Communicating_with_background_scripts&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;메세지교환&lt;/a&gt;을 통해 우회적으로 접근할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;code class=&quot;&quot;&gt;matches&lt;/code&gt;는 말 그대로 적용될 사이트나 대상을 선택하는 것으로 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/match_patterns&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Match patterns in extension manifests&lt;/a&gt;를 참고하세요.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;드디어 &lt;code&gt;run_at&lt;/code&gt;을 설명할 때가 됐네요.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이 옵션은 &lt;code&gt;js&lt;/code&gt;에 지정된 스크립트가 주입되는 시기를 결정합니다.&lt;br /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&quot;document_start&quot;: 로딩될 때. DOM이 아직 로드 중입니다.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&quot;document_end&quot;:&amp;nbsp; DOM 로드 후. DOM 로드가 완료되었지만 스크립트나 이미지와 같은 리소스가 로드 중 일 수 있습니다.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&quot;document_idle&quot;: 완료 될 때. 웹문서 및 모든 리소스의 로드가 완료 시.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b class=&quot;&quot;&gt;-&amp;nbsp;Options UI&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;code class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/options_ui&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;options_ui&lt;/a&gt;&lt;/code&gt;는 말 그대로 설정 UI를 만드는 것 입니다. &lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994A0C485C2A5B7B05&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994A0C485C2A5B7B05&quot; width=&quot;800&quot; height=&quot;452&quot; filename=&quot;options_page.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; class=&quot;&quot;&gt;&lt;br /&gt;Options UI[from&amp;nbsp; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;User interface&lt;/a&gt;]&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/options_page#Browser_compatibility&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;options_page&lt;/a&gt;&lt;/code&gt;라고 &lt;br /&gt;&lt;/p&gt;&lt;pre class=&quot;&quot;&gt;&lt;code class=&quot;json&quot;&gt;&quot;options_page&quot;: &quot;옵션.html&quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;옵션 페이지를 만드는 것도 있는데,&amp;nbsp; Deprecated(더 이상 사용되지 않는) 상태이므로 사용하지 맙시다. 무엇보다 파이어폭스에서 지원을 안 하며 크롬 계열에선 옵션 창이 새 탭에서 뜬다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.3 권한.&lt;/h3&gt;&lt;p&gt;&lt;b&gt;- Permission&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Permission&lt;/a&gt;의 종류는 크게 두가지로 나뉘어진다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;아까 나왔던 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/match_patterns&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;매치 패턴&lt;/a&gt;과 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions#API_permissions&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;브라우저 &lt;/a&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions#API_permissions&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;API&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- Web Accessible Resources&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/web_accessible_resources&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Web Accessible Resources&lt;/a&gt;는 웹페이지에서 접근하여 사용하려는 리소스를 등록하는 용도입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.4 정리.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;그림으로 보면 깔-끔.&lt;/p&gt;
&lt;p&gt;정리하고 갑시다.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B023465C293E7218&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B023465C293E7218&quot; width=&quot;800&quot; height=&quot;800&quot; filename=&quot;webextension-anatomy.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;그림으로 보는 파일구조[from &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Anatomy of an Extention&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.5 제 매니페스트.&lt;/h3&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot; class=&quot;&quot;&gt;&lt;b&gt;manifest.json&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;Readable Font&quot;,
  &quot;version&quot;: &quot;1.1.0&quot;,
  &quot;manifest_version&quot;: 2,

  &quot;description&quot;: &quot;가독성 좋은 글씨를 보여줍니다.&quot;,
  &quot;icons&quot;: {
    &quot;16&quot;:  &quot;icon@16.png&quot;,
    &quot;32&quot;:  &quot;icon@32.png&quot;,
    &quot;128&quot;: &quot;icon@128.png&quot;
  },

  &quot;browser_action&quot;: {
    &quot;default_title&quot;: &quot;Readable Font&quot;,
    &quot;default_popup&quot;: &quot;popup/popup.html&quot;,
    &quot;default_icon&quot;:  &quot;icon@16.png&quot;
  },

  &quot;content_scripts&quot;: [{
    &quot;all_frames&quot;: true,
    &quot;match_about_blank&quot;: true,
    &quot;matches&quot;: [&quot;&amp;lt; all_urls&amp;gt;&quot;],
    &quot;run_at&quot;: &quot;document_start&quot;,
    &quot;js&quot;: [&quot;contents/content.js&quot;]
  }],

  &quot;permissions&quot;: [
    &quot;storage&quot;,
    &quot;&amp;lt; all_urls&amp;gt;&quot;
  ],

  &quot;web_accessible_resources&quot;: [&quot;contents/*.css&quot;, &quot;contents/*.woff2&quot;],

  &quot;options_ui&quot;: {
    &quot;page&quot;: &quot;options/options.html&quot;
  }
}&lt;code&gt;&lt;/code&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;&quot;&gt;역시 하이라이터 오류로 all부분의 앞에 스페이스 처리했으니 이해해주세요.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;3. 추가 디자인 구현 및 디버깅.&lt;/h2&gt;&lt;h4&gt;&lt;b&gt;3.1 디자인 구현.&lt;/b&gt;&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;html과 css를 사용하여 popup과 option 화면을 만들었습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;팝업화면.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994AB2375C2A925713&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994AB2375C2A925713&quot; width=&quot;800&quot; height=&quot;449&quot; filename=&quot;popup1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;popup.html&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt; !doctype html&amp;gt;
&amp;lt;html&amp;gt;

&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Readable Font&amp;lt;/title&amp;gt;
&amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;../contents/substitue.css&quot; type=&quot;text/css&quot; media=&quot;screen&quot; /&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;./popup.css&quot; type=&quot;text/css&quot; /&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;../lib/toggle.css&quot; type=&quot;text/css&quot; /&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body id=&quot;mainPopup&quot;&amp;gt;
&amp;lt;div id=&quot;title&quot;&amp;gt;Readable Font&amp;lt;/div&amp;gt;
&amp;lt;div class=&quot;toggle&quot;&amp;gt;
  &amp;lt;h2&amp;gt;선명하게
    &amp;lt;input type=&quot;checkbox&quot; id=&quot;font_sharpen&quot; class=&quot;toggle_checkbox&quot;&amp;gt;
    &amp;lt;label class=&quot;toggle_btn&quot; for=&quot;font_sharpen&quot;&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/h2&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&quot;toggle&quot;&amp;gt;
  &amp;lt;h2&amp;gt;글꼴치환
    &amp;lt;input type=&quot;checkbox&quot; id=&quot;font_substitue&quot; class=&quot;toggle_checkbox&quot;&amp;gt;
    &amp;lt;label class=&quot;toggle_btn&quot; for=&quot;font_substitue&quot;&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/h2&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&quot;toggle&quot;&amp;gt;
  &amp;lt;h2&amp;gt;수식표현
    &amp;lt;input type=&quot;checkbox&quot; id=&quot;font_math&quot; class=&quot;toggle_checkbox&quot;&amp;gt;
    &amp;lt;label class=&quot;toggle_btn&quot; for=&quot;font_math&quot;&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/h2&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;script type=&quot;text/javascript&quot; src=&quot;./popup.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script type=&quot;text/javascript&quot; src=&quot;../lib/checkbox.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&gt;&lt;b&gt;popup.css&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;css&quot;&gt;#mainPopup
{
  padding:    10px;
  height:     200px;
  width:      250px;
  overflow-y: scroll;
  overflow-x: hidden;
}

#title
{
  text-align:  center;
  font-size:   23px;
  font-weight: 900;
  font-family: &quot;Noto Serif&quot;, serif;
}

h2
{
  font-size:   24px;
  font-weight: 900;
  font-family: &quot;Noto Sans&quot;, sans-serif;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;옵션화면.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B8214E5C2A92C118&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B8214E5C2A92C118&quot; width=&quot;800&quot; height=&quot;449&quot; filename=&quot;option1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;options.html&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt; !doctype html&amp;gt;
&amp;lt;html&amp;gt;

&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Readable Font&amp;lt;/title&amp;gt;
&amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;../contents/substitue.css&quot; type=&quot;text/css&quot; media=&quot;screen&quot; /&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;./options.css&quot; type=&quot;text/css&quot; /&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;../lib/toggle.css&quot; type=&quot;text/css&quot; /&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
&amp;lt;div id=&quot;title&quot;&amp;gt;Readable Font&amp;lt;/div&amp;gt;

&amp;lt;h1&amp;gt;선명하게&amp;lt;/h1&amp;gt;
&amp;lt;div class=&quot;toggle&quot;&amp;gt;
  &amp;lt;h2&amp;gt;저해상도 기기 최적화
    &amp;lt;input type=&quot;checkbox&quot; id=&quot;font_subpixel&quot; class=&quot;toggle_checkbox&quot;&amp;gt;
    &amp;lt;label class=&quot;toggle_btn&quot; for=&quot;font_subpixel&quot;&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/h2&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;p&amp;gt;선명하게 기술에서 쓰이는 안티얼라이싱은 저해상도 기기에서 흐릿하게 보일 수도 있습니다.&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;저해상도 기기 최적화 옵션을 활성화하면 서브픽셀 렌더링을 사용합니다.&amp;lt;/p&amp;gt;
  &amp;lt;div class=&quot;toggle&quot;&amp;gt;
  &amp;lt;h2&amp;gt;가독성 향상
    &amp;lt;input type=&quot;checkbox&quot; id=&quot;font_legibility&quot; class=&quot;toggle_checkbox&quot;&amp;gt;
    &amp;lt;label class=&quot;toggle_btn&quot; for=&quot;font_legibility&quot;&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/h2&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;p&amp;gt;글씨의 합자(ligatures)와 간격조정(kerning) 기능을 활성화 시켜 가독성을 개선합니다.&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;글꼴의 렌더링 옵션을 수정하는 것이므로 글씨의 간격이 일부 변형될 수 도 있습니다.&amp;lt;/p&amp;gt;
  &amp;lt;br&amp;gt;
  &amp;lt;h1&amp;gt;글꼴치환&amp;lt;/h1&amp;gt;
  &amp;lt;div class=&quot;toggle&quot;&amp;gt;
  &amp;lt;h2&amp;gt;향상된 글꼴
    &amp;lt;input type=&quot;checkbox&quot; id=&quot;font_better&quot; class=&quot;toggle_checkbox&quot;&amp;gt;
    &amp;lt;label class=&quot;toggle_btn&quot; for=&quot;font_better&quot;&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/h2&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;p&amp;gt;못생긴 글꼴을 비슷한 느낌이지만, 더 나은 글꼴로 대체합니다.&amp;lt;/p&amp;gt;
  &amp;lt;div class=&quot;toggle&quot;&amp;gt;
  &amp;lt;h2&amp;gt;비슷한 글꼴
    &amp;lt;input type=&quot;checkbox&quot; id=&quot;font_alter&quot; class=&quot;toggle_checkbox&quot;&amp;gt;
    &amp;lt;label class=&quot;toggle_btn&quot; for=&quot;font_alter&quot;&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/h2&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;p&amp;gt;화면에 표시 될 글꼴이 없을 경우, 유사한 글꼴을 보여줍니다.&amp;lt;/p&amp;gt;
    &amp;lt;br&amp;gt;
    &amp;lt;h1&amp;gt;수식표현&amp;lt;/h1&amp;gt;
    &amp;lt;div class=&quot;toggle&quot;&amp;gt;
      &amp;lt;h2&amp;gt;MathJax
        &amp;lt;input type=&quot;checkbox&quot; id=&quot;font_mathjax&quot; class=&quot;toggle_checkbox&quot;&amp;gt;
        &amp;lt;label class=&quot;toggle_btn&quot; for=&quot;font_mathjax&quot;&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;/h2&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;p&amp;gt;MathML(수식 표현 체계중 하나)를 크롬계열 브라우저에서는 지원하지 않습니다.&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;MathML이 포함된 문서가 있으면 MathJax를 로드하여 보여줍니다.&amp;lt;/p&amp;gt;
      &amp;lt;br&amp;gt;
      &amp;lt;h1&amp;gt;License&amp;lt;/h1&amp;gt;
      &amp;lt;h2 id=&quot;readable&quot;&amp;gt;Readable Font&amp;lt;/h2&amp;gt;
      ...이하생략
      &amp;lt;script type=&quot;text/javascript&quot; src=&quot;./options.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
      &amp;lt;script type=&quot;text/javascript&quot; src=&quot;../lib/checkbox.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&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;options.css&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;css&quot;&gt;#title {
  text-align:  center;
  font-size:   30px;
  font-weight: 900;
  font-family: &quot;Noto Serif&quot;, serif;
}

#readable {
  font-family: &quot;Noto Serif&quot;, serif;
}

body {
  margin: 20px 20px;
}

table,
h1,
h2,
p {
  font-family: &quot;Noto Sans&quot;, sans-serif;
}

h1 {
  font-size:   30px;
  font-weight: 900;
}

h1::after {
  content:    '';
  display:    block;
  margin-top: 15px;
  border-top: 1.5px solid #9A9A9A;
}

table,
h2 {
  font-size:   24px;
  font-weight: 800;
}

p {
  font-size: 16px;
}

pre {
  font-size:   12px;
  font-family: &quot;D2 Coding&quot;, monospace;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;h4&gt;3.2 디버깅.&lt;/h4&gt;&lt;p&gt;디버깅이라 쓰고, 확인하기입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;파이어폭스에&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;'about:debugging'을 치고 들어가서 '임시 부가기능 로드중...'을 누른 후, manifest.json 파일을 로드합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995323375C2A971514&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995323375C2A971514&quot; width=&quot;800&quot; height=&quot;449&quot; filename=&quot;debugging1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그 후 '디버그' 버튼을 누르면 확장 기능과 관련된 화면이 나오거나 기능이 동작할 시&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99740C365C2A97DF15&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99740C365C2A97DF15&quot; width=&quot;800&quot; height=&quot;449&quot; filename=&quot;debugging2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;디버깅 도구에 내용이 표시됩니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자바스크립트 같은 경우 &lt;code class=&quot;js&quot;&gt;console.log(&quot;Hi&quot;)&lt;/code&gt; 같은 기능을 적절히 이용해가며 디버깅하세요.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;4. 기능 코딩.&lt;/h2&gt;&lt;p&gt;자바스크립트를 사용해서 본격적으로 코딩해봅시다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;4.1 체크박스 상태 로딩 및 저장.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;먼저 할 것은 팝업과 옵션 페이지를 열었을 때 체크박스의 옵션 상태를 로딩하고,&lt;/p&gt;
&lt;p&gt;변경점이 생기면 저장을 하는 것 입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;옵션 상태를 로딩 및 저장해주는 기능을 하는 checkbox.js와 각 옵션을 정의해주는 popup.js, options.js로 나뉘어 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;checkbox.js&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;/*jshint esversion: 6 */
/* =====================================================
 Checkbox Load &amp;amp;&amp;amp; Storage
 ===================================================== */
var storage = chrome.storage.local;

function get_checkbox(id)
{
  var check = document.getElementById(id);
  return check.checked;
}

function set_checkbox(id, value)
{
  var check     = document.getElementById(id);
  check.checked = value;
}

function load_checkbox(id)
{
  var state = id.substring(5);
  storage.get(state, (option) =&amp;gt; {
    set_checkbox(id, option[state]);
  });
}

function toggle_storage(id)
{
  var state = id.substring(5);
  if (get_checkbox(id))
    storage.set({[state]: true});
  else
    storage.set({[state]: false});
}

function click_check(id)
{
  var font = document.getElementById(id);
  font.addEventListener(&quot;click&quot;, function() {
    toggle_storage(id);
  });
}

window.addEventListener('load', () =&amp;gt; {
  id_callback(load_checkbox);
  id_callback(click_check);
});&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 로딩.&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;window.addEventListener()&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;팝업 또는 옵션페이지가 로드될 때 각 옵션의 id값에 따라 체크박스를 로드, 체크하는 기능을 활성화.&lt;/p&gt;
&lt;p&gt;팝업과 옵션페이지의 자바스크립트 파일에 &lt;code class=&quot;&quot;&gt;id_callback&lt;/code&gt;를 정의해 해당되는 id를 설정해주면 됩니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;popup.html과 options.html에서 &lt;code&gt;font_sharpen&lt;/code&gt;, &lt;code&gt;font_subpixel&lt;/code&gt;처럼 정의한 적이 있었죠?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;load_checkbox()&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;id의 &lt;code&gt;font_&lt;/code&gt; 부분은 제거한게 옵션 이름입니다.&lt;/p&gt;
&lt;p&gt;옵션이름으로 저장된 상태를 가져온 뒤 &lt;code&gt;set_checkbox&lt;/code&gt;를 사용해 체크박스에 저장된 상태를 적용시킵니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;set_checkbox()&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;입력받은 &lt;code&gt;id&lt;/code&gt;에 대응되는 체크박스에 입력받은 상태를 적용시킵니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 상태 확인 및 저장.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;click_check&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;옵션 &lt;code&gt;id&lt;/code&gt;에 클릭 이벤트가 발생시 toggle 시킵니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/180591204720&quot; data-did=&quot;8e6e7a7cf4ca7436b9d90a550dcaac96d1ef2af3&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/180591204720/확장기능-만들-때-주의할-점&quot; title=&quot;&quot; style=&quot;&quot;&gt;https://black7375.tumblr.com/post/180591204720/확장기능-만들-때-주의할-점&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;script async=&quot;&quot; src=&quot;https://assets.tumblr.com/post.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;toggle_storage()&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;입력받은 &lt;code&gt;id&lt;/code&gt;에 대응되는 체크박스 상태를 확인(&lt;code&gt;get_checkbox&lt;/code&gt;)하고 반전시킵니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;get_checkbox()&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;p class=&quot;&quot;&gt;입력받은 &lt;code&gt;id&lt;/code&gt;에 대응되는 체크박스 상태를 반환합니다.&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;* 보다보니.. 몇개 작명이 잘못된 듯 싶다.&lt;/p&gt;
&lt;p&gt;set_checkbox의 &lt;code&gt;value&lt;/code&gt;를 state로,&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;click_check의 &lt;code&gt;font&lt;/code&gt;는 check로 고쳐야겠다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그럼 &lt;code class=&quot;&quot;&gt;id_callback&lt;/code&gt;이 있는 popup.js와 options.js를 보도록 합시다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;popup.js&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;/*jshint esversion: 6 */

function id_callback(callback)
{
  if(callback &amp;amp;&amp;amp; typeof(callback) === &quot;function&quot;)
  {
    callback(&quot;font_sharpen&quot;);
    callback(&quot;font_substitue&quot;);
    callback(&quot;font_math&quot;);
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;보다시피 엄청 간단합니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 콜백.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;id_callback()&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;콜백으로 들어오는 인자값이 함수인지 확인 후 &lt;code&gt;font_sharpen&lt;/code&gt;, &lt;code&gt;font_substitue&lt;/code&gt;, &lt;code&gt;font_math&lt;/code&gt;에 대한 체크박스 동작(checkbox.js) 활성화.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;options.js&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;/*jshint esversion: 6 */
var storage = chrome.storage.local;

var options = {
  legibility: true,
  better:     true,
  mathjax:    true
};
var optionList = Object.keys(options);

function init_options()
{
  optionList.forEach((option) =&amp;gt; {
    storage.get(option, (state) =&amp;gt; {
      if(typeof(state[option]) === &quot;undefined&quot; || state[option] === null)
        storage.set(options);
    });
  });
}

function id_callback(callback)
{
  if(callback &amp;amp;&amp;amp; typeof(callback) === &quot;function&quot;)
  {
    callback(&quot;font_subpixel&quot;);
    callback(&quot;font_legibility&quot;);

    callback(&quot;font_better&quot;);
    callback(&quot;font_alter&quot;);

    callback(&quot;font_mathjax&quot;);
  }
}

window.addEventListener('load', () =&amp;gt; {
  init_options();
});&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;options.js는 popup.js에 비하여 조금 깁니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이유는 초기설정값을 지정해주기 때문입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 초기값 설정.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;window.addEventListener()&lt;/b&gt;&lt;/p&gt;&lt;div&gt;로드 될 때 초기 옵션 값을 체크합니다.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;b&gt;options&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;json 형태로 초기값을 설정해놨습니다.&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;optionList&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;js&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/keys&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Object.keys()&lt;/a&gt;&lt;/code&gt;를 사용하여 for..in문 형태로 사용하도록 합니다.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;b&gt;init_options()&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;각 옵션의 상태가 정의되지 않았거나 null 값인 경우 options의 값을 사용합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;4.2 옵션 상태에 따른 CSS 주입.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;이건 content.js가 담당하고 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;content.js&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;/*jshint esversion: 6 */
//====================basic
var storage = chrome.storage.local;

function load_css(file)
{
  var link   = document.createElement(&quot;link&quot;);
  link.href  = chrome.extension.getURL('contents/' + file + '.css');
  link.rel   = &quot;stylesheet&quot;;
  link.type  = &quot;text/css&quot;;
  link.media = &quot;screen&quot;;
  link.id    = file;
  document.getElementsByTagName(&quot;html&quot;)[0].appendChild(link);
}

function unload(file)
{
  var node = document.getElementById(file);
  if (node)
    node.parentNode.removeChild(node);
}

function on_off(file, loadCallback, unloadCallback, loadOption, unloadOption)
{
  storage.get(file, (option) =&amp;gt; {
    if (option[file])
    {
      if(loadCallback &amp;amp;&amp;amp; typeof(loadCallback) === &quot;function&quot;)
      {
        loadCallback(file);
        if(loadOption &amp;amp;&amp;amp; typeof(loadOption) === &quot;function&quot;)
          loadOption(file);
        if(file === &quot;subpixel&quot;)
          unload(&quot;sharpen&quot;);
        if(file === &quot;mathjax&quot;)
          load_mathjax();
      }
    } else
    {
      if(unloadCallback &amp;amp;&amp;amp; typeof(unloadCallback) === &quot;function&quot;)
      {
        unloadCallback(file);
        if(unloadOption &amp;amp;&amp;amp; typeof(unloadOption) === &quot;function&quot;)
          unloadOption(file);
      }
    }
  });
}

function check(file)
{
  on_off(file, load_css, unload, load_option, unload_option);
}

function update()
{
  check(&quot;sharpen&quot;);
  check(&quot;substitue&quot;);
  check(&quot;math&quot;);
}
window.addEventListener('load',update);
chrome.storage.onChanged.addListener(update);

//====================options
var feature = {
  sharpen:   [&quot;subpixel&quot;, &quot;legibility&quot;],
  substitue: [&quot;better&quot;, &quot;alter&quot;],
  math:      [&quot;mathjax&quot;]
};

function load_option(file)
{
  feature[file].forEach((option) =&amp;gt; {
    on_off(option, load_css, unload);
  });
}

function unload_option(file)
{
  feature[file].forEach((option) =&amp;gt; {
    unload(option);
  });
}

function load_mathjax()
{
  if((window.unsafeWindow == null ? window : unsafeWindow).MathJax == null)
  {
    if((document.getElementsByTagName(&quot;math&quot;).length &amp;gt; 0) ||
       (document.getElementsByTagNameNS ==  null ? false :
        (document.getElementsByTagNameNS(&quot;http://www.w3.org/1998/Math/MathML&quot;,&quot;math&quot;).length &amp;gt; 0)))
    {
      var  head   = document.getElementsByTagName(&quot;head&quot;)[0];
      var script  = document.createElement(&quot;script&quot;);
      script.type = &quot;text/x-mathjax-config&quot;;
      script[(window.opera ? &quot;innerHTML&quot; : &quot;text&quot;)] =
        &quot;  MathJax.Hub.Config({\n&quot; +
        &quot;  \&quot;HTML-CSS\&quot;: {\n&quot; +
        &quot;    messageStyle: \&quot;normal\&quot;,\n&quot; +
        &quot;    linebreaks: {\n&quot; +
        &quot;      automatic: false\n&quot; +
        &quot;    },\n&quot; +
        &quot;    undefinedFamily: \&quot;'STIX Two Math', STIXGeneral, 'Arial Unicode MS', 'Noto Serif KR', serif\&quot;\n&quot; +
        &quot;  },\n&quot; +
        &quot;  config: [\&quot;MMLorHTML.js\&quot;],\n&quot; +
        &quot;  jax: [\&quot;input/TeX\&quot;,\&quot;input/MathML\&quot;,\&quot;output/HTML-CSS\&quot;,\&quot;output/NativeMML\&quot;],\n&quot; +
        &quot;  extensions: [\&quot;tex2jax.js\&quot;,\&quot;mml2jax.js\&quot;,\&quot;MathMenu.js\&quot;,\&quot;MathZoom.js\&quot;],\n&quot; +
        &quot;  TeX: {\n&quot; +
        &quot;    extensions: [\&quot;AMSmath.js\&quot;,\&quot;AMSsymbols.js\&quot;,\&quot;noErrors.js\&quot;,\&quot;noUndefined.js\&quot;]\n&quot; +
        &quot;  }\n&quot; +
        &quot;});&quot;;
      head.appendChild(script);

      script       = document.createElement(&quot;script&quot;);
      script.async = &quot;&quot;;
      script.type  = &quot;text/javascript&quot;;
      script.src   = &quot;https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML-AM_HTMLorMML&quot;;
      script.id    = &quot;mathjax&quot;;
      head.appendChild(script);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;&lt;span class=&quot;&quot;&gt;Basic.&lt;/span&gt;&lt;/h4&gt;&lt;p class=&quot;&quot;&gt;기본적인 기능들에 대해서 알아봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 이벤트.&lt;/b&gt;&lt;code class=&quot;js&quot;&gt;&lt;br /&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;window.addEventListener()&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;페이지가 로드될 때 업데이트하라고 지시한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;chrome.storage.onChanged.addListener()&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;스토리지에 변경점이 생길때 업데이트 하도록 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;스토리지에 변경점이란 앞서 popup과 option에서 On/Off등을 하며 값을 수정할 때겠죠?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 업데이트.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;update()&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;글꼴들의 선명하게, 치환, 수식 기능을 점검.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;check()&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;on_off&lt;/code&gt; 함수에 update에 해당하는 값과 각종 함수들을 넣어서 전해주는 Wrapper입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;on_off()&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;update, check를 통해 전한 값의 상태가 참이면 load, 거짓이면 unload 합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;참 동작: 해당하는 load_css(), load_option(), 각종 예외사항을 적용 &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;거짓 동작: unload(), unload_option() 수행&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;지금보니까 on_off 쪽은 수정해야 할 것이 조금씩 보인다. -_-&lt;/p&gt;
&lt;p&gt;나중에 업뎃할만한 결심이 서면 수정해봐야 할 듯.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;load_css()&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;html 문서에 해당하는 css를 삽입.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;unload()&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;해당하는 id를 제거.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;Options&lt;/h4&gt;&lt;div&gt;&lt;b&gt;- 업데이트 옵션.&lt;/b&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;b&gt;feature&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;각 기능의 옵션에 대해 명시해놓은 곳입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;load_option()&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;feature를 참고하여 옵션의 값을 체크하여 on/off 동작을 수행합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;unload_option()&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;feature를 참고하여 옵션을 비활성화 합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;load_mathjax()&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;math 태그가 있을때만 동적으로 로드합니다.&lt;/p&gt;
&lt;p&gt;MathJax.Hub.Config 부분은 Mathjax 설정.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;나름 쉽죠?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;확장 기능을 만들 때 꼭 도움이 되었으면 좋겠습니다.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol class=&quot;footnotes&quot;&gt;
    &lt;li id=&quot;footnote_56_1&quot;&gt;MS Edge용에도 등록할까 했는데..
&lt;a href=&quot;https://developer.microsoft.com/en-us/store/register&quot;&gt;돈내놓으라고 하길래&lt;/a&gt; 빠른 포기.&lt;br&gt;유료 프로그램도 아니고, 공짜 프로그램인데 굳~~이 내돈 들일 필요가 있나 싶더란. &lt;a href=&quot;#footnote_link_56_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_56_2&quot;&gt;덕분에 web 프로그래밍 코드 컨벤션 따윈 모르고 내마음 가는대로 작성ㅋㅋ&lt;br&gt;
개인 플젝이라 상관없긴 하다. &lt;a href=&quot;#footnote_link_56_2&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_56_3&quot;&gt;이 문서는 MDN을 참고하여 만들어졌습니다.&lt;br&gt;MDN을 참고하는 이유는.. &lt;a href=&quot;https://blog.gaerae.com/2017/11/mozilla-microsoft-google-w3c-samsung-mdn-web-docs.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;구글,MS,삼성,W3C가 웹 기술문서를 모질라의 MDN에 통합 결정!&lt;/a&gt;으로 기술문서가 가장 풍부하기 때문!!  &lt;a href=&quot;#footnote_link_56_3&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description>
      <category>프로그래밍/Web</category>
      <category>Addon</category>
      <category>Readable_Font</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/56</guid>
      <comments>https://black7375.tistory.com/56#entry56comment</comments>
      <pubDate>Mon, 31 Dec 2018 06:56:19 +0900</pubDate>
    </item>
    <item>
      <title>Billboard.js 기초 사용법.</title>
      <link>https://black7375.tistory.com/54</link>
      <description>&lt;span style=&quot;background-color: rgb(154, 165, 234);&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/51&quot; target=&quot;_blank&quot;&gt;2018/10/31 - [IT] - Letter - Enhanced  Ver. 2 프리뷰.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;p class=&quot;&quot;&gt;에서 약속했던대로 Billboard.js라는 차트 기초 사용법을 알아봅시다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;예제 및 기초 사용법.&lt;br /&gt;&lt;/h2&gt;
&lt;p&gt;제가 예제로 써놨던 것은 &lt;a href=&quot;https://naver.github.io/billboard.js/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Billboard.js의 홈페이지&lt;/a&gt;에 나오는 예제였습니다.&lt;/p&gt;
&lt;div id=&quot;chart&quot;&gt;&lt;/div&gt;
&lt;p&gt;코드로 보여주면,&lt;br /&gt;&lt;/p&gt;
&lt;script&gt;
bb.generate({
    bindto: &quot;#chart&quot;,
    data: {
        columns: [
            [&quot;data1&quot;, 30, 200, 100, 170, 150, 250],
            [&quot;data2&quot;, 130, 100, 140, 35, 110, 50]
        ],
        types: {
          data1: &quot;line&quot;,
          data2: &quot;area-spline&quot;
        },
        colors: {
          data1: &quot;red&quot;,
          data2: &quot;green&quot;
        }
    }
});&lt;/script&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div id=&quot;chart&quot;&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;bb.generate({&lt;br /&gt;    bindto: &quot;#chart&quot;,&lt;br /&gt;    data: {&lt;br /&gt;        columns: [&lt;br /&gt;            [&quot;data1&quot;, 30, 200, 100, 170, 150, 250],&lt;br /&gt;            [&quot;data2&quot;, 130, 100, 140, 35, 110, 50]&lt;br /&gt;        ],&lt;br /&gt;        types: {&lt;br /&gt;          data1: &quot;line&quot;,&lt;br /&gt;          data2: &quot;area-spline&quot;&lt;br /&gt;        },&lt;br /&gt;        colors: {&lt;br /&gt;          data1: &quot;red&quot;,&lt;br /&gt;          data2: &quot;green&quot;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;});&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;였습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;border&quot;&gt;&lt;h4 style=&quot;text-align: center;&quot;&gt;class vs id?&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;지금까지 &lt;code class=&quot;html&quot;&gt;&amp;lt;div class=&quot;&quot;&amp;gt;&lt;/code&gt;형식을 써왔기 때문에 &lt;code class=&quot;html&quot;&gt;id&lt;/code&gt;가 나와서 어떤 차이인가 간략히 설명하면&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;&lt;p&gt;페이지 내부에서 사용 가능 횟수.&lt;br /&gt;ex) 2번 사용한 경우.&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;div class=&quot;border&quot;&amp;gt;내용들&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class=&quot;border&quot;&amp;gt;내용들&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;class: 여러번.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;id: 한번 만.&lt;/li&gt;&lt;/ul&gt;&lt;li class=&quot;&quot;&gt;복수 적용.&lt;br /&gt;ex) 2개를 복수 적용한 경우.&lt;br /&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;div class=&quot;cover light&quot; style=&quot;background-image: url(이미지);&quot;&amp;gt;내용들 &amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div class=&quot;cover natural&quot; style=&quot;background-image: url(이미지);&quot;&amp;gt;내용들 &amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;class: 가능.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;id: 불가능.&lt;/li&gt;&lt;/ul&gt;&lt;li class=&quot;&quot;&gt;표현법.&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;class: &lt;code class=&quot;html&quot;&gt;.class이름&lt;/code&gt;.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;id: &lt;code class=&quot;html&quot;&gt;#id이름&lt;/code&gt;.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;p class=&quot;&quot;&gt;차트를 여러번 쓰거나 티스토리의 기본기능들이 대부분 &lt;code class=&quot;html&quot;&gt;class&lt;/code&gt;의 형식으로 이루어져 있기 때문에 일관성을 위하여 &lt;code class=&quot;html&quot;&gt;class&lt;/code&gt;를 사용해도 좋습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;여러분도 이미 눈치챘겠지만&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;div의 위치: 차트가 삽입될 위치&lt;br /&gt;&lt;/li&gt;&lt;li&gt;bindto: 차트 이름, class나 id를 사용하면 됨.&lt;/li&gt;&lt;li&gt;data: 차트의 각종 데이터.&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;columns: &lt;code&gt;[&quot;계열이름&quot;, 1번데이터, 2번데이터, ...]&lt;/code&gt;&lt;/li&gt;&lt;li&gt;types: &lt;code&gt;계열이름: &quot;차트형태&quot;&lt;code&gt;&lt;/code&gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;colors: &lt;code&gt;계열이름: &quot;색상&quot;&lt;/code&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;p&gt;라는 것만 알면 쉽게 차트를 만들어 볼 수 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Billboard.js에서 제공하는 차트의 형태는 다음과 같습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://camo.githubusercontent.com/fcd03ce15cf183f6ab4f6ab1d464da236724cd66/68747470733a2f2f6e617665722e6769746875622e696f2f62696c6c626f6172642e6a732f696d672f63686172742d74797065732e706e673f763d33&quot; alt=&quot;Chart Types&quot; data-canonical-src=&quot;https://naver.github.io/billboard.js/img/chart-types.png?v=3&quot; style=&quot;max-width:100%;&quot;&gt;&lt;/p&gt;&lt;h2&gt;꿀팁.&lt;br /&gt;&lt;/h2&gt;&lt;h4&gt;- 쉽게 만들기.&lt;/h4&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99176C465BE2289034&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99176C465BE2289034&quot; width=&quot;800&quot; height=&quot;454&quot; filename=&quot;billboard js playground.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://naver.github.io/billboard.js/playground/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Playground&lt;/a&gt;를 사용하면 표 형태로 데이터를 추가하고, 그래픽 상태로 &lt;code class=&quot;js&quot;&gt;bb.generate();&lt;/code&gt; 안에 들어갈 코드를 자동으로 생성할 수 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;- 예제들.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://naver.github.io/billboard.js/demo/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;데모 페이지&lt;/a&gt;에 들어가면 여러가지 예제를 제공해줍니다.&lt;/p&gt;
&lt;p&gt;이를 이용해 자신이 원하는 차트를 만들어볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;- D3.js 호환.&lt;/h4&gt;&lt;p&gt;각종 데이터 시작화에 사용되는 &lt;a href=&quot;https://d3js.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;D3.js&lt;/a&gt;가 Billboard.js에 사용되기 때문에 D3.js에서 썼던 코드를 그대로 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;-끝-&lt;br /&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <category>Chart</category>
      <category>web</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/54</guid>
      <comments>https://black7375.tistory.com/54#entry54comment</comments>
      <pubDate>Wed, 7 Nov 2018 09:18:03 +0900</pubDate>
    </item>
    <item>
      <title>iframely가 아닌 Embedly를 택한 이유.</title>
      <link>https://black7375.tistory.com/53</link>
      <description>&lt;p&gt;원래 텀블러에 올릴만한 글이나,&lt;/p&gt;&lt;p&gt;텀블러 스킨은 일부 스크립트를 불러오기가 힘든 관계로 티스토리에 적습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;사실 코드 복사 &amp;amp; 붙여넣기엔 &lt;a href=&quot;https://iframely.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;iframely&lt;/a&gt;가 Embedly보다 좋지만, 만들어지는 코드 형태가 복잡해서 API를 사용하면 모를까 일반 사용자들이 코드를 짜기엔 적합하지 않다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예를 들어 글쓰다 날려먹었단 제 블로그 일기를 Embedly와 iframely를 차례로 나열하면,&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;embedly-card&quot;&gt;&lt;h4&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/179626774060&quot; title=&quot;&quot; style=&quot;&quot;&gt;플래시는 나의 적.&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;플래시는 나의 적.플래시 활성 안했다고 임시저장한게 없어서 다 날라갔다. 플래시에 에러맞고 불구덩이 쳐박힌 내 기분을 니들이 알아? https://www.youtube.com/watch?v=D3ZFtSoWtRc 그건 그렇고 임시저장해놓은 글들이 많았구나.. 나중에 차근차근 풀어야겠다.&lt;/p&gt;&lt;/blockquote&gt;
&lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/179626774060&quot; data-did=&quot;84ede33bb7805ca258720b3a16fb4008ece6d444&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/179626774060/플래시-활성-안했다고-임시저장한게-없어서-다-날라갔다-플래시에-에러맞고-불구덩이-쳐박힌&quot;&gt;https://black7375.tumblr.com/post/179626774060/플래시-활성-안했다고-임시저장한게-없어서-다-날라갔다-플래시에-에러맞고-불구덩이-쳐박힌&lt;/a&gt;&lt;/div&gt;&lt;script async=&quot;&quot; src=&quot;https://assets.tumblr.com/post.js&quot;&gt;&lt;/script&gt;
&lt;p class=&quot;&quot;&gt;iframely가 원본과 훨씬 가깝게 보여주고 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;그러나 코드를 비교해 보면&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;blockquote class=&quot;embedly-card&quot;&amp;gt;&amp;lt;h4&amp;gt;&amp;lt;a href=&quot;https://black7375.tumblr.com/post/179626774060&quot;&amp;gt;플래시는 나의 적.&amp;lt;/a&amp;gt;&amp;lt;/h4&amp;gt;&amp;lt;p&amp;gt;플래시는 나의 적.플래시 활성 안했다고 임시저장한게 없어서 다 날라갔다. 플래시에 에러맞고 불구덩이 쳐박힌 내 기분을 니들이 알아? https://www.youtube.com/watch?v=D3ZFtSoWtRc 그건 그렇고 임시저장해놓은 글들이 많았구나.. 나중에 차근차근 풀어야겠다.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;&amp;lt;script async src=&quot;//cdn.embedly.com/widgets/platform.js&quot; charset=&quot;UTF-8&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/179626774060&quot; data-did=&quot;84ede33bb7805ca258720b3a16fb4008ece6d444&quot;  &amp;gt;&lt;br /&gt;&amp;lt;a href=&quot;https://black7375.tumblr.com/post/179626774060/플래시-활성-안했다고-임시저장한게-없어서-다-날라갔다-플래시에-에러맞고-불구덩이-쳐박힌&quot;&amp;gt;https://black7375.tumblr.com/post/179626774060/플래시-활성-안했다고-임시저장한게-없어서-다-날라갔다-플래시에-에러맞고-불구덩이-쳐박힌&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;script async src=&quot;https://assets.tumblr.com/post.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Embedly에 비해 iframely가 범용성이 부족하고 복잡하다는 것을 알 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;고로 외부컨텐츠 버튼을 사용하여 코드를 입력할 땐, Embedly의 형태가 맞다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <category>Tip</category>
      <category>web</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/53</guid>
      <comments>https://black7375.tistory.com/53#entry53comment</comments>
      <pubDate>Tue, 6 Nov 2018 03:59:15 +0900</pubDate>
    </item>
    <item>
      <title>Letter - Enhanced 스킨 공개.[Ver. 2.0]</title>
      <link>https://black7375.tistory.com/51</link>
      <description>&lt;p&gt;* 여기는 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR', serif;&quot; class=&quot;&quot;&gt;Letter - Enhanced Ver. 2&lt;/span&gt;&lt;/b&gt;의 기능을 미리 볼 수 있는 페이지 입니다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;* 이 페이지에서 보여주는 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR', serif;&quot; class=&quot;&quot;&gt;Letter - Enhanced&lt;/span&gt;&lt;/b&gt; 스킨은 개발 중인 관계로 미공개 기능이나 코드, 버그가 포함되어 있을 수도 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt; 맨붕.. 내가 만들어놨던 테스트 페이지가 실수로 싹 날라갔다.&lt;/p&gt;&lt;p&gt;으아망ㄴㅁ리ㅓ;ㅣㅏ 플래시 때문에 자동저장도 안됐어! 너ᅟᅡᆷㄹ;ㅣᅟᅡᆫㅁ얼&lt;/p&gt;&lt;p&gt;플래시는 나의 적ㄴㅁㅇ;ㅣ러ㅣ;ㅣ망ㄴㄹ댜ㅓ매;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990B85395BD9FF5E0C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990B85395BD9FF5E0C&quot; width=&quot;900&quot; height=&quot;214&quot; filename=&quot;Letter - Enhanced.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;0. 파일 첨부.&lt;/h2&gt;&lt;p&gt;&lt;b&gt;Ver 2.1&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block;   height: auto; max-width: 100%;&quot;&gt;&lt;a href=&quot;https://t1.daumcdn.net/cfile/tistory/99353F4C5EDCFB7310&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;https://i1.daumcdn.net/cfs.tistory/v/0/blog/image/extension/zip.gif&quot; style=&quot;vertical-align: middle;&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;Letter-Enhanced-2.1.zip&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;깃허브에서도 확인할 수 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;embedly-card&quot;&gt;&lt;h4&gt;&lt;a href=&quot;https://github.com/black7375/Letter-Enhanced&quot;&gt;black7375/Letter-Enhanced&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Tistory's Letter Skin + Font setting, Pretty Blockquote, Math &amp;amp; Code highlighting - black7375/Letter-Enhanced&lt;/p&gt;&lt;/blockquote&gt;

&lt;p class=&quot;&quot;&gt;수정이 필요한 것이 있으면 깃허브 이슈기능이나 댓글로 알려주세요~&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;적용법은 전 글로 대체합니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/50&quot; target=&quot;_blank&quot;&gt;2018/10/23 - [IT] - Letter - Enhanced 스킨 공개.[Ver 1.52]&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1. 기능들.&lt;/h2&gt;&lt;p&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR', serif;&quot; class=&quot;&quot;&gt;Letter - Enhanced Ver. 2&lt;/span&gt;&lt;/b&gt;는 기본적인 html 요소들을 더 이쁘게 고치고, 여러가지 요소를 쉽게 추가하도록 돕는 것이 목표입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 기본으로 표시되는 인용구, 구분선, 더보기, 리스트등을 고치고 각종 요소들을 추가하였습니다.&lt;/p&gt;&lt;p&gt;2.0에 추가되는 내용은 지속적으로 업데이트되고 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;기존의 디자인과 제가 정한 디자인 컨셉을 최대한 지키며 추가하는 중.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.1 넓은 화면.&lt;/h3&gt;&lt;p&gt;글의 최대 넓이(800px $\rightarrow$ 900px)를 조정해 PC 환경에서 시원시원하게 볼 수 있도록 하였습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.2 인용구.&lt;/h3&gt;&lt;p&gt;현재 기본적으로 표시되는 인용구 외에 2가지를 추가하였습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 기본.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;지금은 따옴표 옆에 문자가 바로 나타나는데 신경쓰여서 아래에서 글이 시작되도록 옵션을 바꾸었습니다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;그리고 지은이(?) 또는 출처 등을 쓸 수 있도록 하였습니다.&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;동틀 녘 햇빛 포개짐.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;Bright vixens jump; dozy fowl quack.&lt;/p&gt;&lt;footer&gt;Pangram&lt;/footer&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- Inline.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;기존 버전입니다.&lt;/p&gt;&lt;blockquote class=&quot;inline&quot;&gt;&lt;p&gt;동틀 녘 햇빛 포개짐.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;Bright vixens jump; dozy fowl quack.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- simple.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;따옴표가 사라진 심플한 버전입니다.&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;simple&quot;&gt;&lt;p&gt;동틀 녘 햇빛 포개짐.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;Bright vixens jump; dozy fowl quack.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- mobile.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;티스토리 모바일 버전 스타일 입니다.&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;mobile&quot;&gt;&lt;p&gt;동틀 녘 햇빛 포개짐.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;Bright vixens jump; dozy fowl quack.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;- none.&lt;/b&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;원래 표시되던 형식의 인용구입니다.&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;none&quot;&gt;&lt;p&gt;동틀 녘 햇빛 포개짐.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;Bright vixens jump; dozy fowl quack.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;blockquote&amp;gt;내용&amp;lt;footer&amp;gt;지은이&amp;lt;/footer&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;&amp;lt;blockquote class=&quot;inlne&quot;&amp;gt;내용..&amp;lt;/blockquote&amp;gt;&lt;br /&gt;&amp;lt;blockquote class=&quot;simple&quot;&amp;gt;내용..&amp;lt;/blockquote&amp;gt;&lt;br /&gt;&amp;lt;blockquote class=&quot;mobile&quot;&amp;gt;내용..&amp;lt;/blockquote&amp;gt;&lt;br /&gt;&amp;lt;blockquote class=&quot;none&quot;&amp;gt;내용..&amp;lt;/blockquote&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.3 구분선.&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 기본.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;우선 기본적으로 표시되는 기본선을 개선하였습니다.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;저 나름대론 감성있게 표현한다고 했는데 어울리나요? ㅎㅎ&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- simple.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;화면 중간에 짧은 선이 나타나는 simple 한 구분선입니다.&lt;br /&gt;&lt;/p&gt;&lt;hr class=&quot;simple&quot;&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- none.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;역시 기본적으로 제공해주는 구분선입니다.&lt;/p&gt;&lt;p&gt;혹시 이걸 원하시는 분들이 있을까봐 넣어봤어요.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;hr class=&quot;none&quot;&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;hr class=&quot;simple&quot;&amp;gt;&lt;br /&gt;&amp;lt;hr class=&quot;none&quot;&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.4 글상자.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;기본 구분선 스타일과 비슷한 글상자를 추가하였습니다.&lt;/p&gt;
&lt;div class=&quot;border&quot;&gt;&lt;p&gt;글상자 내용1&lt;br /&gt;&lt;/p&gt;&lt;p&gt;글상자 내용2&lt;br /&gt;&lt;/p&gt;&lt;p&gt;글상자 내용3...&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;div class=&quot;border&quot;&amp;gt;내용..&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;1.5 더보기.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;일반적인 글자랑 똑같이 나와서 구분하기 힘들게 생겼던 더보기에 약간의 강조효과를 줬습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;전후비교.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9930A8355BE0B48F15&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9930A8355BE0B48F15&quot; width=&quot;800&quot; height=&quot;191&quot; filename=&quot;moreless - ori.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;button type=&quot;button&quot; class=&quot;btn_more&quot; id=&quot;more51_0&quot; data-id=&quot;51_0&quot;&gt;더보기&lt;/button&gt;&lt;div class=&quot;moreless_content&quot; id=&quot;content51_0&quot; style=&quot;display: none;&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;btn_less&quot; id=&quot;less51_0&quot; data-id=&quot;51_0&quot;&gt;&lt;span class=&quot;txt_fold&quot;&gt;접기&lt;/span&gt;&lt;/button&gt;
  &lt;p class=&quot;txt_view&quot;&gt;&lt;p&gt;더보기 내용1&lt;/p&gt;&lt;p&gt;더보기 내용2&lt;br /&gt;&lt;/p&gt;&lt;/p&gt;
&lt;button type=&quot;button&quot; class=&quot;btn_less&quot; id=&quot;less51_0&quot; data-id=&quot;51_0&quot;&gt;&lt;span class=&quot;txt_fold&quot;&gt;접기&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;1.6 리스트.&lt;/h4&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 버그 수정.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;우선 리스트간 사이가 대문짝만하게 갈라져 나타났던 Letter 스킨 고유의 문제가 2018.10.27 기준으로 해결되었습니다. 짝짝&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;전후 비교.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99130E4E5BD8CCB618&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99130E4E5BD8CCB618&quot; width=&quot;900&quot; height=&quot;373&quot; filename=&quot;ul.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;$X$는 집합이며, $f$의 '정의역'이라고 한다.&lt;/li&gt;&lt;li&gt;$Y$는 집합이며, $f$의 '공역'이라고 한다.&lt;/li&gt;&lt;li&gt;$\operatorname{graph}⁡ f$는 곱집합 $X \times Y$의 부분집합이며, $f$의 그래프라고 한다.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;단, 임의의 $x \in X$에 대하여, $(x,y)\in \operatorname{graph}⁡f$인 $y \in Y$가 유일하게 존재한다.&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 정의 목록(dl, dt, dd).&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;역시 일반 글처럼만 나왔던 정의목록에 강조하는 효과를 줬습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;전후비교.&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 622px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A9BB395BE0B53216&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A9BB395BE0B53216&quot; width=&quot;622&quot; height=&quot;333&quot; filename=&quot;dt - ori.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;dl&gt;
    &lt;dt&gt;정의1&lt;/dt&gt;
    &lt;dd&gt;정의 내용1&lt;/dd&gt;
    &lt;dt&gt;정의2&lt;/dt&gt;
    &lt;dd&gt;정의 내용1&lt;/dd&gt;
    &lt;dd&gt;정의 내용2&lt;/dd&gt;
    &lt;dd&gt;정의 내용3&lt;/dd&gt;
    &lt;dd&gt;정의 내용4&lt;/dd&gt;
    &lt;dd&gt;정의 내용5&lt;/dd&gt;
 &lt;/dl&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;dl의 class에 colon을 사용하면 다음과 같이도 보여줄 수 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;dl class=&quot;colon&quot;&gt;
    &lt;dt&gt;정의1&lt;/dt&gt;
    &lt;dd&gt;정의 내용1&lt;/dd&gt;
    &lt;dt&gt;정의2&lt;/dt&gt;
    &lt;dd&gt;정의 내용1&lt;/dd&gt;
    &lt;dd&gt;정의 내용2&lt;/dd&gt;
    &lt;dd&gt;정의 내용3&lt;/dd&gt;
    &lt;dd&gt;정의 내용4&lt;/dd&gt;
    &lt;dd&gt;정의 내용5&lt;/dd&gt;
 &lt;/dl&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;dl class=&quot;colon&quot;&amp;gt;&lt;br /&gt;  &amp;lt;dt&amp;gt;정의&amp;lt;/dt&amp;gt;&lt;br /&gt;  &amp;lt;dd&amp;gt;정의 내용&amp;lt;/dd&amp;gt;&lt;br /&gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1.7 이미지.&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 이미지 강조 &amp;amp; 그림자 효과.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;마우스를 올리면 이미지를 약간 확대하고, 그림자 효과를 주어 구분할 수 있게 하였습니다. &lt;br /&gt;&lt;/p&gt;&lt;p&gt; &lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 자동 이미지 배열.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;이미지 요소들을 나열하면 크기와 배열이 자동으로 되는 기능을 추가하였습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예1. 종류와 크기가 랜덤으로 생성되는 고양이.(첫사진 제외)&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;photos&quot;&gt;&lt;img src=&quot;https://placekitten.com/408/287&quot;&gt;&lt;/div&gt;
&lt;script&gt;function getRandomSize(min, max) {
  return Math.round(Math.random() * (max - min) + min);
}

var allImages = &quot;&quot;;

for (var i = 0; i &lt; 25; i++) {
  var width = getRandomSize(200, 400);
  var height =  getRandomSize(200, 400);
  allImages += '&lt;img src=&quot;https://placekitten.com/'+width+'/'+height+'&quot; alt=&quot;pretty kitty&quot;&gt;';
}

$('.photos').append(allImages);&lt;/script&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예2. 비율에 따른 예.&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;photos&quot;&gt;&lt;img src=&quot;https://placehold.it/350x150/69D2E7/ffffff&quot;&gt;&lt;img src=&quot;https://placehold.it/320x180/A7DBD8/ffffff&quot;&gt;&lt;img src=&quot;https://placehold.it/320x300/E0E4CC/ffffff&quot;&gt;&lt;img src=&quot;https://placehold.it/472x500/F38630/ffffff&quot;&gt;&lt;img src=&quot;https://placehold.it/540x360/FA6900/ffffff&quot;&gt;&lt;img src=&quot;https://placehold.it/800x600/ECD078/ffffff&quot;&gt;&lt;img src=&quot;https://placehold.it/400x120/D95B43/ffffff&quot;&gt;&lt;img src=&quot;https://placehold.it/300x300/C02942/ffffff&quot;&gt;&lt;img src=&quot;https://placehold.it/320x500/542437/ffffff&quot;&gt;&lt;img src=&quot;https://placehold.it/450x300/53777A/ffffff&quot;&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;div class=&quot;photos&quot;&amp;gt;이미지..&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 이미지 커버.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;이미지를 배경으로 놓을 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;예) 3개의 시를 제가 찍었던 사진과 함께 넣어봤습니다.&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;cover&quot; style=&quot;background-image: url(&amp;quot;https://66.media.tumblr.com/5a241c161a2d86a7a2f0658d600cf617/tumblr_p6lpqvdIf31v28uuio3_1280.jpg&amp;quot;); text-shadow: rgb(34, 34, 34) 0px 0px 1px, rgb(34, 34, 34) 0px 0px 2px, rgb(34, 34, 34) 0px 0px 3px, rgb(34, 34, 34) 0px 0px 4px, rgb(34, 34, 34) 0px 0px 5px !important;&quot;&gt;&lt;p&gt;시1  -  하얀색 글씨가 기본입니다. 유니코드가 필요한 한글이라 폰트를 다른 걸로 교체했다.&lt;/p&gt;&lt;blockquote class=&quot;&quot; style=&quot; font-family: auto; font-weight:700;&quot;&gt;&lt;p&gt;山에는 ᄭᅩᆺ픠네&lt;br /&gt;ᄭᅩᆺ치픠네&lt;br /&gt;갈 봄 녀름업시&lt;br /&gt;ᄭᅩᆺ치픠네&lt;br /&gt;&lt;br /&gt;山에&lt;br /&gt;山에&lt;br /&gt;픠는ᄭᅩᆺ츤&lt;br /&gt;저만치 혼자서 픠여잇네&lt;br /&gt;&lt;br /&gt;山에서우는 적은새요&lt;br /&gt;ᄭᅩᆺ치죠와&lt;br /&gt;山에서&lt;br /&gt;사노라네&lt;br /&gt;&lt;br /&gt;山에는 ᄭᅩᆺ지네&lt;br /&gt;ᄭᅩᆺ치지네&lt;br /&gt;갈 봄 녀름업시&lt;br /&gt;ᄭᅩᆺ치지네 &lt;br /&gt;&lt;/p&gt;&lt;footer class=&quot;&quot;&gt;山有花, 김소월&lt;br /&gt;&lt;/footer&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;div class=&quot;cover light&quot; style=&quot;background-image: url(&amp;quot;https://66.media.tumblr.com/d1f7b65ca2349f375b3bf7d517577e51/tumblr_p3zrr1hcYR1v28uuio2_1280.jpg&amp;quot;);&quot;&gt;&lt;p&gt;시2 - 밝은 화면에 어울리는 light를 적용하여 검은 글씨가 등장.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;죽는 날까지 하늘을 우러러&lt;br /&gt;한 점 부끄럼이 없기를,&lt;br /&gt;잎새에 이는 바람에도&lt;br /&gt;나는 괴로워했다.&lt;br /&gt;별을 노래하는 마음으로&lt;br /&gt;모든 죽어가는 것을 사랑해야지&lt;br /&gt;그리고 나한테 주어진 길을&lt;br /&gt;걸어가야겠다.&lt;br /&gt;&lt;br /&gt;오늘 밤에도 별이 바람에 스치운다. &lt;br /&gt;&lt;/p&gt;&lt;footer&gt;서시(序詩), 윤동주&lt;/footer&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;div class=&quot;cover natural&quot; style=&quot;background-image: url(&amp;quot;https://66.media.tumblr.com/f990e54bbb7698df4d0d2034784d09f5/tumblr_phmgrqitIV1v28uuio6_1280.jpg&amp;quot;) !important; text-shadow: rgb(34, 34, 34) 0px 0px 1px, rgb(34, 34, 34) 0px 0px 2px, rgb(34, 34, 34) 0px 0px 3px, rgb(34, 34, 34) 0px 0px 4px, rgb(34, 34, 34) 0px 0px 5px !important;&quot;&gt;
&lt;p class=&quot;&quot;&gt;시3 - natural을 적용하여 배경과 상호작용하게 만들었다. 무서운 느낌이 글자의 색 때문에 그대로 전해진다.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;十三人의兒孩가道路로疾走하오.&lt;br /&gt;(길은막달은골목이適當하오.)&lt;br /&gt;&amp;nbsp;&lt;br /&gt;第一의兒孩가무섭다고그리오.&lt;br /&gt;第二의兒孩도무섭다고그리오.&lt;br /&gt;第三의兒孩도무섭다고그리오.&lt;br /&gt;第四의兒孩도무섭다고그리오.&lt;br /&gt;第五의兒孩도무섭다고그리오.&lt;br /&gt;第六의兒孩도무섭다고그리오.&lt;br /&gt;第七의兒孩도무섭다고그리오.&lt;br /&gt;第八의兒孩도무섭다고그리오.&lt;br /&gt;第九의兒孩도무섭다고그리오.&lt;br /&gt;第十의兒孩도무섭다고그리오.&lt;br /&gt;第十一의兒孩가무섭다고그리오.&lt;br /&gt;第十二의兒孩도무섭다고그리오.&lt;br /&gt;第十三의兒孩도무섭다고그리오.&lt;br /&gt;十三人의兒孩는무서운兒孩와무서워하는兒孩와그러케뿐이모혓소.(다른事情은업는것이차라리나앗소)&lt;br /&gt;&lt;br /&gt;그中에一人의兒孩가무서운兒孩라도좃소.&lt;br /&gt;그中에二人의兒孩가무서운兒孩라도좃소.&lt;br /&gt;그中에二人의兒孩가무서워하는兒孩라도좃소.&lt;br /&gt;그中에一人의兒孩가무서워하는兒孩라도좃소.&lt;br /&gt;&lt;br /&gt;(길은뚤닌골목이라도適當하오.)&lt;br /&gt;十三人의兒孩가道路로疾走하지아니하야도좃소. &lt;br /&gt;&lt;/p&gt;&lt;footer&gt;烏瞰圖 詩第一號, 이상&lt;/footer&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;div class=&quot;cover&quot; style=&quot;background-image: url(이미지);&quot;&amp;gt;내용들&amp;lt;/div&amp;gt;
&amp;lt;div class=&quot;cover light&quot; style=&quot;background-image: url(이미지);&quot;&amp;gt;내용들&amp;lt;/div&amp;gt;
&amp;lt;div class=&quot;cover natural&quot; style=&quot;background-image: url(이미지);&quot;&amp;gt;내용들&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이미지라 되어 있는 곳에 이미지 주소만 넣으면 된다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;border&quot;&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;b&gt;티스토리 이미지 주소 꿀팁.&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;티스토리에서 이미지를 삽입하면 다음과 같이 치환자가 삽입되는데&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995145415BDDC4212F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995145415BDDC4212F&quot; width=&quot;900&quot; height=&quot;1200&quot; filename=&quot;photo_2018-11-04_00-04-30.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;[ ##_1N|cfile5.uf@995145415BDDC4212F07E6.jpg|width=&quot;900&quot; height=&quot;1200&quot; filename=&quot;photo_2018-11-04_00-04-30.jpg&quot; filemime=&quot;image/jpeg&quot; style=&quot;&quot;&quot;&quot;|_##]&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;&quot;&gt;995145415BDDC4212F07E6.jpg 중 뒤의 8글자를 자르면 &lt;a href=&quot;https://t1.daumcdn.net/cfile/tistory/995145415BDDC4212F&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://t1.daumcdn.net/cfile/tistory/995145415BDDC4212F&lt;/a&gt;처럼 바로 이미지 주소를 얻을 수 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.8 차트.&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;네이버의 &lt;a href=&quot;https://naver.github.io/billboard.js/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Billboard.js&lt;/a&gt;를 사용하여 손쉽게 차트를 추가할 수 있습니다.&lt;/p&gt;&lt;p&gt;차트 종류와 사용법은 상대적으로 복잡한 관계로 글을 하나 파서 설명하도록 하겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;더 많은 예제를 보려면 &lt;a href=&quot;https://naver.github.io/billboard.js/demo/#Chart.AreaChart&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;데모 페이지&lt;/a&gt;를 확인하세요.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://nhnent.github.io/tui.chart/latest/index.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;TUI(TOAST UI) Chart&lt;/a&gt;도 고려해보긴 했는데 Billboard.js가 취향에 맞아서 선택.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예)&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;chart&quot;&gt;&lt;/div&gt;
&lt;script&gt;
bb.generate({
    bindto: &quot;.chart&quot;,
    data: {
        columns: [
            [&quot;data1&quot;, 30, 200, 100, 170, 150, 250],
            [&quot;data2&quot;, 130, 100, 140, 35, 110, 50]
        ],
        types: {
          data1: &quot;line&quot;,
          data2: &quot;area-spline&quot;
        },
        colors: {
          data1: &quot;red&quot;,
          data2: &quot;green&quot;
        }
    }
});&lt;/script&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/54&quot; target=&quot;_blank&quot;&gt;2018/11/07 - [IT] - Billboard.js 기초 사용법.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;참고.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.9 카드형 링크.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://embed.ly/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Embedly&lt;/a&gt;를 사용하여 카드 형태의 링크를 제공합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예) 이 페이지. SEO 최적화 버전과 그냥 버전.&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;embedly-card&quot;&gt;&lt;h4&gt;&lt;a href=&quot;https://black7375.tistory.com/51&quot;&gt;Letter - Enhanced Ver. 2 프리뷰.&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;호흡이 긴 포스팅을 위주로 하고 있습니다.&lt;/p&gt;&lt;/blockquote&gt;
&lt;a class=&quot;embedly-card&quot; href=&quot;https://black7375.tistory.com/51&quot;&gt;Letter - Enhanced Ver. 2 프리뷰.&lt;/a&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;사용법.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;blockquote class=&quot;embedly-card&quot;&amp;gt;&amp;lt;h4&amp;gt;&amp;lt;a href=&quot;주소&quot;&amp;gt;사이트 제목&amp;lt;/a&amp;gt;&amp;lt;/h4&amp;gt;&amp;lt;p&amp;gt;사이트 내용 요약&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;&amp;lt;a class=&quot;embedly-card&quot; href=&quot;주소&quot;&amp;gt;사이트 제목&amp;lt;/a&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위가 blockquote를 사용한 방법이 SEO 최적화 방식이고, a를 사용한 방법이 일반적인 방식이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.10 파일첨부.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;보다 깔끔하고 눈에 띄게 파일첨부 UI를 수정하였습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;전후비교.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 132px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9946883B5C214FA315&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9946883B5C214FA315&quot; width=&quot;132&quot; height=&quot;171&quot; filename=&quot;File_Attach.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block;   height: auto; max-width: 100%;&quot;&gt;&lt;a href=&quot;https://t1.daumcdn.net/cfile/tistory/99C2B94A5C214EE313&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;https://i1.daumcdn.net/cfs.tistory/v/0/blog/image/extension/txt.gif&quot; style=&quot;vertical-align: middle;&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;Example.txt&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;1.11 기타.&lt;/b&gt;&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;- 부드러운 스크롤(파이어폭스, 크롬, 오페라).&lt;/p&gt;&lt;p class=&quot;&quot;&gt;- 컨텐츠 로딩시 애니메이션.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;- Embedly, '카테고리 글 더 보기' 플러그인과 호환성 개선.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;- 각종 버그 수정 및 업데이트(Letter, Highlight.js, Mathjax).&lt;/p&gt;&lt;p class=&quot;&quot;&gt;- 수식 폰트 개선(한글 Fallback을 Noto Serif KR로. 수식내 한글표현이 자연스러워졌어요!!).&lt;/p&gt;&lt;p class=&quot;&quot;&gt;(참고. &lt;a href=&quot;https://www.tug.org/pracjourn/2006-1/hartke/hartke.pdf&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;A Survey of Free Math Fonts for T&lt;/a&gt;&lt;a href=&quot;https://www.tug.org/pracjourn/2006-1/hartke/hartke.pdf&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;E&lt;/a&gt;&lt;a href=&quot;https://www.tug.org/pracjourn/2006-1/hartke/hartke.pdf&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;X and LaTex&lt;/a&gt;, &lt;a href=&quot;https://tex.stackexchange.com/questions/425098/which-opentype-math-fonts-are-available&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Which OpenType Math fonts are available?&lt;/a&gt;, &lt;a href=&quot;https://ctan.org/topic/font-maths&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Math Font&lt;/a&gt;)&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;등등.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.12 2.1 수정&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;- 성능향상&lt;/p&gt;&lt;p class=&quot;&quot;&gt;- 2020년에 미작동 되는 기능 수정&lt;/p&gt;&lt;p class=&quot;&quot;&gt;- 티스토리에서 업데이트된 letter 스킨 반영&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;2. 배포시기?&lt;/h2&gt;&lt;p class=&quot;&quot;&gt;&lt;strike&gt;2018년 11월~12월.&lt;/strike&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;strike&gt;그러니까 올해 말에 배포할 것을 목표로 삼고 있습니다.&lt;/strike&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;2018-12-27에 배포!!&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;3. TODO?&lt;/h2&gt;&lt;p&gt;이 기능들은 추후 버전에 넣는 것을 검토만 하고 있으며,&lt;/p&gt;&lt;p&gt;언제 들어갈지 저도 &lt;b&gt;모릅니다&lt;/b&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;2년 3년 지나도 안들어갈 수도 있고, 제가 사용하는 스킨을 바꿔서 지원이 끊길 수도 있고..&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그나마 답해드릴 수 있는건 3.0은 내년 언젠가엔 나온다는 것.&lt;/p&gt;&lt;p&gt;나중에 들어갈 업데이트들 일부는 전반적인 구조 조정이 필요한 큰 공사가 될 수도 있어 지금까지의 업데이트와 달리 시간이 좀 걸립니다.ㅠ&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;스크롤 시 헤더 표시[내리면 사라짐].&lt;/li&gt;&lt;li&gt;페이지 이동 애니메이션.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;아이콘을 벡터인 폰트로 변경(Font Awesome).&lt;/li&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://fontfaceobserver.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Font Face Observer&lt;/a&gt;를 사용해 글씨 깜박임 제거.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;&lt;a href=&quot;https://multilingualjs.github.io/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;multilingual.js&lt;/a&gt;를 사용해 자연스러운 영문, 한글 글꼴 로드.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;화면 크기에 유동적인 글씨 크기. &lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;반응형 폰트 크기.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;목차(TOC) 생성.&lt;/li&gt;&lt;li&gt;마크다운 지원.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;글씨 크기 변경 버튼.&lt;/li&gt;&lt;li&gt;홈에서 기본형, 갤러리 변경 버튼.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;다크 모드 버튼.&lt;/li&gt;&lt;li&gt;텍스트 요약 버튼.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;영상 iframe을 반응형으로.&lt;/li&gt;&lt;li&gt;영상 pip.&lt;/li&gt;&lt;li&gt;와이드 이미지.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Auto Link.&lt;/li&gt;&lt;li&gt;댓글에 이미지(https://imgur.com/upload) 영상(https://gfycat.com/ko/upload) 버튼.&lt;/li&gt;&lt;li&gt;위아래 이동 버튼.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;amp 지원.&lt;/li&gt;&lt;li&gt;404 페이지 꾸미기.&lt;/li&gt;&lt;li&gt;핀터레스트, 텀블러 링크.&lt;/li&gt;&lt;li&gt;단축키&lt;br /&gt;&lt;/li&gt;&lt;li&gt;기타 성능향상(&lt;a href=&quot;https://css-tricks.com/case-study-boosting-front-end-performance/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;예&lt;/a&gt;&amp;nbsp; &lt;a href=&quot;https://github.com/dieulot/instantclick&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;예2&lt;/a&gt;)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;결론 에디터 업그레이드에서 플래시 제거 좀 ㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜ&lt;br /&gt;&lt;/p&gt;&lt;p&gt;-끝-&lt;br /&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/51</guid>
      <comments>https://black7375.tistory.com/51#entry51comment</comments>
      <pubDate>Wed, 31 Oct 2018 06:30:50 +0900</pubDate>
    </item>
    <item>
      <title>Letter - Enhanced 스킨 공개.[Ver 1.52]</title>
      <link>https://black7375.tistory.com/50</link>
      <description>&lt;div&gt;* 공지: &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR', serif;&quot; class=&quot;&quot;&gt;Letter - Enhanced&lt;/span&gt;&lt;/b&gt; 버전 1.52를 공개합니다. &lt;br /&gt;&lt;/div&gt;&lt;div&gt;* 공지: 새로운 버전이 나왔으므로 전 버전에 대한 지원은 끊깁니다.&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/51&quot; target=&quot;_blank&quot;&gt;2018/10/31 - [IT] - Letter - Enhanced 스킨 공개.[Ver. 2.0]&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;개발 중인 스킨의 기능을 간단히 알고 싶다면,&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://black7375.tistory.com/51&quot; target=&quot;_blank&quot;&gt;2018/10/31 - [IT] - Letter - Enhanced  Ver. 2 프리뷰.&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;를 참고하세요.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990B85395BD9FF5E0C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990B85395BD9FF5E0C&quot; width=&quot;900&quot; height=&quot;214&quot; filename=&quot;Letter - Enhanced.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;h2 class=&quot;&quot;&gt;1. 제작 동기.&lt;/h2&gt;&lt;p&gt;티스토리에서 이번에 공개된 스킨 중 &lt;a href=&quot;https://www.tistory.com/skin/xf_Letter&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Letter&lt;/a&gt; 스킨이 마음에 들더라고요.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;처음엔 &lt;a href=&quot;https://www.tistory.com/skin/pg_Poster&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Poster&lt;/a&gt; 스킨을 써보려고 했는데 굵기가 다른 이상한 메뉴버튼과 못생긴 사이드바의 콜라보로 포기.. 글 내부 배치도 Letter가 더 낫드란.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 900px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994AA43F5BD9E85C03&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994AA43F5BD9E85C03&quot; width=&quot;900&quot; height=&quot;42&quot; filename=&quot;posterskin1.PNG&quot; filemime=&quot;image/png&quot; original=&quot;yes&quot;/&gt;&lt;span class=&quot;cap1&quot; style=&quot;display: block; max-width:100%; &quot;&gt;요개 젤 큰 이유였다.ㅋㅋ&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;덕분에 슬슬 질려가던 #2에서 Letter로 스킨을 변경!!&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그런데 일부 폰트, 인용에 대한 불만과 수식기능, 코드 하이라이트 기능이 미지원 때문에 스킨을 수정하게 되었습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그 이름은 &lt;b&gt;&lt;span style=&quot;font-family: &amp;quot;Noto Serif KR&amp;quot;, serif; font-size: 18pt;&quot; class=&quot;&quot;&gt;Letter - Enhanced&lt;/span&gt;&lt;/b&gt;!!&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;혹시 필요하신 분들이 있을까봐 공유해봅니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;* 파일은 4번 문항에 있습니다. '&lt;a href=&quot;#file_attach&quot; name=&quot;back&quot;&gt;파일 첨부&lt;/a&gt;'를 눌러 이동!!&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;* 파이어폭스를 기준으로 변경했습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR', serif;&quot; class=&quot;&quot;&gt;Letter - Enhanced&lt;/span&gt;&lt;/b&gt;는 기존 Letter 스킨의 심플함은 간직하면서 더 나은 느낌과 기능을 추구합니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;현대적이면서 적당히 클래식하여 종이보는 느낌 정도?&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;디자인시 주로 참조하고 있는 서비스는 &lt;a href=&quot;https://medium.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;미디움&lt;/a&gt;, &lt;a href=&quot;https://brunch.co.kr/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;브런치&lt;/a&gt;, &lt;a href=&quot;https://exposure.co/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;익스포저&lt;/a&gt;, &lt;a href=&quot;https://www.instapaper.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;인스타페이퍼&lt;/a&gt; 등이 있습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;기타: &lt;a href=&quot;https://jekyllrb-ko.github.io/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;지킬&lt;/a&gt;, &lt;a href=&quot;https://ko.wordpress.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;워드프레스&lt;/a&gt;, &lt;a href=&quot;https://www.tumblr.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;텀블러&lt;/a&gt;, &lt;a href=&quot;https://www.silvrback.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;실버백&lt;/a&gt;, &lt;a href=&quot;https://post.naver.com&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;네어버 포스트&lt;/a&gt;, &lt;a href=&quot;https://black7375.tistory.com/m&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;티스토리 모바일&lt;/a&gt; 정도?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;특히 익스포저랑 인스타페이퍼가 넘나 취향저격.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;기술적인 것이나 각종 코드 스니펫의 경우 &lt;a href=&quot;https://developer.mozilla.org&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;MDN&lt;/a&gt;, &lt;a href=&quot;https://css-tricks.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;CSS-Tricks&lt;/a&gt;, &lt;a href=&quot;https://www.w3schools.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;W3Schools&lt;/a&gt;를 참고하고 있습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;다 만들기는 넘 귀찮;;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;참고로 티스토리에서 &lt;a href=&quot;https://notice.tistory.com/2451&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;구형 브라우저는 지원하지 않기&lt;/a&gt;로 했고 제 스킨 또한 앞으로도 지원하지 않을 예정입니다.&lt;/p&gt;
&lt;p&gt;이점 유의해주십시오.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;2. 주요 변경점.&lt;/h2&gt;&lt;h3&gt;2.1 폰트 변경.&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;Lato와 맑은고딕 기반에서 Noto Sans(본고딕)으로 옮겼습니다.&lt;/p&gt;
&lt;p&gt;개인적으로 산돌 고딕 Neo1을 좋아하지만 상용폰트라 사용은 못하고..&lt;/p&gt;Noto Sans를 사용했습니다.&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;비교해보죠.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;style&gt;
@import url('https://fonts.googleapis.com/css?family=Lato');
&lt;/style&gt; 
&lt;p class=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 14pt; font-family: Lato, lato;&quot;&gt;Lato.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 14pt; font-family: Lato, lato;&quot;&gt;Bright vixens jump; dozy fowl quack.&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 14pt; font-family: 맑은 고딕, Malgun Gothic;&quot;&gt;맑은고딕&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;span style=&quot;font-size: 14pt; font-family: 맑은 고딕, Malgun Gothic;&quot;&gt;동틀 녘 햇빛 포개짐. &lt;/span&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;span style=&quot;font-size: 14pt; font-family: 맑은 고딕, Malgun Gothic;&quot;&gt;Bright vixens jump; dozy fowl quack.&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;Noto Sans.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;동틀 녘 햇빛 포개짐. &lt;/span&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;Bright vixens jump; dozy fowl quack.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;가독성이 좋아집니다.ㅎㅎ&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 class=&quot;&quot;&gt;2.2 폰트 렌더링 옵션.[Ver. 1.5 Bugfix]&lt;/h3&gt;&lt;p&gt;제가 만든 유저 스타일에서 적용했던 폰트 렌더링 + Calibre(이북리더)에서 사용하는 설정 일부를 적용했습니다.&lt;br /&gt;&lt;/p&gt;
 &lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/178792994180&quot; data-did=&quot;e7ea53cf85733635f9e3319531105bb4fff28e87&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/178792994180/readable-font-more-pretty&quot;&gt;https://black7375.tumblr.com/post/178792994180/readable-font-more-pretty&lt;/a&gt;&lt;/div&gt;  &lt;script async=&quot;&quot; src=&quot;https://assets.tumblr.com/post.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;차례대로 적용 전, 후 사진.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994AEB485BCDC6C817&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994AEB485BCDC6C817&quot; width=&quot;800&quot; height=&quot;398&quot; filename=&quot;font_render1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F9F8445BCDC6C91B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F9F8445BCDC6C91B&quot; width=&quot;800&quot; height=&quot;398&quot; filename=&quot;font_render-2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;살짝 두꺼워진듯한 느낌이 납니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;코드.&lt;br /&gt;&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code class=&quot;css&quot;&gt;body, input&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -webkit-text-stroke-width: 0.02px !important;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -webkit-font-smoothing: antialiased !important;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; text-shadow: 0px 0px 0.001px #ACACAC !important;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; text-align:justify;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; text-justify:inter-cluster;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; text-rendering: optimizeLegibility;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;Ver. 1.5&lt;/b&gt;: 일부 !important를 제거하였습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 class=&quot;&quot;&gt;2.3 인용구.&lt;/h3&gt;&lt;p&gt;원래 이런 느낌이었던 인용구를&lt;/p&gt;
&lt;blockquote class=&quot;none&quot;&gt;&lt;p&gt;동틀 녘 햇빛 포개짐.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;Bright vixens jump; dozy fowl quack.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이렇게 바꾸었습니다.&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;동틀 녘 햇빛 포개짐.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;Bright vixens jump; dozy fowl quack.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://css-tricks.com/snippets/css/simple-and-nice-blockquote-styling/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Simple and Nice Blockquote Styling&lt;/a&gt;을 참고했습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;아무래도 인용은 명조(세리프)가 좋죠?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.4 수식.&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://www.mathjax.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Mathjax&lt;/a&gt;를 사용하여 '$$'사이에 LaTeX 수식이 있으면 바꾸어주도록 했습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* &quot;AMSmath.js&quot;, &quot;AMSsymbols.js&quot;, &quot;color.js&quot;, &quot;mhchem.js&quot;을 추가기능으로 설정했습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예1.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$$
\LaTeX \\
is\, a\, document\, preparation\, system \\
$$
$$
\begin{align}
E &amp;amp;= mc^2 \\
m &amp;amp;= \frac{m_0}{\sqrt{1-\frac{v^2}{c^2}}}
\end{align}
$$&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;latex&quot;&gt;$$ \LaTeX \\ is\, a\, document\, preparation\, system \\ $$ $$ \begin{align} E &amp;amp;= mc^2 \\ m &amp;amp;= \frac{m_0}{\sqrt{1-\frac{v^2}{c^2}}} \end{align} $$ &lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;&quot;&gt; &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예2.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$$\ce{C6H5-CHO}&lt;br /&gt;\ce{$A$ -&amp;gt;[\ce{+H2O}] $B$}&lt;br /&gt;\ce{SO4^2- + Ba^2+ -&amp;gt; BaSO4 v}$$&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;latex&quot;&gt;$$\ce{C6H5-CHO}
\ce{$A$ -&amp;gt;[\ce{+H2O}] $B$}
\ce{SO4^2- + Ba^2+ -&amp;gt; BaSO4 v}$$&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예3.&lt;/p&gt;
&lt;p&gt;인라인 기능도 제공합니다. '$'으로 쌍으로 감싸면 &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;글 중간에 $f:X \rightarrow Y$처럼 적용.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 class=&quot;&quot;&gt;2.5 코드 하이라이트.[Ver. 1.5 Add]&lt;/h3&gt;&lt;p&gt;위에서 본것처럼 코드들의 하이라이트를 제공합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;사용법은&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&quot;언어이름&quot;&amp;gt;
코드..
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;문단안에서도 'code'태그를 사용하면 인라인 코드&lt;code&gt;inline code&lt;/code&gt;를 입력할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;언어이름은 &lt;a href=&quot;https://highlightjs.readthedocs.io/en/latest/css-classes-reference.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Highlight.js&lt;/a&gt;를 참고.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;따로 적지 않으면 자동으로 적용됩니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;Ver 1.5&lt;/b&gt;:&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;긴 코드는 자동 줄바꿈이 아니라 가로 스크롤바로 볼 수 있게 바뀌었습니다.(수식 참고)&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996F13485BD0469B2D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996F13485BD0469B2D&quot; width=&quot;800&quot; height=&quot;456&quot; filename=&quot;math.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;한줄로 이어진 코드가 예전엔 이렇게 나왔었죠.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 class=&quot;&quot;&gt;2.6 메뉴 버튼 이동.[Ver 1.5 Add @베누시안]&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://notice.tistory.com/2460?category=110385&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;티스토리 공지&lt;/a&gt;를 보다가 좋은 기능을 발견해서 추가하게 되었습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;메뉴의 'X' 버튼의 위치를 다음과 같이 바꾸게 됩니다.(전후)&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C6B5405BD0192112&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C6B5405BD0192112&quot; width=&quot;800&quot; height=&quot;266&quot; filename=&quot;Menu x - 1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996DA9365BD019210B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996DA9365BD019210B&quot; width=&quot;800&quot; height=&quot;265&quot; filename=&quot;Menu x - 2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;3. 기타 변경점.&lt;/h2&gt;&lt;p class=&quot;&quot;&gt;자잘한 변경 사항들입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 아티클 이미지 보기 옵션 수정(width: 100%; max-width: 100%;&amp;nbsp; height: auto !important;).&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 마우스로 글 드래그시 청녹색(#007878)을 띄게함.[아쿠아 스킨과 어울리게!!]&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 메타 컬러 지정.(#EB531F 티스토리 상징인 주황색)&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 로봇 지정(&quot;noindex, nofollow&quot; $\rightarrow$ &quot;ALL&quot;)[처음 발견시 수정했었는데 &lt;a href=&quot;https://notice.tistory.com/2460?category=110385&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;지금은 &quot;ALL&quot;을 기본으로 수정이 되었다고 합니다.&lt;/a&gt;]&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- index.xml 정보 수정[&lt;b&gt;Ver. 1.5&lt;/b&gt;]&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- skin.html을 2018.10.24 기준으로 업데이트[&lt;b&gt;Ver. 1.5&lt;/b&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 중복된 코드 제거(.category_list .list_horizontal .thumbnail_post)[&lt;b&gt;Ver. 1.5&lt;/b&gt;]&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 본문에서 표를 자동으로 가운데 정렬.[&lt;b&gt;Ver. 1.5&lt;/b&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 댓글 잘림 현상 해결(.category_content_area .list_reply li)[&lt;b&gt;Ver. 1.5 @베누시안&lt;/b&gt;]&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- CREDITS 파일 추가(컨트리뷰터들 표시)[&lt;b&gt;Ver. 1.5&lt;/b&gt;]&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- LICENSE 파일 추가(MIT)[&lt;b&gt;Ver. 1.5&lt;/b&gt;]&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 일부 버그 픽스(.area_menu .btn_menu)[&lt;b&gt;Ver. 1.52&lt;/b&gt;]&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;4. &lt;a href=&quot;#back&quot; name=&quot;file_attach&quot;&gt;파일 첨부&lt;/a&gt;.&lt;/h2&gt;&lt;h4&gt;Ver. 1.0&lt;/h4&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block;   height: auto; max-width: 100%;&quot;&gt;&lt;a href=&quot;https://t1.daumcdn.net/cfile/tistory/9986193C5BCE18DC0A&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;https://i1.daumcdn.net/cfs.tistory/v/0/blog/image/extension/zip.gif&quot; style=&quot;vertical-align: middle;&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;Letter - Enhanced(2018-10-23).zip&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;라이센스: MIT(원래 Letter 라이센스와 같습니다.)&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;Ver. 1.52 &lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block;   height: auto; max-width: 100%;&quot;&gt;&lt;a href=&quot;https://t1.daumcdn.net/cfile/tistory/99928E3B5BD03F563A&quot;&gt;&lt;img alt=&quot;&quot; src=&quot;https://i1.daumcdn.net/cfs.tistory/v/0/blog/image/extension/zip.gif&quot; style=&quot;vertical-align: middle;&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;Letter - Enhanced(2018-10-24).zip&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;따로 수정하고 싶으신 분들은 깃허브에서 포크하시면 됩니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;좋은 기능이나 버그 패치를 만들어 풀리퀘스트(Pull Request)해주시면 아주 좋아하고, CREDIT 목록에 넣어드립니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;베타 버전(?) 또한 사용해볼 수 있어요.&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;embedly-card&quot;&gt;&lt;h4&gt;&lt;a href=&quot;https://github.com/black7375/Letter-Enhanced&quot;&gt;black7375/Letter-Enhanced&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Tistory's Letter Skin + Font setting, Pretty Blockquote, Math &amp;amp; Code highlighting - black7375/Letter-Enhanced&lt;/p&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;//cdn.embedly.com/widgets/platform.js&quot; charset=&quot;UTF-8&quot;&gt;&lt;/script&gt;
&lt;p class=&quot;&quot;&gt;수정이 필요한 것이 있으면 댓글로 알려주세요~&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;검토 후 적용을 고려해보겠습니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;5. 스킨 적용하기.&lt;/h2&gt;&lt;h3&gt;5.1 다운 받고 압축풀기.&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;첨부되어 있는 파일이나 깃허브에서 파일을 받아 압축을 풉니다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D052365BD01F4A19&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D052365BD01F4A19&quot; width=&quot;800&quot; height=&quot;234&quot; filename=&quot;skin install0.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 class=&quot;&quot;&gt;5.2 스킨 등록하기.&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;블로그 관리의 '꾸미기-스킨 변경' 메뉴에서 '스킨 등록'을 누릅니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F76B465BD01C8D19&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F76B465BD01C8D19&quot; width=&quot;800&quot; height=&quot;507&quot; filename=&quot;skin install1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;'추가' 버튼을 누른 뒤&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9948704A5BD03E8C2D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9948704A5BD03E8C2D&quot; width=&quot;800&quot; height=&quot;648&quot; filename=&quot;skin install1.2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;폴더를 제외하고 모두 선택합니다.&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BEB2405BD03D8F0C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BEB2405BD03D8F0C&quot; width=&quot;800&quot; height=&quot;392&quot; filename=&quot;skin install2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;한번 더 '추가'를 눌러 이미지 폴더 내부의 것들을 모두 업로드 합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999038465BD03EA331&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999038465BD03EA331&quot; width=&quot;800&quot; height=&quot;474&quot; filename=&quot;skin install2.5.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;'저장' 버튼을 누릅니다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E6B5335BD021751E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E6B5335BD021751E&quot; width=&quot;800&quot; height=&quot;648&quot; filename=&quot;skin install3.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;적당한 이름을 지어줍니다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 407px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F8CF355BD021750E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F8CF355BD021750E&quot; width=&quot;407&quot; height=&quot;323&quot; filename=&quot;skin install4.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;/p&gt;&lt;h3&gt;5.3 스킨 적용하기.&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;블로그 관리의 '꾸미기-스킨 변경' 메뉴에서 '스킨 목록'을 고른뒤 저장해 놓았던 스킨을 클릭합니다.&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994C60365BD022BC28&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994C60365BD022BC28&quot; width=&quot;800&quot; height=&quot;491&quot; filename=&quot;skin install5.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그러면 팝업과 함께 '적용'이 나오는데 버튼을 누르면 됩니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B1DE495BD022F515&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B1DE495BD022F515&quot; width=&quot;800&quot; height=&quot;309&quot; filename=&quot;skin install6.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;5.6 추가 사항.&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;아참.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR', serif;&quot; class=&quot;&quot;&gt;Letter - Enhanced&lt;/span&gt;&lt;/b&gt; 스킨은 모바일에서도 볼 수 있어요.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;모바일에서 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR', serif;&quot; class=&quot;&quot;&gt;Letter - Enhanced&lt;/span&gt;&lt;/b&gt;를 사용하려면 다음과 같이 하면 됩니다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;블로그 관리의 '모바일'에 들어가 티스토리 모바일웹 자동연결을 '사용하지 않습니다.'로 바꾸어 주고 변경 사항을 적용하면 됩니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DF34345BD0263526&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DF34345BD0263526&quot; width=&quot;800&quot; height=&quot;649&quot; filename=&quot;skin install7.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;앞으로도 이쁜 스킨들을 티스토리에서 만나볼 수 있다면 좋겠네요.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;-끝-&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Web</category>
      <category>CSS</category>
      <category>HTML</category>
      <category>web</category>
      <category>배포</category>
      <category>스킨</category>
      <category>티스토리</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/50</guid>
      <comments>https://black7375.tistory.com/50#entry50comment</comments>
      <pubDate>Tue, 23 Oct 2018 00:30:30 +0900</pubDate>
    </item>
    <item>
      <title>Web과 OS의 통합.</title>
      <link>https://black7375.tistory.com/49</link>
      <description>&lt;h2&gt;0. Prolog.&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;Web과 OS 통합.&lt;/p&gt;&lt;p&gt;이 주제는 &lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992AB54D5BBE72D608&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992AB54D5BBE72D608&quot; width=&quot;820&quot; height=&quot;592&quot; filename=&quot;pixel slate.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Pixel 3 XL + Pixel Slate[from &lt;a href=&quot;https://store.google.com/us/product/pixel_slate&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Google Strore&lt;/a&gt;]&lt;/p&gt;&lt;p&gt;구글이 공개한 픽셀 슬레이트를 보고 생각나서 시작했습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아.. 다른 것도 정리해야 하는데 일만 치고 있네..&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1. Chrome OS.&lt;/h2&gt;&lt;p&gt;역시 웹과 OS의 통합이라 하면, 구글이 만든 Chrome OS이 본좌라 들었다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;내가 크롬북을 가지고 있지 않기 때문에 Chrome OS를 직접 써볼 수는 없고, Chromium OS 기반인 Cloudready를 써봤다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Chromium OS와 Chrome OS의 차이는 아래에서 참고하고,&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;embedly-card&quot;&gt;&lt;h4&gt;&lt;a href=&quot;https://poin2.co.kr/blog/8219&quot;&gt;Chromium OS와 Chrome OS의 차이점&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;종종 웹서핑을 하다보면 오래된 윈도우 랩탑을 크롬북으로 만들기 라는 글을 마주치게 됩니다. 보통 Neverware의 Cloudready를 설치하는 방법을 소개하는 글인데요, 이 때 실제로 설치되는 OS는 Chromium OS 입니다. 크로미움, 크롬, 뭔가 이름은 비슷한데 말이죠. 그럼 Chromium과 Chrome OS는 무엇이 다른걸까요? Chromium OS는 개발자들이 참여하는 오픈 소스 프로젝트이며 Chrome OS의 기반이 됩니다.&lt;/p&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;//cdn.embedly.com/widgets/platform.js&quot; charset=&quot;UTF-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;&lt;br /&gt; &lt;/p&gt;&lt;p&gt;우선 USB에 &lt;a href=&quot;https://www.neverware.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Chromium OS&lt;/a&gt;를 구웠다.&lt;/p&gt;&lt;p&gt;이 과정에서 OS 설치용으로 쓰던 4GB짜리 USB가 파티션 오류가 났나 미디어 없음 상태가 뜨면서 사망하였다.&lt;/p&gt;&lt;p&gt;전에 비슷한 경험을 한적 있어서 &lt;a href=&quot;https://answers.microsoft.com/ko-kr/windows/forum/windows_7-hardware/usb/6835cb84-0c5c-e011-8dfc-68b599b31bf5?messageId=b7cb5265-345c-e011-8dfc-68b599b31bf5&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Diskpart&lt;/a&gt;, &lt;a href=&quot;http://hddguru.com/software/HDD-LLF-Low-Level-Format-Tool/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Low Fommat&lt;/a&gt;이나 &lt;a href=&quot;https://www.partitionguru.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;파티션 복구&lt;/a&gt;를 시도해봤는데 Diskpart에선 clean이 안되고 나머지 툴에선 아예 나타나질 않음..&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;여러분 꼬옥 8~16GB짜리 USB를 사용하세요 ㅠㅠㅠㅠㅠ&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;암튼 USB를 통해 Live Booting을 해보았습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;대충 이런식으로 생겼습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9929494F5BBE808223&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9929494F5BBE808223&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;ChromeOS.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DCAF505BBE80821E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DCAF505BBE80821E&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;ChromeOS2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.1 OS 기본 기능.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;일단 기본적인 로그아웃 패널, 다운로드 매니저, 알림 등 기본 OS 기능은 가지고 있었습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E297505BBE77D10F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E297505BBE77D10F&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;Account.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D66B4D5BBE77D112&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D66B4D5BBE77D112&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;Alarm1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9969AD505BBE77D10B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9969AD505BBE77D10B&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;Alarm2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 작업창 전환, 에어로 스냅등 윈도우 관련 기능도 있었습니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99EFEB4F5BBE77D006&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99EFEB4F5BBE77D006&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;Taskwindow.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A6D13C5BBE78C111&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A6D13C5BBE78C111&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;Snap.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;윈도우 관련 기능중 특이했던 거라면, 크롬을 연속으로 열면 이쁘게 겹치도록 띄워진다는것 정도?&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99569F495BBE78C112&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99569F495BBE78C112&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;AutoWindow.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;마지막으로 작업창은 다음과 같이 앱목록으로 전환할 수 있었습니다.&lt;/p&gt;&lt;p&gt;처음 누르면 검색창과 함께 최근 이벤트를 가진앱(설치, 실행 등)이 표시되고, 목록을 펼치면 앱목록이 표시되는 형식이었습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992B31425BBE797812&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992B31425BBE797812&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;TaskBar1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99AB354B5BBE79D315&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99AB354B5BBE79D315&quot; width=&quot;820&quot; height=&quot;513&quot; filename=&quot;chrome-os-launcher.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;앱목록[from &lt;a href=&quot;https://www.droid-life.com/2017/07/07/chrome-os-getting-sweet-touch-friendly-launcher/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Chrome OS is Getting a Sweet Touch-Friendly Launcher&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;까먹어서 앱목록은 퍼왔습니다.&lt;/p&gt;&lt;p&gt;제가 쓴 버전의 앱목록엔 최근 이벤트 앱라인이 상단에 위치해있었습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p&gt;어쨌든 Chromium OS는 OS가 가지고 있을만한 기본 기능들은 가지고 있었습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.2 Web과 통합 기능.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;그럼 어떠한 방식으로 Web과 OS의 통합이 이루어졌는지 알아봅시다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;1.2.1 파일 브라우저.&lt;br /&gt;&lt;/h4&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99683E3D5BBE7C2F19&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99683E3D5BBE7C2F19&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;Fullmode.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;파일앱이 구글 드라이브+다운로드, 다른 파티션 보기로 이루어져 있습니다.&lt;/p&gt;&lt;p&gt;기본적으로는 구글 드라이브와 다운로드 폴더를 이용해야 한다는 뜻입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일반적인 파일은 모두 구글 드라이브에 저장하고, 다운로드 해야할 필요가 있는 파일만 '다운로드' 폴더에 저장한다는 뜻입니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;또 구글 드라이브에서 봤을만한 추가기능 기능을 제공해줍니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9991D24D5BBE810515&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9991D24D5BBE810515&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;Addon.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;1.2.2 크롬 기능.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;기본적인 OS 기능 + 크롬이 컨셉인 OS다보니 웹브라우저 기능과 통합된 부분이 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;보통의 OS에서는 웹페이지는 프로세스로 보여주지 않는 것과 달리 크롬의 작업관리자를 사용하면 웹페이지, 확장기능, 어플리케이션의 상태를 한눈에 확인할 수 있습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9948F9505BBE7DF717&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9948F9505BBE7DF717&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;Manage.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 캡쳐 기능도 크롬의 단축키와 똑같았습니다.&lt;/p&gt;&lt;p&gt;또한 프로그램의 확장자에 따라 구글 Docs를 연결해주기도 하고, MS Office Online을 연결해주기도 하는 등 웹브라우저를 이용해서 각종 작업을 할 수 있었습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;1.2.3 웹앱.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;&lt;b&gt;- 스토어 웹 앱.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;크롬 스토어에 테마나 확장기능만이 아니라 앱 항목이 추가되어 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;크롬 스토어 스크린샷 찍는 것도 깜박해서 생략.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;대신 설치했던 앱들 화면을 보여주는 걸로.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993F8B395BBE81511C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993F8B395BBE81511C&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;Apps.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;- 웹앱 만들기.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아까 Chrome 작업 관리자에서 각 웹페이지를 마치 앱처럼 취급한다는 말을 한적이 있죠?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://poin2.co.kr/blog/3757&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;자주 가는 사이트 앱 형태로 사용하기 (작업표시줄 바로가기)&lt;/a&gt;를 보면 간단하게 웹앱을 만들 수 있습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99881B485BBE82B227&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99881B485BBE82B227&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;add0.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 802px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994A8F475BBE82B225&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994A8F475BBE82B225&quot; width=&quot;802&quot; height=&quot;623&quot; filename=&quot;add1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996D6A3C5BBE82B31F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996D6A3C5BBE82B31F&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;add2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 웹앱은 아래 스크린 샷처럼 보여지는 웹페이지를 따로 확인하고 전환할 수 있습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BFD1395BBE82D721&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BFD1395BBE82D721&quot; width=&quot;820&quot; height=&quot;461&quot; filename=&quot;Youtube.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;2. 기존 OS 웹 통합.&lt;/h2&gt;&lt;p&gt;그럼 Chrome OS에서 웹 통합이란 장점만 어떻게 기존 OS에서 취할 수 있을까요?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.1 클라우드 동기화 프로그램.&lt;/h3&gt;&lt;p&gt;&lt;b&gt;- 공식 프로그램 사용.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;클라우드를 운영하는 대부분 회사들은 예를들어 Onedrive, Dropbox, Google Drive등은 공식적으로 동기화 프로그램을 제공합니다.&lt;/p&gt;&lt;p&gt;동기화 프로그램을 사용하면 크롬 OS만큼은 아니더라도 원활하게 클라우드에 있던 파일을 가져올 수 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991B6E485BBE96FB1B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991B6E485BBE96FB1B&quot; width=&quot;820&quot; height=&quot;555&quot; filename=&quot;adobe drive.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;b&gt;
&lt;/b&gt;&lt;p&gt;&lt;b&gt;- 통합 동기화 프로그램 사용.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.odrive.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Odrive&lt;/a&gt;, &lt;a href=&quot;https://www.goodsync.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Goodsync&lt;/a&gt;, &lt;a href=&quot;https://www.raidrive.com/ko/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Raidrive&lt;/a&gt;등을 사용하면 다양한 클라우드의 파일을 통합적으로 동기화 할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.2 웹앱 통합.&lt;/h3&gt;&lt;p&gt;웹을 앱처럼 사용하려는 시도에 대해 서술합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;- &lt;a href=&quot;https://getwebcatalog.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Webcatalog&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일반적으로 제가 권장하는 것은 &lt;a href=&quot;https://getwebcatalog.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Webcatalog&lt;/a&gt; 입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;웹 카달로그는 윈도우, 맥, 리눅스 모두 지원하며 웹앱 스토어를 제공하고,&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9930CC355BBE8DA432&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9930CC355BBE8DA432&quot; width=&quot;820&quot; height=&quot;689&quot; filename=&quot;webapp - install.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;설치된 웹앱은 다음과 같이 일반 프로그램처럼 추가가 됩니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 340px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F57C385BBE8DA301&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F57C385BBE8DA301&quot; width=&quot;340&quot; height=&quot;134&quot; filename=&quot;webapp - new.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;또한 제가 Webcatalog를 좋게 보는 이유는 Juli란 사이트 특화 브라우저(Site-specific Browsers)를 제공하여 홈, 앞, 뒤로가기, 설정이란 옵션을 제공하기 때문입니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99EE7F3E5BBE965112&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99EE7F3E5BBE965112&quot; width=&quot;820&quot; height=&quot;616&quot; filename=&quot;webapp - flipboard.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;설정에서는 다크모드, 특화된 CSS 및 Javascript도 추가할 수 있어 유용성이 훨씬 커집니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9981C5425BBE8DA409&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9981C5425BBE8DA409&quot; width=&quot;820&quot; height=&quot;616&quot; filename=&quot;webapp - setting.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BAEC505BBE8F5409&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BAEC505BBE8F5409&quot; width=&quot;820&quot; height=&quot;616&quot; filename=&quot;webapp - setting2.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;단점으로는 광고 차단같은 부가기능을 사용할 수 없다는 점인데..&lt;/p&gt;&lt;p&gt;이건 Juli 브라우저의 강점을 포기한다면 파이어폭스나 크롬을 엔진으로 사용할 수 있습니다.ᅟ&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 앱을 2개 초과로 설치하려면 구매해야 한다는 점이 단점으로 적용될 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://webcatalog.onfastspring.com/webcatalog-lite&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;구매(가격: USD 5.49)&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;WebCatalog has 
permanent licenses, which have no time limit. In other words, the 
license never expires. Also, your license permits you to use the app on 
all of the devices you own, as long as you are the only one using the 
app.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;영구 라이센스에 모든 장치에서 사용할 수 있으니 하나쯤사는 것도 좋습니다.&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;- &lt;a href=&quot;https://github.com/jiahaog/nativefier&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Nativefier&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;또 다른 대안으론 &lt;a href=&quot;https://github.com/jiahaog/nativefier&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Nativefier&lt;/a&gt;가 존재합니다. 역시 윈도우/맥/리눅스 다 지원합니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992634445BBE94380A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992634445BBE94380A&quot; width=&quot;820&quot; height=&quot;493&quot; filename=&quot;walkthrough.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;작동화면[from &lt;a href=&quot;https://github.com/jiahaog/nativefier&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Nativefier&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;&lt;p&gt;설치는&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install nativefier -g&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;로 할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;다만 단점이 여러가지 있습니다.&lt;/p&gt;&lt;p&gt;GUI가 없고 명령어(CUI) 방식이라는 겁니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;웹앱 설치 명령어.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nativefier &quot;http://medium.com&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;또는&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nativefier --name &quot;Some Awesome App&quot; &quot;http://medium.com&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;처럼 할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;둘째는 쓸데없는 것이 많이 깔린다는 겁니다.&lt;/p&gt;&lt;p&gt;위 코드를 실행하면 아래처럼 폴더가 생성되는데&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9925903D5BBE97662B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9925903D5BBE97662B&quot; width=&quot;820&quot; height=&quot;515&quot; filename=&quot;webapp - nativefier installed2.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;폴더에 들어가면 많은 파일이 존재하고 용량을 잡아먹습니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995D27395BBE976617&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995D27395BBE976617&quot; width=&quot;820&quot; height=&quot;440&quot; filename=&quot;webapp - nativefier installed.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;약 120MB정도 되는데 간단한 웹앱이 120MB나 잡아먹는 것은 용량 낭비중의 낭비입니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 543px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9967E83E5BBE9AA327&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9967E83E5BBE9AA327&quot; width=&quot;543&quot; height=&quot;728&quot; filename=&quot;webapp - nativefier installed3.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Webcatalog는 2~3KB의 작은 용량에&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 543px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BE8B385BBE9C5E2C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BE8B385BBE9C5E2C&quot; width=&quot;543&quot; height=&quot;771&quot; filename=&quot;webcatalog - installed.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;바로가기가 생성되어 일정한 옵션에 따라 브라우저를 호출하는 구조입니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 543px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993F214B5BBE9C5E30&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993F214B5BBE9C5E30&quot; width=&quot;543&quot; height=&quot;771&quot; filename=&quot;webcatalog - installed2.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그런다고 시작이나 어플리케이션 폴더에 등록을 해주거나 특별한 UI나 설정을 제공해주는 것도 아니니 뭐...(물론 플래시, CSS, Javascript정도는 설정 가능합니다) &lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992913335BBE976620&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992913335BBE976620&quot; width=&quot;820&quot; height=&quot;513&quot; filename=&quot;webapp - nativefier.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;암튼 결론은 그냥 6천원 정도 내고 Webcatalog를 사는게 정신건강에 좋다는 말..&lt;/p&gt;&lt;p&gt;하.. 협찬받는 것도 아닌데 광고하고 있네&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;- 기타.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;맥에서는 &lt;a href=&quot;https://fluidapp.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Fluid&lt;/a&gt;, 리눅스에서는 &lt;a href=&quot;https://peppermintos.com/guide/ice/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Ice&lt;/a&gt;(&lt;a href=&quot;https://github.com/peppermintos/ice&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;깃허브&lt;/a&gt;)도 고려해볼 수도 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Fluid&lt;br /&gt;&lt;/p&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/He7MkP3SxAs&quot; width=&quot;560&quot; height=&quot;315&quot; allow=&quot;autoplay; encrypted-media&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Ice&lt;/p&gt;&lt;p&gt;Webcatalog와 거의 비슷한 기능을 제공해줍니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996D364A5BBE934707&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996D364A5BBE934707&quot; width=&quot;820&quot; height=&quot;445&quot; filename=&quot;ice-1.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 593px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99594E415BBE93470B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99594E415BBE93470B&quot; width=&quot;593&quot; height=&quot;377&quot; filename=&quot;ice-3.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 593px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998F74375BBE934711&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998F74375BBE934711&quot; width=&quot;593&quot; height=&quot;377&quot; filename=&quot;ice-4.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 388px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B05C495BBE934710&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B05C495BBE934710&quot; width=&quot;388&quot; height=&quot;474&quot; filename=&quot;ice-5.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Ice[from &lt;a href=&quot;https://peppermintos.com/guide/ice/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Peppermint OS&lt;/a&gt;&lt;a href=&quot;https://peppermintos.com/guide/ice/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;]&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Webcatalog, Nativefier, Fluid를 비교하려면 &lt;a href=&quot;https://github.com/quanglam2807/webcatalog/wiki/Comparison-Tablehttps://github.com/quanglam2807/webcatalog/wiki/Comparison-Table&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;깃허브&lt;/a&gt;를 확인해 봅시다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;3. 맺음말&lt;/h2&gt;&lt;p&gt;기타 구글 서비스 사용과 아쉬운점은 크롬 사용과 일반 어플리케이션들로 대체할 수 있습니다.&lt;/p&gt;&lt;p&gt;이 정도면 Chrome OS가 아닌 다른 OS에서 웹과의 통합도 나쁜 정도는 아닐거 같네요.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;-끝-&lt;br /&gt;&lt;/p&gt;</description>
      <category>IT/UX</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/49</guid>
      <comments>https://black7375.tistory.com/49#entry49comment</comments>
      <pubDate>Thu, 11 Oct 2018 09:48:11 +0900</pubDate>
    </item>
    <item>
      <title>Windows UX 향상 프로젝트.</title>
      <link>https://black7375.tistory.com/48</link>
      <description>&lt;script async=&quot;&quot; src=&quot;//cdn.embedly.com/widgets/platform.js&quot; charset=&quot;UTF-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;요즘 심심해서 해보는 플젝.&lt;/p&gt;&lt;p&gt;사용 환경을 향상 시키는 각종 유틸리티, 트윅, 어플리케이션 등을 소개 및 추천한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;쓰려는 강좌는 안쓰고 오늘도 뻘짓하고 있다..&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;앞으로 맥, 리눅스도 작성할 계획이니 잘 봐주세요!!&lt;/p&gt;&lt;p&gt;UX 향상 프로젝트 특성상 여러가지 프로그램이나 테마들을 소개할텐데&amp;nbsp;무료를 먼저 소개하고, 유료 프로그램들은 뒤에 배치할 예정입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;문서 업뎃은 하고 싶을때 가끔씩 ㅎㅋㅋ&lt;/p&gt;&lt;p&gt;귀찮으니 말투도 왔다갔다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일부 프로그램은 일반인들이 잘 안쓸만한 것도 있다.(관리용 모니터링 툴같은거)&lt;/p&gt;&lt;p&gt;그래서 강력 추천 하는 건 &lt;b&gt;[ 강추 ]&lt;/b&gt;, 일반인들이 안쓸만한 건 &lt;b&gt;[ 전문가 ]&lt;/b&gt; 라고 표시했다.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1. 기본앱 다크모드(Windows10) - 눈을 편하게.&lt;/h2&gt;&lt;p&gt;다크모드를 사용하면 전반적으로 눈이 편해지는 느낌이라 선호한다.&lt;/p&gt;choco install notepadplusplus -y
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설정.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;설정-개인설정-색에서 스크롤을 내려보면 기본 앱 모드 선택에서 어둡게를 선택하면 된다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_46233_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/996D35345B8CFFB81D&quot; width=&quot;820&quot; height=&quot;727&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;그럼 윈도우 기본앱들이 다크모드가 된다!!&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_96063_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/996E19475B8CFF0709&quot; width=&quot;820&quot; height=&quot;760&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;2. 정밀(프리시전) 터치패드(Windows10) - 터치패드 UX 향상. [ 강추 ]&lt;/h2&gt;&lt;p&gt;알만한 사람들은 모두 알듯이, 윈도우의 터치패드는 Mac OS에 비해&amp;nbsp;터치감도 별로고, 제스처&amp;nbsp;기능도 떨어진다.&lt;/p&gt;&lt;p&gt;그래서 정밀(프리시전) 터치패드 프로젝트를 엘란, 시냅틱스와 함께 시작했다.&lt;/p&gt;&lt;p&gt;두 업체는 대표적인 터치패드 제작 업체다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;embedly-card&quot;&gt;&lt;h4&gt;&lt;a href=&quot;http://www.itworld.co.kr/news/82694&quot;&gt;더 나은 윈도우용 터치패드 '프리시전 터치패드' 본격화&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;정말
 좋은 노트북들이 처참한 터치패드 때문에 이름을 더럽히는 경우가 많다는 것은 감안하면, 마이크로소프트가 이와 관련해 뭔가를 
시도하고 있다는 것은 반가운 소식이다. 최근 개최된 빌드 2013 컨퍼런스에서 프로그램 책임자 제임스 클라크는 프리시전 
터치패드(Precision Touchpad)란 새로운 구상을 소개했다. 마이크로소프트와 인텔, 그리고 주요 PC 업체에 터치패드 
기술을 제공하는 엘란(Elan)과 시냅틱스(Synaptics)가 손을 잡았다&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;정밀 터치패드 기능을 사용하면 스크롤 감도, 제스처 기능 활성화등 이득이 많다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b style=&quot;&quot;&gt;설정.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;우선 정밀 터치패드를 지원하는지 확인해보자.&lt;/p&gt;&lt;p&gt;설정-장치-터치패드에 들어가 정밀 터치패드를 지원한다는 문구가 뜨는지 확인한다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_39780_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/993F8C415B8D035735&quot; width=&quot;820&quot; height=&quot;727&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 다음과 같이 설정한다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_80557_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/997ADA425B8D042B21&quot; width=&quot;820&quot; height=&quot;727&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 두손가락으로 확대 축소를 하고 세 손가락으로 터치패드를 위, 아래, 양옆으로 움직여보자.&lt;/p&gt;&lt;p&gt;맥처럼 가상 데스크톱을 최대한 활용할 수 있게 된다!!&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;작업 보기는 아래 스크린 샷처럼 보여준다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_64195_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/998DEF3C5B8DADB312&quot; width=&quot;820&quot; height=&quot;461&quot;&gt;&lt;/p&gt;&lt;p&gt;현재 데스크톱의 프로그램 목록들과 데스크톱의 화면을 보여주고, 바탕화면 전환은 데스크탑 목록을 순환 할 수 있게 해준다. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;한번에 여러가지 프로그램을 키고 쓰는 스타일이라면 정말 유용한 기능.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;혹시 PC에 정밀 터치 패드가 있다는 문구가 뜨지 않는다고 하여 시무룩 할 필요가 없다.&lt;/p&gt;&lt;p&gt;강제로 활성화를 시키면 제스처 사용이 가능하다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;우선 제어판-하드웨어 및 소리-장치 및 프린터-장치 관리자에서 엘란(ELAN)인지&amp;nbsp;시냅틱스(Synaptics)인지 확인한다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_48604_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/9922ED425B8D060B1B&quot; width=&quot;820&quot; height=&quot;600&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고&lt;/p&gt;&lt;p&gt;ELAN: &lt;a href=&quot;https://support.lenovo.com/us/ko/downloads/ds120858&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://support.lenovo.com/us/ko/downloads/ds120858&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Synaptics:&amp;nbsp;&lt;a href=&quot;https://support.lenovo.com/us/ko/downloads/ds104007&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://support.lenovo.com/us/ko/downloads/ds104007&lt;/a&gt;&lt;/p&gt;&lt;p&gt;에서 장치 제조사에 맞추어 다운받고 설치.&lt;/p&gt;&lt;p&gt;단, 설치경로는 '&lt;b&gt;미리&lt;/b&gt;' 기억(복사)해두어야 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;설치가 끝났다면 장치관리자에서 터치패드 장치를 우클릭 후&lt;/p&gt;&lt;p&gt;드라이버 업데이트-컴퓨터에서 드라이버 소프트웨어 검색-컴퓨터의 사용 가능한 드라이버 목록에서 직접 선택-디스크 있음-찾아보기에서&lt;/p&gt;&lt;p&gt;&amp;nbsp;ELAN: ETD.inf&lt;/p&gt;&lt;p&gt;Synaptics: synpd.inf&lt;/p&gt;&lt;p&gt;을 선택.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;재부팅을 하면 정밀 터치패드 옵션이 활성화 된다.&lt;/p&gt;&lt;p&gt;터치감이 좋아지는 것은 덤.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;3. &lt;a href=&quot;https://pooi.moe/QuickLook/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Quicklook&lt;/a&gt; - 미리보기. [ 강추 ]&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;Quicklook은 탐색기에서 미리보기를 제공하는 프로그램이다.&lt;br /&gt;이미지, PDF, 오피스, 마크다운 문서등을 탐색기에서 스페이스바를 누르면 미리볼 수 있다.(한번 더 누르면 닫힘)&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img id=&quot;tx_entry_64213_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/995AA44E5B8DB01E17&quot; width=&quot;410&quot; height=&quot;268&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;img id=&quot;tx_entry_83118_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/99858A4D5B8DB1B512&quot; width=&quot;410&quot; height=&quot;259&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img id=&quot;tx_entry_11651_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/9998A84B5B8DB07E19&quot; width=&quot;410&quot; height=&quot;381&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;img id=&quot;tx_entry_20643_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/99FAF43E5B8DB1B114&quot; width=&quot;410&quot; height=&quot;323&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;사진을 보면 알겠지만 기본기가 상당하다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설치.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.microsoft.com/ko-kr/p/quicklook/9nv4bs3l1h4s?ocid=badge&amp;amp;rtc=1&amp;amp;activetab=pivot%3aoverviewtab&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;스토어 버전&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/QL-Win/QuickLook/releases&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;다운로드&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;4. &lt;a href=&quot;https://github.com/File-New-Project/EarTrumpet&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;EarTrumpet&lt;/a&gt;(Windows10) - 볼륨 관리자.&lt;/h2&gt;&lt;p&gt;프로그램마다 소리를 제어할 수 있도록 해줍니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_83987_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/9998C4355B8DC2F30E&quot; style=&quot;width: 300px; height: 241px;&quot; width=&quot;300&quot; height=&quot;241&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설치.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.microsoft.com/ko-kr/p/eartrumpet/9nblggh516xp?activetab=pivot:overviewtab&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;스토어&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설정&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;EarTrumpet은 설치 후 기본으로 설정하고, 기존 소리 아이콘은 필요가 없어지므로 비활성화 시킵니다.&lt;br /&gt;작업표시줄 우클릭-작업표시줄 설정 또는 설정-개인설정-작업표시줄에서 알림 영역에 있는 작업 표시줄에 표시할 아이콘 선택에 들어가 기존의 볼륨은 끕니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_97425_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/99F89C3F5B8DC4FF05&quot; width=&quot;820&quot; height=&quot;727&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;5. &lt;a href=&quot;https://chocolatey.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Chocolatey&lt;/a&gt; - 또 다른 윈도우 스토어(패키지 매니저). [ 전문가 ]&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;Chocolatey는 PC에서도 스토어 기능(패키지 매니저) 기능을 하게 해주는 프로그램이다.&lt;/p&gt;&lt;p&gt;스마트폰을 사용해봐서 알겠지만 스토어 기능은 다양한 프로그램들을 검색 및 설치를 하고 한번에 업데이트 하도록 도와준다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그동안 중구난방이었던 프로그램 업데이트를 한곳에서 모아본다는 것에 큰 의의를 가집니다.&lt;/p&gt;&lt;p&gt;마이크로소프트 스토어보다 프로그램 양이 많은 듯.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설치.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;cmd.exe나 powershell.exe를 관리자 권한으로 실행 시킨뒤 [둘중 하나만 하면 됨]&lt;/p&gt;&lt;p&gt;아래 명령을 실행시켜 Chocolatey를 설치한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;- Cmd&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;cmd&quot;&gt;@&quot;%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe&quot; -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command &quot;iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))&quot; &amp;amp;&amp;amp; SET &quot;PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin&quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;- Powershell&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;ps&quot;&gt;Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;원래 chocolatey는 유닉스/리눅스 계열의 컴퓨터 전문가들이 편하게 사용하려고 만들어 놓은 것이므로 우리가 보통 생각하는 스토어 화면 대신 명령어로 입력해야 한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;명령어 대신 스토어 화면을 보고 싶은 사람은&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;cmd&quot;&gt;choco install chocolateygui -y&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;명령어를 입력하면&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_94347_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/9939AA425B8DB9E221&quot; width=&quot;820&quot; height=&quot;362&quot;&gt;&lt;/p&gt;&lt;p&gt;Chocolatey GUI란 이름으로 스토어 화면을 만나볼 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;패키지 매니저 사용할 줄 아는 사람은 어느때처럼&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;cmd&quot;&gt;choco --help&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;를 입력해서 사용법을 익히면 됨.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;6. &lt;a href=&quot;https://picpick.app/ko/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;픽픽(Pickpick)&lt;/a&gt; or &lt;a href=&quot;https://getsharex.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;ShareX&lt;/a&gt;- 캡처+그림판 대체.&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;캡처와 그림판 역할 뿐만 아니라 간단한 그래픽 도구까지 제공하는 완소템. MS 오피스와 UI가 비슷해 이질감도 전-혀 없다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://picpick.app/en/buy&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;외국&lt;/a&gt;에서는 $29.99를 받고 팔지만 특별히 한국어 버전은 기업 사용자에게까지(!) 무료로 뿌리는 프로그램이다.&lt;/p&gt;&lt;p&gt;퍄.. 감사합니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_34584_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/990863355B8DB63A1C&quot; width=&quot;820&quot; height=&quot;522&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_47164_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/99870B495B8DBD8F2F&quot; width=&quot;820&quot; height=&quot;491&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설치.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://picpick.app/ko/download&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;다운로드&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 외국에선 ShareX란 프로그램이 유명한 걸로 안다.&lt;/p&gt;&lt;p&gt;사실 캡처 기능만 따지고 보면 ShareX가 더 좋다. gif, ocr 기능도 되니..&lt;/p&gt;&lt;p&gt;Pickpick이 좋은 점은 간단한 편집 기능도 제공한다는 것.&lt;/p&gt;&lt;p&gt;캡처만 필요하면 ShareX 쓰자.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_19120_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/99F000495B8DB5FB22&quot; width=&quot;820&quot; height=&quot;452&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;물론 한국어도 지원한다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img id=&quot;tx_entry_42460_&quot; class=&quot;txc-image&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/99E1AC335B8DBF4936&quot; width=&quot;820&quot; height=&quot;396&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설치&lt;/b&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;cmd&quot;&gt;choco install sharex -y&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://getsharex.com/downloads/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;다운로드&lt;/a&gt;. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;7. &lt;a href=&quot;https://notepad-plus-plus.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Notepad++&lt;/a&gt; - 메모장 대용.&lt;/h2&gt;&lt;p&gt;Notepad++은 완벽한 메모장 대체 프로그램이다.&lt;br /&gt;탭으로 표시되는 텍스트창, 껐다 다시 키면 그대로 보여주는 기능이 일반 사용자에게 핵심이라 할 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;원래 코딩용으로 만들어진 에디터지만 그런 역할은 Visual Studio Code나 Emacs, Sublime Text에게 넘겨주고, 텍스트 보기와 간단한 텍스트 메모 역할을 하면 된다.(스크린 샷에서 new 라고 써진게 다 메모해둔것.)&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9960333C5B8FAF4935&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9960333C5B8FAF4935&quot; width=&quot;820&quot; height=&quot;517&quot; filename=&quot;notepad++.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설치.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://notepad-plus-plus.org/download/v7.5.8.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;다운로드.&lt;/a&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;cmd&quot;&gt;choco install notepadplusplus -y&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;8. &lt;a href=&quot;https://kr.bandisoft.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;반디집 &amp;amp; 꿀뷰&lt;/a&gt; - 성능좋은 압축 프로그램, 이미지 뷰어.&lt;/h2&gt;&lt;p&gt;반디 소프트의 프로그램들은 가볍고 빠르기로. 유명하죠&lt;br /&gt;&lt;/p&gt;&lt;p&gt;둘다 용량을 얼마 차지하지 않는 편입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt; 반디집은 멀티코어를 활용하여 빠른 압축을 자랑하고, alz나 egg 파일 지원, HiDPI(고해상도 모니터) 또한 지원해준다.&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9920874E5BAD04BE33&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9920874E5BAD04BE33&quot; width=&quot;820&quot; height=&quot;602&quot; filename=&quot;Bandizip.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;꿀뷰 역시 빠른 이미지 프로세싱이 장점이다. 또한 이미지 정보 표시 및 RAW 이미지 뷰어 기능이 있다.&lt;/p&gt;&lt;p&gt; &lt;br /&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;height: 242px;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 410px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99ED773B5BAD334324&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99ED773B5BAD334324&quot; width=&quot;410&quot; height=&quot;242&quot; filename=&quot;Honeyview - Meta.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;height: 242px;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 410px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A68F335BAD334824&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A68F335BAD334824&quot; width=&quot;410&quot; height=&quot;242&quot; filename=&quot;Honeyview - RAW.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;왼쪽 스크린샷을 보면 다양한 이미지 메타 정보를 보여주고, 오른쪽은 RAW 파일을 성공적으로 보여주고 있음을 알 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;* 사진은 &lt;a href=&quot;https://www.photographyblog.com/previews/nikon_d850_photos/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Nikon D850 Sample Images&lt;/a&gt;의 이미지를 사용했습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설치.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://kr.bandisoft.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;다운로드&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;cmd&quot;&gt;choco install bandizip -y
choco install honeyview -y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;9. &lt;a href=&quot;https://www.stardock.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Object Desktop&lt;/a&gt;(유료) - UX 향상 툴 모음. [ 강추 ]&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;이 문서를 만들게된 가장 큰 계기다.&lt;br /&gt;이번에 구매한 Object Desktop 소개는 내 텀블러 블로그에 올린 사용기로 대체한다.&lt;br /&gt;&lt;/p&gt;
 &lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/177685197975&quot; data-did=&quot;a10813575c5dfa1fb973940e5bb255a17e03cc49&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/177685197975/object-desktop-사용기&quot;&gt;https://black7375.tumblr.com/post/177685197975/object-desktop-사용기&lt;/a&gt;&lt;/div&gt;  &lt;script async=&quot;&quot; src=&quot;https://assets.tumblr.com/post.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설치&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.stardock.com/products/odnt/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;제품 소개 링크.&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설정.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Fences는 폴더는 폴더, 문서는 Files &amp;amp; Documents, 프로그램 바로가기는 Programs로 자동으로 가도록 설정해놨습니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995F3A375B8FA80924&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995F3A375B8FA80924&quot; width=&quot;820&quot; height=&quot;521&quot; filename=&quot;fences set.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Groupy는 Combine if possible 옵션으로 설정했습니다. &lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9973F73D5B8FA93F06&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9973F73D5B8FA93F06&quot; width=&quot;820&quot; height=&quot;521&quot; filename=&quot;groupy set1.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Combine if possible 옵션을 켜면, 1번째 사진처럼 지원하는 어플리케이션에 한해 기존 윈도우 창과 통합된 듯 조화롭게 보여줍니다.&lt;/p&gt;&lt;p&gt;깔끔하고 버리는 공간이 줄어들어 좋습니다.&lt;br /&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;height: 256px;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 410px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C0DD475B8FAA6B16&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C0DD475B8FAA6B16&quot; width=&quot;410&quot; height=&quot;256&quot; filename=&quot;groupy set1 RST.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;height: 256px;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 410px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99156F4F5B8FAA6E11&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99156F4F5B8FAA6E11&quot; width=&quot;410&quot; height=&quot;256&quot; filename=&quot;groupy set1 RST2.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 막 합쳐지는 것을 막기위해 Shift를 누르고 합치도록 해놨고, 웹브라우저처럼 탭을 마우스 휠버튼으로 끄도록 설정했습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999BD0355B8FAC4836&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999BD0355B8FAC4836&quot; width=&quot;820&quot; height=&quot;521&quot; filename=&quot;groupy set2.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;마지막으로 어플리케이션 그룹핑을 활성화해서 비슷한 종류의 프로그램은 자동으로 묶이게 설정했습니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C43F375B8FAC4819&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C43F375B8FAC4819&quot; width=&quot;820&quot; height=&quot;521&quot; filename=&quot;groupy set3.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;바탕화면이 깔끔해지는 Fences와 프로그램창이 깔끔해지는 Groupy는 Object Desktop에서 강력추천하는 프로그램!!&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;10. 커서 - KDE의 이쁜 커서&lt;br /&gt;&lt;/h2&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 293px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9976BB4F5D32D26429&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9976BB4F5D32D26429&quot; width=&quot;293&quot; height=&quot;225&quot; filename=&quot;preview.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;화이트, 다크테마 모두 어울리며 캐주얼, 전문적 느낌 사이에서 균형을 잘 잡은 커서 테마입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설치&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/black7375/Breeze-Cursors-for-Windows&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;다운로드.&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설정&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;1. 다운로드 후 Final 폴더에서 'KDE Breeze install.inf' 파일을 오른쪽 클릭 한 후 설치한다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994256505D32EC8015&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994256505D32EC8015&quot; width=&quot;800&quot; height=&quot;399&quot; filename=&quot;cursor-install.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;2. 제어판의 '하드웨어 및 소리' 중 '마우스' 옵션을 누른다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A0CA335D32ED7208&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A0CA335D32ED7208&quot; width=&quot;800&quot; height=&quot;426&quot; filename=&quot;cursor-control.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;3. '포인터' 탭에서 'KDE Breeze Dark'를 선택 후 적용한다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 595px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994079345D32ED9401&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994079345D32ED9401&quot; width=&quot;595&quot; height=&quot;682&quot; filename=&quot;cursor-mouse.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;또는&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D646345D3467DA18&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D646345D3467DA18&quot; width=&quot;800&quot; height=&quot;614&quot; filename=&quot;preview.png&quot; filemime=&quot;image/png&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.deviantart.com/krourke/art/Capitaine-cursors-624189658&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Capitaine cursors&lt;/a&gt;(Breeze + Mac 느낌)&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D19D4A5D3468B030&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D19D4A5D3468B030&quot; width=&quot;800&quot; height=&quot;450&quot; filename=&quot;ml.blau.3.png&quot; filemime=&quot;image/png&quot; style=&quot;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.deviantart.com/maik/art/ml-blau-3-614604903&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;ml.blau.3&lt;/a&gt;(Mac + Windows 느낌)&lt;br /&gt;&lt;/p&gt;&lt;p&gt;도 추천할 만한 커서 테마다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;나중에 소개할 프로그램 목록은 아래에 리스트로 놔둘테니 필요한 것이 있다면 다운받거나 구매하여 사용하면 된다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;예정.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://moogi.new21.org/prg4.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;날개셋 입력기&lt;/a&gt; - 이어 치기등 다양한 기능을 지원하는 입력기.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://cmder.net/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Cmder&lt;/a&gt; - cmd, poweshell 대용.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.mozilla.org/ko/firefox/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Firefox&lt;/a&gt; or &lt;a href=&quot;https://www.google.com/intl/ko_ALL/chrome/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Chrome &lt;/a&gt;- 웹브라우저.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://filezilla-project.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;FileZilla&lt;/a&gt; - FTP 클라이언트.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://tv.kakao.com/guide/potplayer&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Podplayer&lt;/a&gt; or &lt;a href=&quot;https://sourceforge.net/projects/mpcbe/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;MPC-BE&lt;/a&gt; - 동영상 재생기.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://madvr.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;madVR&lt;/a&gt; or &lt;a href=&quot;http://www.dmitrirender.ru/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;dmitriRender&lt;/a&gt;(유료) - 비디오 렌더러(영상 화질 향상).&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/Nevcairiel/LAVFilters&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;LAVFilters&lt;/a&gt; - 통합 코덱.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.foobar2000.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Foobar2000&lt;/a&gt; or &lt;a href=&quot;http://www.aimp.ru/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;AIMP&lt;/a&gt; or &lt;a href=&quot;https://www.getmusicbee.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;MusicBee&lt;/a&gt; - 음악 재생기.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.kls-soft.com/wscc/index.php&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Windows System Control Center&lt;/a&gt; - Sysinternals Suite, Nirsoft 관리툴.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/sysinternals/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Sysinternals Suite&lt;/a&gt; - 윈도우 관리 및 모니터링 툴 모음.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.ccleaner.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Ccleaner&lt;/a&gt;&lt;a href=&quot;https://www.ccleaner.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt; and Recuva&lt;/a&gt; - Piriform의 윈도우 클리너 및 파일 복원 프로그램.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.softpedia.com/get/System/System-Miscellaneous/Unlocker.shtml&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Unlocker&lt;/a&gt; - 파일이나 폴더 강제 삭제.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://autohotkey.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Autohotkey&lt;/a&gt; - 윈도우 매크로 프로그램.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://teus.me/category/IT/%EC%9E%90%EC%9E%91%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;구라제거기&lt;/a&gt; - 쓸데없는 ActiveX 프로그램 제거.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.magicaljellybean.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;KeyF&lt;/a&gt;&lt;a href=&quot;https://www.magicaljellybean.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;inder&lt;/a&gt; - 프로그램 시리얼 관리.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.mirinsoft.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;CloneApp&lt;/a&gt; - 프로그램 설정 백업.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://rufus.akeo.ie/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Rufus&lt;/a&gt; - 부팅용 USB 만들기.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.ext2fsd.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Ext2Fsd&lt;/a&gt; - 리눅스 파일시스템 접근.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://quest-app.appspot.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;QTranslate&lt;/a&gt;&lt;a href=&quot;https://quest-app.appspot.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt; &lt;/a&gt;- 번역기.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://ditto-cp.sourceforge.io/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Ditto&lt;/a&gt; - 클립보드 매니저.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.codesector.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Teracopy&lt;/a&gt; or &lt;a href=&quot;https://fastcopy.jp/en/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Fastcopy&lt;/a&gt; - 복사를 빠르게&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.voidtools.com&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Everything&lt;/a&gt; - 빠른 파일 검색.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.wox.one/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Wox&lt;/a&gt; or &lt;a href=&quot;https://www.listary.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Listary&lt;/a&gt; - 윈도우용 Spotlight.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.mactype.net/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Mactype&lt;/a&gt; - Mac 느낌의 폰트 렌더링.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.premeforwindows.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Preme&lt;/a&gt; - 마우스를 이용한 창컨트롤 향상.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://windowgrid.net/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;WindowGrid&lt;/a&gt; - 마우스를 이용한 창 조절.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.rainmeter.net/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Rainmeter&lt;/a&gt; - 바탕화면 위젯 및 꾸미기.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://rammichael.com/7-taskbar-tweaker&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;7+ Taskbar Tweaker&lt;/a&gt; - 작업 표시줄 트윅.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/TranslucentTB/TranslucentTB&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;TranslucentTB&lt;/a&gt;(Windows10) - 작업 표시줄 투명도 조절.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://winaero.com/comment.php?comment.news.1836&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Winaero Tweaker&lt;/a&gt; - 다양한 꾸미기 트윅.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.zhornsoftware.co.uk/zbar/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;ZBar&lt;/a&gt; - 멀티 모니터 사용시 각자 작업 표시줄.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.nurgo-software.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Nurgo Software&lt;/a&gt; - 창관리 향상, 프로그램들을 탭으로 묶기, 스팀게임 부스터.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://justgetflux.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;f.lux&lt;/a&gt; - 블루라이트 감소.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://pad.haroopress.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Haroo&lt;/a&gt;&lt;a href=&quot;http://pad.haroopress.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;pad&lt;/a&gt; or &lt;a href=&quot;https://typora.io/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Typora&lt;/a&gt; - 마크다운 툴.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.turnipsoft.co.uk/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Freda&lt;/a&gt; - Ebook 뷰어.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://meldmerge.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Meld&lt;/a&gt; - 파일 비교 프로그램.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.ghisler.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Total Commander&lt;/a&gt;(유료) or &lt;a href=&quot;https://www.gpsoft.com.au/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Directory Opus&lt;/a&gt;(유료)- 파일 관리자.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.forbootcamp.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;forBootCamp&lt;/a&gt; - 맥을 이용해 부트캠프로 윈도우를 사용할 경우.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.internetdownloadmanager.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Internet Download Manager&lt;/a&gt;(유료) - 다운로드 가속기 및 관리자.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://adguard.com/ko/welcome.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Adguard&lt;/a&gt;(유료) - 광고 차단기.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.microsoft.com/ko-kr/p/drawboard-pdf/9wzdncrfhwqt?activetab=pivot%3aoverviewtab&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Drawboard PDF&lt;/a&gt;(유료) - PDF에 그리기 프로그램.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.1upindustries.com/bins/default.aspx&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Bins&lt;/a&gt;(유료) - 작업 표시줄을 폴더화.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;출처:&amp;nbsp;&lt;a href=&quot;https://www.clien.net/service/board/lecture/11322692&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;윈도우10 터치패드 성능 향상 팁!&lt;/a&gt;,&amp;nbsp; 그리고 나&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>IT/UX</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/48</guid>
      <comments>https://black7375.tistory.com/48#entry48comment</comments>
      <pubDate>Mon, 3 Sep 2018 18:19:02 +0900</pubDate>
    </item>
    <item>
      <title>기초: 논리와 증명.</title>
      <link>https://black7375.tistory.com/45</link>
      <description>&lt;h1&gt;0. 프롤로그.&lt;br /&gt;&lt;/h1&gt;&lt;p&gt;아무래도 프로그래밍 설계에 이산수학 내용이 필요한지라 잠시 연재를 중단하고, 이산수학을 쭈욱 먼저 연재하고자 합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;0과 1로 사고하는 컴퓨터란 것을 알아 감에서 연속적이지 않은 것을 다루는 이산수학은 중요하다.&lt;/p&gt;
&lt;p&gt;연속적인 것으론 미적분, 해석학 같은 게 있겠죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;즉, 이산수학은 비연속적인 것을 다루기 때문에 정수 영역($\aleph_0$)에 한정되는 영역.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;참조한 교재는 제가 썼던 Rosen의 이산수학, 이산수학 Express.&lt;/p&gt;
&lt;p&gt;Rosen의 이산수학의 내용이 비교적 탄탄하기 때문에 Rosen의 이산수학의 목차에 기반하여 만들어졌습니다.&lt;/p&gt;
&lt;p&gt;두 책을 요약한 내용들이라 생각하면 됩니다.&lt;/p&gt;&lt;p&gt;막상 쓰고 보니 요약이라 하기도 좀.. 그러고 이것저것 섞은게 많긴 한데..&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;01 기초: 논리와 증명&lt;/p&gt;
&lt;p&gt;02 기본구조: 집합, 함수, 수열, 수열의 합, 행렬&lt;/p&gt;
&lt;p&gt;03 알고리즘&lt;/p&gt;
&lt;p&gt;04 정수론과 암호&lt;/p&gt;
&lt;p&gt;05 귀납법과 재귀&lt;/p&gt;
&lt;p&gt;06 계수&lt;/p&gt;
&lt;p&gt;07 이산적 확률&lt;/p&gt;
&lt;p&gt;08 고급 계수 기법&lt;/p&gt;
&lt;p&gt;09 관계&lt;/p&gt;
&lt;p&gt;10 그래프&lt;/p&gt;
&lt;p&gt;11 트리&lt;/p&gt;
&lt;p&gt;12 부울 대수&lt;/p&gt;
&lt;p&gt;13 계산 모델링&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이렇게 총 13개의 포스트로 구성이 될 예정.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/43&quot; target=&quot;_blank&quot;&gt;2018/07/22 - [수학] - 무한, 집합, 그리고 수에 대해서.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;의외로 집합과도 닿아 있는 부분이 있어서 위 글을 읽고 오면 도움이 됩니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;나중에 강좌로 쓸 논리회로에도 필요한 내용입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이 강좌는 컴공생들을 타겟으로 만들어졌습니다.&lt;br /&gt;&lt;/p&gt;&lt;h1&gt;1. 기초: 논리와 증명.&lt;/h1&gt;&lt;p&gt;명제 논리와 술어 논리를 다룰 것이다.&lt;/p&gt;
&lt;p&gt;명제 논리는 사고의 최소 구성단위를 명제(원자적 명제)로 하여 명제의 내용·구조에는 개입하지 않고 각 명제 사이의 결합관계만을 연구한다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;술어 논리는 명제에 '주어'와 '술어'의 구조가 존재하고, '주어'가 될 수 있는 대상에 대한 한정 기호를 사용할 수 있는 논리이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1.1 명제 논리.&lt;/h2&gt;&lt;p&gt;명제는 참 또는 거짓. 즉, 진리값을 가지는 명확히 구분할 수 있는 선언적인 문장이나 식이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;집합으로 생각하면 개집합(Open Set).&lt;/p&gt;
&lt;p&gt;개집합이 궁금한 사람들은&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/44&quot; target=&quot;_blank&quot;&gt;2018/07/30 - [수학] - 집합(위상)과 극한에 대하여[일부 내용 펌].&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;을 보고 옵시다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예를 들어,&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;$1+2=3$(참), $1\times 0=1$(거짓)&lt;/p&gt;
&lt;p&gt;파이어폭스는 웹브라우저다.(참)와 크롬은 마이크로소프트 제품이다.(거짓)&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;은 진리값을 가질 수 있으므로 명제이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;반면,&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;빵은 밥보다 맛있다.&lt;/p&gt;
&lt;p&gt;강좌 쓰기 귀찮지??&lt;/p&gt;
&lt;p&gt;$x+1=3$&lt;/p&gt;
&lt;p&gt;$x+y=3$&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;은 명확히 구분되지 않으므로 명제가 아니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strike&gt;두번째가 참인거 같은 기분이면 지는거. ㅜㅜ&lt;/strike&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 참과 모순.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;항상 참인 명제는 $\top$, 항상 모순인 명제는 $\bot$으로 나타낸다.&lt;/p&gt;
&lt;p&gt;$\top$은 True의 T모양을, $\bot$은 $\top$을 뒤집은 모양이라 한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$\bot$은 집합에서 $\emptyset$이라 할 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 명제와 선험성.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;철학쪽 공부를 해본 사람이라면, [나는 겉핥기 식으로 아아주 조금 했다.]&lt;/p&gt;
&lt;p&gt;인식론쪽에서 선험적 명제와 후험적 명제에 대해 들어봤을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;수학을 배우기 때문에 간략하게만 설명하자면,&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;선험적(a priori) 명제: 경험에 앞서 인식이 가능한 내용.(경험에 독립적이다)&lt;/p&gt;
&lt;p&gt;후험적(a posteriori) 명제: 경험 후에 인식이 가능한 내용.(경험에 의존적이다)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그럼 명제랑 도대체 어떠한 관계가 있는가?&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;로봇은 생명체가 아니다.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;라는 명제가 있다고 치자.&lt;/p&gt;
&lt;p&gt;[생명체에 대한 특성은 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%83%9D%EB%AC%BC#%EC%83%9D%EB%AC%BC%EC%9D%98_%ED%8A%B9%EC%84%B1&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;위키피디아-생물&lt;/a&gt;을 기준으로 정한다.]&lt;/p&gt;
&lt;div class=&quot;border&quot;&gt;
&lt;p&gt;&lt;b&gt;생물의 특성.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;생물이 무생물과 구별되는 일반적인 특징으로서, 생물은 자기증식능력, 에너지변환능력, 항상성 유지능력이라고 하는 3가지의 능력을 가지고 있다.&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;물질대사를 한다.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;체내에 필요한 물질이 합성, 분해되는 화학반응&lt;/li&gt;&lt;li&gt;에너지의 출입이 반드시 따름&lt;/li&gt;&lt;li&gt;효소가 반응을 매개함.&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;자극과 반응&lt;/li&gt;&lt;ul&gt;&lt;li&gt;생존을 위해 필수적인 것으로 환경의 변화(자극)를 감지하고 반응함&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;항상성 유지&lt;/li&gt;&lt;ul&gt;&lt;li&gt;외부 환경이 변하더라도 체내 환경을 일정하게 유지하려는 성질을 가진다.&lt;br /&gt;체온, 혈당량, 체액 농도 등을 유지&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;생식과 유전&lt;/li&gt;&lt;ul&gt;&lt;li&gt;종족 유지위해 자신과 닮은 자손을 남기는 것.&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;발생과 생장&lt;/li&gt;&lt;ul&gt;&lt;li&gt;세포가 커지거나, 세포 분열에 의해 수가 늘어나며 자람.&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;적응과 진화&lt;/li&gt;&lt;ul&gt;&lt;li&gt;현재의 환경에 적응되고, 환경이 변함에 따라 변화할 수 있음.&lt;br /&gt;진화론에서는 변화된 형질이 환경에 유리하여 살아남게 되면, 새로운 종으로 된다고 주장.&lt;/li&gt;&lt;/ul&gt;
&lt;li&gt;정교하고 복잡한 체제&lt;/li&gt;&lt;ul&gt;&lt;li&gt;모든 생물은 세포로 구성&lt;/li&gt;&lt;/ul&gt;&lt;/ol&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아직 머신러닝과 로봇공학의 발달이 덜 되었기 때문에 생식과 유전, 발생과 생장, 적응과 진화가 부족하다는 이유로 생명체가 아니라 할 수 있다. 그런데 미국 군의 비밀 연구소에서 작전 지역에서의 적응, 증식, 발달을 가능게 한 로봇이 개발되었을 수도 있다. 그렇다면, 그 로봇은 생명체라고도 할 수 있으므로 이 명제는 거짓이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;하지만 생명체라 정의할 수 있는 로봇이 있다는 것이 증명이 되었냐? 이건 또 아니다.&lt;/p&gt;
&lt;p&gt;어떠한 명제가 참이라는 것이 증명이 안되었다고 해서 그것을 '거짓'이라고 판단할 수는 없지만, 증명되지 않은 명제는 다른 명제의 성립 선험 조건에서 변수로 작용될 수 없다. 따라서 자동적으로 배제된다. 즉, &quot;로봇은 생명체가 아니다.&quot;는 명제로 작용이 될 수 있고, 참이 된다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;명제를 나타낼 때 관습.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;명제는 보통 $p,q,r, \; ...$로 명제 변수(진술 변수)를 표현한다.&lt;/p&gt;
&lt;p&gt;명제변수는 임의의 명제를 간단하게 표현하게 위해 나온 것으로, 정해진 진리값을 갖는 특정명제를 대입하여 진리값을 부여할 수 있다. &lt;/p&gt;
&lt;p&gt;진리값이 참 일때는 $T$, 거짓일 때는 $F$로 표시한다.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;명제를 다루는 분야를 명제 산술(Propositional Calculus) 또는 명제 논리(Propositional Logic)라 부른다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;기존 명제에서 새로운 명제를 만드는 방법에 대해 알아보자.&lt;br /&gt;하나 또는 여러 개의 명제를 조합하여 많은 수학적인 명제가 만들어 지는데 이걸 복합 명제(Compound Propositon)이라 하며 논리 연산자로 만든다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.1.1 부정(Negation, $\lnot$).&lt;/h3&gt;&lt;p&gt;연산자 1개만 사용해서 만드는 가장 간단한 명제 산술.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$p$가 명제면 $\lnot p$ 또는 $\bar{p}$로 표기한다.&lt;br /&gt;&quot;not $p$&quot;라 읽는다.&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:69.70pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:69.67pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$\lnot p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width: 69.7pt; height: 22px; padding: 1.41pt 5.1pt; border-color: rgb(216, 232, 198) rgb(216, 232, 198) rgb(216, 232, 198) rgb(116, 164, 66); border-style: solid; border-width: 0.28pt 0.28pt 0.28pt 1.7pt; background: rgb(255, 255, 255) none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width: 69.67pt; height: 22px; padding: 1.41pt 5.1pt; border-color: rgb(216, 232, 198) rgb(116, 164, 66) rgb(216, 232, 198) rgb(216, 232, 198); border-style: solid; border-width: 0.28pt 1.7pt 0.28pt 0.28pt; background: rgb(255, 255, 255) none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:69.70pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:69.67pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;&lt;/p&gt;
&lt;p&gt;부정 연산자라 당연하게도(?) T는 F, F는 T가 된다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;집합으로 따지면&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 384px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99588C375B53867921&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99588C375B53867921&quot; width=&quot;384&quot; height=&quot;280&quot; filename=&quot;384px-Komplement_einer_Menge.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;여집합[from &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Wikipedia&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;여집합($p^c$)이다. 조금 더 정확하게 할 때 $\lnot p$은 $\operatorname{Int}(X-p)$이라 표현이 가능.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;* 집합 이야긴 $X$라는 위상 공간 하라 가정한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$\operatorname{Int}$가 궁금한 사람들도 극한 글을 읽으면 됩니다.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.1.2. 접속사(Connectives).&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;접속사를 이용한 명제는 2개 이상의 명제로부터 새로운 명제를 만들어내는 논리 연산자(Logical Operators)다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 논리합(Disjunction, $\lor$).&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;$p \lor q$는 논리합이며, &quot;$p$ 또는(or) $q$&quot;라 읽는다.&lt;/p&gt;
&lt;p&gt;모두 거짓일 때만 거짓이며 그 외는 모두 참임을 나타내는데 역시 $0$에 $0$을 제외한 숫자를 더하면 그 숫자가 되는 특성을 떠올리면 쉽게 이해할 수 있다.&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$p \lor q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;집합에서는&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 220px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9942F9435B5385D820&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9942F9435B5385D820&quot; width=&quot;220&quot; height=&quot;160&quot; filename=&quot;220px-Venn0111.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;합집합[from &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;합집합($p \cup q$)이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 논리곱(Conjunction, $\land$).&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;$p \land q$는 논리곱이며 &quot;$p$ 그리고(and) $q$&quot;라 읽는다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;모두 참일 때만 참이며 그 외는 모두 거짓임을 나타내는데 곱셈에서 어떤 수든 $0$(여기선 $F$)을 곱하면 $0$($F$)이란 걸 떠올리면 쉽게 이해할 수 있다.&lt;/p&gt;
&lt;p&gt;진리값은 다음과 같다.&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$p \land q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;
&lt;/p&gt;
&lt;p&gt;* 가끔 but을 and 대신 사용하기도 한다고 한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;집합에서는&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 384px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993D533D5B5385FD21&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993D533D5B5385FD21&quot; width=&quot;384&quot; height=&quot;280&quot; filename=&quot;384px-Venn0001.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;교집합[from &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Wikipedia&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;교집합($p \cap q$)이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 배타적 논리합(Exclusive OR, $\oplus$).&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;배타적 논리합($\oplus$)은 모두 참이거나 거짓을 때는 F, 하나만 참일때만 T이다.&lt;/p&gt;
&lt;p&gt;배타적일 때(같지 않을 때)만 논리합 과정이 일어나 T가 된다고 생각하면 됩니다.&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$p \oplus q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;&lt;/p&gt;
&lt;p&gt;즉, 진리값이 모두 같을 때만 F, 하나라도 다르면 T.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;집합에서는&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 384px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991108415B547F9F29&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991108415B547F9F29&quot; width=&quot;384&quot; height=&quot;280&quot; filename=&quot;384px-Venn0110.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;대칭자[from &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Wikipedia&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;대칭자($p \triangle q$) 위치이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;'포괄적(inclusive)' 논리합(or)과 '배타적(exclusive)' 논리합(or).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;보다시피 포괄적 or과 배타적 or이 존재한다.&lt;/p&gt;
&lt;p&gt;포괄적이란 표현은 넓게넓게 허용한다는 뜻이고, 배타적이란 표현은 같지 않으면 배척한다는 뜻이다.&lt;/p&gt;
&lt;p&gt;이 점을 유의해 두고 기억한다면 쉽게 이해 할 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.1.3 조건문(Conditional state-ment).&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;&lt;b class=&quot;&quot;&gt;- 조건문(Conditional state-ment, $\rightarrow$ or &lt;/b&gt;&lt;b class=&quot;&quot;&gt;&lt;b class=&quot;&quot;&gt;&lt;b class=&quot;&quot;&gt;$\implies$&lt;/b&gt;&lt;/b&gt;) or 함축(Implication&lt;/b&gt;&lt;b class=&quot;&quot;&gt;).&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;조건문 $p \rightarrow q$는 명제 &quot;$p$이면 $q$(if $p$ then $q$)이다.&quot;란 뜻이다.[$\lnot p \lor q = p \rightarrow q$]&lt;/p&gt;
&lt;p&gt;$p$는 가정(Hypothesis) 또는 전제(Premise), 전항(Antecedent)이라고 하며, $q$를 결론(Conclusion) 또는 결과(Consequence)라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&quot;$\lnot p$가 아니면 $q$($q$ unless $\lnot p$)&quot;는 &quot;$p$이면 $q$이다(if $p$ then $q$)&quot;와 같다.&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은 고딕, sans-serif;&quot;&gt;$p$&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$p \rightarrow q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;명제 $p \rightarrow q$는 집합 $\operatorname{Int}\left((X-p)\cup q\right)$에 대응한다.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;b&gt;- 파생된 조건문(Derived conditional state-ments).&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;조건문 $p \rightarrow q$로부터 파생된 몇가지 조건문을 만들 수 있다.&lt;/p&gt;
&lt;p&gt;바로 바로 역(Convers), 이(Inverse), 대우(Contrapositive)!!&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$p \rightarrow q$의 역, 이, 대우는 다음처럼 나타낸다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 412px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BEBC4C5BB66B781A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BEBC4C5BB66B781A&quot; width=&quot;412&quot; height=&quot;193&quot; filename=&quot;역이대우.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;역 이 대우[from &lt;a href=&quot;http://math.kongju.ac.kr/mathcom/pro/pro2.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;국립 공주대학교 수학교육과&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;역: $q \rightarrow p$&lt;/p&gt;
&lt;p&gt;이: $\lnot p \rightarrow \lnot q$&lt;/p&gt;
&lt;p&gt;대우: $\lnot q \rightarrow p$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;b&gt;- 상호 조건문(Biconditional, iff or $\leftrightarrow$ or $\iff$) or 동치(Equivalent).&lt;/b&gt;&lt;br /&gt;두 개의 명제가 같은 진리값을 갖는다는 것을 표현하기 위하여 두 명제를 결합하는 다른방법.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$p \leftrightarrow q$는 $p$는 $q$의 필요충분 조건을 뜻한다.&lt;/p&gt;
&lt;p&gt;영어로 하면 $p$ if and only if $q$”(if and only if는 흔히 iff라고도 쓰임). 즉 'q이면, 그때만 p이다'란 뜻이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;동일한 진리값을 가질 때 참이다. [$(p \rightarrow q) \land (q \rightarrow p)$]&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$p \leftrightarrow q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F &lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;보다시피 베타적 논리합의 역이다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;상호 조건문은 동치(Equivalent)를 뜻한다는 것을 알 수 있다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;파생된 조건문에서 원래 명제와 대우는 동치이고, 역과 이는 동치다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;집합으로 나타내면, $\operatorname{Int}\left((p \cap q)\cup\left(X-(p \cup q)\right)\right)$다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;상호 조건문의 묵시적 사용(Implicit use of biconditionals)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;자연어에서는 'If, then' 또는 'Only if'형태로 표현되며, 'if and only if'의 다른 한 부분은 묵시적이다.즉 역(Converse)이 묵시적으로 주어지며 명시적으로 기술되지 않는다.&lt;/p&gt;
&lt;p&gt;자연어의 부정확성 때문에 자연어의 조건문이 그 역을 묵시적으로 포함하는지 아닌지를 가정해야 한다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;h3&gt;&lt;br /&gt;1.1.4 논리 연산자의 우선순위.&lt;/h3&gt;&lt;p&gt;복합명제를 구성하는 연산자의 순서를 명확히 하기 위해 논리 연산자의 우선순위를 알아보도록 하자.&lt;/p&gt;
&lt;p&gt;사칙연산에서 $\times, \; \div$가 $+, \; -$보다 우선순위인 것처럼.&lt;br /&gt;&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:69.70pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 0.25pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은 고딕, sans-serif;&quot;&gt;연산자&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:69.67pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 0.25pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은 고딕, sans-serif;&quot;&gt;우선순위&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width: 69.7pt; height: 22px; padding: 1.41pt 5.1pt; border-color: rgb(116, 164, 66) rgb(216, 232, 198) rgb(116, 164, 66) rgb(116, 164, 66); border-style: solid; border-width: 0.25pt 0.28pt 0.25pt 1.7pt; background: rgb(255, 255, 255) none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$\lnot$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width: 69.67pt; height: 22px; padding: 1.41pt 5.1pt; border-color: rgb(116, 164, 66) rgb(116, 164, 66) rgb(116, 164, 66) rgb(216, 232, 198); border-style: solid; border-width: 0.25pt 1.7pt 0.25pt 0.28pt; background: rgb(255, 255, 255) none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;1&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:69.70pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 0.25pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$\lor$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:69.67pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 0.25pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:69.70pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 0.25pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$\land$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:69.67pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 0.25pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:69.70pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 0.25pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$\rightarrow$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:69.67pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 0.25pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;4&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:69.70pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;$\leftrightarrow$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:69.67pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;5&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;물론 괄호를 사용하는게 좋은 습관이긴 하다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 class=&quot;&quot;&gt;1.1.5 복합명제와 진리표.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;나중에 복잡한 명제를 해석하거나 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%B9%B4%EB%85%B8_%EB%A7%B5&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;카노 맵&lt;/a&gt;을 그리려면 복합명제로 진리표를 만들 수 있어야 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;말이 나온 김에 $(p \rightarrow q) \land (q \rightarrow p)$(상호 조건문)의 조건표를 그려봅시다.&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:32.97pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:32.97pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:106.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \rightarrow q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:106.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$q \rightarrow p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:140.50pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$(p \rightarrow q)\land(q \rightarrow p)$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:32.97pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:32.97pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:106.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:106.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:140.50pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:32.97pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:32.97pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:106.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:106.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:140.50pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:32.97pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:32.97pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:106.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:106.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:140.50pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:32.97pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:32.97pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:106.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:106.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:140.50pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;각 연산 요소에 대해 연산순서에 따라 하나씩 적어주고, 이를 쌓아 최종적인 명제의 답을 찾아가면 된다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.1.6 논리식(Well-formed&amp;nbsp; formula, wff).&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;대수연산에서 변수, 상수, 연산자등으로 대수식을 만드는 것처럼 논리연산에서도 명제와 접속사(Connectives)를 이용하여 논리식을 만들 수 있다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;명제식은 이러한 명제변수, 연결사 및 괄호로 구성되는 문자열로서, 다음의 규칙에 의거하여 생성되는 정합논리식에 의해 정형화될 수 있다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;명제변수와 상수($T, F$)는 논리식.&lt;/li&gt;&lt;li&gt;접속사를 사용한 명제도 논리식.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;1, 2번을 유한번 반복 적용한 것이 논리식.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;이 정의는 변수 집합이 유한한 경우 배커스-나우르 표기법으로 표현할 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;bnf&quot;&gt;&amp;lt;alpha set&amp;gt; ::= p | q | r | s | t | u | ... (명제 변수의 임의의 유한 집합)
&amp;lt;form&amp;gt; ::= &amp;lt;alpha set&amp;gt; | ¬&amp;lt;form&amp;gt; | (&amp;lt;form&amp;gt;∧&amp;lt;form&amp;gt;) | (&amp;lt;form&amp;gt;∨&amp;lt;form&amp;gt;) | (&amp;lt;form&amp;gt;→&amp;lt;form&amp;gt;) | (&amp;lt;form&amp;gt;↔&amp;lt;form&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;border&quot;&gt;
&lt;h4&gt;배커스-나우르 표기법에 대하여.&lt;/h4&gt;&lt;p&gt;박스 안의 내용은 배커스-나우르 표기법에 필요한 지식들을 다루고 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;
    &lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
        &lt;li&gt;&lt;b&gt;파싱(Parsing, 구문 분석).&lt;/b&gt;&lt;br /&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;일련의 문자열을 의미있는 토큰(token)으로 분해하고 이들로 이루어진 파싱 트리를 만드는 과정을 말한다.&lt;/p&gt;
    &lt;p&gt;
        &lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;
            &lt;tbody&gt;
                &lt;tr&gt;
                    &lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9908F64E5C14B56801&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9908F64E5C14B56801&quot; width=&quot;400&quot; height=&quot;176&quot; filename=&quot;Grammar_example1_IPL.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;
                    &lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 400px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BB724F5C14B57906&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BB724F5C14B57906&quot; width=&quot;400&quot; height=&quot;292&quot; filename=&quot;parsing.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/td&gt;
                &lt;/tr&gt;
            &lt;/tbody&gt;
        &lt;/table&gt;
        &lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;파싱 트리 예[from &lt;a href=&quot;https://en.wikibooks.org/wiki/Introduction_to_Programming_Languages/Parsing&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Introduction to Programming Languages&lt;/a&gt;, &lt;a href=&quot;http://www.aistudy.co.kr/linguistics/natural/parsing.htm&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Parsing&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;b&gt;튜플(Tuple).&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;유한 개의 사물의 순서있는 열거이다. $n$개의 요소를 가진 튜플을 $n$-튜플($n$-tuple) 또는 $n$중쌍, $n$짝이라고 한다. 비어있는 열은 유일한 $0$-튜플이다. 임의의 $n$-튜플은 순서쌍의 개념을 이용하여 재귀적으로 정의된다.&lt;br /&gt;
    &lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
    &lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;몇가지 정의법을 살펴볼까요?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 함수.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;$X, Y, F$를 각각 순서를 나타내는 정의역, 튜플의 성분인 공역, 함수라 할 때&lt;/p&gt;
&lt;p&gt;$$(a_1, a_2, a_3, ..., a_n) \equiv(X,Y,F)$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;에서&lt;/p&gt;
&lt;p&gt;$X=\{1,2,\ldots,n\} \\ Y=\{a_1,a_2,\ldots,a_n\} \\ F=\{(1,a_1),(2,a_2),\ldots,(n,a_n)\}$관계가 성립된다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;간단히 말해서&lt;/p&gt;
&lt;p&gt;$$(a_1,a_2,\ldots,a_n):=(F(1),F(2),\ldots,F(n))$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 순서쌍.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li class=&quot;&quot;&gt;0-튜플, 즉 비어있는 튜플은 공집합 $\emptyset$로 정의한다.&lt;/li&gt;&lt;li&gt;정수 $n&amp;gt;0$에 대해, $n$-튜플은 $n$-튜플의 첫 성분을 첫 성분으로 하고, 나머지 성분들로 이루어진 $(n-1)$-튜플을 둘째 성분으로 하는 순서쌍이다.&lt;br /&gt;$(a_1,a_2,a_3,\ldots,a_n)=(a_1,(a_2,a_3,\ldots,a_n))$&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$(a_1,a_2,a_3,\ldots,a_n)=(a_1,(a_2,(a_3,(\ldots,(a_{n-2},(a_{n-1},(a_n,\emptyset)))\ldots))))$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;라는 건데&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$(1,2,3,4) = (1,(2,3,4)) = (1,(2,(3,4))) = (1,(2,(3,(4,\emptyset))))$$같은 예를 들 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tistory.com/38&quot; target=&quot;_blank&quot;&gt;2018/06/10 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 5. - 리스트와 재귀.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;와 상당히 유사하죠?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 집합.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;순서쌍을 이용한 방법과 은근 비슷합니다.&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;0-튜플, 즉 비어있는 튜플은 공집합 $\emptyset$로 정의한다.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;$x$를 $n$-튜플 $(a_1, a_2,... , a_n)$이라 하자. 끝에 $b$를 추가한 튜플 $x \rightarrow b \equiv (a_1, a_2,... , a_n, b)$는 다음과 같은 집합이다. &lt;br /&gt;$x \rightarrow b \equiv \{\{x\}, \{x, b\}\}$&lt;/li&gt;&lt;/ol&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;예시.&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;역시 예를 들자면&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$$&amp;nbsp;&amp;nbsp; \begin{array}{lclcl}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ()&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;amp; &amp;amp;&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;amp;=&amp;amp; \emptyset&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; \\&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;amp; &amp;amp;&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;amp; &amp;amp;&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; \\&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;amp;=&amp;amp; ()&amp;nbsp;&amp;nbsp;&amp;nbsp; \rightarrow 1 &amp;amp;=&amp;amp; \{\{()\},\{(),1\}\}&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; \\&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;amp; &amp;amp;&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;amp;=&amp;amp; \{\{\emptyset\},\{\emptyset,1\}\}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; \\&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;amp; &amp;amp;&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;amp; &amp;amp;&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; \\&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (1,2)&amp;nbsp;&amp;nbsp; &amp;amp;=&amp;amp; (1)&amp;nbsp;&amp;nbsp; \rightarrow 2 &amp;amp;=&amp;amp; \{\{(1)\},\{(1),2\}\}&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; \\&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;amp; &amp;amp;&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;amp;=&amp;amp; \{\{\{\{\emptyset\},\{\emptyset,1\}\}\},&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; \\&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;amp; &amp;amp;&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;amp; &amp;amp; \{\{\{\emptyset\},\{\emptyset,1\}\},2\}\}&amp;nbsp;&amp;nbsp;&amp;nbsp; \\&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;amp; &amp;amp;&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;amp; &amp;amp;&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; \\&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (1,2,3) &amp;amp;=&amp;amp; (1,2) \rightarrow 3 &amp;amp;=&amp;amp; \{\{(1,2)\},\{(1,2),3\}\}&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;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;amp; &amp;amp;&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;amp;=&amp;amp; \{\{\{\{\{\{\emptyset\},\{\emptyset,1\}\}\}, \\&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;amp; &amp;amp;&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;amp; &amp;amp; \{\{\{\emptyset\},\{\emptyset,1\}\},2\}\}\}, \\&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;amp; &amp;amp;&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;amp; &amp;amp; \{\{\{\{\{\emptyset\},\{\emptyset,1\}\}\},&amp;nbsp;&amp;nbsp; \\&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;amp; &amp;amp;&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;amp; &amp;amp; \{\{\{\emptyset\},\{\emptyset,1\}\},2\}\},3\}\}&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; \\&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; \end{array}&lt;br /&gt;&amp;nbsp;$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;성질.&lt;/b&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;중복된 원소가 있을 수 있다. 튜플의 원소를 중복해서 쓰면 다른 튜플이 된다. 예: $(1, 2, 3) \neq (1, 2, 2, 3)$, 하지만 집합 $\{1, 2, 3\} = \{1, 2, 2, 3\}$ &lt;br /&gt;&lt;/li&gt;&lt;li&gt;정해진 순서가 있다. 튜플의 원소의 순서를 바꾸면 다른 튜플이 될 수 있다. 예: $(1, 2, 3) \neq (3, 2, 1)$, 하지만 집합 ${1, 2, 3} = {3, 2, 1}$&lt;/li&gt;&lt;li&gt;튜플의 원소의 개수는 유한하다. 하지만 집합, 중복집합은 원소 개수가 무한할 수도 있다.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;b&gt;클레이니 스타(Kleene Star).&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;문자열이나 문자의 집합에 쓰이는 단항 연산으로, 0개 이상의 임의 원소의 연쇄를 뜻한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;집합 $V$의 $n$회 연쇄는&lt;/p&gt;
&lt;p&gt;$$V^0 = \{\varepsilon\} \\&lt;br /&gt;V^1 = V \\&lt;br /&gt;V^n = V \circ V^{n-1} = \{uv|u\in V, v\in V^{n-1}\} (n \ge 2)$$라 할 때&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$V^* = \sideset{}{_{i=0}^\infty}\bigcup V^i = \bigcup_{i \in \mathbb{N} }V^i = \{\varepsilon\} \cup V \cup V^2 \cup V^3 \cup V^4 \cup \ldots.$$를 클레이니 스타라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;예시.&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$$\begin{array} \{ \{a, b\}^* = &amp;amp;\{&amp;amp; \\&lt;br /&gt;&amp;amp; &amp;amp;\varepsilon,\\&lt;br /&gt;&amp;amp; &amp;amp;a, b,\\&lt;br /&gt;&amp;amp; &amp;amp;aa, ab, ba, bb,\\&lt;br /&gt;&amp;amp; &amp;amp;aaa, aab, aba, abb, baa, bab, bba, bbb,\\&lt;br /&gt;&amp;amp; &amp;amp;...&amp;amp;\}&amp;amp;\end{array}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\begin{array} \{ \{ab,c\}^* = &amp;amp;\{&amp;amp;\\&lt;br /&gt;&amp;amp; &amp;amp; \varepsilon,\\&lt;br /&gt;&amp;amp; &amp;amp;ab, c,\\&lt;br /&gt;&amp;amp; &amp;amp;abab, abc, cab, cc,\\&lt;br /&gt;&amp;amp; &amp;amp;ababab, ababc, abcab, abcc, cabab, cabc, ccab, ccc,\\&lt;br /&gt;&amp;amp; &amp;amp;...&amp;amp;\}&amp;amp;\end{array}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
    &lt;p&gt;
        &lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
            &lt;li&gt;&lt;b&gt;문맥-자유 문법(Context-free grammar, CFG).&lt;/b&gt;&lt;/li&gt;
        &lt;/ul&gt;
        &lt;p&gt;형식 언어에서 가능한 모든 문자열을 설명하는 생산 규칙 집합이다. 즉, 임의의 문자열이 주어진 문법에 의하여 유도될 수 있는가를 확인하는 것.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;모든 생성규칙이&lt;br /&gt;&lt;/p&gt;
        &lt;p&gt;$$A \to x$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;형태를 따른다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$A$는 비말단(비종결자) 기호이고,&amp;nbsp; $x$는 비말단과 말단 기호들로 구성된 문자열이다.&lt;/p&gt;
&lt;p&gt;말단 기호는 $0, 1, 2,...$같이 더 이상 나눌 수 없는 원자적인 기호(알파벳).&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;문맥-자유 문법 $G$를 $4$-튜플인&amp;nbsp; $G = (V, \Sigma, R, S)$라 정의할 때,&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;$V$는 비말단 기호의 유한집합.&lt;/li&gt;&lt;li&gt;$\Sigma$는 말단 기호의 유한집합으로 $V$와 서로소다.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;$R$은 $V$에서 $(V \cup \Sigma)^*$로 연결되는 생성 규칙의 유한집합이다.&lt;br /&gt;$R$의 멤버는 프로덕션이라 한다. $^*$표시는 클레이니 스타(Kleene Star)이다. &lt;/li&gt;&lt;li&gt;$S$는 시작 기호(변수)로, $V$의 원소다.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;b&gt;알면 좋은 것.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;생성규칙에서 $A\in V$, $x\in R$에 속한다.&lt;/p&gt;
&lt;p&gt;언어 $L$은 $\Sigma ^*$의 부분집합.&lt;/p&gt;
&lt;p&gt;말단기호는 $a,b,c,...$, 문자열은 흔히 $u,v,w,...$처럼 표현.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;언어 $L$ 에 대해서 $L = L(G)$를 만족하는 문맥-자유 문법 $G$가 존재하고 오직 그럴 때에만 $L$ 을 문맥-자유 언어 (context-free language : CFL)라고 한다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;예시.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$G = (\{S\}, \{a,b\}, P,S)$$&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;생성규칙을 보면, $S \to aSa\\&lt;br /&gt;S \to bSb,\\&lt;br /&gt;S \to \varepsilon$ 이고,&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$S \to aSa \to aaSaa \to aabSbaa \to aabbaa$처럼 유도된다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$L(G)=\{ww^R : w \in \{a,b\}^*\}$가 성립한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
        &lt;p class=&quot;&quot;&gt;문장의 문법적 유도를 따른다는 특성 때문에 컴파일러나 각종 파싱하는 것에서 유용한 이론이다.&lt;/p&gt;
    &lt;p&gt;&lt;/p&gt;
    &lt;p&gt;&lt;br /&gt;&lt;/p&gt;
    &lt;ul style=&quot;list-style-type: disc;&quot;&gt;
        &lt;li class=&quot;&quot;&gt;&lt;b&gt;&amp;nbsp;배커스-나우르 표기법(Backus–Naur form, BNF).&lt;/b&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;문맥 자유 문법(Context-free grammar, CFG)을 정규화 표현하기 위해 만들어진 표기법이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* 정규화&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;같은 종류의 표현을 묶어 간소화하는 과정.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;표현법.&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;bnf&quot;&gt;&amp;lt;기호&amp;gt; ::= _표현식_&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;으로 표시합니다.&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;&lt;code class=&quot;bnf&quot;&gt;&amp;lt;기호&amp;gt;&lt;/code&gt;에는 말단 기호가 될 수 없습니다.(비말단 기호임)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;비말단 기호는 &amp;lt;와 &amp;gt;로 묶어서 표현합니다.&lt;/li&gt;&lt;li&gt;여러가지 기호 중 선택이 가능함을 표시하기 위해 &lt;code class=&quot;bnf&quot;&gt;|&lt;/code&gt;를 사용합니다.&lt;/li&gt;&lt;li&gt;&lt;code class=&quot;bnf&quot;&gt;::=&lt;/code&gt;는 왼쪽의 기호가 오른쪽의 식으로 대체됨을 의미합니다.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;&lt;p class=&quot;&quot;&gt;재귀적인 정의라는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;1.2 명제 논리의 응용&lt;/h2&gt;&lt;h3&gt;1.2.1 자연어 문장 변환.&lt;/h3&gt;&lt;p&gt;우리가 나타내려는 뜻을 논리적으로 표현하려면 자연어를 논리식으로 변환할 필요가 있다.&lt;/p&gt;
&lt;p&gt;자연어의 복잡함과 모호함 때문이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이러한 원인으로는&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;- 목적 표현의 복잡성.&lt;/p&gt;
&lt;p&gt;- 대응의 다양성.&lt;/p&gt;
&lt;p&gt;- 구성요소간의 상호작용.&lt;/p&gt;
&lt;p&gt;를 꼽는다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;자연어의 해석에 대하여 정보를 더 원한다면 &lt;a href=&quot;http://www.aistudy.co.kr/linguistics/natural/nlp_kim.htm&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;자연어 이해&lt;/a&gt;를 참고.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자연어를 논리식으로 바꾸어 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;교수님이 다음과 같은 공지를 하였다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 420px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99521D345BE900F42C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99521D345BE900F42C&quot; width=&quot;420&quot; height=&quot;314&quot; filename=&quot;Too much.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot; class=&quot;&quot;&gt;푸린이 같은 교수님 ㅠ[&lt;a href=&quot;https://m.blog.naver.com/nav_sh/220372026688&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;출처&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p class=&quot;&quot;&gt;목표 진도까지 못나가고 수업 시간이 지나지 않으면 강의를 계속한다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;1. 문장을 간단히 표현하기 위해 명제 변수를 도입합니다.&lt;/p&gt;
&lt;p&gt;$p$: 목표 진도까지 못나감.&lt;/p&gt;
&lt;p&gt;$q$: 수업 시간이 안지남.&lt;/p&gt;
&lt;p&gt;$r$: 강의를 계속한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;2. 명제 변수끼리의 관계를 분석합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$(p \land q) \rightarrow r$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;[사실 $\lnot$을 도입하는 것이 옳은 방향이나 깔끔한 예제를 위해 쓰지 않았다]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기서 $\rightarrow$의 조건이 참일 때만 거짓이 나오는 이유를 이해해보도록 합시다.&lt;/p&gt;
&lt;p&gt;(헷갈려하는 사람들이 많더군요)&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;목표 진도까지 못나가고, 수업 시간이 안지나면($p \land q$, 참) 강의를 계속하는 것($r$참)은 당연한 일입니다.($(p \land q) \rightarrow r$, 참)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그럼 목표 진도까지 못나가고, 수업 시간이 안지났는데($p \land q$, 참) 강의를 끝내는 것($r$, 거짓)은 거짓이겠죠.($(p \land q) \rightarrow r$, 거짓)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이번엔 거짓의 조건을 해봅시다.&lt;/p&gt;
&lt;p&gt;목표 진도까지 나갔으나 수업시간이 안끝난 상황($\lnot p \land q$, 거짓)&lt;/p&gt;
&lt;p&gt;또는 목표 진도까지 못나갔지만 수업시간은 끝난 상황($p \land \lnot q$, 거짓)에&lt;/p&gt;
&lt;p&gt;강의를 계속하는 것($r$, 참)과 강의를 끝낸 다($r$, 거짓)는 명제 중 어떤 것이 참일까요?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;정답은 둘 다 참입니다.&lt;/p&gt;
&lt;p&gt;강의를 계속할 지, 안할지 결론을 정해놓지 않았기 때문이죠.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그냥 교수님 마음가는대로 한다는 공지였습니다ㅋㅋㅋ&lt;/p&gt;
&lt;p&gt;$\rightarrow$를 조심하세요.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 545px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BF963C5BE8FF152A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BF963C5BE8FF152A&quot; width=&quot;545&quot; height=&quot;316&quot; filename=&quot;Too much.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; class=&quot;&quot;&gt;죽여줘..[&lt;a href=&quot;http://www.sharetime.co.kr/bbs/board.php?bo_table=issue&amp;amp;wr_id=54809&amp;amp;page=646&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;출처&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자연어를 논리식으로 변환한다니 갑자기 생각나는 것이 있다.&lt;/p&gt;
&lt;p&gt;논리주의에서 수학을 논리학으로 변환한다는 것과 자연어를 명제로 변환하는 것에서 느껴진 유사점이랄까?&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;&lt;b&gt;수리철학.&lt;/b&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 논리주의 &lt;/b&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;수학은 논리학에 포함된다는 주장이다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;이를 위해서 수학의 개념들은 논리학의 개념들로부터, 수학의 정리들은 순수한 논리적 연역을 써서 논리학의 공리들로부터 도출될 수 있다는 것을 보여야 한다. &lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;프레게와 러셀은 논리주의를 증명하고자 했으나 환원공리, 선택공리, 무한공리등의 문제가 발생.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;b&gt;
&lt;/b&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 직관주의&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://terms.naver.com/entry.nhn?docId=3570979&amp;amp;cid=59056&amp;amp;categoryId=59056&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;브라우어&lt;/a&gt;를 필두로한 수학자들은 구성적인 방법을 통하여, 즉 대상을 정의할 대 유한번의 단계로 구성 가능해야 한다고 주장하였다.   따라서 귀류법을 배척하였으며 그 결과 고전 논리의 배중률($p \lor\lnot p$), 이중 부정 삭제($\lnot\lnot p\rightarrow p$), 퍼스의 법칙($\left(p\rightarrow q)\rightarrow p\right)\rightarrow p$)을 거부한다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그러나 무한등의 많은 수학적 지식을 포기해야 하는 상황. 이 글에서 집합과의 비교는 직관주의와 관계가 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 형식주의&lt;/b&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;논리주의에 의한 역리와 직관주의에 의한 고전 수학의 포기를 보완하기 위해 나왔다. 수학을 형식화해 그 형식체계가 무모순임을 분명한 방법(힐베르트는 이를 ‘유한적 방법’이라 불렀다)으로 증명할 수 있다는 것. 수학을 형식화한다는 뜻은 먼저 수학을 공리 체계로 만들고 이를 의미가 없는 형식적인 기호들로 만드는 것과 그 기호들을 문법에 맞도록 하고, 이로부터 다른 논리식을 추론할 수 있도록 규칙을 명시하는 것이다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;괴델의 불완전성 정리에 의해 형식체계의 '무모순성'에 문제가 생긴다. 그러나 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%B4%88%ED%95%9C%EA%B7%80%EB%82%A9%EB%B2%95&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;초한귀납법&lt;/a&gt;을 통하여 무한을 인정할 경우, 산술의 무모순성이 증명되었기 때문. 때문에 현재 수학계에서 대세이다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;정리.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 논리주의는 수학을 논리학으로 환원하는 것에 의해서 패러독스를 제거하려고 하였음.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 직관주의는 논리를 제한하여 일종의 구성 가능한 것만을 수학적 대상으로 취급하여 패러독스를 제거하려 하였음.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;- 형식주의는 무모순성의 증명이 가능한 형식적 체계만을 인정하는 것에 의해서 패러독스를 배제하려 하였다.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그러나 논리주의는 논리학을 확대하거나 또는 복잡하게 만들어 버렸고,&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;직관주의는 수학을 축소시켜 버리는 결과를 낳았으며,&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;형식주의는 타당하게 인정할 수 있는 증명 방식의 범위를 확대하지 않을 수 없는 난점을 파생시켰다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이 문서도 기본적으로 형식주의에 의해서 써지고 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;더 자세한 것을 알고 싶다면 &lt;a href=&quot;http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&amp;amp;mallGb=KOR&amp;amp;barcode=9788930087926&amp;amp;orderClick=LAG&amp;amp;Kc=&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;수학철학 : 논리주의·형식주의·직관주의의 이해와 비판&lt;/a&gt;을 참고하기 바란다.&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.2.2 시스템 명세.&lt;/h3&gt;&lt;p&gt;자연언어로 된 문장을 논리적은 표현으로 변환하는 것은 HW,SW 시스템을 명확히 기술하는데에도 필수적이다.&lt;/p&gt;
&lt;p&gt;자연어로 기획된 것을 실제로 구현할 때에 일관성이 있어야 하기 때문이다.(모순이 되면 안됨)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예) 다음 시스템은 일관성이 있는가?&lt;br /&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;부재중 통화가 있으면 알림이 온다.&lt;/li&gt;&lt;li&gt;부재중 통화가 있다.&lt;/li&gt;&lt;li&gt;부재중 통화가 없고 알림이 온다.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;부재중 통화가 있는 것을 $p$, 알림이 온다는 것을 $q$라 한다면 이렇게 된다.&lt;br /&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;$p \rightarrow q$&lt;/li&gt;&lt;li&gt;$p$&lt;/li&gt;&lt;li&gt;$\lnot p \land q$&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;이고 모순이 없다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그러나 마지막 조건이 '부재중 통화가 있고 알림이 없다'면 $p \land \lnot q$인데 1번 조건을 위배한 것이 되므로 모순이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 class=&quot;&quot;&gt;1.2.3 논리와 비트(Logic &amp;amp; Bits).&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;T=1, F=1로 다룬다. 참 또는 거짓을 값으로 갖는 변수를 불 변수(Boolean variable)라고 한다.&lt;/p&gt;
&lt;p&gt;컴퓨터 비트 연산은 논리 접속사와 대응됨. 프로그래밍에서 $\land \lor \oplus$를 각각 AND, OR, XOR로도 표기함.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;비트 문자열이란 0개 이상의 비트를 갖는 비트열을 말한다. 비트 문자열의 길이란 문자열을 구성하는 비트의 수를 말한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;나중에 논리회로에서 더 자세히 다룰 듯.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 논리회로에서 자주 사용하는 몇몇 연산.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;부정을 해놓은게 많다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;부정 논리합(NOR, $\downarrow$): 논리합($\lor$)의 부정이다.&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \downarrow q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;부정 논리곱(NAND, $\uparrow$): 논리곱($\land$의 부정이다.&lt;br /&gt;&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \uparrow q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:52.94pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;F&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:101.40pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;T&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;+.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;수학적으로 따지는 건 위키백과의 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%B6%88_%EB%8C%80%EC%88%98&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;불 대수&lt;/a&gt;를 보면 좋은데, 여기에 쓰기에 넘치는 내용들이 많다.&lt;/p&gt;
&lt;p&gt;나중에 공부해서 정리할 일이 있으면 풀어서 해설해봄.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 class=&quot;&quot;&gt;&lt;b&gt;1.2.4 퍼지 논리(Fuzzy Logic).&lt;br /&gt;&lt;/b&gt;&lt;/h3&gt;&lt;p&gt;애매함을 정량적으로 표현하기 위하여 만들어진 이론이다.&lt;/p&gt;
&lt;p&gt;$T$가 아니면 $F$같은 이진법 같은 논리에서 벗어나 속하는 정도(Degree)를 표현할 수 있다.&lt;/p&gt;
&lt;p&gt;$0$을 $F$로, $1$을 T로 하면  중간에 속한 정도를 $0.2, \; 0.5, \; 0.8$처럼 나타낸다는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 확률과의 차이&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;퍼지 이론에서 말하는 '속한 정도'는 어떻게 나타낼 수 있을까?&lt;/p&gt;
&lt;p&gt;그러면 드는 생각이 '이거.. 확률이랑 똑같은거 야냐?' 인데 차이가 있다.&lt;/p&gt;
&lt;p&gt;학률로 $20%$라 하면 $20%$의 확률로 $1$에 $80%$ 확률로 $0$에 결정이 나는 것이라면(확률에 따라 전체가 
결정됨), 퍼지 논리는 이미 $20%$는 $1$의 집합에 나머지 $80%$는 $0$집합에 있다는 것이다.(이미 나뉘어진 상태임)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 정의.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이제 약간 더 정교하게 알아봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;퍼지 집합 $A$, 임의의 집합 $U$, 소속함수(membership function) $\mu_A$라 하며, $\mu_A : U \to [0, 1]$란 조건이 붙는다고 하자.&lt;br /&gt;* 참고로 소속함수는 '어떤 원소가 집합에 소속된 정도를 나타내어 주는 함수'다.&lt;/p&gt;
&lt;p&gt;$$A = \left\{(x, \mu_A(x))|x \in U \right\}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;원소나열법처럼 나타내는 방식이 존재하기도 하다.&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot; style=&quot;text-align: left;&quot;&gt;기분이 좋은 정도를 아주 좋음(1), 상당히 좋음(0.8), 
약간 좋음(0.6), 약간 나쁨(0.4), 상당히 나쁨(0.2), 나쁨(0)로 여섯가지로 할 때, 
$U={1,2,3,4,5,6}$과 대응되는 $A={\mu_A(1)=1, \mu_A(2)=0.8, \mu_A(3)=0.6, 
\mu_A(4)=0.4, \mu_A(5)=0.2, \mu_A(6)=0}$라 나타낼 수 있다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그럼 $A$는 튜플을 이용해&lt;br /&gt;$$A={(1,1), (2,0.8), (3,0.6), (4,0.4), 
(5,0.2), (6,0)}$$로 표현하면 된다. 뭐.. $\left\{ x \in U | \mu_A(x) \ne 0 
\right\}$이 무한집합이면 나열할 수 없겠지만.(초한기수를 원소나열법으로 나타낼 수 없는 것과 같다.)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 계산.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;퍼지 논리도 '퍼지 집합'이란 개념이 들어가는 만큼 집합의 연산 방식을 사용하여 계산할 수 있다.&lt;/p&gt;
&lt;p&gt;여집합: $1-소속도$를 하면 된다.&lt;/p&gt;
&lt;p&gt;$$\mu_{A^c}(x) = 1 - \mu_A(x)$$&lt;/p&gt;
&lt;p&gt;예) $\lnot \mu_A(2)= 1-0.8=0.2$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;합집합: 비교한 것 중 큰 소속도를 선택하면 된다.&lt;/p&gt;
&lt;p&gt;$$\mu_{A \cup B}(x) = \max \left ( \mu_A \left ( x \right ), \mu_B \left ( x \right ) \right )$$&lt;/p&gt;
&lt;p&gt;예) $\mu_A(2) \lor \mu_A(5)=\max(0.8,0.2)=0.8$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;교집합: 비교한 것중 작은 소속도를 선택하면 된다.&lt;/p&gt;
&lt;p&gt;$$\mu_{A \cap B}(x) = \min \left ( \mu_A \left ( x \right ), \mu_B \left ( x \right ) \right )$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예) $\mu_A(2) \land \mu_A(5)=\min(0.8,0.2)=0.2$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;차집합: 소속도를 빼면 된다.&lt;/p&gt;
&lt;p&gt;$$A - B = A \cap B^c$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예) $\mu_A(2) - \mu_A(5)=0.8-0.2=0.6$ 이건 딱히 대응되는게 없네..&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.2.5 고급 검색 기능.&lt;/h3&gt;&lt;p&gt;검색 엔진에도 명제를 활용한 기능이 있다.&lt;/p&gt;
&lt;p&gt;바로 고급 검색 기능!!&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;모두 포함(띄어쓰기를 이용한 검색어)과 정확하게 포함(&quot;검색어&quot;)는 $\land$를 뜻한다.&lt;/p&gt;
&lt;p&gt;둘의 차이라면 &quot;&quot;사이에 들어가는 것은 구처럼 취급한다는 것.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;검색어 OR 검색어는 $\lor$을 뜻하며 -검색어는 $\lnot$의 의미이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예) 명제 논리 OR 합 &quot;논리 곱&quot; -부정&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995E70425BE9FA361B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995E70425BE9FA361B&quot; width=&quot;800&quot; height=&quot;306&quot; filename=&quot;search.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1.3 명제의 동치.&lt;/h2&gt;&lt;p&gt;동일한 진리값을 가지는 다른 명제표현으로 대체할 수 있다는 것은 복잡한 명제를 간소화하거나 쉽게 바뀔 수 있다는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;전체 복합명제의 값이 항상 참일 때는 항진명제(tautology)&lt;/p&gt;
&lt;p&gt;전체 복합명제의 값이 항상 거짓일 경우는 모순(contradiction)&lt;/p&gt;
&lt;p&gt;참일 수도 있고, 거짓일 수도 있는 경우는 불확정명제(contingency)라 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.3.1 논리적 동치.&lt;/h3&gt;&lt;p&gt;두개의 복합명제가 모든 가능한 경우에 대하여 같은 진리값을 가지면 논리적으로 동치(logically equivalent)라 한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;복합명제 $p,q$에 대하여, $p\leftrightarrow q$가 항진이면, $p$와 $q$는 논리적으로 동치이며, $p\equiv q$라 표시한다.($\equiv$는 논리 연산자가 아님, $\Leftrightarrow$도 사용 가능.)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;논리적 동치를 보이는 것은 &lt;b&gt;1.1.5 복합명제와 진리표.&lt;/b&gt;처럼 진리표를 만들면 된다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;유명한 논리적 동치 관계를 정리해놓은 표를 첨부한다.&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; style=&quot;width:419.52pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;논리적 동치식&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \land T \equiv p$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \lor F \equiv p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;동일법칙&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$(p \lor q) \lor r \equiv p \lor (q \lor r)$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$(p \land q) \land r \equiv p \land (q \land r)$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;결합법칙&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \lor T \equiv T$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \land F \equiv F$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;지배법칙&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \lor (q \land r) \equiv (p\lor q)\land(p \lor r)$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \land (q \lor r) \equiv (p\land q)\lor(p \land r)$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;분배법칙&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \lor p \equiv p$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \land p \equiv p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;멱등법칙&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$\lnot(p \land q)\equiv \lnot q\lor \lnot q$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$\lnot(p \lor q)\equiv \lnot q\land \lnot q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;드모르간 법칙&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$\lnot(\lnot p) \equiv p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;이중부정법칙&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \lor(p \land q)\equiv p$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \land(p \lor q)\equiv p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;흡수법칙&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \lor q \equiv q \lor p$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \land q \equiv q \land p$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \leftrightarrow q\equiv q\leftrightarrow p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;교환법칙&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$\lnot T \equiv F$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$\lnot F \equiv T$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \lor \lnot p \equiv T$&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \land \lnot p \equiv F$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:104.88pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;부정법칙&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; style=&quot;width:419.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;조건문을 포함한 논리적 동치&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \rightarrow q \equiv \lnot p\lor q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$(p\rightarrow q)\land(p\rightarrow r)\equiv p\rightarrow (q\land r)$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p \rightarrow q \equiv \lnot q \rightarrow \lnot p$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$(p\rightarrow r)\land(q\rightarrow r)\equiv (p\lor q)\rightarrow r$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p\lor q \equiv \lnot p \rightarrow q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$(p\rightarrow q)\lor(p\rightarrow r)\equiv p\rightarrow (q\lor r)$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p\land q \equiv \lnot(p\rightarrow \lnot q)$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$(p\rightarrow r)\lor(q\rightarrow r)\equiv (p\land q)\rightarrow r$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$\lnot(p\rightarrow q)\equiv p \land \lnot q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;  &amp;nbsp;  &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; style=&quot;width:419.54pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family:함초롬바탕;mso-fareast-font-family:함초롬바탕;&quot;&gt;상호 조건문을 포함한 논리적 동치&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p\leftrightarrow q\equiv (p\rightarrow q)\land(q\rightarrow p)$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p\leftrightarrow q\equiv (p\land q)\lor(\lnot p\land \lnot q)$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$p\leftrightarrow q\equiv \lnot p\leftrightarrow \lnot q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;mso-fareast-font-family:함초롬바탕;mso-font-width:100%;letter-spacing:0pt;mso-text-raise:0pt;&quot;&gt;$\lnot(p\leftrightarrow q)\equiv p\leftrightarrow \lnot q$&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;논리적 동치식을 이용하여 식을 간단하게 만들어봅시다.&lt;/p&gt;
&lt;p&gt;$$\begin{matrix}\lnot(\lnot p \lor q) &amp;amp;\equiv&amp;amp; \lnot (\lnot p)\land\lnot q &amp;amp;...&amp;amp;드모르간 법칙\\&lt;br /&gt;&amp;amp;\equiv&amp;amp; p \land\lnot q &amp;amp;...&amp;amp;이중부정법칙\end{matrix}$$&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;$$\begin{matrix}\lnot(p \rightarrow \lnot q)\lor \lnot(p \rightarrow q) &amp;amp;\equiv&amp;amp; (p\land q)\lor(p \land \lnot q) &amp;amp;...&amp;amp;조건법칙\\&lt;br /&gt;&amp;amp;\equiv&amp;amp; p\land(q\lor\lnot q) &amp;amp;...&amp;amp;분배법칙\\&lt;br /&gt;&amp;amp;\equiv&amp;amp; p\land T &amp;amp;...&amp;amp;부정법칙\\&lt;br /&gt;&amp;amp;\equiv&amp;amp; p &amp;amp;...&amp;amp;동일법칙\end{matrix}$$&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;위의 법칙들만 알고 있다면 진리표없이 일반적인 대수계산처럼 할 수 있습니다!!&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.3.2 명제의 만족가능성.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;어떤 복합명제에 대하여 그 명제가 참이 되도록 그 명제의 변수들에 진리값을 할당할 수 있으면 그 명제가 '만족가능($\top$)'하다고 한다.&lt;/p&gt;
&lt;p&gt;반대로 어떤 값을 주더라도 그 명제가 거짓일 경우 그 복합명제는 '만족불가능($\bot$)'하다고 한다.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;예를 들면,&lt;/p&gt;
&lt;p&gt;$p \land q$는 만족가능하지만, $p \land (q \land \lnot q)$는 어떠한 진리값을 할당하더라도 만족불가능합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%8F%84%EC%BF%A0&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;스도쿠&lt;/a&gt;가 대표적인 명제 만족가능성을 이용한 활용이라 할 수 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;photos&quot;&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Sudoku_Puzzle_by_L2G-20050714_standardized_layout.svg/2560px-Sudoku_Puzzle_by_L2G-20050714_standardized_layout.svg.png&quot;&gt;
&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/1/12/Sudoku_Puzzle_by_L2G-20050714_solution_standardized_layout.svg/2560px-Sudoku_Puzzle_by_L2G-20050714_solution_standardized_layout.svg.png&quot;&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1.4 술어와 한정기호.&lt;/h2&gt;&lt;p&gt;우리가 지금까지 배웠던 명제 논리는 최소단위가 '명제'이므로 명제 관계끼리 독립적이기 때문에 논리적 관계는 알 수 있어도 명제 내부구조를 분석할 수 없다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예를 들어 앞서 예제로 나왔던&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;$x+1=3$&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&amp;nbsp;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;또는&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;모든 사람은 숨을 쉰다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;를 말미암아&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;나는 숨을 쉰다.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;를 증명할 수 없다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;그래서 나온 것이 바로 술어논리!!&lt;/p&gt;
&lt;p&gt;차근차근 배워보도록 합시다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.4.1 술어(Predicate), 양화(量化).&lt;/h3&gt;&lt;p&gt;자연어 문장의 주성분은 주어(문장의 주체), 서술어(주어를 서술), 보어(서술어를 보충), 목적어(타동사의 대상)으로 나뉘어져 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이 중 보통 서술어에 해당하는 부분이 바로 술어로 'A는 B이다'에서 B가 바로 술어이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;주어 A는 임의의 변수 $x$, B에 해당하는 술어를 $P$라는 기호로 나타내면(관습)&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;위 문장은 $P(x)$란 명제함수가 된다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$x$에 해당하는 부분(명제함수의 모든 변수)에 특정 값을 대입하면 $P(x)$가 명제가 되며 진리값 판별이 가능해진다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;명제함수 $P(x)$가 $x+1=3$일 때 $P(2)=T$, $P(5)=F$이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;명제함수 $Q(x)$가 &quot;$x$는 숨을 쉰다&quot;일 때 $Q(Me)=T$, $Q(Paper)=F$처럼 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;뭔가 프로그래밍 하는 것 같지 않나요?&lt;/p&gt;
&lt;p&gt;프로그래밍에서 함수에 여러가지 인수를 넣을 수 있는 것처럼, 명제함수에서도 여러개의 변수를 넣을 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;역시 앞서 나왔던&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;$x+y=3$&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;를 $R(x,y)$라 하면 $R(1,2)=T$, $R(2,3)=F$같은 결과가 나온다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;지금까지 살펴본 것처럼 명제함수 $P(x_1, x_2, ...., x_n)$는 명제함수 P의 $n$-튜플 $(x_1,x_2,....,x_n)$의 값이고, $P$를 $n$-변수 술어($n$-place predicate) 또는 $n$-항 술어($n$-ary predicate)라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;전조건과 후조건.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;컴퓨터 프로그램의 입력-출력을 확증할 때 술어의 원리가 사용된다.&lt;/p&gt;
&lt;p&gt;전조건은 올바른 입력 조건, 후조건은 해당되는 출력 조건.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Ex) 입력값 $x,y$를 넣을 때, 출력값 $w,z$며 입력 값으로 곱셈, 나눗셈을 한 값이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;올바른 입력 조건, 출력 조건은 무엇일까?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;전조건에서는 연산이 가능한 값이 들어가야 한다.&lt;/p&gt;
&lt;p&gt;이 예에서 $y$에는 $0$이 불가(0으로 나누기).&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;후조건은 $w = x \times y$, $z = x \div y$라 할 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;본격적으로 술어논리(양화논리)를 배워나가도록 합시다.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.4.2 한정기호(Quantifier), 양화사.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;한정화는 술어가 원소들의 참이 되는 범위를 표현한다.(모든, 어떤, 아무도 등등)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;열린 문장이 의미를 지닐 수 있게 하기 위해서는 변항(변수)이 한정기호를 통해 속박(bound)되어야 한다.(구속변수, binding variable) 이때 한정기호에 의해 속박되지 않은 변항을 자유 변항(free variable)이라고 한다. 자유 변항만으로 이루어진 표현을 식(formula)이라고 한다. 어떠한 변항도 자유롭게 나타나지 않는 식이 문장(sentence)이다.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;한정기호가 적용되는 부분을 한정기호의 범위(scope)라고 한다.[범위에 속하지 않는게 자유 변항이겠죠?]&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;- 전칭 한정기호(Universal Quantifier), 보편양화사.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;고려 대상이 되는(정의역인) 모든 원소들에 대해 술어가 항상 성립하는 것.&lt;/p&gt;&lt;p&gt;$P(x)$의 전칭 한정은 $\forall xP(x)$로 표시하며 '임의의 $x$에 대하여 $P(x)$는 참이다'는 의미를 가진다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;정의역에 속하는 값을 $x_1,x_2,x_3,...$ 일 때 $P(x_1)\land P(x_2)\land P(x_3)\land ...$처럼 논리곱의 형태로 나타낼 수 있다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;- 존재 한정기호(Existential Quentifier) 존재양화사.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;술어가 참이 되는 정의역의 원소가 1개 이상 있는 것.&lt;/p&gt;&lt;p&gt;$P(x)$의 존재 한정은 $\exists xP(x)$로 표시하며 '어떤 $x$에 대하여 참인 $P(x)$가 존재한다'는 의미를 가진다..&lt;br /&gt;&lt;br /&gt;정의역에 속하는 값을 $x_1,x_2,x_3,...$ 일 때 $P(x_1)\lor P(x_2)\lor P(x_3)\lor ...$처럼 논리합의 형태로 나타낼 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$\exists !$ 또는 $\exists _1$표시는 유일 한정기호로, 유일성을 표현한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;예시.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;한정기호($\forall , \exists$)는 명제 논리의 논리 연산자들보다 상위의 우선순위를 가진다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$x \in \mathbb{R}$이라 가정할 때.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;$\forall x(x &amp;lt; x + 5)$:&amp;nbsp; 임의의 정수 $x$ 값은 $x+5$ 보다 항상 작으므로 $T$&lt;/p&gt;&lt;p class=&quot;&quot;&gt;$\exists x(x &amp;lt; x + 5)$: 역시 해당하는 $x$는 존재. $T$&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;$\forall x&amp;lt;3(x = 2)$: 임의의 정수 $x$ 값이 2와 항상 같지 않으므로 $F$&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;$\exists x&amp;lt;2(x = 2)$: $x&amp;lt;2$인 정수 중 $x=2$가 나올 수 없으므로 $F$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$\forall x&amp;lt;3(x = 2)$는 $\forall x(x&amp;lt;3 \to x=2)$&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;$\exists x&amp;lt;2(x = 2)$는 $\exists x(x&amp;lt;2 \land x=2)$와 같은 표현방식이다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;- 동치와 부정.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;같은 진리값을 가질때 쓰이는 동치($\equiv$)와 부정($\lnot$)을 사용한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;부정&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;동치식&amp;nbsp;  &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;$\lnot \exists xP(x)$&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;$\forall x\lnot P(x)$&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;$\lnot \forall xP(x)$&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:209.77pt;height:2.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;$\exists x\lnot P(x)$&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;!--[if !mso]&gt;
&lt;style&gt;
v\:* {behavior:url(#default#vml);}
o\:* {behavior:url(#default#vml);}
w\:* {behavior:url(#default#vml);}
.shape {behavior:url(#default#vml);}
&lt;/style&gt;
&lt;![endif]
--&gt;&lt;/p&gt;&lt;p&gt;드모르간 법칙을 이용하면 위와 같은 결과를 얻을 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.4.3 술어의 활용.&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 자연어 문장의 논리적 표현 변환.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;카페 서비스의 모든 사용자는 음료를 시킨다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;카페 서비스의 어떤 사용자는 커피를 마신다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;를 술어로 바꾸어보자.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위의 자연어 문장은 다음과 같은 의미를 함유하고 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;모든 사용자 $x$는 카페 서비스를 이용하며, $x$는 음료를 시킨다.&lt;/p&gt;&lt;p&gt;어떤 사용자 $y$는 카페 서비스를 이용하며, $y$는 커피를 마신다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;음료를 시키고, 커피를 마시는 동작은 $\operatorname{drink}(x)$, $\operatorname{coffee}(y)$라는 술어가 되며 정의역은 카페를 사용하는 사용자가 된다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;결과.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;$\forall x \; \operatorname{drink}(x)$, $\exists x \; \operatorname{coffee}(y)$&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;만약 $x$(정의역)의 대상이 모든 사람이라면,&lt;/p&gt;&lt;p&gt;모든 사람인 $x$에 대해 $x$가 카페 서비스를 이용하는 사용자라면, $x$는 음료를 시킨다.&lt;/p&gt;&lt;p&gt;어떤 사람인 $y$에 대해 $y$가 카페 서비스를 이용하는 사용자라면, $y$는 커피를 마신다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;카페 서비스를 이용하는 것은 $\operatorname{cafe}(x)$, $\operatorname{cafe}(y)$로 표현 할 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;결과.&lt;/b&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;$\forall x(\operatorname{cafe}(x) \to \operatorname{drink}(x))$&lt;/p&gt;&lt;p class=&quot;&quot;&gt;$\exists y(\operatorname{cafe}(x) \land \operatorname{coffee}(y))$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;$\forall x(\operatorname{cafe}(x) \land \operatorname{drink}(x))$와 $\exists y(\operatorname{cafe}(y) \to \operatorname{coffee}(y))$가 아닌 이유.&lt;/p&gt;&lt;p&gt;$\forall x(\operatorname{cafe}(x) \land \operatorname{drink}(x))$일 경우, 모든 사람이 카페를 이용 및 음료를 시킨다는 뜻으로 의미가 달라진다.&lt;/p&gt;&lt;p&gt;$\exists y(\operatorname{cafe}(y) \to \operatorname{coffee}(y))$는 $F \to T$, $F \to F$가 모두 참이 되기 때문에 원 의미와 달라진다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Element of Style이란 책과 영어 문법책, 문장강화등을 고려해 '좋은 글과 프로그래밍'이라는 글을 기획하고 있다. 아마 토익 공부를 열심히 할 때 쯤 심심해서 올리지 않을까 싶다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 시스템 명세에 한정기호 사용.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;1.2.2 시스템 명세와 비슷하거나 확장한 예를 들어보겠다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;모든 전화는 스팸과 방해금지 모드를 체크한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;어떤 부재중 전화는 알림이 온다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$\forall $&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 이상한 나라의 앨리스.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 논리 프로그래밍.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;1.5 중첩된 한정기호.&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;1.6 추론 규칙.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;예를 들어봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;행복을 추구하는 인간의 성향도, 자비심과 같은 도덕 감정도 보편 윤리의 토가 될 수 없다 .&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* 2019년도 법학적성시험 추리논증 홀수형 20번에서 가져왔습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;자연어로 된 각종 논증구조 문제를 풀어보려면 법학적성시험(LEET)의 &lt;a href=&quot;https://leet.uwayapply.com/gichul/BoardList.htm?board_id=84&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;추리논증문제&lt;/a&gt;를 풀어보길 바랍니다.&lt;p&gt;1.7 증명의 소개.&lt;/p&gt;
&lt;p&gt;1.8 증명 방법과 전략.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;P.S.&lt;/p&gt;
&lt;p&gt;인터넷 밈인 짤을 넣는걸 살짝 시도해봤는데 귀찮아서 다음부터는 안넣을거 같다.&lt;/p&gt;
&lt;p&gt;이것&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;- 끝-&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;출처: Rosen의 이산수학, 이산수학 Express, 위키피디아 [&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%AA%85%EC%A0%9C&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;명제&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%AA%85%EC%A0%9C%EB%85%BC%EB%A6%AC&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;명제논리&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%8A%9C%ED%94%8C&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;튜플&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%81%B4%EB%A0%88%EC%9D%B4%EB%8B%88_%EC%8A%A4%ED%83%80&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;클레이니 스타&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%88%A0%EC%96%B4_%EB%85%BC%EB%A6%AC&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;술어 논리&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%B8%EC%8B%9D%EB%A1%A0&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;인식론&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%8D%BC%EC%A7%80_%EB%85%BC%EB%A6%AC&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;퍼지 논리&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%8D%BC%EC%A7%80_%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;퍼지 집합&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Well-formed_formula&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Well-formed formula&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Context-free_grammar&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Context-free grammar&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Backus–Naur form&lt;/a&gt;, ], 나무위키[&lt;a href=&quot;https://namu.wiki/w/%EC%96%91%ED%99%94%20%EB%85%BC%EB%A6%AC&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;양화 논리&lt;/a&gt;] &lt;a href=&quot;http://www.aistudy.co.kr/linguistics/free_linz.htm&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;문맥-자유 언어&lt;/a&gt;, &lt;a href=&quot;http://www.aistudy.co.kr/linguistics/natural/nlp_kim.htm&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;자연어 이해&lt;/a&gt;, &lt;a href=&quot;http://www.snunews.com/news/articleView.html?idxno=11883&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;완벽을 추구한 한 수학자의 이야기&lt;/a&gt;, &lt;a href=&quot;http://www.laborsbook.org/dic/view.php?dic_part=dic05&amp;amp;idx=2084&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;수학 기초론&lt;/a&gt;,&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>수학/이산수학</category>
      <category>논리</category>
      <category>명제</category>
      <category>수학</category>
      <category>이산수학</category>
      <category>프롤로그</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/45</guid>
      <comments>https://black7375.tistory.com/45#entry45comment</comments>
      <pubDate>Tue, 31 Jul 2018 12:16:18 +0900</pubDate>
    </item>
    <item>
      <title>집합(위상)과 극한에 대하여[일부 내용 펌].</title>
      <link>https://black7375.tistory.com/44</link>
      <description>&lt;p&gt;* 타 블로그의 &lt;b&gt;펌 내용&lt;/b&gt;이 있기 때문에 저작권 문제가 생길 시 언제든 글을 비공개나 삭제 및 수정할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;극한의 정의에 극한 점을 알기 위해선 위상 수학에 나오는 고립점에 대한 이해가 필요하기 때문에 선행합니다.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1. [펌] 집합과 위상(Set and Topology).&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;' &lt;a href=&quot;https://blog.naver.com/PostView.nhn?blogId=min311r&amp;amp;logNo=110131488760&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;개집합, 폐집합, 도집합과 고립점... 그리고 전혀 상관없는 칸토어 집합|작성자 곰그지&lt;/a&gt; ' 이라는 글을 깔끔하도록 일부 고쳐 쓴 내용입니다. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;펌 허락 받았습니다. 헤헤.&lt;/p&gt;&lt;p&gt;허락해주신 곰그지님께 감사인사를 먼저 드립니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;집합 내용이 이해가 안된다면&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/43&quot; target=&quot;_blank&quot;&gt;2018/07/22 - [수학] - 무한, 집합, 그리고 수에 대해서.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;참고.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;또한 개구간, 폐구간 등 구간을 나타내는데 사용한 $($와 $)$는 $&amp;lt;$, $[$와 $]$는 $\leq$의 의미인건 아시죠?&lt;/p&gt;&lt;p&gt;모르면 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B5%AC%EA%B0%84&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;구간&lt;/a&gt; 참고.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.1 위상(Topology).&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;위상은 일단 원소자체가 집합입니다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;그래서 집합론을 조금이라도 공부해놓으면 도움이 되죠.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그렇기 때문에 전체 집합에 포함되는 부분집합들을 가지고 연산을 해볼까 합니다.&lt;/p&gt;&lt;p&gt;집합의 연산이기 때문에 주 연산은 &quot;합집합, 교집합&quot;입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예를 들어, 전체집합은 $X=\{1,2,3,4,5\}$라 두고, 전체집합의 부분집합 $A=\{1\}\; B=\{2,3\}\; C=\{1,2,3\}$ 인 부분집합이 있다고 칩시다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;이 때 집합족 $\mathcal{T}=\{A,B,C\}$를 위상이라 부르고 싶습니다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;우리가 대수에서 얼핏 배웠던 그럴싸한 이야기. 일단 '연산에 닫혀있다'라는 이야기를 해봅시다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;1. 위상의 원소들의 합집합은 위상의 원소여야해.&lt;/p&gt;&lt;p&gt;2. 위상의 원소들의 교집합은 위상의 원소여야해.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$A,B,C$ 같은 경우에 아무리 교집합, 합집합을 해도 결과는&lt;/p&gt;&lt;p&gt;$A,B,C,\emptyset$. 이 네개 중 하나이죠.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;공집합은 $\mathcal{T}$의 원소가 아니자나요!!! 그래서 공집합($\emptyset$)을 추가 시킵니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 이왕이면 여집합을 생각하기 때문에, 전체 집합 $X$도 위상의 원소에 추가시킵니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 위의 두가지 조건에 추가로&lt;br /&gt;&lt;/p&gt;&lt;p&gt;3. 위상의 원소에는 전체집합($X$)과 공집합($\emptyset$)은 당연히 들어갑니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이러한 규칙들을 약속한 집합족 $\mathcal{T}=\{A,B,C, \emptyset, X\}$를 '위상'이란 이름으로 부르게 됩니다.... 짝짝짝!!!!&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위키피디아의 내용을 가지고 간단한 예를 보면 이해가 더 잘됩니다.&lt;/p&gt;&lt;p&gt;앞서 정의한 집합 $C$를 가지고 어떤 것이 위상을 이루고, 어떤 것이 위상을 이루지 않는지 확인해봅시다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;먼저 위상을 이루는 것.&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;$\{\emptyset,\{1,2,3\}\}$&lt;/li&gt;&lt;li&gt;$\{\emptyset,\{1,2,3\},\{1\}\}$&lt;/li&gt;&lt;li&gt;$\{\emptyset,\{1,2,3\},\{1,2\},\{1\},\{2\}\}$&lt;/li&gt;&lt;li&gt;$\{\emptyset,\{1,2,3\},\{1,2\},\{2,3\},\{2\}\}$&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이번엔 위상을 이루지 않는것.&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;$\{\emptyset,\{1,2,3\},\{2\},\{3\}\}$&lt;br /&gt;이유: $\{2\}$와 $\{3\}$의 합집합인 $\{2,3\}$이 없으므로 위상이 아니다.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;$\{\emptyset,\{1,2,3\},\{1,2\},\{2,3\}\}$&lt;br /&gt;이유: $\{1, 2\}$와 $\{2, 3\}$의 교집합인 $\{2\}$가 없으므로 위상이 아니다.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;그림으로 보면 다음과 같습니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 360px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99EDC43F5BE76F082F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99EDC43F5BE76F082F&quot; width=&quot;360&quot; height=&quot;319&quot; filename=&quot;Topological_space_examples.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;어느 정도 이해가 됐죠?&lt;/p&gt;&lt;p&gt;이제 엄근진하게 정리를 해봅시다.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;집합 $X$와 멱집합($\mathcal{P}(X)$)라 할 때 위상($\mathcal{T}$)은 다음의 조건을 만족해야 하는 $\mathcal{T} \subseteq \mathcal{P}(X)$다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$$\emptyset,X \in \mathcal{T} \\&lt;br /&gt;A \subseteq \mathcal{T} \Rightarrow \bigcup A \in \mathcal{T}\\&lt;br /&gt;B,C\in\mathcal T \Rightarrow B\cap C \in\mathcal T $$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설명.&lt;/b&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;&lt;p&gt;$X$의 멱집합 $\mathcal{P}(X)$의 부분 집합이니 공집합($\emptyset$)과 전체집합($X$)이 원소로 들어간다.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;위상 원소들의 합집합은 위상의 원소.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;위상 원소들의 교집합은 위상의 원소.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;* $A$은 $\mathcal{T}$의 부분집합이며 $B,C$는 $\mathcal{T}$의 원소이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;여기서 주의할 점은 위상의 합집합은 무한개를 해도 위상의 원소지만(2번), 교집합은 유한 교집합의 원소만 위상의 원소이다.(3번)&lt;br /&gt;&lt;br /&gt;간단하게 생각해서 $X=\{(a,b) | a,b \in \mathbb{R}\}$, 그러니까 실수인 $a,b$의 $(a,b)$(개구간)을 집합 $X$라 할 때&lt;br /&gt;&lt;/p&gt;&lt;p&gt;합집합을 해보면 항상 개구간만 나옵니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 $(-{1 \over n}, {1 \over n})$을 무한히 교집합하면 $\{0\}$이라는 한점 집합이 나옵니다.&lt;br /&gt;우리는 열린 구간을 위상으로 정의하고 싶은데 점들이 돌아다녀요.&lt;br /&gt;그러다 보면 $\{0\} \cup (0,1) = [0,1)$ 이런 구간들이 만들어지므로 빼버리는 것이다.&lt;/p&gt;&lt;p&gt;다시말해 3번은 $$A_{\alpha}\in\mathcal{T}\left(\alpha\in\left\{1,2,3,...,m\right\}\right) \Rightarrow {\displaystyle \bigcap_{\alpha=1}^{m}A_{\alpha}\in\mathcal{T}}$$라는 것&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;자 그렇게 해서 만들어진 양끝을 포함하지 않는 집합(개구간)들에 공집합과 전체집합을 정의해주면 위상이 잘 정의가 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위상공간 $(X, \mathcal{T})$는 위상을 갖춘 집합이다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.2 개집합과 폐집합(Open, Closed set).&lt;/h3&gt;&lt;p&gt;개집합의 정의 정말 쉽습니다!!!.&lt;br /&gt;딱 하나만 기억하세요. 위상의 원소인가????&lt;br /&gt;&lt;br /&gt;개집합의 정의는 주어진 위상에 포함되는 원소이다! 라는 것만 기억하면 된다.&lt;br /&gt;위상의 원소의 이름이 개집합이라고 기억해도 됩니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;아까 말했던 실수에서의 보통위상에서 다음이 개집합인지 따져봅시다.&lt;br /&gt;$(0,1)$: 당연히 $U$의 원소죠. 개집합입니다&lt;br /&gt;$[0,1)$: $U$의 원소가 아니죠. 개집합이 아닙니다.&lt;br /&gt;$(-\infty , 4)$: $(-n,4)$ 라는 녀석을 무한 합집합을 하면 만들 수 있습니다. 위상의 원소입니다. 즉, 개집합!&lt;br /&gt;&lt;br /&gt;그럼 이번에는 폐집합을 정의해봅니다.&lt;br /&gt;폐집합은 개집합의 여집합으로 기억하면 좋습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예를 들어보죠.&lt;br /&gt;$[0,4]$는 폐집합일까요?&lt;br /&gt;$(-\infty , 0)$은 개집합입니다. 그리고 $(4, \infty)$도 개집합입니다.&lt;br /&gt;두 개를 합집합 해도 개집합입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이 개집합을 전체에서 빼보죠. $$\mathbb{R} - ((-\infty , 0) \cup (4,\infty)) = [0,4]$$&lt;br /&gt;$[0,4]$는 폐집합이란 것을 알 수 있습니다. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;개집합은 스스로의 경계를 전혀 포함하지 않는 위상 공간의 부분 집합이며, 폐집합은 스스로의 경계를 모두 포함하는 위상 공간의 부분 집합이다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;전체집합에서 개집합을 빼면 폐집합이 된다. 즉, 여집합이라고 생각해도 된다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그런데 특이한 것은 개집합과 폐집합은 반대되는 개념이 아니며, 공존할 수 있다는 것이다.&lt;/p&gt;예를 들어 $(0,1],[0,1)$가 있으며 개폐집합이라 한다.&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;공집합은 위상의 원소입니다. 그럼 공집합의 여집합은? (전체집합)&lt;br /&gt;전체집합은 위상의 원소이죠. 그럼 전체집합의 여집합은? (공집합)&lt;br /&gt;&lt;br /&gt;그래서 전체집합과 공집합은 개집합이면서도 폐집합이 됩니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;또한 우리 위상의 원소는 무한합, 유한교가 가능하다라고 했습니다.&lt;/p&gt;&lt;p&gt;(무한합)의 여집합을 취하면 드모르간의 법칙 덕분에 합집합이 교집합으로 바뀝니다. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;따라서 폐집합에서는 무한교가, 유한합만 가능합니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.3 위상 공간 기본(Basics of Topology Space).&lt;/h3&gt;&lt;p&gt;자 그럼 개집합과 폐집합의 관계를 봅시다.&lt;br /&gt;$A = (0,1)$이라는 개집합이 있으면 $[0,1]$ 이라는 녀석은 저 개집합을 덮는 &lt;b&gt;최소의 폐집합&lt;/b&gt;입니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 폐포(Closure)라는 녀석을 정의합니다.&lt;br /&gt;역시 $X$를 집합, $T$를 위상공간($(X, \mathcal{T})$), $A \subset X$일 때,(앞으로도 별 말이 없으면 이와 같음.)&lt;br /&gt;$$\operatorname{Cl}(A) \overset{\underset{\mathrm{def}}{}}{\Longleftrightarrow} \bigcap \{K \supseteq A: K \text{ is closed in } T\}$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설명.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;폐포는 개집합을 포함하는 최소의 폐집합입니다.&lt;/p&gt;&lt;p&gt;$\operatorname{cl}(A), \operatorname{Cl}(A), \overline{A}, A^-$로 표현합니다.&lt;br /&gt;$(0,1)$을 포함하는 폐집합은 무한히 많겠죠. 하지만 $[0,1]$이 제일 작습니다.&lt;br /&gt;그럼 이제 0,1이라는 점에 초점을 맞춰보죠.&lt;br /&gt;&lt;br /&gt;우리가 새롭게 정의할 것은 내부(Interior)와 내점(Interior Point)입니다.&lt;br /&gt;집합이 개집합인가를 생각할 때 중요합니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;폐포와 조건이 같을 때, 내부는&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$$\operatorname{Int}(A) \overset{\underset{\mathrm{def}}{}}{\Longleftrightarrow}&amp;nbsp; \bigcup \{{K \in \mathcal{T}: K \subseteq A}\} $$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;설명.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;집합 $A$가 있는데 그 안에 $a$라는 점이 있어요. $a$를 포함하는 개집합이 $A$에 들어갈 수 있을때 $a$를 내점이라고 부르겠습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;역시 내점은 내부란 집합을 이루는 원소이고, 내부는 $\operatorname{Int}(A), A^\circ$처럼 표현 할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;어렵나요? 예를 들어보죠.&lt;br /&gt;$(0,1)$에서 ${1 \over 2}$는 내점입니다.&lt;br /&gt;$({1 \over 4}, {3 \over 4})$라는 개집합이 존재해서&amp;nbsp; ${1 \over 2} &amp;lt; ({1 \over 4}, {3 \over 4}) &amp;lt; (0,1)$&lt;br /&gt;이런 포함관계를 만족하잖아요. 이런 관계를 만족하는 개집합을 찾아줄 수 있으면 그 점을 내점이라고 부를거에요.&lt;br /&gt;&lt;br /&gt;$(0,1)$ 안에 들어있는 어떤 점을 마음속에서 생각해봅니다.&lt;br /&gt;생각하셨나요. 그 점을 $a$라고 했을 때&lt;br /&gt;&lt;br /&gt;$${1 \over 2} \times a &amp;lt; a \\&lt;br /&gt;a &amp;lt; {(1+a) \over 2}$$ 는 항상 성립하고&lt;br /&gt;어떤 점을 여러분이 떠올렸더라도 내점이 됩니다.&lt;br /&gt;&lt;br /&gt;그래서 개집합을 이렇게 정의도 합니다.&lt;br /&gt;주어진 집합에 속하는 모든 점이 내점이면 그 집합은 개집합이다.&lt;br /&gt;$\operatorname{Int}(A)$는 내점들의 모임이므로 항상 개집합입니다.&lt;br /&gt;&lt;br /&gt;자 그럼 이제 $0, 1$을 다시 생각해보죠.&lt;br /&gt;일단 $0$과 $1$은 $(0,1)$에 포함은 되지 않습니다.&lt;br /&gt;하지만 $0$이나 $1$을 포함하는 개집합은 반드시 $(0,1)$과 교집합이 존재합니다.&lt;br /&gt;이렇게 교집합이 생기는 점을 경계점이라고 이름 붙이고.... 이러한 점들의 집합을&lt;br /&gt;집합$A$의 경계, $\operatorname{Bd}(A)$라고 쓰도록 하죠.&lt;br /&gt;$$\operatorname{Bd}(A) \overset{\underset{\mathrm{def}}{}}{\Longleftrightarrow} \operatorname{Cl}(A) - \operatorname{Int}(A)$$경계는 $폐포 - 내부$(차집합)의 관계를 갖습니다.&lt;/p&gt;&lt;p&gt;$\operatorname{b}(A), \operatorname{Bd}(A), \operatorname{fr}(A), A^n$라고 표현하기도 한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;그리고 $(0,1)$에서 $3$을 생각해봅시다. $3$을 덮는 개집합중에서 $(2,4)$는 $(0,1)$과 교집합이 없습니다. 이처럼 $A$라는 집합 밖에서의 내점들의 집합을 외부라고 이름 붙이죠.&lt;br /&gt;외부는 $(\operatorname{Cl}A)^c$ 또는 $\operatorname{Int}(A^c)$[A의 폐포에 대한 여집합 또는 A여집합의 내부]라 생각할 수 있습니다. &lt;br /&gt;기호로는 $\operatorname{Ext}(A)$ 또는 $A^e$라고 씁니다.&lt;br /&gt;&lt;br /&gt;그럼 전체 집합은 다음과 같이 구분됩니다.&lt;br /&gt;$$전체집합 = \operatorname{Int}(A) \cup \operatorname{Bd}(A) \cup \operatorname{Ext}(A)$$&lt;br /&gt;&lt;br /&gt;$A$가 개집합이든, 폐집합이든, 개집합도 폐집합도 아니든.... 위의 한줄은 성립합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 320px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DB4B3F5B591FA011&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DB4B3F5B591FA011&quot; width=&quot;320&quot; height=&quot;212&quot; filename=&quot;topology1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;전체집합 $X$에 어떤 부분집합 $A$가 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 320px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BB12465B591FA00F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BB12465B591FA00F&quot; width=&quot;320&quot; height=&quot;213&quot; filename=&quot;topology2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;그럼 이 집합으로 만들 수 있는 개집합입니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 320px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A17D3E5B591FA011&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A17D3E5B591FA011&quot; width=&quot;320&quot; height=&quot;212&quot; filename=&quot;topology3.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;경계는 전체집합에서 내부와 외부를 빼서 찾아줄 수 있습니다.&lt;br /&gt;경계는 내부와 외부의 여집합이므로 폐집합이라는 것을 알 수 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;(추가 : $\operatorname{Ext}(A)$는 하얀색이라 표시가 잘 안되었어요.. 주의하세요 ㅎ)&lt;br /&gt;&lt;br /&gt;$A$가 어디까지인지 잘 참고 해주세요....&lt;br /&gt;&lt;br /&gt;일반적으로 아무 집합이나 주어졌을 때 이야기 할 수 있는 것은&lt;br /&gt;$\operatorname{Int}(A) &amp;lt; A$가 항상 성립합니다.&lt;br /&gt;&lt;br /&gt;경계점을 포함한 $\operatorname{Int}(A) + \operatorname{Bd}(A)$를 더해보면..... 그 여집합은 외부가 되기 때문에&lt;br /&gt;둘의 합은 폐집합이 됩니다.&lt;br /&gt;그리고 이 경계를 포함하는 폐집합이 결국 $A$를 포함하는 가장 작은 폐집합(폐포)이 됩니다.&lt;br /&gt;&lt;br /&gt;그래서 폐포를 다음과 같이 쓰기도 합니다.&lt;br /&gt;$$\operatorname{Cl}(A) = \operatorname{Int}(A) \cup \operatorname{Bd}(A)$$&lt;br /&gt;&lt;br /&gt;그럼 다음과 같은 그림의 포함관계가 되겠네요.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 320px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9998783E5B591FA012&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9998783E5B591FA012&quot; width=&quot;320&quot; height=&quot;213&quot; filename=&quot;topology4.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 본격적인 오늘의 주제를 도입해보죠.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.4 도집합이란?(derived set).&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;우리가 대충이나마 내부와 외부, 경계, 그리고 내부를 정의했습니다.&lt;br /&gt;&lt;br /&gt;이번에 정의할 개념은 집적점(accumulation point)의 개념이죠.&lt;br /&gt;경계를 찾는 다른 방법이라고 기억해두면 좋아요.&lt;br /&gt;본격적인 내용이니까 수식 한번 써볼까요&lt;br /&gt;&lt;br /&gt;&lt;b&gt;집적점 정의.&lt;/b&gt;&lt;br /&gt;점 $x$이 $x \in T$일 때,&lt;br /&gt;$$x \in \operatorname{Cl}(A - \{x\})$$그러니까 $U \subseteq&amp;nbsp; X$일 때 $(U - \{x\}) \cap A \neq \emptyset$관계가 성립하면 $x$를 $A$의 집적점이라고 한다.&lt;br /&gt;&lt;br /&gt;이런 집적점들의 집합을 도집합이라고 이름 붙입니다. (기호로는 $A'$ 많이 씁니다)&lt;br /&gt;&lt;br /&gt;$x$를 포함하는 개집합과 $A$의 교집합이 공집합이 아니다. 라는 결론이 나오죠.&lt;br /&gt;교집합이 공집합이 아니다라는 표현 어디서 봤죠? 바로 경계입니다.&lt;br /&gt;&lt;br /&gt;만약 $x$가 $A$ 안에 없으면 $x$를 덮는 개집합이 $A$와 교집합이 생기기 때문에 $x$는 경계에 속하죠. $X$에서 $x$를 빼던 말던 상관이 없으니까요.&lt;br /&gt;&lt;br /&gt;그렇기 때문에 경계의 점 중 $A$에 포함되지 않는 점들은 도집합에 포함됩니다.&lt;br /&gt;즉 도집합은 $A$에 포함되지 않는 경계를 구하는 방법이라고 생각해보면 좋겠네요.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;참고.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;사실 도집합은 모든 개집합의 존재 여부때문에 수열의 수렴성을 보장해주는 그런 점들의 모임이라는 좋은 의의를 가지기도 하지만.... 이야기 흐름상 위와 같이 생각해보고 넘어가겠습니다.&lt;br /&gt;&lt;br /&gt;자, 그럼 의문이 하나 듭니다. 내점의 경우에는요? 도집합과 무슨 관계가 있을까요?? &lt;br /&gt;내점의 경우에도 일반적으로 생각하면 도집합에 포함될 것 같습니다. 그런데 반례도 생겨요.&lt;br /&gt;어떤 경우냐면 바로 한 점이 개집합인 경우는? 내점은 되지만 도집합에 포함되지 않습니다.&lt;br /&gt;그래서 내점 중에서도 도집합에 포함되는 녀석이 있을 수 있다 라는 점을 짚고 넘어가죠.&lt;br /&gt;&lt;br /&gt;그러면 내점이 아니면 다 도집합에 포함 되냐? 그것도 아닙니다.&lt;br /&gt;예를 들어 우리가 $A$라는 집합을 $\{1\} \cup (2,3)$이라는 집합으로 줬습니다.&lt;br /&gt;$1$은 $A$의 점이지만 내점이 아니죠. 그래서 1은 경계에 포함됩니다.&lt;br /&gt;하지만 도집합에는 포함되지 않죠. 그러나 우리는 도집합을 $A$에 속하지 않는 경계를 찾는 법이라고 했으니까 특별히 정의에 문제가 되지 않습니다.&lt;br /&gt;도집합으로 모든 경계를 구할 수 없어요. 그래서 무슨 의미가 있겠냐? 라는 의문이 든다면... 이런 이야기는 가능합니다.&lt;br /&gt;우리가 정의했던 폐포를 다음과 같이 표현해도 문제 없습니다.&lt;br /&gt;&lt;br /&gt;$$\operatorname{Cl}(A) = \operatorname{Int}(A) \cup \operatorname{Bd}(A)=A \cup A'$$&lt;br /&gt;왜냐면 $A$에 속하지 않는 경계점은 모두 도집합에 들어가니까요.&lt;br /&gt;&lt;br /&gt;자 위의 내용을 바탕으로 그림을 한 번 그려보려 합니다. 과연 도집합의 모양은 어떤 모양일까!!!!!&lt;br /&gt;두구두구.....&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 320px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DBBB345B591FA01C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DBBB345B591FA01C&quot; width=&quot;320&quot; height=&quot;213&quot; filename=&quot;topology5.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;아까 $A$에 왜 선이 가있을까? 라고 의문을 가졌던 분들이 있겠죠... 도집합 표현하려고 한 것입니다.&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;$A$의 점이 도집합에 포함될 수 있다. &lt;br /&gt;&lt;/li&gt;&lt;li&gt;한점 개집합이 존재하는 경우, 내점이지만 도집합에 포함되지 않을 수 있다.&lt;/li&gt;&lt;li&gt;내점이 아니면서 도집합에 포함되는 점이 있을 수 있다.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br /&gt;자 그럼 슬슬 오늘 이야기의 핵심이 나옵니다.&lt;br /&gt;저 하얀 부분의 문제가 되는 점을 정의해줄 겁니다.&lt;br /&gt;왠만한 책에서는 찾아보기 힘들어요 ㅋㅋㅋ&lt;br /&gt;그래서 저는 위키신의 지혜를 빌리기로 결심합니다 ㅋㅋㅋ&lt;/p&gt;&lt;h3&gt;&lt;br /&gt;1.5 고립점(Isolated Point)&lt;/h3&gt;&lt;p&gt;&quot;0&quot; is an isolated point of A In topology, a branch of mathematics, a point x of a set S is called an isolated point of S, if there exists a neighborhood of x not containing other points of S.&lt;br /&gt;(x의 근방이 S라는 집합의 다른 점을 포함하지 않으면..... 근방은 가장 작은 개집합으로 생각하세요)&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 320px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997F48365B591FA01B&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997F48365B591FA01B&quot; width=&quot;320&quot; height=&quot;171&quot; filename=&quot;topology6.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;In particular, in a Euclidean space (or in a metric space), x is an isolated point of S, if one can find an open ball around x which contains no other points of S.&lt;br /&gt;(고립점에 대한 정의와 소개입니다. 위의 그림처럼 0처럼 동떨어져있으면 고립점이래요.)&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;A set which is made up only of isolated points is called a discrete set. Any discrete subset of Euclidean space is countable, since the isolation of each of its points (together with the fact the rationals are dense in the reals) means that it may be mapped 1-1 to a set of points with rational co-ordinates, of which there are only countably many. However, a set can be countable but not discrete, e.g. the rational numbers with the absolute difference metric. See also discrete space.&lt;br /&gt;(유클리드 공간에서 고립점들의 집합은 가산이래요, 하지만 역은 성립하지 않는데요)&lt;br /&gt;&lt;br /&gt;예) $S=\{0\} \cup \{1, {1 \over 2}, ..., {1 \over n}, ... \}$ S는 가산집합이지만 0은 고립점이 아닙니다. 수열의 극한이니까 0은 도집합에 쏙 들어가네요. 나머지 점은 고립점일지라도...&lt;br /&gt;&lt;br /&gt;The number of isolated points is a topological invariant, i.e. if two topological spaces X and Y are homeomorphic, the number of isolated points in each is equal.&lt;br /&gt;(고립점 갯수는 동형인 위상에서 같다는 군요)&lt;br /&gt;&lt;br /&gt;여기까지 위키의 내용입니다.&lt;br /&gt;&lt;br /&gt;고립점의 정의는 $x$를 포함하는 어떤 개집합 $X$에 대하여, $x$만 포함하면 되니까&lt;br /&gt;$$\exists U \in \mathcal{T}:U \cap A = \{x\}$$또는$$(U-\{x\}) \cap A = \emptyset$$&lt;br /&gt;이렇게 되겠네요.... 와!!! 아까 도집합과 반대되는 녀석인거 같아요....&lt;br /&gt;&lt;br /&gt;(수정) 고립점에서는 '어떤'이 맞습니다~ 도집합에서는 '임의의(모든)'가 맞습니다&lt;br /&gt;(추가) 고립점의 정의는 다음과 같습니다.&lt;br /&gt;$A$의 점 $x$가 고립점이라고 하면, $x$를 포함하는 적당한(어떤) 근방 $U$에 대하여 $U \cap A=\{x\}$를 만족할때 $x$를 고립점이라고 합니다&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;예를 들어 $\{x\}$ 가 개집합인 이산집합에서는 모든 점이 고립점입니다&lt;br /&gt;&lt;br /&gt;위의 내용은 집적점과 비교한 내용이므로 $\{x\}$를 좌변으로 이항하면 위와 같은 식이 나올겁니다.&lt;br /&gt;그런데 도집합과 가장 큰 차이는.... 도집합은 전체집합의 모든 점이 후보지만,&lt;br /&gt;고립점은 $A$ 안에 포함되는 녀석만 후보라는 점이 차이가 있습니다.&lt;br /&gt;그럼 아까 도집합에서 문제가 생겼던 것을 체크해보죠.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;내점인데 도집합에 속하지 않는다.&lt;br /&gt;내점이기 때문에 반드시 $x \in U \subseteq A$인 개집합이 존재합니다. 하지만 도집합에 속하지 않으므로 $(U-\{x\})\cap A = \emptyset$이죠. 그러니까 결론은 $U=\{x\}..... x$를 덮는 가장 작은 개집합은 한점 집합이라고 생각할 수 있겠죠. 그리고 이경우 고립점의 정의에서 벗어나지 않습니다.&lt;br /&gt;내점인데 도집합에 속하지 않으면 고립점입니다.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;내점이 아닌데 도집합에 속하지 않는다.&lt;br /&gt;아까 체크했던 $\{1\} \cup (2,3)$ 이라는 $A$ 집합에서 $1$이 문제였죠.&lt;br /&gt;$1$은 $A$의 점이지만 $1$을 덮은 작은 개집합 가져오면 $(U-\{x\}) \cap A = \emptyset$라고 말할 수 있겠네요.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;자 그럼 이제 그림을 완성해봅시다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 320px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A1A73E5B591FA011&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A1A73E5B591FA011&quot; width=&quot;320&quot; height=&quot;213&quot; filename=&quot;topology7.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 320px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997792385B591FA016&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997792385B591FA016&quot; width=&quot;320&quot; height=&quot;213&quot; filename=&quot;topology8.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;와 그럼 다음과 같은 이야기를 할 수 있겠네요.&lt;br /&gt;$$Cl(A)=A' \cup \operatorname{Iso}(A)$$&lt;br /&gt;고립점의 영문 앞을 따와 고립점들의 집합을 $\operatorname{Iso}(A)$라고 썼습니다.($A^i$라고도 씀.)&lt;br /&gt;&lt;br /&gt;이 내용이 유용한 것은 도집합과 고립점은 서로소라는 사실입니다.&lt;br /&gt;A와 A의 도집합은 서로소가 아니라서 도집합의 모양을 추측해보기 힘들수도 있지만....&lt;br /&gt;고립점을 통해 페포의 모양을 다르게 구할 수 있다는 겁니다... 그런 점에서 은근 유용할 수도 있죠...&lt;br /&gt;&lt;br /&gt;하아.... 긴 여정이었습니다.&lt;br /&gt;&lt;br /&gt;$$Cl(A)=A' \cup Iso(A)$$&lt;br /&gt;단지 이 한문장을 소개하고 싶었는데 너무 멀리 돌아온 느낌이네요....&lt;br /&gt;&lt;br /&gt;그럼 이 내용을 가지고 실제 적용을 해보겠습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;1) 이산위상에서의 도집합의 모양&lt;br /&gt;자 이제 슬슬 눈치 챘습니까? 이산 위상이라는 녀석은 한점집합을 개집합으로 정의하죠.&lt;br /&gt;아까 이야기 했던 것처럼 한점 집합이 개집합이면 그 녀석은 고립점이 됩니다.&lt;br /&gt;따라서 어떤 집합이 주어져도 도집합은 언제나 공집합입니다.&lt;br /&gt;&lt;br /&gt;2) 비이산 위상에서의 도집합의 모양.&lt;br /&gt;비이산위상이라는 녀석은 위상의 원소가 {공집합, 전체집합} 뿐인 녀석입니다.&lt;br /&gt;자 그럼 이제 $A$의 모양에 대해서 생각해보죠.&lt;br /&gt;&lt;br /&gt;(1)$A$가 공집합 이면&lt;br /&gt;=&amp;gt; 당연히 도집합도 공집합이죠. 교집합이 공집합이니까요&lt;br /&gt;&lt;br /&gt;(2)$A$가 $1$점 집합이면&lt;br /&gt;=&amp;gt; 이경우 $A$의 점은 고립점입니다. 한점이자나요 ㅋ&lt;br /&gt;$A$의 폐포는 $A$를 덮은 가장 작은 폐집합.... $X$죠 ㅋㅋㅋ $\operatorname{Cl}(A)=X$가 됩니다.&lt;br /&gt;그러니까 $A' = \operatorname{Cl}(A) - \operatorname{Iso}(A) = X-A$ 라는 이야기도 할 수 있죠&lt;br /&gt;&lt;br /&gt;(3)$A$가 2점 이상의 집합이면,&lt;br /&gt;=&amp;gt; 이경우 $A$의 점들은 고립점이 될 수 없습니다. 그리고 역시나 $\operatorname{Cl}(A)=X$ 입니다.&lt;br /&gt;그러니까 고립점이 없자나! 라고 하면서 $A'=X$ 라고 이야기 할 수 있습니다.&lt;br /&gt;&lt;br /&gt;(위의 문제는 왠만한 기본서에 집적점의 정의로 풀어놓은 것들이 있을겁니다~)&lt;br /&gt;&lt;br /&gt;자 이제 고립점이 없는 집합 A에 대해서 생각해보죠.&lt;br /&gt;그런 경우에는? $A' = \operatorname{Cl}(A)$ 라는 것이 성립합니다!!&lt;br /&gt;즉 어떤 집합의 도집합과 폐포가 같을 때, 이러한 집합들을 멱집합(Power Set) 이라고 부릅니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;퓨퓨 드디어 극한을 배우기 위한 준비가 끝났습니다.&lt;/p&gt;&lt;p&gt;극한을 배워봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;2. 극한(Limit).&lt;br /&gt;&lt;/h2&gt;&lt;h3&gt;2.1 극한 정의.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;코시(Cauchy)란 수학자에 따르면 극한은&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;When
 the values successively attributed to a particular variable approach 
indefinitely a fixed value so as to end by differing from it by as 
little as one wishes, this latter value is called the limit of all the 
others.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;번역을 해보자면,&lt;br /&gt;&lt;/p&gt;&lt;p&gt;어떤 변수가 가질 수 있는 일련의 값들이 하나의 고정된 값으로 한없이 가까이 가서 우리가 원하는 만큼 그 차이를 줄일 수 있을 때, 그 고정값을 변수에 대한 극한이라고 한다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 649px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991CC33C5BB519841D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991CC33C5BB519841D&quot; width=&quot;649&quot; height=&quot;671&quot; filename=&quot;limit.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;극한[from &lt;a href=&quot;https://brilliant.org/wiki/epsilon-delta-definition-of-a-limit/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Epsilon-Delta Definition of a Limit&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$$
 \lim_{E\ni x \rightarrow c} f(x)=L 
\overset{\underset{\mathrm{def}}{}}{\Longleftrightarrow} 
\forall\epsilon&amp;gt;0 \;\; \exists\delta&amp;gt;0 \;\; s.t.\forall x\in E: 
(0&amp;lt;|x-c|&amp;lt;\delta \Rightarrow |f(x)-L| &amp;lt; \epsilon)$$&lt;/p&gt;&lt;p&gt;해설은 하겠지만 모르는 기호가 있다면 &lt;a href=&quot;https://librewiki.net/wiki/%EC%88%98%ED%95%99_%EA%B8%B0%ED%98%B8&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;다음(리브레 위키&lt;/a&gt;&lt;a href=&quot;https://librewiki.net/wiki/%EC%88%98%ED%95%99_%EA%B8%B0%ED%98%B8&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;)&lt;/a&gt;을 참고.&lt;/p&gt;&lt;p&gt;저 기호들에 대한 설명은 이산수학을 다루면서 따로 포스팅 할 예정.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;간단 설명.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;임의의 $\epsilon &amp;gt; 0$에 대하여, 어떤 $\delta &amp;gt; 0$이 존재하여, 임의의 $x \in E$에 대하여 $0&amp;lt;|x-c|&amp;lt;\delta$는 $|f(x)-L| &amp;lt; \epsilon)$를 함의한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;즉, 임의의 오차 범위($\epsilon$)를 시험하였을 때, 독립 변수가 일정 값과 어떤 작은 거리($\delta$) 이내인 일이면, 함숫값과 극한값이 그 오차 범위 이내인 것을 보장한다는 뜻이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아직 어렵나;; 좀 더 축약해 설명하면&lt;br /&gt;&lt;/p&gt;&lt;p&gt;오차 범위($\epsilon$)보다 작게 만들 수 있는 어떤 작은 거리($\delta$)가 존재해야 극한이다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;정의에 대한 자세한 설명은 위키피디아에서 잘 나와있다.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.2 정의에 대한 설명.&lt;br /&gt;&lt;/h3&gt;&lt;h4&gt;2.2.1 $ \lim_{E\ni x \rightarrow c} f(x)=L$. &lt;/h4&gt;&lt;p&gt;$\lim_{E\ni x \rightarrow c} f(x)=L$은 $x$를 $c$에 충분히 가깝게 하면(극한) 함수 $f(x)$가 $L$에 가까워지도록 만들 수 있다는 것을 의미한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;실수 $\mathbb{R}$의 부분집합인 $E$일 때, [$E \subseteq \mathbb{R}$]&lt;/p&gt;&lt;p&gt;함수 $f$는 실수값 함수로서 집합 $E$에서 집합 $\mathbb{R}$로 사상(일어날 수 있는 결과)이다. [$f:E \to \mathbb{R}$]&lt;/p&gt;&lt;p&gt;* '$:$'는 such that(이러한, 다음과 같은)이나 so that(~하기 위해서)의 뜻.&lt;/p&gt;&lt;p&gt;* '$\to$'는 ~에서 ~로 의 뜻.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$f$는 $E$의 극한 점(집합의 점들이 모여드는 점)인 $c$($c \in E'$)에서 가지는 극한이다. [$\lim_{E\ni x \rightarrow c} f(x)$]&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위에서 다루었던 집적점이 바로 극한점이고!!(요거 배우려고 먼길을 걸어옴..)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 385px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E3B2435B4B9D1923&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E3B2435B4B9D1923&quot; width=&quot;385&quot; height=&quot;116&quot; filename=&quot;accumulation-point.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;극한점은 이런 느낌.[from &lt;a href=&quot;http://legein.egloos.com/339844&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;legein의 이글루&lt;/a&gt;]&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;마지막으로 극한값은 $L$. [$\lim_{E\ni x \rightarrow c} f(x)=L$]&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$\overset{\underset{\mathrm{def}}{}}{\Longleftrightarrow}$는 이 후는 정의를 나타낸다는 뜻.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 극한의 정의에 대해 본격적으로 알아봅시다.&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.2.2 $\forall\epsilon&amp;gt;0 \;\; \exists\delta&amp;gt;0$.&lt;/h4&gt;&lt;p&gt;$\forall\epsilon&amp;gt;0$은 임의의(모든, $\forall$) 양의 실수 $\epsilon$이 그 뒤에 오는 조건을 예외 없이 만족시킨다는 뜻이다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$\exists\delta&amp;gt;0$은 적어도 하나의(어떤) 양의 실수 $\delta$가 그 뒤에 오는 조건을 만족시킨다는 뜻이다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.2.3 $s.t.\forall x\in E$.&lt;/h4&gt;&lt;p&gt;$s.t.$도 such that과 같은 뜻으로 조건의 추가를 의미한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$\forall x\in E$는 임의의 $x$가 $E$의 원소라는 뜻.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.2.4 $0&amp;lt;|x-c|&amp;lt;\delta \Rightarrow |f(x)-L| &amp;lt; \epsilon$.&lt;/h4&gt;&lt;p&gt;$0&amp;lt;|x-c|&amp;lt;\delta$는 독립 변수의 값 $x$가 일정 값 $a$와 거리 $\delta$ 이내이되, $a$와 같지 않다는 뜻이다.&lt;br /&gt;$|f(x)-L| &amp;lt; \epsilon$는 함숫값 $f(x)$에 극한값 $L$을 뺀 값의 절댓값, 즉 오차가 $\epsilon$이내라는 뜻이다.&lt;br /&gt;$A \Rightarrow B$는 A는 B를 함의한다 또는 앞의 조건의 만족이 뒤의 조건의 만족을 보장한다는 뜻이다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.2.5 정리.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;위키백과 스냅샷에 정리가 잘 되어 있어 가지고 와 정리했다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;$\lim_{E\ni x \rightarrow c} f(x)=L$은 $x$를 $c$에 충분히 가깝게 하면 함수 $f(x)$가 $L$에 가까워지도록 만들 수 있다는 것을 의미한다. 이 때 $x$가 $c$와 같아지지 않아도 되며, 심지어 $f(c)$가 정의되지 않아도 상관없다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&quot;$x$를 $c$에 충분히 가깝게&quot; 에서 $x$가 $c$에 가까운 정도는, $f(x)$ 를 $L$에 가까워지게 할 정도에 따라 다르며 함수 $f$와 실수 $c$에 따라 결정된다.&lt;/p&gt;&lt;p&gt;양수 $\epsilon$은 $f(x)$가 $L$에 가까운 정도를 나타낸다. $f(x)$와 $L$의 거리가 $\epsilon$ 이상이 되지 않는다는 의미.&lt;/p&gt;&lt;p&gt;양수 $\delta$는 $x$가 $c$에 가까운 정도를 나타낸다. 즉 $x$와 $c$사이의 거리가 $0$이 아닌 수 $\delta$보다 작을 경우, $f(x)$와 $L$사이의 거리도 $\epsilon$보다 작아진단 뜻이다.&lt;/p&gt;&lt;p&gt;따라서 $\delta$는 $\epsilon$에 따라 결정된다. 이러한 극한의 표현법은 $\epsilon$이 아무리 작더라도, 그에 따라 $\delta$이 충분히 작아질 수 있다는 것을 의미한다.&lt;/p&gt;&lt;p&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;문자 $\epsilon$와 $\delta$는 각각 &quot;오차&quot; 와 &quot;거리&quot; 로 이해할 수 있다. 실제로 코시는 그의 연구에서 $\epsilon$를 &quot;오차(error)&quot; 의 약자로 사용했다. 이러한 관점에서 말하면, 오차 $\epsilon$는 거리 $\delta$를 감소시키고 싶은 만큼 작게 만들 수 있다. 이러한 정의는 하나 이상의 다변수 함수에서도 성립한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;- 한줄 정리.&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;$0&amp;lt;|x-c|&amp;lt;\delta$를 만족하는 범위의 모든 $x$에 대해 $|f(x)-L|&amp;lt;\epsilon$가 성립한다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.3 응용.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;암튼 공돌이는 응용을 중시하는 법!!&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이 광활한 정의를 어떻게 써먹는지 서술해보고자 한다. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;1차 방정식 형식과 2차 방정식 형태의 예를 보자.&lt;/p&gt;&lt;p&gt;우선 아래 나오는 식들은 모두 $\forall \epsilon &amp;gt; 0 \; \exists \delta &amp;gt; 0$를 가정한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이해하기 쉽게 표현된 짤을 보면 감이 잘올까 싶다.&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.3.1 1차 방정식.&lt;br /&gt;&lt;/h4&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 474px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990D4A3C5BB516011A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990D4A3C5BB516011A&quot; width=&quot;474&quot; height=&quot;462&quot; filename=&quot;limit_epsilon_delta_y=2x.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;$\lim_{x \rightarrow 1} 2x =2$ 그래프[from &lt;a href=&quot;https://blog.naver.com/daesangmath/221137924295&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;극한 정의 (입실론-델타)&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;우선 $$\lim_{x \rightarrow 3} 2x+1 = 7$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;을 살펴보자.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$
 \lim_{E\ni x \rightarrow c} f(x)=L$와 비교할 시&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$f(x)=2x+1$, $L=7$, $c=3$이란 것을 알 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 정의 부분인 $\forall\epsilon&amp;gt;0 \;\; \exists\delta&amp;gt;0 \;\; s.t.\forall x\in E: 
(0&amp;lt;|x-c|&amp;lt;\delta \Rightarrow |f(x)-L| &amp;lt; \epsilon)$와 비교해보자.&lt;/p&gt;&lt;p&gt;$0&amp;lt; |x-3| &amp;lt; \delta$일 때, $|(2x +1) - 7| &amp;lt; \epsilon$이 성립해야 한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 적절한 $\delta$값을 찾아봅시다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$$\begin{matrix}|(2x + 1) -7| &amp;amp;=&amp;amp; |2x-6| \\ &amp;amp;=&amp;amp;&amp;nbsp; 2|x-3| \end{matrix} \\ 2|x-3| &amp;lt; \epsilon \Rightarrow |x-3| &amp;lt; {\epsilon \over 2}\\ \therefore \delta = {\epsilon \over 2}$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그럼 찾은 $\delta$값이 적절한가 알아보죠.&lt;/p&gt;&lt;p&gt;$\delta = {\epsilon \over 2}$일때, |$x-3|&amp;lt;{\epsilon \over 2}$ 인가.&lt;/p&gt;&lt;p&gt;$$\begin{matrix}2|x-3| &amp;lt; \epsilon &amp;amp; \Rightarrow &amp;amp; |2x-6| &amp;lt; \epsilon \\ |(2x +1) -7| &amp;lt; \epsilon &amp;amp; \Rightarrow &amp;amp; |f(x)-L| &amp;lt; \epsilon \end{matrix}\\ \therefore 참 \ _\square$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;조금만 생각해보면&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$$ \forall a \in \mathbb{R}, \lim_{x \rightarrow a} bx = L$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일때 $\delta = {\epsilon \over a}$라는 것도 알 수 있다. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.3.2 2차 방정식.&lt;/h4&gt;&lt;div&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 545px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99ABAF3D5BB5160219&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99ABAF3D5BB5160219&quot; width=&quot;545&quot; height=&quot;486&quot; filename=&quot;limit_epsilon_delta_y=xsq.gif&quot; filemime=&quot;image/gif&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;$\lim_{x \rightarrow 1}x^2 = 1$ 그래프[from &lt;a href=&quot;https://blog.naver.com/daesangmath/221137924295&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;극한 정의 (입실론-델타)&lt;/a&gt;]&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;이번엔 2차 방정식을 대상으로 알아보자.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;$$\lim_{x \rightarrow 3} 4x^2 + 1= 37$$&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;1차때와 똑같이 $f(X)=4x^2 + 1$, $L = 37$, $c = 3$일 때, $0 &amp;lt; |x - 3| &amp;lt; \delta$, $|4x^2 - 36| &amp;lt; \epsilon$의 형태를 띈다는 것까진 쉽게 전개할 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;계속해봅시다.&lt;/p&gt;&lt;p&gt;$$\begin{matrix} |4x^2 - 36| &amp;amp;=&amp;amp; 4|x^2 - 9| \\ &amp;amp;=&amp;amp; 4|(x+3)(x-3)| \\ &amp;amp;=&amp;amp; 4|x+3||x-3|\end{matrix}\\ 4|x+3||x-3|&amp;lt; \epsilon \Rightarrow |x-3| &amp;lt;&amp;nbsp; {\epsilon \over 4|x+3|} \\ \therefore \delta = {\epsilon \over 4|x+3|}$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;라고 풀게 된다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그런데 무언가 이상하지 않나요?&lt;/p&gt;&lt;p&gt;$x$의 값이 바뀌면 일정해야 할 $\delta$ 값이 바뀌어 버린다니..&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;무언가 이상하게 여길지 모르지만 $\delta$값이 존재하여 $\epsilon$과의 관계가 증명하는 것이 중요합니다.&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;오차 범위($\epsilon$)보다 작게 만들 수 있는 어떤 작은 거리($\delta$)가 존재해야 극한이다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;라고 언급했듯, $0&amp;lt;\epsilon$을 가지고 명제에 맞는 $\delta$를 '찾아 낼 수' 있다면 극한이고 아니라면 극한이 존재치 않는다는 것이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;'찾아 내는 것'이 문제이므로 특정한 $\delta$값을 정하는 것은 문제가 되지 않습니다.&lt;/p&gt;&lt;p&gt;저는 '적절한' $\delta$ 값을 $1$보다 작다고 잡아보겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그럼 전에 했던 것이 완전히 뻘짓이었냐, 이건 또 아닙니다.&lt;/p&gt;&lt;p&gt;적당한 비율을 찾아낼 수 있기 때문이죠.&lt;/p&gt;&lt;p&gt;$a|x-3|&amp;lt;\epsilon$ 그리고 $4|x+3|&amp;lt;a$에 맞는 변수 $a$가 존재하면,&lt;/p&gt;&lt;p&gt;$$4|x+3||x−3| &amp;lt; a|x-3| \land |x-3|&amp;lt;{\epsilon \over a} \\ 4|x+3||x−3| &amp;lt; a|x-3|&amp;lt;\epsilon \\|x-3|&amp;lt;{\epsilon \over a}&amp;nbsp; \rightarrow 4|x+3||x−3| &amp;lt; \epsilon\\ \therefore \delta = {\epsilon \over a} $$&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아까 범위로 잡은 $\delta&amp;lt;1$을 이용해 $|x-3|&amp;lt;1$로 $4|x+3|&amp;lt;a$을 만들 때, &lt;br /&gt;&lt;/p&gt;&lt;p&gt;$$|x-3|&amp;lt;1 \\ 0&amp;lt;x-3&amp;lt;1 \\ 3&amp;lt;x&amp;lt;4 \\ 12&amp;lt;4x&amp;lt;16 \\ -28&amp;lt;24&amp;lt;4x+12&amp;lt;28 \\ -28&amp;lt;4(x+3)&amp;lt;28 \Rightarrow 4|x+3|&amp;lt;28 \\ \therefore a=28 \; \therefore \delta=\min({\epsilon \over 28}, 1)$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;범위가 올바른지 확인 해볼까요?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$\delta={\epsilon \over 28}$로 잡고&lt;/p&gt;&lt;p&gt;$$4|x+3|&amp;lt;28 \land |x-3|&amp;lt;{\epsilon \over 28} \\ 4|x+3||x-3|&amp;lt;28|x-3| \land 28|x-3|&amp;lt;\epsilon \\ 4|x+3||x-3|&amp;lt;28|x-3|&amp;lt;\epsilon \\ 4|x+3||x-3|&amp;lt;\epsilon \rightarrow |(4x^2 + 1)-37|&amp;lt;\epsilon \ _\square$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;휴. 증명까지 완료했습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.3.3 우극한과 좌극한.&lt;/h4&gt;&lt;p&gt;우리가 흔히 생각하는 우극한($lim_{x \rightarrow c^+} f(x) = L$), 좌극한(($lim_{x \rightarrow c^-} f(x) = L$))은 다음과 같이 나타낼 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;우극한의 정의. $$0&amp;lt;x-c&amp;lt;\delta \Rightarrow |f(x)-L| &amp;lt; \epsilon$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;좌극한의 정의. $$-\delta&amp;lt;x-c&amp;lt;0 \Rightarrow |f(x)-L| &amp;lt; \epsilon$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;-끝-&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;출처: 위키피디아[&lt;a href=&quot;https://ko.wikipedia.org/w/index.php?title=%EC%9C%84%EC%83%81_%EA%B3%B5%EA%B0%84_(%EC%88%98%ED%95%99)&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;위상 공간(수학)&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%EC%A0%81%EC%A0%90&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;집적점&lt;/a&gt;,&amp;nbsp; &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%88%98%EC%97%B4%EC%9D%98_%EA%B7%B9%ED%95%9C&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;수열의 극한&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98%EC%9D%98_%EA%B7%B9%ED%95%9C&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;함수의 극한&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%97%A1%EC%8B%A4%EB%A1%A0-%EB%8D%B8%ED%83%80_%EB%85%BC%EB%B2%95&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;엡실론-델타 논법&lt;/a&gt;, &lt;a href=&quot;https://ko.wikipedia.org/w/index.php?title=%EC%97%A1%EC%8B%A4%EB%A1%A0-%EB%8D%B8%ED%83%80_%EB%85%BC%EB%B2%95&amp;amp;oldid=17459346&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;과거 엡실론-델타 논법&lt;/a&gt; ],  &lt;a href=&quot;http://legein.egloos.com/339844&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;수열의 극한&lt;/a&gt;, &lt;a href=&quot;https://blog.naver.com/PostView.nhn?blogId=min311r&amp;amp;logNo=110131488760&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;개집합, 폐집합, 도집합과 고립점... 그리고 전혀 상관없는 칸토어 집합&lt;/a&gt;, &lt;a href=&quot;http://jjycjnmath.tistory.com/150&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;위상수학이란 무엇일까?&lt;/a&gt; , ProofWiki[&lt;a href=&quot;https://proofwiki.org/wiki/Definition:Closure_(Topology)&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Definition:Closure (Topology)&lt;/a&gt; , &lt;a href=&quot;https://proofwiki.org/wiki/Definition:Interior_(Topology)&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Definition:Interior (Topology)&lt;/a&gt;, &lt;a href=&quot;https://proofwiki.org/wiki/Definition:Boundary_(Topology)&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Definition:Boundary (Topology)&lt;/a&gt;, &lt;a href=&quot;https://proofwiki.org/wiki/Definition:Exterior_(Topology)&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Definition:Exterior (Topology)&lt;/a&gt;, &lt;a href=&quot;https://proofwiki.org/wiki/Definition:Accumulation_Point_of_Set&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Definition:Accumulation Point of Set&lt;/a&gt;, &lt;a href=&quot;https://proofwiki.org/wiki/Definition:Isolated_Point_(Topology)&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Definition:Isolated Point (Topology)&lt;/a&gt; ] &lt;br /&gt;&lt;/p&gt;</description>
      <category>수학</category>
      <category>극한</category>
      <category>수학</category>
      <category>위상</category>
      <category>집합</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/44</guid>
      <comments>https://black7375.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 30 Jul 2018 08:27:24 +0900</pubDate>
    </item>
    <item>
      <title>무한, 집합, 그리고 수에 대해서.</title>
      <link>https://black7375.tistory.com/43</link>
      <description>&lt;script type=&quot;text/x-mathjax-config&quot;&gt;
MathJax.Hub.Config({
    &quot;HTML-CSS&quot;: {
        messageStyle: &quot;normal&quot;,
        linebreaks: {
            automatic: false
        }
    },
    tex2jax: { 
        inlineMath: [[&quot;$&quot;,&quot;$&quot;],[&quot;\\(&quot;,&quot;\\)&quot;]], 
        displayMath: [[&quot;$$&quot;,&quot;$$&quot;],[&quot;\\[&quot;,&quot;\\]&quot;]], 
        processEscapes: true
    },
    TeX: {
        Macros: {
            tr: &quot;{\\scriptscriptstyle\\mathrm{T}}&quot;,
        },
				extensions: [&quot;color.js&quot;]
    }
});
&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML&quot; type=&quot;text/javascript&quot; async=&quot;&quot;&gt;
&lt;/script&gt;	
&lt;p&gt;무한($\infty$)의 성질들을 집합과 수를 통해 간단하게라도 알아보도록 하자.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img class=&quot;txc-image&quot; id=&quot;tx_entry_73001_&quot; style=&quot;&quot; src=&quot;https://t1.daumcdn.net/cfile/tistory/99287C3C5B433E9122&quot; width=&quot;820&quot; height=&quot;394&quot;&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;M.C. Escher - Möbius Strip II(1963)[from &lt;a class=&quot;tx-link&quot; href=&quot;https://wallup.net/artwork-m-c-escher-insect-ants-grid-3d-white-background-mobius-strip/&quot; target=&quot;_blank&quot;&gt;Wallup&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1. 집합(Set)과 무한(Infinity).&lt;/h2&gt;&lt;p&gt;무한의 성질을 알려면 집합에 대하여 아는 것이 좋다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;국립국어원에 따르면 집합은&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;특정 조건에 맞는 원소들의 모임. 임의의 한 원소가 그 모임에 속하는지를 알 수 있고, 그 모임에 속하는 임의의 두 원소가 다른가 같은가를 구별할 수 있는 명확한 표준이 있는 것을 이른다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;역시 무한은&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;수(數), 양(量), 공간, 시간 따위에 제한이나 한계가 없음.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.1 집합 기본.&lt;/h3&gt;&lt;p&gt;우선 집합의 기본 사항들을 간단히 짚고 넘어가도록 한다.&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;1.1.1 집합과 포함관계.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;&lt;b&gt;- 집합의 표현.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;3보다 크고 10보다 작은 짝수 집합 $A$는 $$A=\{4,6,8\}$$라고 나타낼 수 있습니다.&lt;br /&gt;집합 $A$를 이루는 $4, 6, 8$는 '원소'라고 부릅니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;원소의 개수는 $$n(A)=3$$처럼 나타내며,&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;원소와 원소가 아닌 것은 다음과 &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$4 \in A, 5 \notin A$$&lt;br /&gt;같이 표현 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;원소가 없다면 '공집합'이라 하며, $$\emptyset$$로 표현합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우리가 방금 집합 $A$처럼 원소들을 나열하여 표현한 것을 '원소 나열법'이라 합니다.&lt;/p&gt;
&lt;p&gt;원소 나열법은 직관적이지만, 원소가 많은 집합이나, 집합의 특성을 표현하기에는 힘들다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예를 들어 3보다 큰 짝수 집합 $B$를 원소 나열법으로 표현 할 수 있을까?&lt;/p&gt;
&lt;p&gt;$$B=\{4,6,8,10,...\}$$라고 밖에 표현 할 수 없다.&lt;/p&gt;
&lt;p&gt;집합을 정확히 표현하는데 문제가 생긴다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그래서 나온 표기 방식은 '조건 표기법'이라 한다.&lt;/p&gt;
&lt;p&gt;$$A=\{x|3&amp;lt;(x=2n)&amp;lt;9, n은 \; 정수\} \\ B=\{x|3&amp;lt;x=2n, n은 \; 정수\}$$&lt;/p&gt;
&lt;p&gt;로 표시 할 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;집합과 원소를 나타낼 때 관습.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;집합은 보통 $A,B,C$처럼 대문자로 표시하며, 원소는 $a,b,c$처럼 소문자로 표현한다.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 부분 집합.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 155px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99EA123B5B5385501E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99EA123B5B5385501E&quot; width=&quot;155&quot; height=&quot;155&quot; filename=&quot;155px-Venn_A_subset_B.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;부분집합[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;어떤 집합의 모든 원소가 다른 집합의 원소에 속할 때 '부분 집합'이라 한다.&lt;/p&gt;
&lt;p&gt;집합 $A$는 집합 $B$에 포함되기 때문에 부분 집합이다.&lt;/p&gt;
&lt;p&gt;$$A \subset B$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;실제로 포함하다의 Contain에서 C를 기호화 한 것 이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;만약 집합 $C$를 5이상의 자연수라 하면&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$4 \notin C$$이므로, $$A \subset C$$가 아니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;잠깐 부분 집합의 성질을 알아보자.&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;&lt;p&gt;공집합($\emptyset$)은 임의의 집합(모든 집합)의 부분 집합이다. ($\emptyset \subset All$)&lt;br /&gt;공집합에 속한 원소가 없기 때문.&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;임의의 집합은 자기 자신의 부분 집합이다. ($All \subset All$)&lt;br /&gt;역시 자신이 가지고 있는 원소는 자신과 같기 때문.&lt;br /&gt;* 임의의 집합이라는 뜻에서 $All$이라 표시했다.&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;자기 자신을 제외한 부분 집합을 '진부분 집합'이라 한다.&lt;/p&gt;
&lt;p&gt;$$\subsetneq$$로 표시한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예) A에서는&amp;nbsp; $\emptyset, \{4\}, \{6\}, \{8\}, \{4,6\}, \{4,8\}, \{6, 8\}$이 진부분 집합이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;만약 집합 $A$와 $B$가&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$ A \subset B, B\subset A 이면, \; A = B$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이면 '상등'하다고 하다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;바로 위에서 설명한 진부분 집합이 부분 집합이되 상등하지 않은 집합을 의미한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;임의의 집합 $I$, $J$, $K$가&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$I \subset J, J \subset K 이면 \; I \subset K$$이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;1.1.2 집합의 연산.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;&lt;b&gt;- 합집합과 교집합.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 220px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9942F9435B5385D820&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9942F9435B5385D820&quot; width=&quot;220&quot; height=&quot;160&quot; filename=&quot;220px-Venn0111.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;합집합[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;어떤 집합과 다른 집합의 모든 원소를 이용하여 만든 집합을 '합집합'이라 한다.&lt;/p&gt;
&lt;p&gt;$$A \cup C = \{x|(x \in A) \lor (x \in C)\}$$는 A와 C의 모든 원소를 이용하여 만든 집합으로, 4이상의 자연수가 합집합의 결과이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\bigcup_{i\in I}A_i=\{x|\exists i\in I\colon x\in A_i\}$$로도 표현한다.&lt;/p&gt;
&lt;p&gt;단, $A_i (i \in I)$에서 $I$는 집합이며 $i \in I$s는 $A_i$를 식별하기 위해 쓰인다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 384px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993D533D5B5385FD21&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993D533D5B5385FD21&quot; width=&quot;384&quot; height=&quot;280&quot; filename=&quot;384px-Venn0001.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;교집합[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;어떤 집합과 다른 집합의 같은 원소를 이용하여 만든 집합을 '교집합'이라 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$A \cap C =\{x|(x \in A) \land (x \in C)\}$$은 {6, 8}이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* $\lor$은 $or$(또는), $\land$는 $and$(그리고)라는 뜻.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;역시 또 다른 표현으론&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\bigcap_{i\in I}A_i=\{x|\forall i\in I\colon x\in A_i\}$$가 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;공통된 원소가 하나도 없을 때, 즉 교집합의 결과가 공집합일 때, '서로소'라고 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 여집합과 차집합, 대칭자.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;주어진 집합에서 부분 집합을 생각 할 때 '전체 집합'&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_43_1&quot; id=&quot;footnote_link_43_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 43, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(43, 1)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;은 보통 Universal의 U를 따&lt;/p&gt;
&lt;p&gt;$U$라고 표현한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 384px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99588C375B53867921&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99588C375B53867921&quot; width=&quot;384&quot; height=&quot;280&quot; filename=&quot;384px-Komplement_einer_Menge.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;여집합[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;전체 집합 $U$에서 부분 집합 $A$에 속하지 않는 모든 원소로 이루어진 집합을 $U$에 대한 $A$의 '여집합'이라 한다.&lt;/p&gt;
&lt;p&gt;$$A^c=\{x|(x \in A) \land (x \notin A)\}$$&lt;/p&gt;
&lt;p&gt;전체 집합을 위에서 정의했던 집합 B로 가정하고, A의 여집합 일 경우 4, 6, 8을 제외한 나머지 집합이다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 384px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9990AD4C5B5386221F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9990AD4C5B5386221F&quot; width=&quot;384&quot; height=&quot;280&quot; filename=&quot;384px-Venn0010.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;차집합[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;어떤 집합에서 다른 집합의 원소에 속하지 않는 원소들로 이루어진 집합이 차집합이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$A-B=A \cap B^c =\{x|(x \in A) \land (x \notin B)\}$$&lt;/p&gt;
&lt;p&gt;$A \setminus B$라고도 표시한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 384px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991108415B547F9F29&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991108415B547F9F29&quot; width=&quot;384&quot; height=&quot;280&quot; filename=&quot;384px-Venn0110.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;대칭자[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;어떤 집합과 다른 집합에서 둘 다 속하지만, 동시에 둘 다에는 속하지는 않는 원소(하나에만 속함)들로 이루어진 집합을 대칭차라 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$ \begin{matrix}A \triangle B&amp;amp;=&amp;amp;\{x|(x \in A \land x \notin B) \lor (x\notin A \land x \in B)\} \\&lt;br /&gt;&amp;amp;=&amp;amp;(A \cup B) - (A \cap B) \\ &amp;amp;=&amp;amp; (A - B) \cup (B - A) \end{matrix}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 멱집함(Power Set)과 곱집합.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Power Set이라고 특별히 영문 혼용 표기를 한 까닭은 한글로 쓰여진 글에서도 멱집합 대신 Power Set이라는 말이 많이 나와서.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 429px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991ECF465B54AA7901&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991ECF465B54AA7901&quot; width=&quot;429&quot; height=&quot;325&quot; filename=&quot;powerset_of_3.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;멱집합[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EB%A9%B1%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;멱집합은 모든 부분집합을 모은 집합이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;임의의 집합 S의 멱집합은&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\mathcal{P}(S)=\{A\colon A\subseteq S\}$$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그리고 $\mathcal{P}(S)$대신 $P(S)$, $2^S$처럼도 표기하기도 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예를 들어 집합 $B=\{1,2,3\}$의 멱집합 $\mathcal{P}(A)$은&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\mathcal{P}(B)=\{\emptyset, \{1\}, \{2\}, \{3\}, \{1,2\}, \{1,3\}, \{2,3\}, \{1,2,3\} \}$$&lt;/p&gt;
이다.&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 501px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D5C1455B54ACE40F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D5C1455B54ACE40F&quot; width=&quot;501&quot; height=&quot;381&quot; filename=&quot;Cartesian_Product_qtl1.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;곱집합[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EA%B3%B1%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;각 집합의 원소를 각 성분으로 하는 튜플들의 집합이다.&lt;/p&gt;
&lt;p&gt;$A \times B$처럼 표시한다.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;$$\prod_{i\in I}A_i=\{(x_i)_{i\in I}|\forall i\in I\colon x_i\in A_i\}$$로도 표시한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* 튜플(tuple)은 유한 개의 사물의 순서있는 열거이다. 주로 $()$를 사용하여 표시.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 드모르간 법칙.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;전체집합 U와 부분 집합 I, J가 있다면, $$(I \cap J)^c = I^c \cup J^c \\ (I \cup J)^c = I^c \cap J^c$$이 성립합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$X - \bigcup_{i\in I}A_i=\bigcap_{i\in I}{}(X - A_i)\\ X - \bigcap_{i\in I}A_i=\bigcup_{i\in I}{}(X - A_i)$$로도 표현.&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;1.1.3 집합의 대응.&lt;/h4&gt;&lt;p&gt;어떤 집합과 다른 집합이 주어졌을 때, 어떤 집합의 원소에 대해 다른 집합의 원소가 정해지면 어떤 집합에서 다른 집합으로 '대응'한다고 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;프로야구를 생각하며 여러 대응 관계를 생각해보자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 구단과 선수들의 관계.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;구단 하나에 여러 명의 선수들이 대응되는 관계다.&lt;/p&gt;
&lt;p&gt;일대다 대응이라 표현.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 선수와 출전 선수&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;구단의 선수와 경기에 출전하는 선수들은 1개씩 대응되는 관계다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;일의 대응이라 표현.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 선수와 등번호.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;구단 선수와 등번호는 정확히 1명당 1개가 대응된다.&lt;/p&gt;
&lt;p&gt;일대일 대응이라 표현.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;일대일 대응은 일의 대응과 달리 '모든' 원소가 짝지어져야 한다.&lt;/p&gt;
&lt;p&gt;두 집합이 일대일 대응이 이루어지는 경우 '대등'하다고 하며 $\sim$를 사용하여 표현합니다.$$구단 선수 \sim 등번호$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;1.1.4 집합과 함수.&lt;/h4&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 191px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99914B335B5386F71E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99914B335B5386F71E&quot; width=&quot;191&quot; height=&quot;189&quot; filename=&quot;191px-Function_machine2.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;함수[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;함수&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_43_2&quot; id=&quot;footnote_link_43_2&quot; onmouseover=&quot;tistoryFootnote.show(this, 43, 2)&quot; onmouseout=&quot;tistoryFootnote.hide(43, 2)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;2&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;는 첫 번째 집합의 임의의 한 원소를 두 번째 집합의 오직 한 원소에 대응시키는 대응 관계이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;함수에 대해 설명하려면, 정의역, 공역, 치역이란 용어 설명이 필요하다.&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;정의역(domain)은 그 함수의 값이 정의된 집합이다.&lt;/li&gt;&lt;li&gt;공역(codomain) 또는 공변역은 이 함수의 값들이 속하는 집합이다. &lt;br /&gt;&lt;/li&gt;&lt;li&gt;치역(range 또는 target set)이라고 하는 것은 함수의 모든 &quot;출력&quot;값의 집합이다. 다시 말해, 정의역의 상(像)이다. &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99060F4F5B54D2AD16&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99060F4F5B54D2AD16&quot; width=&quot;800&quot; height=&quot;600&quot; filename=&quot;Codomain2.SVG.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;함수[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;함수 $f$는 다음과 같은 튜플 $(X,Y,\operatorname{graph}f)$이다. &lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;$X$는 집합이며, $f$의 '정의역'이라고 한다.&lt;/li&gt;&lt;li&gt;$Y$는 집합이며, $f$의 '공역'이라고 한다.&lt;/li&gt;&lt;li&gt;$\operatorname{graph}⁡ f$($f(x)$)는 곱집합 $X \times Y$의 부분집합이며, $f$의 그래프라고 한다.('치역')&lt;/li&gt;&lt;li&gt;단, 임의의 $x \in X$에 대하여, $(x,y)\in \operatorname{graph}⁡f$인 $y \in Y$가 유일하게 존재한다.&lt;br /&gt;$\operatorname{graph}⁡ f=f(x)=\{f(x):x\in X \} \subset Y$&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;다시 말해, 함수는 정의역의 각 원소를 정확히 하나의 공역 원소에 대응시킨다.&lt;/p&gt;
&lt;p&gt;이러한 $y$를 $f(x)$라고 쓰며, 이러한 $y$들의 집합을 '치역'이라고 한다. 치역은 공역의 부분 집합이나, 공역보다 작을 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;모두 함수를 나타내는 같은 표현이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$f \colon X \to Y \\ f \colon x \mapsto y \\ f(x)=y$$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 함수와 대응.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;집합의 대응과 비슷하게 함수의 대응이 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D0AF4E5B54D6DC1A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D0AF4E5B54D6DC1A&quot; width=&quot;200&quot; height=&quot;200&quot; filename=&quot;Injection.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;단사함수[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;정의역의 서로 다른 원소를 항상 공역의 서로 다른 원소로 대응시킨다면, 단사함수나 일대일 함수라 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;일의 대응과 비슷.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9904924F5B54D68F19&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9904924F5B54D68F19&quot; width=&quot;200&quot; height=&quot;200&quot; filename=&quot;Surjection.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;전사함수[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;공역의 모든 원소에게 정의역의 적어도 하나의 원소를 대응시킨다면, (즉, 치역이 공역과 같다면) 전사 함수 또는 위로의 함수라고 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;일대다 대응과 비슷하다고 느끼겠지만 전사함수는 '모든' 원소를 대응시켜야 하는 것 뿐이지, 반드시 일대다 대응이 되는 것은 아니다.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 200px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99DB37395B54D6C91C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99DB37395B54D6C91C&quot; width=&quot;200&quot; height=&quot;200&quot; filename=&quot;Bijection.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;전단사 함수[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;동시에 단사 함수이자 전사 함수라면, 전단사 함수 또는 일대일 대응이라고 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;일대일 대응과 비슷.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.2 유한집합과 무한집합 .&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;집합 A의 원소 개수는 3이었다. 그러나 집합 B, C의 원소 개수를 셀 수 있는가?&amp;nbsp;&lt;/p&gt;
&lt;p&gt;$B=\{4, 6, 8, 10, 12, 14, ...\}, C=\{5, 6, 7, 8, 9, ...\}$처럼 끝도 없이 이어지므로 셀 수 없다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이처럼 원소의 개수에 한계(1억개든, 10조개이든)가 있는 집합을 '유한집합'이라 하고, 한계가 없는 집합을 '무한집합'이라 한다.&lt;/p&gt;
&lt;p&gt;* 유한집합의 원소 개수는 '위수'라고 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;유한집합은 일대일 대응이 될 경우 위수, 즉 집합의 크기가 같다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그렇다면 무한집합은 어떨까?&lt;/p&gt;
&lt;p&gt;무한집합도 비슷하다. 일대일 대응이 되는지 확인하고 농도나 기수(Cardinality)라 표현한다.&lt;/p&gt;
&lt;p&gt;만약 무한인 어떤 집합과 다른 집합이 주어졌을 때 일대일 대응이 되는 경우 기수가 같다고 한다.$$|A| \; or \; cardA$$라고 적는다.&lt;/p&gt;
&lt;p&gt;* 무한집합의 기수는 초한기수라고 부름.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기서 중요한 사실을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;두 집합이 일대일 대응이 될 경우 기수가 같다.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;제한이 없다는 무한집합도 크기를 비교할 수 있게 된 것이다!!&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자연수 집합 $\mathbb{N}$과 자연수인 짝수의 집합 $E$을 비교해보자.(Natural Number와 Even number에서 따옴.)&lt;/p&gt;
&lt;p&gt;$$\begin{matrix} \mathbb{N}| &amp;amp; 1 &amp;amp; 2 &amp;amp; 3 &amp;amp; 4 &amp;amp; … \\ E| &amp;amp; 2 &amp;amp; 4 &amp;amp; 6 &amp;amp; 8 &amp;amp; … \end{matrix}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;분명 자연수의 집합의 진부분 집합인 자연수인 짝수 집합이 대등하다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;대등하다는 것은 기수가 같고, 기수가 같다는 건 집합의 크기가 같다는 뜻이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;어떻게 일대일 대응이 된다는 말인가? &lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 646px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E01D485B44F97214&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E01D485B44F97214&quot; width=&quot;646&quot; height=&quot;214&quot; filename=&quot;ab-xy.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;갈릴레이 - 새로운 두 과학에 대한 논의 및 수학적 설명[from &lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=3568416&amp;amp;cid=58944&amp;amp;categoryId=58970&quot; target=&quot;_blank&quot;&gt;네이버 지식백과&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;선분 AB를 자연수 중 짝수, 선분 CD를 자연수라 할 때 그림처럼 이어준다면 두 선분의 점들은 일대일 대응이 된다는 뜻이다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아직도 대등하다는 뜻이 이해되지 않는다면 필시 $$\begin{matrix} \mathbb{N}| &amp;amp; 1 &amp;amp; 2 &amp;amp; 3 &amp;amp; 4 &amp;amp; 5 &amp;amp; … \\ E| &amp;amp; x &amp;amp; 2 &amp;amp; x &amp;amp; 4 &amp;amp; x &amp;amp; … \end{matrix}$$ 처럼 대응되지 않았기 때문이다.&lt;/p&gt;
&lt;p&gt;칸토어라는 수학자는 이렇게 돌파한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;'최선을 다한 대응'을 찾아라!&lt;/p&gt;
&lt;p&gt;무슨 말인가 하면, 원소끼리 대응을 하는 것은 $$\begin{matrix} \mathbb{N}| &amp;amp; 1 &amp;amp; 2 &amp;amp; 3 &amp;amp; 4 &amp;amp; … \\ E| &amp;amp; x &amp;amp; 2 &amp;amp; x &amp;amp; 4 &amp;amp; … \end{matrix}$$또는 $$\begin{matrix} E| &amp;amp; 2 &amp;amp; 4 &amp;amp; 6 &amp;amp; 8 &amp;amp; … \\ \mathbb{N}| &amp;amp; x &amp;amp; 1 &amp;amp; x &amp;amp; 2 &amp;amp; … \end{matrix}$$처럼 엿장수 마음대로 일 수 있기 때문에 중간에 비는 것이 없이 모두 일대일 대응이 되도록 하라는 것이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;방금 예로부터 우리는 유한집합과 무한집합의 차이를 느낄 수 있었고, 정의 해볼 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;자신과 대등한 진부분 집합이라면 무한집합이고, 아니라면 유한집합이다.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;또한&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;전체와 부분의 기수가 똑같을 수 있으며, 포함 관계와 기수는 다른 개념이다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;라는 것 또한 알 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;포함 관계와 기수가 다른 개념이라는 것은 집합 $A$와 $C$처럼 포함 관계가 아닌 집합끼리 기수 비교를 할 수 있다는 것을 생각하면 좀 더 명확하다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;2. 수와 기수.&lt;br /&gt;&lt;/h2&gt;&lt;h3&gt;2.1 자연수.&lt;br /&gt;&lt;/h3&gt;&lt;h4&gt;2.1.1 자연수와 가산집합.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;힐베르트의 호텔 이야기를 들어본 적 있나요?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;무한개의 방이 있는 호텔에 손님이 다 찼는데 1명이 오면 힐베르트가 기존 손님들에게 지금 있는 방에서 1을 더한 방($n+1$)으로 이동하라고 해서 객실을 확보하고, 무한명의 손님이 온다면 2를 곱한 객실($2n$)로 이동하게 하고 홀수 번의 방에 손님들을 묵게 해준다는 내용 입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;대등하다면 크기가 같다는 성질을 이용한 이야기입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;수학에서 자연수의 기수를 가산 기수 또는 $\aleph_0$(알레프 제로)라고 한다.&lt;/p&gt;
&lt;p&gt;자연수와 대등한 집합은 셀 수 있다는 뜻에서 가산집합이라 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;가산집합의 가장 큰 특징은 무한집합들은 한 개 이상의 가산집합을 포함한다는 것.&lt;/p&gt;
&lt;p&gt;어쩌면 당연하지만, 무한집합도 1개 이상의 원소를 가지고 있다.&lt;/p&gt;
&lt;p&gt;이 말은 1개 정도는 셀 수 있다는 뜻이며, 무한집합은 가산집합을 포함한다고 생각할 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;힐베르트의 호텔에서 나온 성질을 $\aleph_0$를 사용하여 나타내면,$$\aleph_0 + 1 = \aleph_0 \\ \aleph_0 \times 2 = \aleph_0$$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.1.2 자연수의 공리.&lt;/h4&gt;&lt;p&gt;바로 뒤에서 정수와 비교하기 전에 자연수가 무엇인지에 대해 다루어보자.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기선 나무위키에 있는 페아노 공리를 통해 알아봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* 공리는 어떤 이론체계에서 가장 기초적인 근거가 되는 명제(命題)이다. 어떤 다른 명제들을 증명하기 위한 전제로 이용되는 가장 기본적인 가정을 가리킨다. 지식이 참된 것이 되기 위해서는 근거가 필요하나 근거를 소급해 보면 더 이상 증명하기가 곤란한 명제에 다다른다. 이것이 바로 공리이다. 참고로 증명이 필요한 명제중 증명이 완료된 명제를 정리라고 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: square;&quot;&gt;&lt;li&gt;$1 \in \mathbb{N}$&lt;br /&gt;1을 뜻하는 원소를 가진다. [사실 꼭 1이 아니라 1과 '같은 의미'를 가지면 됨.]&lt;br /&gt;&lt;/li&gt;&lt;li&gt;$x \in \mathbb{N} \to x^+ \in \mathbb{N}$&lt;br /&gt;자연수인 원소 $x$의 바로 다음 원소 $x^+$는 자연수다.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;$\forall x \in \mathbb{N} \to x^+ \neq 1$&lt;br /&gt;자연수인 임의의(모든) 원소 $x$가 있으면 다음 원소 $x^+$는 1이 아니다.($x$가 0이 아님)&lt;/li&gt;&lt;li&gt;$x \in \mathbb{N}, y \in \mathbb{N} \; s.t \;x \neq y \to x^+ \neq y^+$&lt;br /&gt;자연수인 원소 $x$와 $y$는 $x$가 $y$가 다를 때 다음 원소인&amp;nbsp; $x^+$와 $y^+$도 다르다.&lt;br /&gt;(s.t.는 such that의 뜻으로 '다음과 같다'란 의미 , 대우 시킴)&lt;/li&gt;&lt;li&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;$1 \in X$&lt;/li&gt;&lt;li&gt;$x \in X \to x^+ \in X \\ \therefore X=\mathbb{N}$&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;$X$가 집합 일 때, &lt;br /&gt;$1$인 원소를 포함한다.[1]&lt;br /&gt;또한 원소 $x$가 $X$에 포함되면 다음 원소 $x^+$도 $X$에서도 성립한다.&amp;nbsp; 그러면 집합 $X$는 $\mathbb{N}$(자연수)와 같다.[2]&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;어쩌면 당연하게 느끼던 자연수에 대하여 잘 설명하고 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;페아노의 공리 중 마지막은 수학적 귀납법을 이용한 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;잠깐 수학적 귀납법을 알아보죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 수학적 귀납법.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;자연수 $n$에 대한 임의의 1항 술어 $P(-)$가 있을 때, $P(n)$이 모든 자연수 n에 대하여 성립한다는 것을 증명하려면 다음 두 조건을 만족시키면 된다. &lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: square;&quot;&gt;&lt;li&gt;n=1일 때, 명제 P(n)이 성립한다.&lt;/li&gt;&lt;li&gt;n=k일 때, 명제 P(n)이 성립한다고 가정하면 n=k+1일 때에도&amp;nbsp; p(n) 역시 성립한다.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;페아노의 공리와 비슷하죠?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;모든 자연수가 어떤 주어진 성질을 만족시킨다는 명제를 증명하는 방법이기 때문에 자연수의 정의를 이용한 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;식으로 나타내면 이렇게 된다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\forall P(-)((P(0) \land \forall n(P(n) \; \Longrightarrow \; P(n+1))) \; \Longrightarrow&amp;nbsp; \; \forall nP(n))$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.2 정수.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;정수는 음의 정수(-1, -2, -3, -4, ...), 0, 양의 정수(1, 2, 3, 4, ...)가 합해져서 만들어진 수 입니다.&lt;/p&gt;
&lt;p&gt;독일어 Zahlen에서 따와 보통 $\mathbb{Z}$로 표시합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;양의 정수가 곧 자연수이므로,$$\mathbb{N} \subset \mathbb{Z}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자연수와 정수가 대응이 되나 확인해봅시다.(아래에서는 Integer에서 따와 I로 표시한 듯.)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 501px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995947385B463F8302&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995947385B463F8302&quot; width=&quot;501&quot; height=&quot;221&quot; filename=&quot;N-I.jpeg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;자연수와 정수 대응[from &lt;a class=&quot;tx-link&quot; href=&quot;https://www.quora.com/Is-there-an-infinity-bigger-than-the-infinity-of-real-numbers&quot; target=&quot;_blank&quot;&gt;Quora&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;억지 같지만, 일정한 규칙(절댓값 순)을 가지고 자연수와 정수가 일대일로 대응하는 것을 볼 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자연수와 정수의 크기는 같았다!!&lt;/p&gt;
&lt;p&gt;양의 정수와 음의 정수의 기수를 더한 것이 자연수의 기수이므로 이렇게 나타낼 수 있다.&lt;/p&gt;
&lt;p&gt;$$\aleph_0 + \aleph_0 = \aleph_0$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;(양의 정수는 자연수, 음의 정수도 $-$를 붙힌 자연수로 취급 할 수 있다.)&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.3 유리수.&lt;/h3&gt;&lt;h4&gt;2.3.1 유리수와의 대응.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;유리수는 두 정수 $m, n(n \ne 0)$의 몫(Quotient)인 ${m \over n}$으로 나타낼 수 있는 수다.&lt;/p&gt;
&lt;p&gt;역시 $\mathbb{Q}로 표시$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;유리수에서 $+$가 붙는 수는 양수, $-$가 붙는 수는 음수라 부른다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;${1 \over 1}=1, {2 \over 1}=2, {-3 \over 1}=-3$이므로 유리수는 정수를 포함한다.$$\mathbb{Z} \subset \mathbb{Q}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;유리수도 자연수와 대등할까?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;정수에서 양의 정수가 일대일 대응되면, 음의 정수도 일대일 대응이 된다는 것을 보았으므로, 양수에 치중하여 설명해본다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;두 정수 $m, n$으로 이루어졌다는 것은 수를 데카르트 좌표계(흔히 $x,y$축으로 이루어지는 직교 좌표계)에 배열할 수 있다는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;흔히 대각화 증명(Diagonalization Proof)라 부른다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 646px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F4933C5B4656F01A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F4933C5B4656F01A&quot; width=&quot;646&quot; height=&quot;314&quot; filename=&quot;m-n1.jpg&quot; filemime=&quot;image/jpeg&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;데카르트 좌표에 대응[from &lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=3568639&amp;amp;cid=58944&amp;amp;categoryId=58970&quot; target=&quot;_blank&quot;&gt;네이버 지식백&lt;/a&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=3568639&amp;amp;cid=58944&amp;amp;categoryId=58970&quot; target=&quot;_blank&quot;&gt;과&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 분수의 특성을 생각해보면 ${1 \over 1}={2 \over 2}={3 \over 3}=1$처럼 중복되는 조합이 생겨나게 된다.&lt;/p&gt;
&lt;p&gt;어떻게 하면 될까?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그냥 제외하고 넘어가면 된다.&lt;br /&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 600px; width: 600px; height: 291px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99390E445B465A5A1E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99390E445B465A5A1E&quot; width=&quot;600&quot; height=&quot;291&quot; filename=&quot;m-n2.jpg&quot; filemime=&quot;image/jpeg&quot; style=&quot;width: 600px; height: 291px;&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 410px; width: 410px; height: 364px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/998365335B465F7222&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F998365335B465F7222&quot; width=&quot;410&quot; height=&quot;364&quot; filename=&quot;m-n4.png&quot; filemime=&quot;image/png&quot; style=&quot;width: 410px; height: 364px;&quot; original=&quot;yes&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;데카르트 좌표에 대응과 흐름 - 2[from &lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=3568639&amp;amp;cid=58944&amp;amp;categoryId=58970&quot; target=&quot;_blank&quot;&gt;네이버 지식백&lt;/a&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=3568639&amp;amp;cid=58944&amp;amp;categoryId=58970&quot; target=&quot;_blank&quot;&gt;과&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://divisbyzero.com/2013/04/16/countability-of-the-rationals-drawn-using-tikz/&quot; target=&quot;_blank&quot;&gt;D&lt;/a&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://divisbyzero.com/2013/04/16/countability-of-the-rationals-drawn-using-tikz/&quot; target=&quot;_blank&quot;&gt;ivisbyzero&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;조금 편하게 보라고 두번째 그림을 삽입했는데 둘의 흐름이 조금 다르게 나와있지만, 원리는 비슷하다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;역시 음수를 포함 한 유리수 전체와 비교해보자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;사이트마다 진행 방향이 마음대로라(대응만 되면 되니..) 양수 흐름을 같이 첨부했다.&lt;br /&gt;&lt;/p&gt;&lt;table cellspacing=&quot;5&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 410px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9918BE465B46615E24&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9918BE465B46615E24&quot; width=&quot;410&quot; height=&quot;389&quot; filename=&quot;m-n3.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 560px; width: 560px; height: 400px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99ACFC345B46616424&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99ACFC345B46616424&quot; width=&quot;560&quot; height=&quot;400&quot; filename=&quot;m-n5.png&quot; filemime=&quot;image/png&quot; style=&quot;width: 560px; height: 400px;&quot;/&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;text-align: center;&quot;&gt;자연수와 유리수 대응[from &lt;a class=&quot;tx-link&quot; href=&quot;https://www.quora.com/Is-there-an-infinity-bigger-than-the-infinity-of-real-numbers&quot; target=&quot;_blank&quot;&gt;Quora&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아무튼 지금까지 첨부한 사진들처럼 자연수와 유리수는 대응될 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;정수 $m,n$쌍은 $m \times n$로 표현하므로 $$\aleph_0 \times \aleph_0 = \aleph_0$$란 특성을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이제 기수에서 조금 빠져서, 유리수를 통해 무한과 관계를 몇가지 살펴보도록 하죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.3.2 유리수와 소수.&lt;/h4&gt;&lt;p&gt;유리수의 조밀성과 극한을 설명하기 위해 소수(Decimals, Prime Number가 아니다)를 사용하겠습니다.&lt;/p&gt;
&lt;p&gt;그 전에 소수와의 관계를 알아봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;유리수는 정수 숫자 2개로 조합한 분수라고 했죠?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;유리수는 분수의 형태이기 때문에 정수 사이를 표현할 수 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;분수와 비슷하게 정수 사이를 표현할 수 있는 수는?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;바로 소수 입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;소수는 우리가 사용하는 아라비아 숫자를&amp;nbsp; 위치에 따라 ${1 \over 2}=0.5, {1 \over 10}=0.1, {1 \over 100}=0.01$처럼 나타내는 방식이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;위치 기수법에 대해 알고 싶다면&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/27&quot; target=&quot;_blank&quot;&gt;2017/10/06 - [수학] - 기수법(記數法, Numeral System)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;를 참고하기 바란다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기서 드는 의문은 분수와 소수가 호환이 가능한 가이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;분수를 소수로 바꾸면 $$\begin{matrix} {1 \over 1}&amp;amp;=&amp;amp;1, &amp;amp; {1 \over 2}&amp;amp;=&amp;amp;0.5, &amp;amp; {1 \over 3}&amp;amp;=&amp;amp;0.33333..., &amp;amp; {1 \over 4}&amp;amp;=&amp;amp;0.25, \\ {1 \over 5}&amp;amp;=&amp;amp;0.2, &amp;amp; {1 \over 6}&amp;amp;=&amp;amp;0.16666..., &amp;amp; {1 \over 7}&amp;amp;=&amp;amp;0.1428571428... \end{matrix}$$처럼 된다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;분수는 유한소수 또는 순환소수 중 하나로 표현되는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;분수가 나누어 떨어지거나 순환되는 소수로 변환되는 이유는 나누는 수가 $n$일 때 나머지는 $0$부터 $n-1$까지 $n$개만이 가능하고, 같은 나머지가 나오면 그 뒤로의 나눗셈의 과정은 반복되기 때문이다.&lt;/p&gt;
&lt;p&gt;그리고 소인수분해 시 2와 5만을 가지는 수들만 유한소수가 되는 이유는 우리는 10진법을 사용하고 있기 때문입니다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt; 순환소수는 점을 찍어 순환이 된다는 것을 표시한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;ex) $0.33333...=0.\dot{3}, 0.16666...=0.1\dot{6}, 0.1428571428...=0.\dot{1}\dot{4}\dot{2}\dot{8}\dot{5}\dot{7}$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$0.\dot{3}$처럼 첫 자리부터 순환하면 순순환소수, $0.1\dot{6}$처럼 그 이후로 순환이 시작되면 혼순환소수다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;분수는 소수로 나타낼 수 있다는 것을 알 수 있었다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;분수와 반대로 소수도 분수로 나타낼 수 있는지 알아볼 차례다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;유한소수는 $$0.5={5 \over 10}={1 \over 2}, 0.25={25 \over 100}={1 \over 4}, 0.2={2 \over 10}={1 \over 5}$$와 같이 한 자리당 $10^n$차이라는 것을 이용하여 바꿀 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;순환소수는 $$\begin{matrix} x=0.\dot{3}&amp;nbsp; \\ 10x=3.\dot{3}&amp;nbsp; \\&amp;nbsp; 10x-x=9x&amp;amp;=&amp;amp;3 \\ x={3 \over 9}={1 \over 3} \end{matrix}$$&lt;br /&gt;$$\begin{matrix} y=0.1\dot{6} \\ 100y=16.\dot{6} \\ 100y-10y=90y=15 \\ y={15 \over 90}={1 \over 6} \end{matrix}$$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\begin{matrix} z=0.\dot{1}\dot{4}\dot{2}\dot{8}\dot{5}\dot{7} \\ 1000000z=142857.\dot{1}\dot{4}\dot{2}\dot{8}\dot{5}\dot{7} \\ 1000000z-z=999999z=142857 \\ z={142857 \over 999999}={1 \over 7}\end{matrix}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;처럼 처음 순환하는 것 만큼만 남겨두고 나머지 순환 부분을 제거하는 방식을 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 순환하지 않는 무한소수(비순환소수)라면?&lt;/p&gt;
&lt;p&gt;에를 들어 $\sqrt{2}=1.414213...$나 $\pi=3.141592...$와 같다면 유리수가 아닌 무리수입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;유한소수와 순환소수는 유리수고, 비순환소수는 무리수다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.3.3 유리수와 조밀성.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;1과 2사이에 얼마나 어떤 유리수가 존재할까?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$1.2, 1.9$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그러면 그 사이는?&lt;/p&gt;
&lt;p&gt;$1.4, 1.5$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;또 그 사이는?&lt;/p&gt;
&lt;p&gt;$1.45, 1.46$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;또또 그 사이는?&lt;/p&gt;
&lt;p&gt;$1.451, 1.456$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자연수와 정수에서는 1과 2사이의 수를 찾을 수 없었지만, 유리수에서는 무수히 많습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;두 유리수 a와 b(단, a&amp;lt;b) 사이에 다른 유리수가 존재한다는 것을 식으로 설명하면&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$a,b \in \mathbb{Q}, \; a&amp;lt;b \to a&amp;lt; {a+b \over 2} &amp;lt;b$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;의 형태.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이러한 성질을 '조밀성'이라고 한다.&lt;/p&gt;
&lt;p&gt;반대로 $\mathbb{N}$이나 $\mathbb{Z}$처럼 띄엄띄엄 있는 것은 '이산성'이라 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.3.4 유리수와 극한.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;한가지 재미있는 현상을 보자.&lt;/p&gt;
&lt;p&gt;$${1 \over 3}=0.33333..=0.\dot{3} \\ {1 \over 3} \times 3 = 0.\dot{3} \times 3 \\ 1 = 0.\dot{9}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;${1 \over 3} \times 3$을 하면 분명 $1$이란 결과가 나와야 할 터인데 $0.\dot{9}$라는 말도 안되는 결과가 나와버렸다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;0.9999...처럼 9가 무한히 나오기 때문에 $1$과 가까워지지만 $1$이 된다는 것을 이해하기 힘들다.&lt;/p&gt;
&lt;p&gt;이렇게 언제나 크거나 작도록 값을 조정할 수 있고 끝이 없으므로 현실적으로 존재하기 어렵다는 개념이 '가무한'이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그러나 ${1 \over 3} \times 3=1$이 맞지 않은가?&lt;/p&gt;
&lt;p&gt;이 때문에 나온 것이 바로 '극한'이라는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;극한을 설명하는 글을 쓰다 너무 길어져서 극한에 관련된 부분은 글을 새로 팔려고 한다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/44&quot; target=&quot;_blank&quot;&gt;2018/07/30 - [수학] - 집합(위상)과 극한에 대하여[일부 내용 펌].&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;어쨌든 극한은 무한히 가까이 가는 과정과 그 과정이 구체적으로 나타난 결과인 극한 값이라는 두 개의 의미를 가지고 있는데 $0.\dot{9}$는 무한의 과정이 사실로 나타난 결과로, 실제로 존재하는 극한 값이며 이것은 정확히 '1과 동일한 실체'다. 실무한이라는 뜻.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.4 무리수.&lt;br /&gt;&lt;/h3&gt;&lt;h4&gt;2.4.1 무리수와 실수 기본.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;비순환소수가 무리수에 속한다는 것을 이용하여 아주~ 간단하게 말하면 0을 제외한 정수비(분수)가 아닌 수이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt; 실수는 유리수 $\cup$ 무리수며 Real Number에서 따와 $\mathbb{R}$로 보통 표시한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;실수는 수직선의 형태로 표현 할 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 591px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9945C9345B4CF31122&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9945C9345B4CF31122&quot; width=&quot;591&quot; height=&quot;52&quot; filename=&quot;Number-line.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;수직선[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%88%98%EC%A7%81%EC%84%A0_(%EC%88%98%ED%95%99)&quot; target=&quot;_blank&quot;&gt;Wekipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.4.2 무리수.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;무리수의 정의하는 방법도 극한 글을 읽고 오면 쉽게 이해할 수 있다.&lt;/p&gt;
&lt;p&gt;(특히 개집합, 폐집합 부분)&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;데데킨트는 '&lt;a href=&quot;https://ko.wikipedia.org/wiki/데데킨트_절단&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;데데킨트 절단(Dedekind Cut)&lt;/a&gt;'이란 방법을 사용하여 설명한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/990A7F3E5B4CFE5F2A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F990A7F3E5B4CFE5F2A&quot; width=&quot;820&quot; height=&quot;254&quot; filename=&quot;dedekind cut.jpeg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;데데킨트 절단[from &lt;a class=&quot;tx-link&quot; href=&quot;https://twitter.com/SheenCB/status/948600364051279872&quot; target=&quot;_blank&quot;&gt;twitter @SheenCB&lt;/a&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://twitter.com/SheenCB/status/948600364051279872&quot; target=&quot;_blank&quot;&gt;]&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;유리수를 가위나 칼 같은 도구로 대소 두 집합 A, B가 나오도록 '절단(cut)' 해버린다고 생각하자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;단, $A \cup B = \mathbb{Q}$와 $A \cap B =\emptyset$이며 $a&amp;lt;b$(각각 A와 B에서 가장 큰 유리수, 가장 작은 유리수)가 이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;절단 시 상태는 도구에 $a$와 $b$가 닿느냐 닿지 않느냐로 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;닿느냐 닿지 않느냐는 a와 b를 포함하냐 하지 않느냐와 같은 말로서 개구간, 폐구간으로 이해할 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\begin{array}{c|c|c|c} \hline \hline&lt;br /&gt;&amp;nbsp; 절단종류 &amp;amp; a &amp;amp; b &amp;amp; 결과 \\ \hline \hline&lt;br /&gt;&amp;nbsp; 1 &amp;amp; T &amp;amp; T &amp;amp; [a,b] \\ \hline&lt;br /&gt;&amp;nbsp; 2 &amp;amp; T &amp;amp; F &amp;amp; [a,b) \\ \hline&lt;br /&gt;&amp;nbsp; 3 &amp;amp; F &amp;amp; T &amp;amp; (a,b] \\ \hline&lt;br /&gt;&amp;nbsp; 4 &amp;amp; F &amp;amp; F &amp;amp; (a,b) \\ \hline&lt;br /&gt;\end{array}$$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;절단을 2를 기준으로 했다고 가정하자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;1번의 경우 최대인 수와 최소인 수가 집합 $A$, $B$에 있다.&lt;/p&gt;&lt;p&gt;집합 $A$는 $\{..., 0,1,2\}$, 집합 $B$는 $\{3,4,5,...\}$, 또는 $\{...,-1,0,1\}$과 $\{2,3,4,...\}$ 와 같이 이산성을 가질 때 성립한다.&lt;/p&gt;&lt;p&gt;정수를 나타낸다는 뜻.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;유리수가 해당되는 것이 $\{a | a \leq 2\}$와 $\{b | 2 &amp;lt; b\}$이다.&lt;/p&gt;
&lt;p&gt;$[a,b)$의 형태를 가지는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;'조밀성'을 띄기 때문에 $[a,b]$는 될 수 없고, $(a,b]$는 $[a,b)$와 사실상 동치이다.&lt;/p&gt;
&lt;p&gt;즉, 유리수는 도구에 한쪽만 닿는 2번 $[a,b)$와 3번 $(a,b]$ 임을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그럼 무리수는?&lt;/p&gt;
&lt;p&gt;양쪽 다 닿지 않는 4번 $(a,b)$이다.&lt;/p&gt;
&lt;p&gt;아주 대표적인 예로 유리수인 $a,b$를 $a^2&amp;lt;2&amp;lt;b^2$를 만족하는 원소를 찾는 것이다.&lt;/p&gt;
&lt;p&gt;유리수의 조밀성 때처럼 해보자.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이때 '(단순)연분수'를 사용할 것이다.&lt;/p&gt;
&lt;p&gt;연분수는 다음과 같이 이루어져 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$x = a_0 + {1 \over a_1 + {1 \over a_2 + {1 \over a_3 + ...}}}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이를 $[a_0; a_1, a_2, a_3, ...]= \lim_{n \to \infty}[a_0; a_1, a_2, a_3, ..., a_n]$처럼 표현이 가능하다.&lt;/p&gt;
&lt;p&gt;$a_n$때 나오는 근삿값은 $n$번째 convergent라고 말하며 $c_n$로 표현한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$a_n$의 자리엔 정수($a_0$은 정수, 나머지 $a_n$은 양의 정수)를 뽑고, 그 뒤에 남은 진분수는 역수를 취하여 분모로 옮긴 다음&amp;nbsp; &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;유한소수인 ${11 \over 4}$와 순환소수인 ${11 \over 3}$을 예로 들어 연분수를 사용해보자.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;$${11 \over 4}=2+{3 \over 4}=2+{1 \over {4 \over 3}}=2+{1 \over 1+{1 \over
 3}}=2+{1 \over 1+{1 \over{3 \over 1}}}=2+{1 \over 1+{1 \over 2+{1 \over
 1}}} \\&lt;br /&gt;{11 \over 3}=3+{2 \over 3}=3+{1 \over {3 \over 2}}=3+{1 \over 1+{1 \over
 2}}=3+{1 \over 1+{1 \over {2 \over 1}}}=3+{1 \over 1+{1 \over 1+{1 
\over 1}}}$$&lt;/p&gt;
&lt;p&gt;이렇게 연분수는 유리수를 유한 연분수의 형태로 나타낼 수 있으며, 무한 연분수는 무리수다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$\sqrt{2}$를 이와 동일하게 계산해보자.&lt;/p&gt;
&lt;p&gt;$$\begin{matrix} \sqrt{2}&amp;amp;=&amp;amp;1+(\sqrt{2}-1)&amp;amp;=&amp;amp;1+{1 \over {1 \over \sqrt{2}-1}}&amp;amp;=&amp;amp;1+{1 \over {\sqrt{2}+1 \over (\sqrt{2}-1)(\sqrt{2}+1)}}&amp;amp;=&amp;amp;1+{1 \over {\sqrt{2}+1 \over 2-1}}&amp;amp;=&amp;amp;1+{1 \over 2+(\sqrt{2}-1)}...(ㄱ)&lt;br /&gt;\\&amp;amp;=&amp;amp;1+{1 \over 2+ {1 \over {1 \over \sqrt{2}-1}}}&amp;amp;=&amp;amp;1+{1 \over 2+ {1 \over {\sqrt{2}+1 \over (\sqrt{2}-1)(\sqrt{2}+1)}}}&amp;amp;=&amp;amp;1+{1 \over 2+ {1 \over \sqrt{2}+1}}...(ㄴ)&lt;br /&gt;\\&amp;amp;=&amp;amp;1+{1 \over 2+{1 \over 2+(\sqrt{2}-1)}}...(ㄷ) \end{matrix}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이는&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\sqrt{2}=1+{1 \over {2 + \over {1 \over {2 + {1 \over 2+…}}}}}=[1; 2,2,2,...]=[1; \dot{2}]$$&lt;/p&gt;
&lt;p&gt;로도 표현이 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$\sqrt{2}$의 convergent(ㄱ, ㄴ, ㄷ처럼 표시된 부분)는 다음의 표와 그림처럼 나타난다.&lt;/p&gt;
&lt;p&gt;$$\begin{array}{c|c c c c c c c c c c}&lt;br /&gt;n &amp;amp; 0 &amp;amp; 1 &amp;amp; 2 &amp;amp; 3 &amp;amp; 4 &amp;amp; 5 &amp;amp; 6 &amp;amp; 7 &amp;amp; 8 &amp;amp; 9 \\ \hline&lt;br /&gt;c_n &amp;amp; {1 \over 1} &amp;amp; {3 \over 2} &amp;amp; {7 \over 5} &amp;amp; {17 \over 12} &amp;amp; {41 \over 29} &amp;amp; {99 \over 70} &amp;amp; {239 \over 169} &amp;amp; {577 \over 408} &amp;amp; {1393 \over 985} &amp;amp; {3363 \over 2378} \end{array}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 819px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991176435B4D1B8717&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991176435B4D1B8717&quot; width=&quot;819&quot; height=&quot;410&quot; filename=&quot;Dedekind_cut-_square_root_of_two.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;$\sqrt{2}$에 한없이 접근하는 모습[from &lt;a class=&quot;tx-link&quot; href=&quot;https://en.wikipedia.org/wiki/Dedekind_cut&quot; target=&quot;_blank&quot;&gt;wikipedia&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 무리수의 구성.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;무리수는 다항 방정식의 근이 될 수 있는 '대수적 무리수'와 '초월수'로 나눌 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;대수적 무리수의 대표적인 예는 $\sqrt{2}$이며, 초월수의 대표적인 예는 $\pi$이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;무리수에 대해 알았으니, 실수의 기수에 대해 알아봅시다.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.5 실수와 도형.&lt;/h3&gt;&lt;h4&gt;2.5.1 실수와의 대응.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;무한소수의 형태로 $0$과 $1$사이의 모든 소수를 번호를 매겨서 나열해보겠다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$r_1=0.\colorbox{Yellow}{$a_{11}$}a_{12}a_{13}a_{14}a_{15}a_{16}... \\&lt;br /&gt;r_2=0.a_{21}\colorbox{Yellow}{$a_{22}$}a_{23}a_{24}a_{25}a_{26}... \\&lt;br /&gt;r_3=0.a_{31}a_{32}\colorbox{Yellow}{$a_{33}$}a_{34}a_{35}a_{36}... \\&lt;br /&gt;r_4=0.a_{41}a_{42}a_{43}\colorbox{Yellow}{$a_{44}$}a_{45}a_{46}... \\&lt;br /&gt;... \\&lt;br /&gt;$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이제 새로운 소수를 생각해보자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$0.b_1b_2b_3b_4b_5b_6...$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 $b_n$을 만들때 $b_1$에서는 $a_{11}$, $b_2$에선 $a_{22}$, $b_3$에선 $a_{33}$..와 같이 대각선에 있는 수를 제외시키고 만든다면 수없이 많은 무한소수를 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$0$에서 $1$사이의 모든 소수를 나열했다는 '가정이 틀렸다'는 것이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그래서 실수는 '셀 수 없는' 집합이다라는 것을 알 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;자연수의 기수를 $\aleph_0$로 나타냈던 것처럼 실수의 기수는 $C$로 나타내며 연속체라고 부른다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우리가 사용한 증명은 제외시키는 수가 대각선으로 있기 때문에 '대각선 증명'이라 불린다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.5.2 선분, 직선, 원&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;선분, 직선, 원의 기수에 대해 생각해봅시다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;일단 선분과 선분의 관계는 삼각형을 그림으로서 일대일 대응이 가능하다고 하였다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그럼 선분과 직선은?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;직선은 길이가 무한하고 가정하기 때문에 삼각형의 모양으론 일대일 대응이 불가능하다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;
&lt;p&gt;그럼 원과 선분의 관계를 생각해보자.&lt;/p&gt;
&lt;p&gt;수직선 상으로 내리면 일대일 대응이 가능하다!!&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C26E465B4F600E0C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C26E465B4F600E0C&quot; width=&quot;820&quot; height=&quot;728&quot; filename=&quot;circle-line1.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;원과 선분 AB의 관계.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;직선과 원도 생각해보자.&lt;/p&gt;
&lt;p&gt;원의 중심으로부터 방사형으로 뻗어나가게 하면 직선과 일대일 대응이 가능하다!!&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99FD094F5B4E7F0308&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99FD094F5B4E7F0308&quot; width=&quot;820&quot; height=&quot;532&quot; filename=&quot;circle-line2.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;원과 직선 CD의 관계.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;원과 선분과 대등하고, 원과 직선이 대등하므로 선분과 직선 또한 대등하다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;실수가 수직선의 형태와 같다고 했죠?&lt;/p&gt;
&lt;p&gt;수직선은 선분과 대등하므로, 아까 $0~1$까지에서 나온 실수의 성질은 실수 전체의 성질과 동일하다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;사실 $(0,1)$과 실수 전체를 대응시키는 함수를 찾으면 되는 건데..&lt;/p&gt;
&lt;p&gt;삼각함수 중 $tan(\pi \times (x+{1 \over 2}))$를 하면 0과 1 극한값이 각각 $-\infty, +\infty$값이 나오므로 간단하긴 하다.&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999664385B50E6591C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999664385B50E6591C&quot; width=&quot;820&quot; height=&quot;615&quot; filename=&quot;tan.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;오랜만에 써보는 매쓰랩 코드..(호환이 되는 Octave를 이용해서 그렸다.)&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;matlab&quot;&gt;x=0+0.01:0.01:1-0.01;
y=pi*(x+0.5);
plot(x,tan(y)), grid on;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위 코드를 사용하면 그래프를 그려볼 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.5.3 차원.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;차원은 공간 내에 있는 점 등의 위치를 나타내기 위해 필요한 축의 개수를 말한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9946134A5B4BB07733&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9946134A5B4BB07733&quot; width=&quot;500&quot; height=&quot;168&quot; filename=&quot;Dimension_levels.svg.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;차원과 축[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%B0%A8%EC%9B%90&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;1차원(직선) 위의 점은 1개, 2차원(평면) 위의 점은 2개, 공간(3차원) 위의 점은 3개처럼.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;차원에 따라 대응을 시킬 수 있는가?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;0과 1차원은 원의 중심(0차원)에서 직선(1차원)으로 뻗어나가는 식으로 대응시키면 된다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그럼 다른 차원들은?&lt;/p&gt;
&lt;p&gt;1차원을 기준으로 해보자.&lt;/p&gt;
&lt;p&gt;2차원($a_n,b_n$)에서 1차원은 $a_1 b_1 a_2 b_2 a_3 b_3 a_4 b_4...$로 대응시키면 된다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이제 2차원의 방식을 3차원, 4차원으로 똑같이 확장하면 된다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;3차원: $a_1 b_1 c_1 a_2 b_2 c_2 a_3 b_3 c_3 a_4 b_4 c_4...$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;4차원: $a_1 b_1 c_1 d_1 a_2 b_2 c_2 d_2 a_3 b_3 c_3 d_3 a_4 b_4 c_4 d_4...$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$...$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;정리하자면,&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;어떤 차원의 공간이든 연속체와 점 갯수가 같다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.5.4 멱집합.&lt;/h4&gt;&lt;b&gt;- 멱집합의 기수&lt;/b&gt;&lt;br /&gt;
&lt;p&gt;멱집합의 기수는 원래 집합의 원소가 원소로 존재하는가 하지 않는가로 생각할 수 있다.&lt;/p&gt;
&lt;p&gt;위 멱집합에서는 1이 존재하는가 하지 않는가, 2가 존재하는가 하지 않는가, 3이 존재하는가 하지 않는가로 나뉘어 $2^3=8$개이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이해가 가지 않는다면 데데킨트 절단 때처럼 ($T,F$로 나누어 표로 작성해보자)&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;멱집합의 기수를 임의의 집합 $S$를 사용하여 일반화하면 &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$|\mathcal{P(S)}|=2^{|S|} =2^{\aleph_0}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;가 된다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;마지막에 $\aleph_0$를 사용한 이유는 $|S|$는 임의의 집합 $S$의 기수(원소 갯수)이므로 0이나 자연수의 기수($\aleph_0$)이기 때문이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;굳이 무한집합에서도 어떻게 성립되는가를 알기 위해 대응이 되는지 살펴보자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;집합 $S$에 대해 $\mathcal{P}(S)$와 일대일 대응시키는 것이 목표.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt; 일대일 대응시키는 함수 $f$가 있을 때($f:S \to \mathcal{P}(S)$)&lt;/p&gt;
&lt;p&gt;집합 $\mathcal{P}(S)$의 부분집합 $X$를($X \subset \mathcal{P}(S)$)&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$X=\{s \in S |&amp;nbsp; s \notin f(s)\}$$$S$의 원소 $s$가 포함되지 않는 경우라 하자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;$X \in \mathcal{P}(S)$이므로(멱집합의 정의를 생각해보자) $X \subset S$인데, 어떤 $s$에 대해서도 $X$와 $f(s)$는 같을 수가 없다는 조건($X$의 정의)이 있어 모순이 된다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;쉽게 설명해 집합 S의 임의의 원소 s가 있을 때,&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;- $s \in X$일때.&lt;/p&gt;
&lt;p&gt;$s \notin f(s)$지만, 집합의 조건을 만족하기에 $f(s) = X$($\because X \subset \mathcal{P}(S)$)여서 $s \notin f(s)=X$이므로 $s \notin X$라 모순.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;- $s \notin X$일때.&lt;/p&gt;
&lt;p&gt;$f(s)=X$여서 $s \notin f(s)$지만, 집합의 조건에 따라 $X \in \mathcal{P}$여서 $s$는 $X$에 대응하는 원소($f(s)=X$)이므로 $s \in X$라 모순.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;s라는 원소는 반드시 둘 중 어느 한 쪽에만 들어가기 때문이다.&lt;/p&gt;따라서 이 대응은 절대 일대일 대응일 수 없다.&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;위키백과에 나온 증명은 이진법의 원리 이용한 것이다.&lt;/p&gt;
&lt;p&gt;$2^{|S|}$는 기수의 거듭제곱이므로&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\{0,1\}^S=\{f\colon S\to \{0,1\}\}$$&lt;/p&gt;
&lt;p&gt;의 크기를 가지며&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\mathcal P(S)\longrightarrow\{0,1\}^S \\ X\longmapsto f(s)=\begin{cases}1&amp;amp;s\in X\\0&amp;amp;s\notin X\end{cases}$$0과 1로 대응이 된다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;형태는 조금 달랐지만 멱집합의 기수는 항상 원래 집합보다 큼을 알 수 있다.&lt;/p&gt;
&lt;p&gt;$$|\mathcal{P(S)}| &amp;gt; |S|$$&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;즉, $$\mathcal{P}(2^{\aleph_0})&amp;gt;\aleph_0$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 실수와 멱집합.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;연속체의 기수 $C$와 $\aleph_0$의 관계를 생각해보자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우리가 사용하는 수들은 보통 10진법으로 사용하고 있다.&lt;/p&gt;
&lt;p&gt;그러나 2진법으로 읽는다면?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;10진법과 2진법 변환은 예전에 올렸던 글&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/27&quot; target=&quot;_blank&quot;&gt;2017/10/06 - [수학] - 기수법(記數法, Numeral System)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;을 참고.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;2진법의 각자리는 $0$과 $1$로 이루어지기 때문에 $2^n$개의 가능성, 즉 $2^{\aleph_0}$란 기수를 가진다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$C=2^{\aleph_0}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.5.5 연속체 가설(continuum hypothesis).&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;초한기수로 수열을 만든다면 $\aleph_0, \aleph_1, \aleph_2, \aleph_3, \aleph_4, \aleph_5, ...$로 나타낼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;연속체 가설은 $\aleph_1=2^{\aleph_0}=C$ 그러니까 $\mathbb{N}$과 $\mathbb{R}$사이의 기수가 존재치 않다는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 패러독스(역설).&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;유명한 패러독스 중에 이발사 패러독스가 있다.&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;자기 스스로 면도를 하지 않는 주민들의 면도를 이발사가 해준다. 단, 스스로 깎는 사람은 잘라주지 않는다.&lt;/p&gt;
&lt;p&gt;이발사는 자신의 수염을 어떻게 해야 하는가?&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;여기에서 자신을 원소로 가지지 않는 집합을 $X$, 모든 집합을 $U$, 임의의 집합 $A$와 함께 표시하면 어딘가 익숙한&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$X=\{A \in U | A \notin A\}$$이 만들어진다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이는 이미 멱집합의 기수에서 증명한 것으로, 모순이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$R=\{x|x \notin x\}$이면 $R\in R \Longleftrightarrow R \notin R$라는 것이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기에서 필요한 것이 괴델의 불완전성 정리이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;무모순인 동시에 완전할 수 없다. 즉 어떤 체계가 무모순이라면, 그 체계에서는 참이면서도 증명할 수 없는 명제가 적어도 하나 이상 존재한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;어떤 이론의 무모순성을 증명하려면 그보다 더 강력한 이론이 필요하다.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;불완정성 정리는 힐베르트(형식주의), 프레게(논리주의)를 비롯한 수학계와 철학계에 빅엿을 선사한다.&lt;/p&gt;
&lt;p&gt;그리고 인지 과학, 컴퓨터 과학 등까지 수많은 영향을 끼쳤다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;불완전성 원리가 영향을 끼친 것은 이 글에도 있다.&lt;/p&gt;&lt;p&gt;'전체 집합' 또는 '모든 집합'이라는 것은 불가능 하므로, '임의의 집합'이라고 표현을 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 연속체 가설과 불완정성 정리.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;연속체 가설은 계속 풀리지 않아 &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%ED%9E%90%EB%B2%A0%EB%A5%B4%ED%8A%B8_%EB%AC%B8%EC%A0%9C&quot; target=&quot;_blank&quot;&gt;힐베르트가 20세기에 풀어야 할 문제&lt;/a&gt; 1번으로 제안했다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;쿠르트 괴델은 기존 집합의 공리로는 연속체 가설을 반증할 수 없음을 증명했고(불완전성 원리), 폴 코헨은 기존 집합의 공리로는 연속체 가설을 증명할 수 없음을 증명했다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;현재 연속체 가설에 대한 명확한 답은 알아도 상관없고, 몰라도 상관없는 상태.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;-끝.-&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;참고.&lt;/b&gt; 위키백과[&lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot;&gt;집합&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot;&gt;함수&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%9E%90%EC%97%B0%EC%88%98&quot; target=&quot;_blank&quot;&gt;자연수&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/w/index.php?title=%EC%88%98%ED%95%99%EC%A0%81_%EA%B7%80%EB%82%A9%EB%B2%95&quot; target=&quot;_blank&quot;&gt;수학적 귀납법&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%B0%A8%EC%9B%90&quot; target=&quot;_blank&quot;&gt;차원&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EA%B3%B5%EB%A6%AC&quot; target=&quot;_blank&quot;&gt;공리&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%A0%9C%EA%B3%B1%EA%B7%BC_2&quot; target=&quot;_blank&quot;&gt;제곱근 2&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%97%B0%EB%B6%84%EC%88%98&quot; target=&quot;_blank&quot;&gt;연분수&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EB%8C%80%EA%B0%81%EC%84%A0_%EB%85%BC%EB%B2%95&quot; target=&quot;_blank&quot;&gt;대각선 논법&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/w/index.php?title=%EB%A9%B1%EC%A7%91%ED%95%A9&quot; target=&quot;_blank&quot;&gt;멱집합&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EB%9F%AC%EC%85%80%EC%9D%98_%EC%97%AD%EC%84%A4&quot; target=&quot;_blank&quot;&gt;러셀의 역설&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EA%B4%B4%EB%8D%B8%EC%9D%98_%EB%B6%88%EC%99%84%EC%A0%84%EC%84%B1_%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot;&gt;괴델의 불완전성 정리&lt;/a&gt; ], 네이버 지식백과[&lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=3568416&amp;amp;cid=58944&amp;amp;categoryId=58970&quot; target=&quot;_blank&quot;&gt;짝수vs자연수&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=3568517&amp;amp;cid=58944&amp;amp;categoryId=58970&quot; target=&quot;_blank&quot;&gt;자연수vs정수&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=3568639&amp;amp;cid=58944&amp;amp;categoryId=58970&quot; target=&quot;_blank&quot;&gt;자연수vs유리수&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=3568763&amp;amp;cid=58944&amp;amp;categoryId=58970&quot; target=&quot;_blank&quot;&gt;자연수vs실수&lt;/a&gt;,&amp;nbsp; &lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=2426078&amp;amp;cid=51349&amp;amp;categoryId=51349&quot; target=&quot;_blank&quot;&gt;유리수에서 실수로의 확장 - 데데킨트의 방법&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://terms.naver.com/entry.nhn?docId=3570783&amp;amp;cid=58944&amp;amp;categoryId=58970&quot; target=&quot;_blank&quot;&gt;괴델의 불완전성 정리&lt;/a&gt;],&amp;nbsp; &lt;a class=&quot;tx-link&quot; href=&quot;http://oll.libertyfund.org/titles/galilei-dialogues-concerning-two-new-sciences&quot; target=&quot;_blank&quot;&gt;Two New Sciences&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://www.quora.com/Is-there-an-infinity-bigger-than-the-infinity-of-real-numbers&quot; target=&quot;_blank&quot;&gt;Quora&lt;/a&gt;, 나무위키[&lt;a class=&quot;tx-link&quot; href=&quot;https://namu.wiki/w/%EC%9E%90%EC%97%B0%EC%88%98&quot; target=&quot;_blank&quot;&gt;자연수&lt;/a&gt;, &lt;a class=&quot;tx-link&quot; href=&quot;https://namu.wiki/w/%EB%B6%88%EC%99%84%EC%A0%84%EC%84%B1%20%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot;&gt;불완전성 정리&lt;/a&gt;], 제타위키[&lt;a class=&quot;tx-link&quot; href=&quot;https://zetawiki.com/wiki/%EB%9F%AC%EC%85%80%EC%9D%98_%EC%97%AD%EC%84%A4,_%EC%9D%B4%EB%B0%9C%EC%82%AC_%EC%97%AD%EC%84%A4&quot; target=&quot;_blank&quot;&gt;러셀의 역설, 이발사 역설&lt;/a&gt; ] &lt;a class=&quot;tx-link&quot; href=&quot;http://suhak.tistory.com/265&quot; target=&quot;_blank&quot;&gt;집합의 크기(cardinality)&lt;/a&gt; ,&lt;br /&gt;&lt;/p&gt;&lt;div style=&quot;background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 273px; top: 20737px; opacity: 0.3;&quot; id=&quot;s3gt_translate_tooltip_mini&quot; class=&quot;s3gt_translate_tooltip_mini_box&quot; is_mini=&quot;true&quot;&gt;&lt;div id=&quot;s3gt_translate_tooltip_mini_logo&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;선택한 텍스트 번역&quot;&gt;&lt;/div&gt;&lt;div id=&quot;s3gt_translate_tooltip_mini_sound&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;재생&quot; title_play=&quot;재생&quot; title_stop=&quot;중지&quot;&gt;&lt;/div&gt;&lt;div id=&quot;s3gt_translate_tooltip_mini_copy&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;클립보드에 텍스트 복사&quot;&gt;&lt;/div&gt;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;moz-extension://eb01d262-7f59-4b57-8859-d324bed86041/skin/s3gt_tooltip_mini.css&quot;&gt;&lt;style type=&quot;text/css&quot; media=&quot;print&quot;&gt;#s3gt_translate_tooltip_mini { display: none !important;&lt;br /&gt;&lt;/style&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol class=&quot;footnotes&quot;&gt;
    &lt;li id=&quot;footnote_43_1&quot;&gt;사실, '전체 집합'보단 '임의의 집합'이 옳은 표현이다. 이유는 뒤에서 설명한다. &lt;a href=&quot;#footnote_link_43_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_43_2&quot;&gt;사상(寫像)이라고도 함.
한자로 알 수 있듯, 물체를 복사하는 것처럼 형상을 보존하는 대응이다.  &lt;a href=&quot;#footnote_link_43_2&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description>
      <category>수학</category>
      <category>극한</category>
      <category>무한</category>
      <category>수</category>
      <category>수학</category>
      <category>집합</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/43</guid>
      <comments>https://black7375.tistory.com/43#entry43comment</comments>
      <pubDate>Sun, 22 Jul 2018 04:05:38 +0900</pubDate>
    </item>
    <item>
      <title>프로그래밍 폰트</title>
      <link>https://black7375.tistory.com/41</link>
      <description>&lt;link href=&quot;//cdn.jsdelivr.net/npm/nanum-gothic-coding@4.0.0/nanum-gothic-coding.min.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
&lt;link href=&quot;//cdn.jsdelivr.net/npm/hack-font@3/build/web/hack.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
&lt;link href=&quot;http://cdn.jsdelivr.net/gh/joungkyun/font-d2coding/d2coding.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/dejavu-sans@1.0.0/css/dejavu-sans.min.css&quot;&gt;
 &lt;link href=&quot;https://fonts.googleapis.com/css?family=Anonymous+Pro&amp;amp;subset=latin-ext&quot; rel=&quot;stylesheet&quot;&gt;
 &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;//fonts.googleapis.com/css?family=Droid+Sans+Mono&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://mplus-webfonts.sourceforge.jp/mplus_webfonts.css&quot;&gt;
&lt;link href=&quot;https://fonts.googleapis.com/css?family=IBM+Plex+Mono&amp;amp;subset=latin-ext&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt; 
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/npm/source-code-pro@2.30.0/source-code-pro.css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/npm/roboto-mono-webfont@2.0.986/roboto-mono.min.css&quot;&gt;
 &lt;link href=&quot;https://fonts.googleapis.com/css?family=Ubuntu+Mono&quot; rel=&quot;stylesheet&quot;&gt; 
&lt;link href=&quot;https://fonts.googleapis.com/css?family=M+PLUS+1p&quot; rel=&quot;stylesheet&quot;&gt;

&lt;h2&gt;프로그래밍 폰트가 필요한 이유.&lt;br /&gt;&lt;/h2&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 750px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9979E1405C82C5A80A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9979E1405C82C5A80A&quot; width=&quot;750&quot; height=&quot;415&quot; filename=&quot;font.jpg&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; class=&quot;&quot;&gt;폰트의 용어[from &lt;a href=&quot;https://del4u.tistory.com/105&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;폰트 관련 용어&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;프로그래밍 용도의 폰트가 필요한 이유는&lt;/p&gt;&lt;ol&gt;&lt;li&gt;비슷하게 생긴 글자 구분&lt;/li&gt;&lt;li&gt;고정폭&lt;/li&gt;&lt;li&gt;기타 가독성 향상.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;나눔고딕, 굴림체과 비교해보자.(/font/로 되어 있는 것은 웹폰트가 없어서 PC에 깔려 있어야 보인다.)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;참고로 ~체나 Mono가 들어간 것은 고정폭 폰트.&lt;/p&gt;
&lt;p&gt;애초에 프로그래밍 폰트로 나온 것은 '체'나 'Mono'가 붙어있지 않지만, 굴림-굴림체 처럼 일종의 시리즈로 묶인 폰트는 '체'나 'Mono'가 붙는다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;리가추어(ligature) 폰트는 여러 글자를 하나로 묶어 표현 해준다. ( &lt;a href=&quot;http://neoweb.co/2018/01/06/ligature-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%EC%83%88%EB%A1%9C%EC%9A%B4-%EA%B8%80%EA%BC%B4%EB%93%A4/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;여기서 확인&lt;/a&gt; )&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;난 햇갈려서 잘 안쓰긴 하지만.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아래 사이트를 보면 폰트 비교와 설치가 가능하다.&lt;br /&gt;&lt;/p&gt;
 &lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/175268344655&quot; data-did=&quot;56fa38e23eb408a67f5ce97b0f2ca5bc97eb4df5&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/175268344655/programming-fonts&quot; title=&quot;&quot; style=&quot;&quot;&gt;https://black7375.tumblr.com/post/175268344655/programming-fonts&lt;/a&gt;&lt;/div&gt;  &lt;script async=&quot;&quot; src=&quot;https://assets.tumblr.com/post.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;나눔고딕.&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:Nanum Gothic;&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;폰트 자체는 좋으나 a~z와 A~Z의 크기가 달라 혼동이 올 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;소문자 L과 대문자 i의 구분이 잘 안된다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;/굴림체./&lt;/b&gt;&lt;br /&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:굴림체;&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;못생겼다.&lt;/p&gt;
&lt;p&gt;역시 소문자 L과 대문자 i의 구분이 잘 안됨.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;추천하는 폰트.&lt;/h2&gt;&lt;h3&gt;&lt;b&gt;1. Hack&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:Hack;&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bitstream Vera Sans Mono를 기반으로 만들어진 글꼴이다.&lt;/p&gt;
&lt;p&gt;파워 라인 글꼴도 지원도 하고, 아름다움과 가독성 모두 잡았다.
단점이라면 한글 지원을 안 하는 것.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;2. D2 Coding&lt;/b&gt; &lt;br /&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'D2 coding', D2coding;&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;한글을 지원하는 몇 안되는 폰트다.&lt;/p&gt;
&lt;p&gt;나눔바른고딕을 기반으로 한다.
| 표시가 2개로 나누어져 있는 것도 좋다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이 블로그는 영문은 hack, 한글은 d2 coding을 사용중이다.&lt;/p&gt;
&lt;p&gt;문제는 두개의 크기가 안맞다는 건데 1.17배를 시켜서 해결했다.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;기타 유명한 폰트(16개).&lt;/h2&gt;&lt;p&gt;설명 안 써놓은 것은 귀찮은 걸로..&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;1. /Bitstream Vera Sans Mono/ 또는 DejaVu Sans Mono&lt;/b&gt;&lt;/h3&gt;&lt;p&gt;예전부터 꾸준히 인기가 있던 폰트들이다.&lt;/p&gt;
&lt;p&gt;둘을 ‘또는’ 으로  분류한 이유는 거의 비슷하게 생겼기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;/Bitstream Vera Sans Mono/&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Bitstream Vera Sans Mono';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;DejaVu Sans Mono&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'DejaVu Sans Mono', 'DejaVu Sans';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DejaVu Sans Mono는 Bitstream Vera Sans Mono를 개선한 폰트이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C610475B42140011&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C610475B42140011&quot; width=&quot;820&quot; height=&quot;223&quot; filename=&quot;bitstream-vs-dejavu.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;차이점이라면 과하게 오른쪽으로 치우쳐져 있던 'm'자를 올바르게 정렬 시켰고, _ _로 되어 있던 것을 __로 합쳤다는 것이다.&lt;/p&gt;
&lt;p&gt;m자가 오른쪽으로 치우져져 있다는 것은 빨간색으로 표시한 부분에서 n,someString 에서 e와 붙어있다는 것에서 드러난다.&lt;/p&gt;
&lt;p&gt;_ _표시를 선호한다면 Bitstream Vera Sans Mono, __를 선호하고 m의 올바른 정렬을 원한다면 DejaVu Sans Mono를 사용하자.&lt;/p&gt;
&lt;p&gt;이 아래는 알파벳 순.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;2. Anonymous Pro&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Anonymous Pro';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;1990 년대 중반에 개발한 Macintosh 비트맵 글꼴 인 Anonymous 9의 트루 타입 버전을 기반으로 만들어졌다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;3. /Consolas/&lt;/b&gt;&lt;br /&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Consolas'';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마소가 만든 것.&lt;br /&gt;윈도우 코딩용 기본 폰트&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;4. /Courier New/&lt;/b&gt;&lt;br /&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:Courier New;&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;윈도우 고정폭 중 하나.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;5. /Dina/&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Dina', 'Dina ttf 10px';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;6. Droid Sans Mono&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Droid Sans Mono';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;작은 화면에서도 잘 보여준다고.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;7. /Fixedsys/&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Fixedsys';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;또 윈도우 글꼴. CMD의 전통적인 폰트다.&lt;/p&gt;
&lt;style type=&quot;text/css&quot;&gt;@font-face {
font-family: 'FixedsysExcelsior';
src: url('https://doir.ir/fixedsys/fsex300-webfont.eot');
src: url('https://doir.ir/fixedsys/fsex300-webfont.eot?#iefix') format('embedded-opentype'),
     url('https://doir.ir/fixedsys/fsex300-webfont.woff') format('woff'),
     url('https://doir.ir/fixedsys/fsex300-webfont.ttf') format('truetype'),
     url('https://doir.ir/fixedsys/fsex300-webfont.svg#FixedsysExcelsior301Regular') format('svg');
font-weight: normal;
font-style: normal;
-webkit-font-smoothing:aliased;
font-smooth:never;
}&lt;/style&gt;
&lt;p&gt;Fixedsys Excelsior라고 비슷한 느낌의 폰트가 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Fixedsys Excelsior&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'FixedsysExcelsior', 'Fixedsys Excelsior 3.01';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;css 적용을 했는데 안된다. 왜 그러지?&lt;/p&gt;
&lt;p&gt;이유 찾는 중.&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;8. /Lucida Console/&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Lucida Console';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h3&gt;&lt;b&gt;9. M+&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'M PLUS 1p', 'mplus-1p-regular', 'mplus-1m-regular';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;css 적용을 했는데 안된다. 왜 그러지?&lt;/p&gt;
&lt;p&gt;이유 찾는 중 2.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;10. /Menlo/&lt;/b&gt;&lt;br /&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Menlo';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;애플 코딩용 기본 폰트&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;11. /Monofur/&lt;/b&gt;&lt;br /&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Monofur';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tex용 글꼴인 Malvem을 기반으로 만든 것으로 특이하다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;12. /ProggyClean/&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'ProggyClean', 'Proggy CleanTT';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;프로그래머가 만든 폰트라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;13. IBM Plex Mono&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'IBM Plex Mono';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이름에서 알 수 있듯 IBM이 만들었다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;14. Source Code Pro&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Source Code Pro';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그래픽 계의 갑인 어도비가 만든 폰트.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;15. Roboto Mono&lt;/b&gt;&lt;br /&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Roboto Mono';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;h3&gt;&lt;b&gt;16. Ubuntu Mono&lt;/b&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code style=&quot;font-family:'Ubuntu Mono';&quot;&gt;//Abcdefghijklmnopqrstuvwxyz
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//1234567890([{&amp;lt;&amp;gt;}])
//`~!@#$%^&amp;amp;*-_=+:;”’\|
//1LlIij|¦!❙❚⏸丨亅 «‹❮&amp;lt;&amp;gt;❯»›
//-―ㅡㅡ Ø0Oo8B ;；
//„‚'`“‟‘‛ ”’&quot;❛ ❜❟ ❝ ❞⹂〝〞〟＂丶


var sum = 0;
for (var i=0; i&amp;lt;arr.length; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp; sum += arr[i];
};

var TestClass = React.createClass({
&amp;nbsp;&amp;nbsp;&amp;nbsp; render: function() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;div className=&quot;someString&quot;&amp;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; fooBar
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이름에서도 알 수 있듯 우분투에 들어갈 목적으로 만든 폰트&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이외에 &lt;a href=&quot;https://github.com/tonsky/FiraCode&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Fira Code&lt;/a&gt;, &lt;a href=&quot;http://input.fontbureau.com/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Input Mono&lt;/a&gt;, &lt;a href=&quot;https://larsenwork.com/monoid/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Monoid&lt;/a&gt;, &lt;a href=&quot;http://terminus-font.sourceforge.net/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Terminus&lt;/a&gt;, &lt;a href=&quot;https://www.typography.com/fonts/operator/styles/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Operator&lt;/a&gt;, &lt;a href=&quot;https://www.fsd.it/shop/fonts/pragmatapro/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Pra&lt;/a&gt;&lt;a href=&quot;https://www.fsd.it/shop/fonts/pragmatapro/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;g&lt;/a&gt;&lt;a href=&quot;https://www.fsd.it/shop/fonts/pragmatapro/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;mataPro&lt;/a&gt;도 아끼는 폰트다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;&quot;&gt;폰트 관련 용어는 &lt;a href=&quot;https://www.canva.com/learn/typography-terms/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;A beautifully illustrated glossary of typographic terms you should know&lt;/a&gt;에서 아주 깔끔하게 나와있다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;기타 타이포그래피에 관심이 있는 분들을 위해 몇가지 링크를 준비해두었다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;일반.&lt;br /&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/795&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;라틴알파벳의 이탤릭체와 한글의 흘림체 비교연구&lt;/a&gt;&lt;br /&gt;흘림체에 관한 연구인데, 폰트 지식의 기초를 잘 정리해놓아서 추천한다.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/1931&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;굴림체의 조형적 특징과 선호도 분석&lt;/a&gt;&lt;br /&gt;악명이 자자한 굴림체를 왜 쓰면 안되는지에 대한 논문까지 나왔다. ㅋㅋㅋ&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;친환경.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;각각 잉크의 번짐, 조형을 이용해 친환경적으로 만드는 방법에 대한 연구.&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/826&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;잉크를 ‘아끼는 글자’&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/817&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;인쇄물에서의 친환경 타이포그라피&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;가독성.&lt;/h3&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/1911&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;본문용 한글 서체의 구조와 인지 요인 상관성 연구&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/1913&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;글자 너비 변화와 가독성의 상관관계&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/3848&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;반응형 타이포그래피의 기본 원칙&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;웹.&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;웹 프로그래머가 읽으면 좋다.&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/4615&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;KS 코드 완성형 한글의 추가 글자 제안&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://black7375.tistory.com/56&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Readable Font&lt;/a&gt;란 부가기능에 폰트를 탑제할 때 이용했다.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/4724&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;multilingual.js:다국어 웹 타이포그래피를 위한 섞어쓰기 라이브러리&lt;/a&gt;&lt;br /&gt;이 블로그의 &amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;내부의 영문(Hack)/한글(D2 Coding) 폭을 동일하게 맞추기 위해 사용했다.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;다국어&lt;br /&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/4586&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;한글과 로마자의 섞어 짜기를 위한 로마자 형태 연구&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://koreantypography.org/blog/archives/4596&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;다국어 타이포그래피를 위한 한글-로마자 하이브리드 글자체 디자인&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style=&quot;background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 739px; top: 20097px; opacity: 0.2;&quot; id=&quot;s3gt_translate_tooltip_mini&quot; class=&quot;s3gt_translate_tooltip_mini_box&quot; is_mini=&quot;true&quot;&gt;&lt;div id=&quot;s3gt_translate_tooltip_mini_logo&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Translate selected text&quot;&gt;&lt;/div&gt;&lt;div id=&quot;s3gt_translate_tooltip_mini_sound&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Play&quot; title_play=&quot;Play&quot; title_stop=&quot;Stop&quot;&gt;&lt;/div&gt;&lt;div id=&quot;s3gt_translate_tooltip_mini_copy&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Copy text to Clipboard&quot;&gt;&lt;/div&gt;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;moz-extension://6b45f09d-4bb0-4041-bd5f-d729b9f06da3/skin/s3gt_tooltip_mini.css&quot;&gt;&lt;style type=&quot;text/css&quot; media=&quot;print&quot;&gt;#s3gt_translate_tooltip_mini { display: none !important; }&lt;/style&gt;&lt;/div&gt;&lt;div style=&quot;background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 739px; top: 20097px; opacity: 0.2;&quot; id=&quot;s3gt_translate_tooltip_mini&quot; class=&quot;s3gt_translate_tooltip_mini_box&quot; is_mini=&quot;true&quot;&gt;&lt;div id=&quot;s3gt_translate_tooltip_mini_logo&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;선택한 텍스트 번역&quot;&gt;&lt;/div&gt;&lt;div id=&quot;s3gt_translate_tooltip_mini_sound&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;재생&quot; title_play=&quot;재생&quot; title_stop=&quot;중지&quot;&gt;&lt;/div&gt;&lt;div id=&quot;s3gt_translate_tooltip_mini_copy&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;클립보드에 텍스트 복사&quot;&gt;&lt;/div&gt;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;moz-extension://9147a1a7-9d9b-44b5-9f8b-518b03fe66ce/skin/s3gt_tooltip_mini.css&quot;&gt;&lt;style type=&quot;text/css&quot; media=&quot;print&quot;&gt;#s3gt_translate_tooltip_mini { display: none !importan&lt;br /&gt;&lt;/style&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>프로그래밍/기타</category>
      <category>font</category>
      <category>프로그래밍</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/41</guid>
      <comments>https://black7375.tistory.com/41#entry41comment</comments>
      <pubDate>Sun, 8 Jul 2018 23:29:28 +0900</pubDate>
    </item>
    <item>
      <title>내 맘대로 프로그램 설계 5. - 리스트와 재귀.</title>
      <link>https://black7375.tistory.com/38</link>
      <description>&lt;!--MathJax(LaTeX) --&gt;
&lt;script type=&quot;text/javascript&quot; async=&quot;&quot; src=&quot;https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML&quot;&gt;
&lt;/script&gt;
&lt;h4&gt;내 맘대로 하는 프로그램 설계 시리즈.&lt;/h4&gt;&lt;p&gt;&lt;b&gt;Chapter1 - 간단한 데이터 처리(4섹션)&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/31&quot; target=&quot;_blank&quot;&gt;2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/32&quot; target=&quot;_blank&quot;&gt;2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 2. - 데이터 타입.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/34&quot; target=&quot;_blank&quot;&gt;2018/01/16 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 3. - 함수와 변수.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/36&quot; target=&quot;_blank&quot;&gt;2018/05/29 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 4. - 고정 크기 데이터.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/6&quot; target=&quot;_blank&quot;&gt;2017/06/30 - [프로그래밍/설계] - 프로그래밍과 추상화에 대하여.[부록]&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Chapter2 - 임의의 데이터 처리&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/38&quot; target=&quot;_blank&quot;&gt;2018/06/10 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 5. - 리스트와 재귀(현재).&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1. 시작하기.&lt;/h2&gt;&lt;p&gt;시작하기는 지난 시간을 복습하거나, 이번 섹션 내용과 이어지는 것을 체크해주는 역할을 하고 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;지금 1~5를 전반적으로 다듬는 중.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;2. 리스트.&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;구조체를 사용하면 갯수가 정해져 있는 복합적인 데이터들을 정리하는데 유용하다.&lt;/p&gt;&lt;p&gt;ex) 색, 음악, 좌표 값&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그러나 길다란 메모 목록처럼 정해진 갯수의 데이터가 아니라면?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;바로 '&lt;span style=&quot;background-color: rgb(255, 228, 0);&quot;&gt;리스트&lt;/span&gt;' 라는게 적격이다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.1 리스트 생성 및 기초 사용법.&lt;/h3&gt;&lt;p&gt;리스트는 비어있는 것부터 시작합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.1 - 1&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;'()&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;응? 어디서 보던 거죠?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;바로 &lt;a href=&quot;http://black7375.tistory.com/32&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Section 2 - 데이터 타입&lt;/a&gt; 의 마지막에 등장했던 널 값(Null)입니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;데이터가 없다는 것을 뜻하는 널 값이 곧 비어있는 리스트였다는 뜻입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;기억이 맞나 다시 한번 확인해보죠.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.1 -2&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;null&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: '()&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;기존에 배웠던 숫자, 불린처럼 '()도 리터럴 상수입니다.(이하 '()로 표시)&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이젠 리스트에 데이터를 만드는 방법을 알아볼 차례입니다.&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;b&gt;
&lt;/b&gt;&lt;p&gt;&lt;b&gt;- 리스트 생성법&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(cons 인자 리스트-인자)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;첫번째에 인자 값으로 우리가 원하는 데이터를 넣고, 두번째에는 리스트로 된 인자 값을 넣으면 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;실제로 데이터를 넣어볼 차례인데, 작성하다 배가 고프니 음식 데이터를 넣어보겠습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992CAB355B343DB30C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992CAB355B343DB30C&quot; width=&quot;820&quot; height=&quot;107&quot; filename=&quot;cons1.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99AF36335B3443E913&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99AF36335B3443E913&quot; width=&quot;820&quot; height=&quot;446&quot; filename=&quot;cons2.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.2&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(cons 'pizza '()                       )
(cons 'ramen
      (cons 'chicken (cons 'pizza '())))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;첫번째는 'pizza라는 데이터만 넣은 것이고, 두번째는 'ramen을 넣고 리스트를 생성 시키는 식으로 'chicken, 'pizza를 넣은 것이죠.&lt;/p&gt;&lt;p&gt;구조체와 상당히 유사합니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그럼 위의 것은 food-list1, 아랫것은 food-list2로 하고, 원하는 음식의 값이 들어있는지 판단하는 프로그램을 만들어보겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;리스트 안에 있는 값을 선택하는 방법을 알아봅시다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;- 리스트 선택법&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(car 인자 리스트-인자)
(cdr 인자 리스트-인자)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 인자, 리스트-인자&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;cons로 만들어진 리스트에서 인자를 선택하려면 car를 리스트-인자 부분을 선택하려면 cdr을 쓰면 됩니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;잠시 확인해봅시다.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.3&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;----------constant
(define food-list1 (cons 'pizza '()                ))
(define food-list2 (cons 'ramen
                         (cons 'chicken food-list1)))

;----------list test
(check-expect (car food-list1) 'pizza)
(check-expect (cdr food-list1) '()   )

(check-expect (car food-list2)
              'ramen                    )
(check-expect (cdr food-list2)
              (cons 'chicken food-list1))
(check-expect (car (cdr food-list2))
              'chicken             )
(check-expect (cdr (cdr food-list2))
              food-list1           )&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 모든 6개 테스트 통과함!&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;리스트 목록은 나중에도 리스트를 쓰기 위해 상수로 만들어 두었습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;리스트에서 값 추출법까지 알았으니 두 리스트에서 음식이 존재하는지 본격적으로 찾아보도록 하죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;+.&lt;/h4&gt;&lt;p&gt;HtDP에서는 null, car, cdr이 empty, first, rest라고 표현되어 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이는 BSL의 특성으로, 학생들에게 더 직관적으로 가르치기 위함입니다.&lt;/p&gt;&lt;p&gt;원래 Racket에서는 null, car, cdr을 사용합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
저희는 범용성이 있도록 Racket의 방식을 사용합니다.
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.2 리스트와 재귀.&lt;br /&gt;&lt;/h3&gt;
&lt;p&gt;문제의 조건을 정리하면 다음과 같습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$$search-food = \begin{cases}&lt;br /&gt;\emptyset \ni food-list, &amp;amp; false \\ \\&lt;br /&gt;(cons \ni food-list) \land (\exists \; a-food \in food-list), &amp;amp; true \\&lt;br /&gt;(cons \not\ni food-list) \lor (\forall \; a-food \notin food-list), &amp;amp; false&lt;br /&gt;\end{cases}$$&lt;/p&gt;&lt;p&gt;1. food-list가 null에 속할 경우 false다.&lt;/p&gt;&lt;p&gt;2. food-list가 cons에 속하고, food-list에 a-food가 존재할 경우 true다.&lt;/p&gt;&lt;p&gt;3. food-list가 cons에 속하지 않거나. food-list에 임의의 a-food가 없을 경우 false다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.4 -계약, 목적, 헤더&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;search-food : food food-list -&amp;gt; boolean
;;Contain food in food-list?
(define (search-food  a-food food-list))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여러분도 익숙해졌을 계약, 목적, 헤더를 기술 해놓았습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;천천히 함수 템플릿을 만들어 갑시다.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (search-food  a-food food-list)
  (cond
    [(null? food-list) #false]
    [(cons? food-list) ......]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;가장 먼저 해야할 것은 food-list가 빈 리스트인지, 리스트는 맞는지 확인해야 합니다.&lt;/p&gt;&lt;p&gt;a-food를 찾는 건 나중의 일이죠.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;문제 조건대로(수식 정리 참고.)&lt;br /&gt;리스트인 food-list에 있는지 확인해야 합니다.&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (search-food  a-food food-list)
  (cond
    [(null? food-list) #false]
    [(cons? food-list)
     ... (equal? a-food (car food-list)) ... (cdr food-list) ... ]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;a-food가 food-list의 인자 값이 같은지 체크하고, 아니라면 리스트-인자 값과 비교해보아야 합니다.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (search-food  a-food food-list)
  (cond
    [(null? food-list) #false]
    [(cons? food-list)
     (cond
       [(equal? a-food (car food-list)) #true]
       [ else   ...    (cdr food-list)  .....])]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;food-list에서 리스트-인자를 추출해내고, 추출된 food-list로부터 다시 a-food가 있는지 찾아야 합니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;food-list에서 a-food가 있는 것을 찾는 것이 어떤 것이었죠? &lt;br /&gt;&lt;/p&gt;&lt;p&gt;지금 우리가 작성 중인 함수인 'search-food' 입니다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.4 - 최종&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (search-food  a-food food-list)
  (cond
    [(null? food-list) #false]
    [(cons? food-list)
     (cond
       [(equal? a-food (car food-list))      #true]
       [ else (search-food a-food (cdr food-list))])]))

(check-expect (search-food 'pizza food-list1  ) #true )
(check-expect (search-food 'chicken food-list1) #false)
(check-expect (search-food 'cake food-list1   ) #false)

(check-expect (search-food 'pizza food-list2  ) #true )
(check-expect (search-food 'chicken food-list2) #true )
(check-expect (search-food 'cake food-list2   ) #false)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 모든 6개 테스트 통과함!&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;search-food란 함수 내용을 보면 search-food가 자신(search-food)를 참고하고 있죠.&lt;/p&gt;&lt;p&gt;자기 자신을 참조하는 함수를 재귀(再歸, recursion)함수라고 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;재귀함수는 직관적이기 때문에 프로그램 작성을 편하게 만들어 주며, 알고리즘 문제 해결에서 기초적인 역할을 해줍니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;(처음 배우는 거라 아직 익숙치 않아 어렵다고 느낄 수도 있지만 재귀를 사용하면 쉬워지는 문제들이 꽤 있습니다.)&lt;/p&gt;&lt;p&gt;이해가 잘 되지 않는다면 '한 단계씩 실행'기능을 꼭 사용해보세요.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;재귀함수를 만들 때 조심해야 할 것은 '&lt;span style=&quot;background-color: rgb(255, 228, 0);&quot;&gt;탈출조건&lt;/span&gt;'을 1개 이상 작성해야 한다는 것입니다.&lt;/p&gt;&lt;p&gt;search-food에서는 null? food-list나 equal? a-food (car food-list)부분이 탈출조건 이었죠.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;계속 재귀만 한다면 프로그램이 끝나지 않고, 오류가 생기기는 것은 당연한 일.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;한번 프로그램을 터트려보겠습니다.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (recursion-error args)
  (recursion-error (cons args args)))

(recursion-error food-list2)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;보다시피 재귀가 될 때마다 2배씩 늘려나가는 코드입니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;실행을 시키면&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 460px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/993361475B31794D27&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F993361475B31794D27&quot; width=&quot;460&quot; height=&quot;234&quot; filename=&quot;memory.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;라 팝업 창이 뜬 뒤 Interactions disabled가 출력됩니다.[중지 되었다는 뜻]&lt;br /&gt;&lt;/p&gt;&lt;p&gt;계속 food-list2를 늘려가다 보면 프로그램에 할당된 메모리(램, RAM)이 메모리가 다 차기 때문입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;괴델의 불완전성 원리에 따르면 무모순적인 공리계는 참인 일부 명제를 증명할 수 없으며,&lt;br /&gt;스스로의 모순성을 증명할 수 없다고들 하죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;recursion-error 함수도 똑같습니다.&lt;/p&gt;&lt;p&gt;재귀가 될 때마다 입력 값을 2배로 늘리는 논리 자체는 문제가 없지만(무모순적임, 흔히 말하는 문법적인 에러가 없음)&lt;/p&gt;&lt;p&gt;그 체계 밖(Dr.Racket)입장에서는 메모리만 계속 먹을 수 밖에 없는 불완전하고 모순적인 존재입니다.&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;p&gt;메모리(RAM, Random Access Memory).&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;프로그램이 실행되는 동안 필요한 정보를 저장하는 곳 입니다.&lt;/p&gt;&lt;p&gt;RAM이란 저장된 데이터를 순차적이 아닌 임의의 순서(랜덤)에 따라 액세스할 수 있는 데이터 저장소입니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;재귀를 이용할만한 문제를 몇가지 풀어보도록 합시다.&lt;/p&gt;
&lt;h4&gt;+.&lt;/h4&gt;&lt;p&gt;재귀를 배우기 전까지 리스트와 구조체가 무언가 비슷하다 느끼지 않았나요?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;실제로 구조체를 사용해도 리스트와 비슷하게 구현하는게 가능합니다.&lt;/p&gt;&lt;p&gt;반대도 똑같고요.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;여기선 구조체를 리스트처럼 사용하는 함수들을 만들어보겠습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.5 -1&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;----------list-like structure
;-----constant
(define-struct st-list (value structs))

;-----function
;;st-cons: value, struct -&amp;gt; struct 
;;Like cons.
(define (st-cons a-value a-struct)
   (make-st-list a-value a-struct))

;;st-car: struct -&amp;gt; value
;;Like car
(define (st-car a-struct)
  (st-list-value a-struct))
;;st-cdr: struct -&amp;gt; struct
;;Like cdr
(define (st-cdr a-struct)
  (st-list-structs a-struct))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(다만 struct는 이미 정의되어 있어 쓸 수 없으므로 structs로 사용했음.)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;리스트 대신 st-list, cons는 st-cons, car은 st-car, cdr은 st-cdr로 대응되게 만들었습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;작동이 잘 되나 확인하기 위해&lt;br /&gt;&lt;/p&gt;&lt;p&gt;food-list2 내용을 st-food-list라 정의하고 st-search-food를 만들어보겠습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.5 - 2&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;----------food
(define st-food-list (st-cons 'ramen
                             (st-cons 'chicken (st-cons 'pizza null))))

;;st-search-food: food st-food-list -&amp;gt; boolean
;;Contain food in st-food-list?
(define (st-search-food a-food food-struct)
  (cond
    [(null?    food-struct) #false]
    [(st-list? food-struct)
     (cond
       [(equal? a-food (st-car food-struct))           #true]
       [ else   (st-search-food a-food (st-cdr food-struct))])]))

(check-expect (st-search-food 'pizza st-food-list  ) #true )
(check-expect (st-search-food 'chicken st-food-list) #true )
(check-expect (st-search-food 'cake st-food-list   ) #false)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 모든 3개 테스트 통과함.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;정상적으로 작동이 되는 것을 볼 수 있다.&lt;/p&gt;&lt;p&gt;혹시 다른 언어에서 탐나는 기능이 있다면 이렇게 우회적으로 구현하면 된다. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.3 리스트와 재귀의 활용.&lt;br /&gt;&lt;/h3&gt;&lt;h4&gt;2.3.1 list 함수.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;문제를 풀어보기 전에, cons를 여러번 반복해야만 리스트를 만들 수 있는 것이 걸리지 않았나요?&lt;/p&gt;&lt;p&gt;Chapter1 부록에서도 명시되어 있듯이 프로그램을 만들 때는 중복을 줄이는 것이 좋습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;다행히 list라는 함수가 알아서 리스트를 만들어주는 역할을 합니다.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(list 인자1, 인자2, 인자3 ...)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;처럼 쓰면 된다는 의미입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;한번 확인을 해봅시다.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.6&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(list 1 2 3 'symbol &quot;string&quot;)

(define food-list3 (list 'ramen 'chicken 'pizza))

(check-expect (car  food-list3          )
                                  'ramen)
(check-expect (cdr  food-list3          )
              (cons 'chicken food-list1))
(check-expect (car  (cdr food-list3)    )
                                'chicken)
(check-expect (cdr  (cdr food-list3)    )
                              food-list1)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: (cons 1 (cons 2 (cons 3 (cons 'symbol (cons &quot;string&quot; '()))))), 모든 4개 테스트 통과함!&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;list란 함수에 대해 대충 파악이 되었죠?&lt;/p&gt;&lt;p&gt;모두 리스트를 만들어주고, 가장 안에 있는 리스트는 '() 즉 null로 자동적으로 생성시켜줍니다. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.3.2 활용.&lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;리스트와 재귀를 사용한 문제를 풀어봅시다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;- 구조체와 함께 새로운 list 생성.&lt;/b&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;작성자가 야밤에 배가 고픔에도 계속 작성하다 망상을 하기 시작했다.&lt;/p&gt;&lt;p&gt;야식 리스트를 생각하기 시작한 것.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;ramen: 2000 won&lt;/p&gt;&lt;p&gt;chicken: 15000 won&lt;/p&gt;&lt;p&gt;pizza: 12000 won&lt;/p&gt;&lt;p&gt;cake: 5000 won&lt;/p&gt;&lt;p&gt;pork-hock: 17000 won&lt;/p&gt;&lt;p&gt; jajangmyeon: 6000 won&lt;br /&gt;&lt;/p&gt;&lt;p&gt;jjamppong: 7000 won&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 이 음식들을 다 먹고 계산할 것을 생각하니 골이 땅기기 시작했다.&lt;/p&gt;&lt;p&gt;구조체로 음식 이름과 가격을 표시한 음식 리스트를 만들고 계산 값을 구하시오.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;음식 구조체와 리스트를 만들어봅시다.&lt;/p&gt;&lt;p&gt;물론 (define ramen 2000)과 같이 사용하는게 더 알맞지만, 구조체와 함께 사용해보기 위해서.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5. - 1&lt;br /&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define-struct food-info (name price))

;;add-food: food-name, food-price -&amp;gt; food-info
;;Create food-info struct.
(define (add-food a-name a-price)
  (make-food-info a-name a-price))

(define food-list4 (list
                    (add-food 'ramen       2000 )
                    (add-food 'chicken     15000)
                    (add-food 'pizza       12000)
                    (add-food 'cake        5000 )
                    (add-food 'pork-hock   17000)
                    (add-food 'jajangmyeon 6000 )
                    (add-food 'jamppong    7000 )))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;음식 이름과 가격이 들어가는 food-info 구조체와 자동으로 구조체를 생성해주는 add-food 함수를 만들었습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 food-list4를 방금 전에 배운 list 함수로 만들었습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;food-list4 내용&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(cons
 (make-food-info 'ramen 2000)
 (cons
  (make-food-info 'chicken 15000)
  (cons
   (make-food-info 'pizza 12000)
   (cons
    (make-food-info 'cake 5000)
    (cons
     (make-food-info 'pork-hock 17000)
     (cons (make-food-info 'jajangmyeon 6000) (cons (make-food-info 'jamppong 7000) '())))))))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;우리가 원하는 대로 리스트가 생성되었음을 알 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.7 -2&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;calulate-price: food-list -&amp;gt; number
;;Sum foods' price.
(define (calculate-price a-food-list)
  (cond
    [(null? a-food-list)                          0]
    [ else  (+ (food-info-price (car a-food-list))
               (calculate-price (cdr a-food-list)))]))

(check-expect (calculate-price food-list4) 64000)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 테스트 통과함!&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;우선 재귀에서 가장 중요하다고 했던 제한 조건!!&lt;/p&gt;&lt;p&gt;리스트가 비었는지 확인하고, 비었다면 0을 반환합니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;- 간단한 정렬&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;food-list4를 내림차순(비싼 것부터 싼 것 순)으로 정렬해보자.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C5D0405B34614D35&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C5D0405B34614D35&quot; width=&quot;820&quot; height=&quot;106&quot; filename=&quot;cons3.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;처음 리스트를 배울 때는 구조체처럼 포함시키는 개념으로 생각해왔는데, car은 값의 추출 cdr은 연결된 리스트로 이동한다고 생각을 바꾸면 좀 더 쉽습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 BSL이 아닌 BSL(List 축약)을 사용하겠습니다.&lt;/p&gt;&lt;p&gt;cons가 아닌 list를 기준으로 보여주므로 좀 더 간결한 환경에서 사용할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;food-list4 내용 - BSL(List 축약)&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(list
 (make-food-info 'ramen 2000)
 (make-food-info 'chicken 15000)
 (make-food-info 'pizza 12000)
 (make-food-info 'cake 5000)
 (make-food-info 'pork-hock 17000)
 (make-food-info 'jajangmyeon 6000)
 (make-food-info 'jamppong 7000))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그럼 sort-price 함수를 만들어봅시다.&lt;/p&gt;&lt;p&gt;$$sort-price = \begin{cases}&lt;br /&gt;\emptyset, &amp;amp; \emptyset \\&lt;br /&gt;else, &amp;amp; check \; food-info-price \; \&amp;amp;\&amp;amp;&amp;nbsp; \;sort-price \; next \; food-list&lt;br /&gt;\end{cases}$$&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;sort-price 계약, 목적, 헤더&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code clsass=&quot;scheme&quot;&gt;;;sort-price: unsorted food-list -&amp;gt; sorted food-list
;;sort food-list
(define (sort-price a-food-list) ...)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이를 수식에 있는 조건식 대로 사용하면&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;sort-price 함수 템플릿&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (sort-price a-food-list)
  (cond
    [(null? a-food-list) null]
    [ else ... (car a-food-list) (sort-price (cdr a-food-list)) ...]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;함수 템플릿이 만들어집니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;함수 템플릿에서 else 부분을 살펴보면&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;car a-food-list는 현재 food-list에서 food-info를 추출&lt;br /&gt;&lt;/li&gt;&lt;li&gt;(sort-price (cdr a-food-list))에서는 다음 food-list에서 정렬된(sort-price 목적) food-list를 출력&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;이란 것을 알 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이 때 필요한 동작은 추출된 food-info를 sort-price가 된 리스트의 적절한 위치에 삽입하는 것이다.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.8 - 1&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (sort-price a-food-list)
  (cond
    [(null? a-food-list) null]
    [ else (insert (car a-food-list) (sort-price (cdr a-food-list)))]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;insert 함수도 똑같이 함수 템플릿을 만들어보면&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;insert 함수 템플릿&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;insert: number food-list -&amp;gt; new food-list
;;make new descending order list
(define (insert a-food-info a-food-list)
  (cond
    [(null? a-food-list) ...]
    [ else ... (car a-food-list) ... (insert a-food (cdr a-food-list)) ...]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$$insert = \begin{cases}&lt;br /&gt;\emptyset \ni food-list, &amp;amp; \left\{ food-info, \emptyset \ \right\} \\ \\&lt;br /&gt;food-info &amp;gt;= next-food-info, &amp;amp; \left\{ food-info, food-list \right\} \\&lt;br /&gt;food-info &amp;lt; next-food-info, &amp;amp; \left\{ next-food-info, insert(food-info, next-food-list) \right\}&lt;br /&gt;\end{cases} $$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;insert 함수는 리스트가 비었을 경우 food-info와 빈 리스트로 만들고,&lt;br /&gt;food-info의 가격이 다음 food-info 가격보다 같거나 높다면 그대로 생성하며,&lt;br /&gt;&lt;/p&gt;&lt;p&gt;food-info의 가격이 다음 food-info 가격보다 적다면 가격이 같거나 클 때까지 반복한다.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.8 - 2&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;insert: number food-list -&amp;gt; new food-list
;;make new descending order list
(define (insert a-food-info a-food-list)
  (cond
    [(null? a-food-list) (cons a-food-info null)]
    [ else  (cond
              [(&amp;gt;=   (food-info-price a-food-info) (food-info-price    (car a-food-list)))
               (cons  a-food-info     a-food-list)                                        ]
              [(&amp;lt;    (food-info-price a-food-info) (food-info-price    (car a-food-list)))
               (cons (car             a-food-list) (insert a-food-info (cdr a-food-list)))])]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과를 확인해보면 잘 작동한다는 것을 알 수 있습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.8 - 3&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(check-expect (insert (car food-list4) (cdr food-list4)) (list
                                                           (add-food 'chicken     15000)
                                                           (add-food 'pizza       12000)
                                                           (add-food 'cake        5000 )
                                                           (add-food 'pork-hock   17000)
                                                           (add-food 'jajangmyeon 6000 )
                                                           (add-food 'jamppong    7000 )
                                                           (add-food 'ramen       2000 )))

(check-expect (sort-price food-list4) (list
                                        (add-food 'pork-hock   17000)
                                        (add-food 'chicken     15000)
                                        (add-food 'pizza       12000)
                                        (add-food 'jamppong    7000 )
                                        (add-food 'jajangmyeon 6000 )
                                        (add-food 'cake        5000 )
                                        (add-food 'ramen       2000 )))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 모든 2개 테스트 통과함!&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아직 완전히 정리가 안되죠?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;sort-price와 insert는 아래와 같이 나타낼 수 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(sort-price ramen chicken pizza cake pork-hook jajangmyeon jamppong)
(sort-price chicken pizza cake pork-hook jajangmyeon jamppong)
(sort-price pizza cake pork-hook jajangmyeon jamppong)
(sort-price cake pork-hook jajangmyeon jamppong)
(sort-price pork-hook jajangmyeon jamppong)
(sort-price jajangmyeon jamppong)
(sort-price jamppong)
(sort-price '())
'(jamppong)
'(jamppong jajangmyeon)
'(pork-hock jamppong jajangmyeon)
'(pork-hock jamppong jajangmyeon cake)
'(pork-hock pizza jamppong jajangmyeon cake)
'(pork-hock chicken pizza jamppong jajangmyeon cake)
'(pork-hock chicken pizza jamppong jajangmyeon cake ramen)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;지금 바로 이해가 안되는 분들은 정렬에 대한 것은 뒤에서 더 자세히 다룰테니 리스트와 재귀에 대한 감만 잡고 가면 좋겠습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;마지막 문제로 재귀에만 온전히 집중할 수 있는 문제를 풀어봅시다.&lt;/p&gt;&lt;p&gt;&lt;b&gt;- 팩토리얼(!)&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;팩토리얼은 다음과 같이 나타낼 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;$$factorial = \begin{cases}&lt;br /&gt;n! = \prod_{k=1}^{n} k = n*(n-1)*(n-2)*…*3*2*1 \\&lt;br /&gt;0!=1&lt;br /&gt;\end{cases} $$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;1에서 n까지의 모든 자연수의 곱이며, 0일 때는 1인수.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.9&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;factorial: N -&amp;gt; N
;;n*(n-1)*(n-2)*...*3*2*1
(define (factorial n)
  (if (&amp;lt; n 2)
      1
      (* n (factorial (- n 1)))))

(check-expect (factorial 5) 120)
(check-expect (factorial 2) 2  )
(check-expect (factorial 0) 1  )&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 모든 3개 테스트 통과함!&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.4 리스트와 재귀 좀 더 알아보기.&lt;br /&gt;&lt;/h3&gt;&lt;h4&gt;2.4.1 리스트 축약.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;BSL(List 축약), Racket, Lisp에서는 list 함수를 더 생략하여 (list 1 2 ..) 대신 '(1 2 ..)처럼 표시 가능합니다.&lt;/p&gt;&lt;p&gt;'(1 2 ..)는 (quote (1 2 ..))방식과 같습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 '()가 왜 빈 리스트인지 명확하게 알 수 있죠?&lt;/p&gt;&lt;p&gt;다만 조심해야 할 것은 list와 '의 방식이 완전히 같지 않다는 것 입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 5.10&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;'(1 2 variable 'symbol &quot;string&quot; #true)
'(1 2 (function &quot;string&quot; #true) 3)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: (list 1 2 'variable (list 'quote 'symbol) &quot;string&quot; #true),&lt;br /&gt;(list 1 2 (list 'function &quot;string&quot; #true) 3)&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일반적인 데이터 유형이 아닌 [함수 or 변수]나 똑같이 '를 붙여서 나타내는 심볼은 예측과 다르게 나오는 것을 볼 수 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;variable에는 '가 자동으로 붙여져서 'variable이 되며, 'symbol은 (quote (symbol))로 해석이 됩니다.&lt;/p&gt;&lt;p&gt;마지막으로 괄호 사이의 fuction &quot;string&quot; #true도 ()에 '이 붙은 것처럼 처리가 되어 하나의 리스트로 해석합니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;+.&lt;/h4&gt;&lt;p&gt;BSL이 아닌 Racket에선 eval이란 함수를 사용하면 list를 풀 수 있습니다.
&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아래의 코드를 Racket에서 실행해보면&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lisp&quot;&gt;(equal? (list 1 2 3) '(1 2 3))
(eval #'(+ 1 2 (* 2 3)))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: #t, 9&lt;/p&gt;&lt;p&gt;* #t는 #true와 같습니다. #표시는 '후에 나오는 +가 연산자 라는 것을 명시해줍니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;가 나오게 됩니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;리스트인 '(+ 1 2 (* 2 3))가 eval 연산 후 (+ 1 2 (* 2 3))이 되어 9로 계산됩니다.&lt;/p&gt;&lt;p&gt;quote 함수나 '역할의 정반대라는 것을 알 수 있죠.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이 때문에 데이터가 코드가 되기도 하고, 코드가 데이터가 되기도 합니다.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define pizza 10)
pizza
'pizza
(eval #'pizza)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 10, 'pizza, 10&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;종합해보자면 ' 표시가 붙으면 데이터가 되는데 eval을 붙이면 데이터를 코드로 바꿀 수 있다는 뜻입니다.&lt;/p&gt;&lt;p&gt;여기에서 Racket 같은 Lisp 계열에서는 함수나 데이터가 모두 '리스트(list)'라는 결과를 얻어낼 수 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Lisp에서 가장 흥미로운 점이며 무궁무진한 흑마법을 만들어 낼 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.4.2 재귀와 꼬리 재귀.&lt;/h4&gt;&lt;p&gt;우리가 지금까지 배웠던 재귀는 함수가 종료 조건을 만날 때까지 재귀를 하다 종료 조건 후에는 돌아옵니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예컨대 재귀의 깊이(Depth)는 1-2-3-4-5(종료 조건)-4-3-2-1로 표현 할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;재귀의 동작처럼 나중에 들어간 것이 먼저 나오는 구조(LIFO, Last In First Out)를 스택(Stack) 구조라고 합니다.&lt;/p&gt;&lt;p&gt;메모리에서도 재귀가 깊어질 때마다 생기는 인자, 반환 값들, 반환 시 돌아갈 위치값 들을 메모리의 스택 영역에 쌓아놓습니다.&lt;/p&gt;&lt;p&gt;그런데 스택의 크기가 너무 커지면 다른 프로그램에 방해를 하기 때문에 보통 크기를 제한하게 되죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;스택의 제한된 크기를 초과하는 경우를 오버플로우(Overflow)라는 에러가 생깁니다.&lt;/p&gt;&lt;p&gt;정해진 크기를 초과해서 생긴 오류라고 생각하면 됩니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 재귀 시 스택 오버플로우를 막기 위해 생긴 기법이 바로 꼬리 재귀(Tail Recursion)입니다.&lt;/p&gt;&lt;p&gt;꼬리 재귀의 핵심 개념은 반환 시 추가 연산이 필요하지 않게 재귀의 꼬리(최종 리턴이 발생하는 곳)까지 필요한 값들을 전달하는 것 입니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위에서 나왔던 팩토리얼을 꼬리 재귀로 구현해보겠습니다.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;factorial-tail: N accumulator -&amp;gt; N
;;n*(n-1)*(n-2)*...*3*2*1
(define (factorial-tail n acc)
  (if (&amp;lt; n 2)
      acc
      (factorial-tail (- n 1) (* acc n))))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;보다시피 다음 연산에 필요한 모든 값들을 인수 형태로 전해주고 있습니다.&lt;br /&gt; &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일반적인 팩토리얼 함수와 5!의 연산 과정을 비교해보면&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;Factorial
;; Output:
;; &amp;gt;(factorial 5)
;; &amp;gt; (factorial 4)
;; &amp;gt; &amp;gt;(factorial 3)
;; &amp;gt; &amp;gt; (factorial 2)
;; &amp;gt; &amp;gt; &amp;gt;(factorial 1)
;; &amp;lt; &amp;lt; &amp;lt; 1
;; &amp;lt; &amp;lt; &amp;lt;1
;; &amp;lt; &amp;lt; 2
;; &amp;lt; &amp;lt;6
;; &amp;lt; 24
;; &amp;lt;120
;; 120

;;Factorial-tail
;; Output:
;; &amp;gt;(factorial-tail 5 1)
;; &amp;gt;(factorial-tail 4 5)
;; &amp;gt;(factorial-tail 3 20)
;; &amp;gt;(factorial-tail 2 60)
;; &amp;gt;(factorial-tail 1 120)
;; &amp;lt;120
;; 120&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;조금 더 이해가 잘 됩니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;꼬리 재귀에서는 불편하게 (factoial-tail 5 1)이라고 값을 넣는데,&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Racket 자체에서는&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (factorial-tail n (acc 1))
...)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;처럼 사용하면 acc의 기본 값을 1로 정할 수 있습니다.&lt;/p&gt;&lt;p&gt;HtDP의 언어들은 기능이 제한되서 안되지만..&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그런데 꼬리 재귀도 어쨌든 재귀라 다시 돌아가는 과정이 필요한데 어떻게 스택 오버플로우를 피하는 것이 가능한가.&lt;/p&gt;&lt;p&gt;답은 컴파일러 최적화에 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;컴파일러는 코드를 기계어로 번역 해주는 역할을 합니다.&lt;/p&gt;&lt;p&gt;이 과정에서 최적화 역시 수행해주고요.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;꼬리 재귀는 결과도 전달을 하기 때문에 앞의 내용은 더 이상 필요하지 않아 반복문으로 바꾸어 줍니다.&lt;/p&gt;&lt;p&gt;Racket을 기준으로&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (factorial-loop n (acc 1))
  (begin (for ([n (in-range 2 (+ n 1))])
    (set! acc (* acc n)))
         acc))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;과 같이 만들 수 있습니다.[정확히 맞는 건 아니만 비스무레한 형태로 바뀝니다]&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;코드를 설명하기 전에 못보던 함수들이 좀 보이죠?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;begin은 안에 든 함수들을 순서대로 실행하고 마지막 값을 반환하는 함수입니다.&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(begin (+ 1 2)
         (+ 5 7)
         (* 4 8))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 32&lt;br /&gt;&lt;/p&gt;&lt;p&gt;보다시피 마지막으로 실행하는 함수인 (* 4 8)의 값인 32만을 반환합니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;for은 순서대로 대입을 해주는 함수입니다.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(for ([x '(1 2 3)])
    (print x))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 123&lt;br /&gt;&lt;/p&gt;&lt;p&gt;x에 1, 2, 3을 순서대로 대입해줍니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;마찬가지로 in-range는 0, 1, 2, 3같은 것을 자동적으로 생성 시켜주는 역할을 합니다.&lt;/p&gt;&lt;p&gt;(0 부터 시작)&lt;br /&gt;&lt;/p&gt;&lt;p&gt;set!은 예전에 변수의 값을 바꾸는 함수라 했었고요.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 정리해보면 factorial-loop는&lt;/p&gt;&lt;p&gt;for문으로 2, 3, ..., (n-1), n순으로 n에 대입하고 acc에 기존 결과값과 n을 곱해 저장해주는 함수입니다.&lt;/p&gt;&lt;p&gt;마지막으로 저장되었던 acc값을 반환하고요,&lt;/p&gt;&lt;p&gt;보다시피 재귀가 필요하지 않고 변수의 상태 변화로 해결합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;기존 변수를 바꾸어 사용하니 메모리가 절약되겠죠.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt; &lt;/p&gt;&lt;p&gt;C언어였으면 상태 변화가 이루어지는 코드가 좀 더 간단했을 테지만 상태 변화를 최대한 지양하는 Racket이다 보니 절차적인 방식으로 코드를 짜면 복잡해 보입니다. 사실 range를 사용하는게 파이썬에서 주로 사용하는 스타일이라 익숙하지 않을 수도.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;+.&lt;/h4&gt;&lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/175291125910&quot; data-did=&quot;5ff76e487f5741296f7f8e70b168f6096dbddef8&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/175291125910/재귀가-아름다운-이유&quot;&gt;https://black7375.tumblr.com/post/175291125910/재귀가-아름다운-이유&lt;/a&gt;&lt;/div&gt;&lt;p&gt;  &lt;script async=&quot;&quot; src=&quot;https://assets.tumblr.com/post.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;&lt;p&gt;는 그냥 써본 말..&lt;/p&gt;&lt;p&gt;재미로만 ㅋㅋ&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;3. 후기&lt;/h2&gt;
&lt;p&gt;이번 시간에는 리스트와 재귀에 대하여 알아보았습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;분량은 적어졌지만, 내용을 압축적으로 전달하다 보니 어려워 보일 수도 있겠네요.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;다음 시간에는 자료들을 담는 방법인 자료구조에 대하여 알아보도록 할께요.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;친구가 나보고 가끔씩 TMI(Too Much Infomation)끼가 보인다고 하던데 블로그 글쓰면서 왜 그랬는지 느낄 수 있었다..&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아 참!! 어떻게 생각하면 임의의 데이터 처리는 시간과 자원만 주어진다면 무한에 가까운 데이터를 처리할 수 있다는 뜻인데, 무한에 대해 궁금하면&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/43&quot; target=&quot;_blank&quot;&gt;2018/07/22 - [수학] - 무한, 집합, 그리고 수에 대해서.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;읽어보길.&lt;br /&gt;&lt;/p&gt;</description>
      <category>프로그래밍/설계</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/38</guid>
      <comments>https://black7375.tistory.com/38#entry38comment</comments>
      <pubDate>Sun, 10 Jun 2018 02:17:01 +0900</pubDate>
    </item>
    <item>
      <title>내 맘대로 프로그램 설계 4. - 고정 크기 데이터.</title>
      <link>https://black7375.tistory.com/36</link>
      <description>&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;script type=&quot;text/javascript&quot; src=&quot;https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML&quot;&gt; &lt;/script&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 섹션에서는 섹션2,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;h4 data-ke-size=&quot;size20&quot;&gt;내 맘대로 하는 프로그램 설계 시리즈.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Chapter1 - 간단한 데이터 처리(4섹션)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://black7375.tistory.com/31&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비.&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://black7375.tistory.com/32&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 2. - 데이터 타입.&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://black7375.tistory.com/34&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2018/01/16 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 3. - 함수와 변수.&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://black7375.tistory.com/36&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2018/05/29 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 4. - 고정 크기 데이터.(현재)&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;a href=&quot;http://black7375.tistory.com/6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2017/06/30 - [프로그래밍/설계] - 프로그래밍과 추상화에 대하여.[부록]&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;b&gt;Chapter2 - 임의의 데이터 처리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://black7375.tistory.com/38&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2018/06/10 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 5. - 리스트와 재귀.&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 시작하기.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적으로 Section4에 들어가기 전에 지난 시간에 배웠던 것들을 정리하고 넘어가도록 합시다.&lt;/p&gt;
&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99A008375A66E41E0E?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99A008375A66E41E0E?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A008375A66E41E0E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A008375A66E41E0E&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;277&quot; height=&quot;237&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;망각곡선[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EB%A7%9D%EA%B0%81_%EA%B3%A1%EC%84%A0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wikipedia&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;(아마도? &lt;span style=&quot;text-decoration: line-through;&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;Section2, 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;b&gt;원자 데이터(Atomic Data).&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;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EB%A6%AC%ED%84%B0%EB%9F%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;리터럴&lt;/a&gt; 상수(Literal Constant)라고들 부르기도 한다.&lt;/p&gt;
&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;pre class=&quot;scheme&quot;&gt;&lt;code&gt;(define 상수이름 상수값)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Racket은 함수형 언어의 특성 때문에 변수가 없으며, 선언 후에 값의 변경이 안된다고 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 앞 강좌에서는 변수 정의라고 했지만, 이제 상수를 선언한다고 부릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람이 특별히 이름을 붙여주어 의미를 가지게 되는 상수라 하여 심볼릭 상수(Symbolic Constant)라고도 한다.&lt;/p&gt;
&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;pre class=&quot;gcode&quot;&gt;&lt;code&gt;;정의 (define (함수이름 매개변수 ..)   함수표현식)  ;사용 (함수이름 인자 ..)&lt;/code&gt;&lt;/pre&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;/p&gt;
&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;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&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 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;&amp;nbsp;&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;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;h4 data-ke-size=&quot;size20&quot;&gt;+.&lt;/h4&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;CAD 프로그램을 만들려면 건축, DNA 분석 프로그램을 만들 때는 생명과학 지식이 도메인 지식이다.&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;h4 data-ke-size=&quot;size20&quot;&gt;++.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;check-expect라는 함수를 사용하면 쉽게 테스트를 할 수 있다.&lt;/p&gt;
&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;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;(check-expect (+ 10 5) 15) (check-expect (- 10 5) 10)&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;403&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99CDA0485AE248A80F?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99CDA0485AE248A80F?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99CDA0485AE248A80F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99CDA0485AE248A80F&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;595&quot; height=&quot;403&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;403&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;모든 테스트가 통과하면 실행창에 '모든 n개 테스트 통과함!'이라고만 뜬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2개중 1개 테스트 실패함이라고 표시되어야 하지만 반대로 표시되는 소소한 버그가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;border&quot;&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://ko.m.wikipedia.org/wiki/%EC%A1%B4%EC%9E%AC%EC%9D%98_%EB%B2%94%EC%A3%BC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;범주(範疇,&amp;nbsp;catergoria)&lt;/b&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;blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;10개&amp;nbsp;범주를&amp;nbsp;들었다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;칸트는&amp;nbsp;순수오성개념으로&amp;nbsp;4강12목(四綱十二目)&amp;nbsp;-&amp;nbsp;분량(단일성,&amp;nbsp;수다성(&amp;lt;數多性&amp;gt;,&amp;nbsp;총체성),&amp;nbsp;성질(실재성&amp;middot;부정성&amp;middot;제한성),&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;/li&gt;
&lt;li&gt;헤겔은 범주를 객관적 존재론의 최고개념이라 하여 질, 양, 한도, 본질과 현상, 동일성, 구별, 대립, 모순, 근거, 내용과 형식, 현실성과 가능성, 필연성과 우연성, 실체와 부속성, 원인과 결과, 상호작용 등을 들었다.&lt;/li&gt;
&lt;/ul&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;철학적인 개념이지만 상당히 유용한 기준이라서 여기에도 넣어본다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교적 간단하게 적기 편한 칸트의 범주(흔히 4강 12목이라 부름)로..&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://blog.naver.com/mysig21/220219478863&quot;&gt;정리된 내용&lt;/a&gt;을 일부 수정해 만든 글이며 포함된 코드는 임의의 슈도코드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가능한 이해하기 쉽게 바꾸어 표현했다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 240px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 60px; background: #c3d7af none repeat scroll 0% 0%;&quot; rowspan=&quot;3&quot;&gt;분량&lt;br /&gt;- 양이 많고 적음&lt;br /&gt;- 주체의 한정&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;단칭판단 (하나)&lt;br /&gt;A = B[1]&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;A는 B다&lt;br /&gt;한 A는 B다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;특칭판단 (여럿)&lt;br /&gt;A = B[N &amp;lt; B.Size]&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;어떤 A는 B다&lt;br /&gt;많은 A는 B다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;전칭판단 (모두)&lt;br /&gt;A = B[B.Size]&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;모든 A는 B다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 60px; background: #c3d7af none repeat scroll 0% 0%;&quot; rowspan=&quot;3&quot;&gt;성질&lt;br /&gt;- 어떠하다&lt;br /&gt;- 정도가 많고 적음&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;긍정판단 (실질/조금)&lt;br /&gt;A == B&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;A는 B하다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;부정판단 (부정/전혀)&lt;br /&gt;A != B&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;A는 B가 아니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;무한판단 (제한/많이)&lt;br /&gt;A == (!B)&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;A는 B가 되지 않는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 60px; background: #c3d7af none repeat scroll 0% 0%;&quot; rowspan=&quot;3&quot;&gt;관계&lt;br /&gt;- 연결해줌&lt;br /&gt;- 상호작용&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;정언판단(실체와 속성)&lt;br /&gt;A = B&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;A는 B다 [주어, 술어, 연결사]&lt;br /&gt;A는 B를 포함한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;가언판단(원인과 결과)&lt;br /&gt;if (A is B) { C = D }&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;만일 A가 B면, C는 D다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;선언판단(상호작용, 교환적 인과)&lt;br /&gt;A = B | C | D&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;A는 B거나 C거나 D이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 60px; background: #c3d7af none repeat scroll 0% 0%;&quot; rowspan=&quot;3&quot;&gt;양상&amp;nbsp;&lt;br /&gt;- 판단에 기여하지 않음&lt;br /&gt;- 연결어의 가치를 다룸&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;개연판단(가능/불가능)&lt;br /&gt;(A is B)?&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;A는 B일 수 있다&lt;br /&gt;A는 B일지도 모른다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;실연판단(현존/부재)&lt;br /&gt;Def A is B&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;A는 B일 것 이다 (A가 B이든 아니든 참으로 가정한다는 의미)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;필연판단(필연/우연)&lt;br /&gt;Must A is B&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;A는 B여야 한다&amp;nbsp;&lt;br /&gt;A는 B가 분명하다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 고정 크기 데이터.&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 이미지 추가설명.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번에 조금 덜 다루었던 이미지(Image)를 좀더 다루어보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 재미있게 프로그래밍을 배워보기 위해서 인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 소개시켜 드릴것 까지 Section2에서 다루었다면 여러분들이 힘들었을 거에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 이미지를 다룰려면 '2htdp/image'라는 배움꾸러미(라이브러리)를 사용해야 합니다.&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.1.1 이미지 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번에 이미지를 다루었던 방법은 이미지의 속성값(width, height)을 이용하는 것이었습니다.&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 class=&quot;tx-link&quot; href=&quot;http://docs.racket-lang.org/teachpack/2htdpimage.html&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;/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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;line : 두점을 이용해 선을 그림.&lt;/li&gt;
&lt;li&gt;circle : 반지름의 크기대로 원을 그림.&lt;/li&gt;
&lt;li&gt;ellipse : 장축과 단축으로 타원을 그림.&lt;/li&gt;
&lt;li&gt;rectangle : 밑변과 높이로 직사각형을 그림.&lt;/li&gt;
&lt;li&gt;triangle : 정삼각형을 그림.&lt;/li&gt;
&lt;li&gt;star : 별을 그림.&lt;/li&gt;
&lt;li&gt;text : 문자열 그림을 그림.&lt;/li&gt;
&lt;/ul&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.2&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;;----------library (require 2htdp/image)  ;----------function (line 30 -20 &quot;purple&quot;) (line 30 20  &quot;purple&quot;) (line 30 20  &quot;silver&quot;)  (circle 30 &quot;outline&quot; &quot;purple&quot;) (circle 20 &quot;outline&quot; &quot;purple&quot;) (circle 30 &quot;solid&quot;   &quot;purple&quot;) (circle 30 255       &quot;purple&quot;)  (ellipse 30 20 &quot;outline&quot; &quot;purple&quot;) (ellipse 20 30 &quot;outline&quot; &quot;purple&quot;)  (rectangle 30 20 &quot;outline&quot; &quot;purple&quot;) (rectangle 20 30 &quot;outline&quot; &quot;purple&quot;)  (triangle 30 &quot;outline&quot; &quot;purple&quot;) (triangle 20 &quot;outline&quot; &quot;purple&quot;)  (star 30 &quot;outline&quot; &quot;purple&quot;) (star 20 &quot;outline&quot; &quot;purple&quot;)  (text &quot;Hello&quot; 30 &quot;purple&quot;) (text &quot;Hello&quot; 20 &quot;purple&quot;)&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;77&quot; data-origin-height=&quot;685&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99057A415AE250E520?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99057A415AE250E520?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99057A415AE250E520&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99057A415AE250E520&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;77&quot; height=&quot;685&quot; data-origin-width=&quot;77&quot; data-origin-height=&quot;685&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;2.1.2 이미지 합성.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지들을 합성 시켜 봅시다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;overlay: 중심을 기준으로 하여 이미지들을 위에 배치합니다.&lt;/li&gt;
&lt;li&gt;overlay/xy : 두번째 이미지를 xy축을 사용하여 배치합니다.(왼쪽 모서리 기준)&lt;/li&gt;
&lt;li&gt;overlay/align : 이미지들을 왼쪽 정렬, 가운데 정렬처럼 정렬시킵니다..&lt;/li&gt;
&lt;li&gt;underlay : overlay와 반대로 이미지들을 배치합니다.&lt;/li&gt;
&lt;li&gt;empty-scene : 너비와 높이에 맞추어 하얀 사각형을 그림.&lt;/li&gt;
&lt;li&gt;place-image: 지정된 이미지에 다른 이미지를 배치한다. 단, 테두리를 벗어나면 잘린다.&lt;/li&gt;
&lt;li&gt;scene+line : 주어진 이미지에 선을 그린다.&lt;/li&gt;
&lt;/ul&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.3&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;(overlay (triangle 30 &quot;solid&quot; &quot;black&quot; )          (square   40 &quot;solid&quot; &quot;purple&quot;)          (circle   30 &quot;solid&quot; &quot;silver&quot;))  (overlay/xy (triangle 30 &quot;solid&quot; &quot;black&quot;)             0 0             (overlay/xy (square 40 &quot;solid&quot; &quot;purple&quot;)                         20 10                         (circle 30 &quot;solid&quot; &quot;silver&quot;)))  (overlay/align &quot;left&quot; &quot;bottom&quot;               (triangle 30 &quot;solid&quot; &quot;black&quot; )               (square   40 &quot;solid&quot; &quot;purple&quot;)               (circle   30 &quot;solid&quot; &quot;silver&quot;))  (underlay (circle   30 &quot;solid&quot; &quot;silver&quot;)           (square   40 &quot;solid&quot; &quot;purple&quot;)           (triangle 30 &quot;solid&quot; &quot;black&quot; ))  (empty-scene 30 20)  (place-image (circle 30 &quot;solid&quot; &quot;black&quot;)              20 0              (empty-scene 50 50))  (scene+line (ellipse   30 20 &quot;outline&quot; &quot;purple&quot;)              0  20 30 0   &quot;purple&quot;) (scene+line (rectangle 30 20 &quot;solid&quot;   &quot;silver&quot;)              10 20 20 -10 &quot;purple&quot;)&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;90&quot; data-origin-height=&quot;423&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9918914C5AE25E833C?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9918914C5AE25E833C?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9918914C5AE25E833C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9918914C5AE25E833C&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;90&quot; height=&quot;423&quot; data-origin-width=&quot;90&quot; data-origin-height=&quot;423&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1.3 이미지 활용.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재미로 이미지를 활용한 프로그램을 만들어 보도록 할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'2htdp/universe'라는 라이브러리를 추가해봅시다.(아마 universe.rkt라고 되어 있을 겁니다.)&lt;/p&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;250&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9930084C5AFBD69721?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9930084C5AFBD69721?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9930084C5AFBD69721&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9930084C5AFBD69721&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;250&quot; height=&quot;370&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;운영체제[from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%9A%B4%EC%98%81_%EC%B2%B4%EC%A0%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 사용하는 BSL은 프로그래밍 언어이고, 프로그래밍 언어를 실행하는 Dr.Racket은 소형 운영체제라 생각할 수 있습니다.&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;운영체제에 대해 쉽게 설명하자면 하드웨어와 응용프로그램(어플리케이션)을 중재 해주는 프로그램입니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dr.Racket이 실제로 직접적인 하드웨어 제어를 하는 것은 아니지만 저희가 BSL로 만든 프로그램이 컴퓨터의 자원(램, CPU, 입출력 등)을 활용하는데 중재 해주는 역할을 하기 때문에 소형 운영체제처럼 여길 수 있습니다.&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;722&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/997DBE4E5AFBD70F05?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/997DBE4E5AFBD70F05?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/997DBE4E5AFBD70F05&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F997DBE4E5AFBD70F05&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;406&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;big-bang 함수 설명[from &lt;a class=&quot;tx-link&quot; href=&quot;http://docs.racket-lang.org/teachpack/2htdpuniverse.html#%28tech._world%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;racket-lang&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;universe라는 라이브러리에서 제공하는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;http://docs.racket-lang.org/teachpack/2htdpuniverse.html#%28form._world._%28%28lib._2htdp%2Funiverse..rkt%29._big-bang%29%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;big-bang&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;어떤 함수가 어떤 이벤트를 처리하는지 운영체제에게 알려주는 역할을 합니다.&lt;/p&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-expr)이 있고, 그 값은 프로그램의 초기값이 됩니다.&lt;br /&gt;위 그림에서는 World_0 이겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추후 World-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;이외에 big-bang은 필수 요소(clause)과 많은 옵션의 요소(clause)들로 구성됩니다.&lt;br /&gt;필수: to-draw&lt;br /&gt;선택: on-tick, on-mouse 등..&lt;/p&gt;
&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 class=&quot;tx-link&quot; href=&quot;http://docs.racket-lang.org/teachpack/2htdpuniverse.html#%28form._world._%28%28lib._2htdp%2Funiverse..rkt%29._to-draw%29%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;to-draw&lt;/a&gt;라는 기능은 Dr.Racket에 초기상태를 포함하여 프로그램의 상태를 렌더링하는 방법을 알려줍니다.&lt;br /&gt;다른 옵션의 요소들은 운영체제에게 특정 기능이 특정 이벤트를 처리한다는 것을 알려줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clause라고 나온 것들이 아래 설명의 이벤트 핸들러(Event Handler) 역할을 했다는 뜻.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;border&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; 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;&lt;b&gt;- 상태 관련 용어&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해(Solution):&lt;/p&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;세계(World):&lt;/p&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;상태(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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- UI 관련 용어&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EB%A0%8C%EB%8D%94%EB%A7%81&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;렌더링(R&lt;/a&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EB%A0%8C%EB%8D%94%EB%A7%81&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;endering)&lt;/a&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;컴퓨터 프로그램을 사용하여 모델(또는 이들을 모아놓은 장면인 씬(scene) 파일)로부터 영상을 만들어내는 과정.&lt;br /&gt;&amp;nbsp;간단한 UCC 같이 영상을 만들어보신 분들은 렌더링이란 단어가 익숙할 겁니다.&lt;/p&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 class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%B4%EB%B2%A4%ED%8A%B8_(%EC%BB%B4%ED%93%A8%ED%8C%85)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이벤트(Event)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%B4%EB%B2%A4%ED%8A%B8_(%EC%BB%B4%ED%93%A8%ED%8C%85)#%EC%9D%B4%EB%B2%A4%ED%8A%B8_%ED%95%B8%EB%93%A4%EB%9F%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이벤트 핸들러(Event Handler)&lt;/a&gt;:&lt;br /&gt;이벤트가 일어났을 때 받아서 처리하는 함수입니다.&lt;br /&gt;정확히 말하면 콜백(Callback)이지만, 여기서는 위에 나온 개념 정도로만 알아도 상관 없습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BSL에서 이벤트 관리는 해당 기능이 프로그램의 상태와 이벤트에 대한 설명에 시간을 사용하고 다음 상태의 프로그램을 생성하는 것을 의미합니다.&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;간단하게 만들어보죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 주요 big-bang 요소들의 핸들러를 위한 계약과 목적을 알아보도록 합시다.&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;to-draw의 핸들러 함수는 WorldState 또는 WorldState width height 가 매개변수가 될 수 있고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;on-tick에 쓸 핸들러 함수는 WorldState, WorldState rate 또는 WorldState rate limit 이 매개변수가 될 수 있는 형식입니다.&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;to-draw: WorldState (width height) -&amp;gt; image; 이미지 렌더링, 필수&lt;/li&gt;
&lt;li&gt;on-tick: WorldState (rate (limit)) -&amp;gt; WorldState ; 시간의 지남&lt;/li&gt;
&lt;li&gt;on-key: WorldState, KeyEvent -&amp;gt; WorldState ; 키보드 이벤트&lt;/li&gt;
&lt;li&gt;on-mouse: WorldState integer integer MouseEvent -&amp;gt; WorldState ; 마우스 이벤트&lt;/li&gt;
&lt;li&gt;stop-when: WorldState (WorldState) -&amp;gt; boolean (image) ; 멈출 때&lt;/li&gt;
&lt;li&gt;name: NULL -&amp;gt; symbol or string ; 창 제목&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 공식 문서에서 HandlerResult란 표현이 있었는데 WorldState와 사실상 같으므로, WorldState로 표시했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 이유로 scene도 image라 표시.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;border: 1px solid; padding: 10px;&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2htdp/universe의 데이터 타입.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WorldState는 아무 데이터 타입이나 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;width, height, limit은 자연수(integer), rate는 실수(real).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KeyEvent는 문자열(string)이지만(예 a키는 &quot;a&quot;, 스페이스바는 &quot; &quot;) 특수키는 확장된 방식으로 표현합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[엔터: &quot;\r&quot;, 탭: &quot;\t&quot;, 백스페이스: &quot;\b&quot;, 시프트: &quot;shift&quot;, 화살표: &quot;left&quot; &quot;right&quot; &quot;up&quot; &quot;down&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;MouseEvent도 제약된 문자열(string) 형식으로 다음 동작 중 하나입니다 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[누름: &quot;button-down&quot;, 땜: &quot;button-up&quot;, 드래그: &quot;drag&quot;, 움직임: &quot;move&quot;, 창안으로: &quot;enter&quot;, 창밖으로: &quot;leave&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;a class=&quot;tx-link&quot; href=&quot;https://docs.racket-lang.org/teachpack/2htdpuniverse.html#%28form._world._%28%28lib._2htdp%2Funiverse..rkt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; 2htdp/universe&lt;/a&gt; 라이브러리 문서를 참고해주세요.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 필수 요소인 to-draw를 이용해 만들어보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자(WorldState)를 통해 image를 만드는 핸들러 함수(number-&amp;gt;circle)를 만들고 테스트 해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터 함수 테스트는 check-expect를 이용하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계약과 목적 또한 충분히 숙지했으니, Constract나 Purpose라는 표시 없이 넣도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 좀 더 간결하게 보이기 위한 노력입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.4 - 1&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;;----------library (require 2htdp/universe)  ;----------fuction ;;number-&amp;gt;circle: WorldState -&amp;gt; image ;;Make circle from number. (define (number-&amp;gt;circle r)   (circle r &quot;solid&quot; &quot;purple&quot;))  ;----------fuction test (check-expect (number-&amp;gt;circle 10)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;21&quot; data-origin-height=&quot;21&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99D5F83A5B05ABD50A?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99D5F83A5B05ABD50A?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D5F83A5B05ABD50A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D5F83A5B05ABD50A&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;21&quot; height=&quot;21&quot; data-origin-width=&quot;21&quot; data-origin-height=&quot;21&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;                   ) (check-expect (number-&amp;gt;circle 100)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;201&quot; data-origin-height=&quot;201&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99C3C1365B05AC070A?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99C3C1365B05AC070A?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C3C1365B05AC070A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C3C1365B05AC070A&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;201&quot; height=&quot;201&quot; data-origin-width=&quot;201&quot; data-origin-height=&quot;201&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;)  ;----------big-bang test (big-bang  100 [to-draw number-&amp;gt;circle])&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;343&quot; data-origin-height=&quot;344&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/999160435B05ABC70A?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/999160435B05ABC70A?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999160435B05ABC70A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999160435B05ABC70A&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;343&quot; height=&quot;344&quot; data-origin-width=&quot;343&quot; data-origin-height=&quot;344&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 style=&quot;text-align: center; clear: none; float: none;&quot; 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;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.4 -2&lt;/p&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;(check-expect (number-&amp;gt;circle 10)               (circle 10  &quot;solid&quot; &quot;purple&quot;)) (check-expect (number-&amp;gt;circle 100)               (circle 100 &quot;solid&quot; &quot;purple&quot;))&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;숫자(반지름 r)에 따라 원을 그리는 함수를 만들고, 테스트 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 big-bang 함수를 써보았는데요, 초기값은 100, 그리는 요소로 위에서 만든 number-&amp;gt;circle을 사용했습니다.&lt;br /&gt;이때 World 창이 실행되어 반지름이 100인 원 이미지가 출력 되었고, X버튼을 누를 때까지 실행 영역은 그대로 멈춰있습니다.&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;여러분이 생각한 것처럼 실제로 실행이 되고 있는 중이 맞고,&lt;br /&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 이미지를 제어하면서 조금 더 알아봅시다.&lt;/p&gt;
&lt;blockquote class=&quot;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화살표 키를 이용하여 원의 크기를 제어하고(1씩), 10 미만으로 원의 크기가 작아지면 종료되도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;창 제목도 커스텀 해보겠습니다.&lt;/p&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;이때 big-bang의 World 상태는 이벤트가 일어날 때(키보드가 눌릴 때)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마치 이미지를 연속으로 보여주는 필름 영화처럼 변화하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 나왔던 World_0-&amp;gt;World_1-&amp;gt;World_2 ... 같은 식으로요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9939843C5B09036C10?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9939843C5B09036C10?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9939843C5B09036C10&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9939843C5B09036C10&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;820&quot; height=&quot;215&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Film Strip[from &lt;a class=&quot;tx-link&quot; href=&quot;https://pixabay.com/en/film-strip-35mm-frame-camera-30008/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pixabay&lt;/a&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 저희는 입력 받은 World의 상태가 이벤트가 일어날 때마다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 핸들러가 기존 World의 상태를 처리(크기 조절)하여 반환하고,&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;p data-ke-size=&quot;size16&quot;&gt;보조 문제와 관련된 big-bang의 요소는 [Clause] 와 같은 방식으로 표시하였습니다.&lt;/p&gt;
&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; - 화살표 키로 크기 제어.[on-key]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 원 그리기.[to-draw]&lt;/p&gt;
&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; - 10 미만 가려내기.[stop-when]&lt;/p&gt;
&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; - 창 제목[name]&lt;/p&gt;
&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;* 원 크기 제어.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 화살표 키로 크기 제어.[on-key]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽, 위 화살표는 원의 크기를 1씩 줄이고, 오른쪽과 아래 화살표로는 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;pre class=&quot;maxima&quot;&gt;&lt;code&gt;;;key-control: WorldState KeyEvent -&amp;gt; WorldState ;;Size control with arrow-key. (define (key-control world a-key) ...)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key로 조절을 하기 위한 것이니 함수 이름은 key-control.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력값은 on-key에서 요구하는 대로 WorldState string -&amp;gt; WorldState.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개 변수 이름은 WorldState값 -&amp;gt; world, 키보드 키(string) -&amp;gt; a-key라고 표현합니다.&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;$$key-control = \begin{cases}&lt;br /&gt;왼쪽 &amp;amp; 화살표, &amp;amp; -1 \\&lt;br /&gt;오른쪽 &amp;amp; 화살표, &amp;amp; +1 \\&lt;br /&gt;위쪽 &amp;amp; 화살표, &amp;amp; +1 \\&lt;br /&gt;아래쪽 &amp;amp; 화살표, &amp;amp; -1 \\&lt;br /&gt;나머지 &amp;amp; , &amp;amp; 반응없음.&lt;br /&gt;\end{cases}$$&lt;/p&gt;
&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 class=&quot;tx-link&quot; href=&quot;http://docs.racket-lang.org/teachpack/2htdpuniverse.html#%28def._world._%28%28lib._2htdp%2Funiverse..rkt%29._key-event~3f%29%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;key=? &lt;/a&gt;라는 함수(universe 라이브러리에 포함)로 &lt;a class=&quot;tx-link&quot; href=&quot;http://docs.racket-lang.org/teachpack/2htdpuniverse.html#%28tech._world._keyevent%29&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;key=? 함수는 입력 받은 키보드 신호가 같으면 #true를 다르면 #false를 반환 합니다.&lt;/p&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을 기준으로 좌우상하, a키, f1키를 사용해보았습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.5 - 1&lt;/p&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;;----------fuction ;;key-control: WorldState KeyEvent -&amp;gt; WorldState ;;Size control with  arrow-key. (define (key-control world a-key)   (cond     [(key=? a-key &quot;left&quot; )  (- world 1)]     [(key=? a-key &quot;right&quot;)  (+ world 1)]     [(key=? a-key &quot;up&quot;   )  (- world 1)]     [(key=? a-key &quot;down&quot; )  (+ world 1)]     [(= (string-length a-key) 1)  world] ; order-free checking     [ else                        world]))  ;----------fuction test (check-expect (key-control 10 &quot;left&quot; ) 9 ) (check-expect (key-control 10 &quot;right&quot;) 11) (check-expect (key-control 10 &quot;up&quot;   ) 9 ) (check-expect (key-control 10 &quot;down&quot; ) 11) (check-expect (key-control 10 &quot;a&quot;    ) 10) (check-expect (key-control 10 &quot;f1&quot;   ) 10)&lt;/code&gt;&lt;/pre&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 data-ke-size=&quot;size16&quot;&gt;key-control은 키보드 이벤트에 대한 핸들러가 될 것입니다.&lt;/p&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; - 원 그리기.[to-draw]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 만든 number-&amp;gt;circle 함수를 쓰도록 하겠습니다.&lt;/p&gt;
&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; - 10 미만 가려내기.[stop-when]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WorldState값이 10 미만이 되면 #true를 반환하고, 나머지 경우는 #false를 반환하면 된다.&lt;/p&gt;
&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 class=&quot;lasso&quot;&gt;&lt;code&gt;;;under-ten?: WorldState -&amp;gt; boolean ;;Check under than 10. (define (under-ten? world) ...)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10보다 작은지 판독하는 것이므로 함수 이름은 under-ten?.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력은 stop-when이 요구하는 것처럼 WorldState -&amp;gt; boolean.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수는 key-control과 마찬가지로 world.&lt;/p&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;p data-ke-size=&quot;size16&quot;&gt;이건 경우의 수가 작으므로, if를 사용하여 처리하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10 미만일 때 #true가 되야 되므로 경계 값인 11, 10, 9를 테스트 케이스로 사용했습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.5 - 2&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;;----------fuction ;;under-ten?: WorldState -&amp;gt; boolean ;;Check under than 10. (define (under-ten? world)   (if (&amp;gt; 10 world)      #true #false))  ;----------fuction test (check-expect (under-ten? 11) #false) (check-expect (under-ten? 10) #false) (check-expect (under-ten? 9)  #true )&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;&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; - 창 이름.[name]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;창 이름은 함수가 아닌 상수.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;창 이름을 Big-Bang TEST로 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;puppet&quot;&gt;&lt;code&gt;;----------constant (define window-name &quot;Big-Bang TEST&quot;)&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;* Big-Bang 테스트 하기.&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.5 - 4&lt;/p&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;;----------big-bang test (big-bang 100   [to-draw   number-&amp;gt;circle]   [on-key    key-control   ]   [stop-when under-ten?    ]   [name      window-name   ])&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/991D904C5B072C2935?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/991D904C5B072C2935?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991D904C5B072C2935&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991D904C5B072C2935&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;269&quot; height=&quot;266&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화살표 키로 이미지의 크기를 줄여 10 미만이 된다면 사진처럼 마지막 상태값(9)을 반환하게 됩니다.&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;on-tick이나 on-mouse 같은 요소들을 이용해서 이미지를 제어해보고,&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 class=&quot;tx-link&quot; href=&quot;http://htdp.org/2018-01-06/Book/part_one.html#%28part._sec~3aprogs%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HtDP&lt;/a&gt;를 참고해보도록 하고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2htdp/univers 라이브러리의 사용법이 궁금하면 역시 &lt;a class=&quot;tx-link&quot; href=&quot;https://docs.racket-lang.org/teachpack/2htdpuniverse.html?q=2htdp%2Fimage&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 썼던 big-bang 표현으로 프로그램의 이벤트, 상태 변환, 속성 결정법 등을 체험하였습니다.&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;2.2 구조체(Struct).&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2.1 구조체의 필요성.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 이미지 사용법을 보는 도중 &lt;a class=&quot;tx-link&quot; href=&quot;http://docs.racket-lang.org/teachpack/2htdpimage.html#%28def._%28%28lib._2htdp%2Fimage..rkt%29._image-color~3f%29%29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;image-color?&lt;/a&gt;라는 것이 궁금해서 들어간적이 있나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;image-color?의 설명을 보면 &amp;nbsp;색 구조체(Struct)가 있던 것인지 &amp;nbsp;확인하고 불린값(Boolean)으로 반환해준다고 되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr class=&quot;none tx-hr-border-3&quot;/&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;image-color?&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;llvm&quot;&gt;&lt;code&gt;(image-color? x) &amp;rarr; boolean?   x : any/c&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Determines if x represents a color. Strings, symbols, and &lt;span style=&quot;background-color: #ffe400;&quot;&gt;color structs&lt;/span&gt; are allowed as colors.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr class=&quot;none tx-hr-border-3&quot;/&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 그 밑의 Color란 구조체(Struct)의 설명을 보면 0~255의&amp;nbsp;RGB값(Red, Green, Blue)과 Alpha(투명도)를 이용하여 make-color란 생성자를 통해 색을 정의한다고 되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr class=&quot;none tx-hr-border-3&quot;/&gt;
&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;Color&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;(struct	 	color (red green blue alpha)     #:extra-constructor-name make-color)   red : (and/c natural-number/c (&amp;lt;=/c 255))   green : (and/c natural-number/c (&amp;lt;=/c 255))   blue : (and/c natural-number/c (&amp;lt;=/c 255))   alpha : (and/c natural-number/c (&amp;lt;=/c 255))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The color struct defines a color with red, green, blue, and alpha components that range from 0 to 255.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr class=&quot;none tx-hr-border-3&quot;/&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 구조체(Struct)의 필요성에&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;함수에서 입력 값이 딱 1개의 수나 기호를 가지는 경우는 많지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 정보를 함수에 입력해야 되는 경우가 잦다는 것인데, 여러 정보를 묶어서(Compound) 하나의 자료로 나타내는 것이 효율적입니다.&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. 고정 크기 데이터'라는 섹션 제목은 구조체를 의미합니다.&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;513&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/995429415B1FD5E213?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/995429415B1FD5E213?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995429415B1FD5E213&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995429415B1FD5E213&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;513&quot; height=&quot;134&quot; data-origin-width=&quot;513&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;위에 나온 Color란 구조체에서는 빨강, 초록, 파랑과 투명도란 값들을 모아서 하나의 색을 이루는 의미가 있는 단위가 된 예입니다.&lt;/p&gt;
&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;table style=&quot;border-collapse: collapse; table-layout: fixed; mso-table-overlap: never; border: none;&quot; align=&quot;center&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 419.52pt; height: 23px; padding: 1.41pt 5.1pt; border-color: #74a442 #74a442 #d8e8c6; border-style: solid; border-width: 1.7pt 1.7pt 0.28pt; background: #c3d7af none repeat scroll 0% 0%;&quot; colspan=&quot;4&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;font-family: 맑은 고딕, sans-serif; font-weight: bold;&quot;&gt;구조체 이름&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0pt; font-weight: bold; font-family: 맑은 고딕, sans-serif;&quot;&gt;: color&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #74a442 1.70pt; border-bottom: solid #74a442 1.70pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;red: 238&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #74a442 1.70pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;green: 169&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #74a442 1.70pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;blue: 16&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #74a442 1.70pt; border-right: solid #74a442 1.70pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은 고딕, sans-serif;&quot;&gt;alpha: 255&lt;/span&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;(alpha 값은 투명도로, 제 표의 노랑색은 투명도를 딱히 설정해놓지 않아 255가 들어갔습니다.)&lt;/p&gt;
&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;h4 data-ke-size=&quot;size20&quot;&gt;2.2.2 구조체 생성 및 기초 사용법.&lt;/h4&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;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 class=&quot;scheme&quot;&gt;&lt;code&gt;(define-struct 구조체이름 (매개변수1 매개변수2 ..))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예) 구조체 이름: 노래, 구조체 매개변수: 아티스트, 트랙, 장르, 년도&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.6 - 1&lt;/p&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;(define-struct Song (artist track genre year))&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 data-ke-size=&quot;size16&quot;&gt;- 구조체 사용법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성: 실제 데이터를 넣는 과정입니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(make-구조체이름 인자1 인자2 ...)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추출: 구조체에서 인자값을 알아내는 방법입니다.&lt;/p&gt;
&lt;pre class=&quot;scheme&quot;&gt;&lt;code&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;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.6 - 2&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;(Song-artist  (make-Song &quot;Busker Busker&quot; 4 'Rock 2012)) (Song-genre  (make-Song &quot;Bolbbalgan4&quot;   7 'Folk 2016))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답: &quot;Busker Busker&quot;, 'Folk&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;/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;그래서 struct?는 구조체 , Song?은 Song 구조체인지 판독 가능합니다.&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;2.2.3 구조체 활용법.&lt;/h4&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 class=&quot;lisp&quot;&gt;&lt;code&gt;(make-Song   &quot;Cherry Blossom Ending&quot; &quot;BuskerBusker&quot; 4 'Rock 2012)   (make-Song   &quot;Freesia&quot;               &quot;Bolbbalgan4&quot;  7 'Folk 2016)&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;그럼 이렇게 한번 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빨간색을 (red, 255, 0, 0)라고 표현하지 않고, red=(255, 0, 0)처럼 표현하는 것이 더 나은 방식이 아닐까?&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;더 쉬운 예로 상수 원주율 Pi는 그냥 3.141592..의 데이터에 이름을 붙인 것이지 3.14592..란 데이터에 Pi란 단어가 들어가지 않는 것과 같다.&lt;/p&gt;
&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;위에서는 알아서 on-tick이나 on-mouse 같은 요소들을 자율적으로 사용해보라 했지만,&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;이번에 우리가 만들어볼 것은 4가지의 상태를 전환하는 프로그램입니다.&lt;/p&gt;
&lt;blockquote class=&quot;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1초마다 상태가 전환되는데 파란색 -&amp;gt; 노란색 -&amp;gt;&amp;nbsp; 초록색 원(반지름 20)으로 전환됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키보드 스페이스를 누르면 노란색으로 표시되고, 마우스 커서를 창안으로 넣으면 빨간색으로 전환되며 종료됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원은 200x200인 empty-scene 안에 언급된 색 순서대로 80x0 160x50 80x100 0x50위치에 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위치는 2htdp/image에 미리 정의되어 있는 posn 이란 구조체를 사용하며, x와 y라는 매개변수를 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 자신의 색이 표시되면 &quot;solid&quot;로, 아니면 &quot;outline&quot; 원이 그려집니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 실제로 만들어보면 종료시 빨간색으로 전환이 안되는데 stop-when 체크를&amp;nbsp; to-draw보다 먼저 실행하기 때문입니다.&lt;/p&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 style=&quot;text-align: center;&quot; 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;224&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/9933A53B5B26C10A2F?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/9933A53B5B26C10A2F?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9933A53B5B26C10A2F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9933A53B5B26C10A2F&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;224&quot; height=&quot;295&quot; data-origin-width=&quot;224&quot; data-origin-height=&quot;295&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;&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 style=&quot;text-align: center; clear: none; float: none;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;상태표.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; table-layout: fixed; mso-table-overlap: never; border: none;&quot; align=&quot;center&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 23px; padding: 1.41pt 5.1pt; border-color: #74a442 #d8e8c6 #d8e8c6 #74a442; border-style: solid; border-width: 1.7pt 0.28pt 0.28pt 1.7pt; background: #c3d7af none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt; font-weight: bold;&quot;&gt;Q(t)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 23px; padding: 1.41pt 5.1pt; border-color: #74a442 #d8e8c6 #d8e8c6; border-style: solid; border-width: 1.7pt 0.28pt 0.28pt; background: #c3d7af none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;font-family: 맑은 고딕; mso-fareast-font-family: 맑은 고딕; font-weight: bold;&quot;&gt;입력&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 23px; padding: 1.41pt 5.1pt; border-color: #74a442 #d8e8c6 #d8e8c6; border-style: solid; border-width: 1.7pt 0.28pt 0.28pt; background: #c3d7af none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt; font-weight: bold;&quot;&gt;Q(t+1)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 23px; padding: 1.41pt 5.1pt; border-color: #74a442 #74a442 #d8e8c6 #d8e8c6; border-style: solid; border-width: 1.7pt 1.7pt 0.28pt 0.28pt; background: #c3d7af none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;font-family: 맑은 고딕; mso-fareast-font-family: 맑은 고딕; font-weight: bold;&quot;&gt;출력&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; border-color: #d8e8c6 #d8e8c6 #d8e8c6 #74a442; border-style: solid; border-width: 0.28pt 0.28pt 0.28pt 1.7pt; background: #ffffff none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;blue&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; background: #ffffff none repeat scroll 0% 0%; border: 0.28pt solid #d8e8c6;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;blue&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; background: #ffffff none repeat scroll 0% 0%; border: 0.28pt solid #d8e8c6;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; border-color: #d8e8c6 #74a442 #d8e8c6 #d8e8c6; border-style: solid; border-width: 0.28pt 1.7pt 0.28pt 0.28pt; background: #ffffff none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; border-color: #d8e8c6 #d8e8c6 #d8e8c6 #74a442; border-style: solid; border-width: 0.28pt 0.28pt 0.28pt 1.7pt; background: #ffffff none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; background: #ffffff none repeat scroll 0% 0%; border: 0.28pt solid #d8e8c6;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; background: #ffffff none repeat scroll 0% 0%; border: 0.28pt solid #d8e8c6;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;green&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; border-color: #d8e8c6 #74a442 #d8e8c6 #d8e8c6; border-style: solid; border-width: 0.28pt 1.7pt 0.28pt 0.28pt; background: #ffffff none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;green&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; border-color: #d8e8c6 #d8e8c6 #d8e8c6 #74a442; border-style: solid; border-width: 0.28pt 0.28pt 0.28pt 1.7pt; background: #ffffff none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;green&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; background: #ffffff none repeat scroll 0% 0%; border: 0.28pt solid #d8e8c6;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;green&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; background: #ffffff none repeat scroll 0% 0%; border: 0.28pt solid #d8e8c6;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;blue&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 22px; padding: 1.41pt 5.1pt; border-color: #d8e8c6 #74a442 #d8e8c6 #d8e8c6; border-style: solid; border-width: 0.28pt 1.7pt 0.28pt 0.28pt; background: #ffffff none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;blue&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #74a442 1.70pt; border-bottom: solid #d8e8c6 0.28pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;blue&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; background: #ffffff; border: solid #d8e8c6 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;blue&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; background: #ffffff; border: solid #d8e8c6 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #d8e8c6 0.28pt; border-right: solid #74a442 1.70pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #74a442 1.70pt; border-bottom: solid #d8e8c6 0.28pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; background: #ffffff; border: solid #d8e8c6 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; background: #ffffff; border: solid #d8e8c6 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;green&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #d8e8c6 0.28pt; border-right: solid #74a442 1.70pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;green&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #74a442 1.70pt; border-bottom: solid #d8e8c6 0.28pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; background: #ffffff; border: solid #d8e8c6 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; background: #ffffff; border: solid #d8e8c6 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #d8e8c6 0.28pt; border-right: solid #74a442 1.70pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #74a442 1.70pt; border-bottom: solid #d8e8c6 0.28pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;?&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; background: #ffffff; border: solid #d8e8c6 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;?, &amp;ldquo; &amp;rdquo;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; background: #ffffff; border: solid #d8e8c6 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #d8e8c6 0.28pt; border-right: solid #74a442 1.70pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;yellow&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #74a442 1.70pt; border-bottom: solid #d8e8c6 0.28pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; background: #ffffff; border: solid #d8e8c6 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; background: #ffffff; border: solid #d8e8c6 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #d8e8c6 0.28pt; border-right: solid #74a442 1.70pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #74a442 1.70pt; border-bottom: solid #74a442 1.70pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;?&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #74a442 1.70pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;?, &amp;ldquo;enter&amp;rdquo;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #74a442 1.70pt; border-right: solid #d8e8c6 0.28pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;red&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 104.88pt; height: 12.82pt; padding: 1.41pt 5.10pt 1.41pt 5.10pt; border-top: solid #d8e8c6 0.28pt; border-left: solid #d8e8c6 0.28pt; border-bottom: solid #74a442 1.70pt; border-right: solid #74a442 1.70pt; background: #ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;span&gt;&lt;span style=&quot;mso-fareast-font-family: 맑은 고딕; font-family: 맑은 고딕; mso-ascii-font-family: 맑은 고딕; mso-font-width: 100%; letter-spacing: 0pt; mso-text-raise: 0pt;&quot;&gt;red&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 상태인 Q(t), big-bang에 입력되는 입력값, 다음 상태 예정인 Q(t+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;hr/&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 내용이 거의 비슷한데 왜 Q(t), 입력, Q(t+1), 출력을 넣었는가.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금의 상태표는 마지막 함수를 기준으로 기술하고 있기 때문에 Q(t)와 입력이, Q(t+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;중간 중간 함수 작성 시 막힌다면 Q(t), 입력에 값을 넣고, 다음 상태와 최종 출력값을 계산해보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr/&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;상태 다이어그램.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot; 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;813&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/996AD5405B28131023?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/996AD5405B28131023?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996AD5405B28131023&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996AD5405B28131023&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;813&quot; height=&quot;290&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원 안에 있는 것은 상태값,&amp;nbsp; 화살표는 전이방향, 전이시 텍스트는 '입력1, 입력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;&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 1&lt;/p&gt;
&lt;pre class=&quot;puppet&quot;&gt;&lt;code&gt;;----------constant ;-----background (define WIDTH  200) (define HEIGHT 200) (define BACKGROUND (empty-scene WIDTH HEIGHT))  ;-----circle (define R 20)  ;;ncolor (define BLUE   0) (define YELLOW 1) (define GREEN  2) (define RED    3)  ;;posn (define START   (make-posn 80  0  )) ;;100 50 (define MIDDLE   (make-posn 160 50 )) ;;150 100 (define END   (make-posn 80  100)) ;;100 150 (define ERROR   (make-posn 0   50 )) ;;50  100&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;배경으로 쓸 BACKGROUND, 원의 반지름, 색, 좌표를 설정해주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;색은 &quot;blue&quot;, &quot;yellow&quot;같은 식이 아니라, 숫자로 설정하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[숫자로 색을 설정했으므로 기존 color 구조체와 차이를 두기위해 number color라는 뜻으로 ncolor라 표시했습니다.]&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;/p&gt;
&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;계약-목적-헤더&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;;----------big-bang ;;4state-trans ; WorldState -&amp;gt; image ;;4 color's circle transition. (define (4state-trans ncolor))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4가지 상태의 변환을 나타내는 문제이므로, 4state-trans라는 이름을 붙였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 색을 입력하여 전환되도록 색을 big-bang의 world 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;그러고 보니 마지막 순서는 big-bang을 실행하는 함수죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 big-bang과 관련된 부분을 찾아서 헤더를 확장해봅시다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;함수 템플릿&lt;/p&gt;
&lt;pre class=&quot;scheme&quot;&gt;&lt;code&gt;(define (4state-trans ncolor)   (big-bang ncolor     [to-draw   ...]     [on-tick   ...]     [on-mouse  ...]     [on-key    ...]     [stop-when ...]))&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;이 상태를 함수 템플릿이라 부릅니다.(섹션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;필수 요소이자 화면에 이미지 표시 기능인 to-draw, 1초마다 상태 전환을 위한 on-tick, 마우스와 키보드 이벤트 인식을 위한 on-mouse, on-key, 프로그램의 종료 조건을 위한 stop-when이 조건입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4state의 조건들은 다 작성했으니 '...'으로 되어 있는 값들을 채워줘야 할 때입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 2&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;;----------big-bang ;;4state-trans: WorldState -&amp;gt; image ;;4 color's circle transition. (define (4state-trans ncolor)   (big-bang ncolor     [to-draw   render      ]     [on-tick   next-color 1]     [on-mouse  enter?      ]     [on-key    space?      ]     [stop-when RED?        ]))  ;----------big-bang test (4state-trans BLUE)&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;이미지를 생성해주기 때문에 render, 1초마다 전환(next-color)을 하기 위해 on-tick에 1을 붙여주었습니다&lt;/div&gt;
&lt;div&gt;마우스가 창에 들어왔는지와 스페이스키가 눌리는지를 확인하는 enter?과 space?&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빨간색인지 판독하는 RED? 핸들러를 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;draw, tick, key, stop의 조건들을 하나 씩 뜯어볼 차례입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 간단한 tick, key, stop부터 해봅시다.&lt;/p&gt;
&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;- tick&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간이 지날 때(1초)마다 다음 상태로 전환이 됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 3&lt;/p&gt;
&lt;pre class=&quot;openscad&quot;&gt;&lt;code&gt;;----------function ;-----handler ;;next-color: WorldState -&amp;gt; WorldState ;;Purpose: Transition next state. (define (next-color world)   (if (equal? world RED)   RED (remainder (+ world 1) 3)))  ;----------fuction test ;-----tick (check-expect (next-color BLUE  ) YELLOW) (check-expect (next-color YELLOW) GREEN ) (check-expect (next-color GREEN ) BLUE  ) (check-expect (next-color RED   ) RED   )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;world의 값이 빨간색일 경우 전환할 색이 없으므로, RED(3)를 반환하고, 다음 상태로 전환하기 위해 remainder(나머지)를 사용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3의 나머지를 사용하면 0-&amp;gt;-1-&amp;gt;2-&amp;gt;0-&amp;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 data-ke-size=&quot;size16&quot;&gt;1을 YELLOW, 3을 RED로 사용하지 않은 이유는 색을 나타내는 것이 아니라 숫자의 의미이기 때문입니다.&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;&amp;nbsp;- mouse&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;그러면 stop의 조건에 맞아 떨어져서 종료가 되겠죠.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 4&lt;/p&gt;
&lt;pre class=&quot;openscad&quot;&gt;&lt;code&gt;;----------function ;-----handler ;;enter?: WorldState integer integer MouseEvent -&amp;gt; WorldState ;;Check MouseEvent is &quot;enter&quot;. (define (enter? world x y a-mouse)   (if (mouse=? a-mouse &quot;enter&quot;)      RED world))  ;----------fuction test ;-----mouse (check-expect (enter? BLUE 10 10 &quot;enter&quot;) RED ) (check-expect (enter? BLUE 10 10 &quot;leave&quot;) BLUE) (check-expect (enter? BLUE 10 10 &quot;drag&quot; ) BLUE)&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;&amp;nbsp;- key&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 5&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;;----------function ;-----handler ;;space?: WorldState KeyEvent -&amp;gt; WorldState ;;Check KeyEvent is &quot;space&quot;. (define (space? world a-key)   (cond     [(key=? a-key &quot; &quot;)           YELLOW]     [(= (string-length a-key) 1) world ]     [ else                       world ]))  ;----------fuction test ;-----key (check-expect (space? BLUE &quot; &quot; ) YELLOW) (check-expect (space? BLUE &quot;a&quot; ) BLUE  ) (check-expect (space? BLUE &quot;f1&quot;) BLUE  )&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;&amp;nbsp;- stop&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종료 조건을 확인하는 것으로 현재 world(색) 상태가 빨간색인지 확인하면 됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 6&lt;/p&gt;
&lt;pre class=&quot;openscad&quot;&gt;&lt;code&gt;;----------function ;-----handler ;;RED? WorldSate -&amp;gt; boolean ;;Check WorldState is RED. (define (RED? world)   (equal? RED world))  ;----------fuction test ;-----stop (check-expect (RED? RED ) #true ) (check-expect (RED? BLUE) #false)&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;&amp;nbsp;- draw&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;$$draw = \begin{cases}&lt;br /&gt;원의색, &amp;amp; blue, yellow, green, red \\ \\&lt;br /&gt;world=원의색, &amp;amp; solid \\&lt;br /&gt;world \ne 원의색, &amp;amp; outline \\ \\&lt;br /&gt;원위치, &amp;amp; posn(x,y) \; of \; empty-scene&lt;br /&gt;\end{cases}$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건을 토대로 on-draw의 핸들러 함수인 render를 만들어보겠습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 7&lt;/p&gt;
&lt;pre class=&quot;mel&quot;&gt;&lt;code&gt;;----------function ;-----handler ;;render: WorldState -&amp;gt; image ;;Render scene. (define (render world)   (overlay/align &quot;left&quot; &quot;top&quot;                  (render-circle world BLUE  )                  (render-circle world YELLOW)                  (render-circle world GREEN )                  (render-circle world RED   )                   BACKGROUND))  ;----------fuction test ;-----draw (check-expect (render BLUE)              (overlay/align &quot;left&quot; &quot;top&quot;                             (render-circle BLUE BLUE  )                             (render-circle BLUE YELLOW)                             (render-circle BLUE GREEN )                             (render-circle BLUE RED   )                              BACKGROUND)) (check-expect (render YELLOW)              (overlay/align &quot;left&quot; &quot;top&quot;                             (render-circle YELLOW BLUE  )                             (render-circle YELLOW YELLOW)                             (render-circle YELLOW GREEN )                             (render-circle YELLOW RED   )                              BACKGROUND))&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;BACKGROUND의 좌측 상단을 기준으로 하여 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;render 함수에서 미지의 값은 현재 상태와 원의 색에 따라 그려주는 render-circle입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;render-circle은 posn에 따라 원의 위치를 결정하는 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유의할 점은 원이 있을 좌표를 지정하여 배치할 overlay/xy 함수는 기준점이 필요하다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 반지름의 크기가 0이어서 보이지 않는 원을 만들고 기준점으로 삼을 것입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 8&lt;/p&gt;
&lt;pre class=&quot;openscad&quot;&gt;&lt;code&gt;;----------constant ;-----circle (define zero-circle   (circle 0 &quot;solid&quot; &quot;white&quot;))  ;----------function ;-----draw ;;render-circle: WorldState ncolor -&amp;gt; image ;;Rendering circle with position and shape. (define (render-circle world ncolor)   (overlay/xy zero-circle               (posn-x       (number-&amp;gt;posn ncolor))               (posn-y       (number-&amp;gt;posn ncolor))               (circle-shape world         ncolor)))  ;----------fuction test ;-----draw (check-expect (render-circle BLUE BLUE)  (overlay/xy zero-circle                                                      (posn-x (number-&amp;gt;posn BLUE))                                                      (posn-y (number-&amp;gt;posn BLUE))                                                      (circle-shape BLUE    BLUE))) (check-expect (render-circle RED  BLUE)  (overlay/xy zero-circle                                                      (posn-x (number-&amp;gt;posn BLUE))                                                      (posn-y (number-&amp;gt;posn BLUE))                                                      (circle-shape RED     BLUE)))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원이 그려질 x, y 좌표는 앞서 만들어놓은 START, INPUT, END, ERROR 구조체로부터 가져와야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러려면 숫자로 표현되는 색(현재 world 상태)을 구조체로 변환해주는 number-&amp;gt;posn 함수가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 9&lt;/p&gt;
&lt;pre class=&quot;openscad&quot;&gt;&lt;code&gt;;----------function ;-----draw ;;number-&amp;gt;posn: ncolor -&amp;gt; posn ;;Transition color to posn (define (number-&amp;gt;posn ncolor)   (cond     [(equal? ncolor BLUE  ) START ]     [(equal? ncolor YELLOW) MIDDLE]     [(equal? ncolor GREEN ) END   ]     [(equal? ncolor RED   ) ERROR ]     [ else                  ERROR ]))  ;----------fuction test ;-----draw (check-expect (number-&amp;gt;posn BLUE)   START ) (check-expect (number-&amp;gt;posn YELLOW) MIDDLE) (check-expect (number-&amp;gt;posn GREEN)  END   ) (check-expect (number-&amp;gt;posn RED)    ERROR )&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;number-&amp;gt;posn이 만들어졌으니 원의 모양을 만들어주는 circle-shape 함수를 만들어볼 차례입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 10&lt;/p&gt;
&lt;pre class=&quot;openscad&quot;&gt;&lt;code&gt;;----------function ;-----draw ;;circle-shape: WorldState ncolor -&amp;gt; image ;;Render circle with mode, ncolor. (define (circle-shape world ncolor)   (if (equal? world ncolor)      (circle R &quot;solid&quot;   (number-&amp;gt;ncolor ncolor))      (circle R &quot;outline&quot; (number-&amp;gt;ncolor ncolor))))  ;----------fuction test ;-----draw (check-expect (circle-shape BLUE   BLUE  ) (circle R &quot;solid&quot;   &quot;blue&quot;  )) (check-expect (circle-shape YELLOW YELLOW) (circle R &quot;solid&quot;   &quot;yellow&quot;)) (check-expect (circle-shape GREEN  GREEN ) (circle R &quot;solid&quot;   &quot;green&quot; )) (check-expect (circle-shape RED    RED   ) (circle R &quot;solid&quot;   &quot;red&quot;   )) (check-expect (circle-shape YELLOW BLUE  ) (circle R &quot;outline&quot; &quot;blue&quot;  )) (check-expect (circle-shape GREEN  BLUE  ) (circle R &quot;outline&quot; &quot;blue&quot;  )) (check-expect (circle-shape RED    BLUE  ) (circle R &quot;outline&quot; &quot;blue&quot;  ))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;circle-shape 함수에서는 현재 색(world)과 지정색 원의 색(color)가 같은지 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같다면 채워진(solid), 아니면 비워진(outline)원을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;render-circle때와 마찬가지로 색은 BLUE, YELLOW처럼 숫자로 이루어져 있기 때문에 숫자를 색으로 바꾸어주는 number-&amp;gt;color가 필요하다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 11&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;;----------function ;-----draw ;;number-&amp;gt;color: ncolor -&amp;gt; color ;;Transition ncolor to color (define (number-&amp;gt;color ncolor)   (cond     [(equal? ncolor BLUE  ) &quot;blue&quot;  ]     [(equal? ncolor YELLOW) &quot;yellow&quot;]     [(equal? ncolor GREEN ) &quot;green&quot; ]     [(equal? ncolor RED   ) &quot;red&quot;   ]     [ else                  &quot;red&quot;   ]))  ;----------fuction test ;-----draw (check-expect (number-&amp;gt;color BLUE  ) &quot;blue&quot;  ) (check-expect (number-&amp;gt;color YELLOW) &quot;yellow&quot;) (check-expect (number-&amp;gt;color GREEN ) &quot;green&quot; ) (check-expect (number-&amp;gt;color RED   ) &quot;red&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;한번 실행을 시켜볼까요?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 12&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;;----------big-bang test (4state-trans BLUE)&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;&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Code 4.7 - 전체&lt;/p&gt;
&lt;pre class=&quot;openscad&quot;&gt;&lt;code&gt;;-------------------------Code 4.7------------------------- ;----------constant ;-----background (define WIDTH  200) (define HEIGHT 200) (define BACKGROUND (empty-scene WIDTH HEIGHT))  ;-----circle (define R 20) (define zero-circle   (circle 0 &quot;solid&quot; &quot;white&quot;))  ;;ncolor (define BLUE   0) (define YELLOW 1) (define GREEN  2) (define RED    3)  ;;posn (define START   (make-posn 80  0  )) ;;100 50 (define MIDDLE   (make-posn 160 50 )) ;;150 100 (define END   (make-posn 80  100)) ;;100 150 (define ERROR   (make-posn 0   50 )) ;;50  100  ;----------function ;-----draw ;;number-&amp;gt;posn: ncolor -&amp;gt; posn ;;Transition ncolor to posn (define (number-&amp;gt;posn ncolor)   (cond     [(equal? ncolor BLUE  ) START ]     [(equal? ncolor YELLOW) MIDDLE]     [(equal? ncolor GREEN ) END   ]     [(equal? ncolor RED   ) ERROR ]     [ else                  ERROR ]))  ;;number-&amp;gt;color: ncolor -&amp;gt; color ;;Transition ncolor to color (define (number-&amp;gt;color ncolor)   (cond     [(equal? ncolor BLUE  ) &quot;blue&quot;  ]     [(equal? ncolor YELLOW) &quot;yellow&quot;]     [(equal? ncolor GREEN ) &quot;green&quot; ]     [(equal? ncolor RED   ) &quot;red&quot;   ]     [ else                  &quot;red&quot;   ]))  ;;circle-shape: WorldState ncolor -&amp;gt; image ;;Render circle with mode, ncolor. (define (circle-shape world ncolor)   (if (equal? world ncolor)      (circle R &quot;solid&quot;   (number-&amp;gt;ncolor ncolor))      (circle R &quot;outline&quot; (number-&amp;gt;ncolor ncolor))))  ;;render-circle: WorldState ncolor -&amp;gt; image ;;Rendering circle with position and shape. (define (render-circle world ncolor)   (overlay/xy zero-circle               (posn-x       (number-&amp;gt;posn ncolor))               (posn-y       (number-&amp;gt;posn ncolor))               (circle-shape world         ncolor)))  ;-----handler ;;render: WorldState -&amp;gt; image ;;Render scene. (define (render world)   (overlay/align &quot;left&quot; &quot;top&quot;                  (render-circle world BLUE  )                  (render-circle world YELLOW)                  (render-circle world GREEN )                  (render-circle world RED   )                   BACKGROUND))  ;;next-color: WorldState -&amp;gt; WorldState ;;Transition next state. (define (next-color world)   (if (equal? world RED)   RED (remainder (+ world 1) 3)))  ;;enter?: WorldState integer integer MolibraryEvent -&amp;gt; WorldState ;;Check MouseEvent is &quot;enter&quot;. (define (enter? world x y a-mouse)   (if (mouse=? a-mouse &quot;enter&quot;)      RED world))  ;;space?: WorldState KeyEvent -&amp;gt; WorldState ;;Check KeyEvent is &quot;space&quot;. (define (space? world a-key)   (cond     [(key=? a-key &quot; &quot;)           YELLOW]     [(= (string-length a-key) 1) world ]     [ else                       world ]))  ;;RED? WorldSate -&amp;gt; boolean ;;Check WorldState is RED. (define (RED? world)   (equal? RED world))  ;----------big-bang ;;4state-trans: WorldState -&amp;gt; image ;;4 color's circle transition. (define (4state-trans ncolor)   (big-bang ncolor     [to-draw   render      ]     [on-tick   next-color 1]     [on-mouse  enter?      ]     [on-key    space?      ]     [stop-when RED?        ]))  ;-------------------------Test 4.7------------------------- ;----------fuction test ;-----draw (check-expect (number-&amp;gt;posn BLUE)   START ) (check-expect (number-&amp;gt;posn YELLOW) MIDDLE) (check-expect (number-&amp;gt;posn GREEN)  END   ) (check-expect (number-&amp;gt;posn RED)    ERROR )  (check-expect (number-&amp;gt;color BLUE  ) &quot;blue&quot;  ) (check-expect (number-&amp;gt;color YELLOW) &quot;yellow&quot;) (check-expect (number-&amp;gt;color GREEN ) &quot;green&quot; ) (check-expect (number-&amp;gt;color RED   ) &quot;red&quot;   )  (check-expect (circle-shape BLUE   BLUE  ) (circle R &quot;solid&quot;   &quot;blue&quot;  )) (check-expect (circle-shape YELLOW YELLOW) (circle R &quot;solid&quot;   &quot;yellow&quot;)) (check-expect (circle-shape GREEN  GREEN ) (circle R &quot;solid&quot;   &quot;green&quot; )) (check-expect (circle-shape RED    RED   ) (circle R &quot;solid&quot;   &quot;red&quot;   )) (check-expect (circle-shape YELLOW BLUE  ) (circle R &quot;outline&quot; &quot;blue&quot;  )) (check-expect (circle-shape GREEN  BLUE  ) (circle R &quot;outline&quot; &quot;blue&quot;  )) (check-expect (circle-shape RED    BLUE  ) (circle R &quot;outline&quot; &quot;blue&quot;  ))  (check-expect (render-circle BLUE BLUE)  (overlay/xy zero-circle                                                      (posn-x (number-&amp;gt;posn BLUE))                                                      (posn-y (number-&amp;gt;posn BLUE))                                                      (circle-shape BLUE    BLUE))) (check-expect (render-circle RED  BLUE)  (overlay/xy zero-circle                                                      (posn-x (number-&amp;gt;posn BLUE))                                                      (posn-y (number-&amp;gt;posn BLUE))                                                      (circle-shape RED     BLUE)))  (check-expect (render BLUE)              (overlay/align &quot;left&quot; &quot;top&quot;                             (render-circle BLUE BLUE  )                             (render-circle BLUE YELLOW)                             (render-circle BLUE GREEN )                             (render-circle BLUE RED   )                              BACKGROUND)) (check-expect (render YELLOW)              (overlay/align &quot;left&quot; &quot;top&quot;                             (render-circle YELLOW BLUE  )                             (render-circle YELLOW YELLOW)                             (render-circle YELLOW GREEN )                             (render-circle YELLOW RED   )                              BACKGROUND))  ;-----tick (check-expect (next-color BLUE  ) YELLOW) (check-expect (next-color YELLOW) GREEN ) (check-expect (next-color GREEN ) BLUE  ) (check-expect (next-color RED   ) RED   )  ;-----mouse (check-expect (enter? BLUE 10 10 &quot;enter&quot;) RED ) (check-expect (enter? BLUE 10 10 &quot;leave&quot;) BLUE) (check-expect (enter? BLUE 10 10 &quot;drag&quot; ) BLUE)  ;-----key (check-expect (space? BLUE &quot; &quot; ) YELLOW) (check-expect (space? BLUE &quot;a&quot; ) BLUE  ) (check-expect (space? BLUE &quot;f1&quot;) BLUE  )  ;-----stop (check-expect (RED? RED ) #true ) (check-expect (RED? BLUE) #false)  ;----------big-bang test (4state-trans BLUE)&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;특히, draw쪽 코드를 살펴보면 몇가지 배울점을 발견할 수 있습니다.&lt;/p&gt;
&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. number-&amp;gt;posn과 number-&amp;gt;color&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 ncolor를 color로 변환하는 함수며, 비슷한 형태로 구현하였습니다.&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. 모으기[행 단위]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;draw의 최종 목적인 render-circle을 보면 number-&amp;gt;color, circle-shape 순으로 등장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 render-circle의 바로위에 number-&amp;gt;color, circle-shape 순으로 배열하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;circle-shape에서 새로 등장하는 number-&amp;gt;posn은 render-circle과 거리가 언급한 2함수에 비하면 멀기 때문에 더 위에 배치하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 코드를 배치하다 보니 위에 있는 posn, ncolor, circle과 대칭이 되는 구조가 우연히 만들어져서 한층 읽기 편해졌습니다.&lt;/p&gt;
&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;3. &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%9C%A0%ED%95%9C_%EC%83%81%ED%83%9C_%EA%B8%B0%EA%B3%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;유한 상태 기계(finite-state machine, FSM)&lt;/a&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;이러한 기계는 한 번에 오로지 하나의 상태만을 가지게 되며, 현재 상태(Current State)란 임의의 주어진 시간의 상태를 칭한다.[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;유한 상태 기계는 크게 무어 모델(Moore model)과 밀리 모델(Mealy model)로 나뉠 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;div&gt;무어 모델은 현재 상태들로만 결정이 된다.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;밀리 모델은 현재 상태 + 입력으로 결정이 된다.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&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초마다 B-&amp;gt;Y-&amp;gt;G-&amp;gt;B-&amp;gt;...같이 현재 상태로만 결정이 되었다면 무어 모델지만, 키보드 이벤트 &quot; &quot;나 마우스 이벤트 &quot;enter&quot;과 같은 입력에도 영향을 받았으니 밀리 모델입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유한 상태 모델은 Chapter2 부록에서 정규 표현식과 함께 조금 더 다루어보도록 하겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;+.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;posn은 position의 약어(abbreviation)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 쓰기에는 긴 단어일 때 약어(abbreviation)나 두문자어(acronym)로 작명을 하면 된다.&lt;/p&gt;
&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;방금 전의 position -&amp;gt; posn. 이나 corporated -&amp;gt; Corp. building -&amp;gt; bldg. 같은 예가 있다.&lt;/p&gt;
&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;F&amp;eacute;d&amp;eacute;ration Internationale de Football Association -&amp;gt; FIFA, Acquired Immune Deficiency Syndrome -&amp;gt; AIDS 같은 예가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FIFA는 프랑스어라고 한다.&lt;/p&gt;
&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;h4 data-ke-size=&quot;size20&quot;&gt;+++.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;;----------library 후에 라이브러리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;;----------constant 후에 상수.&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;;----------function test 후에 함수 테스트 등으로&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;pre class=&quot;cal&quot;&gt;&lt;code&gt;program 프로그램이름;     // 이 소스코드가 프로그램이라는것을 의미한다. label                     // Goto문의 지표가 된다.   지표1, 지표2;  uses                      // 외부유닛의 참조목록이다.   유닛1, 유닛2;  type                      // 자료형 선언부이다.   형명칭: 자료형;  var                       // 변수 선언부이다.   변수명: 자료형;  const                     // 상수 선언부이다.   상수명=상수값;    procedure 프로시저이름; // 프로시저를 만들었다.   begin                   // 시작     명령;   end;                    // 끝 - 프로시저  begin                     // 시작   프로시저이름;   명령;                   // end의 앞에는 원칙적으로는 ;이 오면 안된다. 이 문제는 나중에 다룬다. end.                      // 끝 - 프로그램&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;파스칼 소스코드 구조 [from &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikibooks.org/wiki/%ED%8C%8C%EC%8A%A4%EC%B9%BC_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%EA%B8%B0%EB%B3%B8%EC%84%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;wikibooks&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;대신 유연성이 떨어진다는 단점이 존재합니다.(C언어와 비교.)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 섹션4 후기.&lt;/h2&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 어려워서 못 따라오겠다면 다시 섹션 2, 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;섹션 4까지의 내용을 이해할 수 있는 독자라면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://black7375.tistory.com/6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2017/06/30 - [프로그래밍/설계] - 프로그래밍과 추상화에 대하여.&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;프로그래밍을 '추상화'라는 관점으로 쭉 해석해놓은 것입니다.&lt;/p&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;/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;454&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://t1.daumcdn.net/cfile/tistory/99B2A4395B22909431?original&quot; data-phocus=&quot;https://t1.daumcdn.net/cfile/tistory/99B2A4395B22909431?original&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B2A4395B22909431&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B2A4395B22909431&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;454&quot; height=&quot;454&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;454&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;또 후반에 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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조.&amp;nbsp; &lt;a class=&quot;tx-link&quot; href=&quot;https://docs.racket-lang.org/teachpack/2htdpimage.html?q=2htdp%2Fimage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;image&lt;/a&gt;&amp;amp;&lt;a class=&quot;tx-link&quot; href=&quot;https://docs.racket-lang.org/teachpack/2htdpuniverse.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;universe&lt;/a&gt;(racket-lang), &lt;a class=&quot;tx-link&quot; href=&quot;https://ko.wikipedia.org/wiki/%EC%9C%A0%ED%95%9C_%EC%83%81%ED%83%9C_%EA%B8%B0%EA%B3%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;유한 상태 기계(Wikipedia)&lt;/a&gt;&lt;/p&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini&quot; class=&quot;s3gt_translate_tooltip_mini_box&quot; style=&quot;background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 349px; top: 13834px; opacity: 0.65;&quot;&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_logo&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Translate selected text&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_sound&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Play&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_copy&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Copy text to Clipboard&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini&quot; class=&quot;s3gt_translate_tooltip_mini_box&quot; style=&quot;background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 800px; top: 16951px; opacity: 0.85;&quot;&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_logo&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Translate selected text&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_sound&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Play&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_copy&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Copy text to Clipboard&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini&quot; class=&quot;s3gt_translate_tooltip_mini_box&quot; style=&quot;background: initial !important; border: initial !important; border-radius: initial !important; border-spacing: initial !important; border-collapse: initial !important; direction: ltr !important; flex-direction: initial !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; min-width: initial !important; max-width: initial !important; min-height: initial !important; max-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; table-layout: initial !important; text-align: initial !important; text-shadow: initial !important; width: initial !important; word-break: initial !important; word-spacing: initial !important; overflow-wrap: initial !important; box-sizing: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; position: absolute; left: 270px; top: 26000px; opacity: 0.6;&quot;&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_logo&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Translate selected text&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_sound&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Play&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;s3gt_translate_tooltip_mini_copy&quot; class=&quot;s3gt_translate_tooltip_mini&quot; title=&quot;Copy text to Clipboard&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&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>Racket</category>
      <category>강좌</category>
      <category>설계</category>
      <category>프로그래밍</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/36</guid>
      <comments>https://black7375.tistory.com/36#entry36comment</comments>
      <pubDate>Tue, 29 May 2018 18:31:45 +0900</pubDate>
    </item>
    <item>
      <title>어플리케이션 흐름의 구조와 분석.</title>
      <link>https://black7375.tistory.com/35</link>
      <description>&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;우리들은 수많은 서비스와 정보들의 홍수 속에서 살아가고 있다.&lt;p&gt;난 소비자로서 좋은 서비스에 대한 선택과 고민을 해왔고, 또 만들고 싶은 프로그램에 대한 고민을 해왔다.&lt;/p&gt;&lt;p&gt;그리고 이제 그 해답에 대한 갈피를 조금이나마 잡은 듯하다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이상적인 제품에 대한 계획(?)같은 해석에 관한 것은 추후 내가 만들어보고 싶어서 빠졌지만, &lt;/p&gt;&lt;p&gt;이 글을 통하여 각종 어플리케이션들이 차지하는 위치와 구조에 대하여 설명하고자 한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 class=&quot;&quot;&gt;1. 구조(Structure)와 사상하는 프로그램.&lt;/h2&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999F5F365C5C113813&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999F5F365C5C113813&quot; width=&quot;800&quot; height=&quot;450&quot; filename=&quot;슬라이드6.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;다양한 서비스와 어플리케이션들을 사용해보고 해당 어플리케이션의 본질에 대하여 한 문장씩 정리해보았다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;그 후 카테고리 별로 정리를 하였다.&lt;/p&gt;&lt;h3&gt;1.1 입력(Input).&lt;br /&gt;&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;정보를 저장전에 사용됨.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;입력: 정보를 저장하기 위해 받아들임.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(내부)&lt;/div&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;div&gt;내부 컨텐츠: 공유(SNS)등 내부 계정들을 통한 정보, Create에서 생성되는 정보 등.&lt;br /&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(외부)&lt;/div&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;외부 컨텐츠: Mail이나 타사 서비스들.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;카메라: 이미지 입력.&lt;/li&gt;&lt;li&gt;IME: 글자 입력 .&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3 class=&quot;&quot;&gt;1.2 저장(Store).&lt;/h3&gt;&lt;p&gt;정보를 활용하기 위해 저장.&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;메모: 현재의 정보를 미래로 전달.&lt;/h4&gt;&lt;p&gt;(시간)&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;시계: 시간을 보여줌, 시간에 따른 알람, 스톱워치, 타이머.&lt;/li&gt;&lt;li&gt;달력: 달력과 그에 따른 일정을 보여줌.&lt;/li&gt;&lt;li&gt;일정: 일정을 시간 또는 내용으로 표시.&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_35_1&quot; id=&quot;footnote_link_35_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 35, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(35, 1)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;(정보)&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;서지관리: 메타데이터를 이용한 레퍼런스(출처) 관리.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Read it Later: 북마크와 클리핑.&lt;/li&gt;&lt;li&gt;노트: 간단한 서식의 글, 그림, 표등을 표현.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;드로잉: 펜이나 붓같은 느낌이 나는 도구로 그림을 그림.&lt;/li&gt;&lt;li&gt;스티키 노트: 위젯 형태로 보여줌.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;기타: 사진, 영상, 음성등의 데이터로 남기는 모든 행위.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;클라우드: 정보를 다른 곳에서 쓸 수 있게 처리.&lt;/h4&gt;&lt;p&gt;(저장)&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;주소록: 주소 저장 및 관리.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;드라이브: 파일 저장 및 관리.&lt;/li&gt;&lt;li&gt;VCS: 버전 관리.&lt;/li&gt;&lt;li&gt;백업: 정보들을 백업.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 class=&quot;&quot;&gt;1.3 창조(Create).&lt;/h3&gt;&lt;p&gt;저장된 정보를 이용하여 새로운 정보를 만들어냄.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;마인드맵: 정보를 연결하고 관계를 지음.&lt;/b&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;(리스트): 순서대로 정렬함. 정보에 변형이 없다는 것이 특징.&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;마크 업: 정보를 써내려 가며 강조함.&lt;/li&gt;&lt;li&gt;워드프로세서: 문서 작성(종이나 인쇄를 목적)&lt;/li&gt;&lt;li&gt;프레젠테이션: 발표용 문서 작성(디지털 목적)&lt;/li&gt;&lt;li&gt;웹브라우저: 웹문서 보기.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;(합성 or 연산): 정보를 합침. 상쇄 및 보간간섭, 가산 및 감산혼합과 같이 일반적인 정보를 합칠 수도 있고, 크기 조절이나 주파수 변조처럼 추상적인 성질을 합칠 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;계산기: 수를 계산.&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;스프레드 시트: 정보를 쉽게 정리.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;수치해석: 해의 근삿값을 구해줌.&lt;/li&gt;&lt;li&gt;Computer Algebra System(CAS): 전통적인 대수학을 푸는 것처럼 값을 구함.&lt;/li&gt;&lt;li&gt;DB: 정보 체계화 및 관리.&lt;/li&gt;&lt;/ul&gt;&lt;li class=&quot;&quot;&gt;통계: 수량적인 비교로 분석.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;비트맵: 픽셀을 기준으로 다루기.&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;편집: 사진이나 그래픽에 그래픽 처리를 위한 것.&lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;보정: 화이트밸런스, 노출값등 카메라에서 지원하는 요소들을 수정.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;페인팅: 브러시를 사용해 그림.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li class=&quot;&quot;&gt;벡터: 색상과 위치 속성등을 이용함.&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;일러스트: 2D 그래픽 도구.&lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;CAD: 정밀한 설계를 위한 것.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;기타 3D 프로그램: 폴리곤, 넙스, 서브디비전 등.&lt;/li&gt;&lt;/ul&gt;&lt;li class=&quot;&quot;&gt;DAW: 오디오의 레코딩, 편집등.&lt;/li&gt;&lt;li class=&quot;&quot;&gt;기타 이미지, 음성, 영상처리.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;b&gt;컨텐츠: 각종 결과물.&lt;/b&gt;&lt;p&gt;책, 영화, UCC, 사진 등으로 불리는 것들.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.4 전달(Trans).&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;디지털 세계 내외부로 전달함.&lt;/p&gt;&lt;p&gt;&lt;b&gt;내부&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;(공유)&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;메신저: 정보를 단위매체(텍스트, 사진 등)로 다른 사람이나 그룹에게 전달하고 받음.&lt;/li&gt;&lt;li&gt;블로그: 정보를 자신 또는 불특정 다수의 사람들에게 보여줌.&lt;/li&gt;&lt;li&gt;SNS: 정보를 가깝거나 비슷한 그룹의 사람들과 주고 받음.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;커뮤니티: 정보를 불특정 다수의 사람들에게 주고 받음.&lt;/li&gt;&lt;li&gt;카페: 대형 포털에서 제공하는 커뮤니티 서비스.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;위키: 정보를 다수의 사람들이 수정 가능하고 공유.&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot;&gt;-&amp;gt; 권한의 문제.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;외부&lt;/b&gt;&lt;/p&gt;&lt;div&gt;(출력)&lt;/div&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;알림: 신호를 전달.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;div class=&quot;&quot;&gt;뷰어 or 플레이어: 디스플레이로.&lt;/div&gt;&lt;/li&gt;&lt;li&gt;프린터: 종이로 ..etc&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;원래 형태는&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/995535375C5930DF17&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F995535375C5930DF17&quot; width=&quot;800&quot; height=&quot;450&quot; filename=&quot;슬라이드1.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;와 같았는데 입력에 해당하는 기능들이 많아 편의를 위해, 분산을 위하여 분리하였음.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;1.5 자동화(Automation).&lt;/h3&gt;&lt;p class=&quot;&quot;&gt;위의 과정을 자동적으로 순환시켜줌.&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;매크로: 몇가지 정해진 절차를 실행.&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;RPA: 체계적으로 프로그래밍한 매크로.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;AI: 자동으로 매크로(또는 함수등)를 만들기 위한 것.[Meta Macro]&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;그 후 핵심적인 기능들에 대한 관계도를 처음과 같이 만들었다.&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 class=&quot;&quot;&gt;2. 구조 분석.&lt;/h2&gt;&lt;p&gt;이 파트에서는 어플리케이션 흐름에 대하여 집중적으로 설명한다.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.1 전반적인 구조.&lt;br /&gt;&lt;/h3&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99BB5D4B5C5930DF21&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99BB5D4B5C5930DF21&quot; width=&quot;800&quot; height=&quot;450&quot; filename=&quot;슬라이드3.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot; class=&quot;&quot;&gt;우선 정보가 돌아가는 전반적인 구조에 대해 생각해보자.&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;디지털을 다루는 가장 원초적인 언어인 &lt;a href=&quot;http://infocenter.arm.com/help/topic/com.arm.doc.dui0204ik/index.html&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;어셈블리&lt;/a&gt;를&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_35_2&quot; id=&quot;footnote_link_35_2&quot; onmouseover=&quot;tistoryFootnote.show(this, 35, 2)&quot; onmouseout=&quot;tistoryFootnote.hide(35, 2)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;2&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_35_3&quot; id=&quot;footnote_link_35_3&quot; onmouseover=&quot;tistoryFootnote.show(this, 35, 3)&quot; onmouseout=&quot;tistoryFootnote.hide(35, 3)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;3&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt; 생각해보면 정보는 입ㆍ출력(Import ㆍ Export), 메모리 접근(Memory Access), 데이터 처리(Data Processing), 분기(Branch) 정도로 나뉠 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;어플리케이션도 디지털 정보를 다루기 위한 SW이고, 사람 인지능력의 한계 때문에 각자 '특화'된 영역이 존재하게 된다.&lt;/p&gt;&lt;p&gt;따라서 전체 구조를 보면 마치 프렉탈처럼 대응되도록 분야가 나뉘어지게 된다.&lt;/p&gt;&lt;p&gt;때문에 이 구조에서 벗어나기가 어렵다고 생각한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;입출력=&amp;gt;Trans&lt;br /&gt;&lt;code class=&quot;arm&quot;&gt;EXPORT&lt;/code&gt;된 정보를 &lt;code class=&quot;arm&quot;&gt;IMPORT&lt;/code&gt;하는 것처럼 정보를 입력받고(Input), 디지털 세계 내외부로 전달(Trans)&lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;메모리접근=&amp;gt; Store&lt;br /&gt;&lt;code class=&quot;arm&quot;&gt;STR&lt;/code&gt;, &lt;code class=&quot;arm&quot;&gt;LDR&lt;/code&gt;처럼 저장&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_35_4&quot; id=&quot;footnote_link_35_4&quot; onmouseover=&quot;tistoryFootnote.show(this, 35, 4)&quot; onmouseout=&quot;tistoryFootnote.hide(35, 4)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;4&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;한다.&lt;br /&gt;&lt;/li&gt;&lt;li class=&quot;&quot;&gt;데이터 처리=&amp;gt; Create&lt;br /&gt;&lt;code class=&quot;arm&quot;&gt;ADD&lt;/code&gt;, &lt;code class=&quot;arm&quot;&gt;MOV&lt;/code&gt;처럼 연산하거나 옮기는 등의 작업을 하여 새로운 정보를 만들어낸다.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;분기=&amp;gt; Automation&lt;br /&gt;&lt;code class=&quot;arm&quot;&gt;MACRO&lt;/code&gt;, &lt;code class=&quot;arm&quot;&gt;IF&lt;/code&gt;처럼 어떤 작업 도와주거나 특정조건시 행동을 하도록 해줌.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot;&gt;또는 MVC 모델처럼 Model=&amp;gt;Store, View=&amp;gt;Trans, Controller=&amp;gt;Create로 치환할 수도 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;실제로 카테고리 정리 후 마지막으로 추상화단계를 거칠때 두개 다에서 조금씩 영감을 받았다.&lt;/p&gt;&lt;p&gt;사실 촘스키 언어 계층을 이용해 튜링머신과 관련해서 쓰고 싶었으나 좀 귀찮아서..&lt;/p&gt;&lt;p&gt;만약 학사 논문을 작성하게 되면 수직계열화 또는 어플리케이션과 오토마타 관련해서 써볼까 생각중이긴 한디..&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.2 심층적인 구조.&lt;br /&gt;&lt;/h3&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;각 모듈별로 조금 더 자세히 살펴보도록 합시다.&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;역시 관리의 편의성을 위해&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 800px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99533E375C5930DF13&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99533E375C5930DF13&quot; width=&quot;800&quot; height=&quot;450&quot; filename=&quot;슬라이드4.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;Input을 분리하였다.&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;&lt;b&gt;2.2.1 Input.&lt;/b&gt;&lt;/h4&gt;&lt;p&gt;내부에서 생성된 정보를 받아들이는 In, 외부의 정보를 받아들이는 Out으로 나뉘어져 있다.&lt;/p&gt;&lt;p&gt;내부라는 것은 하나의 계(System) 안에서 내부를 뜻하는 것으로, 계정 또는 서비스를 기준으로 삼을 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;위에서도 썼듯이 각각에서 대표적인 프로그램은&lt;/div&gt;&lt;div class=&quot;&quot;&gt;&lt;b&gt;In:&lt;/b&gt; 뉴스피드나 새글 목록 같은 구독 프로그램&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;out:&lt;/b&gt; 카메라, IME(입력기), 외부 서비스(사용중인 계정이 구글이라면 MS 계정은 외부 서비스가 된다.)&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.2.2 Store.&lt;br /&gt;&lt;/h4&gt;&lt;p class=&quot;&quot;&gt;아마 가장 고민이 많았던 파트가 아닐까 싶다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;말이 Time과 Space로 나뉘어져 있지 저 둘은 위에서 보면 알 수 있듯 메모와 클라우드의 속성을 그대로 옮겨놓은 것이다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;클라우드가 메모보다 상위의 개념에 속하지 않냐고 물을 수 있는데, 아니다.(단호)&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;메모는 정보를 &lt;b&gt;미래로 전달&lt;/b&gt;하는 것이 목적이고, 아날로그 데이터는 물론 단순한 텍스트 파일, 이미지, 영상 등 형태를 가리지 않고 미래로 정보가 전달된다는 조건만 맞으면 된다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;반면 클라우드는 네트워크에 연결된 &lt;b&gt;다른 장치를 이용해 저장&lt;/b&gt;하는 것으로 정보를 전달하려는 순간 이미 시간에 종속적이며(광속에 가깝다 하더라도 약간의 시간이 필요), 또 다른 컴퓨터라는 공간이 필요하다.&lt;/p&gt;&lt;p&gt;물리학적으로 메모는 시간에만 종속적이만 클라우드는 시공간에 종속적이므로 메모는 클라우드보다 추상화된 개념일 수 밖에 없다는 뜻이다. 하이데거 존재와 시간 같은 것을 보아도 마찬가지다. 존재와 실존은 시간 속에 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;설사 미래에 양자 얽힘과 같은 것을 이용해 시간의 제약을 깬다고 하더라도 공간은 가역적이지만 시간은 비가역적인 성질 때문에 상위에 속한 개념일 수밖에 없다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;메모와 클라우드의 개념은 시공간이란 가장 높은 추상화가 이루어져 있는 단계이므로 어떤 서비스에서든 사용이 되고 &lt;b&gt;가장 핵심이 되는 중요한 서비스&lt;/b&gt;라 생각한다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;여기에서 또 드는 의문은 각종 SW나 정보들은 오프라인 환경에서도 사용할 수 있는데 어떻게 Space가 클라우드냐는 생각이 들 수 있다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이에 대한 간단한 대답은 인간의 뇌를 컴퓨터로 취급하고 사람이 컴퓨터와 상호작용을 한다면 오프라인 상태의 컴퓨터와 네트워크로 연결이 된 상태로 볼 수 있다.&lt;/p&gt;&lt;p&gt;'인터넷 망 네트워크'가 아니라&amp;nbsp; '데이터 관점의 네트워크'라는 것이다. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;클라우드 계열에 속하는 프로그램중 아주 재미있는 것이 있다.&lt;/p&gt;&lt;p&gt;Git이나 SVN 같은 VCS(Version Control System)이다.&lt;/p&gt;&lt;p&gt;시간의 특성을 제대로 보여주는 것 중의 하나인데, 시간이 흐른다는 것은 무엇일까?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;바로 상태가 변했다는 것, 상호작용이 이루어졌다는 것 자체이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위키 서비스를 운영 중인데 10명의 사람이 편집한다고 해보자.&lt;/p&gt;&lt;p&gt;1년이 지났어도 여전히 10명의 사람만이 편집한다고 해서 시간이 흐르지 않은 걸까?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위키내부의 문서가 바뀌고, 각종 토론 내역 같은게 있으니 계(System)의 상태는 과거와 다르다.&lt;/p&gt;&lt;p&gt;반면, 10년동안 모두가 아무 활동이 없었다고 하다면 계의 상태는 과거와 같다고 할 수 있다.&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_35_5&quot; id=&quot;footnote_link_35_5&quot; onmouseover=&quot;tistoryFootnote.show(this, 35, 5)&quot; onmouseout=&quot;tistoryFootnote.hide(35, 5)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;5&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;VCS는 상호작용 내역을 저장해 과거 버전과 오고가고 하여 시간의 비가역성을 일부 극복해낸 프로그램이다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;어쨌든 클라우드 서비스는 사람이 특별히 인지하지 않아야 이상적인 서비스지만 메모는 사람이 인지하도록 만들어야 한다는 것도 그렇고.. 메모와 클라우드는 서로 상호의존적인 관계이다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;그래서 오피스 솔루션이 없던 드롭박스, 박스와 같은 클라우드 플랫폼도 메모 사업에 뛰어드는 경우가 많다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;img src=&quot;https://aem.dropbox.com/cms/content/dam/dropbox/blog/files/2016/10/paper-fol2-notifications.jpg&quot; aria-hidden=&quot;false&quot; class=&quot;a09-image__img&quot; title=&quot;&quot; style=&quot;&quot; width=&quot;auto&quot; height=&quot;auto&quot;&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://pjrjx47372.i.lithium.com/t5/image/serverpage/image-id/9095iBF12917A431F3554/image-size/large?v=1.0&amp;amp;px=999&quot; alt=&quot;Screen Shot 2017-11-27 at 3.58.40 PM.png&quot; title=&quot;Screen Shot 2017-11-27 at 3.58.40 PM.png&quot; class=&quot;lia-media-image&quot; tabindex=&quot;0&quot;&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;a href=&quot;https://blog.dropbox.com/topics/work-culture/get-on-the-same-page-with-dropbox-paper&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Dropbox 블로그&lt;/a&gt;와 &lt;a href=&quot;https://community.box.com/t5/Creating-and-Editing-Box-Notes/Introduction-to-Box-Notes/ta-p/325&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Box 커뮤니티&lt;/a&gt;에서 가져왔다.&lt;br /&gt;&lt;/p&gt;&lt;h4 class=&quot;&quot;&gt;2.2.3 Create.&lt;/h4&gt;&lt;p&gt;자료를 연결하여 새로운 가치를 창출하는 포지션이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;자료의 연결은 크게 두가지 형태로 나뉘어지는데&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;원자료의 값이 출력시 그대로 반영되는 리스트&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_35_6&quot; id=&quot;footnote_link_35_6&quot; onmouseover=&quot;tistoryFootnote.show(this, 35, 6)&quot; onmouseout=&quot;tistoryFootnote.hide(35, 6)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;6&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;예.&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;리스트 인자1&lt;/li&gt;&lt;li&gt;리스트 인자2&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot;&gt;와 출력시 달라지는 함수형태&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;예.&lt;/b&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;$$function(함수 인자1, 함수 인자2)$$&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 저 둘을 포함하는 추상적인 연결의 형태.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;인자1 - 인자2&lt;/b&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_35_7&quot; id=&quot;footnote_link_35_7&quot; onmouseover=&quot;tistoryFootnote.show(this, 35, 7)&quot; onmouseout=&quot;tistoryFootnote.hide(35, 7)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;7&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;가 나올 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이 세개의 구조로 특화된 프로그램이 마인드맵(추상적 연결), 마크업 언어(리스트), 계산기(함수)다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;2.2.4 Trans&lt;br /&gt;&lt;/h4&gt;&lt;div&gt;&lt;p class=&quot;&quot;&gt;말 그대로 전달을 하는데 특화가 된 모듈이다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;대표적인 것이 바로 메신저류 서비스인데 메모가 되어 있던 내용들을 전달하는데 의미를 가진다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;재미있는 것은 메모와 권한(유저끼리)의 차이일 뿐이지, 그다지 차이는 없다.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 컨텐츠 구조.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;&lt;p class=&quot;&quot;&gt;우선 &lt;b&gt;컨텐츠 구조&lt;/b&gt;&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_35_8&quot; id=&quot;footnote_link_35_8&quot; onmouseover=&quot;tistoryFootnote.show(this, 35, 8)&quot; onmouseout=&quot;tistoryFootnote.hide(35, 8)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;8&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;를 보자.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;table class=&quot;txc-table&quot; style=&quot;border:none;border-collapse:collapse;;font-family:&quot; width=&quot;764&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;;&quot;&gt;&lt;p&gt;최상위 &lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;;&quot;&gt;&lt;p&gt;구분 &lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;;&quot;&gt;&lt;p&gt;묶음 &lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;;&quot;&gt;&lt;p&gt;단위 &lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;메모&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;프로젝트&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;보드(섹션)&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;노트(페이지) 그룹&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;노트(페이지)&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;메신저&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;대화방&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;채널&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p class=&quot;&quot;&gt;&amp;nbsp;연관 또는 답 메세지&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;메세지&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;블로그&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;카테고리&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;매거진&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;챕터&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;포스트&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width: 152px; height: 52px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204); border-left: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;SNS&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 52px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;뉴스피드&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 52px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;계정, 그룹, 페이지등의 뉴스피드&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 52px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;연관 포스트, 리블로그&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 52px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;포스트&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;카페&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;게시판&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;카테고리&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;답글&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;글&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width: 152px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204); border-left: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;커뮤니티&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;게시판&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;카테고리&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;답글&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;글&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width: 152px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204); border-left: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;위키&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;위키&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;분류&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p class=&quot;&quot;&gt;&amp;nbsp;틀, 관련문서&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 152px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;&amp;nbsp;문서&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot; rowspan=&quot;1&quot;&gt;&amp;nbsp;설명&lt;/td&gt;&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot; rowspan=&quot;1&quot;&gt;&lt;p&gt;&amp;nbsp;작업을 위한 묶음.&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot; rowspan=&quot;1&quot;&gt;&lt;p&gt;&amp;nbsp;폴더와 같이 내용이 없는 것으로 구분.&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot; rowspan=&quot;1&quot;&gt;&lt;p class=&quot;&quot;&gt;&amp;nbsp;링크나 하위문서등 문서를 기준으로 묶인 그룹.&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:152;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot; rowspan=&quot;1&quot;&gt;&amp;nbsp;사용자가 보는 문서.&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p class=&quot;&quot;&gt;보다시피 세부적인 것이 다를뿐 규격은 거의 호환이 된다.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;이를 가장 잘 활용하는 서비스가 페이스북.&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;SNS -&amp;gt; 담벼락(타임라인)&lt;/li&gt;&lt;li&gt;메신저 -&amp;gt; 페이스북 메신저&lt;/li&gt;&lt;li&gt;블로그 -&amp;gt; 페이지&lt;/li&gt;&lt;li&gt;카페 -&amp;gt; 그룹&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;SNS(마이크로 블로그)가 아니라 커뮤니티 중심인 서비스로는 &lt;a href=&quot;https://www.discourse.org/&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Discourse&lt;/a&gt;가 좋은 예.&lt;br /&gt;&lt;/div&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;div&gt;블로그 -&amp;gt; 구글 Blogger나 워드프레스와 통합 기능&lt;br /&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;커뮤니티 -&amp;gt; Discourse 자체의 목적&lt;/li&gt;&lt;li&gt;위키 -&amp;gt; 위키 포스트 기능&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 서비스 권한.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;이제 서비스 권한이다.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p class=&quot;&quot;&gt;다음은 권한차이를 보기위한 두가지 지표다.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;사용자 분류&lt;/b&gt;(위에 있을 수록 폐쇄적).&lt;sup class=&quot;footnote&quot;&gt;&lt;a href=&quot;#footnote_35_9&quot; id=&quot;footnote_link_35_9&quot; onmouseover=&quot;tistoryFootnote.show(this, 35, 9)&quot; onmouseout=&quot;tistoryFootnote.hide(35, 9)&quot; style=&quot;color:#f9650d; font-family: Verdana, Sans-serif; display: inline;&quot;&gt;&lt;span style=&quot;display: none;&quot;&gt;[각주:&lt;/span&gt;9&lt;span style=&quot;display: none;&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;table class=&quot;txc-table&quot; style=&quot;border:none;border-collapse:collapse;;font-family:&quot; width=&quot;784&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;사용자 구분&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;;&quot;&gt;&lt;p&gt;기호&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;;&quot;&gt;&lt;p&gt;부가설명&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width: 261px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204); border-left: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;자신(Self) &lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 261px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;S&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 261px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;계정 소유자&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;친한 친구(Best Friend)&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;B&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;특별한 등급의 친구&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;친구(Friend)&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;F&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;친구 신청 후 허락&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;지인(Acquaintance)&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;A&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;맞팔&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;구독(Subscriber, Reader)&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;R&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;팔로우&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;멤버(Member)&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;M&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;가입한 사용자&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p class=&quot;&quot;&gt;모두(Unpecified, User)&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:261;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;모든 사용자 &lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;p class=&quot;&quot;&gt;보통 서비스들에서 서비스의 복잡도를 줄이기 위해 지인과 친구를 구별하지 않아 살짝 헷갈릴수 있지만 실제 인간관계를 생각해보면 쉽다.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;나와 친척은 서로 얼굴을 알고 있는 사이고 어느정도 호감(팔로우)은 있지만, 친구 사이라 보기는 어렵다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;게시물 권한.&lt;/b&gt;&lt;/p&gt;&lt;table class=&quot;txc-table&quot; style=&quot;border:none;border-collapse:collapse;;font-family:&quot; width=&quot;764&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;설명&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;글 쓰기&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;자신의 글을 쓰거나 고칠수 있는 권한&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;글 읽기&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;자신의 글을 읽을 수 있는 권한&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;게시판 쓰기&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;게시판에 글을 유저가 쓰거나 고칠 수 있는 권한&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;게시판 읽기&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;게시판의 글을 유저가 읽을 수 있는 권한&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;사용자 노출도&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:382;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p class=&quot;&quot;&gt;&amp;nbsp;자신의 계정이 노출 되는 환경&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;p class=&quot;&quot;&gt;게시판은 서비스의 성격에 따라 온전히 혼자서 사용하는 곳이 아니다는 점이 가장 큰 차이.&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;통상적인 서비스 권한.&lt;/b&gt;(역시 절대적이지는 않음)&lt;/p&gt;&lt;table class=&quot;txc-table&quot; style=&quot;border:none;border-collapse:collapse;;font-family:&quot; width=&quot;784&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;;&quot;&gt;&lt;p&gt;글 쓰기&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204); border-top: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;글 읽기&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204); border-top: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;게시판 쓰기&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;;&quot;&gt;&lt;p&gt;게시판 읽기&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;;&quot;&gt;&lt;p&gt;사용자 노출도 &lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;메모&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;S&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;S&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;S &lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;S&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;S&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;메신저&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;S&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;M&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;R&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;M&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;R&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;블로그&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;S&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;S&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width: 130px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204); border-left: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;SNS&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 130px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;S&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;M&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;M&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 130px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;R &lt;br /&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width: 130px; height: 26px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;M&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;카페&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;S&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;M&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;M&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;M&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;M&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;커뮤니티&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;S&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;M &lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;border-left:1px solid #ccc;;&quot;&gt;&lt;p&gt;위키&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width: 131px; height: 24px; border-bottom: 1px solid rgb(204, 204, 204); border-right: 1px solid rgb(204, 204, 204);&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td style=&quot;width:130;height:24;border-bottom:1px solid #ccc;border-right:1px solid #ccc;;&quot;&gt;&lt;p&gt;U&lt;br /&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;p class=&quot;&quot;&gt;메모는 따로 공유를 하지 않는 한 혼자서 사용하는 서비스다.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;이와 반대되는 서비스는 위키로 모두다 공유하며 사용하는 서비스다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;블로그는 메모 글이 열려있는 형태다.&lt;/p&gt;&lt;p&gt;글과 게시판은 혼자서 채우지만 글과 게시판, 사용자 정보는 찾아오는 사람들이 모두 볼 수 있다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;커뮤니티는 게시판을 불특정 다수의 멤버들과 함께 채울 수 있다는 점이 블로그와 다르다.&lt;/p&gt;&lt;p&gt;카페도 커뮤니티 서비스지만 포털 서비스가 가두리 양식을 하려고 만들어졌고 카페정책 자체가 검색이 힘든 폐쇄적인 경우가 많아 글 읽기, 게시판과 유저 노출도 모두 멤버로 바뀐다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;서비스 형태가 특이해서 SNS와 메신저는 파악하는데 조금 걸렸는데..&lt;/p&gt;&lt;p&gt;SNS는 마이크로블로그라 불리는 형태로 운영이 되지만, 폐쇄적이라 멤버가 되어야 컨텐츠들을 자유롭게 볼 수 있다. 게시판이 통합되어 뉴스피드나 인박스되는 형태로 운영이 되기 때문에 불특정 다수의 멤버글을 읽는게 아니라 타게팅이된(ex. 구독) 글들을 보는 형태다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;메신저는 전달받는 메시지나 초대된 대화방의 메시지를 멤버면 읽을 수 있지만 상대방에게 전할 때는 최소한 구독이 된 상태여야 하므로 R이다.&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;h4&gt;2.2.5 Automation.&lt;br /&gt;&lt;/h4&gt;&lt;p class=&quot;&quot;&gt;말그대로 자동화를 수행한다.&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;b&gt;매크로&lt;/b&gt;: 안드로이드의 Tasker, IOS의 Workflow, Web에서 IFTTT&lt;br /&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li class=&quot;&quot;&gt;&lt;b&gt;정교한 매크로&lt;/b&gt;: RPA(UI Path, Automation Anywhere)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;b&gt;메타 매크로&lt;/b&gt;: AI, Chat Bot &lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot;&gt;너무 명확해서 따로 쓸말은 없는듯.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;아직 인공지능쪽 개념을 많이 모르기도 하고.&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;2.3 흐름.&lt;br /&gt;&lt;/h3&gt;&lt;div&gt;매우 간략하게나마 어플리케이션의 흐름을 적어본다면&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;&quot;&gt;&lt;b&gt;- 책 쓰기.&lt;/b&gt;&lt;/div&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;div&gt;주제 설정 및 소통(Trans)&lt;br /&gt;그룹웨어, 메신저등을 통함.&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div&gt;자료 수집 및 저장(Store, Automation)&lt;br /&gt;각종 설정-&amp;gt; 노트&lt;br /&gt;사진 -&amp;gt; 자동 백업 및 분류&lt;br /&gt;사이트 -&amp;gt; 클리핑(Read It Later)&lt;br /&gt;논문 -&amp;gt; 서지관리 프로그램&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div class=&quot;&quot;&gt;책 저작(Create, Automation)&lt;br /&gt;일러스트나 포토샵을 통해 이미지 만들기&lt;br /&gt;Indesign같은 프로그램을 사용하여 저작&lt;br /&gt;퇴고 및 오탈자 수정자동 서식&lt;br /&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div class=&quot;&quot;&gt;홍보(Trans, Automation)&lt;br /&gt;커뮤니티, SNS, Store등에 올리기.&lt;br /&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;&quot;&gt;&lt;b&gt;- 프로그래밍.&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;주제 설정 및 회의(Trans)&lt;br /&gt;그룹웨어, 메신저등을 통함.&lt;/li&gt;&lt;li&gt;자료 수집 및 저장(Store)&lt;br /&gt;사이트 -&amp;gt; 클리핑(Read It Later)&lt;br /&gt;코드 스니펫 -&amp;gt; Github Gist&lt;br /&gt;각종 리소스 -&amp;gt; 클라우드 공유&lt;/li&gt;&lt;li&gt;만들기(Create, Automation)&lt;br /&gt;리소스 제작.&lt;br /&gt;프로그래밍.&lt;br /&gt;자동 포맷, 빌드 테스트 등&lt;/li&gt;&lt;li&gt;홍보(Trans, Automation)&lt;br /&gt;커뮤니티, SNS, Store등에 올리기.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이렇듯 정보의 유통을 수직계열화 시키는 게 IT플랫폼 사업의 핵심이고, 모두가 지향하고 있는 지점이다.&lt;/p&gt;&lt;p&gt;다루는 방법이 비슷비슷한점이 많다보니 나중엔 깔끔히 통일된 플랫폼이 등장하지 않을까 싶다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;솔직히 이걸론 제품 설계할만큼 충분한 자료는 아니지만 플랫폼의 전반적인 구조 이해에는 도움이 되었기를 바란다.&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol class=&quot;footnotes&quot;&gt;
    &lt;li id=&quot;footnote_35_1&quot;&gt;GTD 포함. &lt;a href=&quot;#footnote_link_35_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_35_2&quot;&gt;아래 예제에서 사용할 것은 ARM 어셈블리.&lt;br&gt;참고하세요. &lt;a href=&quot;#footnote_link_35_2&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_35_3&quot;&gt;어셈블리는 기계어를 치환한 것이므로 동일하게 취급하였음. &lt;a href=&quot;#footnote_link_35_3&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_35_4&quot;&gt;레지스터나 메모리가 아니라 스토리지에 저장하는게 가장 큰 차이 &lt;a href=&quot;#footnote_link_35_4&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_35_5&quot;&gt;흔히 말하는 양자역학에서 말하는 '관찰'이라는 것도 물체와 광자와의 '상호작용'이 필요한 것이기 때문에 시간이 흘러서 상태가 바뀐다고 말할 수 있다. &lt;a href=&quot;#footnote_link_35_5&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_35_6&quot;&gt;프로그래밍에선 자료구조 정도로 생각해도 무방. &lt;a href=&quot;#footnote_link_35_6&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_35_7&quot;&gt;'-'는 단지 서로 연관성이 있다는 것을 나타내는 표현일 뿐이다. &lt;a href=&quot;#footnote_link_35_7&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_35_8&quot;&gt;서비스에 따라 일부 기능은 제한 될 수도 있음. &lt;a href=&quot;#footnote_link_35_8&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;footnote_35_9&quot;&gt;* 친한 친구는 싸이월드 일촌 같은 개념.
&lt;br&gt;
** 서비스에 따라 합치기도 함. &lt;a href=&quot;#footnote_link_35_9&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description>
      <category>IT</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/35</guid>
      <comments>https://black7375.tistory.com/35#entry35comment</comments>
      <pubDate>Fri, 19 Jan 2018 16:30:02 +0900</pubDate>
    </item>
    <item>
      <title>내 맘대로 프로그램 설계 3. - 함수와 변수.</title>
      <link>https://black7375.tistory.com/34</link>
      <description>&lt;script async=&quot;&quot; src=&quot;https://assets.tumblr.com/post.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; async=&quot;&quot; src=&quot;https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML&quot;&gt;
&lt;script async=&quot;&quot; src=&quot;//cdn.embedly.com/widgets/platform.js&quot; charset=&quot;UTF-8&quot;&gt;&lt;/script&gt; 
&lt;p&gt;원래 합쳐져서 Section2 였던 '기초'에서 '간단한 데이터 처리'와 '함수'로 나뉘어 구성하게 되었습니다.&lt;/p&gt;
&lt;p&gt;너무 길어서 로딩도 오래걸리고, 읽는 사람도 힘들겠더군요.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr&gt;&lt;h4&gt;내 맘대로 하는 프로그램 설계 시리즈.&lt;/h4&gt;&lt;p&gt;&lt;b&gt;Chapter1 - 간단한 데이터 처리(4섹션)&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/31&quot; target=&quot;_blank&quot;&gt;2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/32&quot; target=&quot;_blank&quot;&gt;2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 2. - 데이터 타입.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/34&quot; target=&quot;_blank&quot;&gt;2018/01/16 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 3. - 함수와 변수.(현재)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/36&quot; target=&quot;_blank&quot;&gt;2018/05/29 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 4. - 고정 크기 데이터.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/6&quot; target=&quot;_blank&quot;&gt;2017/06/30 - [프로그래밍/설계] - 프로그래밍과 추상화에 대하여.[부록]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Chapter2 - 임의의 데이터 처리&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://black7375.tistory.com/38&quot; target=&quot;_blank&quot;&gt;2018/06/10 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 5. - 리스트와 재귀.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;어.. 전 포스트에 비해 분량이 조금 많아 보이는데..&lt;/p&gt;
&lt;p&gt;조절을 실패해서 그렇습니다;;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이렇게 된거 그냥 초반의지가 불타올랐을때 끝장내버립시다.ㅎㅎ&lt;/p&gt;
&lt;p&gt;나중에 갈수록 하기 싫어지더라고요.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;1. 시작하기.&lt;/h2&gt;&lt;p&gt;지금껏 간단히 각종 데이터들을 간단하게나마 다루어보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이제 함수를 본격적으로 다루어보기로 합시다.&lt;/p&gt;
&lt;p&gt;Parameter와 Argument 쪽 &lt;b&gt;+.&lt;/b&gt;를 보셨다면 이해의 속도가 훨씬 빨라질 것입니다&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h2&gt;2. 함수&lt;br /&gt;&lt;/h2&gt;&lt;h3&gt;2.1 함수 만들기.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;Racket에서 함수의 개념은 우리가 수학에서 배웠던 함수와 유사합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아래와 같은 관계가 성사됩니다.&lt;/p&gt;&lt;div&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 330px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99092A365A66E58917&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99092A365A66E58917&quot; width=&quot;330&quot; height=&quot;327&quot; filename=&quot;function.png&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;함수[from &lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;Wikipedia&lt;/a&gt;]&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;수학에서 직사각형의 넓이(S)와 둘레(L)를 구하는 함수를 한번 생각해봅시다.&lt;/p&gt;
&lt;p&gt;밑변과 높이를 각각 w와 h라 표시하면&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$S= w \times h \\ L=2w + 2h$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;가 되겠죠.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;위 2개 함수들을 Racket의 방식으로 만들어봅시다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우선 Racket의 함수를 만드는 방식은&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (함수이름 매개변수) 함수표현식)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;과 같다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우선 S과 L는 아래 식처럼 나타낼 수 있다.&lt;/p&gt;
&lt;p&gt;관습에 따라 각각 f(x), g(x)의 형태를 취하겠습니다.&lt;/p&gt;
&lt;p&gt;$$S = f(w, h) = w \times h \\&lt;br /&gt;L = g(w,h) = 2w + 2h$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기서 둘의 생김새가 굉장히 유사하며,&lt;br /&gt;&lt;/p&gt;&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은\ 고딕, sans-serif; font-weight: bold;&quot;&gt;수식&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은\ 고딕, sans-serif; font-weight: bold;&quot;&gt;값&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #74a442 1.70pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#c3d7af;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-weight: bold; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;Racket&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은\ 고딕, sans-serif;&quot;&gt;함수이름&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;f, g&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은\ 고딕, sans-serif;&quot;&gt;함수이름&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은\ 고딕, sans-serif;&quot;&gt;독립변수&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;w, h&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #d8e8c6 0.28pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은\ 고딕, sans-serif;&quot;&gt;매개변수&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width: 139.84pt; height: 22px; padding: 1.41pt 5.1pt; border-color: rgb(216, 232, 198) rgb(216, 232, 198) rgb(216, 232, 198) rgb(116, 164, 66); border-style: solid; border-width: 0.28pt 0.28pt 0.28pt 1.7pt; background: rgb(255, 255, 255) none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은\ 고딕, sans-serif;&quot;&gt;함수수식&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width: 139.84pt; height: 22px; padding: 1.41pt 5.1pt; border-color: rgb(216, 232, 198); border-style: solid; border-width: 0.28pt; background: rgb(255, 255, 255) none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;w*h, 2w+2h&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width: 139.84pt; height: 22px; padding: 1.41pt 5.1pt; border-color: rgb(216, 232, 198) rgb(116, 164, 66) rgb(216, 232, 198) rgb(216, 232, 198); border-style: solid; border-width: 0.28pt 1.7pt 0.28pt 0.28pt; background: rgb(255, 255, 255) none repeat scroll 0% 0%;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은\ 고딕, sans-serif;&quot;&gt;함수표현식&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #74a442 1.70pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은\ 고딕, sans-serif;&quot;&gt;종속변수&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #d8e8c6 0.28pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;S, L&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:139.84pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #d8e8c6 0.28pt;border-left:solid #d8e8c6 0.28pt;border-bottom:solid #74a442 1.70pt;border-right:solid #74a442 1.70pt;background:#ffffff;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;font-family: 맑은\ 고딕, sans-serif;&quot;&gt;결과값&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;관계임을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이제 Racket 함수로 바꾸어 봅시다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 3.1&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (f w h) (* w h))
(define (g w h)
  (+ (* 2 w)
     (* 2 h)))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;쉽죠?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그런데 실행해보면 아무일도 일어나지 않습니다.&lt;/p&gt;
&lt;p&gt;함수만 만들어졌지 쓰지 않았기 때문이죠.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* 대화창 영역에 실행시키면 define은 사용할 수 없다고 나옵니다. 그 이유론, 만약 대화창 영역에서 함수를 만들 수 있다면 그 후 모든 결과 값에 영향을 미칠 수 있는 걸 들 수 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;한번 예제를 짜보고 그에 맞게 나오는지 확인해봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse:collapse;table-layout:fixed;border-top:none;border-left:none;border-bottom:none;border-right:none;mso-table-overlap:never;&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width:75.58pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:none;border-bottom:solid #699b37 2.55pt;border-right:solid #c6e1ab 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-weight: bold; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;w, h&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:68.79pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:solid #c6e1ab 0.28pt;border-bottom:solid #699b37 2.55pt;border-right:solid #c6e1ab 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;1, 1&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:68.79pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:solid #c6e1ab 0.28pt;border-bottom:solid #699b37 2.55pt;border-right:solid #c6e1ab 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;1, 2&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:68.79pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:solid #c6e1ab 0.28pt;border-bottom:solid #699b37 2.55pt;border-right:solid #c6e1ab 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;2, 1&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:68.79pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:solid #c6e1ab 0.28pt;border-bottom:solid #699b37 2.55pt;border-right:solid #c6e1ab 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;2, 2&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:68.79pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:solid #c6e1ab 0.28pt;border-bottom:solid #699b37 2.55pt;border-right:none;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;...&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width:75.58pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:none;border-bottom:solid #699b37 2.55pt;border-right:solid #c6e1ab 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-weight: bold; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;f(w,h), g(w,h)&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:68.79pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:solid #c6e1ab 0.28pt;border-bottom:solid #699b37 2.55pt;border-right:solid #c6e1ab 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;1, 4&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:68.79pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:solid #c6e1ab 0.28pt;border-bottom:solid #699b37 2.55pt;border-right:solid #c6e1ab 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;2, 6&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:68.79pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:solid #c6e1ab 0.28pt;border-bottom:solid #699b37 2.55pt;border-right:solid #c6e1ab 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;2, 6&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:68.79pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:solid #c6e1ab 0.28pt;border-bottom:solid #699b37 2.55pt;border-right:solid #c6e1ab 0.28pt;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;4, 8&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width:68.79pt;height:12.82pt;padding:1.41pt 5.10pt 1.41pt 5.10pt;border-top:solid #699b37 2.55pt;border-left:solid #c6e1ab 0.28pt;border-bottom:solid #699b37 2.55pt;border-right:none;&quot; valign=&quot;middle&quot;&gt;&lt;p class=&quot;0&quot; style=&quot;text-align:center;word-break:keep-all;mso-pagination:none;text-autospace:none;mso-padding-alt:0pt 0pt 0pt 0pt;&quot;&gt;&lt;span style=&quot;letter-spacing: 0pt; font-family: 맑은\ 고딕, sans-serif;&quot;&gt;...&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이렇게 테스트 케이스를 만드는 작업은 함수를 잘못 만들어진 경우, 그 이유를 찾기 쉽게 만듭니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그래서 함수를 만든다면 &lt;b&gt;꼭&lt;/b&gt; 테스트 케이스를 만들어서 테스트를 해보시기 바랍니다.&lt;/p&gt;
&lt;p&gt;* 사실 &lt;b&gt;함수를 만들기 전&lt;/b&gt;에 미리 테스트 케이스를 만들어야 하지만, 여기 예제에서는 테스트 케이스 만드는 것을 중간에 넣는 게 집중을 흐릴수 있어 함수를 만든후 작성하였습니다.&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p style=&quot;text-align: center;&quot;&gt;Code 3.2&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(f 1 1)
(g 1 1)

(f 1 2)
(g 1 2)

(f 2 1)
(g 2 1)

(f 2 2)
(g 2 2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;사용법은 예전에 쓰던 것과 동일합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;결국 2htdp\image.rkt라는 배움꾸러미는 이런 함수들을 미리 정의하고 모아놓은 것에 불과했다는 것임을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;예전부터 써왔던 함수들 또한 기본적으로 정의가 되어있었던 것이고요.&lt;/p&gt;
&lt;h4&gt;+.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;원래 +. 파트는 안읽어보아도 된다고 했지만 여기는 왠만하면 읽어보았으면 합니다.&lt;/p&gt;
&lt;p&gt;그리 어렵지 않아요.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;프로그래밍을 하다보면 Parameter(매개변수)와 Argument(인자)라는 단어가 계속 나올 것입니다.&lt;/p&gt;
&lt;p&gt;혹시나 궁금하다면 미리 알아놓도록 합시다.&lt;br /&gt;&lt;/p&gt;
 &lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/169349889805&quot; data-did=&quot;87c0054a28a8c705293a386f88f643dc288d90d2&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/169349889805/parameter-vs-argument&quot;&gt;https://black7375.tumblr.com/post/169349889805/parameter-vs-argument&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Racket처럼 바꾸어보자면&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (fn x y)
  ;;표현식(expression)
  )

(fn 1 2.3)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;의 형태이겠죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;++.&lt;/h4&gt;&lt;p&gt;내가 생각하는 적절한 함수의 길이&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/162403828110/내가-생각하는-적절한-함수의-길이&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://black7375.tumblr.com/post/162403828110/내가-생각하는-적절한-함수의-길이&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/162403828110&quot; data-did=&quot;16fd54199f0f14f55e67c0b283130e88308e5ce0&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/162403828110/내가-생각하는-적절한-함수의-길이&quot;&gt;https://black7375.tumblr.com/post/162403828110/내가-생각하는-적절한-함수의-길이&lt;/a&gt;&lt;/div&gt;  
&lt;p&gt;함수는 1~2가지의 기능만 해야한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;함수가 길어지면 복잡해지고 구조를 알아보기 힘들어지는 것은 필연적인 결과다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;+++.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;Racket에서 함수는 무조건 1개이상의 매개변수가 필요하고, 1개의 결과값이 반환(Return)되지만,&lt;/p&gt;
&lt;p&gt;C언어 계열에서는 void라는 키워드를 사용하면 매개변수 없이, 결과값 없이 함수만 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;파스칼이나 SQL 쪽에선 반환값이 있으면 Function, 없으면 Procedure로 구분합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.2 함수 업그레이드.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;그런데 이 함수들에게는 몇가지 문제점이 존재합니다.&lt;/p&gt;
&lt;p&gt;아니, 잘못한게 없는데 뭔말이지?!?!?!?!!?!&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;틀린게 아니라고 문제가 없다는건 아니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;직관적이거나 우아하지 않다는게 문제다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;하나씩 문제점을 짚어보도록 하자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;2.2.1 직관성.&lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;우리는 지금까지 미리 정의된 함수들을 사용해왔다.&lt;/p&gt;
&lt;p&gt;그것도 무척 자연스럽게.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;왜 그럴까요?&lt;/p&gt;
&lt;p&gt;우리 모두에게 통용될만한 기호나 단어들을 써왔기 때문이죠.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우리가 정의하는 함수나 변수의 이름도 그러해야 합니다. &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;대부분의 수학문제를 풀때야 1문제에 나오는 함수가 수십~수십만개 단위로 잘나오지 않습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그러나 프로그래밍을 할때는 규모가 커지는 경우가 많기 때문에 '작명(네이밍)'하는 행위는 굉장히 중요합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;또한 다른 사람이 함수나 변수의 이름을 봤을때 바로 알아보지 못하면 함수내부의 구조를 살펴보아야 하기 때문에 낭비되는 시간이 굉장히 많이 생깁니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;만약 다른 사람에게 보여주지 않을거라 해도 '미래의 자신'이라는 또 다른 강적이 존재합니다. ㅎㅎ&lt;/p&gt;
&lt;p&gt;(과연 천재가 아닌 이상 모든걸 기억할 수 있을까?)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이제 작명을 하는 방법을 한번 알아보자.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;문장에서 그 문장의 요약을 할때 꼭 필요한 요소를 뽑는다고 하면&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;동사. 명사(주어, 목적어).&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;를 들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;절대적이지는 않지만&lt;/p&gt;
&lt;p&gt;함수는 기능을 하는 단위며 결과값을 반환(Return)하기 때문에 동사(기능)와 주어(문장의 주체-&amp;gt;결과)에 가깝고,&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;변수는 구성요소이므로 명사에 가까운 특성을 가진다고 볼 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;정말 이것만 알아도 어느정도 괜찮은 작명을 할 수 있다.&lt;/p&gt;
&lt;p&gt;(데이터베이스 모델링할 때 얻은 아이디어 입니다. - 개체도출과 관계설정.)&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아까 우리가 만든 함수의 요구사항을 설명해보자.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;- 직사각형의 크기는 가로 * 세로다.&lt;/p&gt;
&lt;p&gt;- 직사각형의 둘레는 가로*2 + 세로*2다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;함수를 실행시켰을때 나오는 &lt;b&gt;결과&lt;/b&gt;나 함수의 &lt;b&gt;동작&lt;/b&gt;을 가장 설명하는 것은 직사각형의 크기와 둘레이며,&lt;/p&gt;
&lt;p&gt;변수는 &lt;b&gt;목적어&lt;/b&gt;인 가로와 세로이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그렇다면 함수의 이름은 &lt;i&gt;&lt;b&gt;rectangle-size&lt;/b&gt;&lt;/i&gt;, &lt;i&gt;&lt;b&gt;rectangle-length&lt;/b&gt;&lt;/i&gt;, 변수의 이름은 &lt;i&gt;&lt;b&gt;width&lt;/b&gt;&lt;/i&gt;, &lt;b&gt;&lt;i&gt;height&lt;/i&gt;&lt;/b&gt;가 적당하다고 할 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* 사실 S, L. 얘들도 Size, Length, w와 h는 width, height의 줄임말로 쓰였다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;rectangle이 너무 길다면 rect-size, rect-length처럼 처음 한두음절을 이용하는 것도 괜찮다. 이름이 너무 길면 읽는데 방해되기 때문.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;결과:&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 3.3&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (rect-size    width height)
  (* width height))
(define (rect-length  width height)
  (+ (* 2 width  )
     (* 2 height )))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;작명은 존재성을 불어넣어주는 행위이다.&lt;/p&gt;
&lt;p&gt;가치를 부여하는 것이므로 항상 조심조심!!&lt;/p&gt;&lt;h4&gt;+.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;이름 짓는 것이 쉬워보이지만&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 728px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9911CF435A66E6510F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9911CF435A66E6510F&quot; width=&quot;728&quot; height=&quot;637&quot; filename=&quot;naming.PNG&quot; filemime=&quot;image/png&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;라는 말이 있다.ㅋㅋ&lt;/p&gt;
&lt;p&gt;그만큼 중요하단 말이겠죠.&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;++.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;언어마다 이름을 짓는 스타일이 조금씩 다르다.&lt;/p&gt;
&lt;p&gt;Racket이나 Lisp 계열은 rect-size였다면, C언어쪽은 rect_size, 자바는 rectSize, 파스칼은 RectSize같은 방식을 사용한다.&lt;/p&gt;
&lt;p&gt;이를 네이밍 컨벤션이나 코드 컨벤션이라고 하는데 기본 함수나 기존 코드들과의 통일성을 위하여 어느정도 맞추어주는 것이 좋다.&lt;/p&gt;
&lt;p&gt;그냥 문체를 비슷하게 맞춘다고 생각하자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;2.2.2 간결성.&lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;이과 계열에서 우아하다, 아름답다는 말은 간결하고 기존이론과 들이맞는다는 것이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우리가 만들어 놓은 함수중에 문제가 되는 것은 rect-length다.&lt;/p&gt;
&lt;p&gt;아까 g(w, h)에서&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$ \begin{matrix} g(w, h) &amp;amp;=&amp;amp; 2w + 2h \\ &amp;amp;=&amp;amp; 2(w + h) \end{matrix}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;처럼 수식 부분에서 반복되던 패턴을 줄일 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;반복되는 패턴이 존재하면 1개 고칠것을 여러개 고쳐야 하고(유지보수), 1번에 처리할 수 있는 것을 여러번에 걸쳐 처리(성능)해야하므로 프로그램을 만들때 반드시 처단해야하는 녀석이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;사람도 기계도 뒷감당하기가 힘들어진다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;결과:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 3.4&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (rect-length-upgrade width height)
  (* 2 (+ width height)))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;* rect-length가 이미 있어서 rect-length-upgrade라 하였습니다.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;2.3 변수(variable)와 상수(constant).&lt;/h3&gt;&lt;p&gt;함수는 변수와 변수끼리의 관계를 나타낸다.&lt;/p&gt;
&lt;p&gt;그래서 변수에 대한 이해를 가지는 것은 필요하다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;2.3.1 변수.&lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;변수(variable)는 말그대로 변할수 있는 수이다.&lt;/p&gt;
&lt;p&gt;변할수 있다는 말을 뒤집어 보면 무조건적으로 변하지는 않을수도 있다는 뜻을 가진다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;무조건적으로만 변한다면 랜덤(Random)인 난수이겠지;;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;만약 함수내에서 일정한 패턴으로 변수가 반복된다면?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;간결성이란 항목에서 배웠듯 중복되는 행위는 최대한 줄여야 하고 따로 분리를 해야한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;만약 환율과 관계된 프로그램을 만들게된다고 하면 원, 달러, 유로등 각 통화에 대한 변수가 반복이 될것이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그렇다면 각 변수(won, dollar, euro 등)을 한번에 관리하는게 좋지 않겠는가?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Racket에서는&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define 변수이름 변수값)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;* 변수값은 정확히 말하자면 표현식을 의미한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;로 변수를 선언하여 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;예:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 3.5&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define won    1000)
(define dollar 1   )
(define euro   0.8 )
won
dollar
euro&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 1000, 1, 0.8&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이제 won은 1000, dollar는 1, euro는 0.8로서 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;여기서도 추후 중복될 작업을 줄이려면,&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 3.6&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define usd 1           )
(define eur (* 0.8  usd))
(define krw (* 1000 usd))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;* 만약, 같은 이름으로 다시 선언하게되면&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;this name was defined previously and cannot be re-defined&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;이라고 재선언을 할 수 없다는 에러가 뜨므로 다른 이름을 사용했다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* won은 KRW, dollar는 USD, euro는 EUR로 보통 표시한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;처럼 달러화만 바꾸면 전체 환율이 변환되도록 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;변수를 알아보았으니, 변수와 상대적으로 대비되는 개념인 상수를 알아보도록 하자.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;2.3.2 상수.&lt;br /&gt;&lt;/h4&gt;
&lt;p&gt;상수(constant)는 일정한 수이다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;상수로 만들 수 있는 수는 수학에서의 π(PI, 3.141592..)나 물리의 중력가속도(g, 9.8...)같은 수.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이러한 상수도 중복된 패턴(일정한 값)을 가진 상태에서 자주 쓰이는 것이고, 값 정밀도등도 편히 관리하기 위해 선언을 해주는 것이 좋습니다. '이름을 부여'하면 어떠한 상수인지 직관적으로 알아볼 수 있기도 하고요.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;예:&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 3.7&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define PI #i3.14)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;* Racket에서는 자주 쓰이는 상수인 pi, e 같은게 미리 정의되어 있긴 하다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;여기까지 했다면, Racket으로 만들어지는 프로그램은 함수와 변수로 이루어진 복합체라는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;+.&lt;/h4&gt;&lt;p&gt;Racet에서는 변수나 상수 둘다 같은 방식으로 선언했지만, 다른 언어는 다른 방식으로 선언합니다.&lt;/p&gt;
&lt;p&gt;그 이유로는 Racket에선 함수 표현식 내부에서 선언(define)된 변수를 수정할 수 없지만, 다른 언어에서는 a의 값이 1이라 되어 있을때, a=2 또는 a=a+1같은 방식으로 변수를 수정할 수 있습니다.&lt;/p&gt;
&lt;p&gt;이 말은, Racket에서 선언하는 모든 변수는 상수처럼 동작한다는 것을 의미합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;값의 변경을 하려면 set! 이란 함수(void를 반환)를 사용해야 하며, 고급 학생 버전에서 사용해볼 수 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define name 1)
name
(set!   name 2)
name&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 1, (void), 2&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;다른 언어에서는 주로 const라는 키워드를 추가로 붙여 상수로 만들고, 값(상태)의 변경을 막습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;++.&lt;/h4&gt;&lt;p&gt;컴퓨터
 과학쪽에서는 함수가 결과값말고 다른 상태를 변경시키면 부작용(Side Effect, 보통 사이드 이펙트라 부름)이 생겼다고 
한다. 사이트 이펙트가 생기면, 예측되지 못한 값이 나올 확률이 올라가 버그가 나오기 쉽고, 컴파일러가 최적화를 하기 힘들어진다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;근삿값이 정확한 값과 함께 계산하면 근삿값이 나오듯이 사이드 이펙트도 사이드 이펙트가 일어난 함수가 사용되면 퍼져나간다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;변수의 변경, 저장된 데이터의 변경 이런게 다 상태의 변경에 속한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Racket같이 함수형 언어란 패러다임에 속하는 언어들은 Side Effect를 줄이기 위하여 특정한 경우를 제외하고 변수를 바꾸는 것을 막고 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;h4&gt;+++.&lt;/h4&gt;&lt;p&gt;상수를 만들때 관습은 대문자를 사용하는 것입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;아마 변수와 쉽게 구분하기 위해 생긴것이겠죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;2.4 조건 함수.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;프로그램들은 여러 상황의 문제를 조건에 맞게 판단해야 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이때 조건이란 것은 맞는지, 틀린지를 따지는 것이기 때문에 불린과 땔래야 땔수 없는 관계라 할 수 있다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우리가 확장된 계산에서 봤던 등호표시(&amp;lt;,&amp;lt;=, &amp;gt;, &amp;gt;=, =)나 불린값에서 봤던 논리계산(and, or, not등)이 그러한 예라 할 수 있죠.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그러나 저러한 조건 처리 방식은 여러 조건 가운데 어떤 조건이 성립하는지 결정하는 것은 힘들다.&lt;/p&gt;
&lt;p&gt;이걸 결정해주는 함수를 조건함수(Conditonal Function)이라 하고, 조건표현을 통해서 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;조건표현 사용법.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(cond
  [질문 답]
  ...
  [질문 답]&lt;br /&gt;  [else 답])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;* 대괄호를 소괄호로 해도 되나, 대괄호로 사용하는게 가독성 측면에서 더 좋다.&lt;/p&gt;
&lt;p&gt;* else는 위의 질문들이 모두 false일때 답(결과값)을 반환하며 없어도 상관 없다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;의 방법으로 사용한다.&lt;/p&gt;
&lt;p&gt;* 위에서 아래로 차례대로 조건을 검사한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;문제를 풀어봅시다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;문제 3.1&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;환전을 하기위해 프로그램을 짜는데, 1달러가 0.7 유로보다 작으면 'EUR을 출력하고, 1000원이하이면 'KRW를 출력하며, 6.5위안을 초과하면 'CNY를 출력한다. 그 이외의 결과면 'USD를 출력한다.&lt;br /&gt;단, 1달러에 6위안(cny)라 정의한다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;* 환율을 위해 usd, eur, krw, cny를 사용한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;코드:&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 3.8&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define cny (* 6 usd))
(cond
  [(&amp;lt;  usd (/ 0.7  eur)) 'EUR]
  [(&amp;lt;= usd (/ 1000 krw)) 'KRW]
  [(&amp;gt;  usd (/ 6.5  cny)) 'CNY]
  [else                  'USD])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;답: 'KRW&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이번에는 조건함수를 한번 만들어봅시다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;문제 3.2&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;달러로
 환전을 할때, 내는 금액에 따라 차등적으로 수수료를 적용하려합니다.&lt;/p&gt;
&lt;p&gt;소금액인 10만원(100000) 이하나 큰 금액인 
1억(100000000) 초과는 3%, 10~100만원(1000000) 이하는 4%, 100만~1000만원(10000000) 
이하는 5% 을 만들고, 같은 방식으로 5000만원(50000000) 이하는 4%, 1억이하는 3.5%의 수수료를 부과할때, 
이천만원(20000000)을 환전한 결과는?&lt;/p&gt;
&lt;p&gt;프로그램 이름은 krw-&amp;gt;usd라 하며, 전에 만든 환율을 이용한다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;코드:&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 3.9&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (krw-&amp;gt;usd won)
  (cond
    [(or (&amp;gt;= 100000    won)
         (&amp;lt;  100000000 won)) (/ (- won (* 0.03  won)) krw)]
    [(&amp;gt;=        1000000 won) (/ (- won (* 0.04  won)) krw)]
    [(&amp;gt;=       10000000 won) (/ (- won (* 0.05  won)) krw)]
    [(&amp;gt;=       50000000 won) (/ (- won (* 0.04  won)) krw)]
    [(&amp;gt;=      100000000 won) (/ (- won (* 0.035 won)) krw)]))

(krw-&amp;gt;usd 20000000)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 19200&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;뚜뚱~ 삼연타 문제!&lt;/p&gt;
&lt;p&gt;이게 다 끝나간다는 증거랍니다. 조금더 힘을 내요!!&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;문제 3.3&lt;br /&gt;&lt;/p&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;Code 2.21의 코드가 잘만든 것이라 생각하시나요?&lt;/p&gt;
&lt;p&gt;아니라면 코드를 수정해보고, 그 이유를 대봅시다.&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;힌트:&lt;/p&gt;
&lt;p&gt;그야 잘만든게 아니니까 문제가 나왔겠죠?&lt;br /&gt;&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot;&gt;&lt;li&gt;&lt;p&gt;1가지 논리적인 오류가 있습니다. &lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;하나의 함수에 미리 정의해놓은 여러가지 함수가 들어갈수 있습니다.&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;함수 업그레이드와 변수와 상수 참고.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;할 수 있으면 가독성도 좋게 만들어봅시다.&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;* 논리적 오류는 구문(문법)이 틀렸다는 것이 아니라 알고리즘(풀이과정)에서 잘못된 것이 있다는 것 입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* 외부 동작은 바꾸지 않으면서, 내부의 구조를 바꾸는 것을 리펙토링(Refactoring)이라 합니다. 여기선 리펙토링을 요구하는 것.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;코드:&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Code 3.10&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;----------exchange
(define exch-level1 100000   )
(define exch-level2 1000000  )
(define exch-level3 10000000 )
(define exch-level4 50000000 )
(define exch-level5 100000000)

(define (exch-usd money exch-rate)
  (/ money exch-rate))

;----------charge
(define charge-level1 0.03 )
(define charge-level2 0.035)
(define charge-level3 0.04 )
(define charge-level4 0.05 )

(define (charge-calc charge-level money)
  (- money (* charge-level money)))

;----------krw-&amp;gt;usd exchange
(define (krw-&amp;gt;usd2 won)
  (cond
    [(&amp;gt;  0           won)      'Error-*less-than-0*]
    [(or (&amp;gt;= exch-level1 won)
         (&amp;lt;  exch-level5 won)) (exch-usd (charge-calc charge-level1 won) krw)]
    [(&amp;gt;= exch-level2 won)      (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level3 won)      (exch-usd (charge-calc charge-level4 won) krw)]
    [(&amp;gt;= exch-level4 won)      (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level5 won)      (exch-usd (charge-calc charge-level2 won) krw)]))

;----------Test
(krw-&amp;gt;usd2 20000000)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과: 19200&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;* 세미콜론(;)로 시작하면 컴퓨터가 그 줄은 무시하며, 주석이라 부릅니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;제 코딩 스타일대로 리펙토링을 해보았습니다.&lt;/p&gt;
&lt;p&gt;살짝 길어지긴 했지만, 관리와 가독성 측면에서는 훨씬 더 좋아졌습니다.&lt;/p&gt;
&lt;p&gt;솔직히 길이가 길어진건 강좌를 위해 오버를 한 감도 완전히 없진 않습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. 논리적 오류.&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;0보다 작아지면, 환전을 할수 없겠죠?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그래서 저는 에러가 났다고 보여주었습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;border&quot;&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;b&gt;논리적 사고 원리.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;논리적으로 생각하는 방법을 크게 두가지로 구분지어 나타낼 수 있다.&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;확실성의 원리.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;명료성(섞이지 않았는가), 충분근거율(충분한 근거를 가지고 있는가)로 나눌 수 있다.&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;충분근거율.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;명료성은 다른 사고와 섞이지 않았는가를 구분하는 것으로 비교적 간단하다.&lt;/p&gt;
&lt;p&gt;하지만 '충분한 근거'는 상당히 애매모호한 개념이라 설명이 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;이성 vs 경험.&lt;br /&gt;이성적 확실성은 그 자체로 확증되므로, 필연성(어느 경우에나 반드시)을 가지지만, 경험적 확실성은 사실성(그 경우에는)만을 함유한다.&lt;/li&gt;&lt;li&gt;직접적 vs 간접적.&lt;br /&gt;매개에 따라 보증한다.&lt;br /&gt;매개는 확실성의 입증 수단으로 이성, 경험일 수 있다.&lt;br /&gt;어떠한 현상을 직접 관찰, 증명한 경우는 직접적 확실성을 책에서 보거나 듣기만 한 경우는 간접적 확실성이라 할 수 있다.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;정합성의 원리.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;사고의 앞뒤가 맞게 수행하느냐를 확인하는 것이다.&lt;/p&gt;
&lt;p&gt;이 때 다른 사고는 나의 다른 사고 뿐만이 아니라 다른 사람의 사고도 포함한다.&lt;/p&gt;
&lt;p&gt;정합성의 원리는 동일률, 모순율, 배중률로 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;동일률.&lt;br /&gt;어떤 것도 자기 자신과 같다는 것이다.&lt;br /&gt;사람은 사람, 동물은 동물, 식물은 식물이라는 것.&lt;br /&gt;만약 식물을 동물이라고 했다면 정합하지 않다고 할 수 있다.&lt;br /&gt;하지만 사람은 동물과 같은 포함관계는 정합하다.&lt;br /&gt;&lt;br /&gt;주의해야 할 점은 동일성을 같은 관점으로 바라보아야 한다는 것이다.&lt;br /&gt;문맥상 앞에서 말하는 것과 뒤에서 말하는 것이 다르다면 분리해여 생각해야한다.&lt;br /&gt;이는 추후에 나올 Scope 개념으로 생각할 수 있다.&lt;br /&gt;&lt;br /&gt;예시. 난중일기에서 아주 유명한 부분.&lt;br /&gt;&lt;blockquote class=&quot;tx-quote-tistory&quot;&gt;&lt;p&gt;必死則生 반드시 죽으려 하는 자는 살고&lt;br /&gt;必生則死 반드시 살고자 하는 자는 죽을 것이요&lt;/p&gt;&lt;/blockquote&gt;반드시 (전투에 상관을 신뢰하고 임하여) 죽으려 하는 자는 (전투에서 승리하여) 살고&lt;br /&gt;반드시 (도주해서라도) 살고자 하는 자는 (군법으로) 죽을 것이요&lt;br /&gt;&lt;/li&gt;&lt;li&gt;모순율.&lt;br /&gt;어긋나는 것이 속할 수 없으며, 어긋나는 성질이 함께 속할 수 없다는 것이다.&lt;br /&gt;모순의 원형인 어떤 방패라도 뚫을 수 있는 창과 어떤 창도 막을수 있는 방패가 대표적인 예.&lt;br /&gt;&lt;br /&gt;역시 동일한 관점으로 판단하는 것이 중요하다.&lt;br /&gt;흔히 말하는 웃프다(웃을만 하지만 슬프다)가 대표적인 예로, 즐거움이란 감정과 슬프다는 감정은 공존할 수 없지만 다른 관점으로 보았을 때는 모순되지 않는다.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;배중률.&lt;br /&gt;중간(혹은 3자)는 배제된다, 모순 관계에 있는 두 생각이 모두 틀릴 수 없다는 것이다.&lt;br /&gt;위에서 나온 최강의 창과 방패란 가정에서 둘 중 하나가 틀리다면 나머지 하나는 정답이다.&lt;br /&gt;&lt;br /&gt;역시 배중률에서도 주의할 점이 존재한다.&lt;br /&gt;앞서 나온 다른 관점과 모순이 아닌 관계일 때이다.&lt;br /&gt;배중률은 모순관계인가를 주의깊게 살펴야 적용가능하다.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. 변수선언.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;저는 변수를 선언하여, 만약 수수료(charge-level)나 수수료의 기준금액(exch-level)이 바뀌면 변수만 조정하면 되도록 하였습니다.&lt;/p&gt;
&lt;p&gt;이말은 변수만 바꾸면 되며 굳이 함수내부의 구조까지 알 필요가 없다는 뜻입니다.&lt;/p&gt;
&lt;p&gt;관리의 측면에서 큰 이득입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. 함수 모듈화.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;반복되는 함수를 나뉘어 놓았습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우리가 실제로 사용하는 주기능을 하는 함수(krw-&amp;gt;usd)와 보조해주는 함수(exch-money, charge-calc)로 나눴습니다.&lt;/p&gt;
&lt;p&gt;주기능을 하는 함수를 주함수(Main Function), 보조해주는 함수를 보조함수(Auxiliary Function)라 합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;1개의 함수는 1~2개 정도의 기능만 해야 하며, 너무 길어지는 것은 관리하기가 힘들어져서 확장하거나 문제가 생겼을때 고치기도 힘들고, 중복된 코드의 양이 늘어날 가능성도 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;함수를 쪼개놓으면 미리 만들어놓은 함수를 재사용하게 된다.&lt;/p&gt;
&lt;p&gt;재사용을 하면 같은 문제에 시간을 낭비할 필요가 없어지니 이득!!&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. 모으기.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;여기부터는 가독성과 관련된 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;좋은 글이 읽기 쉬운거처럼, 좋은 소스코드의 조건에도 읽기 쉬워야된다는 조건이 붙습니다.&lt;/p&gt;
&lt;p&gt;그래야 편하게 관리를 하고, 의도를 파악할 수 있죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;서로 관련이 있는 항목끼리 모아놓고 관련이 없는 것과는 줄을 띄어서 관리하는 것은 가독성 관리의 기본이라 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;그룹화를 하게되면, 더 큰덩어리로 다룰수 있기 때문.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;줄을 띄어쓰는 것 말고, 주석으로 공간을 구분하여 서로 관련이 있는 기능들을 모아놓았습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. 열 맞추기.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;과연 소스코드를 세로로 읽을 수 있는 방법이 없을까 하고 고민하다 제가 작년부터 도입한 방식입니다.&lt;/p&gt;
&lt;p&gt;글의 경우, 왼쪽정렬을 하는 것이 만들기도 편하고 가장 가독성이 좋기에 왼쪽정렬방식으로 되어있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이 또한 서로 관련이 있는 항목끼리 열을 맞추어 가독성을 높인 것입니다.&lt;/p&gt;
&lt;p&gt;예) 변수선언, Cond내부 등&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;좋은 코드가 되려면 관리성, 가독성, 확장성 등 여러가지를 고려해야 합니다.&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h4&gt;+.&lt;br /&gt;&lt;/h4&gt;&lt;p&gt;아래의 제 텀블러 포스트들을 보며 필자의 개똥철학을 느껴보자.&lt;/p&gt;
&lt;p&gt;그냥 싸질러놓은 거라 몇몇요소에서는 살짝 난해할 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;또 염두해야 할건, 강좌로 쓴다고 다 옳다는 건 아니고, 내가 좋다고 생각하는 방식을 소개하는 것뿐이다.&lt;/p&gt;
&lt;p&gt;프로그래밍은 은근 예술(Art)의 축에 속하여 각 사람마다 다른 철학이 첨예하게 논쟁을 벌인다.&lt;/p&gt;
&lt;p&gt;대표적인 것이 앞에서 언급된 네이밍 컨벤션.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;열맞춤을 이용한 가독성 향상법&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/168955500760/%EC%97%B4%EB%A7%9E%EC%B6%A4%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EA%B0%80%EB%8F%85%EC%84%B1-%ED%96%A5%EC%83%81%EB%B2%95&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://black7375.tumblr.com/post/168955500760/열맞춤을-이용한-가독성-향상법&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
 &lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/168955500760&quot; data-did=&quot;fc9ec47da05729887eb1138e4bf0b2ad1884c18e&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/168955500760/열맞춤을-이용한-가독성-향상법&quot;&gt;https://black7375.tumblr.com/post/168955500760/열맞춤을-이용한-가독성-향상법&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;주석을 되도록 쓰지 말자.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/169042924365/주석을-되도록-쓰지-말자&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://black7375.tumblr.com/post/169042924365/주석을-되도록-쓰지-말자&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
 &lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/169042924365&quot; data-did=&quot;b1ee89bd358d13c1f71668b9131b41ed5546324d&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/169042924365/주석을-되도록-쓰지-말자&quot;&gt;https://black7375.tumblr.com/post/169042924365/주석을-되도록-쓰지-말자&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;주석의 오모함.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/168962832200/주석의-오모함&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://black7375.tumblr.com/post/168962832200/주석의-오모함&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
 &lt;div class=&quot;tumblr-post&quot; data-href=&quot;https://embed.tumblr.com/embed/post/k_R1-u4V1Tvc52yda1jroA/168962832200&quot; data-did=&quot;2b48d367fcc89872c69c39ee62b5c3d2d7eaf0c9&quot;&gt;&lt;a href=&quot;https://black7375.tumblr.com/post/168962832200/주석의-오모함&quot;&gt;https://black7375.tumblr.com/post/168962832200/주석의-오모함&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;2.5 디자인 레시피 기초.&lt;br /&gt;&lt;/h3&gt;&lt;p&gt;혹시 문제 2.4를 풀때 살짝 햇갈리지 않았나요?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;프로그램의 규모가 커질수록 내부는 더 복잡해는 경우가 많기 때문에 논리적이고, 체계적으로 접근해야합니다.&lt;/p&gt;
&lt;p&gt;익숙해지면 쓰윽~ 구조만 짜놓고 바로 코드를 짤수도 있겠지만, 이게 잘 안되는 초보자에게는 더더욱 그렇습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;프로그램 만드는 방식을 일종의 공식화를 해놓은 것을 여기선&amp;nbsp; '디자인 레시피'라고 부릅니다.(전글에 소개시켜줬습니다.)&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;디자인 레시피를 이용해 2.5의 코드를 만들어봅시다.&lt;/p&gt;
&lt;p&gt;하지만 2.5코드의 구조는 그리 복잡하지 않기에 축소된 디자인 레시피를 사용할 것입니다.&lt;/p&gt;
&lt;p&gt;소잡는데 쓰는 칼을 닭잡을 때 쓸 필요가 없죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div style=&quot;border:1px solid; padding:10px;&quot;&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;b&gt;축소된 디자인 레시피 .&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;1. 문제분석.&lt;/p&gt;
&lt;p&gt;함수가 다루는 조건을 살펴본다.&lt;/p&gt;
&lt;p&gt;문제 분석을 통해 문제 속 모든 조건을 나열한다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;2.  계약, 목적, 헤더.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;계약(Contract): 의미가 있는 이름을 붙이고, 정보의 입출력을 작성한다.&lt;br /&gt;문제 분석 내용을 기초로 작성합니다.&lt;br /&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Design_by_contract&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;계약에 의한 설계(Design by Contract)&lt;/a&gt;라는 것을 바탕으로 합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;계약을 작성한 다음, 함수의 헤더(Header)를 작성합니다.&lt;/p&gt;
&lt;p&gt;헤더(Header): 계약을 바탕으로 함수명과 파라미터를 작성합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;마지막으로,&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;목적: 프로그램의 목적을 작성한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;3. 예시.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;2.2.1 함수 만들기에서 미리 테스트용 예제를 만들어놓을 필요가 있다고 했었습니다.&lt;/p&gt;
&lt;p&gt;각 조건마다 예제를 만듭시다.&lt;/p&gt;
&lt;p&gt;예제들은 조건마다 1개씩은 만들고, 조건 구간의 경계값을 포함해야 합니다.&lt;/p&gt;
&lt;p&gt;조건의 경계구간이 들어가는 예를 작성해야 오류확인이 쉽겠죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;4.&amp;nbsp; 함수 정의.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;문제 2.5의 코드는 짧습니다.&lt;/p&gt;
&lt;p&gt;때문에 템플릿과정은 생략된뒤 진행됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;매개변수(Parameter)를 사용해 각 조건의 틀을 완성 후, 구현을 합니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;5. 테스트.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;미리 만들어놓던 예시를 가지고, 테스트를 한다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;6. 정리.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;필요없는 부분을 제거하고, 코드를 보기좋게 정리합니다.&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;한번 만들어봅시다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. 문제분석.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;수수료&lt;/b&gt;를 걷을때, &lt;b&gt;조건&lt;/b&gt;에 따라 수수료가 붙는다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이때 저는 간결히 표현하기 위해 수식으로 표현하도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;$$f(x) = \begin{cases}&lt;br /&gt;[0, &amp;amp; 100000], &amp;amp; 3\%&amp;nbsp; \\&lt;br /&gt;(100000, &amp;amp; 1000000], &amp;amp; 4\% \\&lt;br /&gt;(1000000, &amp;amp; 10000000], &amp;amp; 5\% \\&lt;br /&gt;(10000000, &amp;amp; 50000000], &amp;amp; 4\% \\&lt;br /&gt;(50000000, &amp;amp; 100000000], &amp;amp; 3.5\% \\&lt;br /&gt;(100000000, &amp;amp; +\infty), &amp;amp; 3\%&lt;br /&gt;\end{cases}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;[]는 닫힌(폐)구간, ()는 열린(개)구간입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. 계약, 목적, 헤더.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;계약.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;krw에서 usd로 바뀐 '결과값'이 나오기 때문에 krw-&amp;gt;usd를 함수명으로 정하였습니다.&lt;/p&gt;
&lt;p&gt;매개변수인 원화와 결과값인 달러 모두 '숫자'라는 데이터(자료형)을 사용합니다.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;Constract: krw-&amp;gt;usd ; number-&amp;gt;number&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;세미콜론을 사용하여 함수이름과 입출력을 구분하였습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;헤더.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;krw-&amp;gt;usd인 함수의 매개변수부분까지 작성합니다.&lt;/p&gt;
&lt;p&gt;이때 저는 들어오는 돈의 단위가 원(won)이므로, won이란 이름의 파라미터를 사용했습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (krw-&amp;gt;usd won) 표현식)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;함수정의 및 구현을 할 때 '표현식'부분을 채워갈 것입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;목적.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;이 프로그램의 목적은 원화를 달러로 환전하는 것입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;또한 금액에 따른 수수료를 내야 합니다.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;Purpose: Exchange KRW to USD and make a commission based on the amount.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. 예시.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;우리가 만들 함수에서 경계값은 수식에서의 0, 100000, 
1000000, 10000000, 50000000, 100000000입니다. 그리고 추가적으로 음수값과 1억이 넘는 값을 넣어보는
 것입니다.(양 극단의 경계값이라 할 수 있죠.)&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;-1000: 에러. 환전안됨.&lt;/p&gt;
&lt;p&gt;0: 0, 3%&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;100000: 3%&lt;/p&gt;
&lt;p&gt;1000000: 4%&lt;/p&gt;
&lt;p&gt;10000000: 5%&lt;/p&gt;
&lt;p&gt;50000000: 4%&lt;/p&gt;
&lt;p&gt;100000000: 3.5%&lt;/p&gt;
&lt;p&gt;200000000: 3%&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;라는 것을 염두해보고 8개를 미리 계산해봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;공식은 다음과 같습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;$$\frac{금액 - (수수료 \times 금액)}{krw(1000)}$$&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그리고, 계산한 결과를 적어줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;Example: Input     -&amp;gt; Output
;;         -1000     -&amp;gt; Error
;;         0         -&amp;gt; 0
;;         100000    -&amp;gt; 97
;;         1000000   -&amp;gt; 960
;;         10000000  -&amp;gt; 9500
;;         50000000  -&amp;gt; 48000
;;         100000000 -&amp;gt; 96500
;;         200000000 -&amp;gt; 194000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;가 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. 함수 정의.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;먼저 관리의 편의성을 위해 수수료 기준 금액과 수수료를 변수로 선언해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;수수료
 기준 금액은 교환레벨(Exchange Level)이라는 의미에서 exch-level, 수수료는 요금이라는 의미에서 
charge-level이라는 이름을 붙였습니다. 만약 한국 돈말고 다른 나라의 돈도 바꾸어야 했다면, exch-level 대신 
krw-level을 사용했을겁니다. Commission이란 단어를 수수료의 의미로 사용하지 않은 이유는 길기도 하고, 
Charge보다 의미를 모르는 사람들이 많을 확률이 높기 때문입니다.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define exch-level1 100000)
(define exch-level2 1000000)
(define exch-level3 10000000)
(define exch-level4 50000000)
(define exch-level5 100000000)

(define charge-level1 0.03)
(define charge-level2 0.035)
(define charge-level3 0.04)
(define charge-level4 0.05)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;변수 설정과정은 끝났고,&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우선 미리 작성해놓았던 헤더의 함수표현식 부분을 각 조건들을 표시해보았습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (krw-&amp;gt;usd2 won)
  (cond
    [(&amp;gt; 0 won) ...]
    [(or (&amp;gt;= exch-level1 won)
         (&amp;lt; exch-level5 won)) ...]
    [(&amp;gt;= exch-level2 won) ...]
    [(&amp;gt;= exch-level3 won) ...]
    [(&amp;gt;= exch-level4 won) ...]
    [(&amp;gt;= exch-level5 won) ...])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이제 응답 부분을 채워야 합니다.&lt;/p&gt;
&lt;p&gt;응답 부분은 수수료를 빼고, 환전을 해주는 기능입니다.&lt;/p&gt;
&lt;p&gt;2가지의 기능이 들어간다는 것을 알 수 있습니다.(수수료를 뺌, 환전)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;저는 krw-&amp;gt;usd2가 복잡해지는 것을 방지하기 위해 이 두 기능을 보조 함수로 만들었습니다.&lt;/p&gt;
&lt;p&gt;보조함수를 만들 때도 똑같은 과정을 거칩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;수수료 기능은 수수료를 계산(Charge Calculate)를 해준다는 뜻에서 charge-calc로 정했습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;환전 기능은 달러로 변환을 해주기 때문에 exch-usd로 하였습니다.&lt;/p&gt;
&lt;p&gt;이런식으로 2~3번 과정을 완료합니다.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;;Constract: charge-calc ; number, number-&amp;gt;number
;;Purpose: Calculate money excluding commissions.
;;Example: Input     -&amp;gt; Output
;;         0.1,  100 -&amp;gt; 90
;;         0.03, 100 -&amp;gt; 97
(define (charge-calc charge-level money) ...)

;;Constract: exch-usd ; number-&amp;gt;usd
;;Purpose: Exchange money to USD with exchanging rate.
;;Example: Input     -&amp;gt; Output
;;         1000, krw -&amp;gt; 1
;;         0.8,  eur -&amp;gt; 1
;;         6,    cny -&amp;gt; 1
(define (exch-usd money exch-rate) ...)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고, 함수를 완성시키고 예제를 가지고 테스트 해봅니다.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (charge-calc charge-level money)
  (- money (* charge-level money)))

(define (exch-usd money exch-rate)
  (/ money exch-rate))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;* 테스트하는것은 테스트단계에 한꺼번에 적겠습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;다시 krw-&amp;gt;usd2로 돌아옵시다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;charge-calc과 exch-usd를 가지고 응답부분을 채우면 krw-&amp;gt;usd2가 완성됩니다.&lt;/p&gt;
&lt;p&gt;음수 부분은 0보다 작은 값이 들어왔다는 것을 알려주기 위해 'Error-*less-than-0*로 응답하도록 했습니다.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define (krw-&amp;gt;usd2 won)
  (cond
    [(&amp;gt; 0 won) 'Error-*less-than-0*]
    [(or (&amp;gt;= exch-level1 won)
         (&amp;lt; exch-level5 won)) (exch-usd (charge-calc charge-level1 won) krw)]
    [(&amp;gt;= exch-level2 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level3 won) (exch-usd (charge-calc charge-level4 won) krw)]
    [(&amp;gt;= exch-level4 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level5 won) (exch-usd (charge-calc charge-level2 won) krw)]))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;완성되었습니다!!&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. 테스트.&lt;/b&gt; &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;안적었었던 charge-calc과 exch-usd 테스트 코드입니다.[보기 쉬우라고 미리 열맞춤을 적용시켜놓았습니다.]&lt;/p&gt;
&lt;p&gt;예제를 기반으로 만들어져있죠?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(charge-calc 0.1 100) ;90
(charge-calc 0.03 100) ;97

(exch-usd 1000 krw) ;1
(exch-usd 0.8  eur) ;1
(exch-usd 6    cny) ;1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;새로만든 krw-&amp;gt;usd2 예전에 만들어놓은 krw-&amp;gt;usd를 테스트 코드로 비교해보았습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(krw-&amp;gt;usd2 -1000)     ;Error
(krw-&amp;gt;usd2 0)         ;0
(krw-&amp;gt;usd2 100000)    ;97
(krw-&amp;gt;usd2 1000000)   ;960
(krw-&amp;gt;usd2 10000000)  ;9500
(krw-&amp;gt;usd2 50000000)  ;48000
(krw-&amp;gt;usd2 100000000) ;96500
(krw-&amp;gt;usd2 200000000) ;194000

(krw-&amp;gt;usd  -1000)     ;Error -&amp;gt; -0.97 Problem!!!
(krw-&amp;gt;usd  0)         ;0
(krw-&amp;gt;usd  100000)    ;97
(krw-&amp;gt;usd  1000000)   ;960
(krw-&amp;gt;usd  10000000)  ;9500
(krw-&amp;gt;usd  50000000)  ;48000
(krw-&amp;gt;usd  100000000) ;96500
(krw-&amp;gt;usd  200000000) ;194000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(krw-&amp;gt;usd -1000)에서는 -0.97이라는 답이 나오며 원하던 모습과 다르게 동작하여 문제가 생겼습니다.&lt;/p&gt;
&lt;p&gt;음수를 처리하는 것을 깜박하여 생긴것으로 디자인 레시피의 과정을 따라가지 않는다면 충분히 나올수도 있을 법만한 실수입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;테스트까지 모두 끝났으니 답을 한번 구해봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(krw-&amp;gt;usd2 20000000)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과: 19200&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;6. 정리.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;디자인 레시피의 마지막 과정으로 코드를 깔끔하게 정리해봅시다.&lt;/p&gt;
&lt;p&gt;유종의 미를 거둘 시간~&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;현재 여러분의 다음과 같이 생겼으며 상당히 어지러울 것입니다.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define exch-level1 100000)
(define exch-level2 1000000)
(define exch-level3 10000000)
(define exch-level4 50000000)
(define exch-level5 100000000)

(define charge-level1 0.03)
(define charge-level2 0.035)
(define charge-level3 0.04)
(define charge-level4 0.05)

;;Constract: charge-calc ; number, number-&amp;gt;number
;;Purpose: Calculate money excluding commissions.
;;Example: Input     -&amp;gt; Output
;;         0.1,  100 -&amp;gt; 90
;;         0.03, 100 -&amp;gt; 97
(define (charge-calc charge-level money)
  (- money (* charge-level money)))

(charge-calc 0.1 100) ;90
(charge-calc 0.03 100) ;97

;;Constract: exch-usd ; number, number-&amp;gt;usd
;;Purpose: Exchange money to USD with exchanging rate.
;;Example: Input     -&amp;gt; Output
;;         1000, krw -&amp;gt; 1
;;         0.8,  eur -&amp;gt; 1
;;         6,    cny -&amp;gt; 1
(define (exch-usd money exch-rate)
  (/ money exch-rate))

(exch-usd 1000 krw) ;1
(exch-usd 0.8 eur) ;1
(exch-usd 6 cny) ;1

;;Constract: krw-&amp;gt;usd ; number-&amp;gt;number
;;Purpose: Exchange KRW to USD and make a commission based on the amount.
;;Example: Input     -&amp;gt; Output
;;         -10       -&amp;gt; Error
;;         0         -&amp;gt; 0
;;         100000    -&amp;gt; 97
;;         1000000   -&amp;gt; 960
;;         10000000  -&amp;gt; 9500
;;         50000000  -&amp;gt; 48000
;;         100000000 -&amp;gt; 96500
;;         200000000 -&amp;gt; 194000
(define (krw-&amp;gt;usd2 won)
  (cond
    [(&amp;gt; 0 won) 'Error-*less-than-0*]
    [(or (&amp;gt;= exch-level1 won)
         (&amp;lt; exch-level5 won)) (exch-usd (charge-calc charge-level1 won) krw)]
    [(&amp;gt;= exch-level2 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level3 won) (exch-usd (charge-calc charge-level4 won) krw)]
    [(&amp;gt;= exch-level4 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level5 won) (exch-usd (charge-calc charge-level2 won) krw)]))

(krw-&amp;gt;usd2 -1000) ;Error
(krw-&amp;gt;usd2 0) ;0
(krw-&amp;gt;usd2 100000) ;97
(krw-&amp;gt;usd2 1000000) ;960
(krw-&amp;gt;usd2 10000000) ;9500
(krw-&amp;gt;usd2 50000000) ;48000
(krw-&amp;gt;usd2 100000000) ;96500
(krw-&amp;gt;usd2 200000000) ;194000

(krw-&amp;gt;usd  -1000) ;Error -&amp;gt; -0.97 Problem!!!
(krw-&amp;gt;usd  0) ;0
(krw-&amp;gt;usd  100000) ;97
(krw-&amp;gt;usd  1000000) ;960
(krw-&amp;gt;usd  10000000) ;9500
(krw-&amp;gt;usd  50000000) ;48000
(krw-&amp;gt;usd  100000000) ;96500
(krw-&amp;gt;usd  200000000) ;194000

(krw-&amp;gt;usd2 20000000)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;코드제거.&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;첫번째로 해야 할 것은 쓸데없는 코드를 제거하는 것입니다.&lt;/p&gt;
&lt;p&gt;쓸데없는 코드는 실행했을때 아무런 의미도 가지지 않는 코드입니다.&lt;/p&gt;
&lt;p&gt;주석이란 뜻이죠.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그중에서도 가장 쓸모가 없는 것은 예제를 나타낸 코드입니다.&lt;/p&gt;
&lt;p&gt;이미 테스트코드와 예상답을 적어놓았으니 어찌보면 중복된 의미를 가진 것을 제거한다고 볼 수도 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예제코드 제거결과.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define exch-level1 100000)
(define exch-level2 1000000)
(define exch-level3 10000000)
(define exch-level4 50000000)
(define exch-level5 100000000)

(define charge-level1 0.03)
(define charge-level2 0.035)
(define charge-level3 0.04)
(define charge-level4 0.05)

;;Constract: charge-calc ; number, number-&amp;gt;number
;;Purpose: Calculate money excluding commissions.
(define (charge-calc charge-level money)
  (- money (* charge-level money)))

(charge-calc 0.1 100) ;90
(charge-calc 0.03 100) ;97

;;Constract: exch-usd ; number, number-&amp;gt;usd
;;Purpose: Exchange money to USD with exchanging rate.
(define (exch-usd money exch-rate)
  (/ money exch-rate))

(exch-usd 1000 krw) ;1
(exch-usd 0.8 eur) ;1
(exch-usd 6 cny) ;1

;;Constract: krw-&amp;gt;usd ; number-&amp;gt;number
;;Purpose: Exchange KRW to USD and make a commission based on the amount.
(define (krw-&amp;gt;usd2 won)
  (cond
    [(&amp;gt; 0 won) 'Error-*less-than-0*]
    [(or (&amp;gt;= exch-level1 won)
         (&amp;lt; exch-level5 won)) (exch-usd (charge-calc charge-level1 won) krw)]
    [(&amp;gt;= exch-level2 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level3 won) (exch-usd (charge-calc charge-level4 won) krw)]
    [(&amp;gt;= exch-level4 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level5 won) (exch-usd (charge-calc charge-level2 won) krw)]))

(krw-&amp;gt;usd2 -1000) ;Error
(krw-&amp;gt;usd2 0) ;0
(krw-&amp;gt;usd2 100000) ;97
(krw-&amp;gt;usd2 1000000) ;960
(krw-&amp;gt;usd2 10000000) ;9500
(krw-&amp;gt;usd2 50000000) ;48000
(krw-&amp;gt;usd2 100000000) ;96500
(krw-&amp;gt;usd2 200000000) ;194000

(krw-&amp;gt;usd  -1000) ;Error -&amp;gt; -0.97 Problem!!!
(krw-&amp;gt;usd  0) ;0
(krw-&amp;gt;usd  100000) ;97
(krw-&amp;gt;usd  1000000) ;960
(krw-&amp;gt;usd  10000000) ;9500
(krw-&amp;gt;usd  50000000) ;48000
(krw-&amp;gt;usd  100000000) ;96500
(krw-&amp;gt;usd  200000000) ;194000

(krw-&amp;gt;usd2 20000000)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;모으기.[행 단위 정리]&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;다음으로 해야 할 일은 비슷한 의미를 가지는 코드들을 모으는 것 입니다.&lt;/p&gt;
&lt;p&gt;여기서 가장 먼저해야 할 것은 진짜 작동하기위한 코드와 테스트용 코드를 분리하는 것입니다.&lt;/p&gt;
&lt;p&gt;이때 계약(Constract)과 목적(Purpose)가 있는 코드를 테스트 코드와 함께 분리합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;계약과 목적부분의 주석을 테스트 코드와 함께 분리하는 이유는 테스트를 해보는 사람에게 함수의 계약과 목적부분은 일종의 문서처럼 작용할 수 있기 때문입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;구현이 된 코드와 테스트하는 코드는 성질이 아예 다른 것이기 때문에 원칙적으로 파일을 분리시켜서 관리해야합니다.(원래 파일이 section3였다면 section3_test와 같이.)&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;사실
 프로그래밍에 익숙해지면 계약과 목적부분은 굳이 작성하지 않아도 곧바로 만들수 있으며, 모든 함수마다 계약과 목적을 설명하는 것도
 힘들어 관리가 힘듭니다. 그래서 전 일관성을 위해 만들었더라도 아예 없애버리는 편입니다. 여기선 힘들게 만들었으니 한번 
써먹어보고 남기고 싶다면 어떻게 해야하는지 가이드를 해주는 것에 가깝습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;테스트 모으기 결과.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define exch-level1 100000)
(define exch-level2 1000000)
(define exch-level3 10000000)
(define exch-level4 50000000)
(define exch-level5 100000000)

(define charge-level1 0.03)
(define charge-level2 0.035)
(define charge-level3 0.04)
(define charge-level4 0.05)

(define (charge-calc charge-level money)
  (- money (* charge-level money)))

(define (exch-usd money exch-rate)
  (/ money exch-rate))

(define (krw-&amp;gt;usd2 won)
  (cond
    [(&amp;gt; 0 won) 'Error-*less-than-0*]
    [(or (&amp;gt;= exch-level1 won)
         (&amp;lt; exch-level5 won)) (exch-usd (charge-calc charge-level1 won) krw)]
    [(&amp;gt;= exch-level2 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level3 won) (exch-usd (charge-calc charge-level4 won) krw)]
    [(&amp;gt;= exch-level4 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level5 won) (exch-usd (charge-calc charge-level2 won) krw)]))

(krw-&amp;gt;usd2 20000000)

;;Constract: charge-calc ; number, number-&amp;gt;number
;;Purpose: Calculate money excluding commissions.
(charge-calc 0.1 100) ;90
(charge-calc 0.03 100) ;97

;;Constract: exch-usd ; number, number-&amp;gt;usd
;;Purpose: Exchange money to USD with exchanging rate.
(exch-usd 1000 krw) ;1
(exch-usd 0.8 eur) ;1
(exch-usd 6 cny) ;1

;;Constract: krw-&amp;gt;usd ; number-&amp;gt;number
;;Purpose: Exchange KRW to USD and make a commission based on the amount.
(krw-&amp;gt;usd2 -1000) ;Error
(krw-&amp;gt;usd2 0) ;0
(krw-&amp;gt;usd2 100000) ;97
(krw-&amp;gt;usd2 1000000) ;960
(krw-&amp;gt;usd2 10000000) ;9500
(krw-&amp;gt;usd2 50000000) ;48000
(krw-&amp;gt;usd2 100000000) ;96500
(krw-&amp;gt;usd2 200000000) ;194000

(krw-&amp;gt;usd  -1000) ;Error -&amp;gt; -0.97 Problem!!!
(krw-&amp;gt;usd  0) ;0
(krw-&amp;gt;usd  100000) ;97
(krw-&amp;gt;usd  1000000) ;960
(krw-&amp;gt;usd  10000000) ;9500
(krw-&amp;gt;usd  50000000) ;48000
(krw-&amp;gt;usd  100000000) ;96500
(krw-&amp;gt;usd  200000000) ;194000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;테스트하는 부분을 아래에 싹다 모아놓았습니다.&lt;/p&gt;
&lt;p&gt;그냥 파일이 분리되었다고 생각하십시오.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;나머지부분은 기능의 의미를 기준으로 모아봅시다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;교환레벨인 exch-level과 usd로 교환하는 exch-usd와 유사합니다.&lt;/p&gt;
&lt;p&gt;charge-level과 charge-calc은 수수료와 관계가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;기능 모으기 결과.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;(define exch-level1 100000)
(define exch-level2 1000000)
(define exch-level3 10000000)
(define exch-level4 50000000)
(define exch-level5 100000000)

(define (exch-usd money exch-rate)
  (/ money exch-rate))

(define charge-level1 0.03)
(define charge-level2 0.035)
(define charge-level3 0.04)
(define charge-level4 0.05)

(define (charge-calc charge-level money)
  (- money (* charge-level money)))

(define (krw-&amp;gt;usd2 won)
  (cond
    [(&amp;gt; 0 won) 'Error-*less-than-0*]
    [(or (&amp;gt;= exch-level1 won)
         (&amp;lt; exch-level5 won)) (exch-usd (charge-calc charge-level1 won) krw)]
    [(&amp;gt;= exch-level2 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level3 won) (exch-usd (charge-calc charge-level4 won) krw)]
    [(&amp;gt;= exch-level4 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level5 won) (exch-usd (charge-calc charge-level2 won) krw)]))

(krw-&amp;gt;usd2 20000000)


;;Constract: exch-usd ; number, number-&amp;gt;usd
;;Purpose: Exchange money to USD with exchanging rate.
(exch-usd 1000 krw) ;1
(exch-usd 0.8 eur) ;1
(exch-usd 6 cny) ;1

;;Constract: charge-calc ; number, number-&amp;gt;number
;;Purpose: Calculate money excluding commissions.
(charge-calc 0.1 100) ;90
(charge-calc 0.03 100) ;97

;;Constract: krw-&amp;gt;usd ; number-&amp;gt;number
;;Purpose: Exchange KRW to USD and make a commission based on the amount.
(krw-&amp;gt;usd2 -1000) ;Error
(krw-&amp;gt;usd2 0) ;0
(krw-&amp;gt;usd2 100000) ;97
(krw-&amp;gt;usd2 1000000) ;960
(krw-&amp;gt;usd2 10000000) ;9500
(krw-&amp;gt;usd2 50000000) ;48000
(krw-&amp;gt;usd2 100000000) ;96500
(krw-&amp;gt;usd2 200000000) ;194000

(krw-&amp;gt;usd  -1000) ;Error -&amp;gt; -0.97 Problem!!!
(krw-&amp;gt;usd  0) ;0
(krw-&amp;gt;usd  100000) ;97
(krw-&amp;gt;usd  1000000) ;960
(krw-&amp;gt;usd  10000000) ;9500
(krw-&amp;gt;usd  50000000) ;48000
(krw-&amp;gt;usd  100000000) ;96500
(krw-&amp;gt;usd  200000000) ;194000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;구현의 exchage 부분이 위쪽에 위치하므로 테스트 부분의 exch-usd를 윗쪽으로 이동하여 순서대로 정렬시켰습니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;구분하기.[행 구역 구분]&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;주석을 사용하여 코드들을 깔끔하게 구분해봅시다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;구분하기 결과.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;-------------------------Code 3.10-------------------------
;-------------------------Solution 3.3
;----------exchange
(define exch-level1 100000)
(define exch-level2 1000000)
(define exch-level3 10000000)
(define exch-level4 50000000)
(define exch-level5 100000000)

(define (exch-usd money exch-rate)
  (/ money exch-rate))

;----------charge
(define charge-level1 0.03)
(define charge-level2 0.035)
(define charge-level3 0.04)
(define charge-level4 0.05)

(define (charge-calc charge-level money)
  (- money (* charge-level money)))

;----------krw-&amp;gt;usd exchange
(define (krw-&amp;gt;usd2 won)
  (cond
    [(&amp;gt; 0 won) 'Error-*less-than-0*]
    [(or (&amp;gt;= exch-level1 won)
         (&amp;lt; exch-level5 won)) (exch-usd (charge-calc charge-level1 won) krw)]
    [(&amp;gt;= exch-level2 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level3 won) (exch-usd (charge-calc charge-level4 won) krw)]
    [(&amp;gt;= exch-level4 won) (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level5 won) (exch-usd (charge-calc charge-level2 won) krw)]))

;----------Test
(krw-&amp;gt;usd2 20000000)

;-------------------------Test 3.10-------------------------
;----------exch-usd
;;Constract: exch-usd ; number, number-&amp;gt;usd
;;Purpose: Exchange money to USD with exchanging rate.
(exch-usd 1000 krw) ;1
(exch-usd 0.8 eur) ;1
(exch-usd 6 cny) ;1

;----------charge
;;Constract: charge-calc ; number, number-&amp;gt;number
;;Purpose: Calculate money excluding commissions.
(charge-calc 0.1 100) ;90
(charge-calc 0.03 100) ;97

;----------krw-&amp;gt;usd exchange
;;Constract: krw-&amp;gt;usd ; number-&amp;gt;number
;;Purpose: Exchange KRW to USD and make a commission based on the amount.
(krw-&amp;gt;usd2 -1000) ;Error
(krw-&amp;gt;usd2 0) ;0
(krw-&amp;gt;usd2 100000) ;97
(krw-&amp;gt;usd2 1000000) ;960
(krw-&amp;gt;usd2 10000000) ;9500
(krw-&amp;gt;usd2 50000000) ;48000
(krw-&amp;gt;usd2 100000000) ;96500
(krw-&amp;gt;usd2 200000000) ;194000

;-----Compare with krw-&amp;gt;usd
(krw-&amp;gt;usd  -1000) ;Error -&amp;gt; -0.97 Problem!!!
(krw-&amp;gt;usd  0) ;0
(krw-&amp;gt;usd  100000) ;97
(krw-&amp;gt;usd  1000000) ;960
(krw-&amp;gt;usd  10000000) ;9500
(krw-&amp;gt;usd  50000000) ;48000
(krw-&amp;gt;usd  100000000) ;96500
(krw-&amp;gt;usd  200000000) ;194000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;의미별로 구분되어 쉽게 구별이 가죠?&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;열 맞추기.[열 단위 정리]&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;문법적으로 비슷한 의미를 가진 열끼리 열을 맞추어봅니다.&lt;/p&gt;
&lt;p&gt;세로로 읽을때 훨씬 깔끔하단 것을 느낄수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;코드를 보는데 표 같아서 좋다고 할까요.&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;scheme&quot;&gt;;-------------------------Code 3.10-------------------------
;-------------------------Solution 3.3
;----------exchange
(define exch-level1 100000   )
(define exch-level2 1000000  )
(define exch-level3 10000000 )
(define exch-level4 50000000 )
(define exch-level5 100000000)

(define (exch-usd money exch-rate)
  (/ money exch-rate))

;----------charge
(define charge-level1 0.03 )
(define charge-level2 0.035)
(define charge-level3 0.04 )
(define charge-level4 0.05 )

(define (charge-calc charge-level money)
  (- money (* charge-level money)))

;----------krw-&amp;gt;usd exchange
(define (krw-&amp;gt;usd2 won)
  (cond
    [(&amp;gt;  0           won)      'Error-*less-than-0*]
    [(or (&amp;gt;= exch-level1 won)
         (&amp;lt;  exch-level5 won)) (exch-usd (charge-calc charge-level1 won) krw)]
    [(&amp;gt;= exch-level2 won)      (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level3 won)      (exch-usd (charge-calc charge-level4 won) krw)]
    [(&amp;gt;= exch-level4 won)      (exch-usd (charge-calc charge-level3 won) krw)]
    [(&amp;gt;= exch-level5 won)      (exch-usd (charge-calc charge-level2 won) krw)]))

;----------Test
(krw-&amp;gt;usd2 20000000)


;-------------------------Test 3.10-------------------------
;----------exch-usd
;;Constract: exch-usd ; number, number-&amp;gt;usd
;;Purpose: Exchange money to USD with exchanging rate.
(exch-usd 1000 krw) ;1
(exch-usd 0.8  eur) ;1
(exch-usd 6    cny) ;1

;----------charge-calc
;;Constract: charge-calc ; number, number-&amp;gt;number
;;Purpose: Calculate money excluding commissions.
(charge-calc 0.1  100) ;90
(charge-calc 0.03 100) ;97

;----------krw-&amp;gt;usd
;;Constract: krw-&amp;gt;usd ; number-&amp;gt;number
;;Purpose: Exchange KRW to USD and make a commission based on the amount.
(krw-&amp;gt;usd2 -1000)     ;Error
(krw-&amp;gt;usd2 0)         ;0
(krw-&amp;gt;usd2 100000)    ;97
(krw-&amp;gt;usd2 1000000)   ;960
(krw-&amp;gt;usd2 10000000)  ;9500
(krw-&amp;gt;usd2 50000000)  ;48000
(krw-&amp;gt;usd2 100000000) ;96500
(krw-&amp;gt;usd2 200000000) ;194000

;-----Compare with krw-&amp;gt;usd
(krw-&amp;gt;usd  -1000)     ;Error -&amp;gt; -0.97 Problem!!!
(krw-&amp;gt;usd  0)         ;0
(krw-&amp;gt;usd  100000)    ;97
(krw-&amp;gt;usd  1000000)   ;960
(krw-&amp;gt;usd  10000000)  ;9500
(krw-&amp;gt;usd  50000000)  ;48000
(krw-&amp;gt;usd  100000000) ;96500
(krw-&amp;gt;usd  200000000) ;194000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;실제로 할때는 시간을 아끼고, 알아보기 쉽게하기 위해 처음부터 정리하는 것을 고려하며 코드를 짜도록 합시다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;드디어 디자인 레시피까지하여 내 맘대로 하는 프로그래밍 설계 2 - 기초가 끝났습니다.&lt;/p&gt;
&lt;p&gt;진짜 끝났어요.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;3. 섹션3 후기.&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;어때요?&lt;/p&gt;
&lt;p&gt;할 만 했나요?&lt;/p&gt;
&lt;p&gt;프로그래밍의 기본기를 익히신것을 축하합니다!!!!&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;섹션2는 HtDP의 2판이 완전히 새로 쓰여졌다길래 1판과 비교해가며 쓰느라 분량조절을 실패한듯 합니다.&lt;/p&gt;
&lt;p&gt;전반적으로 2판이 훨씬 재미있게 쓰여졌더라고요.&lt;/p&gt;
&lt;p&gt;제 강좌보다도. 영어가 가능하면 한번 보세요.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;전 텍스트로 놀지만 HtDP 2판에서는 애니메이션처럼 휙휙 움직이는 걸 눈앞에서 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;전 코드에 그림넣는게 귀찮아서 이 방식을 안따랐어요. 워낙 텍스트를 좋아하기도 하고.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote class=&quot;embedly-card&quot; data-card-controls=&quot;0&quot;&gt;&lt;h4&gt;&lt;a href=&quot;http://htdp.org/2003-09-26/Book/&quot;&gt;How to Design Programs: An Introduction to Computing and Programming&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;How
 to Design Programs An Introduction to Computing and Programming 
Matthias Felleisen Robert Bruce Findler Matthew Flatt Shriram 
Krishnamurthi The MIT Press Cambridge, Massachusetts London, England&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote class=&quot;embedly-card&quot; data-card-controls=&quot;0&quot;&gt;&lt;h4&gt;&lt;a href=&quot;http://htdp.org/2018-01-06/Book/&quot;&gt;How to Design Programs, Second Edition&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Matthias Felleisen, Robert Bruce Findler, Matthew Flatt, Shriram Krishnamurthi&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;제껀 (제생각에)알아야할 것들 위주로 우겨넣다보니 좀 노잼화가 됐고, '+' 때문에 주제가 이리저리 옮겨다니는 경향이 있는듯.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;다음 강좌에서는 고정된 데이터를 다루는 방법을 알아보도록 합시다.&lt;/p&gt;
&lt;p&gt;혹시 어려운점이나 오류, 추가했으면 하는 내용이 있으면 언제든지 댓글을 달아주세요.&lt;/p&gt;
&lt;p&gt;실시간으로 답변은 힘들지만, 하루에서 이틀안에 답변을 주도록 하겠습니다.&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;기타참고.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;철학의 주요개념(백종현)&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>프로그래밍/설계</category>
      <author>BlaCk_Void</author>
      <guid isPermaLink="true">https://black7375.tistory.com/34</guid>
      <comments>https://black7375.tistory.com/34#entry34comment</comments>
      <pubDate>Tue, 16 Jan 2018 04:23:57 +0900</pubDate>
    </item>
  </channel>
</rss>