<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>5분 기록</title>
    <link>https://noteit.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 11 Jun 2026 15:52:32 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>기록하는 남자</managingEditor>
    <image>
      <title>5분 기록</title>
      <url>https://tistory1.daumcdn.net/tistory/6775890/attach/d9c3439e8d1c407a87a1275224b440fc</url>
      <link>https://noteit.tistory.com</link>
    </image>
    <item>
      <title>[Calculus] 결정불능형 정리표</title>
      <link>https://noteit.tistory.com/entry/Elementary-calculus-%EA%B2%B0%EC%A0%95%EB%B6%88%EB%8A%A5%ED%98%95-%EC%A0%95%EB%A6%AC%ED%91%9C</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;1352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rhNSI/btsQVzx5mWY/yKKiE6AQkyrdKNtFkyxHq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rhNSI/btsQVzx5mWY/yKKiE6AQkyrdKNtFkyxHq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rhNSI/btsQVzx5mWY/yKKiE6AQkyrdKNtFkyxHq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrhNSI%2FbtsQVzx5mWY%2FyKKiE6AQkyrdKNtFkyxHq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;1352&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;1352&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;1150&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci1KEl/btsQWdIcBAV/8EO1vnlGWmTsgK6gjBqLWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci1KEl/btsQWdIcBAV/8EO1vnlGWmTsgK6gjBqLWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci1KEl/btsQWdIcBAV/8EO1vnlGWmTsgK6gjBqLWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci1KEl%2FbtsQWdIcBAV%2F8EO1vnlGWmTsgK6gjBqLWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;281&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;490&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;2796&quot; data-origin-height=&quot;1278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LkJ6W/btsQYsRvd1s/0qPtFFhYeH6aUWHqvgIGt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LkJ6W/btsQYsRvd1s/0qPtFFhYeH6aUWHqvgIGt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LkJ6W/btsQYsRvd1s/0qPtFFhYeH6aUWHqvgIGt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLkJ6W%2FbtsQYsRvd1s%2F0qPtFFhYeH6aUWHqvgIGt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2796&quot; height=&quot;1278&quot; data-origin-width=&quot;2796&quot; data-origin-height=&quot;1278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Mathematics</category>
      <author>기록하는 남자</author>
      <guid isPermaLink="true">https://noteit.tistory.com/56</guid>
      <comments>https://noteit.tistory.com/entry/Elementary-calculus-%EA%B2%B0%EC%A0%95%EB%B6%88%EB%8A%A5%ED%98%95-%EC%A0%95%EB%A6%AC%ED%91%9C#entry56comment</comments>
      <pubDate>Tue, 30 Sep 2025 21:22:50 +0900</pubDate>
    </item>
    <item>
      <title>[Analysis] lim (1/n) = 0의 &amp;epsilon;&amp;ndash;N 증명</title>
      <link>https://noteit.tistory.com/entry/Analysis-lim-1n-0%EC%9D%98-%CE%B5%E2%80%93N-%EC%A6%9D%EB%AA%85</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m24PV/btsQVV1YyhY/WOaWWzLhnsC09nRIRkodL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m24PV/btsQVV1YyhY/WOaWWzLhnsC09nRIRkodL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m24PV/btsQVV1YyhY/WOaWWzLhnsC09nRIRkodL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm24PV%2FbtsQVV1YyhY%2FWOaWWzLhnsC09nRIRkodL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1476&quot; height=&quot;126&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;126&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;1396&quot; data-origin-height=&quot;42&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BTAkx/btsQWjaztHf/DLkaZ2CVDkF0GYSgl5yL50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BTAkx/btsQWjaztHf/DLkaZ2CVDkF0GYSgl5yL50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BTAkx/btsQWjaztHf/DLkaZ2CVDkF0GYSgl5yL50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBTAkx%2FbtsQWjaztHf%2FDLkaZ2CVDkF0GYSgl5yL50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1396&quot; height=&quot;42&quot; data-origin-width=&quot;1396&quot; data-origin-height=&quot;42&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQAGJt/btsQXMiBrWX/Q5jGpVNwUdkAHqUQOVUgA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQAGJt/btsQXMiBrWX/Q5jGpVNwUdkAHqUQOVUgA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQAGJt/btsQXMiBrWX/Q5jGpVNwUdkAHqUQOVUgA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQAGJt%2FbtsQXMiBrWX%2FQ5jGpVNwUdkAHqUQOVUgA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;427&quot; height=&quot;65&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;166&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;1644&quot; data-origin-height=&quot;870&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUNEg0/btsQXYb1eP2/Uh2GkURKef7K6MewHukMsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUNEg0/btsQXYb1eP2/Uh2GkURKef7K6MewHukMsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUNEg0/btsQXYb1eP2/Uh2GkURKef7K6MewHukMsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUNEg0%2FbtsQXYb1eP2%2FUh2GkURKef7K6MewHukMsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1644&quot; height=&quot;870&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;870&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;저 식을 통해 n &amp;gt; N이 되는 N이 존재함을 증명하면 된다. 그러면 n &amp;gt; N을 만족하는 n 에 대해서 위 식이 성립한다고 볼 수 있다. 즉, 수렴이 된다고 볼 수 있다.&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;1066&quot; data-origin-height=&quot;850&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nqS8s/btsQVBCGGLM/vbKUa9RcgiDQwD1K0gpFn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nqS8s/btsQVBCGGLM/vbKUa9RcgiDQwD1K0gpFn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nqS8s/btsQVBCGGLM/vbKUa9RcgiDQwD1K0gpFn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnqS8s%2FbtsQVBCGGLM%2FvbKUa9RcgiDQwD1K0gpFn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;527&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;850&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;2060&quot; data-origin-height=&quot;1452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wglcb/btsQWsd5wID/XnRVscsFgCfCkLm70LNxz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wglcb/btsQWsd5wID/XnRVscsFgCfCkLm70LNxz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wglcb/btsQWsd5wID/XnRVscsFgCfCkLm70LNxz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwglcb%2FbtsQWsd5wID%2FXnRVscsFgCfCkLm70LNxz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;550&quot; data-origin-width=&quot;2060&quot; data-origin-height=&quot;1452&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>Mathematics</category>
      <author>기록하는 남자</author>
      <guid isPermaLink="true">https://noteit.tistory.com/54</guid>
      <comments>https://noteit.tistory.com/entry/Analysis-lim-1n-0%EC%9D%98-%CE%B5%E2%80%93N-%EC%A6%9D%EB%AA%85#entry54comment</comments>
      <pubDate>Tue, 30 Sep 2025 20:49:44 +0900</pubDate>
    </item>
    <item>
      <title>SOLID 원칙</title>
      <link>https://noteit.tistory.com/entry/SOLID-%EC%9B%90%EC%B9%99</link>
      <description>&lt;h2 data-end=&quot;142&quot; data-start=&quot;125&quot; data-ke-size=&quot;size26&quot;&gt;  SOLID 원칙이란?&lt;/h2&gt;
&lt;blockquote data-end=&quot;177&quot; data-start=&quot;144&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;177&quot; data-start=&quot;146&quot; data-ke-size=&quot;size16&quot;&gt;SOLID = 객체지향 설계 5대 원칙의 앞글자를 딴 말&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;485&quot; data-start=&quot;179&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;알파벳&lt;/td&gt;
&lt;td&gt;원칙 이름&lt;/td&gt;
&lt;td&gt;한글 설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;289&quot; data-start=&quot;239&quot;&gt;
&lt;td&gt;S&lt;/td&gt;
&lt;td&gt;Single Responsibility Principle&lt;/td&gt;
&lt;td&gt;단일 책임 원칙&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;330&quot; data-start=&quot;290&quot;&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;Open/Closed Principle&lt;/td&gt;
&lt;td&gt;개방-폐쇄 원칙&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;381&quot; data-start=&quot;331&quot;&gt;
&lt;td&gt;L&lt;/td&gt;
&lt;td&gt;Liskov Substitution Principle&lt;/td&gt;
&lt;td&gt;리스코프 치환 원칙&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;435&quot; data-start=&quot;382&quot;&gt;
&lt;td&gt;I&lt;/td&gt;
&lt;td&gt;Interface Segregation Principle&lt;/td&gt;
&lt;td&gt;인터페이스 분리 원칙&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;485&quot; data-start=&quot;436&quot;&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;Dependency Inversion Principle&lt;/td&gt;
&lt;td&gt;의존 역전 원칙&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;490&quot; data-start=&quot;487&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;509&quot; data-start=&quot;492&quot; data-ke-size=&quot;size26&quot;&gt;  각 원칙 자세히 보기&lt;/h2&gt;
&lt;h2 data-end=&quot;509&quot; data-start=&quot;492&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;S&lt;/b&gt;: 단일 책임 원칙 (Single Responsibility Principle)&lt;/h2&gt;
&lt;blockquote data-end=&quot;597&quot; data-start=&quot;570&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;597&quot; data-start=&quot;572&quot; data-ke-size=&quot;size16&quot;&gt;한 클래스는 &lt;b&gt;하나의 책임만&lt;/b&gt; 가져야 한다&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;677&quot; data-start=&quot;599&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;627&quot; data-start=&quot;599&quot;&gt;한 클래스는 하나의 기능(역할)에만 집중해야 함&lt;/li&gt;
&lt;li data-end=&quot;677&quot; data-start=&quot;628&quot;&gt;예: UserService는 사용자 관리만, EmailService는 이메일만&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1743926571910&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ❌ 잘못된 예
class UserManager {
  createUser() { ... }
  sendWelcomeEmail() { ... } // 이메일은 다른 책임!
}

// ✅ 바른 예
class UserManager {
  createUser() { ... }
}

class EmailService {
  sendWelcomeEmail() { ... }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 한 클래스는 자신과 관련된 것만 심플하게 책임을 가지도록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;952&quot; data-start=&quot;904&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;O&lt;/b&gt;: 개방-폐쇄 원칙 (Open/Closed Principle)&lt;/h3&gt;
&lt;blockquote data-end=&quot;985&quot; data-start=&quot;953&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;985&quot; data-start=&quot;955&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;확장에는 열려 있고, 변경에는 닫혀 있어야 한다&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1057&quot; data-start=&quot;987&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1022&quot; data-start=&quot;987&quot;&gt;새로운 기능은 기존 코드 &lt;b&gt;수정 없이&lt;/b&gt; 확장 가능해야 함&lt;/li&gt;
&lt;li data-end=&quot;1057&quot; data-start=&quot;1023&quot;&gt;예: 조건문 대신 다형성(Polymorphism)으로 확장&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1743926924691&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ❌ OCP 위반: 조건문 방식

class BadPaymentProcessor {
  process(type) {
    if (type === 'credit') {
      console.log('  카드 결제 처리');
    } else if (type === 'paypal') {
      console.log('  페이팔 결제 처리');
    }
  }
}

const bad1 = new BadPaymentProcessor();
bad1.process('credit');

//   &quot;카카오페이&quot; 추가하려면 기존 메서드 수정해야 함
class BadPaymentProcessorV2 {
  process(type) {
    if (type === 'credit') {
      console.log('  카드 결제 처리');
    } else if (type === 'paypal') {
      console.log('  페이팔 결제 처리');
    } else if (type === 'kakao') {
      console.log('  카카오페이 결제 처리'); // ✋ OCP 위반: 기존 코드 수정
    }
  }
}

const bad2 = new BadPaymentProcessorV2();
bad2.process('kakao');



// ✅ OCP 준수: 다형성 방식

class PaymentMethod {
  pay() {}
}

class CreditCard extends PaymentMethod {
  pay() { console.log('  카드 결제 처리'); }
}

class PayPal extends PaymentMethod {
  pay() { console.log('  페이팔 결제 처리'); }
}

class GoodPaymentProcessor {
  constructor(method) {
    this.method = method;
  }
  process() {
    this.method.pay();
  }
}

const good1 = new GoodPaymentProcessor(new CreditCard());
good1.process();

//   &quot;카카오페이&quot;는 클래스만 추가하면 됨! 기존 코드 수정 ❌
class KakaoPay extends PaymentMethod {
  pay() { console.log('  카카오페이 결제 처리'); }
}

const good2 = new GoodPaymentProcessor(new KakaoPay());
good2.process(); // OCP 지킴&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-end=&quot;1703&quot; data-start=&quot;1686&quot; data-ke-size=&quot;size23&quot;&gt;  설명 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1879&quot; data-start=&quot;1704&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1785&quot; data-start=&quot;1704&quot;&gt;❌ &lt;b&gt;BadPaymentProcessor&lt;/b&gt;는 기능을 추가할 때마다 조건문 늘어나고, 기존 코드를 &lt;b&gt;직접 수정해야 해서&lt;/b&gt; OCP를 위반함&lt;/li&gt;
&lt;li data-end=&quot;1879&quot; data-start=&quot;1786&quot;&gt;✅ &lt;b&gt;GoodPaymentProcessor&lt;/b&gt;는 새로운 기능이 생겨도 &lt;b&gt;클래스만 추가하면 되므로&lt;/b&gt; OCP를 만족함 (확장에는 열려 있고, 수정에는 닫혀 있음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if문으로 조건 거는 걸로 전부 처리하면 나중에 변경사항 생기면 조건문 건드려서 코드 고쳐야 되니까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 각각 상속한 각 클래스 사용하고 새로운 기능 오면 또 상속하는 새로운 클래스 만들어서 확장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1122&quot; data-start=&quot;1064&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;L&lt;/b&gt;: 리스코프 치환 원칙 (Liskov Substitution Principle)&lt;/h3&gt;
&lt;blockquote data-end=&quot;1161&quot; data-start=&quot;1123&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1161&quot; data-start=&quot;1125&quot; data-ke-size=&quot;size16&quot;&gt;자식 클래스는 &lt;b&gt;언제나 부모 클래스를 대체할 수 있어야 한다&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1191&quot; data-start=&quot;1163&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1191&quot; data-start=&quot;1163&quot;&gt;자식 클래스가 부모 클래스의 역할을 깨면 안 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1743927119994&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ❌ 잘못된 예: LSP 위반
class PaymentService {
  process(amount: number) {
    console.log(`결제 ${amount}원 완료`);
  }
}

class BankTransferService extends PaymentService {
  process(amount: number) {
    // ❗ 부모 클래스는 항상 결제를 처리할 수 있다고 보장했는데,
    // 자식 클래스가 그 계약을 깨버림 (런타임 오류 발생)
    throw new Error(&quot;BankTransfer는 수동 처리만 지원함&quot;);
  }
}

// 위의 구조는 리스코프 치환 원칙(LSP)을 위반한 것!
// PaymentService를 기대한 코드에서 BankTransferService로 바꾸면 문제가 생김.


// ✅ 바른 예: LSP 준수

//   공통된 동작을 추상화한 인터페이스 정의
interface IPaymentService {
  process(amount: number): void;
}

// 카드 결제는 정상적으로 process 가능
class CardPaymentService implements IPaymentService {
  process(amount: number) {
    console.log(`카드로 ${amount}원 결제 완료`);
  }
}

// 은행 이체는 결제와는 다른 방식이므로, 아예 다른 클래스/메서드로 분리
class BankTransferService {
  requestManualTransfer(amount: number) {
    console.log(`수동 이체 요청: ${amount}원`);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-end=&quot;755&quot; data-start=&quot;744&quot; data-ke-size=&quot;size26&quot;&gt;  설명 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;912&quot; data-start=&quot;756&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;851&quot; data-start=&quot;756&quot;&gt;잘못된 예에선 부모(PaymentService)는 process()를 보장하지만&lt;br /&gt;자식(BankTransferService)은 그걸 깨버림 &amp;rarr; LSP 위반 ❌&lt;/li&gt;
&lt;li data-end=&quot;912&quot; data-start=&quot;852&quot;&gt;바른 예에선 아예 인터페이스를 분리해서,&lt;br /&gt;각 클래스가 자기 역할만 하도록 설계 &amp;rarr; 안정성 확보 ✅&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;h3 data-end=&quot;1429&quot; data-start=&quot;1368&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;I&lt;/b&gt;: 인터페이스 분리 원칙 (Interface Segregation Principle)&lt;/h3&gt;
&lt;blockquote data-end=&quot;1479&quot; data-start=&quot;1430&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1479&quot; data-start=&quot;1432&quot; data-ke-size=&quot;size16&quot;&gt;많은 기능을 가진 &lt;b&gt;큰 인터페이스보단&lt;/b&gt;, &lt;b&gt;작고 구체적인 인터페이스&lt;/b&gt;로 나누자&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1743928905658&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ❌ 잘못된 예: 지나치게 큰 인터페이스

interface Worker {
  work(): void;
  eat(): void;
}

// 로봇도 작업은 하지만, 밥은 안 먹음
class HumanWorker implements Worker {
  work() { console.log('사람이 일함'); }
  eat() { console.log('사람이 밥 먹음'); }
}

class RobotWorker implements Worker {
  work() { console.log('로봇이 일함'); }

  // ❗ 로봇은 밥을 먹지 않지만, 어쩔 수 없이 구현해야 함 &amp;rarr; ISP 위반
  eat() {
    throw new Error(&quot;로봇은 밥을 먹지 않습니다&quot;);
  }
}



// ✅ 바른 예: 인터페이스 분리

interface Workable {
  work(): void;
}

interface Eatable {
  eat(): void;
}

class Human implements Workable, Eatable {
  work() { console.log('사람이 일함'); }
  eat() { console.log('사람이 밥 먹음'); }
}

class Robot implements Workable {
  work() { console.log('로봇이 일함'); }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1002&quot; data-start=&quot;990&quot; data-ke-size=&quot;size23&quot;&gt;  설명 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1198&quot; data-start=&quot;1004&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1095&quot; data-start=&quot;1004&quot;&gt;❌ &lt;b&gt;Worker&lt;/b&gt; 인터페이스는 &lt;b&gt;너무 많은 역할&lt;/b&gt;을 담고 있어서, 어떤 구현체(로봇)는 필요 없는 eat()까지 구현해야 함 &amp;rarr; &lt;b&gt;ISP 위반&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1198&quot; data-start=&quot;1096&quot;&gt;✅ 인터페이스를 Workable, Eatable로 &lt;b&gt;작게 나누면&lt;/b&gt;, 클래스는 &lt;b&gt;자신에게 필요한 기능만&lt;/b&gt; 선택해서 구현할 수 있음 &amp;rarr; &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;h3 data-end=&quot;132&quot; data-start=&quot;111&quot; data-ke-size=&quot;size23&quot;&gt;  두 원칙 차이 한눈에 정리&lt;/h3&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;494&quot; data-start=&quot;134&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;원칙&amp;nbsp;&lt;/td&gt;
&lt;td&gt;핵심&lt;/td&gt;
&lt;td&gt;개념위반 시&amp;nbsp;&lt;/td&gt;
&lt;td&gt;문제적용 시점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;340&quot; data-start=&quot;218&quot;&gt;
&lt;td&gt;&lt;b&gt;LSP (리스코프 치환 원칙)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;&amp;ldquo;자식은 부모를 대체할 수 있어야 한다&amp;rdquo;&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;부모 타입으로 사용했을 때 &lt;b&gt;예외가 발생&lt;/b&gt;하거나 &lt;b&gt;기대한 동작이 깨짐&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;상속할 때&lt;/b&gt; (클래스 간 관계)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;494&quot; data-start=&quot;341&quot;&gt;
&lt;td&gt;&lt;b&gt;ISP (인터페이스 분리 원칙)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;&amp;ldquo;클라이언트는 자신이 사용하지 않는 인터페이스에 의존하지 말아야 한다&amp;rdquo;&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;불필요한 메서드를 &lt;b&gt;강제로 구현&lt;/b&gt;해야 함 &amp;rarr; 코드가 지저분해지고, 책임이 섞임&lt;/td&gt;
&lt;td&gt;&lt;b&gt;인터페이스 설계할 때&lt;/b&gt; (타입 정의/구조 설계 시)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;h3 data-end=&quot;1731&quot; data-start=&quot;1674&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;D&lt;/b&gt;: 의존 역전 원칙 (Dependency Inversion Principle)&lt;/h3&gt;
&lt;blockquote data-end=&quot;1794&quot; data-start=&quot;1732&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1794&quot; data-start=&quot;1734&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고수준 모듈(비즈니스 로직)은 저수준 모듈(구현 디테일)에 의존하면 안 된다.&lt;/b&gt;&lt;br /&gt;대신 &lt;b&gt;추상화(인터페이스)에 의존해야 한다&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1824&quot; data-start=&quot;1796&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1824&quot; data-start=&quot;1796&quot;&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;pre id=&quot;code_1743927493430&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ❌ 나쁜 예: 구체 클래스에 직접 의존
class MySQLDatabase {
  connect() {
    console.log('MySQL 연결');
  }
}

class UserServiceBad {
  db = new MySQLDatabase(); //   문제! 특정 구현에 강하게 결합됨

  init() {
    this.db.connect();
  }
}

const badService = new UserServiceBad();
badService.init(); // ✅ 동작은 하지만 &amp;rarr; 나중에 다른 DB로 바꾸려면 이 클래스 자체를 수정해야 함



// ✅ 좋은 예: 인터페이스(추상화)에 의존
interface Database {
  connect(): void;
}

class MySQLDatabaseV2 implements Database {
  connect() { console.log('MySQL 연결'); }
}

class PostgreSQLDatabase implements Database {
  connect() { console.log('PostgreSQL 연결'); }
}

class UserService {
  constructor(private db: Database) {} //   추상화에 의존

  init() {
    this.db.connect();
  }
}

//   실제 사용 시, 원하는 구현체를 외부에서 주입하면 됨
const goodService = new UserService(new PostgreSQLDatabase());
goodService.init(); // ✅ PostgreSQL 연결&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;962&quot; data-start=&quot;950&quot; data-ke-size=&quot;size23&quot;&gt;  설명 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1210&quot; data-start=&quot;964&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1084&quot; data-start=&quot;964&quot;&gt;❌ &lt;b&gt;UserServiceBad&lt;/b&gt;는 MySQLDatabase라는 &lt;b&gt;구체 구현에 직접 의존&lt;/b&gt;해서,
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1084&quot; data-start=&quot;1028&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1084&quot; data-start=&quot;1028&quot;&gt;다른 DB를 쓰고 싶으면 내부 코드를 &lt;b&gt;직접 고쳐야 함&lt;/b&gt; &amp;rarr; &lt;b&gt;결합도 높음, 확장성 낮음&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1210&quot; data-start=&quot;1086&quot;&gt;✅ &lt;b&gt;UserService&lt;/b&gt;는 Database라는 &lt;b&gt;인터페이스(추상화)에만 의존&lt;/b&gt;하고,
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1210&quot; data-start=&quot;1145&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1210&quot; data-start=&quot;1145&quot;&gt;구체 구현(MySQL, PostgreSQL)은 &lt;b&gt;외부에서 주입(DI)&lt;/b&gt; &amp;rarr; &lt;b&gt;확장성 높고, 유지보수 쉬움&lt;/b&gt;&lt;b&gt;&lt;/b&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;156&quot; data-start=&quot;114&quot;&gt;&lt;b&gt;구체(Concrete)&lt;/b&gt; = 실제 동작을 가지고 있는 &lt;b&gt;구현체&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;213&quot; data-start=&quot;157&quot;&gt;&lt;b&gt;추상(Abstract)&lt;/b&gt; = 어떤 기능이 있을지는 정해졌지만, &lt;b&gt;구현은 없는 틀(약속)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 72px;&quot; border=&quot;1&quot; data-end=&quot;920&quot; data-start=&quot;531&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;뜻&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot; data-end=&quot;751&quot; data-start=&quot;683&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;추상&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;기능(역할)만 정의된 틀&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;interface, abstract class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot; data-end=&quot;820&quot; data-start=&quot;752&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;구체&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;실제 동작을 가진 클래스&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;class MySQLDatabase&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;실제 구현체말고 인터페이스를 비즈니스 로직 클래스가 사용하게 만드셈.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래야 비즈니스 인스턴스 생성할 때 바꿔 뀌는 게 되니까&lt;/p&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;h1 data-end=&quot;111&quot; data-start=&quot;80&quot;&gt;IoC &amp;amp; DI: DIP를 실현하는 핵심 도구들&lt;/h1&gt;
&lt;hr data-end=&quot;116&quot; data-start=&quot;113&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;164&quot; data-start=&quot;118&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;IoC (Inversion of Control, 제어의 역전)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;200&quot; data-start=&quot;166&quot; data-ke-size=&quot;size23&quot;&gt;  말 그대로: &lt;b&gt;제어 흐름의 주도권을 뒤집는다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;282&quot; data-start=&quot;202&quot; data-ke-size=&quot;size16&quot;&gt;보통 우리가 직접 객체를 new해서 제어하지만,&lt;br /&gt;IoC에서는 &lt;b&gt;외부에서 필요한 걸 알아서 넣어줌&lt;/b&gt; &amp;rarr; 그래서 &lt;b&gt;제어가 &amp;ldquo;역전&amp;rdquo;됨&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-end=&quot;302&quot; data-start=&quot;284&quot; data-ke-size=&quot;size23&quot;&gt;❌ 제어를 직접 하는 예:&lt;/h3&gt;
&lt;pre id=&quot;code_1743927729827&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class UserService {
  db = new MySQLDatabase(); // 직접 new 함 (제어권 자신에게 있음)
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-end=&quot;409&quot; data-start=&quot;390&quot; data-ke-size=&quot;size23&quot;&gt;✅ IoC (제어의 역전):&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1743927742583&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class UserService {
  constructor(private db: Database) {} // 외부에서 넣어줌 (제어권을 위임함)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&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;이처럼, 객체 생성이나 연결을 &lt;b&gt;직접 하지 않고 외부에 맡기는 게 IoC야.&lt;/b&gt;&lt;br /&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;705&quot; data-start=&quot;660&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DI (Dependency Injection, 의존성 주입)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-end=&quot;731&quot; data-start=&quot;707&quot; data-ke-size=&quot;size16&quot;&gt;  IoC를 실현하는 &lt;b&gt;구체적인 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;765&quot; data-start=&quot;733&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 필요한 의존성(객체)을 &lt;b&gt;외부에서 주입해주는 방식&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;770&quot; data-start=&quot;767&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;790&quot; data-start=&quot;772&quot; data-ke-size=&quot;size16&quot;&gt;DI는 크게 3가지 방식이 있어:&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;980&quot; data-start=&quot;792&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;방식&amp;nbsp;&lt;/td&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;886&quot; data-start=&quot;820&quot;&gt;
&lt;td&gt;&lt;b&gt;생성자 주입&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;constructor(private db: Database) &amp;larr; 우리가 방금 쓴 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;941&quot; data-start=&quot;887&quot;&gt;
&lt;td&gt;&lt;b&gt;세터 주입&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;setDatabase(db: Database) 같은 메서드로 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;980&quot; data-start=&quot;942&quot;&gt;
&lt;td&gt;&lt;b&gt;인터페이스 주입&lt;/b&gt;&lt;/td&gt;
&lt;td&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;h2 data-end=&quot;174&quot; data-start=&quot;132&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;생성자 주입 (Constructor Injection)&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-end=&quot;228&quot; data-start=&quot;176&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;228&quot; data-start=&quot;178&quot; data-ke-size=&quot;size16&quot;&gt;의존성을 &lt;b&gt;생성자 매개변수로 주입&lt;/b&gt;&lt;br /&gt;가장 일반적이고 안전한 방식 (불변성 유지)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre id=&quot;code_1743928350710&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Database {
  connect(): void;
}

class MySQLDatabase implements Database {
  connect() {
    console.log('MySQL 연결');
  }
}

class UserService {
  constructor(private db: Database) {}

  init() {
    this.db.connect();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1743928263304&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 의존성 주입 (수동)
const db = new MySQLDatabase();
const userService = new UserService(db);
userService.init();&lt;/code&gt;&lt;/pre&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;h2 data-end=&quot;626&quot; data-start=&quot;590&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;세터 주입 (Setter Injection)&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-end=&quot;704&quot; data-start=&quot;628&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;704&quot; data-start=&quot;630&quot; data-ke-size=&quot;size16&quot;&gt;의존성을 나중에 &lt;b&gt;set 메서드를 통해 주입&lt;/b&gt;&lt;br /&gt;초기화 시점 분리 가능, 유연하지만 실수로 안 넣으면 런타임 에러 위험 있음&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1743928376495&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Database {
  connect(): void;
}

class MySQLDatabase implements Database {
  connect() {
    console.log('MySQL 연결');
  }
}

class UserService {
  private db!: Database; // 주입 전까지 undefined (주의 필요)

  setDatabase(db: Database) {
    this.db = db;
  }

  init() {
    this.db.connect();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1743928383336&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 사용
const userService = new UserService();
userService.setDatabase(new MySQLDatabase());
userService.init();&lt;/code&gt;&lt;/pre&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;h2 data-end=&quot;1178&quot; data-start=&quot;1136&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;인터페이스 주입 (Interface Injection)&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-end=&quot;1250&quot; data-start=&quot;1180&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1250&quot; data-start=&quot;1182&quot; data-ke-size=&quot;size16&quot;&gt;클래스가 &lt;b&gt;&quot;나는 이 의존성을 받아야 한다&quot;는 메서드 구조를 강제&lt;/b&gt;&lt;br /&gt;직접 주입하는 쪽이 &lt;b&gt;주입 규약을 따름&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre id=&quot;code_1743928428067&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Database {
  connect(): void;
}

interface DatabaseInjectable {
  injectDatabase(db: Database): void;
}

class MySQLDatabase implements Database {
  connect() {
    console.log('MySQL 연결');
  }
}

class UserService implements DatabaseInjectable {
  private db!: Database;

  injectDatabase(db: Database) {
    this.db = db;
  }

  init() {
    this.db.connect();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1743928432413&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 외부에서 인터페이스 기반으로 주입
const userService = new UserService();
userService.injectDatabase(new MySQLDatabase());
userService.init();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2087&quot; data-start=&quot;1882&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;방식&lt;/td&gt;
&lt;td&gt;장점&lt;/td&gt;
&lt;td&gt;단점&lt;/td&gt;
&lt;td&gt;특징&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1979&quot; data-start=&quot;1934&quot;&gt;
&lt;td&gt;생성자 주입&lt;/td&gt;
&lt;td&gt;안정적, 불변성 유지&lt;/td&gt;
&lt;td&gt;순환참조 시 불편&lt;/td&gt;
&lt;td&gt;가장 일반적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2028&quot; data-start=&quot;1980&quot;&gt;
&lt;td&gt;세터 주입&lt;/td&gt;
&lt;td&gt;유연, 선택적 의존성&lt;/td&gt;
&lt;td&gt;안 주입하고 쓸 위험&lt;/td&gt;
&lt;td&gt;설정 단계 분리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2087&quot; data-start=&quot;2029&quot;&gt;
&lt;td&gt;인터페이스 주입&lt;/td&gt;
&lt;td&gt;주입 규칙 명확&lt;/td&gt;
&lt;td&gt;구현 복잡도 &amp;uarr;&lt;/td&gt;
&lt;td&gt;Java/Spring 쪽에서 자주 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1119&quot; data-start=&quot;1006&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;역할&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1057&quot; data-start=&quot;1034&quot;&gt;
&lt;td&gt;&lt;b&gt;DIP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;추상화에 의존하자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1083&quot; data-start=&quot;1058&quot;&gt;
&lt;td&gt;&lt;b&gt;IoC&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;제어를 외부로 넘기자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1119&quot; data-start=&quot;1084&quot;&gt;
&lt;td&gt;&lt;b&gt;DI&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;그 외부가 객체를 &quot;주입&quot;해주는 방식이다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;164&quot; data-start=&quot;151&quot; data-ke-size=&quot;size26&quot;&gt;순환 참조란?&lt;/h2&gt;
&lt;p data-end=&quot;198&quot; data-start=&quot;166&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;두 클래스가 서로를 의존할 때 생기는 상황&lt;/b&gt;&lt;br /&gt;즉,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;219&quot; data-start=&quot;200&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;209&quot; data-start=&quot;200&quot;&gt;A &amp;rarr; B&lt;/li&gt;
&lt;li data-end=&quot;219&quot; data-start=&quot;210&quot;&gt;B &amp;rarr; A&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;285&quot; data-start=&quot;221&quot; data-ke-size=&quot;size16&quot;&gt;둘 다 &lt;b&gt;생성자에서 서로를 필요로 하면&lt;/b&gt;,&lt;br /&gt;&lt;b&gt;무한 루프&lt;/b&gt;에 빠져서 에러 나거나 앱이 제대로 동작 안 함.&lt;/p&gt;
&lt;p data-end=&quot;285&quot; data-start=&quot;221&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;285&quot; data-start=&quot;221&quot; data-ke-size=&quot;size16&quot;&gt;TypeScript 예제: 생성자 주입 + 순환 참조&lt;/p&gt;
&lt;pre id=&quot;code_1743928685792&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {
  constructor(private b: B) {}
}

class B {
  constructor(private a: A) {}
}

// 문제 발생 시도
const a = new A(new B(new A())); // ❌ 이런 식으로는 불가능&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A를 만들려면 B가 필요하고,&lt;br /&gt;B를 만들려면 또 A가 필요하고&amp;hellip;&lt;br /&gt;➡️ 끝이 없어서 &lt;b&gt;스택 오버플로우&lt;/b&gt; or &lt;b&gt;런타임 오류&lt;/b&gt;가 남&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;607&quot; data-start=&quot;579&quot; data-ke-size=&quot;size26&quot;&gt;왜 생성자 주입이 순환 참조에 불리하냐?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;732&quot; data-start=&quot;609&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;652&quot; data-start=&quot;609&quot;&gt;생성자 주입은 &lt;b&gt;&quot;객체 생성 시점에 모든 의존성이 완성돼 있어야 함&quot;&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;700&quot; data-start=&quot;653&quot;&gt;근데 A와 B가 서로를 필요로 하면 &lt;b&gt;서로가 아직 생성 안 됐는데 필요로 함&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;732&quot; data-start=&quot;701&quot;&gt;즉, &lt;b&gt;순환 구조라 객체 생성 자체가 불가능해짐&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;764&quot; data-start=&quot;739&quot; data-ke-size=&quot;size26&quot;&gt;해결 방법 1: 세터 주입으로 바꾸기&lt;/h2&gt;
&lt;pre id=&quot;code_1743928721336&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {
  private b!: B;
  setB(b: B) {
    this.b = b;
  }
}

class B {
  private a!: A;
  setA(a: A) {
    this.a = a;
  }
}

// 인스턴스 생성 후 의존성 연결
const a = new A();
const b = new B();

a.setB(b);
b.setA(a);&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;h2 data-end=&quot;1076&quot; data-start=&quot;1028&quot; data-ke-size=&quot;size26&quot;&gt;해결 방법 2: DI 컨테이너가 순환 참조 감지 + Lazy Injection&lt;/h2&gt;
&lt;p data-end=&quot;1107&quot; data-start=&quot;1078&quot; data-ke-size=&quot;size16&quot;&gt;프레임워크들은 종종 자동으로 감지해서 해결하려고 해:&lt;/p&gt;
&lt;h3 data-end=&quot;1137&quot; data-start=&quot;1109&quot; data-ke-size=&quot;size23&quot;&gt;NestJS 예: forwardRef()&lt;/h3&gt;
&lt;pre id=&quot;code_1743928745054&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Injectable()
export class A {
  constructor(@Inject(forwardRef(() =&amp;gt; B)) private b: B) {}
}

@Injectable()
export class B {
  constructor(@Inject(forwardRef(() =&amp;gt; A)) private a: A) {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ forwardRef()는 **&quot;얘 나중에 올 거야&quot;**라고 알려주는 것&lt;br /&gt;➡️ NestJS가 순환 참조를 알고 &lt;b&gt;나중에 연결&lt;/b&gt;해줌&lt;/p&gt;
&lt;h2 data-end=&quot;1431&quot; data-start=&quot;1423&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;요약&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1654&quot; data-start=&quot;1433&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;주입 방식&lt;/td&gt;
&lt;td&gt;순환 참조에 강함?&lt;/td&gt;
&lt;td&gt;이유&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1548&quot; data-start=&quot;1501&quot;&gt;
&lt;td&gt;&lt;b&gt;생성자 주입&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;❌ 약함&lt;/td&gt;
&lt;td&gt;객체 생성 전에 의존성이 모두 있어야 해서&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1586&quot; data-start=&quot;1549&quot;&gt;
&lt;td&gt;&lt;b&gt;세터 주입&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ 강함&lt;/td&gt;
&lt;td&gt;생성 후 의존성 설정 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1654&quot; data-start=&quot;1587&quot;&gt;
&lt;td&gt;&lt;b&gt;프레임워크 DI (forwardRef 등)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ 강함&lt;/td&gt;
&lt;td&gt;내부적으로 Lazy Load, Proxy로 해결&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</description>
      <category>개발</category>
      <author>기록하는 남자</author>
      <guid isPermaLink="true">https://noteit.tistory.com/53</guid>
      <comments>https://noteit.tistory.com/entry/SOLID-%EC%9B%90%EC%B9%99#entry53comment</comments>
      <pubDate>Sun, 6 Apr 2025 17:44:35 +0900</pubDate>
    </item>
    <item>
      <title>Static Import, Dynamic Import</title>
      <link>https://noteit.tistory.com/entry/Static-Import-Dynamic-Import</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;​&lt;span&gt;JavaScript에서 모듈을 불러오는 방식에는 &lt;b&gt;정적 임포트&lt;/b&gt;와 &lt;b&gt;동적 임포트&lt;/b&gt; 두 가지가 있습니다. 각 방식의 특징과 차이점을 설명드리겠습니다.&lt;/span&gt;​&lt;/p&gt;
&lt;hr data-end=&quot;93&quot; data-start=&quot;90&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;125&quot; data-start=&quot;95&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정적 임포트 (Static Import)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;208&quot; data-start=&quot;127&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정적 임포트는 컴파일 시점에 모듈을 가져오는 방식으로, import 키워드를 사용하여 모듈을 선언합니다.&lt;/span&gt;​&lt;/p&gt;
&lt;p data-end=&quot;217&quot; data-start=&quot;210&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-end=&quot;518&quot; data-start=&quot;219&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;317&quot; data-start=&quot;219&quot;&gt;&lt;b&gt;컴파일 시점 로딩:&lt;/b&gt; &lt;span&gt;모든 정적 임포트는 코드가 실행되기 전에 로드됩니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;421&quot; data-start=&quot;318&quot;&gt;&lt;b&gt;상위 수준에서만 사용 가능:&lt;/b&gt; &lt;span&gt;모든 정적 임포트는 모듈의 최상위 수준에서만 선언할 수 있으며, 조건문이나 함수 내부에서는 사용할 수 없습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;518&quot; data-start=&quot;422&quot;&gt;&lt;b&gt;문법적 엄격성:&lt;/b&gt; &lt;span&gt;모듈 경로는 문자열 리터럴로만 지정할 수 있으며, 변수나 표현식을 사용할 수 없습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;527&quot; data-start=&quot;520&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1743828368883&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { add, subtract } from './math.js';

console.log(add(2, 3));      // 5
console.log(subtract(5, 2)); // 3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;527&quot; data-start=&quot;520&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;708&quot; data-start=&quot;701&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-end=&quot;913&quot; data-start=&quot;710&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;811&quot; data-start=&quot;710&quot;&gt;&lt;b&gt;정적 분석 가능:&lt;/b&gt; &lt;span&gt;코드의 모듈 의존성을 정적으로 분석할 수 있어, 트리 쉐이킹(tree-shaking)과 같은 최적화가 가능합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;913&quot; data-start=&quot;812&quot;&gt;&lt;b&gt;빠른 초기 로딩:&lt;/b&gt; &lt;span&gt;필요한 모듈이 미리 로드되므로, 코드 실행 시 지연이 없습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;922&quot; data-start=&quot;915&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-end=&quot;1124&quot; data-start=&quot;924&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1023&quot; data-start=&quot;924&quot;&gt;&lt;b&gt;유연성 부족:&lt;/b&gt; &lt;span&gt;조건부 로딩이나 동적 경로 로딩이 불가능합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;1124&quot; data-start=&quot;1024&quot;&gt;&lt;b&gt;큰 번들 크기:&lt;/b&gt; &lt;span&gt;모든 모듈이 한 번에 로드되므로, 사용되지 않는 코드까지 포함되어 번들 크기가 커질 수 있습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1129&quot; data-start=&quot;1126&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1162&quot; data-start=&quot;1131&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;동적 임포트 (Dynamic Import)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1249&quot; data-start=&quot;1164&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;동적 임포트는 코드 실행 시점에 모듈을 비동기적으로 가져오는 방식으로, import() 함수를 사용합니다.&lt;/span&gt;​&lt;/p&gt;
&lt;p data-end=&quot;1258&quot; data-start=&quot;1251&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-end=&quot;1556&quot; data-start=&quot;1260&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1359&quot; data-start=&quot;1260&quot;&gt;&lt;b&gt;런타임 로딩:&lt;/b&gt; &lt;span&gt;코드가 실행되는 동안 필요한 시점에 모듈을 로드합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;1459&quot; data-start=&quot;1360&quot;&gt;&lt;b&gt;비동기 처리:&lt;/b&gt; &lt;span&gt;import() 함수는 프로미스(Promise)를 반환하므로, then 또는 async/await를 사용하여 처리할 수 있습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;1556&quot; data-start=&quot;1460&quot;&gt;&lt;b&gt;유연성:&lt;/b&gt; &lt;span&gt;조건문, 함수 내부 등 어디에서나 호출할 수 있으며, 모듈 경로를 동적으로 지정할 수 있습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1565&quot; data-start=&quot;1558&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1743828387838&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 조건부 로딩
if (user.isLoggedIn) {
  import('./dashboard.js')
    .then((module) =&amp;gt; {
      module.loadDashboard();
    })
    .catch((error) =&amp;gt; {
      console.error('Error loading dashboard:', error);
    });
}

// 동적 경로 로딩
const moduleName = 'analytics';
import(`./modules/${moduleName}.js`)
  .then((module) =&amp;gt; {
    module.init();
  })
  .catch((error) =&amp;gt; {
    console.error(`Error loading ${moduleName} module:`, error);
  });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1565&quot; data-start=&quot;1558&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2066&quot; data-start=&quot;2059&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-end=&quot;2267&quot; data-start=&quot;2068&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2170&quot; data-start=&quot;2068&quot;&gt;&lt;b&gt;번들 크기 최적화:&lt;/b&gt; &lt;span&gt;필요한 모듈만 로드하므로 초기 번들 크기를 줄일 수 있습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;2267&quot; data-start=&quot;2171&quot;&gt;&lt;b&gt;유연성:&lt;/b&gt; &lt;span&gt;사용자 상호작용이나 특정 조건에 따라 모듈을 로드할 수 있습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2276&quot; data-start=&quot;2269&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-end=&quot;2481&quot; data-start=&quot;2278&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2379&quot; data-start=&quot;2278&quot;&gt;&lt;b&gt;초기 로딩 지연:&lt;/b&gt; &lt;span&gt;모듈 로딩이 비동기적으로 이루어지므로, 로딩 완료 전까지 해당 모듈의 기능을 사용할 수 없습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;2481&quot; data-start=&quot;2380&quot;&gt;&lt;b&gt;에러 처리 필요:&lt;/b&gt; &lt;span&gt;네트워크 문제 등으로 인해 모듈 로딩에 실패할 수 있으므로, 적절한 에러 처리가 필요합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2486&quot; data-start=&quot;2483&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2517&quot; data-start=&quot;2488&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정적 임포트와 동적 임포트의 선택 기준&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2753&quot; data-start=&quot;2519&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2628&quot; data-start=&quot;2519&quot;&gt;&lt;b&gt;초기 로딩 성능이 중요한 경우:&lt;/b&gt; &lt;span&gt;동적 임포트를 사용하여 초기 번들 크기를 줄이고, 필요한 시점에 모듈을 로드하는 것이 좋습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;2753&quot; data-start=&quot;2629&quot;&gt;&lt;b&gt;모든 기능이 즉시 필요하거나, 트리 쉐이킹*이 가능한 경우:&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;112&quot; data-start=&quot;83&quot; data-ke-size=&quot;size26&quot;&gt;  트리 쉐이킹*(Tree Shaking)이란?&lt;/h2&gt;
&lt;blockquote data-end=&quot;175&quot; data-start=&quot;114&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;175&quot; data-start=&quot;116&quot; data-ke-size=&quot;size16&quot;&gt;사용되지 않는 코드(= dead code)를 &lt;b&gt;정적 분석&lt;/b&gt;을 통해 번들에서 제거하는 &lt;b&gt;최적화 기법&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;180&quot; data-start=&quot;177&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;193&quot; data-start=&quot;182&quot; data-ke-size=&quot;size26&quot;&gt;⚙️ 동작 원리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;339&quot; data-start=&quot;195&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;284&quot; data-start=&quot;195&quot;&gt;&lt;b&gt;ESM (ECMAScript Module)&lt;/b&gt; 기반의 import/export 구조를 분석해서&lt;br /&gt;&lt;b&gt;어떤 코드가 실제로 사용되고 있는지 판단&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;339&quot; data-start=&quot;286&quot;&gt;사용되지 않는 코드는 &lt;b&gt;DCE(Dead Code Elimination)&lt;/b&gt; 기법으로 제거됨&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;344&quot; data-start=&quot;341&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;361&quot; data-start=&quot;346&quot; data-ke-size=&quot;size26&quot;&gt;  어떻게 적용하냐?&lt;/h2&gt;
&lt;blockquote data-end=&quot;446&quot; data-start=&quot;363&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;446&quot; data-start=&quot;365&quot; data-ke-size=&quot;size16&quot;&gt;번들러(Webpack, Vite 등)가 트리 쉐이킹을 제대로 적용하려면&lt;br /&gt;코드에 &lt;b&gt;side effect가 없다는 걸 명확히 알려줘야 함&lt;/b&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;package.json에 명시&lt;/p&gt;
&lt;pre id=&quot;code_1743828746282&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;sideEffects&quot;: false
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;576&quot; data-start=&quot;518&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;576&quot; data-start=&quot;518&quot;&gt;프로젝트 전체에 부작용(side effect)이 없음을 의미 &amp;rarr; 안 쓰는 코드 safely 제거 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;599&quot; data-start=&quot;578&quot; data-ke-size=&quot;size16&quot;&gt;또는 일부만 예외로 설정할 수도 있음:&lt;/p&gt;
&lt;pre id=&quot;code_1743828765508&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;sideEffects&quot;: [&quot;./src/styles/global.css&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;720&quot; data-start=&quot;663&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;720&quot; data-start=&quot;663&quot;&gt;CSS처럼 import만 해도 효과가 있는 파일은 &lt;b&gt;side effect 있음&lt;/b&gt;으로 간주해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;725&quot; data-start=&quot;722&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;738&quot; data-start=&quot;727&quot; data-ke-size=&quot;size26&quot;&gt;  주의할 점&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1006&quot; data-start=&quot;740&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;조건&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;823&quot; data-start=&quot;768&quot;&gt;
&lt;td&gt;✅ &lt;b&gt;ESM만 작동&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;import/export 문법 구조일 때만 트리 쉐이킹 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;880&quot; data-start=&quot;824&quot;&gt;
&lt;td&gt;❌ &lt;b&gt;CommonJS는 안 됨&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;require()는 정적 분석 불가 &amp;rarr; 제거 못 함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;940&quot; data-start=&quot;881&quot;&gt;
&lt;td&gt;⚠️ &lt;b&gt;동적 import는 감지 불가&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;import() 같은 동적 로딩은 분석 대상 아님&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1006&quot; data-start=&quot;941&quot;&gt;
&lt;td&gt;❗ &lt;b&gt;side effect 있는 코드&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;명시하지 않으면 제거 안 됨 (실행되기만 해도 영향 주는 코드)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;1098&quot; data-start=&quot;1032&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1098&quot; data-start=&quot;1034&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ESM = ECMAScript Module&lt;/b&gt;의 줄임말로,&lt;br /&gt;JavaScript 표준 모듈 시스템을 의미함&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1202&quot; data-start=&quot;1110&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1139&quot; data-start=&quot;1110&quot;&gt;import / export 문법 사용&lt;/li&gt;
&lt;li data-end=&quot;1161&quot; data-start=&quot;1140&quot;&gt;정적 구조 &amp;rarr; 코드 분석에 유리&lt;/li&gt;
&lt;li data-end=&quot;1202&quot; data-start=&quot;1162&quot;&gt;브라우저, Node.js, Webpack, Vite 등에서 기본 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;115&quot; data-start=&quot;81&quot; data-ke-size=&quot;size26&quot;&gt;DCE(Dead Code Elimination)란?&lt;/h2&gt;
&lt;blockquote data-end=&quot;170&quot; data-start=&quot;117&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;170&quot; data-start=&quot;119&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제로 실행되지 않는 코드(= dead code)를 빌드 타임에 제거하는 최적화 기법&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;239&quot; data-start=&quot;172&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;204&quot; data-start=&quot;172&quot;&gt;&amp;ldquo;사용되지 않는다&amp;rdquo; &amp;ne; &amp;ldquo;문법적으로 틀렸다&amp;rdquo;는 아님&lt;/li&gt;
&lt;li data-end=&quot;239&quot; data-start=&quot;205&quot;&gt;단지 &lt;b&gt;실행될 일이 없다는 걸 분석해서 제거&lt;/b&gt;하는 거야&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;244&quot; data-start=&quot;241&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;260&quot; data-start=&quot;246&quot; data-ke-size=&quot;size26&quot;&gt;어떻게 동작함?&lt;/h2&gt;
&lt;h3 data-end=&quot;276&quot; data-start=&quot;262&quot; data-ke-size=&quot;size23&quot;&gt;정적 분석 기반&lt;/h3&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;277&quot; data-ke-size=&quot;size16&quot;&gt;코드를 실행하지 않고도, &lt;b&gt;분기/사용 흐름을 따라가며 판단&lt;/b&gt;함&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;277&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;277&quot; data-ke-size=&quot;size16&quot;&gt;예시&lt;/p&gt;
&lt;pre id=&quot;code_1743828929246&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function test() {
  return;
  console.log(&quot;이건 절대 실행 안 됨&quot;); // dead code
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는&lt;/p&gt;
&lt;pre id=&quot;code_1743828938583&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function unused() {
  console.log(&quot;누구도 날 안 써줘  &quot;);
} &lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-end=&quot;550&quot; data-start=&quot;533&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-end=&quot;550&quot; data-start=&quot;533&quot; data-ke-size=&quot;size26&quot;&gt;실제로는 누가 해줌?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;683&quot; data-start=&quot;552&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;587&quot; data-start=&quot;552&quot;&gt;&lt;b&gt;Terser&lt;/b&gt; (Webpack의 기본 minifier)&lt;/li&gt;
&lt;li data-end=&quot;638&quot; data-start=&quot;588&quot;&gt;&lt;b&gt;esbuild&lt;/b&gt;, &lt;b&gt;Rollup&lt;/b&gt;, &lt;b&gt;Vite&lt;/b&gt; 등 자체적으로 DCE 내장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;795&quot; data-start=&quot;775&quot; data-ke-size=&quot;size26&quot;&gt;DCE가 제거하는 것들 예시&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;995&quot; data-start=&quot;797&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;코드&lt;/td&gt;
&lt;td&gt;제거 대상?&lt;/td&gt;
&lt;td&gt;이유&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;888&quot; data-start=&quot;848&quot;&gt;
&lt;td&gt;if (false) { ... }&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;절대 실행 안 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;931&quot; data-start=&quot;889&quot;&gt;
&lt;td&gt;return; console.log(...)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;도달 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;961&quot; data-start=&quot;932&quot;&gt;
&lt;td&gt;미사용 함수/변수&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;호출/참조 안 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;995&quot; data-start=&quot;962&quot;&gt;
&lt;td&gt;debugger;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;최적화 시 제거 대상&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1000&quot; data-start=&quot;997&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1020&quot; data-start=&quot;1002&quot; data-ke-size=&quot;size26&quot;&gt;  DCE가 안 되는 경우&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1108&quot; data-start=&quot;1022&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1045&quot; data-start=&quot;1022&quot;&gt;&lt;b&gt;eval() 같은 동적 실행&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1084&quot; data-start=&quot;1046&quot;&gt;전역 오브젝트 조작 (window.someFunc = ...)&lt;/li&gt;
&lt;li data-end=&quot;1108&quot; data-start=&quot;1085&quot;&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;&amp;nbsp;&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;br /&gt;DCE는 &lt;b&gt;모듈 안의 코드 흐름&lt;/b&gt;까지 살펴서 더 미세하게 제거&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;658&quot; data-start=&quot;320&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;트리 쉐이킹 (Tree Shaking)&lt;/td&gt;
&lt;td&gt;DCE (Dead Code Elimination)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;505&quot; data-start=&quot;450&quot;&gt;
&lt;td&gt;분석 대상&lt;/td&gt;
&lt;td&gt;import / export&lt;/td&gt;
&lt;td&gt;코드 내부의 조건문, 흐름, 변수 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;534&quot; data-start=&quot;506&quot;&gt;
&lt;td&gt;레벨&lt;/td&gt;
&lt;td&gt;모듈 수준&lt;/td&gt;
&lt;td&gt;함수/블록/문장 수준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;573&quot; data-start=&quot;535&quot;&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;td&gt;안 쓰는 export 제거&lt;/td&gt;
&lt;td&gt;도달 불가한 코드 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;611&quot; data-start=&quot;574&quot;&gt;
&lt;td&gt;언제 작동?&lt;/td&gt;
&lt;td&gt;ESM 기반에서만&lt;/td&gt;
&lt;td&gt;ESM이 아니어도 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;658&quot; data-start=&quot;612&quot;&gt;
&lt;td&gt;도구&lt;/td&gt;
&lt;td&gt;Rollup, Webpack 등&lt;/td&gt;
&lt;td&gt;Terser, esbuild 등&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</description>
      <category>개발</category>
      <author>기록하는 남자</author>
      <guid isPermaLink="true">https://noteit.tistory.com/52</guid>
      <comments>https://noteit.tistory.com/entry/Static-Import-Dynamic-Import#entry52comment</comments>
      <pubDate>Sat, 5 Apr 2025 14:01:19 +0900</pubDate>
    </item>
    <item>
      <title>Error: Failed to load chunk server/chunks/ssr/</title>
      <link>https://noteit.tistory.com/entry/Error-Failed-to-load-chunk-serverchunksssr</link>
      <description>&lt;p data-end=&quot;236&quot; data-start=&quot;197&quot; data-ke-size=&quot;size18&quot;&gt;Next.js에서 `@radix-ui/react-tabs`를 설치한 후,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`Error: Failed to load chunk server/chunks/ssr/` 같은 에러가 발생했다.&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;특히 프로덕션 환경에서 캐시 문제로 인해 발생하는 경우가 많다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로덕션 환경이 아닌, 로컬 개발 환경에서 작업 중이었기 때문에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 경로 문제를 의심해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import 경로를 확인해보니,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 이름 앞에 `\b`(백스페이스 문자)가 보이지 않게 들어가 있는 걸 발견했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 Mac에서 VS Code로 파일을 생성하거나 이름을 수정할 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간혹 이런 제어 문자(`\b`)가 파일명에 끼어드는 경우가 있어서 발생한 것으로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 파일을 삭제하고, 올바른 이름으로 다시 생성한 뒤 import를 수정하니 에러가 해결되었다.&lt;/p&gt;
&lt;p data-end=&quot;236&quot; data-start=&quot;197&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;236&quot; data-start=&quot;197&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;236&quot; data-start=&quot;197&quot; data-ke-size=&quot;size23&quot;&gt;정리&lt;/h3&gt;
&lt;p data-end=&quot;236&quot; data-start=&quot;197&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;파일 시스템의 대소문자 구분:&lt;/b&gt; &lt;span&gt;macOS의 기본 파일 시스템인 HFS+는 대소문자를 구분하지 않습니다. 따라서 VS Code에서 파일 이름의 대소문자를 변경할 경우, 내부적으로 혼동이 발생하여 숨겨진 제어 문자가 추가될 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;236&quot; data-start=&quot;197&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;236&quot; data-start=&quot;197&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;파일 이름에 보이지 않는 제어 문자(예: \b)가 포함되면, 웹 애플리케이션이 해당 파일을 정확하게 찾고 로드하는 데 문제가 발생할 수 있습니다.&lt;/span&gt; &lt;span&gt;이러한 문제가 발생하는 이유와 그로 인해 ChunkLoadError가 발생하는 과정을 설명드리겠습니다.&lt;/span&gt;​&lt;/p&gt;
&lt;p data-end=&quot;156&quot; data-start=&quot;128&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 파일 시스템과 모듈 번들러의 파일 처리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;369&quot; data-start=&quot;158&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;257&quot; data-start=&quot;158&quot;&gt;&lt;b&gt;파일 시스템의 역할&lt;/b&gt;: &lt;span&gt;운영 체제의 파일 시스템은 파일 이름을 기반으로 파일을 관리하고 접근합니다. 파일 이름에 보이지 않는 제어 문자가 포함되면, 파일 시스템이 해당 파일을 예상과 다르게 처리할 수 있습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;369&quot; data-start=&quot;259&quot;&gt;&lt;b&gt;모듈 번들러(Webpack 등)의 역할&lt;/b&gt;: &lt;span&gt;모듈 번들러는 소스 코드를 분석하여 의존성을 파악하고, 이를 기반으로 청크(chunk) 파일을 생성합니다. 이 과정에서 파일 경로와 이름이 정확해야 합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;396&quot; data-start=&quot;371&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 제어 문자로 인한 문제 발생 과정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;603&quot; data-start=&quot;398&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;497&quot; data-start=&quot;398&quot;&gt;&lt;b&gt;파일 탐색 및 로딩&lt;/b&gt;: &lt;span&gt;애플리케이션이 특정 모듈이나 컴포넌트를 로드하려고 할 때, 해당 파일의 경로를 기반으로 파일 시스템에서 파일을 찾습니다. 파일 이름에 보이지 않는 제어 문자가 포함되어 있으면, 실제 파일 경로와 일치하지 않아 파일을 찾지 못할 수 있습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;603&quot; data-start=&quot;499&quot;&gt;&lt;b&gt;청크 파일 생성 및 매핑&lt;/b&gt;: &lt;span&gt;모듈 번들러는 각 모듈을 청크로 분리하고, 이를 고유한 이름으로 저장합니다. 이때 파일 이름이 예상과 다르거나 일관되지 않으면, 생성된 청크 파일과 애플리케이션 코드 간의 매핑이 어긋나게 됩니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;631&quot; data-start=&quot;605&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. ChunkLoadError 발생&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;835&quot; data-start=&quot;633&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;734&quot; data-start=&quot;633&quot;&gt;&lt;b&gt;청크 로딩 실패&lt;/b&gt;: &lt;span&gt;애플리케이션이 특정 청크를 로드하려고 시도할 때, 해당 청크 파일을 찾지 못하면 ChunkLoadError가 발생합니다. 이는 브라우저가 지정된 경로에서 청크 파일을 가져오지 못했음을 의미합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;835&quot; data-start=&quot;736&quot;&gt;&lt;b&gt;오류의 원인&lt;/b&gt;: &lt;span&gt;파일 이름에 포함된 보이지 않는 제어 문자로 인해, 파일 경로가 예상과 다르게 해석되거나, 파일이 존재하지 않는 것으로 인식되어 로딩에 실패하게 됩니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;849&quot; data-start=&quot;837&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 해결 방안&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1057&quot; data-start=&quot;851&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;952&quot; data-start=&quot;851&quot;&gt;&lt;b&gt;파일 이름 검증&lt;/b&gt;: &lt;span&gt;파일을 생성하거나 수정할 때, 보이지 않는 제어 문자가 포함되지 않도록 주의해야 합니다. 특히, 파일 이름을 복사하거나 붙여넣기 할 때 이러한 문제가 발생할 수 있으므로, 텍스트 에디터나 IDE에서 파일 이름을 확인하는 것이 중요합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;1057&quot; data-start=&quot;954&quot;&gt;&lt;b&gt;문제 발생 시 조치&lt;/b&gt;: &lt;span&gt;만약 이러한 문제가 발생했다면, 해당 파일을 삭제하고 새로운 파일을 생성하여 올바른 이름으로 저장하는 것이 좋습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1144&quot; data-start=&quot;1059&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이러한 과정을 통해, 파일 이름에 보이지 않는 제어 문자가 포함되는 것을 방지하고, 그로 인한 ChunkLoadError와 같은 오류를 예방할 수 있습니다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;236&quot; data-start=&quot;197&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;개발(Development) 단계에서의 원인과 해결 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;248&quot; data-start=&quot;238&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 원인:&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;462&quot; data-start=&quot;250&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;359&quot; data-start=&quot;250&quot;&gt;&lt;b&gt;파일 누락 또는 경로 문제:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;359&quot; data-start=&quot;276&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;359&quot; data-start=&quot;276&quot;&gt;&lt;span&gt;개발 중에 파일 경로나 이름이 변경되었지만, 개발 서버가 이를 인식하지 못하여 이전 경로를 참조하는 경우입니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;462&quot; data-start=&quot;361&quot;&gt;&lt;b&gt;빌드 불일치:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;462&quot; data-start=&quot;379&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;462&quot; data-start=&quot;379&quot;&gt;&lt;span&gt;코드 수정 후 개발 서버가 최신 빌드를 반영하지 못하여, 오래된 청크 파일을 로드하려는 경우입니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;474&quot; data-start=&quot;464&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-end=&quot;836&quot; data-start=&quot;476&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;578&quot; data-start=&quot;476&quot;&gt;&lt;b&gt;개발 서버 재시작:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;578&quot; data-start=&quot;495&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;578&quot; data-start=&quot;495&quot;&gt;&lt;span&gt;개발 서버를 재시작하여 변경 사항이 올바르게 반영되도록 합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;727&quot; data-start=&quot;580&quot;&gt;&lt;b&gt;빌드 폴더 삭제 및 재빌드:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;727&quot; data-start=&quot;604&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;727&quot; data-start=&quot;604&quot;&gt;&lt;span&gt;프로젝트의 빌드 폴더(예: .next 또는 dist 폴더)를 삭제한 후 애플리케이션을 다시 빌드하고 실행합니다.&lt;/span&gt; ​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;836&quot; data-start=&quot;729&quot;&gt;&lt;b&gt;브라우저 캐시 삭제:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;836&quot; data-start=&quot;749&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;836&quot; data-start=&quot;749&quot;&gt;&lt;span&gt;브라우저의 캐시를 지운 후 페이지를 새로고침하여 최신 파일을 로드하도록 합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;841&quot; data-start=&quot;838&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;883&quot; data-start=&quot;843&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;프로덕션(Production) 단계에서의 원인과 해결 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;895&quot; data-start=&quot;885&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 원인:&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1263&quot; data-start=&quot;897&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1010&quot; data-start=&quot;897&quot;&gt;&lt;b&gt;파일 누락 또는 경로 문제:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1010&quot; data-start=&quot;923&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1010&quot; data-start=&quot;923&quot;&gt;&lt;span&gt;배포 시 청크 파일이 누락되었거나, 경로 설정이 잘못되어 클라이언트가 해당 파일을 찾지 못하는 경우입니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1116&quot; data-start=&quot;1012&quot;&gt;&lt;b&gt;캐싱 문제:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1116&quot; data-start=&quot;1029&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1116&quot; data-start=&quot;1029&quot;&gt;&lt;span&gt;사용자의 브라우저가 이전 버전의 파일을 캐시하고 있어, 최신 버전의 파일을 로드하지 못하는 경우입니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1263&quot; data-start=&quot;1118&quot;&gt;&lt;b&gt;빌드 불일치:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1263&quot; data-start=&quot;1136&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1263&quot; data-start=&quot;1136&quot;&gt;&lt;span&gt;서버에 배포된 파일과 클라이언트에서 요청하는 파일의 버전이 일치하지 않는 경우입니다. 예를 들어, 사용자가 애플리케이션을 사용하는 도중에 새로운 버전이 배포되어, 기존의 청크 파일이 삭제된 경우입니다.&lt;/span&gt; ​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1275&quot; data-start=&quot;1265&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-end=&quot;1638&quot; data-start=&quot;1277&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1382&quot; data-start=&quot;1277&quot;&gt;&lt;b&gt;캐싱 전략 개선*:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1382&quot; data-start=&quot;1295&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1382&quot; data-start=&quot;1295&quot;&gt;&lt;span&gt;청크 파일의 이름에 해시를 포함시켜 파일 변경 시 새로운 이름으로 생성되도록 합니다. 이를 통해 브라우저가 최신 파일을 로드하도록 유도합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1490&quot; data-start=&quot;1384&quot;&gt;&lt;b&gt;서비스 워커 활용:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1490&quot; data-start=&quot;1403&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1490&quot; data-start=&quot;1403&quot;&gt;&lt;span&gt;서비스 워커를 사용하여 새로운 버전이 배포되었을 때 사용자에게 알리고, 페이지를 새로고침하도록 유도할 수 있습니다.&lt;/span&gt;​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1638&quot; data-start=&quot;1492&quot;&gt;&lt;b&gt;에러 핸들링 추가:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1638&quot; data-start=&quot;1511&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1638&quot; data-start=&quot;1511&quot;&gt;&lt;span&gt;청크 로드 에러를 감지하여 사용자에게 알리고, 페이지를 자동으로 새로고침하거나 적절한 조치를 취하도록 합니다.&lt;/span&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐싱 전략 개선*&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-end=&quot;141&quot; data-start=&quot;118&quot; data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;브라우저 캐싱과 문제점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;262&quot; data-start=&quot;143&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;브라우저는 웹사이트의 자원(예: JavaScript 파일, CSS 파일 등)을 한 번 다운로드한 후, 성능 향상을 위해 이를 **캐시(cache)**에 저장합니다.&lt;/span&gt; &lt;span&gt;이렇게 하면 동일한 자원을 다시 다운로드하지 않고 캐시에서 불러와 페이지 로딩 속도가 빨라집니다.&lt;/span&gt;​&lt;/p&gt;
&lt;p data-end=&quot;392&quot; data-start=&quot;264&quot; 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;​&lt;/p&gt;
&lt;hr data-end=&quot;397&quot; data-start=&quot;394&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;426&quot; data-start=&quot;399&quot; data-ke-size=&quot;size23&quot;&gt;2. &lt;b&gt;해시를 파일명에 포함하는 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;549&quot; data-start=&quot;428&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파일명에 **해시(hash)**를 추가하면, 파일 내용이 변경될 때마다 새로운 해시 값이 생성되어 &lt;b&gt;파일명이 달라집니다&lt;/b&gt;.&lt;/span&gt; &lt;span&gt;이렇게 하면 브라우저는 파일명이 변경된 것을 감지하고, 캐시를 무시하고 &lt;b&gt;최신 파일을 다시 다운로드&lt;/b&gt;합니다.&lt;/span&gt;​&lt;/p&gt;
&lt;p data-end=&quot;558&quot; data-start=&quot;551&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-end=&quot;640&quot; data-start=&quot;560&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;581&quot; data-start=&quot;560&quot;&gt;&lt;b&gt;변경 전:&lt;/b&gt; main.js&lt;/li&gt;
&lt;li data-end=&quot;640&quot; data-start=&quot;582&quot;&gt;&lt;b&gt;변경 후:&lt;/b&gt; main.abc123.js (파일 내용 변경 시 해시 값 abc123 추가)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;727&quot; data-start=&quot;642&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이러한 방식으로 파일명이 변경되면, 브라우저는 이를 새로운 파일로 인식하여 최신 버전을 로드하게 됩니다.&lt;/span&gt;​&lt;/p&gt;
&lt;hr data-end=&quot;732&quot; data-start=&quot;729&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;763&quot; data-start=&quot;734&quot; data-ke-size=&quot;size23&quot;&gt;3. &lt;b&gt;Webpack에서 해시 적용 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;890&quot; data-start=&quot;765&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Webpack과 같은 모듈 번들러를 사용하면, 설정을 통해 파일명에 해시를 자동으로 추가할 수 있습니다.&lt;/span&gt; &lt;span&gt;이를 위해 output.filename 옵션에 [contenthash]를 사용합니다.&lt;/span&gt;​&lt;/p&gt;
&lt;pre id=&quot;code_1743826548735&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].[contenthash].js', // 각 청크에 대해 contenthash 적용
    path: path.resolve(__dirname, 'dist'),
    clean: true, // 이전 빌드 파일 정리
  },
  // 추가적인 설정...
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;위 설정에서 [name]은 청크의 이름을, [contenthash]는 해당 청크의 내용 기반 해시를 의미합니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1517&quot; data-start=&quot;1415&quot;&gt;&lt;span&gt;파일 내용이 변경되지 않았다면 동일한 해시 값을 가지므로, 브라우저는 기존 캐시를 재사용하여 불필요한 다운로드를 방지합니다.&lt;/span&gt;​&lt;/li&gt;
&lt;li data-end=&quot;1622&quot; data-start=&quot;1518&quot;&gt;&lt;b&gt;변경 사항 즉시 반영:&lt;/b&gt; &lt;span&gt;파일 내용이 변경되면 새로운 해시 값이 적용된 파일명이 생성되어, 브라우저가 최신 파일을 로드합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Next.js는 내부적으로 Webpack을 사용하여 빌드 프로세스를 관리하며, 프로덕션 환경에서 각 번들 파일의 이름에 **해시(hash)**를 자동으로 추가합니다.&lt;/span&gt; &lt;span&gt;이를 통해 파일 내용이 변경될 때마다 새로운 해시 값이 생성되어 브라우저가 최신 파일을 로드하도록 유도합니다.&lt;/span&gt; &lt;span&gt;따라서, 개발자가 별도로 Webpack의 output.filename 옵션을 설정하지 않아도 됩니다.&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;</description>
      <category>프로젝트/P1</category>
      <author>기록하는 남자</author>
      <guid isPermaLink="true">https://noteit.tistory.com/51</guid>
      <comments>https://noteit.tistory.com/entry/Error-Failed-to-load-chunk-serverchunksssr#entry51comment</comments>
      <pubDate>Sat, 5 Apr 2025 13:38:48 +0900</pubDate>
    </item>
    <item>
      <title>ETag</title>
      <link>https://noteit.tistory.com/entry/ETag</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;웹에서 캐시를 똑똑하게 하기 위해 사용하는 핵심 기술 중 하나&lt;/b&gt;가 바로 ETag입니다. ✨&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr data-end=&quot;110&quot; data-start=&quot;107&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;124&quot; data-start=&quot;112&quot; data-ke-size=&quot;size26&quot;&gt;  ETag란?&lt;/h2&gt;
&lt;blockquote data-end=&quot;172&quot; data-start=&quot;126&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;172&quot; data-start=&quot;128&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;이 파일, 바뀐 거야? 안 바뀐 거야?&quot;를 판단하기 위한 고유한 식별자&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;262&quot; data-start=&quot;174&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;208&quot; data-start=&quot;174&quot;&gt;&lt;b&gt;HTTP 응답 헤더&lt;/b&gt;에 포함돼서 브라우저에게 주어져요&lt;/li&gt;
&lt;li data-end=&quot;262&quot; data-start=&quot;209&quot;&gt;이후 브라우저가 같은 리소스를 요청할 때, 이 ETag를 서버에 다시 보내면서 묻습니다:&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;내가&amp;nbsp;가지고&amp;nbsp;있는&amp;nbsp;파일&amp;nbsp;ETag는&amp;nbsp;이건데,&amp;nbsp;바뀌었니?&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;작동 방식&lt;/h2&gt;
&lt;h4 data-end=&quot;353&quot; data-start=&quot;330&quot; data-ke-size=&quot;size20&quot;&gt;1. 클라이언트가 파일을 처음 요청&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1743783704653&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GET /main.js&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-end=&quot;406&quot; data-start=&quot;380&quot; data-ke-size=&quot;size20&quot;&gt;2. 서버가 파일과 함께 ETag를 응답&lt;/h4&gt;
&lt;pre id=&quot;code_1743783724092&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;200 OK ETag: &quot;abc123&quot; Content-Type: application/javascript&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-end=&quot;505&quot; data-start=&quot;479&quot; data-ke-size=&quot;size20&quot;&gt;3. 클라이언트가 다음에 다시 요청할 때&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1743783735848&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GET /main.js If-None-Match: &quot;abc123&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-end=&quot;581&quot; data-start=&quot;556&quot; data-ke-size=&quot;size20&quot;&gt;4. 서버가 확인 후 바뀐 게 없으면?&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;673&quot; data-start=&quot;612&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;673&quot; data-start=&quot;614&quot; data-ke-size=&quot;size16&quot;&gt;✅ 브라우저는 &lt;b&gt;자기 캐시에 있는 파일&lt;/b&gt;을 그냥 씀&lt;br /&gt;&amp;rarr; &lt;b&gt;네트워크 전송 없음&lt;/b&gt; &amp;rarr; 빠름!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;678&quot; data-start=&quot;675&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;697&quot; data-start=&quot;680&quot; data-ke-size=&quot;size26&quot;&gt;  ETag의&amp;nbsp; 목적&lt;/h2&gt;
&lt;div&gt;&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;866&quot; data-start=&quot;699&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;목적&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;763&quot; data-start=&quot;727&quot;&gt;
&lt;td&gt;&lt;b&gt;캐시 최적화&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;변경되지 않았으면 재다운로드 안 함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;808&quot; data-start=&quot;764&quot;&gt;
&lt;td&gt;&lt;b&gt;네트워크 트래픽 감소&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;304 응답이면 파일 자체 안 보내도 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;866&quot; data-start=&quot;809&quot;&gt;
&lt;td&gt;&lt;b&gt;정확한 캐시 검증&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;단순 시간 기준(Last-Modified)보다 더 정밀하게 비교&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;871&quot; data-start=&quot;868&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;896&quot; data-start=&quot;873&quot; data-ke-size=&quot;size26&quot;&gt;  ETag 값은 어떻게 만들어짐?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1003&quot; data-start=&quot;898&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;943&quot; data-start=&quot;898&quot;&gt;보통 파일의 &lt;b&gt;내용(content)&lt;/b&gt; 기준으로 해시(hash)처럼 생성돼요&lt;/li&gt;
&lt;li data-end=&quot;1003&quot; data-start=&quot;944&quot;&gt;예: &quot;abc123&quot;, &quot;W/\&quot;a1b2c3d4\&quot;&quot;&lt;br /&gt;&amp;rarr; 내용이 바뀌면 이 값도 바뀌어요&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1008&quot; data-start=&quot;1005&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1023&quot; data-start=&quot;1010&quot; data-ke-size=&quot;size26&quot;&gt;  어디서 보냐?&lt;/h2&gt;
&lt;p data-end=&quot;1074&quot; data-start=&quot;1025&quot; data-ke-size=&quot;size16&quot;&gt;크롬 개발자도구 &amp;rarr; Network 탭 &amp;rarr; 요청 헤더 &amp;amp; 응답 헤더 보면 이렇게 나옵니다:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1743783772220&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Response Headers: ETag: &quot;abc123&quot; Request Headers: If-None-Match: &quot;abc123&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1167&quot; data-start=&quot;1164&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1403&quot; data-start=&quot;1396&quot; data-ke-size=&quot;size26&quot;&gt;요약&lt;/h2&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1596&quot; data-start=&quot;1405&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1461&quot; data-start=&quot;1433&quot;&gt;
&lt;td&gt;ETag&lt;/td&gt;
&lt;td&gt;리소스 고유 ID (내용 기반)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1492&quot; data-start=&quot;1462&quot;&gt;
&lt;td&gt;목적&lt;/td&gt;
&lt;td&gt;캐시된 파일이 변경됐는지 정확하게 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1520&quot; data-start=&quot;1493&quot;&gt;
&lt;td&gt;응답 예&lt;/td&gt;
&lt;td&gt;ETag: &quot;abc123&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1552&quot; data-start=&quot;1521&quot;&gt;
&lt;td&gt;장점&lt;/td&gt;
&lt;td&gt;빠르고 정확한 캐시 판단, 네트워크 절약&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1596&quot; data-start=&quot;1553&quot;&gt;
&lt;td&gt;주의&lt;/td&gt;
&lt;td&gt;CDN/브라우저에 잘못된 ETag가 남으면 JS 깨질 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</description>
      <category>개발</category>
      <author>기록하는 남자</author>
      <guid isPermaLink="true">https://noteit.tistory.com/50</guid>
      <comments>https://noteit.tistory.com/entry/ETag#entry50comment</comments>
      <pubDate>Sat, 5 Apr 2025 01:23:45 +0900</pubDate>
    </item>
    <item>
      <title>선언적 에러 처리</title>
      <link>https://noteit.tistory.com/entry/%EC%84%A0%EC%96%B8%EC%A0%81-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;선언적 에러 처리(declarative error handling)&amp;rdquo;**는 보통 &lt;b&gt;프로그래밍 스타일&lt;/b&gt;에서 나오는 개념인데,&lt;br /&gt;다른 방식인 &lt;b&gt;명령형(imperative)&lt;/b&gt; 에러 처리랑 대비돼.&lt;/p&gt;
&lt;hr data-end=&quot;141&quot; data-start=&quot;138&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;159&quot; data-start=&quot;143&quot; data-ke-size=&quot;size26&quot;&gt;선언적 에러 처리란?&lt;/h2&gt;
&lt;h3 data-end=&quot;206&quot; data-start=&quot;161&quot; data-ke-size=&quot;size23&quot;&gt;  &lt;b&gt;&amp;ldquo;무슨 일이 일어나야 하는지&amp;rdquo;에 집중하는 방식의 에러 처리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;290&quot; data-start=&quot;207&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;어떻게 처리할지&lt;/b&gt;를 직접 하나하나 코드로 지시하지 않고,&lt;br /&gt;에러가 났을 때 &lt;b&gt;자동으로 어떻게 반응할지를 선언적으로 지정&lt;/b&gt;해두는 거야.&lt;/p&gt;
&lt;hr data-end=&quot;295&quot; data-start=&quot;292&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;332&quot; data-start=&quot;297&quot; data-ke-size=&quot;size23&quot;&gt;  예를 들어 보자: React / Next.js 기준&lt;/h3&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1743780596630&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// React 18+
&amp;lt;Suspense fallback={&amp;lt;Loading /&amp;gt;}&amp;gt;
  &amp;lt;SomeComponent /&amp;gt;
&amp;lt;/Suspense&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1743780608577&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;ErrorBoundary fallback={&amp;lt;ErrorMessage /&amp;gt;}&amp;gt;
  &amp;lt;ProblematicComponent /&amp;gt;
&amp;lt;/ErrorBoundary&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;557&quot; data-start=&quot;525&quot; data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;ErrorBoundary&lt;/b&gt;는 선언적 방식이야.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;622&quot; data-start=&quot;559&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;581&quot; data-start=&quot;559&quot;&gt;❌ 직접 try-catch 안 씀&lt;/li&gt;
&lt;li data-end=&quot;622&quot; data-start=&quot;582&quot;&gt;✅ **&amp;ldquo;이 컴포넌트에서 에러 나면 이렇게 처리해&amp;rdquo;**라고 선언만 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;627&quot; data-start=&quot;624&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;650&quot; data-start=&quot;629&quot; data-ke-size=&quot;size26&quot;&gt;✅ 명령형 vs 선언형 에러 처리&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 76px;&quot; border=&quot;1&quot; data-end=&quot;935&quot; data-start=&quot;652&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;명령형 (Imperative)&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;선언형 (Declarative)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot; data-end=&quot;794&quot; data-start=&quot;753&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;방식&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;직접 try-catch로 제어&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;에러 처리 &quot;룰&quot;을 선언&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot; data-end=&quot;889&quot; data-start=&quot;795&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;예시&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;try { ... } catch (e) { ... }&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&amp;lt;ErrorBoundary fallback={...}&amp;gt;...&amp;lt;/ErrorBoundary&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot; data-end=&quot;935&quot; data-start=&quot;890&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;초점&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;&quot;어떻게&quot;&lt;/b&gt; 처리할지&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;&quot;무슨 일이 나면&quot;&lt;/b&gt; 처리할지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;940&quot; data-start=&quot;937&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;965&quot; data-start=&quot;942&quot; data-ke-size=&quot;size26&quot;&gt;✅ 선언적 에러 처리가 잘 쓰이는 곳&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1160&quot; data-start=&quot;967&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1003&quot; data-start=&quot;967&quot;&gt;React (Error Boundaries, Suspense)&lt;/li&gt;
&lt;li data-end=&quot;1043&quot; data-start=&quot;1004&quot;&gt;Next.js (에러 페이지, app/error.tsx 같은 것들)&lt;/li&gt;
&lt;li data-end=&quot;1087&quot; data-start=&quot;1044&quot;&gt;Zustand, Redux Toolkit (slice에서 에러 상태 지정)&lt;/li&gt;
&lt;li data-end=&quot;1127&quot; data-start=&quot;1088&quot;&gt;GraphQL (Apollo Client에서 onError 핸들링)&lt;/li&gt;
&lt;li data-end=&quot;1160&quot; data-start=&quot;1128&quot;&gt;RxJS (observable.catchError())&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1165&quot; data-start=&quot;1162&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1174&quot; data-start=&quot;1167&quot; data-ke-size=&quot;size26&quot;&gt;✨ 장점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1265&quot; data-start=&quot;1176&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1187&quot; data-start=&quot;1176&quot;&gt;코드가 깔끔해지고&lt;/li&gt;
&lt;li data-end=&quot;1202&quot; data-start=&quot;1188&quot;&gt;관심사 분리가 잘 되고&lt;/li&gt;
&lt;li data-end=&quot;1213&quot; data-start=&quot;1203&quot;&gt;유지보수가 쉬움&lt;/li&gt;
&lt;li data-end=&quot;1265&quot; data-start=&quot;1214&quot;&gt;UI 흐름 제어가 자연스러움 (특히 React 같은 declarative 프레임워크에서)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1270&quot; data-start=&quot;1267&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1609&quot; data-start=&quot;1597&quot; data-ke-size=&quot;size26&quot;&gt;요약&amp;nbsp;&lt;/h2&gt;
&lt;blockquote data-end=&quot;1667&quot; data-start=&quot;1611&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1667&quot; data-start=&quot;1613&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;선언적 에러 처리란, &amp;lsquo;이 상황에서 이렇게 반응해&amp;rsquo;라고 선언만 해두는 방식의 에러 처리야.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>개발</category>
      <author>기록하는 남자</author>
      <guid isPermaLink="true">https://noteit.tistory.com/49</guid>
      <comments>https://noteit.tistory.com/entry/%EC%84%A0%EC%96%B8%EC%A0%81-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC#entry49comment</comments>
      <pubDate>Sat, 5 Apr 2025 00:31:29 +0900</pubDate>
    </item>
    <item>
      <title>[취업을 위한 CS 지식] 18강. CPU 스케줄링</title>
      <link>https://noteit.tistory.com/entry/%EC%B7%A8%EC%97%85%EC%9D%84-%EC%9C%84%ED%95%9C-CS-%EC%A7%80%EC%8B%9D-18%EA%B0%95-CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81</link>
      <description>&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=Ii8E_pM77nw&amp;amp;list=PLVsNizTWUw7GVLg1B6w9PQSiO7yx8TOYA&amp;amp;index=20&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/cSAosp/hyYxSpyiPN/p1fdHRo1e4XhubgU4qhgg0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=460_106_660_306,https://scrap.kakaocdn.net/dn/b6neN7/hyYyQLEncR/Fimlk2kK4Ja4KBv5YqqyxK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=460_106_660_306&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;[취업을 위한 CS 지식] 18강. CPU 스케줄링&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/Ii8E_pM77nw&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;97&quot; data-start=&quot;74&quot; data-ke-size=&quot;size23&quot;&gt;왜 CPU 스케줄링이 필요한가?&lt;/h3&gt;
&lt;p data-end=&quot;249&quot; data-start=&quot;99&quot; data-ke-size=&quot;size16&quot;&gt;여러 프로세스나 스레드가 동시에 실행되려면 CPU를 나눠서 사용해야 한다.&lt;br /&gt;하지만 CPU는 한 번에 하나의 작업만 처리할 수 있으므로, &lt;b&gt;어떤 프로세스가 언제 CPU를 사용할지 결정&lt;/b&gt;하는 과정이 필요하다.&lt;br /&gt;이때 사용하는 것이 바로 &lt;b&gt;CPU 스케줄링&lt;/b&gt;이다.&lt;/p&gt;
&lt;blockquote data-end=&quot;367&quot; data-start=&quot;251&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;367&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CPU 스케줄링의 대상이 되려면 'context(문맥)' 정보가 필요하다.&lt;/b&gt;&lt;br /&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;92&quot; data-start=&quot;57&quot; data-ke-size=&quot;size23&quot;&gt;CPU Utilization (CPU 활용률)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;317&quot; data-start=&quot;94&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;197&quot; data-start=&quot;94&quot;&gt;&lt;b&gt;정의&lt;/b&gt;:&lt;br /&gt;시스템이 가동되는 동안 &lt;b&gt;CPU가 유휴(idle) 상태가 아닌 시간의 비율&lt;/b&gt;.&lt;br /&gt;즉, CPU가 실제로 &lt;b&gt;어떤 작업이든 수행한 시간 / 전체 시간&lt;/b&gt;.&lt;/li&gt;
&lt;li data-end=&quot;317&quot; data-start=&quot;199&quot;&gt;CPU는 시스템의 핵심 자원이므로 효율적인 사용이 중요하지만, &lt;b&gt;CPU 활용률이 높다는 것은 상황에 따라 해석이 달라질 수 있다&lt;/b&gt;. 적절한 수준(보통 60-80%)의 CPU 활용률은 자원을 효율적으로 사용한다고 볼 수 있지만, 지나치게 높은 활용률(90-100%)은 시스템 과부하나 병목 현상을 의미할 수 있다. 시스템 효율성은 CPU 활용률 외에도 처리량, 응답 시간, 다른 자원의 균형적 사용 등을 종합적으로 고려해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;535&quot; data-start=&quot;512&quot; data-ke-size=&quot;size23&quot;&gt;프로세스의 특성과 스케줄링 전략&lt;/h3&gt;
&lt;p data-end=&quot;560&quot; data-start=&quot;537&quot; data-ke-size=&quot;size16&quot;&gt;프로세스는 크게 두 가지 유형으로 나뉜다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;713&quot; data-start=&quot;562&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;646&quot; data-start=&quot;562&quot;&gt;&lt;b&gt;I/O 집중 프로세스 (I/O-bound process)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;646&quot; data-start=&quot;606&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;646&quot; data-start=&quot;606&quot;&gt;CPU는 잠깐만 쓰고 대부분의 시간은 입출력(I/O) 작업에 사용함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;713&quot; data-start=&quot;647&quot;&gt;&lt;b&gt;CPU 집중 프로세스 (CPU-bound process)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;713&quot; data-start=&quot;691&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;713&quot; data-start=&quot;691&quot;&gt;대부분의 시간 동안 CPU를 사용함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-end=&quot;740&quot; data-start=&quot;715&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;740&quot; data-start=&quot;717&quot; data-ke-size=&quot;size16&quot;&gt;스케줄링 전략에 따라 효율이 크게 달라짐.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;983&quot; data-start=&quot;742&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;881&quot; data-start=&quot;742&quot;&gt;&lt;b&gt;I/O 중심 프로세스에 우선순위를 줄 경우&lt;/b&gt;&lt;br /&gt;&amp;rarr; CPU는 짧게 쓰고 I/O로 넘어가므로&lt;br /&gt;&amp;rarr; 그 사이에 CPU 집중 프로세스가 CPU를 사용할 수 있어&lt;br /&gt;&amp;rarr; &lt;b&gt;CPU를 효율적으로 쓸 수 있음 (병렬 처리 효과 극대화)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;983&quot; data-start=&quot;883&quot;&gt;&lt;b&gt;CPU 중심 프로세스에 우선순위를 줄 경우&lt;/b&gt;&lt;br /&gt;&amp;rarr; I/O 프로세스는 CPU를 잠깐 쓰려고 오래 대기해야 하므로&lt;br /&gt;&amp;rarr; 전체 시스템 자원 활용이 &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;h3 data-end=&quot;1175&quot; data-start=&quot;1157&quot; data-ke-size=&quot;size23&quot;&gt;CPU 스케줄러의 역할&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1276&quot; data-start=&quot;1177&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1229&quot; data-start=&quot;1177&quot;&gt;&lt;b&gt;CPU 스케줄러는 Ready Queue 내에서 어떤 프로세스를 실행시킬지 결정&lt;/b&gt;한다.&lt;/li&gt;
&lt;li data-end=&quot;1276&quot; data-start=&quot;1230&quot;&gt;다양한 스케줄링 알고리즘이 존재 (FCFS, SJF, Round Robin 등)&lt;/li&gt;
&lt;/ul&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;h2 data-end=&quot;155&quot; data-start=&quot;118&quot; data-ke-size=&quot;size26&quot;&gt;선점형 스케줄링 (Preemptive Scheduling)&lt;/h2&gt;
&lt;h3 data-end=&quot;167&quot; data-start=&quot;157&quot; data-ke-size=&quot;size23&quot;&gt;  정의:&lt;/h3&gt;
&lt;blockquote data-end=&quot;243&quot; data-start=&quot;168&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;243&quot; data-start=&quot;170&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현재 실행 중인 프로세스를 강제로 중단&lt;/b&gt;시키고, 더 높은 우선순위의 프로세스나 다른 프로세스를 &lt;b&gt;CPU에 할당&lt;/b&gt;하는 방식.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-end=&quot;256&quot; data-start=&quot;245&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;특징:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;381&quot; data-start=&quot;257&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;291&quot; data-start=&quot;257&quot;&gt;CPU를 사용할 수 있는 &lt;b&gt;여러 프로세스들이 경쟁&lt;/b&gt;함.&lt;/li&gt;
&lt;li data-end=&quot;362&quot; data-start=&quot;292&quot;&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;/li&gt;
&lt;li data-end=&quot;381&quot; data-start=&quot;363&quot;&gt;&lt;b&gt;시스템 반응성이 좋음&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;403&quot; data-start=&quot;383&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;예시 스케줄링 알고리즘:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;491&quot; data-start=&quot;404&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;417&quot; data-start=&quot;404&quot;&gt;Round Robin&lt;/li&gt;
&lt;li data-end=&quot;456&quot; data-start=&quot;418&quot;&gt;Shortest Remaining Time First (SRTF)&lt;/li&gt;
&lt;li data-end=&quot;491&quot; data-start=&quot;457&quot;&gt;Priority Scheduling (선점형 방식일 경우)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;502&quot; data-start=&quot;493&quot; data-ke-size=&quot;size23&quot;&gt;  예:&lt;/h3&gt;
&lt;blockquote data-end=&quot;551&quot; data-start=&quot;503&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;551&quot; data-start=&quot;505&quot; data-ke-size=&quot;size16&quot;&gt;게임 중 알림(전화, 메시지 등)이 오면 현재 게임이 멈추고 알림 처리 &amp;rarr; 선점형.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;556&quot; data-start=&quot;553&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;600&quot; data-start=&quot;558&quot; data-ke-size=&quot;size26&quot;&gt;비선점형 스케줄링 (Non-Preemptive Scheduling)&lt;/h2&gt;
&lt;h3 data-end=&quot;612&quot; data-start=&quot;602&quot; data-ke-size=&quot;size23&quot;&gt;  정의:&lt;/h3&gt;
&lt;blockquote data-end=&quot;676&quot; data-start=&quot;613&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;676&quot; data-start=&quot;615&quot; data-ke-size=&quot;size16&quot;&gt;한 번 CPU를 할당받은 프로세스는 &lt;b&gt;스스로 작업을 끝내거나 입출력을 요청할 때까지&lt;/b&gt; CPU를 계속 사용.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-end=&quot;689&quot; data-start=&quot;678&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;특징:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;796&quot; data-start=&quot;690&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;741&quot; data-start=&quot;690&quot;&gt;현재 실행 중인 프로세스가 &lt;b&gt;CPU를 자발적으로 놓기 전까지&lt;/b&gt; 다른 프로세스는 대기.&lt;/li&gt;
&lt;li data-end=&quot;777&quot; data-start=&quot;742&quot;&gt;&lt;b&gt;선점이 없기 때문에 컨텍스트 스위칭 오버헤드가 적음&lt;/b&gt;.&lt;/li&gt;
&lt;li data-end=&quot;796&quot; data-start=&quot;778&quot;&gt;다만 시스템 반응성은 떨어짐.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;818&quot; data-start=&quot;798&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;예시 스케줄링 알고리즘:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;921&quot; data-start=&quot;819&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;852&quot; data-start=&quot;819&quot;&gt;First-Come, First-Served (FCFS)&lt;/li&gt;
&lt;li data-end=&quot;885&quot; data-start=&quot;853&quot;&gt;Shortest Job First (SJF, 비선점형)&lt;/li&gt;
&lt;li data-end=&quot;921&quot; data-start=&quot;886&quot;&gt;Priority Scheduling (비선점형 방식일 경우)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;932&quot; data-start=&quot;923&quot; data-ke-size=&quot;size23&quot;&gt;  예:&lt;/h3&gt;
&lt;blockquote data-end=&quot;989&quot; data-start=&quot;933&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;989&quot; data-start=&quot;935&quot; data-ke-size=&quot;size16&quot;&gt;프린터로 문서를 출력하는 중엔 아무리 급한 문서가 있어도 현재 문서가 끝나야 출력됨 &amp;rarr; 비선점형.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;994&quot; data-start=&quot;991&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1006&quot; data-start=&quot;996&quot; data-ke-size=&quot;size26&quot;&gt;비교 정리&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1187&quot; data-start=&quot;1008&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;선점형&lt;/td&gt;
&lt;td&gt;비선점형&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1092&quot; data-start=&quot;1057&quot;&gt;
&lt;td&gt;CPU 회수&lt;/td&gt;
&lt;td&gt;강제로 회수 가능&lt;/td&gt;
&lt;td&gt;자발적 반환만 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1110&quot; data-start=&quot;1093&quot;&gt;
&lt;td&gt;반응성&lt;/td&gt;
&lt;td&gt;빠름&lt;/td&gt;
&lt;td&gt;느림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1142&quot; data-start=&quot;1111&quot;&gt;
&lt;td&gt;복잡도&lt;/td&gt;
&lt;td&gt;높음 (컨텍스트 스위칭 발생)&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1187&quot; data-start=&quot;1143&quot;&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;td&gt;Round Robin, SRTF&lt;/td&gt;
&lt;td&gt;FCFS, SJF (비선점)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;338&quot; data-start=&quot;235&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;338&quot; data-start=&quot;325&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;114&quot; data-start=&quot;65&quot; data-ke-size=&quot;size26&quot;&gt;1. &lt;b&gt;선입 선처리(FCFS, First Come First Served)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;125&quot; data-start=&quot;116&quot; data-ke-size=&quot;size23&quot;&gt;  개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;194&quot; data-start=&quot;126&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;164&quot; data-start=&quot;126&quot;&gt;&lt;b&gt;먼저 도착한 프로세스부터 CPU 할당&lt;/b&gt;하는 방식 (비선점형)&lt;/li&gt;
&lt;li data-end=&quot;194&quot; data-start=&quot;165&quot;&gt;FIFO 방식 (큐에 먼저 들어온 순서대로 처리)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;205&quot; data-start=&quot;196&quot; data-ke-size=&quot;size23&quot;&gt;  장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;223&quot; data-start=&quot;206&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;223&quot; data-start=&quot;206&quot;&gt;구조가 단순하고 구현이 쉬움&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;234&quot; data-start=&quot;225&quot; data-ke-size=&quot;size23&quot;&gt;  단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;338&quot; data-start=&quot;235&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;324&quot; data-start=&quot;235&quot;&gt;&lt;b&gt;호위 효과 (Convoy Effect)&lt;/b&gt; 발생 가능&amp;nbsp;&lt;br /&gt;&amp;rarr; 실행 시간이 긴 프로세스가 먼저 도착하면, 뒤에 있는 짧은 프로세스들이 오랫동안 대기&lt;/li&gt;
&lt;li data-end=&quot;338&quot; data-start=&quot;325&quot;&gt;응답 시간이 불균형함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;convoy 호송하다, 호위하다 - 줄지어 행렬해서 뒤에는 느려짐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;390&quot; data-start=&quot;345&quot; data-ke-size=&quot;size26&quot;&gt;2. &lt;b&gt;최단 작업 우선(SJF, Shortest Job First)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;401&quot; data-start=&quot;392&quot; data-ke-size=&quot;size23&quot;&gt;  개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;472&quot; data-start=&quot;402&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;438&quot; data-start=&quot;402&quot;&gt;실행 시간이 &lt;b&gt;가장 짧은 프로세스&lt;/b&gt;에게 먼저 CPU를 할당&lt;/li&gt;
&lt;li data-end=&quot;472&quot; data-start=&quot;439&quot;&gt;기본적으로 &lt;b&gt;비선점형&lt;/b&gt;이지만, 선점형으로도 구현 가능 (SRT)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;483&quot; data-start=&quot;474&quot; data-ke-size=&quot;size23&quot;&gt;  장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;501&quot; data-start=&quot;484&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;501&quot; data-start=&quot;484&quot;&gt;평균 대기 시간이 가장 짧음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;512&quot; data-start=&quot;503&quot; data-ke-size=&quot;size23&quot;&gt;  단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;571&quot; data-start=&quot;513&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;535&quot; data-start=&quot;513&quot;&gt;&lt;b&gt;실행 시간이 예측 가능해야 함&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;571&quot; data-start=&quot;536&quot;&gt;긴 작업은 계속 밀릴 수 있음 (starvation 가능성)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;609&quot; data-start=&quot;578&quot; data-ke-size=&quot;size26&quot;&gt;3. &lt;b&gt;라운드 로빈(Round Robin)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;620&quot; data-start=&quot;611&quot; data-ke-size=&quot;size23&quot;&gt;  개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;724&quot; data-start=&quot;621&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;676&quot; data-start=&quot;621&quot;&gt;FCFS 방식에 &lt;b&gt;타임 슬라이스(time slice)&lt;/b&gt; 개념을 추가한 &lt;b&gt;선점형&lt;/b&gt; 스케줄링&lt;/li&gt;
&lt;li data-end=&quot;724&quot; data-start=&quot;677&quot;&gt;각 프로세스에 일정 시간만 CPU 할당 &amp;rarr; 그 시간이 지나면 다음 프로세스로 전환&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;735&quot; data-start=&quot;726&quot; data-ke-size=&quot;size23&quot;&gt;  장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;776&quot; data-start=&quot;736&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;762&quot; data-start=&quot;736&quot;&gt;&lt;b&gt;모든 프로세스가 공평하게 CPU 사용&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;776&quot; data-start=&quot;763&quot;&gt;시스템 응답성이 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;787&quot; data-start=&quot;778&quot; data-ke-size=&quot;size23&quot;&gt;  단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;845&quot; data-start=&quot;788&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;816&quot; data-start=&quot;788&quot;&gt;너무 짧은 타임 슬라이스는 &lt;b&gt;오버헤드 증가&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;845&quot; data-start=&quot;817&quot;&gt;너무 긴 타임 슬라이스는 &lt;b&gt;FCFS와 유사&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;905&quot; data-start=&quot;852&quot; data-ke-size=&quot;size26&quot;&gt;4. &lt;b&gt;최소 잔여 시간 우선(SRT, Shortest Remaining Time)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;916&quot; data-start=&quot;907&quot; data-ke-size=&quot;size23&quot;&gt;  개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;982&quot; data-start=&quot;917&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;934&quot; data-start=&quot;917&quot;&gt;&lt;b&gt;SJF의 선점형 버전&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;982&quot; data-start=&quot;935&quot;&gt;실행 중인 프로세스보다 더 &lt;b&gt;잔여 시간이 짧은&lt;/b&gt; 프로세스가 도착하면 선점 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;993&quot; data-start=&quot;984&quot; data-ke-size=&quot;size23&quot;&gt;  장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1023&quot; data-start=&quot;994&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1011&quot; data-start=&quot;994&quot;&gt;평균 대기 시간이 매우 짧음&lt;/li&gt;
&lt;li data-end=&quot;1023&quot; data-start=&quot;1012&quot;&gt;응답 속도도 빠름&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1034&quot; data-start=&quot;1025&quot; data-ke-size=&quot;size23&quot;&gt;  단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1092&quot; data-start=&quot;1035&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1061&quot; data-start=&quot;1035&quot;&gt;&lt;b&gt;프로세스의 전체 실행 시간 추정 필요&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1092&quot; data-start=&quot;1062&quot;&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;h2 data-end=&quot;1130&quot; data-start=&quot;1099&quot; data-ke-size=&quot;size26&quot;&gt;5. &lt;b&gt;우선순위(Priority) 스케줄링&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;1141&quot; data-start=&quot;1132&quot; data-ke-size=&quot;size23&quot;&gt;  개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1199&quot; data-start=&quot;1142&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1179&quot; data-start=&quot;1142&quot;&gt;각 프로세스에 &lt;b&gt;우선순위 부여&lt;/b&gt; &amp;rarr; 높은 우선순위 먼저 실행&lt;/li&gt;
&lt;li data-end=&quot;1199&quot; data-start=&quot;1180&quot;&gt;선점형 또는 비선점형 모두 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1211&quot; data-start=&quot;1201&quot; data-ke-size=&quot;size23&quot;&gt;  문제점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1268&quot; data-start=&quot;1212&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1268&quot; data-start=&quot;1212&quot;&gt;&lt;b&gt;기아 현상 (Starvation)&lt;/b&gt;&lt;br /&gt;&amp;rarr; 우선순위 낮은 프로세스가 계속 대기할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1282&quot; data-start=&quot;1270&quot; data-ke-size=&quot;size23&quot;&gt;  해결 방법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1336&quot; data-start=&quot;1283&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1336&quot; data-start=&quot;1283&quot;&gt;&lt;b&gt;에이징(Aging)&lt;/b&gt;&lt;br /&gt;&amp;rarr; 오래 기다리는 프로세스의 우선순위를 점점 올려주는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;210&quot; data-start=&quot;162&quot; data-ke-size=&quot;size26&quot;&gt;6. 다단계 큐 스케줄링 (Multilevel Queue Scheduling)&lt;/h2&gt;
&lt;h3 data-end=&quot;222&quot; data-start=&quot;212&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;개념:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;360&quot; data-start=&quot;223&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;255&quot; data-start=&quot;223&quot;&gt;&lt;b&gt;우선순위&lt;/b&gt;에 따라 여러 개의 큐(레벨)로 나눔&lt;/li&gt;
&lt;li data-end=&quot;291&quot; data-start=&quot;256&quot;&gt;각 큐는 서로 &lt;b&gt;독립적&lt;/b&gt;이고, &lt;b&gt;큐 간 이동이 없음&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;360&quot; data-start=&quot;292&quot;&gt;항상 &lt;b&gt;가장 우선순위가 높은 큐&lt;/b&gt;에 있는 프로세스를 먼저 처리&lt;br /&gt;&amp;rarr; 그 큐가 비어야 다음 우선순위 큐로 넘어감&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;372&quot; data-start=&quot;362&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;특징:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;486&quot; data-start=&quot;373&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;433&quot; data-start=&quot;373&quot;&gt;&lt;b&gt;각 큐는 다른 스케줄링 방식&lt;/b&gt;을 가질 수 있음 (예: 시스템 큐 = RR, 사용자 큐 = FCFS)&lt;/li&gt;
&lt;li data-end=&quot;486&quot; data-start=&quot;434&quot;&gt;&lt;b&gt;고정된 분류&lt;/b&gt;에 따라 프로세스가 큐에 들어가고, 절대 다른 큐로 &lt;b&gt;이동하지 않음&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;497&quot; data-start=&quot;488&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;단점:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;553&quot; data-start=&quot;498&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;522&quot; data-start=&quot;498&quot;&gt;큐 사이 전환이 불가 &amp;rarr; 유연성이 떨어짐&lt;/li&gt;
&lt;li data-end=&quot;553&quot; data-start=&quot;523&quot;&gt;낮은 우선순위 큐의 starvation 가능성 있음&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;1430&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sjuix/btsM41FfPIe/vcAs76tjOGWkV6Mdl4g3D0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sjuix/btsM41FfPIe/vcAs76tjOGWkV6Mdl4g3D0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sjuix/btsM41FfPIe/vcAs76tjOGWkV6Mdl4g3D0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsjuix%2FbtsM41FfPIe%2FvcAs76tjOGWkV6Mdl4g3D0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1430&quot; height=&quot;554&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;554&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;621&quot; data-start=&quot;560&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-end=&quot;621&quot; data-start=&quot;560&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;7. 다단계 피드백 큐 스케줄링 (Multilevel Feedback Queue Scheduling)&lt;/h2&gt;
&lt;h3 data-end=&quot;633&quot; data-start=&quot;623&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;개념:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;716&quot; data-start=&quot;634&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;657&quot; data-start=&quot;634&quot;&gt;&lt;b&gt;다단계 큐 + 피드백 기능&lt;/b&gt; 결합&lt;/li&gt;
&lt;li data-end=&quot;716&quot; data-start=&quot;658&quot;&gt;프로세스가 &lt;b&gt;큐 사이를 이동 가능&lt;/b&gt;함&lt;br /&gt;&amp;rarr; CPU 사용 시간에 따라 우선순위가 &lt;b&gt;변동&lt;/b&gt;됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;731&quot; data-start=&quot;718&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;동작 방식:&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;876&quot; data-start=&quot;732&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;761&quot; data-start=&quot;732&quot;&gt;&lt;b&gt;처음에는 가장 높은 우선순위 큐에 들어감&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;794&quot; data-start=&quot;762&quot;&gt;정해진 &lt;b&gt;타임 슬라이스 내에 작업을 끝내면 종료&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;824&quot; data-start=&quot;795&quot;&gt;끝내지 못하면 &lt;b&gt;우선순위가 낮은 큐로 이동&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;876&quot; data-start=&quot;825&quot;&gt;반대로, &lt;b&gt;오랫동안 대기한 프로세스는 aging을 통해 우선순위가 높아질 수 있음&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-end=&quot;888&quot; data-start=&quot;878&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;목적:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;962&quot; data-start=&quot;889&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;932&quot; data-start=&quot;889&quot;&gt;CPU 집중형 프로세스와 입출력 집중형 프로세스를 구분하여 효율적으로 처리&lt;/li&gt;
&lt;li data-end=&quot;962&quot; data-start=&quot;933&quot;&gt;시스템 &lt;b&gt;반응성&lt;/b&gt; 향상 + &lt;b&gt;공정성&lt;/b&gt; 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;973&quot; data-start=&quot;964&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;장점:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1027&quot; data-start=&quot;974&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;996&quot; data-start=&quot;974&quot;&gt;유연하고, 다양한 프로세스 처리 가능&lt;/li&gt;
&lt;li data-end=&quot;1027&quot; data-start=&quot;997&quot;&gt;&lt;b&gt;starvation 방지&lt;/b&gt; (aging 덕분)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;964&quot; data-end=&quot;973&quot; data-ke-size=&quot;size23&quot;&gt;  단점:&lt;/h3&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 data-end=&quot;116&quot; data-start=&quot;43&quot;&gt;&lt;b&gt;설계 및 구현이 복잡함&lt;/b&gt;&lt;br /&gt;&amp;rarr; 큐의 수, 각 큐의 우선순위, 타임 슬라이스, 큐 이동 기준 등을 세밀하게 설계해야 함&lt;/li&gt;
&lt;li data-end=&quot;176&quot; data-start=&quot;118&quot;&gt;&lt;b&gt;타임 슬라이스 설정이 까다로움&lt;/b&gt;&lt;br /&gt;&amp;rarr; 너무 짧으면 문맥 교환 증가, 너무 길면 반응성 저하&lt;/li&gt;
&lt;li data-end=&quot;306&quot; data-start=&quot;246&quot;&gt;&lt;b&gt;우선순위 조정 기준이 명확하지 않음&lt;/b&gt;&lt;br /&gt;&amp;rarr; CPU 사용량이나 대기 시간 기준이 모호할 수 있음&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;1154&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZJZLD/btsM5XoyhOt/Ofrx2K8g0wHTpu0AeM62tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZJZLD/btsM5XoyhOt/Ofrx2K8g0wHTpu0AeM62tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZJZLD/btsM5XoyhOt/Ofrx2K8g0wHTpu0AeM62tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZJZLD%2FbtsM5XoyhOt%2FOfrx2K8g0wHTpu0AeM62tk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1154&quot; height=&quot;534&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;534&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;h2 data-end=&quot;110&quot; data-start=&quot;85&quot; data-ke-size=&quot;size26&quot;&gt;리눅스의 CPU 스케줄링 정책 개요&lt;/h2&gt;
&lt;p data-end=&quot;172&quot; data-start=&quot;112&quot; data-ke-size=&quot;size16&quot;&gt;리눅스는 여러 유형의 프로세스를 처리하기 위해 다양한 스케줄링 정책을 제공합니다. 크게 두 가지로 나뉩니다:&lt;/p&gt;
&lt;h3 data-end=&quot;209&quot; data-start=&quot;174&quot; data-ke-size=&quot;size23&quot;&gt;1️⃣ 실시간 프로세스를 위한 정책 (Real-time)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;272&quot; data-start=&quot;210&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;245&quot; data-start=&quot;210&quot;&gt;SCHED_FIFO (First In First Out)&lt;/li&gt;
&lt;li data-end=&quot;272&quot; data-start=&quot;246&quot;&gt;SCHED_RR (Round Robin)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;296&quot; data-start=&quot;274&quot; data-ke-size=&quot;size23&quot;&gt;2️⃣ 일반 프로세스를 위한 정책&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;344&quot; data-start=&quot;297&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;313&quot; data-start=&quot;297&quot;&gt;SCHED_NORMAL&lt;/li&gt;
&lt;li data-end=&quot;329&quot; data-start=&quot;314&quot;&gt;SCHED_BATCH&lt;/li&gt;
&lt;li data-end=&quot;344&quot; data-start=&quot;330&quot;&gt;SCHED_IDLE&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;349&quot; data-start=&quot;346&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;369&quot; data-start=&quot;351&quot; data-ke-size=&quot;size26&quot;&gt;  각 스케줄링 정책 설명&lt;/h2&gt;
&lt;div&gt;&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;721&quot; data-start=&quot;371&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;정책&lt;/td&gt;
&lt;td&gt;이름설명&lt;span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;476&quot; data-start=&quot;406&quot;&gt;
&lt;td&gt;&lt;b&gt;SCHED_FIFO&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;실시간성 보장 필요 시 사용, 먼저 들어온 프로세스가 CPU를 계속 가짐 (선점 안 됨)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;531&quot; data-start=&quot;477&quot;&gt;
&lt;td&gt;&lt;b&gt;SCHED_RR&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;FIFO 기반 + 타임 슬라이스 (선점 가능, 실시간에서 사용)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;611&quot; data-start=&quot;532&quot;&gt;
&lt;td&gt;&lt;b&gt;SCHED_NORMAL&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;일반적인 사용자 프로세스에 사용, &lt;b&gt;CFS(Completely Fair Scheduler)&lt;/b&gt; 기반&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;665&quot; data-start=&quot;612&quot;&gt;
&lt;td&gt;&lt;b&gt;SCHED_BATCH&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;백그라운드 작업용, 인터랙티브 반응 필요 없는 배치 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;721&quot; data-start=&quot;666&quot;&gt;
&lt;td&gt;&lt;b&gt;SCHED_IDLE&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;CPU가 완전히 놀고 있을 때만 실행됨 (가장 낮은 우선순위)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;732&quot; data-start=&quot;682&quot; data-ke-size=&quot;size23&quot;&gt;❓ Q1. &lt;b&gt;CPU가 놀고 있을 때 왜 정책(SCHED_IDLE)이 필요할까?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;959&quot; data-start=&quot;734&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;836&quot; data-start=&quot;734&quot;&gt;&lt;b&gt;답변&lt;/b&gt;: 어떤 태스크는 중요하지 않고, 정말 시스템이 &quot;할 일 없을 때만&quot; 실행되길 바랄 수 있음.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;836&quot; data-start=&quot;797&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;836&quot; data-start=&quot;797&quot;&gt;예: 백그라운드에서 돌아가는 로그 정리, 통계 수집, 자동 백업 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;921&quot; data-start=&quot;837&quot;&gt;이럴 때 SCHED_IDLE로 태스크를 설정해두면 &lt;b&gt;CPU가 유휴 상태일 때만 실행&lt;/b&gt;되고, 우선순위 높은 작업이 생기면 &lt;b&gt;즉시 중단&lt;/b&gt;됨.&lt;/li&gt;
&lt;li data-end=&quot;959&quot; data-start=&quot;922&quot;&gt;즉, 시스템 리소스를 &lt;b&gt;전혀 방해하지 않도록 만든 정책&lt;/b&gt;임.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;964&quot; data-start=&quot;961&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1005&quot; data-start=&quot;966&quot; data-ke-size=&quot;size23&quot;&gt;❓ Q2. &lt;b&gt;SCHED_BATCH는 뭐고 왜 따로 있을까?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1359&quot; data-start=&quot;1007&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1103&quot; data-start=&quot;1007&quot;&gt;&lt;b&gt;답변&lt;/b&gt;: SCHED_NORMAL은 **인터랙티브(사용자 반응)**에 최적화된 스케줄링이 적용됨. 예를 들어 마우스 클릭, 키보드 입력 등에 빠르게 반응해야 함.&lt;/li&gt;
&lt;li data-end=&quot;1207&quot; data-start=&quot;1104&quot;&gt;하지만 어떤 프로세스는 &lt;b&gt;사용자와 상호작용이 없는&lt;/b&gt; 순차적 작업만 한다면, 굳이 반응 속도를 신경 쓸 필요 없음.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1207&quot; data-start=&quot;1174&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1207&quot; data-start=&quot;1174&quot;&gt;예: 이미지 변환, 대량 데이터 처리, 보고서 생성 등.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1302&quot; data-start=&quot;1208&quot;&gt;이런 작업을 SCHED_BATCH로 설정하면, &lt;b&gt;인터랙티브 프로세스보다 CPU 우선순위는 낮지만&lt;/b&gt;, &lt;b&gt;효율적으로 긴 작업을 수행할 수 있도록 스케줄링&lt;/b&gt;됨.&lt;/li&gt;
&lt;li data-end=&quot;1359&quot; data-start=&quot;1303&quot;&gt;CFS 안에서 처리되긴 하지만 &lt;b&gt;반응성 평가를 하지 않음&lt;/b&gt; &amp;rarr; 더 효율적인 CPU 사용 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1364&quot; data-start=&quot;1361&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1408&quot; data-start=&quot;1366&quot; data-ke-size=&quot;size23&quot;&gt;❓ Q3. &lt;b&gt;왜 SCHED_FIFO가 실시간 보장을 하는 걸까?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1691&quot; data-start=&quot;1410&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1523&quot; data-start=&quot;1410&quot;&gt;&lt;b&gt;답변&lt;/b&gt;: SCHED_FIFO는 &lt;b&gt;&quot;진짜로 선점이 없는&quot; 스케줄링&lt;/b&gt;을 보장함.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1523&quot; data-start=&quot;1464&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1523&quot; data-start=&quot;1464&quot;&gt;어떤 실시간 태스크가 한 번 CPU를 잡으면 &lt;b&gt;스스로 끝내거나 블록될 때까지 절대 빼앗기지 않음&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1624&quot; data-start=&quot;1524&quot;&gt;이 방식은 **시간 민감한 작업(예: 오디오 처리, 산업 제어)**에서 중요함.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1624&quot; data-start=&quot;1573&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1624&quot; data-start=&quot;1573&quot;&gt;예: 로봇 제어에서 &quot;0.05초 안에 명령 내려야 함&quot; &amp;rarr; &lt;b&gt;절대 딜레이 허용 불가&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1691&quot; data-start=&quot;1625&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;779&quot; data-start=&quot;728&quot; data-ke-size=&quot;size26&quot;&gt;  CFS (Completely Fair Scheduler) &amp;ndash; 리눅스 기본 스케줄러&lt;/h2&gt;
&lt;p data-end=&quot;851&quot; data-start=&quot;781&quot; data-ke-size=&quot;size16&quot;&gt;CFS는 SCHED_NORMAL 정책에 적용되며, 프로세스에게 &lt;b&gt;공평하게 CPU 시간&lt;/b&gt;을 분배하기 위해 만들어졌습니다.&lt;/p&gt;
&lt;h3 data-end=&quot;887&quot; data-start=&quot;853&quot; data-ke-size=&quot;size23&quot;&gt;vruntime (가상 실행 시간, virtural runtime)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;943&quot; data-start=&quot;889&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;940&quot; data-start=&quot;889&quot;&gt;프로세스의 실제 실행 시간이 아니라,&lt;br /&gt;&lt;b&gt;우선순위를 고려한 실행 시간&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1743621619173&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vruntime = 실제 실행 시간 &amp;times; (기본 weight / 해당 프로세스 weight)&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 data-end=&quot;254&quot; data-start=&quot;198&quot;&gt;목적: &lt;b&gt;CFS가 각 프로세스가 CPU를 얼마나 &quot;공정하게&quot; 사용했는지를 판단&lt;/b&gt;하기 위해 사용&lt;/li&gt;
&lt;li data-end=&quot;312&quot; data-start=&quot;255&quot;&gt;핵심: &lt;b&gt;우선순위가 높은 프로세스는 vruntime이 느리게 증가&lt;/b&gt; &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;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;503&quot; data-start=&quot;271&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;503&quot; data-start=&quot;321&quot;&gt;
&lt;tr data-end=&quot;386&quot; data-start=&quot;321&quot;&gt;
&lt;td&gt;&lt;b&gt;우선순위(nice)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;숫자가 작을수록 우선순위 높음 (-20이 제일 높음, 19가 제일 낮음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;433&quot; data-start=&quot;387&quot;&gt;
&lt;td&gt;&lt;b&gt;가중치(weight)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;우선순위 높을수록 weight가 &lt;b&gt;커짐&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;503&quot; data-start=&quot;434&quot;&gt;
&lt;td&gt;&lt;b&gt;vruntime 증가 속도&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;weight가 &lt;b&gt;커지면&lt;/b&gt; vruntime &lt;b&gt;천천히 증가&lt;/b&gt; &amp;rarr; 자주 실행됨&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;&lt;b&gt;상황 예시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1743621759963&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Round 1:
  A, B 모두 vruntime이 비슷하다고 가정하면,
  CFS는 vruntime이 더 작은 A를 먼저 실행시킴.

Round 2:
  A는 실행되었지만 vruntime이 조금밖에 안 늘었음.
  B는 안 돌았기 때문에 vruntime 그대로.

  결과: 여전히 A의 vruntime이 작거나 비슷하므로, 또 A 실행.

Round 3:
  A 또 실행 &amp;rarr; vruntime 조금 증가
  B는 여전히 큐에서 대기

...

이런 식으로 A는 계속 선택되기 쉬움 &amp;rarr; 더 자주 실행됨&lt;/code&gt;&lt;/pre&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;h2 data-end=&quot;1149&quot; data-start=&quot;1128&quot; data-ke-size=&quot;size26&quot;&gt;CFS의 타임 슬라이스 계산&lt;/h2&gt;
&lt;p data-end=&quot;1194&quot; data-start=&quot;1151&quot; data-ke-size=&quot;size16&quot;&gt;타임 슬라이스는 고정값이 아닌 &lt;b&gt;가중치(weight) 비율&lt;/b&gt;에 따라 동적으로 결정됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1743622064855&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;타임 슬라이스 = (프로세스 weight / 전체 weight 합) &amp;times; CFS 큐에 대기하는 프로세스들의 타임 슬라이스 총량&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-end=&quot;495&quot; data-start=&quot;403&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;455&quot; data-start=&quot;403&quot;&gt;목적: &lt;b&gt;이번 턴에 해당 프로세스가 CPU를 얼마나 오랫동안 사용할 수 있을지를 결정&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;495&quot; data-start=&quot;456&quot;&gt;핵심: &lt;b&gt;우선순위가 높은 프로세스는 더 긴 타임슬라이스를 받음&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;518&quot; data-start=&quot;502&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;788&quot; data-start=&quot;520&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;vruntime 계산&lt;/td&gt;
&lt;td&gt;타임슬라이스 계산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;652&quot; data-start=&quot;598&quot;&gt;
&lt;td&gt;  목적&lt;/td&gt;
&lt;td&gt;공정성 판단 (누가 더 CPU 많이 썼는지 비교)&lt;/td&gt;
&lt;td&gt;CPU 점유 시간 배정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;716&quot; data-start=&quot;653&quot;&gt;
&lt;td&gt;  작동 시점&lt;/td&gt;
&lt;td&gt;프로세스가 실행된 후 vruntime에 반영&lt;/td&gt;
&lt;td&gt;실행 전, 얼마나 CPU 줄지 계산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;788&quot; data-start=&quot;717&quot;&gt;
&lt;td&gt;↕️ 우선순위 영향&lt;/td&gt;
&lt;td&gt;높을수록 vruntime 증가가 느려짐 &amp;rarr; 더 자주 실행&lt;/td&gt;
&lt;td&gt;높을수록 더 많은 타임슬라이스 할당됨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스의 스케줄링 정보 확인 방법&lt;/p&gt;
&lt;pre id=&quot;code_1743621391537&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cat /proc/&amp;lt;PID&amp;gt;/sched&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-end=&quot;1492&quot; data-start=&quot;1382&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1416&quot; data-start=&quot;1382&quot;&gt;se.vruntime: 현재까지 누적된 가상 실행 시간&lt;/li&gt;
&lt;li data-end=&quot;1456&quot; data-start=&quot;1417&quot;&gt;se.load.weight: 프로세스의 가중치 (우선순위 기반)&lt;/li&gt;
&lt;li data-end=&quot;1492&quot; data-start=&quot;1457&quot;&gt;prio: 우선순위 값 (숫자가 낮을수록 우선순위 높음)&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;1654&quot; data-origin-height=&quot;852&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqnneM/btsM4YIvW0Y/kb3xxxulQUwR1YGuPemh41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqnneM/btsM4YIvW0Y/kb3xxxulQUwR1YGuPemh41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqnneM/btsM4YIvW0Y/kb3xxxulQUwR1YGuPemh41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqnneM%2FbtsM4YIvW0Y%2Fkb3xxxulQUwR1YGuPemh41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;619&quot; height=&quot;319&quot; data-origin-width=&quot;1654&quot; data-origin-height=&quot;852&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-end=&quot;1527&quot; data-start=&quot;1499&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-end=&quot;1527&quot; data-start=&quot;1499&quot; data-ke-size=&quot;size26&quot;&gt;RB 트리 (Red-Black Tree)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1623&quot; data-start=&quot;1529&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1594&quot; data-start=&quot;1529&quot;&gt;CFS는 vruntime이 &lt;b&gt;가장 작은 프로세스&lt;/b&gt;를 빨리 찾기 위해&lt;br /&gt;&lt;b&gt;RB 트리 자료구조&lt;/b&gt; 사용&lt;/li&gt;
&lt;li data-end=&quot;1623&quot; data-start=&quot;1595&quot;&gt;효율적으로 최소값을 탐색 &amp;rarr; 빠른 스케줄링 결정&lt;/li&gt;
&lt;li data-end=&quot;1623&quot; data-start=&quot;1595&quot;&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;1130&quot; data-origin-height=&quot;706&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/32uIG/btsM6aOKxua/A8ITyvSSzvZf0gwA4rYmuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/32uIG/btsM6aOKxua/A8ITyvSSzvZf0gwA4rYmuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/32uIG/btsM6aOKxua/A8ITyvSSzvZf0gwA4rYmuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F32uIG%2FbtsM6aOKxua%2FA8ITyvSSzvZf0gwA4rYmuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;318&quot; data-origin-width=&quot;1130&quot; data-origin-height=&quot;706&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>CS</category>
      <author>기록하는 남자</author>
      <guid isPermaLink="true">https://noteit.tistory.com/48</guid>
      <comments>https://noteit.tistory.com/entry/%EC%B7%A8%EC%97%85%EC%9D%84-%EC%9C%84%ED%95%9C-CS-%EC%A7%80%EC%8B%9D-18%EA%B0%95-CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81#entry48comment</comments>
      <pubDate>Thu, 3 Apr 2025 04:37:37 +0900</pubDate>
    </item>
    <item>
      <title>[삼성 코테 기출] 감시</title>
      <link>https://noteit.tistory.com/entry/%EC%82%BC%EC%84%B1-%EC%BD%94%ED%85%8C-%EA%B8%B0%EC%B6%9C-%EA%B0%90%EC%8B%9C</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;&lt;a href=&quot;https://www.acmicpc.net/problem/15683&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/15683&lt;/a&gt;&lt;/p&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;2차원배열을 쓰는 경우, 가능한 방향들을 노드라고 두고 그래프를 만들어서 탐색해나간다.&lt;br /&gt;watch처럼 행동이 길어질 수 있는 연산은 추상화하고 코드를 구상해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1743599829853&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;

int N, M;
int office[8][8];
int min_blind = 1e9;

vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; cctvs;
vector&amp;lt;int&amp;gt; cctv_type;

// 방향: 상 우 하 좌
int dy[4] = {-1, 0, 1, 0};
int dx[4] = {0, 1, 0, -1};

// 각 CCTV의 가능한 방향 조합
vector&amp;lt;vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&amp;gt; directions = {
    {}, // 0번 CCTV 없음
    {{0}, {1}, {2}, {3}}, // 1번
    {{0, 2}, {1, 3}},     // 2번
    {{0, 1}, {1, 2}, {2, 3}, {3, 0}}, // 3번
    {{0, 1, 2}, {1, 2, 3}, {2, 3, 0}, {3, 0, 1}}, // 4번
    {{0, 1, 2, 3}} // 5번
};

// 감시 함수
void watch(int y, int x, int dir, int temp[8][8]) {
    while (true) {
        y += dy[dir];
        x += dx[dir];
        if (y &amp;lt; 0 || y &amp;gt;= N || x &amp;lt; 0 || x &amp;gt;= M || temp[y][x] == 6) break;
        if (temp[y][x] == 0)
            temp[y][x] = -1; // 감시 표시
    }
}

// 백트래킹
void dfs(int depth, int board[8][8]) {
    if (depth == cctvs.size()) {
        int cnt = 0;
        for (int i = 0; i &amp;lt; N; ++i)
            for (int j = 0; j &amp;lt; M; ++j)
                if (board[i][j] == 0)
                    cnt++;
        min_blind = min(min_blind, cnt);
        return;
    }

    int y = cctvs[depth].first;
    int x = cctvs[depth].second;
    int type = cctv_type[depth];

    for (auto &amp;amp;dirs : directions[type]) {
        int temp[8][8];
        copy(&amp;amp;board[0][0], &amp;amp;board[0][0] + 64, &amp;amp;temp[0][0]); // 배열 복사
        for (int d : dirs)
            watch(y, x, d, temp);
        dfs(depth + 1, temp);
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;

    for (int i = 0; i &amp;lt; N; ++i)
        for (int j = 0; j &amp;lt; M; ++j) {
            cin &amp;gt;&amp;gt; office[i][j];
            if (1 &amp;lt;= office[i][j] &amp;amp;&amp;amp; office[i][j] &amp;lt;= 5) {
                cctvs.push_back({i, j});
                cctv_type.push_back(office[i][j]);
            }
        }

    dfs(0, office);
    cout &amp;lt;&amp;lt; min_blind &amp;lt;&amp;lt; '\n';
    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘</category>
      <author>기록하는 남자</author>
      <guid isPermaLink="true">https://noteit.tistory.com/47</guid>
      <comments>https://noteit.tistory.com/entry/%EC%82%BC%EC%84%B1-%EC%BD%94%ED%85%8C-%EA%B8%B0%EC%B6%9C-%EA%B0%90%EC%8B%9C#entry47comment</comments>
      <pubDate>Wed, 2 Apr 2025 23:02:24 +0900</pubDate>
    </item>
    <item>
      <title>플로이드-워셜 Floyd-Warshall</title>
      <link>https://noteit.tistory.com/entry/%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9B%8C%EC%85%9C-Floyd-Warshall</link>
      <description>&lt;pre id=&quot;code_1743444876868&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;climits&amp;gt;

using namespace std;

const int INF = 1e9; // 무한대 값 (INT_MAX 써도 됨)

// 1️⃣ Floyd-Warshall 알고리즘
// - 정점 수: V
// - 거리 행렬: dist[i][j] = i에서 j까지 최단 거리
// - 핵심 로직: 3중 for문으로 모든 경유점 k를 기준으로 경로를 갱신
//   시간복잡도: O(V&amp;sup3;)
void floydWarshall(vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&amp;amp; dist) {
    int V = dist.size();

    for (int k = 0; k &amp;lt; V; ++k) {         // 1️⃣ 경유 노드 k 선택 &amp;rarr; O(V)
        for (int i = 0; i &amp;lt; V; ++i) {     // 2️⃣ 출발 노드 i &amp;rarr; O(V)
            for (int j = 0; j &amp;lt; V; ++j) { // 3️⃣ 도착 노드 j &amp;rarr; O(V)
                // i &amp;rarr; k &amp;rarr; j 경로가 기존 i &amp;rarr; j보다 짧으면 갱신
                if (dist[i][k] &amp;lt; INF &amp;amp;&amp;amp; dist[k][j] &amp;lt; INF) {
                    dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
                }
            }
        }
    }
}

int main() {
    int V = 4; // 정점 수
    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; dist(V, vector&amp;lt;int&amp;gt;(V, INF));

    // 2️⃣ 자기 자신까지는 거리 0 설정 &amp;rarr; O(V)
    for (int i = 0; i &amp;lt; V; ++i) {
        dist[i][i] = 0;
    }

    // 3️⃣ 간선 정보 입력 &amp;rarr; O(E)
    // 예: A &amp;rarr; B (가중치)
    dist[0][1] = 5;
    dist[0][3] = 10;
    dist[1][2] = 3;
    dist[2][3] = 1;

    // 4️⃣ 최단 거리 계산
    floydWarshall(dist);

    // 5️⃣ 결과 출력 &amp;rarr; O(V&amp;sup2;)
    cout &amp;lt;&amp;lt; &quot;모든 쌍 최단 거리 행렬:\n&quot;;
    for (int i = 0; i &amp;lt; V; ++i) {
        for (int j = 0; j &amp;lt; V; ++j) {
            if (dist[i][j] == INF) cout &amp;lt;&amp;lt; &quot;INF &quot;;
            else cout &amp;lt;&amp;lt; dist[i][j] &amp;lt;&amp;lt; &quot; &quot;;
        }
        cout &amp;lt;&amp;lt; endl;
    }

    return 0;
}

/*
  전체 시간복잡도 요약:

1. 초기화
   - 자기 자신까지 거리 0 &amp;rarr; O(V)
   - 간선 입력 &amp;rarr; O(E)

2. 플로이드-워셜 알고리즘
   - 3중 for문 (경유지 k, 출발 i, 도착 j)
   - 각 루프 O(V)
   - 총 시간복잡도: O(V&amp;sup3;)

3. 출력
   - 거리 행렬 출력 &amp;rarr; O(V&amp;sup2;)

  최종 시간복잡도 합산:

    O(V + E)      &amp;larr; 초기화
  + O(V&amp;sup3;)         &amp;larr; 최단 거리 계산
  + O(V&amp;sup2;)         &amp;larr; 출력
  ---------------------------
  = **O(V&amp;sup3;)** ✅ (지배항)

※ 간선 수(E)는 상수 수준이고, 전체 시간복잡도는 V&amp;sup3;에 지배됨
*/&lt;/code&gt;&lt;/pre&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;div&gt;알고리즘음수 간선음의 사이클사용 목적
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;818&quot; data-start=&quot;599&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;818&quot; data-start=&quot;687&quot;&gt;
&lt;tr data-end=&quot;731&quot; data-start=&quot;687&quot;&gt;
&lt;td&gt;&lt;b&gt;다익스트라&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;❌ 안 됨&lt;/td&gt;
&lt;td&gt;❌ 안 됨&lt;/td&gt;
&lt;td&gt;단일 시작점 최단 거리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;775&quot; data-start=&quot;732&quot;&gt;
&lt;td&gt;&lt;b&gt;벨만-포드&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ 됨&lt;/td&gt;
&lt;td&gt;✅ 감지 가능&lt;/td&gt;
&lt;td&gt;단일 시작점 + 음수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;818&quot; data-start=&quot;776&quot;&gt;
&lt;td&gt;&lt;b&gt;플로이드-와샬&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ 됨&lt;/td&gt;
&lt;td&gt;❌ 안 됨&lt;/td&gt;
&lt;td&gt;모든 쌍 최단 거리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;832&quot; data-start=&quot;825&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;blockquote data-end=&quot;942&quot; data-start=&quot;834&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;942&quot; data-start=&quot;836&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;플로이드-와샬은 음수 간선은 잘 처리할 수 있다. 단, 음의 사이클이 있으면 못한다.&lt;/b&gt;&lt;br /&gt;그래서 dist[i][i] &amp;lt; 0 임을 확인해서&amp;nbsp;&lt;b&gt;음의 사이클 감지&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>알고리즘</category>
      <author>기록하는 남자</author>
      <guid isPermaLink="true">https://noteit.tistory.com/46</guid>
      <comments>https://noteit.tistory.com/entry/%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9B%8C%EC%85%9C-Floyd-Warshall#entry46comment</comments>
      <pubDate>Tue, 1 Apr 2025 03:39:18 +0900</pubDate>
    </item>
  </channel>
</rss>