<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>프로그래밍 메모장</title>
    <link>https://lodado.tistory.com/</link>
    <description>https://github.com/lodado

공부한거 메모용

이전 블로그
https://blog.naver.com/ycp998
</description>
    <language>ko</language>
    <pubDate>Wed, 20 May 2026 06:47:59 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>lodado</managingEditor>
    <item>
      <title>GA 로깅과 추상화</title>
      <link>https://lodado.tistory.com/116</link>
      <description>&lt;div class=&quot;page-body&quot;&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80c9-9308-c8752aec2928&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Saas 런칭 2~3주만에 뜬금없이 패들을 통한 첫 구독자가 생겨서, &lt;br /&gt;급하게 로깅 관련 기능을 넣기로 했는데 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Google Tag Manager를 사용하기로 했다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8084-88ab-f7a4cef21631&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;대충 아래와 같은 코드를 넣는 식이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js&quot;&gt;&lt;/script&gt;
&lt;pre id=&quot;3540bc66-6020-8025-bd0f-e0785a1c48ff&quot; class=&quot;code code-wrap mel&quot;&gt;&lt;code&gt;window.dataLayer= window.dataLayer || [];
window.dataLayer.push({
  event:&quot;template_created&quot;,
  template_id:template.id,
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80be-8718-f659e23038d0&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Google Tag Manager에서도 &lt;code&gt;dataLayer.push({ event: &quot;event_name&quot; })&lt;/code&gt; 형태로 이벤트를 전달하고, GTM이 그 이벤트를 기준으로 태그를 실행하는 구조를 사용한다. 즉, 기술적으로는 이 방식 자체가 틀린 건 아니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8044-bf5d-eda825243fba&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-801c-9dd9-d7f300391591&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;문제는 React 코드 안에 이걸 직접 넣기 시작하면 금방 지저분해진다는 거였다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8069-89bf-d1099261a506&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-jsx.min.js&quot;&gt;&lt;/script&gt;
&lt;pre id=&quot;3540bc66-6020-80fc-88a8-eece55ef8bf7&quot; class=&quot;code code-wrap language-jsx javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;const handleSubmit=async () =&amp;gt; {
const result= await createTemplate(payload);

window.dataLayer=window.dataLayer|| [];
window.dataLayer.push({
    event:&quot;template_created&quot;,
    template_id:result.id,
  });

router.push(&quot;/templates&quot;);
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8073-9c73-e433a55aa430&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80f8-84bc-fe19256b55c3&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이러면 하나의 함수 안에 세 가지 관심사가 섞인다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-8066-ba63-f200382a5ad1&quot; class=&quot;code code-wrap angelscript&quot;&gt;&lt;code&gt;1. 액션을 실행한다.
2. 로그를 보낸다
3. 페이지를 이동한다&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;3540bc66-6020-8077-bacb-c00a0c2e8e7b&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;처음 한두 개는 괜찮다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80ff-a415-ef176ebe24c9&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그런데 회원가입, 로그인, 비즈니스 로직, 페이지 진입 로그까지 붙기 시작하면 코드가 금방 &amp;ldquo;분석 도구에 점령당한 비즈니스 로직&amp;rdquo;이 된다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8087-b5e0-c0b091be975f&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 이번에는 최소한의 구조를 잡고 넣기로 했다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-802b-ba66-c7847f934a31&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-805d-8c3c-f03c019368ee&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 React 앱에서 직접 GTM을 알지 않게 했다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-804a-a4f6-cc2b2c2abce8&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;나중에 GA4를 쓰든, PostHog를 쓰든, 자체 로그 서버를 붙이든 바꿀 수 있게 &lt;code&gt;AnalyticsAdapter&lt;/code&gt;를 만들었다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80f3-b1ae-df9e12f3dd23&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-802d-bab1-f87a5ac2528f&quot; class=&quot;code code-wrap language-jsx javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;export interface AnalyticsAdapter {
  track(event:AnalyticsEvent):void;
  identify?(userId:string):void;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;3540bc66-6020-801f-9797-d01a4f3c5655&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;GTM용 구현체는 이렇게 숨겼다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-8038-86fe-d46f444ee2e7&quot; class=&quot;code code-wrap language-jsx javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;export const gtmAdapter:AnalyticsAdapter= {
  track(event) {
if (typeof window===&quot;undefined&quot;) return;

window.dataLayer=window.dataLayer|| [];
window.dataLayer.push(event);
  },

  identify(userId) {
if (typeof window===&quot;undefined&quot;) return;

window.dataLayer=window.dataLayer|| [];
window.dataLayer.push({
      user_id:userId,
    });
  },
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;3540bc66-6020-80a9-8f2e-d198ad1a6042&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 앱에서는 Provider로 주입했다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-80ca-97c1-ef44b642651c&quot; class=&quot;code code-wrap language-jsx javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&amp;lt;AnalyticsProvideradapter={gtmAdapter}&amp;gt;
  {children}
&amp;lt;/AnalyticsProvider&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-807c-b82b-d150b7b45cfb&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 앱의 나머지 코드는 &lt;code&gt;window.dataLayer&lt;/code&gt;를 모른다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80d8-9e36-d7a5da3b1854&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8089-ba29-e9d537ae754f&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그냥 이렇게만 호출한다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-java.min.js&quot;&gt;&lt;/script&gt;
&lt;pre id=&quot;3540bc66-6020-8051-a11b-df7749465caa&quot; class=&quot;code code-wrap language-java&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;analytics.track({
  event:&quot;template_created&quot;,
  template_id:template.id,
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;3540bc66-6020-801a-bdfd-cca947256f3a&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;PostHog 같은 제품도 React에서는 Provider로 클라이언트를 주입하고 hook으로 접근하는 패턴을 제공한다. 그래서 analytics를 앱 전역 관심사로 보고 Provider 뒤에 숨기는 건 꽤 자연스러운 방식이라고 봤다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-807e-b3b0-eb4eaaff5878&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;h2 id=&quot;3540bc66-6020-80dc-b485-ef308c452e86&quot; class=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;2. 비즈니스 로직과 로깅을 고차함수로 분리&lt;/h2&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80c3-a12a-d5ec5026744e&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80ed-afe2-e33147868861&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;다음 문제는 이거였다. &lt;br /&gt;useLoginSuccessMutation 등 어떤 액션을 하고, 이 액션에 대한 &lt;br /&gt;로깅을 넣을려고 할때였다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8062-a534-dc578b0f367f&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-8015-b1d2-f92e3b50bdda&quot; class=&quot;code code-wrap abnf&quot;&gt;&lt;code&gt;await createTemplate(payload);
analytics.track(...);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80d3-af3a-fee0e8010f1b&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80b3-abb1-fbdd9c1c3538&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이 코드도 나쁘진 않지만, 결국 모든 비즈니스 함수 주변에 로깅 코드가 붙는다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80b6-ab17-ef54c2db88ba&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 성공/실패 로그가 필요한 액션은 고차함수로 감쌌다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8057-9a58-e67e2502aa93&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-8071-947d-fe4949d8654b&quot; class=&quot;code code-wrap language-jsx javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;export function withTracking&amp;lt;TArgs extends unknown[], TResult&amp;gt;(
  fn: (...args: TArgs) =&amp;gt; Promise&amp;lt;TResult&amp;gt;,
  options: {
    onSuccess?: (result: TResult, args: TArgs) =&amp;gt; AnalyticsEvent;
    onError?: (error: unknown, args: TArgs) =&amp;gt; AnalyticsEvent;
  }
) {
  return async (...args: TArgs) =&amp;gt; {
    try {
      const result = await fn(...args);

      if (options.onSuccess) {
        analytics.track(options.onSuccess(result, args));
      }

      return result;
    } catch (error) {
      if (options.onError) {
        analytics.track(options.onError(error, args));
      }

      throw error;
    }
  };
}`&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8075-8273-e5b8b59b3a23&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8039-a194-c513a9d7ee60&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;사용은 이런 느낌이다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-8031-bb90-ef7b97e2b488&quot; class=&quot;code code-wrap language-jsx javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;const createTemplateWithTracking=withTracking(createTemplate, {
  onSuccess: (template) =&amp;gt; ({
    event:&quot;template_created&quot;,
    template_id:template.id,
    template_name:template.name,
  }),
  onError: (error) =&amp;gt; ({
    event:&quot;template_create_failed&quot;,
    reason:errorinstanceofError?error.message:&quot;unknown&quot;,
  }),
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;3540bc66-6020-80e1-a506-cdab6ba0916a&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 &lt;code&gt;createTemplate&lt;/code&gt; 자체는 순수하게 API 호출만 담당한다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-80fc-bddd-fe8d97021f0a&quot; class=&quot;code code-wrap language-jsx javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;async function createTemplate(payload:CreateTemplatePayload) {
return api.post(&quot;/templates&quot;,payload);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;3540bc66-6020-80b4-ba14-eb58fb675ccb&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;로깅은 바깥에서 감싼다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-800e-8caa-cf10a78c0d26&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;물론 모든 클릭 이벤트를 고차함수로 감싸면 오히려 복잡해질 수 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-800a-aa67-fdcfff4e33fa&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 기준을 나눴다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-804c-b5ca-dffddfa19b89&quot; class=&quot;code code-wrap nginx&quot;&gt;&lt;code&gt;API 성공/실패, 핵심 액션 완료
&amp;rarr; withTracking 또는 mutation onSuccess

단순 버튼 클릭, 탭 클릭
&amp;rarr; cloneElement onClick event로 + children로 이벤트 전송 또는 data attribute

페이지 진입
&amp;rarr; HOC 또는 전역 PageViewTracker&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;h2 id=&quot;3540bc66-6020-80ca-8faa-cc7b5526a164&quot; class=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;3. 페이지 진입 로깅은 HOC로 분리했다&lt;/h2&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-805a-9418-c63a2f0ba289&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;페이지 진입 로그도 컴포넌트 안에서 매번 &lt;code&gt;useEffect&lt;/code&gt;로 넣고 싶지 않았다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-80c2-a775-e2e183814353&quot; class=&quot;code code-wrap language-jsx javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
analytics.track({
    event:&quot;page_view&quot;,
    page_name:&quot;template_list&quot;,
  });
}, []);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;3540bc66-6020-80d8-bb33-ff67c0ffc92d&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이런 코드가 페이지마다 흩어지면 결국 똑같은 문제가 생긴다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80b3-8d2d-c88219c5d432&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 특정 페이지 진입 로그는 HOC로 뺐다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-80a2-b836-f2394a409d2f&quot; class=&quot;code code-wrap language-jsx javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;export function withPageTracking&amp;lt;Pextendsobject&amp;gt;(
Component:React.ComponentType&amp;lt;P&amp;gt;,
createEvent: () =&amp;gt;AnalyticsEvent
) {
return function PageWithTracking(props:P) {
const analytics= useAnalytics();

useEffect(() =&amp;gt; {
analytics.track(createEvent());
    }, [analytics]);

return &amp;lt;Component {...props}/&amp;gt;;
  };
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;3540bc66-6020-801f-801a-e39a7b01c74f&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;사용은 이렇게 한다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-8018-85c8-dc55f4a8026f&quot; class=&quot;code code-wrap language-jsx javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;export default withPageTracking(TemplatePage, () =&amp;gt; ({
  event:&quot;page_view&quot;,
  page_name:&quot;template_list&quot;,
  page_path:&quot;/templates&quot;,
}));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80bc-9b1e-dfa46cb2e995&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8047-9b62-efe5c3c01975&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 아래처럼 기준을 잡았다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-800b-bd13-fc59db58ecd9&quot; class=&quot;code code-wrap&quot;&gt;&lt;code&gt;공통 page_view
&amp;rarr; 전역 PageViewTracker

특정 의미가 있는 페이지 진입
&amp;rarr; withPageTracking&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8018-8ee2-d7c50f1380c2&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;h2 id=&quot;3540bc66-6020-80c9-b4ef-d7839245c1b8&quot; class=&quot;&quot; data-ke-size=&quot;size26&quot;&gt;급하게 넣었지만, 기준은 세웠다&lt;/h2&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80c5-be7d-c352c2865c2a&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-800e-8639-ebf4258685cb&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이번 작업에서 가장 중요하게 본 건 &amp;ldquo;완벽한 분석 시스템&amp;rdquo;이 아니었다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8057-a4c6-cdc3d10ba230&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;한 달 만에 첫 구독자가 생겼고, 이제부터는 최소한 아래 질문에 답할 수 있어야 했다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8012-a931-eb53ae9fde49&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;pre id=&quot;3540bc66-6020-80bb-aa1b-dc19938133ac&quot; class=&quot;code code-wrap&quot;&gt;&lt;code&gt;사용자는 어디서 들어오는가?
회원가입까지 도달하는가?
핵심 기능을 실행하는가?
결제 전 어디서 이탈하는가?
결제한 사용자는 이후에도 기능을 쓰는가?
어떤 기능에서 에러가 많이 나는가?&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8058-8a83-eaef6a6e79a4&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80aa-ab37-f71a33e0eed0&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;PostHog 문서에서도 이벤트를 사용자 행동의 기본 단위로 설명하고, 예시로 버튼 클릭, 페이지뷰, 회원가입 같은 상호작용을 든다. 결국 제품을 운영하려면 &amp;ldquo;사용자가 뭘 했는지&amp;rdquo;를 이벤트 단위로 볼 수 있어야 한다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-80dc-b5ec-d4ef73ddaad9&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;처음부터 모든 걸 추적할 필요는 없다.&lt;/p&gt;
&lt;/div&gt;
&lt;div dir=&quot;auto&quot; style=&quot;display: contents;&quot;&gt;
&lt;p id=&quot;3540bc66-6020-8090-b31f-c4a69ad4f8ba&quot; class=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 적어도 제품의 핵심 퍼널은 알아야 한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <author>lodado</author>
      <guid isPermaLink="true">https://lodado.tistory.com/116</guid>
      <comments>https://lodado.tistory.com/116#entry116comment</comments>
      <pubDate>Sat, 2 May 2026 17:43:22 +0900</pubDate>
    </item>
    <item>
      <title>이직하고 첫달 만에 300커밋 때려박기 - AI 에이전트 주도 개발 아키텍처 설계</title>
      <link>https://lodado.tistory.com/114</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;755&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1K6gr/dJMcagEYhW9/bFyCzJIfRC5iWKgKcXkRY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1K6gr/dJMcagEYhW9/bFyCzJIfRC5iWKgKcXkRY1/img.png&quot; data-alt=&quot;밝게 빛나는 잔디들..?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1K6gr/dJMcagEYhW9/bFyCzJIfRC5iWKgKcXkRY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1K6gr%2FdJMcagEYhW9%2FbFyCzJIfRC5iWKgKcXkRY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;276&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;755&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;밝게 빛나는 잔디들..?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1087&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJ2dZh/dJMcaiJugDF/3fB3JLFMe8SlxG1iFYqtB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJ2dZh/dJMcaiJugDF/3fB3JLFMe8SlxG1iFYqtB0/img.png&quot; data-alt=&quot;61개의 PR..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJ2dZh/dJMcaiJugDF/3fB3JLFMe8SlxG1iFYqtB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJ2dZh%2FdJMcaiJugDF%2F3fB3JLFMe8SlxG1iFYqtB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;740&quot; height=&quot;560&quot; data-origin-width=&quot;1087&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;61개의 PR..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2월쯤에 스타트업으로 이직했는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;스타트업가면 으쌰으쌰 분위기에 재밌겠다! 싶어 왔는데 &lt;br /&gt;와서 보니 유사 디스토피아더라고요;;&lt;br /&gt;&lt;br /&gt;충격과 공포의 업무량을 소화하기 위해 사용한 방식을 소개합니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;95&quot; data-start=&quot;48&quot; data-section-id=&quot;f5meax&quot; data-ke-size=&quot;size26&quot;&gt;1. 물리적으로 작업 공간을 분리하는 방법: Git Worktree + Tmux&lt;/h2&gt;
&lt;p data-end=&quot;225&quot; data-start=&quot;97&quot; data-ke-size=&quot;size16&quot;&gt;AI 에이전트를 활용한 개발에서 가장 먼저 마주하게 되는 문제는 &lt;b&gt;작업 공간 충돌&lt;/b&gt;입니다.&lt;br /&gt;기존의 단일 브랜치 기반 작업 방식은 구조적으로 순차적인 작업을 강제하기 때문에, 여러 AI를 활용한 병렬 작업에 한계가 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;229&quot; data-start=&quot;151&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;265&quot; data-start=&quot;232&quot; data-section-id=&quot;p1b7ly&quot; data-ke-size=&quot;size23&quot;&gt;1.1 단일 브랜치 방식의 한계와 컨텍스트 오염 문제&lt;/h3&gt;
&lt;p data-end=&quot;330&quot; data-start=&quot;267&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 로그인 기능을 개발하시다가 갑작스럽게 결제 관련 긴급 버그를 수정해야 하는 상황을 가정해 보겠습니다.&lt;/p&gt;
&lt;p data-end=&quot;344&quot; data-start=&quot;332&quot; data-ke-size=&quot;size16&quot;&gt;이 경우 일반적으로는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;402&quot; data-start=&quot;346&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;377&quot; data-start=&quot;346&quot; data-section-id=&quot;rnjb2n&quot;&gt;작업 내용을 stash 하거나 임시 커밋을 생성한 뒤&lt;/li&gt;
&lt;li data-end=&quot;402&quot; data-start=&quot;378&quot; data-section-id=&quot;1yq8moo&quot;&gt;브랜치를 전환하여 작업을 진행하게 됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;472&quot; data-start=&quot;404&quot; data-ke-size=&quot;size16&quot;&gt;사람 입장에서는 다소 번거로운 수준일 수 있지만,&lt;br /&gt;AI 에이전트 입장에서는 이 과정이 &lt;b&gt;심각한 문제&lt;/b&gt;를 유발합니다.&lt;/p&gt;
&lt;p data-end=&quot;553&quot; data-start=&quot;474&quot; data-ke-size=&quot;size16&quot;&gt;AI는 현재 작업 디렉토리의 상태를 기반으로 맥락을 이해하고 있기 때문에,&lt;br /&gt;브랜치가 변경되는 순간 다음과 같은 문제가 발생할 수 있습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;641&quot; data-start=&quot;555&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;593&quot; data-start=&quot;555&quot; data-section-id=&quot;kmaz71&quot;&gt;이전에 존재하던 파일을 계속 참조하는 문제 (Ghost file)&lt;/li&gt;
&lt;li data-end=&quot;623&quot; data-start=&quot;594&quot; data-section-id=&quot;9bergq&quot;&gt;전혀 다른 코드베이스를 기반으로 잘못된 판단 수행&lt;/li&gt;
&lt;li data-end=&quot;641&quot; data-start=&quot;624&quot; data-section-id=&quot;k57j60&quot;&gt;부정확한 코드 생성 (환각)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;709&quot; data-start=&quot;643&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로 에이전트를 재초기화하거나 프로젝트를 다시 인덱싱해야 하며,&lt;br /&gt;이 과정에서 시간과 리소스가 크게 낭비됩니다.&lt;/p&gt;
&lt;hr data-end=&quot;714&quot; data-start=&quot;711&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;754&quot; data-start=&quot;716&quot; data-section-id=&quot;1lop5yl&quot; data-ke-size=&quot;size23&quot;&gt;2.2 Git Worktree를 통한 독립적인 작업 환경 구성&lt;/h3&gt;
&lt;p data-end=&quot;796&quot; data-start=&quot;756&quot; data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위한 방법이 &lt;b&gt;Git Worktree&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-end=&quot;875&quot; data-start=&quot;798&quot; data-ke-size=&quot;size16&quot;&gt;Git Worktree는 하나의 Git 저장소를 공유하면서도,&lt;br /&gt;브랜치별로 별도의 물리적 디렉토리를 생성할 수 있도록 해주는 기능입니다.&lt;/p&gt;
&lt;p data-end=&quot;905&quot; data-start=&quot;877&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 다음과 같은 구조를 구성할 수 있습니다:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;my-project/&lt;/span&gt;&lt;br /&gt;&lt;span&gt;my-project-feature/&lt;/span&gt;&lt;br /&gt;&lt;span&gt;my-project-hotfix/&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;
&lt;p data-end=&quot;1015&quot; data-start=&quot;979&quot; data-ke-size=&quot;size16&quot;&gt;각 디렉토리는 서로 다른 브랜치를 가리키며 독립적으로 동작합니다.&lt;/p&gt;
&lt;p data-end=&quot;1029&quot; data-start=&quot;1017&quot; data-ke-size=&quot;size16&quot;&gt;이 구조를 활용하시면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1091&quot; data-start=&quot;1031&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1050&quot; data-start=&quot;1031&quot; data-section-id=&quot;185pm0y&quot;&gt;에이전트 A: 로그인 기능 개발&lt;/li&gt;
&lt;li data-end=&quot;1071&quot; data-start=&quot;1051&quot; data-section-id=&quot;18r34f4&quot;&gt;에이전트 B: 결제 모듈 리팩토링&lt;/li&gt;
&lt;li data-end=&quot;1091&quot; data-start=&quot;1072&quot; data-section-id=&quot;qmxe29&quot;&gt;에이전트 C: 테스트 코드 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1128&quot; data-start=&quot;1093&quot; data-ke-size=&quot;size16&quot;&gt;과 같이 &lt;b&gt;완전한 병렬 작업 환경&lt;/b&gt;을 구성하실 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1141&quot; data-start=&quot;1130&quot; data-ke-size=&quot;size16&quot;&gt;또한 각 워크트리는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1217&quot; data-start=&quot;1143&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1165&quot; data-start=&quot;1143&quot; data-section-id=&quot;uk7spn&quot;&gt;작업 상태가 서로 영향을 주지 않으며&lt;/li&gt;
&lt;li data-end=&quot;1178&quot; data-start=&quot;1166&quot; data-section-id=&quot;yhr7l5&quot;&gt;컨텍스트가 유지되고&lt;/li&gt;
&lt;li data-end=&quot;1217&quot; data-start=&quot;1179&quot; data-section-id=&quot;1t44dhf&quot;&gt;필요 시 독립적인 node_modules 환경도 유지 가능하여&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1246&quot; data-start=&quot;1219&quot; data-ke-size=&quot;size16&quot;&gt;의존성 충돌 없이 안정적으로 운영할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1298&quot; data-start=&quot;1248&quot; data-ke-size=&quot;size16&quot;&gt;즉, 각 AI 에이전트에게 &lt;b&gt;독립된 작업 공간을 제공하는 구조&lt;/b&gt;라고 이해하시면 됩니다.&lt;/p&gt;
&lt;hr data-end=&quot;1303&quot; data-start=&quot;1300&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1335&quot; data-start=&quot;1305&quot; data-section-id=&quot;1c7har0&quot; data-ke-size=&quot;size23&quot;&gt;2.3 Tmux를 활용한 멀티 터미널 세션 관리&lt;/h3&gt;
&lt;p data-end=&quot;1392&quot; data-start=&quot;1337&quot; data-ke-size=&quot;size16&quot;&gt;여러 개의 Worktree를 운영하게 되면,&lt;br /&gt;이를 효율적으로 제어할 수 있는 환경이 필요합니다.&lt;/p&gt;
&lt;p data-end=&quot;1422&quot; data-start=&quot;1394&quot; data-ke-size=&quot;size16&quot;&gt;이때 활용할 수 있는 도구가 &lt;b&gt;Tmux&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-end=&quot;1470&quot; data-start=&quot;1424&quot; data-ke-size=&quot;size16&quot;&gt;Tmux를 사용하면 하나의 화면에서 여러 터미널 세션을 동시에 관리할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1478&quot; data-start=&quot;1472&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;tmux new-session -s feature-a -c ./worktree-a&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;
&lt;p data-end=&quot;1621&quot; data-start=&quot;1547&quot; data-ke-size=&quot;size16&quot;&gt;이 명령어를 사용하면 특정 Worktree에 연결된 세션을 생성할 수 있으며,&lt;br /&gt;해당 세션에서 AI 에이전트를 실행할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1626&quot; data-start=&quot;1623&quot; data-ke-size=&quot;size16&quot;&gt;또한:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1724&quot; data-start=&quot;1628&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1682&quot; data-start=&quot;1628&quot; data-section-id=&quot;1f7i2hz&quot;&gt;Ctrl + B, D를 통해 세션을 분리(Detach)하여 백그라운드로 실행할 수 있고&lt;/li&gt;
&lt;li data-end=&quot;1724&quot; data-start=&quot;1683&quot; data-section-id=&quot;1gkfxqb&quot;&gt;필요할 때 다시 연결(Attach)하여 작업 상태를 확인할 수 있습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1777&quot; data-start=&quot;1726&quot; data-ke-size=&quot;size16&quot;&gt;이를 통해 여러 AI 에이전트를 동시에 실행하고 관리할 수 있는 환경을 구성할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1851&quot; data-start=&quot;1779&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로 개발자는 단순히 코드를 작성하는 역할을 넘어,&lt;br /&gt;여러 AI 에이전트를 운영하는 &lt;b&gt;관리자 역할&lt;/b&gt;을 수행하게 됩니다.&lt;/p&gt;
&lt;hr data-end=&quot;1856&quot; data-start=&quot;1853&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1885&quot; data-start=&quot;1858&quot; data-section-id=&quot;1b7iqm7&quot; data-ke-size=&quot;size23&quot;&gt;2.4 커밋 및 배포 과정 자동화의 필요성&lt;/h3&gt;
&lt;p data-end=&quot;1951&quot; data-start=&quot;1887&quot; data-ke-size=&quot;size16&quot;&gt;병렬 작업 환경을 구축하셨다면,&lt;br /&gt;완성된 결과를 Git에 반영하는 과정 또한 효율적으로 구성하는 것이 중요합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1980&quot; data-start=&quot;1953&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1957&quot; data-start=&quot;1953&quot; data-section-id=&quot;yijpon&quot;&gt;커밋&lt;/li&gt;
&lt;li data-end=&quot;1962&quot; data-start=&quot;1958&quot; data-section-id=&quot;yiicr0&quot;&gt;푸시&lt;/li&gt;
&lt;li data-end=&quot;1980&quot; data-start=&quot;1963&quot; data-section-id=&quot;1abx5ps&quot;&gt;Pull Request 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2039&quot; data-start=&quot;1982&quot; data-ke-size=&quot;size16&quot;&gt;이러한 과정을 자동화하면 작업 흐름의 마찰을 줄이고,&lt;br /&gt;전체 개발 속도를 더욱 향상시킬 수 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;2044&quot; data-start=&quot;2041&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;113&quot; data-start=&quot;68&quot; data-section-id=&quot;7kj5uy&quot; data-ke-size=&quot;size26&quot;&gt;2. 인지 부하의 완전한 외주화: Context7과 사내 디자인 시스템 연동&lt;/h2&gt;
&lt;p data-end=&quot;243&quot; data-start=&quot;115&quot; data-ke-size=&quot;size16&quot;&gt;새로운 조직에 합류했을 때 생산성을 가장 크게 떨어뜨리는 요인은 &lt;b&gt;도메인 지식 부족&lt;/b&gt;입니다.&lt;br /&gt;사내 프레임워크의 특정 버전이나, 내부 디자인 시스템의 규칙은 일반적인 LLM 학습 데이터에 포함되어 있지 않은 경우가 많습니다.&lt;/p&gt;
&lt;p data-end=&quot;304&quot; data-start=&quot;245&quot; data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기 위해서는&lt;br /&gt;&lt;b&gt;기억하고 검색하는 행위 자체를 AI에게 위임하는 전략&lt;/b&gt;이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;348&quot; data-start=&quot;311&quot; data-section-id=&quot;1myn069&quot; data-ke-size=&quot;size23&quot;&gt;2.1 Context7 MCP를 통한 실시간 공식 문서 주입&lt;/h3&gt;
&lt;p data-end=&quot;381&quot; data-start=&quot;350&quot; data-ke-size=&quot;size16&quot;&gt;개발 시간의 상당 부분은 다음과 같은 작업에 사용됩니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;426&quot; data-start=&quot;383&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;393&quot; data-start=&quot;383&quot; data-section-id=&quot;1ivn8i5&quot;&gt;공식 문서 검색&lt;/li&gt;
&lt;li data-end=&quot;413&quot; data-start=&quot;394&quot; data-section-id=&quot;1yw8ubn&quot;&gt;Stack Overflow 탐색&lt;/li&gt;
&lt;li data-end=&quot;426&quot; data-start=&quot;414&quot; data-section-id=&quot;1vzwhsd&quot;&gt;API 사용법 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;477&quot; data-start=&quot;428&quot; data-ke-size=&quot;size16&quot;&gt;하지만 AI에게 코드 작성을 맡기더라도,&lt;br /&gt;LLM은 종종 다음과 같은 문제를 보입니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;534&quot; data-start=&quot;479&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;502&quot; data-start=&quot;479&quot; data-section-id=&quot;1ishbw4&quot;&gt;이미 deprecated된 API 사용&lt;/li&gt;
&lt;li data-end=&quot;519&quot; data-start=&quot;503&quot; data-section-id=&quot;1mn1wsu&quot;&gt;존재하지 않는 메서드 생성&lt;/li&gt;
&lt;li data-end=&quot;534&quot; data-start=&quot;520&quot; data-section-id=&quot;1mowtru&quot;&gt;잘못된 사용 패턴 제안&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;571&quot; data-start=&quot;536&quot; data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하는 방법이 &lt;b&gt;Context7 MCP&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-end=&quot;605&quot; data-start=&quot;573&quot; data-ke-size=&quot;size16&quot;&gt;Context7은 AI 에이전트가 코드 생성을 하기 전에:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;639&quot; data-start=&quot;607&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;627&quot; data-start=&quot;607&quot; data-section-id=&quot;13rv0a1&quot;&gt;해당 라이브러리의 최신 공식 문서&lt;/li&gt;
&lt;li data-end=&quot;639&quot; data-start=&quot;628&quot; data-section-id=&quot;wbsz4&quot;&gt;버전별 코드 예제&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;673&quot; data-start=&quot;641&quot; data-ke-size=&quot;size16&quot;&gt;를 &lt;b&gt;실시간으로 컨텍스트에 주입&lt;/b&gt;해주는 역할을 합니다.&lt;/p&gt;
&lt;p data-end=&quot;691&quot; data-start=&quot;675&quot; data-ke-size=&quot;size16&quot;&gt;동작 방식은 다음과 같습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;788&quot; data-start=&quot;693&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;733&quot; data-start=&quot;693&quot; data-section-id=&quot;1tafi9s&quot;&gt;resolve-library-id를 통해 정확한 라이브러리 식별&lt;/li&gt;
&lt;li data-end=&quot;767&quot; data-start=&quot;734&quot; data-section-id=&quot;htbxns&quot;&gt;query-docs로 필요한 기능의 공식 문서 조회&lt;/li&gt;
&lt;li data-end=&quot;788&quot; data-start=&quot;768&quot; data-section-id=&quot;1ui4z1c&quot;&gt;해당 내용을 기반으로 코드 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;798&quot; data-start=&quot;790&quot; data-ke-size=&quot;size16&quot;&gt;개발자는 단지:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;850&quot; data-start=&quot;800&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;831&quot; data-start=&quot;800&quot; data-section-id=&quot;1m33wv3&quot;&gt;프롬프트에 &quot;use context7&quot;를 추가하거나&lt;/li&gt;
&lt;li data-end=&quot;850&quot; data-start=&quot;832&quot; data-section-id=&quot;nit3y6&quot;&gt;글로벌 룰을 설정하는 것만으로&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;897&quot; data-start=&quot;852&quot; data-ke-size=&quot;size16&quot;&gt;  별도의 문서 검색 없이도 &lt;b&gt;항상 최신 기준의 코드&lt;/b&gt;를 얻을 수 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;902&quot; data-start=&quot;899&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;157&quot; data-start=&quot;100&quot; data-section-id=&quot;12igchl&quot; data-ke-size=&quot;size23&quot;&gt;2.2 Storybook + Cursor MDC + 스킬/커맨드를 통한 사내 디자인 시스템 주입&lt;/h3&gt;
&lt;p data-end=&quot;222&quot; data-start=&quot;159&quot; data-ke-size=&quot;size16&quot;&gt;외부 라이브러리뿐만 아니라,&lt;br /&gt;&lt;b&gt;사내 디자인 시스템과 컴포넌트 정책 역시 AI에게 정확히 주입해야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;302&quot; data-start=&quot;224&quot; data-ke-size=&quot;size16&quot;&gt;이 과정은 단순한 룰 정의를 넘어서,&lt;br /&gt;&lt;b&gt;스킬(Skill), 커맨드(Command), 그리고 멘션(@) 기반 호출 구조&lt;/b&gt;로 구성됩니다.&lt;/p&gt;
&lt;hr data-end=&quot;307&quot; data-start=&quot;304&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;707&quot; data-start=&quot;636&quot; data-ke-size=&quot;size16&quot;&gt;반복적으로 사용하는 작업은&lt;br /&gt;&lt;b&gt;클로드 코드의 커맨드(Command) 또는 스킬(Skill)&lt;/b&gt; 형태로 추상화할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;715&quot; data-start=&quot;709&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;780&quot; data-start=&quot;717&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;740&quot; data-start=&quot;717&quot; data-section-id=&quot;10q09en&quot;&gt;create-ui-component&lt;/li&gt;
&lt;li data-end=&quot;764&quot; data-start=&quot;741&quot; data-section-id=&quot;x32p7v&quot;&gt;apply-design-system&lt;/li&gt;
&lt;li data-end=&quot;780&quot; data-start=&quot;765&quot; data-section-id=&quot;nwjna7&quot;&gt;validate-ui&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;851&quot; data-start=&quot;782&quot; data-ke-size=&quot;size16&quot;&gt;와 같은 커맨드를 정의해두면,&lt;br /&gt;프롬프트에서 해당 작업을 직접 지시하지 않아도&lt;br /&gt;AI가 일관된 방식으로 동작하게 됩니다.&lt;/p&gt;
&lt;hr data-end=&quot;856&quot; data-start=&quot;853&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;888&quot; data-start=&quot;858&quot; data-ke-size=&quot;size16&quot;&gt;그리고 핵심은 &lt;b&gt;멘션(@) 기반 호출 방식&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-end=&quot;902&quot; data-start=&quot;890&quot; data-ke-size=&quot;size16&quot;&gt;개발자가 프롬프트에서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;/design-system&lt;/span&gt;&lt;br /&gt;&lt;span&gt;@storybook&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;
&lt;p data-end=&quot;961&quot; data-start=&quot;951&quot; data-ke-size=&quot;size16&quot;&gt;과 같이 명시하면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1043&quot; data-start=&quot;963&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1002&quot; data-start=&quot;963&quot; data-section-id=&quot;8idjdz&quot;&gt;/design-system &amp;rarr; MDC 룰을 RAG 방식으로 주입&lt;/li&gt;
&lt;li data-end=&quot;1043&quot; data-start=&quot;1003&quot; data-section-id=&quot;11ep5ir&quot;&gt;@storybook &amp;rarr; 사내 Storybook을 컨텍스트로 불러옴&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1067&quot; data-start=&quot;1045&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 두 시스템이 동시에 활성화됩니다.&lt;/p&gt;
&lt;hr data-end=&quot;1072&quot; data-start=&quot;1069&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1134&quot; data-start=&quot;1074&quot; data-ke-size=&quot;size16&quot;&gt;특히 @storybook 멘션은 단순 참조가 아니라,&lt;br /&gt;&lt;b&gt;실행 가능한 컨텍스트 호출&lt;/b&gt;에 가깝습니다.&lt;/p&gt;
&lt;p data-end=&quot;1145&quot; data-start=&quot;1136&quot; data-ke-size=&quot;size16&quot;&gt;AI 에이전트는:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1236&quot; data-start=&quot;1147&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1163&quot; data-start=&quot;1147&quot; data-section-id=&quot;yvxf21&quot;&gt;Storybook을 실행&lt;/li&gt;
&lt;li data-end=&quot;1179&quot; data-start=&quot;1164&quot; data-section-id=&quot;rsppul&quot;&gt;해당 컴포넌트를 렌더링&lt;/li&gt;
&lt;li data-end=&quot;1217&quot; data-start=&quot;1180&quot; data-section-id=&quot;1p3mfzf&quot;&gt;상태별 UI (Hover, Focus, Disabled) 확인&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1251&quot; data-start=&quot;1238&quot; data-ke-size=&quot;size16&quot;&gt;을 수행할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1275&quot; data-start=&quot;1253&quot; data-ke-size=&quot;size16&quot;&gt;즉, 단순히 &amp;ldquo;이렇게 만들어라&amp;rdquo;가 아니라&lt;/p&gt;
&lt;p data-end=&quot;1319&quot; data-start=&quot;1277&quot; data-ke-size=&quot;size16&quot;&gt;  **&amp;ldquo;실제로 렌더링해서 맞는지 확인하라&amp;rdquo;**까지 자동화되는 구조입니다.&lt;/p&gt;
&lt;hr data-end=&quot;1324&quot; data-start=&quot;1321&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1345&quot; data-start=&quot;1326&quot; data-ke-size=&quot;size16&quot;&gt;이 구조의 핵심은 다음과 같습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1480&quot; data-start=&quot;1347&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1369&quot; data-start=&quot;1347&quot; data-section-id=&quot;bmteex&quot;&gt;MDC &amp;rarr; 규칙 정의 (Policy)&lt;/li&gt;
&lt;li data-end=&quot;1406&quot; data-start=&quot;1370&quot; data-section-id=&quot;b6vpk5&quot;&gt;Command/Skill &amp;rarr; 작업 단위 추상화 (Action)&lt;/li&gt;
&lt;li data-end=&quot;1447&quot; data-start=&quot;1407&quot; data-section-id=&quot;1nt4i2l&quot;&gt;Mention(@) &amp;rarr; 필요한 컨텍스트를 즉시 주입 (Trigger)&lt;/li&gt;
&lt;li data-end=&quot;1480&quot; data-start=&quot;1448&quot; data-section-id=&quot;7ky4wb&quot;&gt;Storybook &amp;rarr; 결과 검증 (Validation)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1485&quot; data-start=&quot;1482&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1497&quot; data-start=&quot;1487&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로 AI는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1553&quot; data-start=&quot;1499&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1514&quot; data-start=&quot;1499&quot; data-section-id=&quot;1qxog7g&quot;&gt;디자인 시스템을 이해하고&lt;/li&gt;
&lt;li data-end=&quot;1534&quot; data-start=&quot;1515&quot; data-section-id=&quot;1iaj1cp&quot;&gt;규칙을 준수하며 코드를 생성하고&lt;/li&gt;
&lt;li data-end=&quot;1553&quot; data-start=&quot;1535&quot; data-section-id=&quot;1gl1bp4&quot;&gt;실제 렌더링 결과까지 검증하는&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1594&quot; data-start=&quot;1555&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;엔드투엔드 UI 구현 + 검증 에이전트&lt;/b&gt;로 동작하게 됩니다.&lt;/p&gt;
&lt;hr data-end=&quot;1599&quot; data-start=&quot;1596&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1657&quot; data-start=&quot;1601&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 구성하면&lt;br /&gt;개발자는 더 이상 &amp;ldquo;버튼 padding이 맞는지&amp;rdquo; 같은 디테일을 신경 쓰지 않고,&lt;/p&gt;
&lt;p data-end=&quot;1691&quot; data-start=&quot;1659&quot; data-ke-size=&quot;size16&quot;&gt;  &amp;ldquo;어떤 UI를 만들어야 하는지&amp;rdquo;만 정의하시면 됩니다.&lt;/p&gt;
&lt;hr data-end=&quot;1545&quot; data-start=&quot;1542&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1579&quot; data-start=&quot;1547&quot; data-section-id=&quot;838qx3&quot; data-ke-size=&quot;size23&quot;&gt;2.3 &quot;WHAT&quot;에 집중하고 &quot;HOW&quot;는 위임하기&lt;/h3&gt;
&lt;p data-end=&quot;1612&quot; data-start=&quot;1581&quot; data-ke-size=&quot;size16&quot;&gt;이러한 구조가 완성되면, 개발자의 역할은 크게 바뀝니다.&lt;/p&gt;
&lt;p data-end=&quot;1619&quot; data-start=&quot;1614&quot; data-ke-size=&quot;size16&quot;&gt;기존에는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1649&quot; data-start=&quot;1621&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1628&quot; data-start=&quot;1621&quot; data-section-id=&quot;5ur93c&quot;&gt;변수 선언&lt;/li&gt;
&lt;li data-end=&quot;1637&quot; data-start=&quot;1629&quot; data-section-id=&quot;anlntp&quot;&gt;반복문 작성&lt;/li&gt;
&lt;li data-end=&quot;1649&quot; data-start=&quot;1638&quot; data-section-id=&quot;nmyvyo&quot;&gt;구현 디테일 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1679&quot; data-start=&quot;1651&quot; data-ke-size=&quot;size16&quot;&gt;즉, &quot;어떻게(HOW)&quot; 만들 것인지에 집중했다면,&lt;/p&gt;
&lt;p data-end=&quot;1685&quot; data-start=&quot;1681&quot; data-ke-size=&quot;size16&quot;&gt;이제는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1733&quot; data-start=&quot;1687&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1700&quot; data-start=&quot;1687&quot; data-section-id=&quot;1yn56vp&quot;&gt;어떤 기능이 필요한지&lt;/li&gt;
&lt;li data-end=&quot;1716&quot; data-start=&quot;1701&quot; data-section-id=&quot;1m6lv3o&quot;&gt;어떤 아키텍처를 사용할지&lt;/li&gt;
&lt;li data-end=&quot;1733&quot; data-start=&quot;1717&quot; data-section-id=&quot;1m7k1ow&quot;&gt;어떤 정책을 따라야 하는지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1766&quot; data-start=&quot;1735&quot; data-ke-size=&quot;size16&quot;&gt;  &quot;무엇(WHAT)&quot;을 정의하는 데 집중하게 됩니다.&lt;/p&gt;
&lt;p data-end=&quot;1793&quot; data-start=&quot;1768&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 프롬프트는 다음과 같이 구성됩니다:&lt;/p&gt;
&lt;blockquote data-end=&quot;1897&quot; data-start=&quot;1795&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1897&quot; data-start=&quot;1797&quot; data-ke-size=&quot;size16&quot;&gt;&quot;Next.js App Router 패턴을 따르고, Context7을 활용하여 Supabase Auth를 구현하며, UI는 사내 디자인 시스템의 Card 컴포넌트와 컴파운트 패턴을 사용해주세요.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;1910&quot; data-start=&quot;1899&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1910&quot; data-start=&quot;1899&quot; data-ke-size=&quot;size16&quot;&gt;이 한 줄의 지시로:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1949&quot; data-start=&quot;1912&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1922&quot; data-start=&quot;1912&quot; data-section-id=&quot;m3bcd4&quot;&gt;인증 로직 구현&lt;/li&gt;
&lt;li data-end=&quot;1930&quot; data-start=&quot;1923&quot; data-section-id=&quot;bjt5og&quot;&gt;타입 정의&lt;/li&gt;
&lt;li data-end=&quot;1939&quot; data-start=&quot;1931&quot; data-section-id=&quot;1w7nkt4&quot;&gt;스타일 적용&lt;/li&gt;
&lt;li data-end=&quot;1949&quot; data-start=&quot;1940&quot; data-section-id=&quot;1r1sos9&quot;&gt;컴포넌트 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1974&quot; data-start=&quot;1951&quot; data-ke-size=&quot;size16&quot;&gt;등 수백 줄의 코드가 자동으로 생성됩니다.&lt;/p&gt;
&lt;p data-end=&quot;1974&quot; data-start=&quot;1951&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2144&quot; data-start=&quot;2095&quot; data-ke-size=&quot;size16&quot;&gt;  핵심은&lt;br /&gt;&lt;b&gt;개발자의 인지 부하를 AI 시스템으로 완전히 외주화하는 것&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;주의할 점은 자신이 무엇을 하는지 인지한 상태에서 작업해야 합니다. 설계까지 ai에게 위임하게 되면 대참사가 일어날 수 &lt;br /&gt;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-section-id=&quot;838qx3&quot; data-start=&quot;1547&quot; data-end=&quot;1579&quot; data-ke-size=&quot;size23&quot;&gt;2.4 MCP를 통한 스펙 &amp;amp; 정책 연동&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;389&quot; data-start=&quot;313&quot; data-ke-size=&quot;size16&quot;&gt;여기에 더해, 단순한 기술 문서뿐만 아니라&lt;br /&gt;&lt;b&gt;기획 문서까지 AI가 직접 이해하고 실행 계획을 수립하도록 만드는 것이 중요합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;430&quot; data-start=&quot;391&quot; data-ke-size=&quot;size16&quot;&gt;이를 위해 &lt;b&gt;Jira MCP와 같은 시스템을 연동&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;430&quot; data-start=&quot;391&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;456&quot; data-start=&quot;432&quot; data-ke-size=&quot;size16&quot;&gt;Jira MCP를 활용하면 AI 에이전트는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;524&quot; data-start=&quot;458&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;473&quot; data-start=&quot;458&quot; data-section-id=&quot;19bssre&quot;&gt;Jira 티켓의 요구사항&lt;/li&gt;
&lt;li data-end=&quot;495&quot; data-start=&quot;474&quot; data-section-id=&quot;1am9wj6&quot;&gt;Acceptance Criteria&lt;/li&gt;
&lt;li data-end=&quot;507&quot; data-start=&quot;496&quot; data-section-id=&quot;5kxe2s&quot;&gt;관련 서브 태스크&lt;/li&gt;
&lt;li data-end=&quot;524&quot; data-start=&quot;508&quot; data-section-id=&quot;zegtav&quot;&gt;첨부된 기획 문서 및 스펙&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;545&quot; data-start=&quot;526&quot; data-ke-size=&quot;size16&quot;&gt;을 실시간으로 읽어올 수 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;550&quot; data-start=&quot;547&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;610&quot; data-start=&quot;552&quot; data-ke-size=&quot;size16&quot;&gt;개발자는 더 이상 티켓을 직접 해석하고 작업을 쪼개는 대신,&lt;br /&gt;다음과 같은 형태로 지시할 수 있습니다:&lt;/p&gt;
&lt;blockquote data-end=&quot;674&quot; data-start=&quot;612&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;674&quot; data-start=&quot;614&quot; data-ke-size=&quot;size16&quot;&gt;&quot;Jira MCP를 사용하여 해당 티켓의 요구사항을 분석하고, 구현 계획(Plan)을 단계별로 작성하세요.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;690&quot; data-start=&quot;676&quot; data-ke-size=&quot;size16&quot;&gt;이 지시를 받으면 AI는:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;798&quot; data-start=&quot;692&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;708&quot; data-start=&quot;692&quot; data-section-id=&quot;16zt9hl&quot;&gt;Jira 티켓을 조회하고&lt;/li&gt;
&lt;li data-end=&quot;728&quot; data-start=&quot;709&quot; data-section-id=&quot;7kkc94&quot;&gt;요구사항을 구조적으로 분석하며&lt;/li&gt;
&lt;li data-end=&quot;744&quot; data-start=&quot;729&quot; data-section-id=&quot;17p9aud&quot;&gt;필요한 기능을 도출하고&lt;/li&gt;
&lt;li data-end=&quot;766&quot; data-start=&quot;745&quot; data-section-id=&quot;1c39ctb&quot;&gt;작업 단위(Task)로 분해한 뒤&lt;/li&gt;
&lt;li data-end=&quot;798&quot; data-start=&quot;767&quot; data-section-id=&quot;6m6mm6&quot;&gt;구현 순서와 의존성을 포함한 실행 계획을 생성합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;803&quot; data-start=&quot;800&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;824&quot; data-start=&quot;805&quot; data-ke-size=&quot;size16&quot;&gt;이 과정의 핵심은 다음과 같습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;871&quot; data-start=&quot;826&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;844&quot; data-start=&quot;826&quot; data-section-id=&quot;kqx41b&quot;&gt;인간 &amp;rarr; 요구사항을 읽고 해석&lt;/li&gt;
&lt;li data-end=&quot;871&quot; data-start=&quot;845&quot; data-section-id=&quot;1euvckf&quot;&gt;AI &amp;rarr; 구조화 + 계획 수립 + 실행 준비&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;938&quot; data-start=&quot;873&quot; data-ke-size=&quot;size16&quot;&gt;  즉, 단순 구현뿐만 아니라&lt;br /&gt;  &lt;b&gt;&amp;ldquo;무엇을 만들어야 하는지 정리하는 과정&amp;rdquo;까지 AI에 위임&lt;/b&gt;하는 것입니다&lt;/p&gt;
&lt;hr data-end=&quot;943&quot; data-start=&quot;940&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1000&quot; data-start=&quot;945&quot; data-ke-size=&quot;size16&quot;&gt;또한 이 구조는 기존 Context7, 디자인 시스템 주입과 결합되어 다음과 같은 흐름을 만듭니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1091&quot; data-start=&quot;1002&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1033&quot; data-start=&quot;1002&quot; data-section-id=&quot;1nojm40&quot;&gt;Jira MCP &amp;rarr; 요구사항 및 기획 문서 주입&lt;/li&gt;
&lt;li data-end=&quot;1061&quot; data-start=&quot;1034&quot; data-section-id=&quot;vhs0fm&quot;&gt;Context7 &amp;rarr; 최신 기술 문서 주입&lt;/li&gt;
&lt;li data-end=&quot;1091&quot; data-start=&quot;1062&quot; data-section-id=&quot;1vmz7wi&quot;&gt;MDC / 디자인 시스템 &amp;rarr; UI 정책 주입&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1123&quot; data-start=&quot;1093&quot; data-ke-size=&quot;size16&quot;&gt;  모든 컨텍스트가 통합된 상태에서 AI가 작업 수행&lt;/p&gt;
&lt;hr data-end=&quot;1128&quot; data-start=&quot;1125&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1141&quot; data-start=&quot;1130&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로 개발자는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1192&quot; data-start=&quot;1143&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1165&quot; data-start=&quot;1143&quot; data-section-id=&quot;vhyihu&quot;&gt;문서를 읽고 정리하는 역할에서 벗어나&lt;/li&gt;
&lt;li data-end=&quot;1192&quot; data-start=&quot;1166&quot; data-section-id=&quot;1afpiod&quot;&gt;요구사항의 방향성과 우선순위, 아키텍처, 디자인 패턴만 결정하면 되며&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1198&quot; data-start=&quot;1194&quot; data-ke-size=&quot;size16&quot;&gt;AI는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1234&quot; data-start=&quot;1200&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1207&quot; data-start=&quot;1200&quot; data-section-id=&quot;901lw5&quot;&gt;기획 이해&lt;/li&gt;
&lt;li data-end=&quot;1215&quot; data-start=&quot;1208&quot; data-section-id=&quot;62lfmt&quot;&gt;기술 선택&lt;/li&gt;
&lt;li data-end=&quot;1226&quot; data-start=&quot;1216&quot; data-section-id=&quot;7s7g&quot;&gt;구현 계획 수립&lt;/li&gt;
&lt;li data-end=&quot;1234&quot; data-start=&quot;1227&quot; data-section-id=&quot;v3c0y4&quot;&gt;코드 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1253&quot; data-start=&quot;1236&quot; data-ke-size=&quot;size16&quot;&gt;까지 일관되게 수행하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-turn-start-message=&quot;true&quot; data-message-model-slug=&quot;gpt-5-3&quot; data-message-id=&quot;6ebfed58-ea21-45f5-b0cf-117f188b53c7&quot; data-message-author-role=&quot;assistant&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-end=&quot;149&quot; data-start=&quot;91&quot; data-section-id=&quot;jwxsl0&quot; data-ke-size=&quot;size26&quot;&gt;3. 자율 피드백 루프(Self-Feedback Loop)와 BVA 기반 프론트엔드 테스트 아키텍처&lt;/h2&gt;
&lt;p data-end=&quot;216&quot; data-start=&quot;151&quot; data-ke-size=&quot;size16&quot;&gt;AI 에이전트의 코드 생성 속도가 빨라질수록,&lt;br /&gt;그에 비례하여 &lt;b&gt;버그 역시 빠르게 증가하는 문제&lt;/b&gt;가 발생합니다.&lt;/p&gt;
&lt;p data-end=&quot;287&quot; data-start=&quot;218&quot; data-ke-size=&quot;size16&quot;&gt;이때 인간 개발자가 모든 코드를 직접 검토하고 디버깅하게 되면,&lt;br /&gt;결국 새로운 병목(Bottleneck)이 생기게 됩니다.&lt;/p&gt;
&lt;p data-end=&quot;300&quot; data-start=&quot;289&quot; data-ke-size=&quot;size16&quot;&gt;따라서 필요한 것은:&lt;/p&gt;
&lt;p data-end=&quot;387&quot; data-start=&quot;302&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;코드를 작성한 AI가 스스로 테스트하고 수정하는 구조&lt;/b&gt;&lt;br /&gt;  즉, &lt;b&gt;닫힌 루프(Closed-Loop) 기반의 자율 피드백 시스템&lt;/b&gt;입니다&lt;/p&gt;
&lt;hr data-end=&quot;392&quot; data-start=&quot;389&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;421&quot; data-start=&quot;394&quot; data-section-id=&quot;1kk2723&quot; data-ke-size=&quot;size23&quot;&gt;3.1 MSW를 통한 네트워크 의존성 제거&lt;/h3&gt;
&lt;p data-end=&quot;470&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;프론트엔드 테스트를 어렵게 만드는 가장 큰 요인은&lt;br /&gt;백엔드 API와의 의존성입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;505&quot; data-start=&quot;472&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;481&quot; data-start=&quot;472&quot; data-section-id=&quot;n6yozo&quot;&gt;네트워크 지연&lt;/li&gt;
&lt;li data-end=&quot;492&quot; data-start=&quot;482&quot; data-section-id=&quot;19s14xl&quot;&gt;서버 상태 변화&lt;/li&gt;
&lt;li data-end=&quot;505&quot; data-start=&quot;493&quot; data-section-id=&quot;1mq333o&quot;&gt;예측 불가능한 응답&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;554&quot; data-start=&quot;507&quot; data-ke-size=&quot;size16&quot;&gt;이러한 외부 요인 때문에 테스트가 실패하면,&lt;br /&gt;AI는 원인을 제대로 구분하지 못하고&lt;/p&gt;
&lt;p data-end=&quot;583&quot; data-start=&quot;556&quot; data-ke-size=&quot;size16&quot;&gt;  UI 문제인지&lt;br /&gt;  네트워크 문제인지&lt;/p&gt;
&lt;p data-end=&quot;617&quot; data-start=&quot;585&quot; data-ke-size=&quot;size16&quot;&gt;판단하지 못한 채 불필요한 수정 반복에 빠질 수 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;622&quot; data-start=&quot;619&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;674&quot; data-start=&quot;624&quot; data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기 위해 **MSW(Mock Service Worker)**를 사용합니다.&lt;/p&gt;
&lt;p data-end=&quot;681&quot; data-start=&quot;676&quot; data-ke-size=&quot;size16&quot;&gt;MSW는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;716&quot; data-start=&quot;683&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;698&quot; data-start=&quot;683&quot; data-section-id=&quot;xsy0ol&quot;&gt;HTTP 요청을 가로채고&lt;/li&gt;
&lt;li data-end=&quot;716&quot; data-start=&quot;699&quot; data-section-id=&quot;lxwxt5&quot;&gt;항상 동일한 응답을 반환하여&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;752&quot; data-start=&quot;718&quot; data-ke-size=&quot;size16&quot;&gt;  테스트 환경을 &lt;b&gt;완전히 통제 가능한 상태&lt;/b&gt;로 만듭니다&lt;/p&gt;
&lt;p data-end=&quot;759&quot; data-start=&quot;754&quot; data-ke-size=&quot;size16&quot;&gt;그 결과:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;806&quot; data-start=&quot;761&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;776&quot; data-start=&quot;761&quot; data-section-id=&quot;uuzyk6&quot;&gt;백엔드 없이 테스트 가능&lt;/li&gt;
&lt;li data-end=&quot;789&quot; data-start=&quot;777&quot; data-section-id=&quot;1fqck70&quot;&gt;네트워크 영향 제거&lt;/li&gt;
&lt;li data-end=&quot;806&quot; data-start=&quot;790&quot; data-section-id=&quot;frvlfs&quot;&gt;UI 로직만 순수하게 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;844&quot; data-start=&quot;808&quot; data-ke-size=&quot;size16&quot;&gt;  AI는 오직 &lt;b&gt;컴포넌트 동작 자체에 집중&lt;/b&gt;할 수 있습니다&lt;/p&gt;
&lt;hr data-end=&quot;849&quot; data-start=&quot;846&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;883&quot; data-start=&quot;851&quot; data-section-id=&quot;1k14lbs&quot; data-ke-size=&quot;size23&quot;&gt;3.2 스킬/커맨드 + 멘션 기반 자율 테스트 실행&lt;/h3&gt;
&lt;p data-end=&quot;945&quot; data-start=&quot;885&quot; data-ke-size=&quot;size16&quot;&gt;자율 피드백 루프를 안정적으로 운영하려면&lt;br /&gt;테스트 과정 역시 &lt;b&gt;표준화된 실행 단위&lt;/b&gt;로 정의해야 합니다.&lt;/p&gt;
&lt;p data-end=&quot;998&quot; data-start=&quot;947&quot; data-ke-size=&quot;size16&quot;&gt;이를 위해 테스트 흐름을&lt;br /&gt;**스킬(Skill)과 커맨드(Command)**로 구성합니다.&lt;/p&gt;
&lt;p data-end=&quot;1006&quot; data-start=&quot;1000&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1111&quot; data-start=&quot;1008&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1035&quot; data-start=&quot;1008&quot; data-section-id=&quot;1cv1ss2&quot;&gt;analyze-diff &amp;rarr; 변경 코드 식별&lt;/li&gt;
&lt;li data-end=&quot;1062&quot; data-start=&quot;1036&quot; data-section-id=&quot;u9t1p2&quot;&gt;generate-test &amp;rarr; 테스트 생성&lt;/li&gt;
&lt;li data-end=&quot;1084&quot; data-start=&quot;1063&quot; data-section-id=&quot;1snnpw5&quot;&gt;run-test &amp;rarr; 테스트 실행&lt;/li&gt;
&lt;li data-end=&quot;1111&quot; data-start=&quot;1085&quot; data-section-id=&quot;qtz0i1&quot;&gt;fix-failure &amp;rarr; 실패 기반 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1128&quot; data-start=&quot;1113&quot; data-ke-size=&quot;size16&quot;&gt;이 구조를 적용하면 AI는:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1198&quot; data-start=&quot;1130&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1143&quot; data-start=&quot;1130&quot; data-section-id=&quot;rdpqau&quot;&gt;변경 코드 파악&lt;/li&gt;
&lt;li data-end=&quot;1155&quot; data-start=&quot;1144&quot; data-section-id=&quot;1oq5279&quot;&gt;테스트 생성&lt;/li&gt;
&lt;li data-end=&quot;1167&quot; data-start=&quot;1156&quot; data-section-id=&quot;1f63cxx&quot;&gt;테스트 실행&lt;/li&gt;
&lt;li data-end=&quot;1178&quot; data-start=&quot;1168&quot; data-section-id=&quot;tdocim&quot;&gt;실패 확인&lt;/li&gt;
&lt;li data-end=&quot;1189&quot; data-start=&quot;1179&quot; data-section-id=&quot;6ue01n&quot;&gt;코드 수정&lt;/li&gt;
&lt;li data-end=&quot;1198&quot; data-start=&quot;1190&quot; data-section-id=&quot;floqrw&quot;&gt;재검증&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1235&quot; data-start=&quot;1200&quot; data-ke-size=&quot;size16&quot;&gt;  이 사이클을 반복하며 &lt;b&gt;자율적으로 품질을 끌어올립니다&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-end=&quot;1643&quot; data-start=&quot;1613&quot; data-section-id=&quot;dbvwde&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-end=&quot;1643&quot; data-start=&quot;1613&quot; data-section-id=&quot;dbvwde&quot; data-ke-size=&quot;size23&quot;&gt;3.3 BVA / EP 기반 테스트 데이터 강제&lt;/h3&gt;
&lt;p data-end=&quot;1685&quot; data-start=&quot;1645&quot; data-ke-size=&quot;size16&quot;&gt;테스트의 신뢰성을 확보하기 위해&lt;br /&gt;AI의 임의 데이터 생성을 제한하고,&lt;/p&gt;
&lt;p data-end=&quot;1705&quot; data-start=&quot;1687&quot; data-ke-size=&quot;size16&quot;&gt;다음 두 가지 기법을 강제합니다:&lt;/p&gt;
&lt;hr data-end=&quot;1710&quot; data-start=&quot;1707&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1759&quot; data-start=&quot;1712&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동치 분할 (EP)&lt;/b&gt;&lt;br /&gt;&amp;rarr; 정상 / 비정상 / 오류 상태를 대표하는 값만 사용&lt;/p&gt;
&lt;p data-end=&quot;1809&quot; data-start=&quot;1761&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;경계값 분석 (BVA)&lt;/b&gt;&lt;br /&gt;&amp;rarr; 오류 발생 가능성이 가장 높은 경계값 집중 테스트&lt;/p&gt;
&lt;hr data-end=&quot;1814&quot; data-start=&quot;1811&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1822&quot; data-start=&quot;1816&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;p data-end=&quot;1848&quot; data-start=&quot;1824&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;최소 2글자 입력 시 검색&amp;rdquo; 조건이 있다면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1877&quot; data-start=&quot;1850&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1865&quot; data-start=&quot;1850&quot; data-section-id=&quot;1x87num&quot;&gt;1글자 (min - 1)&lt;/li&gt;
&lt;li data-end=&quot;1877&quot; data-start=&quot;1866&quot; data-section-id=&quot;1p4rgwx&quot;&gt;2글자 (min)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1898&quot; data-start=&quot;1879&quot; data-ke-size=&quot;size16&quot;&gt;이 두 케이스를 반드시 검증합니다.&lt;/p&gt;
&lt;hr data-end=&quot;1903&quot; data-start=&quot;1900&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1908&quot; data-start=&quot;1905&quot; data-ke-size=&quot;size16&quot;&gt;만약:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1975&quot; data-start=&quot;1910&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1941&quot; data-start=&quot;1910&quot; data-section-id=&quot;4fjw7i&quot;&gt;1글자에서 API 호출이 발생하면 &amp;rarr; 테스트 실패&lt;/li&gt;
&lt;li data-end=&quot;1959&quot; data-start=&quot;1942&quot; data-section-id=&quot;1p3w8h9&quot;&gt;AI가 실패 로그를 분석&lt;/li&gt;
&lt;li data-end=&quot;1975&quot; data-start=&quot;1960&quot; data-section-id=&quot;r6avhc&quot;&gt;방어 코드 자동 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;if (input.length &amp;lt; 2) return;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;
&lt;p data-end=&quot;2064&quot; data-start=&quot;2028&quot; data-ke-size=&quot;size16&quot;&gt;  이 과정을 통해 &lt;b&gt;AI가 스스로 버그를 수정&lt;/b&gt;하게 됩니다&lt;/p&gt;
&lt;hr data-end=&quot;2069&quot; data-start=&quot;2066&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2103&quot; data-start=&quot;2071&quot; data-section-id=&quot;1j4seuv&quot; data-ke-size=&quot;size23&quot;&gt;3.4 구현 디테일 배제, 관찰 가능한 결과만 검증&lt;/h3&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2105&quot; data-ke-size=&quot;size16&quot;&gt;중요한 원칙은 다음과 같습니다:&lt;/p&gt;
&lt;blockquote data-end=&quot;2157&quot; data-start=&quot;2124&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2157&quot; data-start=&quot;2126&quot; data-ke-size=&quot;size16&quot;&gt;내부 구현이 아닌, 외부에서 관찰 가능한 결과만 검증한다&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;2181&quot; data-start=&quot;2159&quot; data-ke-size=&quot;size16&quot;&gt;즉, 다음은 테스트 대상에서 제외됩니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2217&quot; data-start=&quot;2183&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2192&quot; data-start=&quot;2183&quot; data-section-id=&quot;12mqmib&quot;&gt;내부 상태 값&lt;/li&gt;
&lt;li data-end=&quot;2205&quot; data-start=&quot;2193&quot; data-section-id=&quot;mfbpyn&quot;&gt;hook 호출 순서&lt;/li&gt;
&lt;li data-end=&quot;2217&quot; data-start=&quot;2206&quot; data-section-id=&quot;1lqdiyh&quot;&gt;구현 로직 디테일&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2222&quot; data-start=&quot;2219&quot; data-ke-size=&quot;size16&quot;&gt;대신:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2266&quot; data-start=&quot;2224&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2233&quot; data-start=&quot;2224&quot; data-section-id=&quot;1nwhasx&quot;&gt;렌더링된 UI&lt;/li&gt;
&lt;li data-end=&quot;2246&quot; data-start=&quot;2234&quot; data-section-id=&quot;17s6tzt&quot;&gt;사용자 이벤트 결과&lt;/li&gt;
&lt;li data-end=&quot;2266&quot; data-start=&quot;2247&quot; data-section-id=&quot;w6popw&quot;&gt;접근성 속성 (aria-* 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2292&quot; data-start=&quot;2268&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;사용자 관점의 동작만 검증&lt;/b&gt;합니다&lt;/p&gt;
&lt;p data-end=&quot;2292&quot; data-start=&quot;2268&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2300&quot; data-start=&quot;2294&quot; data-ke-size=&quot;size16&quot;&gt;이 방식은:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2335&quot; data-start=&quot;2302&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2319&quot; data-start=&quot;2302&quot; data-section-id=&quot;1lzxef9&quot;&gt;리팩토링에 강한 테스트 유지&lt;/li&gt;
&lt;li data-end=&quot;2335&quot; data-start=&quot;2320&quot; data-section-id=&quot;1obqvwx&quot;&gt;깨지기 쉬운 테스트 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2345&quot; data-start=&quot;2337&quot; data-ke-size=&quot;size16&quot;&gt;로 이어집니다.&lt;/p&gt;
&lt;hr data-end=&quot;2350&quot; data-start=&quot;2347&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2375&quot; data-start=&quot;2352&quot; data-section-id=&quot;etw60b&quot; data-ke-size=&quot;size23&quot;&gt;3.5 자동화된 테스트 리포트 생성&lt;/h3&gt;
&lt;p data-end=&quot;2391&quot; data-start=&quot;2377&quot; data-ke-size=&quot;size16&quot;&gt;테스트가 완료되면 AI는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2420&quot; data-start=&quot;2393&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2399&quot; data-start=&quot;2393&quot; data-section-id=&quot;bq7q90&quot;&gt;커버리지&lt;/li&gt;
&lt;li data-end=&quot;2410&quot; data-start=&quot;2400&quot; data-section-id=&quot;brmoxx&quot;&gt;검증된 시나리오&lt;/li&gt;
&lt;li data-end=&quot;2420&quot; data-start=&quot;2411&quot; data-section-id=&quot;19fjyjh&quot;&gt;누락된 케이스&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2460&quot; data-start=&quot;2422&quot; data-ke-size=&quot;size16&quot;&gt;를 자동으로 정리하여&lt;br /&gt;Markdown 형태의 리포트를 생성합니다.&lt;/p&gt;
&lt;p data-end=&quot;2474&quot; data-start=&quot;2462&quot; data-ke-size=&quot;size16&quot;&gt;이 리포트는 개발자가:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2517&quot; data-start=&quot;2476&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2494&quot; data-start=&quot;2476&quot; data-section-id=&quot;1grxzw4&quot;&gt;내부 코드를 깊게 보지 않고도&lt;/li&gt;
&lt;li data-end=&quot;2517&quot; data-start=&quot;2495&quot; data-section-id=&quot;16lxljs&quot;&gt;테스트 품질을 빠르게 판단할 수 있는&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2542&quot; data-start=&quot;2519&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;검증 요약 문서 역할&lt;/b&gt;을 합니다&lt;/p&gt;
&lt;hr data-end=&quot;2547&quot; data-start=&quot;2544&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2555&quot; data-start=&quot;2549&quot; data-section-id=&quot;1hrqjbz&quot; data-ke-size=&quot;size23&quot;&gt;정리&lt;/h3&gt;
&lt;p data-end=&quot;2583&quot; data-start=&quot;2557&quot; data-ke-size=&quot;size16&quot;&gt;이 구조를 통해 다음과 같은 흐름이 완성됩니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;2642&quot; data-start=&quot;2585&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;2595&quot; data-start=&quot;2585&quot; data-section-id=&quot;73e8xq&quot;&gt;코드 생성&lt;/li&gt;
&lt;li data-end=&quot;2607&quot; data-start=&quot;2596&quot; data-section-id=&quot;1oq5279&quot;&gt;테스트 생성&lt;/li&gt;
&lt;li data-end=&quot;2619&quot; data-start=&quot;2608&quot; data-section-id=&quot;1f63cxx&quot;&gt;테스트 실행&lt;/li&gt;
&lt;li data-end=&quot;2633&quot; data-start=&quot;2620&quot; data-section-id=&quot;127ksdy&quot;&gt;실패 기반 수정&lt;/li&gt;
&lt;li data-end=&quot;2642&quot; data-start=&quot;2634&quot; data-section-id=&quot;10ef48f&quot;&gt;재검증&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;2664&quot; data-start=&quot;2644&quot; data-ke-size=&quot;size16&quot;&gt;  완전한 &lt;b&gt;자율 피드백 루프&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2669&quot; data-start=&quot;2666&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;2679&quot; data-start=&quot;2671&quot; data-ke-size=&quot;size16&quot;&gt;결국 개발자는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2733&quot; data-start=&quot;2681&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2700&quot; data-start=&quot;2681&quot; data-section-id=&quot;tozr3v&quot;&gt;버그를 직접 찾는 역할이 아니라&lt;/li&gt;
&lt;li data-end=&quot;2733&quot; data-start=&quot;2701&quot; data-section-id=&quot;1o6v1v0&quot;&gt;검증된 결과를 확인하고 승인하는 역할로 이동하게 됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2763&quot; data-start=&quot;2740&quot; data-ke-size=&quot;size16&quot;&gt;핵심은 다음 한 줄로 정리할 수 있습니다:&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;2815&quot; data-start=&quot;2765&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;&amp;ldquo;코드를 만드는 것&amp;rdquo;이 아니라&lt;br /&gt;&amp;ldquo;코드가 스스로 검증되도록 만드는 것&amp;rdquo;입니다&lt;/b&gt;&lt;/p&gt;
&lt;/div&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;
&lt;h2 data-end=&quot;86&quot; data-start=&quot;60&quot; data-section-id=&quot;73aeeo&quot; data-ke-size=&quot;size26&quot;&gt;5. 결론: 시스템 오케스트레이터로의 진화&lt;/h2&gt;
&lt;p data-end=&quot;223&quot; data-start=&quot;88&quot; data-ke-size=&quot;size16&quot;&gt;이직 직후 단기간 내 수백 개의 커밋을 생성하고 이를 실제 운영 환경에 반영할 수 있었던 성과는, 단순히 AI 도구를 잘 활용한 결과가 아닙니다. 이는 &lt;b&gt;소프트웨어 개발 방식 자체가 구조적으로 변화하고 있음을 보여주는 사례&lt;/b&gt;에 가깝습니다.&lt;/p&gt;
&lt;p data-end=&quot;223&quot; data-start=&quot;88&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;225&quot; data-ke-size=&quot;size16&quot;&gt;Git Worktree와 Tmux의 결합은 물리적인 작업 공간의 제약을 제거하고, 여러 AI 에이전트를 동시에 운영할 수 있는 병렬 확장성을 확보하게 해주었습니다. Context7 MCP와 Cursor MDC를 기반으로 한 지식 외주화 전략은 낯선 코드베이스와 방대한 문서를 학습해야 하는 온보딩 비용을 사실상 제거했습니다. 여기에 MSW와 BVA 기반 테스트 전략으로 구성된 자율 피드백 루프는, AI가 생성한 코드가 실제 프로덕션 환경에서도 신뢰할 수 있는 수준의 품질을 유지하도록 보장하는 핵심 장치로 작동합니다.&lt;/p&gt;
&lt;p data-end=&quot;559&quot; data-start=&quot;517&quot; data-ke-size=&quot;size16&quot;&gt;이 모든 요소가 결합되면서 개발자의 역할 역시 근본적으로 변화하고 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;561&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;561&quot; data-ke-size=&quot;size16&quot;&gt;이제 개발자는 더 이상 코드를 직접 작성하는 데 집중하는 존재가 아니라,&lt;br /&gt;어떤 시스템을 만들 것인지 정의하고,&lt;br /&gt;AI 에이전트들이 충돌 없이 작업할 수 있는 환경을 설계하며,&lt;br /&gt;테스트와 검증 구조를 통해 결과물의 품질을 통제하는 역할을 수행합니다.&lt;/p&gt;
&lt;p data-end=&quot;860&quot; data-start=&quot;705&quot; data-ke-size=&quot;size16&quot;&gt;즉, 개발자는 &amp;lsquo;어떻게 구현할 것인가(HOW)&amp;rsquo;에서 벗어나&lt;br /&gt;&amp;lsquo;무엇을 만들어야 하는가(WHAT)&amp;rsquo;에 집중하는 존재로 이동하고 있으며,그 중심에는 여러 AI를 조율하는 **시스템 오케스트레이터(System Orchestrator)**라는 새로운 역할이 자리 잡고 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;860&quot; data-start=&quot;705&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;971&quot; data-start=&quot;862&quot; data-ke-size=&quot;size16&quot;&gt;결국 압도적인 생산성은 더 빠르게 코드를 작성하는 능력에서 나오지 않습니다.&lt;br /&gt;그보다는, &lt;b&gt;작업을 얼마나 효과적으로 위임하고, 그 결과를 얼마나 정교하게 검증할 수 있는지&lt;/b&gt;에 달려 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1046&quot; data-start=&quot;973&quot; data-ke-size=&quot;size16&quot;&gt;앞으로의 개발 경쟁력은 개인의 숙련도보다&lt;br /&gt;이러한 &lt;b&gt;위임 구조와 피드백 루프를 얼마나 잘 설계하느냐&lt;/b&gt;에 의해 결정될 것입니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Front-end/work</category>
      <author>lodado</author>
      <guid isPermaLink="true">https://lodado.tistory.com/114</guid>
      <comments>https://lodado.tistory.com/114#entry114comment</comments>
      <pubDate>Sat, 28 Mar 2026 16:45:42 +0900</pubDate>
    </item>
    <item>
      <title>경계값 분석으로 테스트 코드짜기</title>
      <link>https://lodado.tistory.com/113</link>
      <description>&lt;div&gt;
&lt;div id=&quot;model-response-message-contentr_56a4aa914bcb11e0&quot; style=&quot;color: #1f1f1f;&quot;&gt;
&lt;p data-path-to-node=&quot;1&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size26&quot;&gt;  왜 버그는 항상 '끝'에서 터질까? : 경계값 분석(BVA) 깊게 파보기&lt;/h2&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;테스트 케이스를 짤 때 모든 경우의 수를 다 검사하는 건 불가능에 가깝습니다. 그렇다면 가장 효율적으로 버그를 잡아낼 수 있는 지점&quot;은 어디일까요? 경험 많은 테스터들은 입을 모아 말합니다. 바로 '경계(Boundary)'라고요.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;1. 경계값 분석(BVA)이란?&lt;/h3&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;경계값 분석은 동등 분할(Equivalence Partitioning)의 연장선에 있는 기법입니다. 데이터나 상태의 범위가 있을 때, 그 범위의 &lt;b data-index-in-node=&quot;85&quot; data-path-to-node=&quot;6&quot;&gt;최솟값과 최댓값 근처&lt;/b&gt;에서 결함이 발생할 확률이 높다는 가설을 바탕으로 테스트 케이스를 설계하는 방법이죠.&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;우리가 흔히 겪는 &lt;b data-index-in-node=&quot;10&quot; data-path-to-node=&quot;7&quot;&gt;'Off-by-one error'&lt;/b&gt;(부등호를 &amp;gt;로 쓸 걸 &amp;gt;=로 써서 생기는 1 차이의 버그)를 잡아내는 데 특화되어 있습니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;2. 왜 '가운데'가 아니라 '모서리'인가?&lt;/h3&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;프로그램의 로직은 보통 조건문(if, switch)으로 나뉩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;A 상태일 때는 이 버튼을 보여줘&quot;&lt;/li&gt;
&lt;li&gt;&quot;B 범위를 넘어가면 이 기능을 막아&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;여기서 개발자가 실수하기 가장 좋은 지점은 &quot;A에서 B로 넘어가는 바로 그 찰나&quot;입니다. 사용자 입장에서 시스템이 요동치는 구간도 바로 이 경계면이죠. 그래서 테스트도 이 '전환점'에 화력을 집중해야 합니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;3. BVA의 핵심: 2-Point vs 3-Point&lt;/h3&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;경계를 어떻게 정의하느냐에 따라 크게 두 가지 방식으로 나뉩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0,0&quot;&gt;2-Point BVA&lt;/b&gt;: 경계값(Boundary)과 그 경계 바로 밖의 값(Off-point)만 테스트합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: 1~100 사이가 유효 범위라면? 1, 100(경계) + 0, 101(실패 케이스)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0&quot;&gt;3-Point BVA&lt;/b&gt;: 경계값, 그리고 그 값의 바로 앞/뒤를 모두 테스트합니다. 조금 더 꼼꼼하게 검증할 때 사용하죠.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: 0, 1, 2 (최솟값 근처) + 99, 100, 101 (최대값 근처)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;4. 숫자뿐만 아니라 '상태'에도 적용하기&lt;/h3&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;많은 분이 BVA를 '숫자 범위'에만 한정 짓지만, 사실 &lt;b data-index-in-node=&quot;32&quot; data-path-to-node=&quot;16&quot;&gt;상태 머신(State Machine)&lt;/b&gt; 구조에서도 강력한 힘을 발휘합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;계층적 구조&lt;/b&gt;: 등급이 낮음 &amp;rarr; 중간 &amp;rarr; 높음 순으로 있다면, '가장 낮은 등급'과 '가장 높은 등급'이 경계가 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;시간적 순서&lt;/b&gt;: 시작 직후, 종료 직전 같은 시점도 경계값입니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,2,0&quot;&gt;데이터 구조&lt;/b&gt;: 리스트의 첫 번째 아이템, 마지막 아이템, 혹은 빈 리스트 자체가 경계가 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;5. BVA가 주는 진짜 가치: 효율성&lt;/h3&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;BVA의 목표는 &quot;최소한의 테스트로 최대한의 커버리지를 확보하는 것&quot;입니다. 가운데 있는 평범한 데이터(무작위 값) 백 날 테스트해봐야, 경계에서 터지는 버그 하나를 못 잡으면 의미가 없거든요. '중간'은 대표성 있는 샘플 하나면 충분합니다. 에너지는 '끝단'에 쏟으세요.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;20&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size23&quot;&gt;리액트 코드로 보는 경계값 로직&lt;/h3&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이 컴포넌트는 글자 수에 따라 텍스트 색상이 바뀝니다. (정상: 검정, 경고: 주황, 초과: 빨강)&lt;/p&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773669789002&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from &quot;react&quot;;

const MAX_LENGTH = 10; // 우리가 설정한 경계값!

export default function CharCounter() {
  const [text, setText] = useState(&quot;&quot;);
  const length = text.length;

  // 1. 경계값 기반 상태 로직
  const getStatusColor = () =&amp;gt; {
    if (length === 0) return &quot;text-gray-400&quot;;       // 최소값 (Empty)
    if (length &amp;lt; MAX_LENGTH) return &quot;text-black&quot;;   // 정상 범위
    if (length === MAX_LENGTH) return &quot;text-orange-500&quot;; // 딱 경계점 (Warning)
    return &quot;text-red-500&quot;;                          // 경계 초과 (Error)
  };

  return (
    &amp;lt;div className=&quot;p-4&quot;&amp;gt;
      &amp;lt;textarea
        className=&quot;border p-2&quot;
        value={text}
        onChange={(e) =&amp;gt; setText(e.target.value)}
        placeholder=&quot;10자 이내로 입력하세요.&quot;
      /&amp;gt;
      
      {/* 2. UI에 나타나는 경계점 피드백 */}
      &amp;lt;p className={`font-bold ${getStatusColor()}`}&amp;gt;
        현재 글자 수: {length} / {MAX_LENGTH}
      &amp;lt;/p&amp;gt;

      {length &amp;gt; MAX_LENGTH &amp;amp;&amp;amp; (
        &amp;lt;span className=&quot;text-red-500 text-sm&quot;&amp;gt;최대 글자 수를 초과했습니다!&amp;lt;/span&amp;gt;
      )}
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;여기서 '경계값 분석'으로 뽑아낼 테스트 포인트&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;개발자는 코드를 짤 때 length &amp;lt; MAX_LENGTH인지, length &amp;lt;= MAX_LENGTH인지 헷갈리기 쉽습니다. 그래서 테스터(혹은 테스트 코드)는 다음 &lt;b data-index-in-node=&quot;93&quot; data-path-to-node=&quot;8&quot;&gt;5가지 지점&lt;/b&gt;을 찔러봐야 합니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 126px;&quot; border=&quot;1&quot; data-path-to-node=&quot;9&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;테스트 포인트&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;값 (Length)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;예상 결과&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;이유&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0,0&quot;&gt;최솟값&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,1,1,0&quot;&gt;0&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,1,2,0&quot;&gt;회색 (Gray)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,1,3,0&quot;&gt;데이터가 없는 시작점&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,0,0&quot;&gt;정상 하한&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,2,1,0&quot;&gt;1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,2,2,0&quot;&gt;검정 (Black)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,2,3,0&quot;&gt;데이터 입력이 시작되는 지점&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,3,0,0&quot;&gt;경계 직전&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,3,1,0&quot;&gt;9&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,3,2,0&quot;&gt;검정 (Black)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,3,3,0&quot;&gt;정상 범위의 마지막 단계&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,4,0,0&quot;&gt;경계값 (Target)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,4,1,0&quot;&gt;10&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,4,2,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,4,2,0&quot;&gt;주황 (Orange)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,4,3,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,4,3,0&quot;&gt;가장 중요한 전환점 (Warning)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,5,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,5,0,0&quot;&gt;경계 초과&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,5,1,0&quot;&gt;11&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,5,2,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,5,2,0&quot;&gt;빨강 (Red)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;span data-path-to-node=&quot;9,5,3,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,5,3,0&quot;&gt;에러가 발생해야 하는 지점&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21&quot;&gt;결론적으로,&lt;/b&gt; 훌륭한 E2E 테스트 설계는 모든 기능을 확인하는 것이 아니라, &lt;b data-index-in-node=&quot;43&quot; data-path-to-node=&quot;21&quot;&gt;어디가 무너지기 쉬운 경계인지를 정확히 짚어내는 안목&lt;/b&gt;에서 시작됩니다. 여러분의 코드에서 '모서리'는 어디인가요?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/work</category>
      <author>lodado</author>
      <guid isPermaLink="true">https://lodado.tistory.com/113</guid>
      <comments>https://lodado.tistory.com/113#entry113comment</comments>
      <pubDate>Mon, 16 Mar 2026 23:06:26 +0900</pubDate>
    </item>
    <item>
      <title>MCP를 통한 문서화 기반(Document-Driven Development) 개발 시스템 만들기</title>
      <link>https://lodado.tistory.com/111</link>
      <description>&lt;p data-end=&quot;764&quot; data-start=&quot;720&quot; data-ke-size=&quot;size16&quot;&gt;AI와 mcp를 써보고, 느낀 점을 적어보았습니다.&lt;/p&gt;
&lt;p data-end=&quot;764&quot; data-start=&quot;720&quot; data-ke-size=&quot;size16&quot;&gt;앞으로는 잘 정리된 히스토리(문서)가 개발에서 가장 중요한 자산이지 않을까 생각됩니다.&lt;/p&gt;
&lt;h2 data-end=&quot;764&quot; data-start=&quot;720&quot; data-ke-size=&quot;size26&quot;&gt;문서화 기반 개발(Document-Driven Development)&lt;/h2&gt;
&lt;p data-end=&quot;1000&quot; data-start=&quot;766&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문서화 기반 개발&lt;/b&gt;이란 말 그대로 &lt;b&gt;문서를 중심&lt;/b&gt;으로 요구사항 도출, 디자인, 개발, 테스트를 하나의 피드백 루프로 통합하는 접근 방식입니다. 기존의 코드 중심 개발(Code-Driven Development)과 달리 개발의 진입점(entry point)이 문서입니다. 팀은 문서를 작성하며 시스템의 동작을 정의하고, 이 문서가 곧바로 설계 명세서가 되며, 나아가 테스트의 기준선 역할까지 수행합니다.&lt;/p&gt;
&lt;p data-end=&quot;1000&quot; data-start=&quot;766&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1000&quot; data-start=&quot;766&quot; data-ke-size=&quot;size16&quot;&gt;문서가 곧 팀의 &lt;b&gt;공통 언어&lt;/b&gt;이자 설계서이고, 또 코드에 대한 &lt;b&gt;검증 기준&lt;/b&gt;이 되는 셈입니다. 잘 정립된 문서는 개발자, 디자이너, 기획자 모두가 바라보는 하나의 진실된 소스(source of truth)로 기능하며, 문서에 쓰인 대로 시스템이 동작하도록 코드를 구현하고 테스트까지 진행하게 됩니다. 이런 사이클에서는 문서와 코드의 괴리가 줄어들고, 문서만 읽어도 현재 시스템이 무엇을 하는지 이해할 수 있게 됩니다.&lt;/p&gt;
&lt;h2 data-end=&quot;1255&quot; data-start=&quot;1241&quot; data-ke-size=&quot;size26&quot;&gt;문서화가 어려운 이유&lt;/h2&gt;
&lt;p data-end=&quot;1326&quot; data-start=&quot;1257&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 왜 현실에서는 문서화 기반 개발이 잘 이루어지지 않을까요? 문서화가 어려운 대표적인 이유 몇 가지를 짚어보겠습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;2105&quot; data-start=&quot;1328&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1512&quot; data-start=&quot;1328&quot;&gt;&lt;b&gt;문서도 유지보수가 필요한 &amp;ldquo;소프트웨어&amp;rdquo;다&lt;/b&gt; &amp;ndash; 코드에 리팩터링이 필요하듯 문서에도 지속적인 업데이트와 구조 개선이 필요합니다. 하지만 많은 조직에서는 코드 리팩터링에는 공을 들이면서도 &lt;b&gt;문서 리팩터링에는 거의 리소스를 할애하지 않습니다&lt;/b&gt;. 시간이 지날수록 코드와 문서의 불일치가 커지고, 문서는 신뢰를 잃게 됩니다.&lt;/li&gt;
&lt;li data-end=&quot;1724&quot; data-start=&quot;1514&quot;&gt;&lt;b&gt;문서는 이타적인 행위다&lt;/b&gt; &amp;ndash; 문서 작성은 당장 개인의 성과로 드러나기보다는 팀 전체를 위한 &lt;b&gt;공유 행위&lt;/b&gt;입니다. 업무에 쫓기는 환경에서는 개발자가 기능 구현이나 버그 수정처럼 눈앞의 일에 집중하게 되고, 문서 작성은 우선순위에서 밀려나기 쉽습니다. 특히 빠른 결과를 요구하는 비즈니스 환경에서는 문서가 쉽게 &lt;b&gt;뒷전&lt;/b&gt;으로 밀려나 결국 내용이 오래되기 쉽습니다.&lt;/li&gt;
&lt;li data-end=&quot;2105&quot; data-start=&quot;1726&quot;&gt;&lt;b&gt;문서보다 비즈니스가 더 빠르다&lt;/b&gt; &amp;ndash; 요즘 같은 &lt;b&gt;빠른 실험과 MVP 중심 개발&lt;/b&gt; 문화에서는 문서화 속도가 비즈니스 변화를 따라가기 어렵습니다. 제품은 수시로 피벗하고 기능은 계속 바뀌는데, 그때마다 문서를 모두 수정하기란 현실적으로 버겁습니다. 결국 문서는 실제 제품보다 항상 한 발 뒤처지게 되죠.&lt;br /&gt;&lt;br /&gt;이러한 문제를 해결하려면, 사람의 수동적인 노력만으로는 한계가 있고 자동화된 문서화 시스템이 필수적입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-end=&quot;2132&quot; data-start=&quot;2107&quot; data-ke-size=&quot;size26&quot;&gt;MCP를 통한 &lt;b&gt;문서 자동화 시스템&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-end=&quot;2524&quot; data-start=&quot;2134&quot; data-ke-size=&quot;size16&quot;&gt;이 자동화된 문서화 시스템의 한 예로 떠오르는 것이 바로 MCP(Multi-Context Protocol)입니다. MCP는 Anthropic이 2024년에 제안한 새로운 표준으로, 요약하면 &lt;b&gt;다양한 소프트웨어 툴과 AI를 연결해주는 프로토콜&lt;/b&gt;입니다&lt;/p&gt;
&lt;p data-end=&quot;2524&quot; data-start=&quot;2134&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2524&quot; data-start=&quot;2134&quot; data-ke-size=&quot;size16&quot;&gt;Notion, Jira, Google Sheets, Figma처럼 서로 다른 플랫폼들의 문서를 &lt;b&gt;AI 에이전트&lt;/b&gt;가 읽고 요약하거나 서로 연결할 수 있게 해주는 통합 규약이라고 볼 수 있습니다. 한마디로 여러 곳에 흩어진 문서와 데이터를 한곳에 모아 활용할 수 있게 만드는 &lt;b&gt;문맥 통합&lt;/b&gt; 도구입니다.&lt;/p&gt;
&lt;p data-end=&quot;2524&quot; data-start=&quot;2134&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1761831274692&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Notion &amp;rarr; MCP (Notion MCP Server)
  &amp;darr; 
Jira &amp;rarr; MCP (Jira MCP Server)
   &amp;darr; 
Figma &amp;rarr; MCP (Figma MCP Server)
   &amp;darr; 
cursor Agent&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3144&quot; data-start=&quot;2673&quot; data-ke-size=&quot;size16&quot;&gt;위의 흐름은 MCP를 활용한 문서 자동화의 단순 예시입니다.&lt;/p&gt;
&lt;p data-end=&quot;3144&quot; data-start=&quot;2673&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3144&quot; data-start=&quot;2673&quot; data-ke-size=&quot;size16&quot;&gt;각각의 도구(Figma, Notion, Jira 등)가 &lt;b&gt;자신만의 MCP 서버&lt;/b&gt;로 열려 있다고 가정하면,&lt;/p&gt;
&lt;p data-end=&quot;3144&quot; data-start=&quot;2673&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3144&quot; data-start=&quot;2673&quot; data-ke-size=&quot;size16&quot;&gt;AI 에이전트나 통합 스크립트가 이들을 차례차례 호출하여 &lt;b&gt;요구사항 &amp;rarr; 티켓 &amp;rarr; 코드 -&amp;gt; 테스트 코드&lt;/b&gt;를 자동으로 엮어낼 수 있습니다. 곧 요구사항 문서가 디자인과 코드 생성으로 이어지고, 작업 완료 시 Jira 티켓이나 노션 페이지의 상태가 자동 갱신되는 등 &lt;b&gt;문서&amp;rarr;개발&amp;rarr;피드백의 루프가 자동화&lt;/b&gt;될 수 있음을 보여줍니다.&lt;/p&gt;
&lt;p data-end=&quot;3144&quot; data-start=&quot;2673&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;3679&quot; data-start=&quot;3647&quot; data-ke-size=&quot;size26&quot;&gt;문서 &amp;rarr; 디자인 &amp;rarr; 개발 &amp;rarr; 테스트 &amp;rarr; 피드백 사이클&lt;/h2&gt;
&lt;p data-end=&quot;3819&quot; data-start=&quot;3681&quot; data-ke-size=&quot;size16&quot;&gt;앞서 언급한 자동화 루프를 조금 더 구체적으로 살펴보겠습니다. &lt;b&gt;문서화 기반 개발 사이클&lt;/b&gt;에서는 문서 작성부터 디자인 시안, 코드 구현, 테스트, 그리고 다시 문서 갱신까지가 하나의 흐름으로 이어집니다. 이를 단계별로 나타내면 다음과 같습니다&lt;/p&gt;
&lt;p data-end=&quot;3819&quot; data-start=&quot;3681&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;3132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AmZxm/dJMcafrlr86/J3qHmQY3IZTzLZnstifnVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AmZxm/dJMcafrlr86/J3qHmQY3IZTzLZnstifnVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AmZxm/dJMcafrlr86/J3qHmQY3IZTzLZnstifnVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAmZxm%2FdJMcafrlr86%2FJ3qHmQY3IZTzLZnstifnVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;395&quot; height=&quot;894&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;3132&quot;/&gt;&lt;/span&gt;&lt;/figure&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-end=&quot;4528&quot; data-start=&quot;4018&quot; data-ke-size=&quot;size16&quot;&gt;요구사항 문서가 변경되면, 그 내용이 Figma에 반영되고, 디자인이 확정되면 코드 저장소에 해당 컴포넌트나 코드 스켈레톤이 생성됩니다.&lt;/p&gt;
&lt;p data-end=&quot;4528&quot; data-start=&quot;4018&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4528&quot; data-start=&quot;4018&quot; data-ke-size=&quot;size16&quot;&gt;개발자가 그 코드를 구현하면 CI 상에서 테스트 코드가 돌아가고, 여기에는 MSW(Mock Service Worker)로 구현한 가짜 API 서버까지 포함하여 통합 테스트가 실행됩니다. 모든 테스트가 통과하면 그 결과가 다시 노션 문서나 Jira 티켓에 자동으로 댓글로 남는다든지 상태를 &amp;ldquo;완료&amp;rdquo;로 변경한다든지 하는 식으로 &lt;b&gt;문서와 티켓이 최신화&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;p data-end=&quot;4528&quot; data-start=&quot;4018&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4528&quot; data-start=&quot;4018&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 함으로써 문서의 변경 &amp;rarr; 코드 변경 &amp;rarr; 테스트 &amp;rarr; 문서 갱신의 &lt;b&gt;순환 고리&lt;/b&gt;가 자동으로 돌아가게 됩니다. 결국 문서가 변경되면 코드와 테스트 결과로 증명되고, 테스트가 실패하면 문서나 코드 중 어딘가 잘못된 부분을 알려주며, 코드 변경도 문서에 자동 기록되는 &lt;b&gt;생태계&lt;/b&gt;가 만들어지는 것입니다.&lt;/p&gt;
&lt;p data-end=&quot;4528&quot; data-start=&quot;4018&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4715&quot; data-start=&quot;4530&quot; data-ke-size=&quot;size16&quot;&gt;이 순환 구조의 핵심은, 문서와 코드, 테스트가 &lt;b&gt;동등한 1급 시민&lt;/b&gt;으로 취급된다는 점입니다. 어느 하나라도 변경되면 나머지 둘이 이를 검증하고 보완해주는 삼각형 구조라고 볼 수 있습니다. 이러한 체계에서는 문서도 항상 최신의 기능을 반영하게 되고, 팀원 누구든 문서를 보면 현재 시스템의 동작과 일치하는 내용을 접하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;4731&quot; data-start=&quot;4717&quot; data-ke-size=&quot;size26&quot;&gt;테스트 코드도 문서다&lt;/h2&gt;
&lt;p data-end=&quot;4880&quot; data-start=&quot;4733&quot; data-ke-size=&quot;size16&quot;&gt;테스트 코드는 개발자가 기대한 시스템의 동작을 코드로 서술한 것으로, 일종의 &amp;ldquo;실행 가능한 문서&amp;rdquo;입니다. 예를 들어 사용자의 로그인 후 동작을 다음과 같이 테스트 코드로 명세할 수 있습니다. 또한, 테스트 코드는 개발자가 기대한 시스템의 동작을 코드로 서술한 문서이며 AI로 만든 산출물에게 바로 강력한 피드백을 줄 수 있는 방법입니다.&amp;nbsp; &amp;nbsp;&lt;br /&gt;즉, 테스트는 &amp;ldquo;읽히는 문서&amp;rdquo;이면서 동시에 &amp;ldquo;실행 가능한 명세(Executable Specification)&amp;rdquo;입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1761831527480&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 테스트 코드도 문서다.
test(&quot;사용자는 로그인 후 대시보드로 이동해야 한다&quot;, async () =&amp;gt; {
  const response = await login(user);
  expect(response.redirect).toBe(&quot;/dashboard&quot;);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5330&quot; data-start=&quot;5054&quot; data-ke-size=&quot;size16&quot;&gt;위 테스트는 자연어 문장(테스트 설명)과 코드 구현이 결합되어 &lt;b&gt;시스템의 요구사항을 스스로 검증&lt;/b&gt;합니다. 테스트 설명 부분을 보면 마치 사양서의 한 문장처럼 &amp;ldquo;사용자는 로그인 후 대시보드로 이동해야 한다&amp;rdquo;라고 적혀 있습니다. 이 문장은 해당 기능의 요구사항을 나타내는 문서 역할을 하고, 아래의 코드 구현부는 실제 로그인 함수 login(user)의 반환값(response.redirect)이 기대한 대로 &amp;ldquo;/dashboard&amp;rdquo;인지 확인함으로써 그 문서의 내용을 &lt;b&gt;검증&lt;/b&gt;합니다.&lt;/p&gt;
&lt;blockquote data-end=&quot;5733&quot; data-start=&quot;5332&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;5733&quot; data-start=&quot;5334&quot; data-ke-size=&quot;size16&quot;&gt;문서가 &amp;ldquo;무엇을 해야 하는지&amp;rdquo; 설명한다면, 테스트는 &amp;ldquo;정말 그렇게 되는지&amp;rdquo;를 증명합니다&lt;br /&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;h2 data-end=&quot;5762&quot; data-start=&quot;5735&quot; data-ke-size=&quot;size26&quot;&gt;  MSW를 통한 통합 테스트 기반 피드백&lt;/h2&gt;
&lt;p data-end=&quot;6159&quot; data-start=&quot;5764&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 앞서 예로 든 테스트 코드에서 실제 &lt;b&gt;API 호출&lt;/b&gt;이나 &lt;b&gt;외부 서비스&lt;/b&gt;와의 통신은 어떻게 다룰까요?&lt;/p&gt;
&lt;p data-end=&quot;6159&quot; data-start=&quot;5764&quot; data-ke-size=&quot;size16&quot;&gt;여기서 등장하는 것이 바로 MSW(Mock Service Worker)입니다.&lt;/p&gt;
&lt;p data-end=&quot;6159&quot; data-start=&quot;5764&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;6159&quot; data-start=&quot;5764&quot; data-ke-size=&quot;size16&quot;&gt;MSW는 브라우저나 Node 환경에서 서비스 워커 API를 활용하여 실제 네트워크 요청을 가로채고, 개발자가 정의한 모의 응답(Mock response)을 반환해주는 라이브러리입니다. 이를 이용하면 별도의 테스트용 서버를 띄우지 않고도 &lt;b&gt;네트워크 계층을 포함한 통합 테스트&lt;/b&gt;를 손쉽게 구현할 수 있습니다. 다시 말해, 프론트엔드 관점에서 &lt;b&gt;클라이언트-서버 간의 상호작용 전체를 테스트 코드에서 재현&lt;/b&gt;할 수 있게 됩니다.&lt;/p&gt;
&lt;p data-end=&quot;6159&quot; data-start=&quot;5764&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;6159&quot; data-start=&quot;5764&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 &amp;ldquo;사용자가 로그인에 성공하면 토큰을 로컬스토리지에 저장한다&amp;rdquo;는 시나리오를 테스트하려 한다면, MSW로 로그인 API의 응답을 가로채어 성공 케이스를 미리 정의해둘 수 있습니다. 아래 코드는 MSW로 가짜 로그인 API 핸들러를 만들고, 이를 테스트에서 사용하는 예시입니다:&lt;/p&gt;
&lt;p data-end=&quot;6159&quot; data-start=&quot;5764&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1761831608456&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 로그인 API 성공 응답 핸들러 정의
export const createLoginSuccessHandler = (mockTokenResponse: TokenResponse) =&amp;gt; {
  return http.post(`${API_BASE_URL}${AUTH_ROUTES.LOGIN}`, async ({ request }) =&amp;gt; {
    const body = await request.json();
    // ... 요청 바디 검증 로직 등이 들어갈 수도 있음
    return HttpResponse.json&amp;lt;ApiResponse&amp;lt;TokenResponse&amp;gt;&amp;gt;({
      code: API_RESPONSE_CODES.OK,
      message: &quot;정상적으로 처리되었습니다.&quot;,
      data: mockTokenResponse,
    });
  });
};

// 테스트 시나리오 구현 (Jest + Testing Library 예시)
describe(&quot;when 유효한 이메일을 입력하고 로그인 버튼을 클릭할 때&quot;, () =&amp;gt; {
  it(&quot;to be: 로그인이 성공하고, 토큰이 localStorage에 저장되어야 함&quot;, async () =&amp;gt; {
    const mockTokenResponse = { memberId: 1, token: &quot;test-token&quot; };
    const testServer = createTestServer([createLoginSuccessHandler(mockTokenResponse)]);
    // 테스트용 서버(MSW) 시작
    testServer.listen();
    
    renderWithProviders(&amp;lt;LoginForm /&amp;gt;);

    // 사용자 입력 시뮬레이션
    await userEvent.type(screen.getByLabelText(&quot;이메일&quot;), &quot;test@example.com&quot;);
    await userEvent.click(screen.getByRole(&quot;button&quot;, { name: &quot;로그인&quot; }));

    // 결과 확인: 로컬스토리지에 토큰 저장됐는지 검증
    await waitFor(() =&amp;gt; {
      expect(authApi.getToken()).toBe(&quot;test-token&quot;);
    });

    // 테스트용 MSW 서버 종료
    testServer.close();
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;7911&quot; data-start=&quot;7539&quot; data-ke-size=&quot;size16&quot;&gt;위 테스트는 실제로 백엔드 서버를 띄운 적은 없지만, MSW를 통해 &lt;b&gt;마치 진짜 서버와 통신하듯&lt;/b&gt; 로그인 과정을 재현했습니다.&lt;/p&gt;
&lt;p data-end=&quot;7911&quot; data-start=&quot;7539&quot; data-ke-size=&quot;size16&quot;&gt;Testing Library를 사용해 사용자의 입력 이벤트를 흉내내고, MSW가 준비한 가짜 응답(test-token)을 받아 로컬스토리지가 업데이트되었는지를 검증함으로써, &lt;b&gt;전체 로그인 흐름이 문서 요구사항대로 이루어지는지&lt;/b&gt;를 자동 테스트한 것입니다. MSW 덕분에 테스트 환경의 리액트 컴포넌트는 실제 API와 대화한다고 믿고 있지만, 뒤에서는 우리의 가짜 서버가 응답을 주고 있기에 네트워크 의존성 없이도 &lt;b&gt;신뢰성 있는 통합 테스트&lt;/b&gt;가 가능합니다.&lt;/p&gt;
&lt;p data-end=&quot;7911&quot; data-start=&quot;7539&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;8307&quot; data-start=&quot;7913&quot; data-ke-size=&quot;size16&quot;&gt;중요한 점은, 이러한 테스트가 단순히 기능이 동작하는지를 넘어 문서에 정의된 시나리오가 제대로 구현되었는지&amp;rdquo;를 검증한다는 것입니다. 즉, &lt;b&gt;문서 &amp;rarr; 코드 &amp;rarr; 테스트&lt;/b&gt;의 일관성이 확보되는 것이죠.&lt;/p&gt;
&lt;p data-end=&quot;8307&quot; data-start=&quot;7913&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;8307&quot; data-start=&quot;7913&quot; data-ke-size=&quot;size16&quot;&gt;MSW를 통한 테스트는 실패할 수도 있습니다(예를 들어, 문서에 따른 시나리오대로 동작하지 않으면 테스트가 실패). 그 실패는 개발팀에게 곧바로 피드백으로 돌아옵니다. &amp;ldquo;무엇이 틀렸는가? 문서의 시나리오가 잘못됐는가, 아니면 구현된 코드에 버그가 있는가?&amp;rdquo;와 같은 질문을 던지게 함으로써, AI는 문서와 코드의 불일치를 조기에 발견하고 수정할 수 있습니다. &lt;br /&gt;&lt;br /&gt;이처럼 &lt;b&gt;MSW + 테스트 코드&lt;/b&gt; 조합은 문서로부터 출발한 기대 동작을 실제 코드에서 &lt;b&gt;자동으로 검증해주는 피드백 루프&lt;/b&gt;를 실현합니다.&lt;/p&gt;
&lt;p data-end=&quot;8307&quot; data-start=&quot;7913&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;8335&quot; data-start=&quot;8309&quot; data-ke-size=&quot;size26&quot;&gt;결론 &amp;ndash; 문서와 코드, 테스트의 삼각 루프&lt;/h2&gt;
&lt;p data-end=&quot;8728&quot; data-start=&quot;8504&quot; data-ke-size=&quot;size16&quot;&gt;MCP와 같은 기술을 통해 &lt;b&gt;문서와 디자인, 데이터가 연결&lt;/b&gt;되고, MSW와 테스트 코드를 통해 &lt;b&gt;문서의 내용이 자동으로 검증&lt;/b&gt;될 수 있습니다. 이러한 환경에서는 문서가 곧 실행 가능한 스펙이 되고, 코드와 테스트는 그 스펙을 구현하고 확인하는 역할을 합니다. 문서가 바뀌면 코드가 바뀌고, 코드가 바뀌면 테스트가 이를 잡아내고, 테스트 결과는 다시 문서에 반영되는 선순환이 자리잡게 됩니다.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-end=&quot;8953&quot; data-start=&quot;8730&quot; data-ke-size=&quot;size16&quot;&gt;결국 &lt;b&gt;&amp;ldquo;문서가 살아 있으면 팀도 살아 있다.&amp;rdquo;&lt;/b&gt; 문서가 최신 상태로 실행되고 있다면, 그 팀은 공유된 이해를 바탕으로 빠르게 움직일 수 있습니다. 그리고 &amp;ldquo;테스트는 문서의 진실을 증명하는 거울&amp;rdquo;이 되어, 우리의 문서(요구사항)가 정말 현실에서 지켜지고 있는지를 항상 비춰줍니다. 문서-코드-테스트가 삼위일체가 된 개발 문화야말로 빠른 변화 속에서도 품질과 이해도를 높이는 길일 것입니다&lt;/p&gt;
&lt;p data-end=&quot;8307&quot; data-start=&quot;7913&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;8307&quot; data-start=&quot;7913&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;8307&quot; data-start=&quot;7913&quot; data-ke-size=&quot;size16&quot;&gt;P.S)&lt;br /&gt;1~2주동안 써봤는데, 문서 기록, jira 연동, 개발이 빠르게 연동되어 개발 외 일의 생산성이 매우 높아져&lt;br /&gt;아주 만족도가 높습니다..!&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/work</category>
      <author>lodado</author>
      <guid isPermaLink="true">https://lodado.tistory.com/111</guid>
      <comments>https://lodado.tistory.com/111#entry111comment</comments>
      <pubDate>Thu, 30 Oct 2025 22:58:51 +0900</pubDate>
    </item>
    <item>
      <title>AI가 디자인을 코드로 옮기는 시대: MCP로 퍼블리싱 워크플로우 자동화하기</title>
      <link>https://lodado.tistory.com/110</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 MCP(Model Context Protocol)를 활용해 실무에 어떤 기능들을 적용할 수 있을지 살펴보고 있습니다. 그중에서도 특히 Cursor 에디터와 Figma를 MCP로 연동하여 &lt;b&gt;디자인-to-코드 퍼블리싱 워크플로우&lt;/b&gt;를 자동화하는 방법을 테스트해보았는데요. 이번 글에서는 그 과정을 정리해서 공유드리고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로는 GAN(생성적 적대 신경망) 구조에서 영감을 받아, 마치 Generator(코드 생성)와 Discriminator(코드 리뷰)가 서로 경쟁하며 결과물을 개선하는 형태로 구현해 보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot; data-end=&quot;100&quot; data-start=&quot;66&quot;&gt;** GAN이 뭐냐면?&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;66&quot; data-end=&quot;100&quot; data-ke-size=&quot;size23&quot;&gt;쉽게 말해서: &amp;ldquo;서로 경쟁하며 발전하는 두 AI&amp;rdquo;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;102&quot; data-end=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;GAN(Generative Adversarial Network)은 두 개의 인공지능이 서로 경쟁하면서 더 나은 결과를 만들어내는 구조입니다.&lt;br /&gt;이 두 AI는&amp;nbsp; 생성자(Generator)&amp;rdquo;와 &amp;ldquo;감별자(Discriminator)&amp;rdquo;**로 이루어져 있습니다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;260&quot; data-end=&quot;281&quot; data-ke-size=&quot;size23&quot;&gt;  두 역할을 비유로 설명하면&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-start=&quot;282&quot; data-end=&quot;534&quot;&gt;
&lt;li data-start=&quot;282&quot; data-end=&quot;405&quot;&gt;&lt;b&gt;Generator (생성자)&lt;/b&gt;:&lt;br /&gt;마치 그림을 그리는 학생처럼, 처음엔 서툴지만 점점 더 진짜처럼 보이는 이미지를 만들려고 노력합니다.&lt;br /&gt;(코드 생성 단계에서는 &amp;ldquo;AI가 새로운 코드를 작성하는 역할&amp;rdquo;)&lt;/li&gt;
&lt;li data-start=&quot;407&quot; data-end=&quot;534&quot;&gt;&lt;b&gt;Discriminator (감별자)&lt;/b&gt;:&lt;br /&gt;미술 선생님처럼, 학생이 만든 그림이 진짜인지 가짜인지 판단하고 피드백을 줍니다.&lt;br /&gt;(코드 리뷰 단계에서는 &amp;ldquo;AI가 코드의 품질, 구조, 가독성 등을 평가하는 역할&amp;rdquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-start=&quot;536&quot; data-end=&quot;539&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;541&quot; data-end=&quot;566&quot; data-ke-size=&quot;size23&quot;&gt;  이 둘이 반복적으로 경쟁하며 발전&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot; data-start=&quot;567&quot; data-end=&quot;731&quot;&gt;
&lt;li data-start=&quot;567&quot; data-end=&quot;596&quot;&gt;&lt;b&gt;Generator&lt;/b&gt;가 코드를 만듭니다.&lt;/li&gt;
&lt;li data-start=&quot;597&quot; data-end=&quot;643&quot;&gt;&lt;b&gt;Discriminator&lt;/b&gt;가 그 코드를 검사하고 문제점을 지적합니다.&lt;/li&gt;
&lt;li data-start=&quot;644&quot; data-end=&quot;687&quot;&gt;Generator는 지적받은 부분을 반영해 더 나은 코드를 만듭니다.&lt;/li&gt;
&lt;li data-start=&quot;688&quot; data-end=&quot;731&quot;&gt;이 과정을 여러 번 반복하면서 점점 더 완성도 높은 코드가 만들어집니다.&lt;/li&gt;
&lt;/ol&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;또한 직접 간단한 MCP 서버를 만들어 코드 리뷰 에이전트도 구성했어요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(mcp 서버 참고 링크 - &lt;a href=&quot;https://github.com/lodado/MCP-Code-Review-Agent&quot;&gt;https://github.com/lodado/MCP-Code-Review-Agent&lt;/a&gt; )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-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;511&quot; data-start=&quot;497&quot; data-ke-size=&quot;size26&quot;&gt;  1. MCP란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;722&quot; data-start=&quot;513&quot; data-ke-size=&quot;size16&quot;&gt;MCP(Model Context Protocol)는 AI 코드 에디터(예: Cursor, Claude Desktop 등)가 로컬 리소스나 외부 API에 접근할 수 있도록 해주는 &lt;b&gt;표준 프로토콜&lt;/b&gt;입니다. 쉽게 말해 &amp;ldquo;AI가 Figma API, GitLab, Notion, DB 등 외부 도구를 직접 불러와 사용할 수 있게 하는 인터페이스&quot;라고 보면 됩니다.&lt;/p&gt;
&lt;p data-end=&quot;722&quot; data-start=&quot;513&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1027&quot; data-start=&quot;724&quot; data-ke-size=&quot;size16&quot;&gt;조금 더 풀어서 설명하자면, MCP 환경에서는 &lt;b&gt;MCP 서버&lt;/b&gt;가 어댑터(Adapter) 역할을 하고, Cursor와 같은 에디터는 &lt;b&gt;클라이언트(Client)&lt;/b&gt; 역할을 합니다. 예를 들어 MCP 서버가 Figma API와 통신하여 디자인 정보를 가져오면, Cursor는 그 정보를 받아와 코드 생성 등에 활용할 수 있게 되죠. MCP는 프로토콜이기 때문에 Cursor뿐만 아니라 Codex, Claude Code 등 &lt;b&gt;여러 AI 코딩 플랫폼에 동일하게 연결&lt;/b&gt;할 수 있습니다. (이 글에서는 주로 Cursor와 codex를 기반으로 설명드릴게요.)&lt;/p&gt;
&lt;p data-end=&quot;1027&quot; data-start=&quot;724&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1043&quot; data-start=&quot;1029&quot; data-ke-size=&quot;size26&quot;&gt;⚙️ 2. 사전 준비&lt;/h2&gt;
&lt;p data-end=&quot;1102&quot; data-start=&quot;1045&quot; data-ke-size=&quot;size16&quot;&gt;본격적인 자동화 실험을 하기 전에 몇 가지 준비 사항이 있었습니다. 아래 항목들을 미리 갖춰야 했어요:&lt;/p&gt;
&lt;p data-end=&quot;1102&quot; data-start=&quot;1045&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1610&quot; data-start=&quot;1104&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1212&quot; data-start=&quot;1104&quot;&gt;&lt;b&gt;Cursor 에디터&lt;/b&gt;: MCP 클라이언트를 지원하는 최신 버전이 필요합니다 (2024.10 이후 버전). 저는 Cursor를 사용했고, MCP 설정을 할 수 있는지 꼭 확인해야 합니다. 꼭 cursor가 필요한건 아닙니다만, 전 cursor에서 진행했습니다.&lt;/li&gt;
&lt;li data-end=&quot;1212&quot; data-start=&quot;1104&quot;&gt;&lt;b&gt;Codex(혹은 claude code 등)&lt;/b&gt;:&amp;nbsp; 실제 리뷰를 진행할 에이전트입니다. MCP 내부에서 코드 리뷰 AI 서버로 이용하며, 로그인이 되어 있어야합니다.openai API를 사용해도 되긴하는데, 해당 방법시 사용 토큰당 과금 요소가 필요합니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;1267&quot; data-start=&quot;1213&quot;&gt;&lt;b&gt;Node.js&lt;/b&gt;: v18 이상이 설치되어 있어야 합니다 (MCP 서버 실행용으로 사용).&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;1492&quot; data-start=&quot;1268&quot;&gt;&lt;b&gt;Figma Personal Access Token&lt;/b&gt;: Figma API에 접근하기 위한 개인 액세스 토큰이 필요합니다. Figma 계정의 설정(Security 탭)에서 생성할 수 있어요. 참고: 발급은 &lt;span data-end=&quot;1455&quot; data-start=&quot;1388&quot;&gt;Figma 개발자 사이트&lt;/span&gt;에서 할 수 있으며, Dev Mode 활성화 등 권한이 필요합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;1610&quot; data-start=&quot;1493&quot;&gt;&lt;b&gt;Figma File Key&lt;/b&gt;: MCP로 연동하려는 Figma 파일의 고유 키 값입니다. 해당 파일의 URL에서 확인할 수 있습니다 (파일 URL 중 file/{파일Key} 형태로 포함되어 있어요).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2014&quot; data-start=&quot;1612&quot; data-ke-size=&quot;size16&quot;&gt;위 준비를 마쳤다면, 이제 &lt;b&gt;Cursor에 MCP 서버를 연결&lt;/b&gt;해야 합니다. Figma MCP 서버로는 오픈소스인 &lt;b&gt;Figma-Context-MCP&lt;/b&gt; 프로젝트를 활용했습니다. Cursor 설정(Settings)에서 MCP 섹션을 열어, 공식 가이드에 따라 Figma MCP를 추가로 등록합니다. (자세한 설정 방법은 &lt;span data-end=&quot;1866&quot; data-start=&quot;1793&quot;&gt;GLips/Figma-Context-MCP 깃허브&lt;/span&gt;와 &lt;span data-end=&quot;2004&quot; data-start=&quot;1868&quot;&gt;Framelink의 Figma MCP Quickstart 문서&lt;/span&gt;를 참고했습니다.)&lt;/p&gt;
&lt;p data-end=&quot;2069&quot; data-start=&quot;2016&quot; data-ke-size=&quot;size16&quot;&gt;Cursor 설정 파일에 MCP 서버를 등록할 때 아래와 같은 JSON 구성을 넣어주면 됩니다:&lt;/p&gt;
&lt;p data-end=&quot;2069&quot; data-start=&quot;2016&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1760886176574&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;Framelink MCP for Figma&quot;: {
      &quot;command&quot;: &quot;npx&quot;,
      &quot;args&quot;: [
        &quot;-y&quot;, 
        &quot;figma-developer-mcp&quot;, 
        &quot;--figma-api-key=YOUR-FIGMA-API-KEY&quot;, 
        &quot;--stdio&quot;
      ]
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2468&quot; data-start=&quot;2347&quot; data-ke-size=&quot;size16&quot;&gt;위와 같이 설정하고 MCP 서버(Figma MCP)를 실행하면, Cursor와 Figma 간 연동 준비가 완료됩니다. 이제 &lt;b&gt;Cursor에서 Figma 디자인 정보를 불러와서 코드 생성을 시작&lt;/b&gt;할 수 있어요!  &lt;/p&gt;
&lt;p data-end=&quot;2468&quot; data-start=&quot;2347&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2468&quot; data-start=&quot;2347&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2712&quot; data-start=&quot;2470&quot; data-ke-size=&quot;size16&quot;&gt;이제부터는 실제로 Figma 디자인을 가져와 코드로 변환하고, AI 코드 리뷰 에이전트를 통해 자동으로 개선하는 과정을 단계별로 설명하겠습니다. 전체 흐름을 요약하면 &amp;ldquo;Figma 디자인 -&amp;gt; 코드 생성 -&amp;gt; AI 코드 리뷰 -&amp;gt; 수정 반영&amp;rdquo;의 반복 루프라고 볼 수 있는데요, 이는 마치 앞서 언급한 GAN의 제너레이터-디스크리미네이터가 서로 경쟁하며 결과물을 개선하는 것과 비슷합니다.&lt;/p&gt;
&lt;p data-end=&quot;2712&quot; data-start=&quot;2470&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;746&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NiO5h/dJMb9aXZZT5/f0vNkuI3T4CcQthFKiq1x1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NiO5h/dJMb9aXZZT5/f0vNkuI3T4CcQthFKiq1x1/img.png&quot; data-alt=&quot;실제 workflow, 해당 스크린샷은 figma 자체 제공MCP를 활용한 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NiO5h/dJMb9aXZZT5/f0vNkuI3T4CcQthFKiq1x1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNiO5h%2FdJMb9aXZZT5%2Ff0vNkuI3T4CcQthFKiq1x1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;528&quot; height=&quot;746&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;746&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실제 workflow, 해당 스크린샷은 figma 자체 제공MCP를 활용한 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;2712&quot; data-start=&quot;2470&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2712&quot; data-start=&quot;2470&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2712&quot; data-start=&quot;2470&quot; data-ke-size=&quot;size16&quot;&gt;그럼 1단계부터 차근차근 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;2837&quot; data-start=&quot;2805&quot; data-ke-size=&quot;size23&quot;&gt;1.1 Figma MCP를 통한 디자인 데이터 추출&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2924&quot; data-start=&quot;2839&quot; data-ke-size=&quot;size16&quot;&gt;우선 Figma에서 구현하려는 UI 컴포넌트를 하나 선택했습니다. 예를 들어, 아래와 같은 Figma 디자인 파일의 특정 컴포넌트를 가져온다고 해볼게요:&lt;/p&gt;
&lt;p data-end=&quot;2924&quot; data-start=&quot;2839&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YLO0V/dJMb9fLL03t/rKSCfaXCd20uN5CfrLrGt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YLO0V/dJMb9fLL03t/rKSCfaXCd20uN5CfrLrGt1/img.png&quot; data-alt=&quot;jira의 Calender component&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YLO0V/dJMb9fLL03t/rKSCfaXCd20uN5CfrLrGt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYLO0V%2FdJMb9fLL03t%2FrKSCfaXCd20uN5CfrLrGt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;675&quot; height=&quot;688&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;688&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;jira의 Calender component&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-end=&quot;3239&quot; data-start=&quot;2926&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;3239&quot; data-start=&quot;2928&quot; data-ke-size=&quot;size16&quot;&gt;@&lt;span data-end=&quot;3062&quot; data-start=&quot;2929&quot;&gt;Figma 디자인 링크&lt;/span&gt;&lt;br /&gt;위 디자인 컴포넌트를 shared 폴더 내에 구현해주세요. &lt;b&gt;React + Tailwind&lt;/b&gt;를 사용하여 UI를 만들고, 코드의 응집도(cohesion)를 높이는 한편 결합도(coupling)는 최소화해주세요. 비즈니스 로직과 UI는 hook 또는 props를 활용해서 분리하도록 합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;3493&quot; data-start=&quot;3241&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3493&quot; data-start=&quot;3241&quot; data-ke-size=&quot;size16&quot;&gt;위와 같은 프롬프트를 Cursor에 입력하면, MCP를 통해 해당 Figma 노드(컴포넌트)의 정보가 AI에게 전달됩니다. 그러면 Cursor의 코드 생성 AI가 지시에 따라 &lt;b&gt;React + Tailwind CSS 조합으로 해당 컴포넌트의 코드를 생성&lt;/b&gt;합니다. 저는 프롬프트에 디자인 구현 시 &lt;b&gt;&amp;ldquo;응집도를 높이고 결합도를 줄여라&amp;rdquo;&lt;/b&gt;, &lt;b&gt;&amp;ldquo;로직과 UI 분리&amp;rdquo;&lt;/b&gt; 등의 베스트 프랙티스도 함께 써주어, 생성된 코드 품질을 높이려고 했어요.  &lt;/p&gt;
&lt;p data-end=&quot;3493&quot; data-start=&quot;3241&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;3532&quot; data-start=&quot;3495&quot; data-ke-size=&quot;size23&quot;&gt;1.3 Compound Pattern 적용 (컴파운드 패턴)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3766&quot; data-start=&quot;3534&quot; data-ke-size=&quot;size16&quot;&gt;코드를 생성할 때 고려한 중요한 아키텍처 원칙 중 하나는 &lt;b&gt;Compound Component Pattern&lt;/b&gt;의 적용이었습니다. 복잡한 UI를 구현하다 보면 &lt;b&gt;Props drilling&lt;/b&gt;(상위 컴포넌트의 props를 여러 단계 하위로 전달)이 많이 발생할 수 있는데요, 이를 줄이기 위해 &lt;b&gt;컴파운드 패턴&lt;/b&gt;으로 컴포넌트를 설계했습니다. 즉, 하나의 컴포넌트를 여러 하위 구성요소로 쪼개어 구성하는 방식입니다.&lt;/p&gt;
&lt;p data-end=&quot;3824&quot; data-start=&quot;3768&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 Card 컴포넌트를 Compound Pattern으로 구성하면 다음과 같은 형태가 됩니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1760886486557&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Compound Pattern 적용 예시
&amp;lt;Card&amp;gt;
  &amp;lt;Card.Header&amp;gt;
    &amp;lt;Card.Title&amp;gt;제목&amp;lt;/Card.Title&amp;gt;
  &amp;lt;/Card.Header&amp;gt;
  &amp;lt;Card.Body&amp;gt;
    &amp;lt;Card.Content&amp;gt;내용&amp;lt;/Card.Content&amp;gt;
  &amp;lt;/Card.Body&amp;gt;
  &amp;lt;Card.Footer&amp;gt;
    &amp;lt;Card.Actions&amp;gt;액션 영역&amp;lt;/Card.Actions&amp;gt;
  &amp;lt;/Card.Footer&amp;gt;
&amp;lt;/Card&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4236&quot; data-start=&quot;4088&quot; data-ke-size=&quot;size16&quot;&gt;위처럼 컴포넌트의 계층을 명확히 분리하면, 필요한 데이터나 함수를 하위 컴포넌트에 전달할 때 중간 단계의 불필요한 props 전달을 줄일 수 있습니다. 또한 각 부분을 독립적인 컴포넌트로 재사용할 수도 있어 &lt;b&gt;응집도를 높이면서도 결합도는 낮게&lt;/b&gt; 유지할 수 있죠.&lt;/p&gt;
&lt;p data-end=&quot;4236&quot; data-start=&quot;4088&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;4264&quot; data-start=&quot;4238&quot; data-ke-size=&quot;size23&quot;&gt;1.4 필요시 Provider 패턴 사용&lt;/h3&gt;
&lt;p data-end=&quot;4445&quot; data-start=&quot;4266&quot; data-ke-size=&quot;size16&quot;&gt;컴파운드 패턴으로 대부분의 UI 상태 전달 문제를 해결했지만, 만약 그것만으로 부족한 &lt;b&gt;복잡한 상태 관리&lt;/b&gt;가 필요할 경우에는 &lt;b&gt;Context API를 활용한 Provider 패턴&lt;/b&gt;을 적용했습니다. 예를 들어 전역적인 상태 공유나 깊은 트리 구조에서의 데이터 전달이 필요한 경우 Context를 사용하면 유용합니다:&lt;/p&gt;
&lt;p data-end=&quot;4445&quot; data-start=&quot;4266&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1760886510061&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Context Provider 패턴 예시
const AppContext = createContext();

const AppProvider = ({ children }) =&amp;gt; {
  // 공유할 상태와 로직 정의
  const value = { /* 상태 값들 */ };

  return (
    &amp;lt;AppContext.Provider value={value}&amp;gt;
      {children}
    &amp;lt;/AppContext.Provider&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4921&quot; data-start=&quot;4725&quot; data-ke-size=&quot;size16&quot;&gt;위처럼 Context를 쓰면 컴포넌트 트리 어디서든 AppContext를 통해 값에 접근할 수 있으므로, props drilling 없이도 필요한 데이터를 주고받을 수 있어요. 다만 Context 사용은 전역으로 상태를 공유하는 것이므로, 정말 필요한 경우에만 제한적으로 사용하고 기본적으로는 컴파운드 패턴 내에서 해결하는 것을 우선으로 했습니다.&lt;/p&gt;
&lt;p data-end=&quot;5023&quot; data-start=&quot;4923&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 해서 1단계에서는 &lt;b&gt;Figma 디자인 -&amp;gt; 초안 코드 생성&lt;/b&gt;까지 완료되었습니다. 이제 생성된 코드를 &lt;b&gt;AI 에이전트를 통해 리뷰하고 개선하는 단계&lt;/b&gt;로 넘어가겠습니다.&lt;/p&gt;
&lt;p data-end=&quot;5023&quot; data-start=&quot;4923&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;5051&quot; data-start=&quot;5025&quot; data-ke-size=&quot;size26&quot;&gt;2단계: 코드 리뷰 및 개선 (반복 루프)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5252&quot; data-start=&quot;5053&quot; data-ke-size=&quot;size16&quot;&gt;2단계에서는 앞서 생성된 코드를 다양한 관점에서 &lt;b&gt;AI로 리뷰&lt;/b&gt;하고, 피드백을 반영하여 코드를 개선하는 과정을 거쳤습니다. 저는 이를 세 가지 종류의 리뷰 에이전트를 통해 &lt;b&gt;여러 번 반복적으로&lt;/b&gt; 수행했는데요, 첫 번째는 일반 코드 품질 리뷰, 두 번째는 &lt;b&gt;웹 접근성(WCAG)&lt;/b&gt; 관점 리뷰, 세 번째는 &lt;b&gt;아키텍처 및 코드 구조&lt;/b&gt; 리뷰였습니다.&lt;/p&gt;
&lt;p data-end=&quot;5252&quot; data-start=&quot;5053&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5508&quot; data-start=&quot;5254&quot; data-ke-size=&quot;size16&quot;&gt;이 부분에서 저는 MCP를 이용해 직접 만든 &lt;b&gt;코드 리뷰 에이전트&lt;/b&gt;를 활용했습니다. 이 MCP 서버는 OpenAI의 Codex(프로그래밍 특화 모델)나 기타 LLM을 활용해 코드의 개선점을 알려주는 역할을 합니다. 쉽게 말해, 제 코드 리뷰 에이전트(MCP 서버)는 AI에게 코드를 보여주고 &amp;ldquo;문제점을 찾아줘&amp;rdquo;라고 물어보면 여러 가지 분석 결과를 주는 비서 같은 존재입니다. 이를 통해 사람 대신 AI가 1차로 리뷰를 해주니 상당히 편하더군요!&lt;/p&gt;
&lt;p data-end=&quot;5508&quot; data-start=&quot;5254&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5699&quot; data-start=&quot;5510&quot; data-ke-size=&quot;size16&quot;&gt;각 리뷰를 진행한 이휴, &lt;b&gt;리뷰 결과를 바로 100% 신뢰하기보다는&lt;/b&gt; 제가 한 번 더 &lt;b&gt;정리하고 핵심만 추출&lt;/b&gt;하는 과정을 거쳤습니다. AI가 장황하게 피드백을 주기도 하고, 가끔 맥락에 맞지 않는 제안을 할 때도 있어서, &lt;b&gt;필터링과 우선순위화&lt;/b&gt;를 사람이 도와주는 셈이죠. 그럼 각 리뷰 단계별로 어떤 작업을 했는지 살펴보겠습니다.&lt;/p&gt;
&lt;p data-end=&quot;5699&quot; data-start=&quot;5510&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5699&quot; data-start=&quot;5510&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5699&quot; data-start=&quot;5510&quot; data-ke-size=&quot;size16&quot;&gt;MCP 코드 및 작동 방식은 링크(&lt;a href=&quot;https://github.com/lodado/MCP-Code-Review-Agent&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/lodado/MCP-Code-Review-Agent&lt;/a&gt;) 서 살펴 보실 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;5699&quot; data-start=&quot;5510&quot; data-ke-size=&quot;size16&quot;&gt;로컬에 띄워놓고, codex를 사용하여 리뷰 및 검증후 MCP 프로토콜이 넘기는 형태로 구현했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5699&quot; data-start=&quot;5510&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;5726&quot; data-start=&quot;5701&quot; data-ke-size=&quot;size23&quot;&gt;2.1 Codex 기반 일반 코드 리뷰&lt;/h3&gt;
&lt;p data-end=&quot;5860&quot; data-start=&quot;5728&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5860&quot; data-start=&quot;5728&quot; data-ke-size=&quot;size16&quot;&gt;먼저 &lt;b&gt;Codex&lt;/b&gt; 기반의 일반 코드 품질 리뷰를 수행했습니다. 이 리뷰는 생성된 코드의 전반적인 품질, 가독성, 버그 여부 등을 점검해주는 역할입니다. 제 코드 리뷰 MCP 에이전트에서 이 기능을 호출하는 명령은 다음과 같았습니다:&lt;/p&gt;
&lt;p data-end=&quot;5860&quot; data-start=&quot;5728&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1760886844872&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; `Analyze the following TypeScript code and provide a comprehensive code review focusing on:

1. **Context**: What does this code do?
2. **Security Issues**: Any security vulnerabilities or concerns
3. **Performance Issues**: Performance bottlenecks or inefficiencies  
4. **Architecture Issues**: Design patterns, coupling, separation of concerns
5. **Logic Issues**: Potential bugs, edge cases, logical errors

Note: Do not include barrel export related content in your analysis.`&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;5860&quot; data-start=&quot;5728&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;6378&quot; data-start=&quot;6296&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;피드백 정제 과정:&lt;/b&gt; Codex로부터 분석 결과(JSON 형태 혹은 텍스트 리포트)가 오면, 다음과 같은 과정을 거쳐서 피드백을 정리했습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;6843&quot; data-start=&quot;6380&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;6479&quot; data-start=&quot;6380&quot;&gt;&lt;b&gt;AI 리뷰 결과 해석:&lt;/b&gt; Codex가 내놓은 리뷰 내용을 쭉 읽어봅니다. 보통 코드 스타일 지적, 잠재 버그, 최적화 제안 등이 섞여 나오는데, 일단 빠르게 훑어보죠.&lt;/li&gt;
&lt;li data-end=&quot;6591&quot; data-start=&quot;6480&quot;&gt;&lt;b&gt;핵심 개선사항 추출:&lt;/b&gt; 리뷰 결과에서 정말로 중요한 지적사항이나 코드 품질에 큰 영향을 미치는 포인트를 뽑아냅니다. (예: &quot;함수 A의 복잡도가 높다&quot;, &quot;불필요한 변수 선언이 있다&quot; 등)&lt;/li&gt;
&lt;li data-end=&quot;6696&quot; data-start=&quot;6592&quot;&gt;&lt;b&gt;우선순위 결정:&lt;/b&gt; 추출된 개선사항들에 우선순위를 매깁니다. 바로 고치지 않으면 위험한 버그 -&amp;gt; 리팩토링하면 좋은 부분 -&amp;gt; 스타일 사항 순으로 중요한 것부터 순위를 정했어요.&lt;/li&gt;
&lt;li data-end=&quot;6843&quot; data-start=&quot;6697&quot;&gt;&lt;b&gt;구체적인 수정 방향 계획:&lt;/b&gt; 각 중요한 지적에 대해 어떻게 수정할지 방향을 간략히 정리합니다. 예를 들어 &quot;함수 A 복잡도 개선&quot;이라면, 함수 쪼개기를 고려한다든지, &quot;변수 최소화&quot;라면 불필요한 변수를 삭제하거나 로직 단순화 계획을 세우는 식이죠.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;6954&quot; data-start=&quot;6845&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 핵심만 추린 후에, 우선순위 높은 항목부터 코드를 개선했습니다. Codex의 제안을 &lt;b&gt;맹신하기보다는 참고&lt;/b&gt;하는 수준으로 활용하고, 제가 수용할 부분은 수용하고 아닌 부분은 걸러냈습니다.&lt;/p&gt;
&lt;p data-end=&quot;5860&quot; data-start=&quot;5728&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;6997&quot; data-start=&quot;6956&quot; data-ke-size=&quot;size23&quot;&gt;2.2 웹 접근성 체크 (Accessibility Agent 리뷰)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;7172&quot; data-start=&quot;6999&quot; data-ke-size=&quot;size16&quot;&gt;다음으로, &lt;b&gt;웹 접근성(WCAG)&lt;/b&gt; 관점에서의 리뷰를 진행했습니다. 아무리 UI를 잘 구현해도, &lt;b&gt;시멘틱 마크업&lt;/b&gt;이나 &lt;b&gt;접근성&lt;/b&gt;이 떨어지면 실제 서비스에서 품질이 낮아질 수 있으니까요. 이를 위해 MCP 리뷰 에이전트의 &lt;b&gt;accessibility 모드&lt;/b&gt;를 활용했습니다. 명령어는 아래와 같습니다:&lt;/p&gt;
&lt;p data-end=&quot;7172&quot; data-start=&quot;6999&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1760886906873&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;`You are a Senior Frontend Publisher with 10+ years of experience in web accessibility and semantic web development. Analyze the following React/TypeScript code focusing specifically on:

1. **Web Accessibility (WCAG 2.1/2.2)**: 
   - ARIA attributes usage and correctness
   - Keyboard navigation support
   - Screen reader compatibility
   - Color contrast and visual accessibility
   - Focus management and tab order
   - Semantic HTML structure

2. **Semantic Web Standards**:
   - Proper HTML5 semantic elements usage
   - Microdata or JSON-LD structured data
   - Meta tags and SEO optimization
   - Progressive enhancement principles

3. **React Accessibility Best Practices**:
   - Proper use of React Aria hooks
   - Accessible form controls and validation
   - Error message accessibility
   - Component accessibility patterns

4. **Performance &amp;amp; UX for Accessibility**:
   - Loading states and skeleton screens
   - Error boundaries and fallbacks
   - Responsive design considerations
   - Animation and motion preferences`&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;5860&quot; data-start=&quot;5728&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;7650&quot; data-start=&quot;7605&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;8106&quot; data-start=&quot;7652&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;7771&quot; data-start=&quot;7652&quot;&gt;&lt;b&gt;WCAG 준수 여부 확인:&lt;/b&gt; AI가 지적한 내용 중 웹 콘텐츠 접근성 가이드라인(WCAG)에 비춰 &lt;b&gt;심각하게 위반되는 사항&lt;/b&gt;이 있는지 체크했습니다. (예: 컨트라스트 비율 부족, 폼 레이블 누락 등)&lt;/li&gt;
&lt;li data-end=&quot;7916&quot; data-start=&quot;7772&quot;&gt;&lt;b&gt;시맨틱 HTML 사용 검토:&lt;/b&gt; &amp;lt;div&amp;gt;로 떼운 부분이 없는지, 적절한 시맨틱 태그(&amp;lt;header&amp;gt;, &amp;lt;main&amp;gt;, &amp;lt;button&amp;gt; 등)를 썼는지 지적된 부분을 살폈습니다. 혹시 빼먹은 시맨틱 태그가 있다면 수정 계획에 포함했습니다.&lt;/li&gt;
&lt;li data-end=&quot;8017&quot; data-start=&quot;7917&quot;&gt;&lt;b&gt;키보드 내비게이션/포커스&lt;/b&gt;: 키보드만으로 UI 조작이 가능한지, focus outline이나 tabindex 처리 등 &lt;b&gt;키보드 접근성&lt;/b&gt; 관련 지적사항을 확인했습니다.&lt;/li&gt;
&lt;li data-end=&quot;8106&quot; data-start=&quot;8018&quot;&gt;&lt;b&gt;스크린 리더 호환성:&lt;/b&gt; 스크린 리더가 읽기 어렵거나 애매한 label/alt 텍스트 문제는 없는지 AI 피드백을 통해 점검하고 개선점을 정했습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;8239&quot; data-start=&quot;8108&quot; data-ke-size=&quot;size16&quot;&gt;이 단계에서는 접근성 전문가가 리뷰해주는 느낌으로 꽤 유용한 지적을 많이 얻었습니다.&lt;/p&gt;
&lt;p data-end=&quot;8239&quot; data-start=&quot;8108&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 &amp;ldquo;이미지에 대체 텍스트가 없습니다&amp;rdquo;와 같은 기본적인 접근성 문제부터, calendar 구성 요소에 role=&quot;application&quot;을 반영하거나 aria-roledescription 등 구체적인 ARIA 속성 제안을 통해 개선할 수 있었죠.&lt;/p&gt;
&lt;p data-end=&quot;8239&quot; data-start=&quot;8108&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;8239&quot; data-start=&quot;8108&quot; data-ke-size=&quot;size16&quot;&gt;이러한 피드백을 하나씩 반영하면서 전체 컴포넌트의 접근성 완성도를 높일 수 있었습니다.&lt;/p&gt;
&lt;p data-end=&quot;8239&quot; data-start=&quot;8108&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;8288&quot; data-start=&quot;8241&quot; data-ke-size=&quot;size23&quot;&gt;2.3 아키텍처 &amp;amp; 코드 구조 리뷰 (Toxic Architect Agent)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;8537&quot; data-start=&quot;8290&quot; data-ke-size=&quot;size16&quot;&gt;세 번째로는 &lt;b&gt;코드 아키텍처&lt;/b&gt;와 &lt;b&gt;설계 품질&lt;/b&gt;에 대한 리뷰를 진행했습니다. 이름하여 &quot;Toxic Architecture Agent&quot;라고 불리는 모드였는데요  , 말 그대로 &lt;b&gt;유해한(안 좋은) 아키텍처 패턴&lt;/b&gt;이 있는지 검토하는 에이전트였습니다. 이 리뷰는 코드가 &lt;b&gt;SOLID 원칙&lt;/b&gt;을 잘 지키고 있는지, &lt;b&gt;디자인 패턴&lt;/b&gt;을 적절히 활용하거나 남용하고 있지는 않은지 등을 점검해줍니다. MCP 에이전트 명령은 다음과 같았습니다:&lt;/p&gt;
&lt;p data-end=&quot;8537&quot; data-start=&quot;8290&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1760887060221&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;`You are a brutally honest Senior Frontend Architect with 15+ years of experience. You have zero tolerance for poor design, messy code, or weak abstractions. You are direct, sarcastic, and extremely critical&amp;mdash;but never use profanity or personal insults. Your tone is harsh but constructive, focused on technical precision and architectural correctness.

Analyze the following TypeScript code with a focus on:

1. **SOLID Principles Violations**:
   - SRP: UI logic, side effects, and data fetching mixed in the same component or module
   - OCP: feature extensions requiring if/else or switch statements
   - LSP: broken abstractions, subclass contracts violated
   - ISP: oversized interfaces, custom hooks doing too much
   - DIP: direct dependency on infra (fetch, storage, SDK) without abstractions

2. **Clean Code Violations**:
   - Poor separation between layers
   - Business logic leaking into components or pages
   - DTOs or API responses exposed to the UI layer
   - Folder structure not aligned with change axes or boundaries
   - Missing or inverted dependency direction

3. **Code Quality Issues**:
   - High coupling and low cohesion
   - &quot;God&quot; components, repeated patterns, and duplicated logic
   - Poor naming conventions and inconsistent coding styles
   - Overuse of \`any\`, \`unknown\`, or overly broad unions
   - Missing error handling, weak input validation
   - Performance bottlenecks (unnecessary re-renders, missing memoization)
   - Unclear data flow or improper state management
   - Excessive prop drilling (3+ levels deep - consider Context API, global state, or compound patterns)

4. **Design Pattern Misuse**:
   - Wrong or missing patterns (e.g., reinventing context or observer logic)
   - Over-engineered abstractions with no payoff
   - Misuse of hooks (unstable deps, side-effect chaos)
   - Excessive prop drilling (consider global state, providers, or compound patterns)
   - Global state abuse or inappropriate state management choices

5. **Frontend Essentials (Performance, Accessibility, Security, DX)**:
   - Performance: unnecessary renders, missing virtualization, bundle bloat, image misuse
   - Accessibility: missing roles/labels, focus traps, keyboard nav, contrast issues
   - Security: XSS, unsafe innerHTML, missing boundary validation
   - DX: missing unit/integration tests, weak linting or typing, broken CI coverage

6. **React / Next.js Specifics**:
   - Improper useEffect deps or cleanup
   - Confused client/server boundaries
   - Wrong caching, ISR, or SWR strategy
   - Incorrect use of Suspense/streaming
   - State mutations, non-serializable data leaks

Note: Do not include barrel export related content in your analysis.`&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;8902&quot; data-start=&quot;8829&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;9365&quot; data-start=&quot;8904&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;9058&quot; data-start=&quot;8904&quot;&gt;&lt;b&gt;SOLID 원칙 준수 검토:&lt;/b&gt; 단일 책임 원칙 위반이나, 의존성 역전 원칙 미흡 등 SOLID 원칙에 어긋나는 코드 구조 지적이 있었는지 확인했습니다. 예컨대 &quot;한 컴포넌트가 너무 많은 일을 한다&quot;라는 피드백이 있다면 단일 책임 원칙 위반이니 리팩토링을 계획했어요.&lt;/li&gt;
&lt;li data-end=&quot;9214&quot; data-start=&quot;9059&quot;&gt;&lt;b&gt;디자인 패턴 적용/남용 평가:&lt;/b&gt; 코드에서 사용한 패턴들이 적절했는지 봤습니다. Compound 패턴이나 Provider 패턴을 썼는데 AI가 보기에 어색한 부분은 없는지, 혹은 &quot;굳이 복잡한 패턴을 쓸 필요 없이 훨씬 단순하게 가능하다&quot;는 지적은 없는지 확인했습니다.&lt;/li&gt;
&lt;li data-end=&quot;9365&quot; data-start=&quot;9215&quot;&gt;&lt;b&gt;전반적 코드 구조 개선 제안:&lt;/b&gt; 폴더 구조나 컴포넌트 구조에 대한 제안도 나왔는데, 예를 들어 &quot;UI 로직과 비즈니스 로직이 완전히 분리되지 않았다&quot; 등의 피드백이 있었습니다. 이러한 지적에 대해서는 구조를 어떻게 더 개선할지 방안을 생각해보고 적용했습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;9637&quot; data-start=&quot;9367&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 세 가지 리뷰(일반 코드 품질, 접근성, 아키텍처)를 거치면서, 코드를 생성 -&amp;gt; 리뷰 -&amp;gt; 개선 -&amp;gt; 다시 리뷰 -&amp;gt; 개선... 하는 &lt;b&gt;루프를 여러 번 반복&lt;/b&gt;하게 되었습니다. 거의 코드가 스스로 리팩토링하며 발전하는 모습이라, 보면서도 신기했습니다.   GAN의 Generator-Discriminator가 서로 경쟁하며 출력물을 개선하듯이, 코드 생성기와 리뷰어 AI가 번갈아 가며 코드를 다듬어주니 결과적으로 초기 버전 대비 훨씬 깔끔하고 견고한 코드가 나오더군요.&lt;/p&gt;
&lt;p data-end=&quot;9637&quot; data-start=&quot;9367&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;9652&quot; data-start=&quot;9639&quot; data-ke-size=&quot;size26&quot;&gt;3단계: 최종 검증&lt;/h2&gt;
&lt;p data-end=&quot;9783&quot; data-start=&quot;9654&quot; data-ke-size=&quot;size16&quot;&gt;여러 차례에 걸친 개선 루프를 돌린 후, 마지막으로는 &lt;b&gt;최종 검증 단계&lt;/b&gt;를 진행했습니다. 최종 검증에서는 지금까지 누적된 변경사항을 &lt;b&gt;종합적으로 점검&lt;/b&gt;하고, 혹시 놓친 문제가 없는지&amp;nbsp;확인했습니다.&lt;/p&gt;
&lt;p data-end=&quot;9783&quot; data-start=&quot;9654&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;10964&quot; data-start=&quot;10950&quot; data-ke-size=&quot;size26&quot;&gt;핵심 원칙 되짚어보기&lt;/h2&gt;
&lt;p data-end=&quot;11026&quot; data-start=&quot;10966&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;11519&quot; data-start=&quot;11028&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;11195&quot; data-start=&quot;11028&quot;&gt;&lt;b&gt;Compound Pattern 우선 적용:&lt;/b&gt; 가능하다면 UI 컴포넌트를 설계할 때 Prop drilling을 줄일 수 있는 Compound 컴포넌트 패턴을 활용하자. 각 UI 요소를 독립적인 컴포넌트로 구성하면 재사용성과 유지보수성이 크게 향상된다. (Context API는 보조적으로!)&lt;/li&gt;
&lt;li data-end=&quot;11357&quot; data-start=&quot;11196&quot;&gt;AI 피드백의 &lt;b&gt;선별&lt;/b&gt; 및 &lt;b&gt;명확한 적용:&lt;/b&gt; AI 리뷰 에이전트가 주는 피드백은 한 번 걸러서 핵심만 취하고, 팀원이나 다른 사람이 봐도 이해하기 쉽게 정제해서 공유하자. 두서없이 적용하기보다 &lt;b&gt;우선순위&lt;/b&gt;를 정해 단계적으로 수정하고, 그 내용을 명확히 기록해두면 좋다.&lt;/li&gt;
&lt;li data-end=&quot;11519&quot; data-start=&quot;11358&quot;&gt;&lt;b&gt;누적 검증과 반복 개선:&lt;/b&gt; 한 번의 생성-리뷰로 끝내지 말고, &lt;b&gt;여러 번의 루프&lt;/b&gt;를 누적하여 돌림으로써 코드 품질을 점진적으로 높이자. 각 단계의 피드백을 다음 단계에 반영하면서, 최종적으로 전체 코드를 다시 검증하면 놓치는 부분 없이 &lt;b&gt;탄탄한 결과물&lt;/b&gt;을 얻을 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-end=&quot;11541&quot; data-start=&quot;11521&quot; data-ke-size=&quot;size26&quot;&gt;사용한 MCP 리뷰 명령어 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;11613&quot; data-start=&quot;11543&quot; data-ke-size=&quot;size16&quot;&gt;혹시 MCP 기반 코드 리뷰 에이전트를 활용해보고 싶은 분들을 위해, 제가 사용했던 주요 명령어들을 한 곳에 모아 요약합니다:&lt;/p&gt;
&lt;p data-end=&quot;11613&quot; data-start=&quot;11543&quot; data-ke-size=&quot;size16&quot;&gt;codex login이 되어 있어야합니다.&lt;/p&gt;
&lt;p data-end=&quot;11613&quot; data-start=&quot;11543&quot; data-ke-size=&quot;size16&quot;&gt;아마&amp;nbsp; MCP 연결도 되긴 할텐데, cursor에서는 샌드박스 &amp;amp; 보안 관련 이슈로 MCP 인터페이스엔 연결 못했고 &lt;br /&gt;jsonrpc + cli 명령으로 연결 및 테스트했습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1760887160790&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Clone and build the tool locally (package not yet published to npm)
git clone https://github.com/lodado/MCP-Code-Review-Agent
cd MCP-Code-Review-Agent
npm install
npm run build
npm link

# 1. Codex 일반 코드 리뷰 (최신 수정 부분만 분석)
echo '{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;id&quot;:1,&quot;method&quot;:&quot;tools/call&quot;,&quot;params&quot;:{&quot;name&quot;:&quot;codex_review&quot;,&quot;arguments&quot;:{&quot;reviewType&quot;:&quot;modified&quot;,&quot;analysisType&quot;:&quot;codex&quot;}}}' | mcp-code-review-agent

# 2. 웹 접근성 리뷰 (코드 전체 풀스캔)
echo '{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;id&quot;:2,&quot;method&quot;:&quot;tools/call&quot;,&quot;params&quot;:{&quot;name&quot;:&quot;codex_review&quot;,&quot;arguments&quot;:{&quot;reviewType&quot;:&quot;full&quot;,&quot;analysisType&quot;:&quot;accessibility&quot;}}}' | mcp-code-review-agent

# 3. 아키텍처 리뷰 (코드 전체 풀스캔)
echo '{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;id&quot;:3,&quot;method&quot;:&quot;tools/call&quot;,&quot;params&quot;:{&quot;name&quot;:&quot;codex_review&quot;,&quot;arguments&quot;:{&quot;reviewType&quot;:&quot;full&quot;,&quot;analysisType&quot;:&quot;toxic-architect&quot;}}}' | mcp-code-review-agent

# 4. 하이브리드 종합 리뷰 (코드 전체 풀스캔)
echo '{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;id&quot;:4,&quot;method&quot;:&quot;tools/call&quot;,&quot;params&quot;:{&quot;name&quot;:&quot;codex_review&quot;,&quot;arguments&quot;:{&quot;reviewType&quot;:&quot;full&quot;,&quot;analysisType&quot;:&quot;hybrid&quot;}}}' | mcp-code-review-agent

# 5. 정적 분석 리뷰 (최신 수정 부분만 분석)
echo '{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;id&quot;:5,&quot;method&quot;:&quot;tools/call&quot;,&quot;params&quot;:{&quot;name&quot;:&quot;codex_review&quot;,&quot;arguments&quot;:{&quot;reviewType&quot;:&quot;modified&quot;,&quot;analysisType&quot;:&quot;static&quot;}}}' | mcp-code-review-agent&lt;/code&gt;&lt;/pre&gt;
&lt;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;12759&quot; data-start=&quot;12745&quot; data-ke-size=&quot;size26&quot;&gt;기대 효과 및 마무리&lt;/h2&gt;
&lt;p data-end=&quot;12837&quot; data-start=&quot;12761&quot; data-ke-size=&quot;size16&quot;&gt;이번에 MCP와 Figma, 그리고 AI 코드 리뷰 에이전트를 조합한 워크플로우를 실험해보면서 느낀 &lt;b&gt;기대 효과&lt;/b&gt;는 다음과 같습니다:&lt;/p&gt;
&lt;p data-end=&quot;12837&quot; data-start=&quot;12761&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;13340&quot; data-start=&quot;12839&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;12945&quot; data-start=&quot;12839&quot;&gt;&lt;b&gt;코드 품질 향상:&lt;/b&gt; 여러 각도의 AI 리뷰(코덱스, 접근성, 아키텍처)를 거치면서 코드의 품질이 종합적으로 개선되었습니다. 사람이 놓칠 수 있는 부분까지 AI가 짚어주니 든든했어요.&lt;/li&gt;
&lt;li data-end=&quot;13047&quot; data-start=&quot;12946&quot;&gt;&lt;b&gt;웹 접근성 강화:&lt;/b&gt; 평소 간과하기 쉬운 접근성 부분도 전문가 수준으로 챙길 수 있었어요. 덕분에 결과물 UI가 &lt;b&gt;더 포용력있는 사용자 경험&lt;/b&gt;을 제공할 것으로 기대됩니다.&lt;/li&gt;
&lt;li data-end=&quot;13184&quot; data-start=&quot;13048&quot;&gt;&lt;b&gt;아키텍처 개선:&lt;/b&gt; SOLID 원칙과 Clean code 관점에서 코드를 한번 더 점검하니, 초기 설계에서 미처 생각 못 한 &lt;b&gt;구조적 개선&lt;/b&gt; 포인트를 잡아낼 수 있었습니다. 장기적으로 유지보수성이 향상될 거라 믿습니다.&lt;/li&gt;
&lt;li data-end=&quot;13340&quot; data-start=&quot;13185&quot;&gt;&lt;b&gt;개발 효율성 증대:&lt;/b&gt; 사람 대신 &lt;b&gt;AI 에이전트들이 리뷰와 수정 가이드&lt;/b&gt;를 제시해주니, 개발자가 반복적인 코드 정돈 작업에 들이는 시간이 줄었습니다. 물론 최종 판단은 개발자가 해야 하지만, 이러한 자동화된 워크플로우가 &lt;b&gt;개발 생산성&lt;/b&gt;을 높여준 것은 분명합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 아쉬운 점은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 아직 figma MCP가 베타 단계이고, design variable이나 font등을 정확히 뽑아내진 못함(#fff등 순수 색상, hex 값으로 표출됨)&lt;br /&gt;2. 다행이자 아쉬운 점은 AI가 아직은 불완전하다는 것이고, &lt;br /&gt;&amp;nbsp; &amp;nbsp; 결국은 검수자의 숙련도에 따라 다른 결과가 나올 수 있음, 알잘딱깔센이 안됨!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 MVP 코드나 UI 코드를 빠르게 뽑아낼때엔 유용한 듯 싶습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;13602&quot; data-start=&quot;13342&quot; data-ke-size=&quot;size16&quot;&gt;마치며, MCP를 활용하면 AI가 코딩 도구들과 직접 소통할 수 있게 되면서 개발 방식에 재미있는 변화가 생기는 것 같습니다. 이번에는 Figma 디자인을 코드로 자동화하는 시나리오였지만, 앞으로 GitHub PR 리뷰나 테스트 자동화 등 다양한 분야에 이런 &lt;b&gt;AI 에이전트+MCP 조합&lt;/b&gt;을 응용해볼 수 있을 것 같아요. 혹시 비슷한 시도를 해보신 분이 있다면 경험을 공유해주시거나, 궁금한 점이 있다면 댓글로 남겨주세요. 읽어주셔서 감사합니다!  &lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;13602&quot; data-start=&quot;13342&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;13602&quot; data-start=&quot;13342&quot; data-ke-size=&quot;size16&quot;&gt;마지막으로 어떤 결과물이 나왔는지 공유드릴려고 생성된 코드 폴더를 제공하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;13602&quot; data-start=&quot;13342&quot; data-ke-size=&quot;size16&quot;&gt;AI가 제안한 방향 및 리뷰 코드에서 거의 건드리지 않은 코드입니다.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;13602&quot; data-start=&quot;13342&quot; data-ke-size=&quot;size16&quot;&gt;돌아가지는 않겠지만.. 전체적인 코드를 한번 참고해주세요!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/ypcRN/dJMb84cpqrV/Rn8Ax9tqq9gfappfyKNelK/Calendar.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;Calendar.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.01MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;13602&quot; data-start=&quot;13342&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/work</category>
      <author>lodado</author>
      <guid isPermaLink="true">https://lodado.tistory.com/110</guid>
      <comments>https://lodado.tistory.com/110#entry110comment</comments>
      <pubDate>Mon, 20 Oct 2025 00:26:06 +0900</pubDate>
    </item>
    <item>
      <title>모듈화 관점에서의 오염</title>
      <link>https://lodado.tistory.com/108</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 회사에서 일하던 프로젝트가 잘되서(?) 사업의 스케일이 커졌고, 모듈리식 레포지토리에서 작은 도메인 단위의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서브 프로젝트 여러개로 쪼개는 모노레포 리펙토링 작업을 진행하고 있다&lt;/p&gt;
&lt;p data-end=&quot;99&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;261&quot; data-start=&quot;101&quot; data-ke-size=&quot;size16&quot;&gt;공통 로직이랑 중복 코드를 추출하면서, 자연스럽게 추출 및 활용이 쉬운 코드와 어려운 코드가 나뉘는 걸 체감하고 있다.&lt;/p&gt;
&lt;p data-end=&quot;261&quot; data-start=&quot;101&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;261&quot; data-start=&quot;101&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 단순히 코드 복잡도나 의존성 때문이라고 생각했는데, 계속 리팩토링을 하다 보니까 그 차이의 본질이 결국 &lt;b&gt;오염(contamination)&lt;/b&gt; 이라는 생각이 들었다. 한 모듈의 상태나 로직이 다른 곳에 얼마나 퍼져 있느냐, 그게 오염의 정도다.&lt;/p&gt;
&lt;p data-end=&quot;261&quot; data-start=&quot;101&quot; data-ke-size=&quot;size16&quot;&gt;오염이 심할수록 추출이 어렵고, 반대로 모듈 경계가 깔끔하게 지켜진 코드일수록 손쉽게 분리된다.&lt;/p&gt;
&lt;p data-end=&quot;261&quot; data-start=&quot;101&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;261&quot; data-start=&quot;101&quot; data-ke-size=&quot;size16&quot;&gt;이를 &amp;ldquo;&lt;b&gt;모듈화 관점에서의 오염(contamination)&lt;/b&gt;&amp;rdquo;은, 한 모듈의 책임/경계가 무너지고 &lt;b&gt;부작용, 상태, 오류, 의존성, 규칙 등이 경계를 넘어 전파되는 현상 &lt;/b&gt;이라고 보면 될듯하다.&lt;/p&gt;
&lt;p data-end=&quot;261&quot; data-start=&quot;101&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;85&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;이 &amp;ldquo;오염&amp;rdquo;이라는 게 뭔지 구체적으로 말하자면, 한 모듈 내부에서만 머물러야 할 값이나 상태, 부작용이 &lt;b&gt;경계를 넘어 퍼지는 현상&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-end=&quot;85&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;276&quot; data-start=&quot;87&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 null이 대표적인 케이스다. 어떤 함수가 null을 반환하고, 그걸 받은 상위 함수가 별다른 검증 없이 그대로 다음 함수로 넘기면, 결국 그 null은 시스템 전반으로 퍼진다. 나중엔 어디서 깨졌는지도 모르는 상태에서 Cannot read property 'x' of null 같은 에러를 뿜는다.&lt;/p&gt;
&lt;p data-end=&quot;276&quot; data-start=&quot;87&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1760113962144&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function getUser(id: string) {
  const user = db.find(u =&amp;gt; u.id === id);
  return user ?? null; // ❌ null 반환
}

function getUserName(id: string) {
  const user = getUser(id);
  return user.name; // ❌ 여기서 null 전파로 터짐
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;611&quot; data-start=&quot;507&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;611&quot; data-start=&quot;507&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;611&quot; data-start=&quot;507&quot; data-ke-size=&quot;size16&quot;&gt;이게 바로 **데이터 오염(data contamination)**이다.&lt;br /&gt;한 곳에서의 &amp;ldquo;불확실한 상태(null)&amp;rdquo;가 검증 없이 전달되며,&lt;br /&gt;모듈 경계를 오염시키는 전형적인 예시다.&lt;/p&gt;
&lt;p data-end=&quot;646&quot; data-start=&quot;613&quot; data-ke-size=&quot;size16&quot;&gt;이런 식의 오염은 null뿐만 아니라 다양하게 존재한다.&lt;/p&gt;
&lt;p data-end=&quot;646&quot; data-start=&quot;613&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;813&quot; data-start=&quot;647&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;673&quot; data-start=&quot;647&quot;&gt;전역 변수를 직접 수정하는 &lt;b&gt;상태 오염&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;711&quot; data-start=&quot;674&quot;&gt;외부 변수에 의존하거나 부작용을 남기는 &lt;b&gt;비순수 함수 오염&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;749&quot; data-start=&quot;712&quot;&gt;특정 API 구조나 데이터 포맷에 직접 묶인 &lt;b&gt;의존성 오염&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;779&quot; data-start=&quot;750&quot;&gt;try-catch 없이 흘러가는 &lt;b&gt;에러 오염&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;813&quot; data-start=&quot;780&quot;&gt;CSS 클래스가 전역에 영향을 미치는 &lt;b&gt;스타일 오염&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;813&quot; data-start=&quot;780&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-end=&quot;928&quot; data-start=&quot;815&quot; data-ke-size=&quot;size16&quot;&gt;결국 오염이란 &amp;ldquo;내부의 영향이 외부로 새는 것&amp;rdquo;이다.&lt;br /&gt;내부 로직의 부작용, 불확실한 값, 전역 변경이 다른 모듈로 번지면서, 코드 추출과 분리가 어려워지고, 유지보수성도 떨어지는 이유가 된다.&lt;/p&gt;
&lt;p data-end=&quot;928&quot; data-start=&quot;815&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1027&quot; data-start=&quot;930&quot; data-ke-size=&quot;size16&quot;&gt;그래서 리팩토링을 하다 보면 &amp;ldquo;이 코드는 왜 이렇게 유지보수, 재사용 하기 힘들까?&amp;rdquo;의 답이 대부분 여기에 있다 &amp;mdash;&lt;br /&gt;&lt;b&gt;경계 밖으로 새어나간 오염이 많을수록, 코드 리펙토링, 재사용이 힘들어진다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;261&quot; data-start=&quot;101&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;493&quot; data-start=&quot;364&quot; data-ke-size=&quot;size16&quot;&gt;결국 유지보수가 쉽고 어려운 건 코드량이나 난이도의 문제가 아니라, &lt;b&gt;얼마나 경계가 명확하고 불필요한 의존이 없는 구조인지&lt;/b&gt;에 달린 것 같다&lt;/p&gt;</description>
      <category>Front-end/work</category>
      <author>lodado</author>
      <guid isPermaLink="true">https://lodado.tistory.com/108</guid>
      <comments>https://lodado.tistory.com/108#entry108comment</comments>
      <pubDate>Sat, 11 Oct 2025 01:38:29 +0900</pubDate>
    </item>
    <item>
      <title>운영체제 관련 정리</title>
      <link>https://lodado.tistory.com/107</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 면접 준비하며 준비했던 내용 공유합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;운영체제 기본 개념&lt;/b&gt;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 하드웨어 (Hardware)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중앙 처리 장치(CPU): 명령어 해석 및 실행.&lt;/li&gt;
&lt;li&gt;메모리(Memory): 프로그램과 데이터를 저장.&lt;/li&gt;
&lt;li&gt;입출력 장치(I/O devices): 사용자와 시스템 간 데이터 교환.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 부트스트랩 (Bootstrap)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저장 위치: ROM(Read-Only Memory)에 저장.&lt;/li&gt;
&lt;li&gt;역할:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;시스템 전원이 켜지면 실행됨.&lt;/li&gt;
&lt;li&gt;운영체제의 커널(kernel) 을 찾아 주 메모리(RAM) 에 적재.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;결과: 커널이 실행되면서 시스템 초기화가 진행됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 커널과 시스템 프로세스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널(Kernel): 운영체제의 핵심 부분, 자원 관리와 제어 담당.&lt;/li&gt;
&lt;li&gt;시스템 프로세스 / 시스템 데몬(Daemon):
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널 수행 중 계속 동작.&lt;/li&gt;
&lt;li&gt;백그라운드에서 시스템 기능(예: 스케줄링, 로그 관리, 네트워크 서비스 등)을 지원.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 주 메모리 (RAM)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특징: 재기록 가능한 메모리.&lt;/li&gt;
&lt;li&gt;용도:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 중인 프로그램과 데이터를 저장.&lt;/li&gt;
&lt;li&gt;CPU가 직접 접근 가능.&lt;/li&gt;
&lt;li&gt;전원이 꺼지면 내용이 사라지는 휘발성 메모리.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 컴퓨터 구조&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(1) 폰 노이만 구조 (Von Neumann Architecture)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명령어와 데이터를 같은 버스(경로)를 통해 전달.&lt;/li&gt;
&lt;li&gt;특징: 구조 단순, 범용 컴퓨터에 널리 사용.&lt;/li&gt;
&lt;li&gt;단점: 명령어와 데이터가 한 버스를 공유해 병목 현상(폰 노이만 병목) 발생 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(2) 하버드 아키텍처 (Harvard Architecture)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명령어와 데이터를 서로 다른 버스에서 전달.&lt;/li&gt;
&lt;li&gt;특징: 명령어 읽기와 데이터 접근을 동시에 수행 가능 &amp;rarr; 병목 최소화.&lt;/li&gt;
&lt;li&gt;주로 임베디드 시스템, DSP(Digital Signal Processor) 등에서 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 입출력 구조 (I/O Structure)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 인터럽트 기반 I/O (Interrupt-Driven I/O)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동작 방식&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 I/O 장치에 작업을 지시하고 다른 일을 수행.&lt;/li&gt;
&lt;li&gt;I/O 장치가 작업을 끝내면 &lt;b&gt;인터럽트(Interrupt)&lt;/b&gt; 신호를 CPU에 보냄.&lt;/li&gt;
&lt;li&gt;CPU는 인터럽트 서비스 루틴(ISR)을 실행하여 결과를 처리.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;: CPU가 불필요하게 대기하지 않음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점&lt;/b&gt;: 인터럽트가 자주 발생하면 오버헤드 증가.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 직접 메모리 접근 (DMA, Direct Memory Access)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동작 방식&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 I/O 장치에 메모리 전송을 직접 하지 않고, &lt;b&gt;DMA 컨트롤러&lt;/b&gt;에게 위임.&lt;/li&gt;
&lt;li&gt;DMA 컨트롤러가 메모리와 I/O 장치 간 데이터를 직접 전송.&lt;/li&gt;
&lt;li&gt;전송이 완료되면 CPU에 인터럽트를 보내 알림.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;: CPU 개입 최소화 &amp;rarr; &lt;b&gt;고속 데이터 전송&lt;/b&gt; 가능 (예: 디스크 &amp;harr; 메모리).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;활용&lt;/b&gt;: 대량 데이터 전송이 필요한 경우 (예: 영상, 네트워크, 디스크 입출력).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 운영체제 (Operating System, OS)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;목적&lt;/b&gt;: 사용자가 시스템을 쉽게 사용할 수 있도록 설계.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원 사용 자체에는 신경 쓰지 않음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자원 할당자(Resource Allocator)&lt;/b&gt;: CPU, 메모리, I/O 자원들을 적절히 배분.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제어 프로그램(Control Program)&lt;/b&gt;: 프로그램 실행과 하드웨어 동작을 제어.&lt;/li&gt;
&lt;/ul&gt;
메모리에 적재되어 있고, 실행되는 프로그램을 &amp;ldquo;프로세스&amp;rdquo;라 부름1. 인터럽트(Interrupt)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;발생 원인&lt;/b&gt;: CPU 외부의 &lt;b&gt;하드웨어 장치&lt;/b&gt;가 CPU에게 서비스를 요청할 때 발생&lt;/li&gt;
&lt;li&gt;예: 키보드 입력, 디스크 I/O 완료, 네트워크 패킷 도착&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비동기적&lt;/b&gt;으로 발생 (CPU가 어떤 명령을 실행 중이든 외부 장치에서 신호를 보냄)&lt;/li&gt;
&lt;li&gt;CPU는 현재 실행 중이던 명령을 끝내고 인터럽트 서비스 루틴(ISR)으로 점프&lt;/li&gt;
&lt;li&gt;주로 &lt;b&gt;외부 이벤트 처리&lt;/b&gt;를 위해 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키보드에서 키가 눌림 &amp;rarr; 인터럽트 발생 &amp;rarr; 운영체제 커널이 입력 버퍼에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;2. 트랩(Trap, 예외 Exception)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;발생 원인&lt;/b&gt;: &lt;b&gt;CPU 내부에서 실행 중인 프로그램이 원인&lt;/b&gt;이 되는 상황&lt;/li&gt;
&lt;li&gt;예: 0으로 나누기, 잘못된 메모리 접근, 시스템 콜 호출&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동기적&lt;/b&gt;으로 발생 (특정 명령 실행 결과로 즉시 발생)&lt;/li&gt;
&lt;li&gt;크게 두 종류로 나뉨:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;예외(Exception)&lt;/b&gt;: 오류 상황 (Divide by zero, Page fault 등)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랩(Trap, 소프트웨어 인터럽트)&lt;/b&gt;: 의도적으로 발생시켜 운영체제 서비스 호출 (System call)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;int 0x80 (리눅스 시스템 콜) &amp;rarr; 커널로 진입&lt;/li&gt;
&lt;li&gt;잘못된 포인터 접근 &amp;rarr; Segmentation fault&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;3. 차이점 요약구분 인터럽트(Interrupt) 트랩 / 예외(Trap, Exception)
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;발생 원인&lt;/td&gt;
&lt;td&gt;&lt;b&gt;하드웨어 장치&lt;/b&gt; (외부)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;CPU 내부 명령 실행 결과&lt;/b&gt; (소프트웨어)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;발생 시점&lt;/td&gt;
&lt;td&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&gt;
&lt;td&gt;주 용도&lt;/td&gt;
&lt;td&gt;외부 이벤트 처리&lt;/td&gt;
&lt;td&gt;오류 처리, 운영체제 서비스 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;td&gt;키보드 입력, 디스크 I/O 완료&lt;/td&gt;
&lt;td&gt;0 나누기, 페이지 폴트, 시스템 콜&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;  정리하면,
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인터럽트&lt;/b&gt;는 외부 장치가 CPU를 부르는 &quot;하드웨어 호출&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랩/예외&lt;/b&gt;는 프로그램 실행 도중 CPU 내부에서 발생하는 &quot;소프트웨어 호출/오류&quot;&lt;/li&gt;
&lt;/ul&gt;
이중 연산모드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU 내부에 &lt;b&gt;모드 비트(Mode Bit)&lt;/b&gt; 라는 플래그가 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;1 &amp;rarr; 사용자 모드(User Mode)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;0 &amp;rarr; 커널 모드(Kernel Mode, Supervisor Mode)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;2. 사용자 모드 (User Mode)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반 응용 프로그램이 동작하는 모드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제한된 명령어만 실행 가능&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입출력(I/O) 명령, 메모리 보호를 무시하는 명령 등은 금지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;잘못된 동작이 발생하면 **트랩(예외)**을 발생시켜 운영체제가 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;3. 커널 모드 (Kernel Mode)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;운영체제(OS) 커널이 실행되는 모드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모든 명령어 실행 가능 (특권 명령 포함)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입출력 제어, 타이머 관리, 메모리 관리, 인터럽트 제어 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;시스템 전체에 영향을 줄 수 있는 연산은 &lt;b&gt;커널 모드에서만 수행&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;4. 모드 전환
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;부팅 시&lt;/b&gt;: 항상 커널 모드에서 시작 (운영체제가 제어권을 가짐)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시스템 콜, 트랩, 인터럽트 발생 시&lt;/b&gt;: 하드웨어가 자동으로 커널 모드로 전환&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널이 작업을 마친 후&lt;/b&gt;: 다시 사용자 모드로 전환하여 응용 프로그램 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;5. 이중 모드 운영의 목적
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;보호(Protection)&lt;/b&gt;: 사용자 프로그램이 임의로 하드웨어 자원(I/O, 메모리 등)을 제어하지 못하게 막음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;안정성(Stability)&lt;/b&gt;: 오류가 발생해도 운영체제가 제어권을 가짐 &amp;rarr; 시스템 전체가 멈추는 것 방지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안(Security)&lt;/b&gt;: 악의적인 프로그램이 커널 수준 권한을 직접 사용하는 것을 차단&lt;/li&gt;
&lt;/ul&gt;
운영체제의 메모리 관리
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;메모리 사용량 추적, 누구에 의해 사용되고 있는지&lt;/li&gt;
&lt;li&gt;어떤 프로세스를 적재하고 제거할 것인지&lt;/li&gt;
&lt;li&gt;필요에 따라 메모리 공간을 할당하고 회수&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;1. 모드 비트 (Mode Bit)&lt;/li&gt;
&lt;li&gt;현재의 운영체제는 인터럽트 구동식이다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 응용 프로그램 (Application Programs)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자 요구를 직접 해결하는 소프트웨어.&lt;/li&gt;
&lt;li&gt;예시: 워드 프로세서, 웹 브라우저 등.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 사용자 (Users)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응용 프로그램을 활용해 컴퓨터를 사용하는 주체.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&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;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;운영체제 서비스&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;운영체제 서비스 (Operating System Services)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제는 사용자와 하드웨어 사이에서 여러 **서비스(services)**를 제공하여 &lt;b&gt;편의성, 효율성, 보안성&lt;/b&gt;을 보장합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 사용자 인터페이스 제공 (User Interface)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CLI(Command Line Interface)&lt;/b&gt;: 터미널 기반 명령어 입력 (예: Bash, PowerShell)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GUI(Graphical User Interface)&lt;/b&gt;: 아이콘/윈도우 기반 그래픽 환경 (예: Windows, macOS)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;터치 인터페이스&lt;/b&gt;: 모바일 OS에서 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 프로그램 수행 (Program Execution)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램을 메모리에 적재하고 실행&lt;/li&gt;
&lt;li&gt;실행 중인 프로그램의 중단, 재개, 종료 기능 제공&lt;/li&gt;
&lt;li&gt;예: fork(), exec() 시스템 콜&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 입출력 연산 (I/O Operations)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자 프로그램은 직접 장치 제어 불가 &amp;rarr; OS가 대신 수행&lt;/li&gt;
&lt;li&gt;키보드 입력, 디스크 읽기/쓰기, 네트워크 송수신 등&lt;/li&gt;
&lt;li&gt;장치 드라이버를 통해 하드웨어 추상화&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 파일 시스템 조작 (File-System Manipulation)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일 생성, 삭제, 읽기/쓰기, 접근 권한 제어&lt;/li&gt;
&lt;li&gt;디렉토리 구조 관리&lt;/li&gt;
&lt;li&gt;예: open(), read(), write(), close() 시스템 콜&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 통신 (Communication)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스 간 통신(IPC, Inter-Process Communication) 기능 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공유 메모리(shared memory)&lt;/b&gt;: 동일 메모리 영역에 접근&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메시지 전달(message passing)&lt;/b&gt;: 커널을 통해 메시지 송수신&lt;/li&gt;
&lt;li&gt;예: 파이프(pipe), 소켓(socket), 큐(queue)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 오류 탐지 (Error Detection)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU, 메모리, I/O 장치 동작 중 발생하는 오류 감지 및 처리&lt;/li&gt;
&lt;li&gt;잘못된 명령 실행, 메모리 접근 위반(segmentation fault), 디스크 읽기 오류 등&lt;/li&gt;
&lt;li&gt;오류 발생 시 트랩을 발생시켜 운영체제가 개입&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 자원 할당 (Resource Allocation)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU 시간, 메모리, I/O 장치, 파일 등 한정된 자원을 효율적으로 분배&lt;/li&gt;
&lt;li&gt;스케줄링(scheduling) 기법 활용 (FCFS, RR, Priority 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제 서비스는 크게 **사용자 편의를 위한 서비스(UI, 실행, I/O, 파일, 통신)**와 **시스템 보호 및 효율성을 위한 서비스(오류 탐지, 자원 할당)**로 나눌 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;System Call (시스템 콜)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 사용자 프로그램이 운영체제의 커널이 제공하는 기능(입출력, 프로세스 제어, 메모리 관리 등)을 요청하는 &lt;b&gt;인터페이스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 사용자 모드 &amp;rarr; 커널 모드로 안전하게 전환하여 &lt;b&gt;특권 명령&lt;/b&gt; 실행 가능하게 해줌&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;read(), write(), open(), close() (파일 조작)&lt;/li&gt;
&lt;li&gt;fork(), exec(), wait() (프로세스 관리)&lt;/li&gt;
&lt;li&gt;socket(), connect(), send(), recv() (통신)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. API (응용 프로그래밍 인터페이스)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 응용 프로그램이 운영체제, 라이브러리, 프레임워크 기능을 쉽게 사용하도록 만든 &lt;b&gt;함수/메서드 집합&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 프로그래머가 직접 system call을 다루지 않고, &lt;b&gt;고수준 함수 호출&lt;/b&gt;로 편리하게 접근할 수 있게 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C의 stdio.h 라이브러리 &amp;rarr; 내부적으로 read()/write() 시스템 콜 호출&lt;/li&gt;
&lt;li&gt;Java의 FileInputStream &amp;rarr; OS의 파일 입출력 system call 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 관계&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;System Call&lt;/b&gt;: 운영체제 커널 기능에 직접 접근하는 인터페이스&lt;/li&gt;
&lt;li&gt;&lt;b&gt;API&lt;/b&gt;: 응용 프로그램이 쉽게 사용할 수 있도록 제공되는 &lt;b&gt;함수 인터페이스&lt;/b&gt; (보통 system call을 내부적으로 호출)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  즉,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API는 &lt;b&gt;프로그래머 친화적인 인터페이스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;System Call은 &lt;b&gt;운영체제 친화적인 인터페이스&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;통신(IPC)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메세지 전달, 공유 메모리&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 메시지 전달 (Message Passing)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개념: 프로세스들이 커널(운영체제)을 매개로 하여 메시지를 주고받음&lt;/li&gt;
&lt;li&gt;방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;send(destination, message)&lt;/li&gt;
&lt;li&gt;receive(source, message)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스 간에 &lt;b&gt;메모리를 공유하지 않음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;분산 시스템에서도 사용 가능 (네트워크 기반 통신)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;: 단순하고, 프로세스 간 &lt;b&gt;강한 독립성&lt;/b&gt; 보장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점&lt;/b&gt;: 커널 개입이 필요해 속도가 느릴 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;: 파이프(pipe), 소켓(socket), 메시지 큐(message queue)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 공유 메모리 (Shared Memory)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개념&lt;/b&gt;: 운영체제가 특정 메모리 영역을 &lt;b&gt;여러 프로세스가 공동으로 접근&lt;/b&gt;할 수 있도록 허용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 번 설정되면 커널 개입 없이 메모리 접근 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가장 빠른 IPC 방식&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주의점&lt;/b&gt;: 동시에 접근할 때 데이터가 꼬이지 않도록 &lt;b&gt;동기화 기법&lt;/b&gt; 필요 (세마포어, 뮤텍스)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;: POSIX shared memory (shm_open, mmap)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 비교 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 메시지 전달 (Message Passing) 공유 메모리 (Shared Memory)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&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&gt;
&lt;td&gt;속도&lt;/td&gt;
&lt;td&gt;상대적으로 느림 (커널 개입 필요)&lt;/td&gt;
&lt;td&gt;빠름 (직접 메모리 접근)&lt;/td&gt;
&lt;/tr&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&gt;
&lt;td&gt;동기화 필요성&lt;/td&gt;
&lt;td&gt;커널이 동기화 보장&lt;/td&gt;
&lt;td&gt;개발자가 직접 동기화 관리 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;활용 예시&lt;/td&gt;
&lt;td&gt;파이프, 소켓, 메시지 큐&lt;/td&gt;
&lt;td&gt;shm, mmap, DB 공유 메모리 캐시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;메시지 전달&lt;/b&gt;: 운영체제 커널을 통해 안전하게 통신, 하지만 속도는 느림.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공유 메모리&lt;/b&gt;: 속도가 빠르지만 동기화 문제 해결을 개발자가 직접 해야 함.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리에서 적재되어 실행중인 프로그램&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업을 할당받는 단위&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프로세스(Process)&lt;/b&gt;: 실행 중인 프로그램. &lt;b&gt;자원(메모리 공간, 파일, 핸들 등)을 할당받는 단위&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&amp;rarr; 커널이 &lt;b&gt;PCB&lt;/b&gt;(Process Control Block)로 관리: PID, 상태, 스케줄링 정보, 메모리 정보(페이지 테이블), 열려 있는 파일 등.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스레드(Thread)&lt;/b&gt;: 프로세스 안의 실행 흐름. &lt;b&gt;CPU 스케줄링의 단위&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&amp;rarr; 각 스레드는 **자신만의 스택, 레지스터 집합, 프로그램 카운터(PC)**를 갖고, &lt;b&gt;코드&amp;middot;데이터&amp;middot;힙은 프로세스 내 다른 스레드와 공유&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;프로세스의 전형적 메모리 구역(가상 메모리 레이아웃)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 순서는 보통의 개념도(낮은 주소 &amp;rarr; 높은 주소)입니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;텍스트(코드) 섹션 (text / code)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기계어 명령이 저장되는 구역 (보통 &lt;b&gt;읽기 전용&lt;/b&gt;, 공유 가능)&lt;/li&gt;
&lt;li&gt;여러 프로세스가 같은 실행 파일을 돌릴 때 코드 페이지를 공유해 메모리 절약 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터 섹션 (data)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;초기값이 있는 전역/정적 변수&lt;/b&gt;가 위치 (예: int g = 10;)&lt;/li&gt;
&lt;li&gt;프로세스마다 개별 복사본을 가짐(스레드 간 공유)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;BSS 섹션 (bss)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;초기값이 없는 전역/정적 변수&lt;/b&gt; (예: int g2;)&lt;/li&gt;
&lt;li&gt;로더가 0으로 초기화하여 시작&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;힙(Heap)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동적 할당 영역&lt;/b&gt; (malloc/free, new/delete)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;런타임에 필요해질수록 &amp;ldquo;위로&amp;rdquo;(주소 증가 방향) 확장&lt;/b&gt;되는 것이 관례&lt;/li&gt;
&lt;li&gt;여러 스레드가 &lt;b&gt;공유&lt;/b&gt; &amp;rarr; 동시성 안전을 위해 할당기 내부에 락/아레나 등 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;스택(Stack)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;함수 호출 프레임&lt;/b&gt;이 쌓이는 영역: &lt;b&gt;복귀 주소, 매개변수, 지역변수, 저장된 레지스터&lt;/b&gt; 등&lt;/li&gt;
&lt;li&gt;일반적으로 &lt;b&gt;&amp;ldquo;아래로&amp;rdquo;(주소 감소 방향) 성장&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스레드마다 독립 스택&lt;/b&gt;을 가짐 (스택 크기는 생성 시 정해지는 경우가 많음)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;(플랫폼에 따라) &lt;b&gt;mmap/공유 라이브러리 영역&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mmap, 공유 객체(.so/.dll) 등이 매핑되는 가변 영역&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념도 (단순화)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;낮은 주소
[ 텍스트 ] &amp;rarr; [ 데이터 ] &amp;rarr; [ BSS ] &amp;rarr; [ 힙 &amp;uarr; ] &amp;hellip; [ mmap 등 ] &amp;hellip; [ &amp;darr; 스택 ]
높은 주소

&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;프로그램 카운터(PC, Instruction Pointer)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;다음에 실행할 명령의 주소&lt;/b&gt;를 가리키는 레지스터.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스레드마다 하나씩&lt;/b&gt; 존재(컨텍스트 스위치 시 PC/레지스터 저장&amp;middot;복원).&lt;/li&gt;
&lt;li&gt;함수 호출 시: 호출 명령이 &lt;b&gt;복귀 주소를 스택에 저장&lt;/b&gt;, PC는 호출 대상 주소로 변경 &amp;rarr; ret 시 스택의 복귀 주소로 PC 복원.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;스택 자세히&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포함 내용:&lt;/li&gt;
&lt;li&gt;&lt;b&gt;복귀 주소(return address), 매개변수(arguments), 지역변수, 저장된 레지스터(예: 프레임 포인터/링크 레지스터)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;단위: &lt;b&gt;스택 프레임&lt;/b&gt;(함수 호출 1회에 해당)&lt;/li&gt;
&lt;li&gt;특징/주의:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Stack Overflow&lt;/b&gt;: 너무 깊은 재귀, 큰 지역배열 등으로 보호 페이지 침범&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스택은 매우 빠름&lt;/b&gt;(연속 메모리 + 단순 푸시/팝) / &lt;b&gt;수명은 블록/스코프에 종속&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;힙 자세히&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동적 수명&lt;/b&gt;: 필요할 때 할당(allocate), 더 이상 필요 없으면 해제(free)&lt;/li&gt;
&lt;li&gt;특징/주의:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;메모리 누수(Leak)&lt;/b&gt;: 해제를 잊으면 장기 실행 시 문제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Double Free / Use-After-Free&lt;/b&gt;: 이미 해제한 블록 재사용 &amp;rarr; 치명적 버그&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fragmentation&lt;/b&gt;: 조각화로 인한 큰 블록 할당 실패 가능&lt;/li&gt;
&lt;li&gt;멀티스레드 환경: &lt;b&gt;동시성 이슈&lt;/b&gt;(락 경합, 캐시 라인 경합 등) &amp;rarr; 현대 할당기는 아레나/슬랩 등으로 완화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;데이터 섹션 &amp;amp; BSS 요약&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터(data)&lt;/b&gt;: 초기값 있는 전역/정적(실행 파일 안에 초기값 저장)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BSS&lt;/b&gt;: 초기값 없는 전역/정적(로더가 0으로 초기화)&lt;/li&gt;
&lt;li&gt;공통: &lt;b&gt;프로세스 단위로 소유&lt;/b&gt;(스레드들이 공유)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;텍스트 섹션 요약&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;실행 코드&lt;/b&gt; 저장&lt;/li&gt;
&lt;li&gt;보통 &lt;b&gt;읽기 전용 + 실행 가능&lt;/b&gt;, &lt;b&gt;프로세스 간 공유 가능한 페이지&lt;/b&gt;로 매핑 돼 메모리 절약&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;1. 프로세스 상태 (Process States)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제는 프로세스를 관리하기 위해 여러 상태로 구분합니다. 대표적인 상태는 다음과 같습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;New (생성)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스가 생성되고 있는 상태&lt;/li&gt;
&lt;li&gt;PCB가 만들어지고, OS가 메모리/자원 할당 준비&lt;/li&gt;
&lt;li&gt;아직 실행은 시작되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Ready (준비완료)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행할 준비가 끝났지만 &lt;b&gt;CPU를 배정받지 못한 상태&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;메모리와 필요한 자원은 확보 완료&lt;/li&gt;
&lt;li&gt;스케줄러가 CPU를 배정하면 곧 실행 상태로 전환됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Running (실행)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU를 점유하고 &lt;b&gt;명령어를 수행 중인 상태&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;단일 코어에서는 한 시점에 하나의 프로세스만 실행 가능&lt;/li&gt;
&lt;li&gt;실행 중 인터럽트나 시간 할당량 만료 시 다시 &lt;b&gt;준비 상태&lt;/b&gt;로 전환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Waiting (대기, Blocked)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;I/O 요청, 이벤트 발생 대기&lt;/b&gt; 등으로 CPU가 아닌 외부 조건을 기다리는 상태&lt;/li&gt;
&lt;li&gt;예: 디스크 입출력 완료, 사용자 입력 등&lt;/li&gt;
&lt;li&gt;조건이 만족되면 준비 상태로 전환됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Terminated (종료)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스 실행이 끝난 상태&lt;/li&gt;
&lt;li&gt;PCB와 자원이 정리(해제)됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. PCB (Process Control Block, 프로세스 제어 블록)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제가 &lt;b&gt;프로세스를 관리하기 위해 유지하는 핵심 데이터 구조&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 프로세스마다 PCB가 1개씩 존재하며, 프로세스의 &amp;ldquo;신분증/이력카드&amp;rdquo; 같은 역할을 함.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PCB에 포함되는 정보&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;프로세스 상태&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;New, Ready, Running, Waiting, Terminated 중 현재 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로그램 카운터 (Program Counter, PC)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 실행할 명령어의 주소 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPU 레지스터 정보&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;범용 레지스터, 스택 포인터, PSW(Program Status Word) 등&lt;/li&gt;
&lt;li&gt;컨텍스트 스위칭 시 저장/복원되어 실행 재개 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스케줄링 정보&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우선순위, 스케줄링 큐 포인터, CPU 사용 시간 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리 관리 정보&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 테이블, 세그먼트 테이블, 메모리 경계 레지스터 등&lt;/li&gt;
&lt;li&gt;해당 프로세스가 접근 가능한 메모리 영역 기록&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;계정 및 자원 정보&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일 핸들, 입출력 장치 상태, 소유자 ID, 사용 권한 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 정리 그림 (흐름도)&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로세스 상태 전이 예시&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;   [New]
     &amp;darr;
   [Ready] &amp;larr; (I/O 완료) &amp;larr; [Waiting]
     &amp;darr; &amp;uarr;
  (스케줄링)   (시간 종료/인터럽트)
     &amp;darr; &amp;uarr;
   [Running]
     &amp;darr;
  [Terminated]

&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  요약:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프로세스 상태&lt;/b&gt;는 생성 &amp;rarr; 준비 &amp;rarr; 실행 &amp;rarr; 대기/종료로 전이되며, CPU&amp;middot;I/O 스케줄링에 따라 바뀜.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PCB&lt;/b&gt;는 프로세스의 모든 관리 정보를 담는 자료구조로, &lt;b&gt;컨텍스트 스위칭&lt;/b&gt;과 &lt;b&gt;스케줄링&lt;/b&gt;에 필수적임.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;쓰레드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업을 실행하는 단위&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스 안의 실행 흐름.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CPU 스케줄링의 단위&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 각 스레드는 **자신만의 스택, 레지스터 집합, 프로그램 카운터(PC)**를 갖고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드&amp;middot;데이터&amp;middot;힙은 프로세스 내 다른 스레드와 공유&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TCB(Thread Control Block)에 포함되는 정보&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드별로 필요한 최소 정보만 따로 가짐:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스레드 ID (TID)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로그램 카운터(PC)&lt;/b&gt;: 다음 실행할 명령어&lt;/li&gt;
&lt;li&gt;&lt;b&gt;레지스터 집합&lt;/b&gt;: 현재 CPU 레지스터 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스택 포인터&lt;/b&gt;: 각 스레드는 자기만의 스택을 가짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스케줄링 정보&lt;/b&gt;: 우선순위, 상태(Running, Ready, Waiting 등)&lt;/li&gt;
&lt;li&gt;(운영체제에 따라) 신호 처리 정보, TLS(Thread-Local Storage) 등&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;프로세스 스케줄링 (Process Scheduling)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제는 동시에 여러 프로세스가 실행되는 환경에서, &lt;b&gt;CPU를 누구에게 줄 것인지&lt;/b&gt;를 결정해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 담당하는 것이 **프로세스 스케줄러(Process Scheduler)**입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;목표&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU 및 시스템 자원의 효율적 활용&lt;/li&gt;
&lt;li&gt;사용자에게 빠른 응답 제공 (대화형 시스템)&lt;/li&gt;
&lt;li&gt;공평성과 우선순위 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;잡 큐(Job Queue)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템에 들어온 모든 프로세스가 대기하는 큐&lt;/li&gt;
&lt;li&gt;여기서 스케줄러가 선택해 실행 대기열(Ready Queue)로 보냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 스케줄러의 종류&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(1) 장기 스케줄러 (Long-Term Scheduler, Job Scheduler)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 어떤 프로세스를 &lt;b&gt;메모리에 올려 실행할지 결정&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행할 **잡 큐(Job Pool)**에서 프로세스를 선택 &amp;rarr; 메모리 적재&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행 프로세스의 전체 수를 제어&lt;/b&gt;하여 CPU와 I/O의 균형 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;효과&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;입출력 중심 프로세스&lt;/b&gt;와 &lt;b&gt;CPU 중심 프로세스&lt;/b&gt;를 적절히 혼합하여 자원 활용 극대화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;: 배치 시스템(batch system)에서 주로 사용됨&lt;/li&gt;
&lt;li&gt;현대의 &lt;b&gt;시분할 시스템&lt;/b&gt;에서는 장기 스케줄러가 거의 사용되지 않음 (대부분 &lt;b&gt;시스템이 자동&lt;/b&gt;으로 처리)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(2) 단기 스케줄러 (Short-Term Scheduler, CPU Scheduler)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: **실행 준비(Ready Queue)**에 있는 프로세스 중, 누구에게 CPU를 줄지 결정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행 시점&lt;/b&gt;: 매우 짧은 시간 단위로 동작 (ms 단위)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;효과&lt;/b&gt;: 시스템 반응성과 CPU 활용률에 직접적 영향&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로세스 특성 고려&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;입출력 중심 프로세스(I/O-bound process)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU는 짧게 쓰고, I/O 요청이 잦음&lt;/li&gt;
&lt;li&gt;빨리 실행해서 I/O 장치가 놀지 않도록 해주는 것이 중요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPU 중심 프로세스(CPU-bound process)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;계산 위주, CPU를 오래 사용&lt;/li&gt;
&lt;li&gt;I/O 요청이 적음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;rArr; 두 종류를 적절히 섞어야 전체 자원 활용이 좋아짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(3) 중기 스케줄러 (Medium-Term Scheduler) &amp;ndash; 선택적&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: &lt;b&gt;프로세스 실행을 일시 중단(suspend) &amp;rarr; 메모리에서 내보냈다가 &amp;rarr; 나중에 복귀&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이 과정을 **스와핑(Swapping)**이라 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;효과&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리 부족 시 부하를 줄이고, 다중 프로그래밍 정도를 제어&lt;/li&gt;
&lt;li&gt;우선순위 있는 프로세스가 자원을 빨리 확보할 수 있게 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 스와핑 (Swapping)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 프로세스를 **보조기억장치(디스크)**로 내보냈다가, 필요할 때 다시 메모리로 불러오는 과정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스는 원래 실행되던 &lt;b&gt;시점부터 재개&lt;/b&gt;됨 (PCB에 상태 저장)&lt;/li&gt;
&lt;li&gt;메모리 공간 확보 및 CPU 이용률 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;: 메모리 관리 유연성 증가, 다중 프로그래밍 향상&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점&lt;/b&gt;: 디스크 I/O 오버헤드 발생 &amp;rarr; 잦으면 성능 저하&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. 정리 표&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스케줄러 종류 동작 위치 역할 실행 빈도 주요 목적&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;장기 스케줄러&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;잡 큐 &amp;rarr; 메모리&lt;/td&gt;
&lt;td&gt;어떤 프로세스를 실행시킬지 선택&lt;/td&gt;
&lt;td&gt;느림 (분/초 단위)&lt;/td&gt;
&lt;td&gt;CPU/IO 밸런스 유지, 다중 프로그래밍 정도 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;단기 스케줄러&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;준비 큐 &amp;rarr; CPU&lt;/td&gt;
&lt;td&gt;다음 실행할 프로세스 선택&lt;/td&gt;
&lt;td&gt;매우 빠름 (ms 단위)&lt;/td&gt;
&lt;td&gt;응답속도 개선, CPU 활용 극대화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;중기 스케줄러&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;메모리 &amp;harr; 디스크&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  요약:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;장기 스케줄러&lt;/b&gt;: 잡 큐에서 메모리로 올릴 프로세스 선택 (CPU vs I/O 균형).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단기 스케줄러&lt;/b&gt;: Ready Queue에서 CPU를 줄 프로세스 선택 (밀리초 단위, 즉각적).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중기 스케줄러&lt;/b&gt;: 메모리 &amp;harr; 디스크로 스와핑, 부하 조절.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;프로세스 생성 (Process Creation)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제에서 새로운 프로세스가 생성될 때, 일반적으로 다음 단계가 일어납니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;부모 프로세스(Parent Process)가 자식 프로세스(Child Process)를 생성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Unix 계열: fork() 시스템 콜 사용&lt;/li&gt;
&lt;li&gt;Windows 계열: CreateProcess() API 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부모와 자식의 실행 관계&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;병행 실행(Concurrent Execution)&lt;/b&gt;: 부모는 계속 실행, 자식은 독립적으로 실행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부모가 대기(Wait)&lt;/b&gt;: 부모는 wait()를 호출하여 자식이 끝날 때까지 기다림&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로세스 주소 공간&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자식은 **부모의 복사본(Copy)**을 가짐 (코드, 데이터, 스택 등)&lt;/li&gt;
&lt;li&gt;하지만 별도의 &lt;b&gt;PID(Process ID)&lt;/b&gt; 부여 &amp;rarr; 독립된 실행 단위&lt;/li&gt;
&lt;li&gt;자식이 원하면 exec() 계열 호출로 &lt;b&gt;새로운 프로그램을 덮어씀&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 프로세스 종료와 관련 개념&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(1) 정상 종료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자식 프로세스가 exit() 호출 시 종료&lt;/li&gt;
&lt;li&gt;운영체제는 **종료 상태(exit status)**를 부모에게 전달&lt;/li&gt;
&lt;li&gt;부모는 wait()를 호출해 종료 상태를 회수 &amp;rarr; 자식 PCB가 해제됨&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(2) 좀비 프로세스 (Zombie Process)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 자식이 종료되었지만, 부모가 wait()를 호출하지 않아 &lt;b&gt;PCB가 해제되지 않은 상태&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행은 끝났지만 PCB는 그대로 남음 &amp;rarr; 프로세스 테이블에 기록 유지&lt;/li&gt;
&lt;li&gt;상태는 &amp;ldquo;Z&amp;rdquo; (Zombie)로 표시&lt;/li&gt;
&lt;li&gt;다수의 좀비가 생기면 &lt;b&gt;프로세스 테이블 고갈&lt;/b&gt; 문제 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(3) 고아 프로세스 (Orphan Process)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 부모가 먼저 종료되어 &lt;b&gt;부모가 없는 자식 프로세스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;처리 방법&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Unix 계열에서는 **init 프로세스(PID 1)**가 고아 프로세스를 자동으로 인수 &amp;rarr; 정상적으로 실행/종료 가능&lt;/li&gt;
&lt;li&gt;따라서 고아 프로세스는 시스템에 큰 문제는 일으키지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 그림으로 정리&lt;/h1&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;부모 fork()
   ├─ 부모 계속 실행
   └─ 자식 프로세스 생성
         ├─ 부모와 병행 실행
         ├─ 부모가 wait() 호출 &amp;rarr; 정상 회수
         ├─ 부모가 회수 안 함 &amp;rarr; [좀비 프로세스]
         └─ 부모 먼저 종료 &amp;rarr; [고아 프로세스]

&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 요약:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;자식은 부모의 복사본으로 생성&lt;/b&gt;되지만, 독립된 PID를 가짐.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부모와 자식은 병행 실행&lt;/b&gt; 가능, 또는 부모가 wait()로 자식 종료까지 대기 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;좀비 프로세스&lt;/b&gt;: 자식 종료 후 부모가 회수하지 않음 &amp;rarr; PCB만 남음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;고아 프로세스&lt;/b&gt;: 부모가 먼저 종료 &amp;rarr; init 프로세스가 대신 관리.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;프로세스 간 통신(IPC, Inter-Process Communication)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;필요성&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다중 프로세스 환경에서 &lt;b&gt;데이터 교환, 동기화, 협력 수행&lt;/b&gt;을 위해 사용&lt;/li&gt;
&lt;li&gt;OS는 안전성과 효율성을 위해 여러 가지 IPC 메커니즘을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. IPC 모델&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(1) &lt;b&gt;공유 메모리 시스템 (Shared Memory)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개념&lt;/b&gt;: 두 프로세스가 &lt;b&gt;같은 메모리 영역&lt;/b&gt;을 공유하여 데이터를 주고받음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 빠른 통신 방법 (커널 개입 최소화, 단순 메모리 접근)&lt;/li&gt;
&lt;li&gt;하지만 &lt;b&gt;동기화 문제&lt;/b&gt;(레이스 컨디션) 발생 가능 &amp;rarr; 세마포어, 뮤텍스 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;: 생산자-소비자 문제, 대규모 데이터 교환&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(2) &lt;b&gt;메시지 전달 시스템 (Message Passing)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개념&lt;/b&gt;: 운영체제가 제공하는 &lt;b&gt;커널 버퍼&lt;/b&gt;를 통해 프로세스들이 메시지를 송수신&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널을 거쳐야 해서 상대적으로 느림&lt;/li&gt;
&lt;li&gt;동기화 문제는 OS가 관리 &amp;rarr; 구현 간단, 안전성 높음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방식&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접 통신: 프로세스들이 서로의 ID를 알고 직접 메시지 교환&lt;/li&gt;
&lt;li&gt;간접 통신: 메일박스(mailbox), 포트(port) 같은 추상화된 채널 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 주요 IPC 기법&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(1) &lt;b&gt;파이프 (Pipe)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개념&lt;/b&gt;: 두 프로세스 간 &lt;b&gt;단방향 통신 채널&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한쪽은 쓰기(write), 다른 쪽은 읽기(read) 전용&lt;/li&gt;
&lt;li&gt;부모-자식 프로세스 간 자주 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;익명 파이프&lt;/b&gt;: 같은 계열 프로세스 간&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명명된 파이프(Named Pipe, FIFO)&lt;/b&gt;: 무관한 프로세스 간도 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(2) &lt;b&gt;메시지 큐 (Message Queue)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개념&lt;/b&gt;: 커널이 제공하는 &lt;b&gt;큐(Queue) 자료구조&lt;/b&gt;를 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비동기적 메시지 전달 가능&lt;/li&gt;
&lt;li&gt;메시지 우선순위 지정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(3) &lt;b&gt;소켓 (Socket)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개념&lt;/b&gt;: 네트워크 기반 IPC 기법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동일 시스템 내 프로세스뿐 아니라, 다른 시스템 간 통신도 가능&lt;/li&gt;
&lt;li&gt;TCP/UDP 기반으로 동작 &amp;rarr; 클라이언트-서버 모델에 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(4) &lt;b&gt;RPC (Remote Procedure Call)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개념&lt;/b&gt;: 원격 프로세스의 함수를 &lt;b&gt;마치 로컬 함수처럼 호출&lt;/b&gt;하는 기법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크/분산 시스템에서 자주 사용&lt;/li&gt;
&lt;li&gt;호출 측은 네트워크 세부사항을 몰라도 함수 호출처럼 사용 가능&lt;/li&gt;
&lt;li&gt;내부적으로는 메시지 전달, 직렬화, 소켓 통신 등으로 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(5) &lt;b&gt;기타 IPC&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;세마포어 (Semaphore)&lt;/b&gt;: 동기화 및 상호 배제를 위한 카운터 기반 메커니즘&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공유 파일 (Shared File)&lt;/b&gt;: 파일을 매개로 데이터 교환, 단 느리고 동기화 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. 정리 표&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방식 특징 장점 단점 활용 예&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&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;td&gt;생산자-소비자 버퍼&lt;/td&gt;
&lt;/tr&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;td&gt;분산 환경 프로세스 간 통신&lt;/td&gt;
&lt;/tr&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;td&gt;Unix 파이프(`&lt;/td&gt;
&lt;/tr&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;td&gt;IPC 채팅, 로깅&lt;/td&gt;
&lt;/tr&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;td&gt;웹 서버-클라이언트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RPC&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;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 요약:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;IPC 모델&lt;/b&gt;: 공유 메모리 vs 메시지 전달&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주요 기법&lt;/b&gt;: 파이프, 메시지 큐, 소켓, RPC 등&lt;/li&gt;
&lt;li&gt;&lt;b&gt;선택 기준&lt;/b&gt;: 데이터 크기, 속도 요구, 안정성, 프로세스 관계(같은 시스템 vs 분산 시스템)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스레드(Thread)의 정의&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU 이용의 기본 단위&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;프로세스 내에서 실행되는 &lt;b&gt;실행 흐름 단위&lt;/b&gt;를 의미합니다.&lt;/li&gt;
&lt;li&gt;프로세스는 최소 1개의 스레드를 가지며, 멀티스레딩을 통해 하나의 프로세스에서 여러 스레드가 병렬로 실행될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스레드의 구성 요소&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드마다 독립적으로 가지는 부분:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Thread ID&lt;/b&gt; : 스레드 고유 식별자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PC(Program Counter)&lt;/b&gt; : 명령어의 실행 위치&lt;/li&gt;
&lt;li&gt;&lt;b&gt;레지스터 집합&lt;/b&gt; : 연산에 필요한 임시 데이터 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스택(Stack)&lt;/b&gt; : 함수 호출, 지역 변수 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드가 같은 프로세스 내에서 &lt;b&gt;공유&lt;/b&gt;하는 부분:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;코드(Code) 영역&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터(Data) 영역&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;운영체제 자원&lt;/b&gt; (파일 핸들, 소켓 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스레드의 종류&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;사용자 스레드 (User Thread)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자 수준 라이브러리에서 지원하는 스레드&lt;/li&gt;
&lt;li&gt;커널이 직접 인식하지 못하고, 하나의 프로세스 단위로 스케줄링됨&lt;/li&gt;
&lt;li&gt;장점: 생성/전환 속도가 빠르고, 오버헤드가 적음&lt;/li&gt;
&lt;li&gt;단점: 하나의 스레드가 커널 호출로 블록되면, 전체 프로세스가 블록될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널 스레드 (Kernel Thread)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;운영체제 커널이 직접 관리하는 스레드&lt;/li&gt;
&lt;li&gt;커널이 스케줄링하므로 다중 CPU 활용 가능&lt;/li&gt;
&lt;li&gt;단점: 생성/전환 시 시스템 콜이 필요해 비용이 크다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  정리하면, &lt;b&gt;스레드 = 프로세스 내 실행 흐름의 최소 단위&lt;/b&gt;이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;**독립적인 실행 상태(PC, 레지스터, 스택)**는 따로 가지지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드/데이터/자원&lt;/b&gt;은 같은 프로세스 내 스레드끼리 공유한다는 특징이 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;fork()와 스레드&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;POSIX 표준&lt;/b&gt;에 따르면 fork()는 &lt;b&gt;호출한 스레드만 복사&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;즉:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부모 프로세스 &amp;rarr; 여러 스레드 존재 가능&lt;/li&gt;
&lt;li&gt;자식 프로세스 &amp;rarr; &lt;b&gt;fork를 호출한 그 스레드만&lt;/b&gt; 존재 (다른 스레드는 복사되지 않음)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이유: 모든 스레드를 그대로 복제하면 동기화 상태, 락(lock) 보유 상태 등이 복잡해져서 일관성을 깨뜨릴 수 있기 때문이에요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  따라서, fork() 후에는 자식 프로세스는 단일 스레드 상태로 시작하고, 필요하면 exec()를 호출해 새 프로그램으로 덮어씌우는 경우가 많습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  exec()&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;exec 계열 함수(execl, execv, execve 등)는 &lt;b&gt;현재 프로세스 전체를 새로운 프로그램으로 대체&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;프로세스 메모리 공간, 코드, 데이터, 스택이 모두 교체되고, &lt;b&gt;기존 스레드는 모두 사라집니다&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;즉:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호출한 프로세스의 PID는 유지됨&lt;/li&gt;
&lt;li&gt;실행 이미지는 완전히 새 프로그램으로 바뀜&lt;/li&gt;
&lt;li&gt;남는 스레드 없음 &amp;rarr; 새 프로그램은 항상 &lt;b&gt;단일 스레드&lt;/b&gt;로 시작&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 정리하면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;fork()&lt;/b&gt; &amp;rarr; 호출한 스레드만 복사 (자식은 단일 스레드 상태).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;exec()&lt;/b&gt; &amp;rarr; 전체 프로세스를 대체 (모든 스레드 사라지고 새 프로그램 시작).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  스레드 풀(Thread Pool)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램 시작 시 &lt;b&gt;일정 개수의 스레드를 미리 생성&lt;/b&gt;해두고, 이 스레드들을 작업(Task) 큐에 있는 일을 처리하는 데 재사용하는 방식.&lt;/li&gt;
&lt;li&gt;즉, 매번 새로운 스레드를 만들고 없애는 대신, **재활용(Recycling)**하는 구조.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 동작 방식&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;스레드 풀 초기화 &amp;rarr; 정해진 개수의 워커 스레드(worker thread) 생성.&lt;/li&gt;
&lt;li&gt;클라이언트/사용자가 작업을 요청 &amp;rarr; 작업이 **작업 큐(task queue)**에 들어감.&lt;/li&gt;
&lt;li&gt;대기 중이던 워커 스레드가 큐에서 작업을 꺼내 실행.&lt;/li&gt;
&lt;li&gt;작업 완료 후 &amp;rarr; 스레드는 종료되지 않고 다시 큐를 감시하며 다음 작업 대기.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;생성/제거 오버헤드 감소&lt;/b&gt;: 스레드를 매번 만들지 않고 재사용하므로 성능 향상.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동시성 제어 용이&lt;/b&gt;: 풀 크기를 제한하면 동시에 실행되는 스레드 수를 조절 가능 &amp;rarr; CPU 과부하 방지.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응답 시간 단축&lt;/b&gt;: 요청이 들어올 때마다 바로 실행할 스레드가 준비되어 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❌ 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;풀 크기 설정 어려움&lt;/b&gt;: 너무 작으면 병목, 너무 크면 문맥 전환 오버헤드 발생.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장시간 블로킹 작업 문제&lt;/b&gt;: 워커 스레드가 오래 점유되면 다른 작업이 밀릴 수 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;복잡성 증가&lt;/b&gt;: 큐 관리, 예외 처리, 동기화 관리가 필요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  동기(Synchronous) vs 비동기(Asynchronous)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동기(Sync)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청한 작업이 &lt;b&gt;끝날 때까지 호출한 쪽이 결과를 기다림&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;제어 흐름이 &lt;b&gt;작업 완료 시점과 맞춰져 있음&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;예: read() 호출 &amp;rarr; 데이터 다 읽을 때까지 반환하지 않음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비동기(Async)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청한 작업을 &lt;b&gt;백그라운드에서 수행&lt;/b&gt;하고, 호출한 쪽은 &lt;b&gt;즉시 반환받음&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;결과는 &lt;b&gt;나중에 이벤트, 콜백, Future/Promise&lt;/b&gt; 등을 통해 알림.&lt;/li&gt;
&lt;li&gt;예: aio_read() &amp;rarr; 바로 return, 읽기 완료되면 알림.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  즉, &amp;ldquo;동기는 결과 반환을 기다리고, 비동기는 기다리지 않는다&amp;rdquo;는 표현은 &lt;b&gt;정확합니다&lt;/b&gt; ✅&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  블로킹(Blocking) vs 논블로킹(Non-blocking)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;블로킹(Blocking)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호출한 함수가 &lt;b&gt;즉시 결과를 줄 수 없으면&lt;/b&gt; &amp;rarr; 호출한 스레드를 멈추고 대기.&lt;/li&gt;
&lt;li&gt;제어권을 커널/라이브러리 쪽에 넘겨주고, 작업이 끝날 때까지 안 돌려줌.&lt;/li&gt;
&lt;li&gt;예: read(fd, buf, size)에서 읽을 데이터가 없으면, 데이터가 올 때까지 멈춤.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;논블로킹(Non-blocking)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호출한 함수가 &lt;b&gt;즉시 결과를 줄 수 없으면 에러/특정 코드(EAGAIN 등)를 반환&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;즉, 제어권을 바로 돌려줌.&lt;/li&gt;
&lt;li&gt;예: read(fd, buf, size) 호출 시 읽을 게 없으면 1 즉시 반환.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  따라서 &amp;ldquo;블로킹은 제어권을 넘기고, 논블로킹은 제어권을 넘기지 않는다&amp;rdquo;는 표현은 &lt;b&gt;살짝 부정확&lt;/b&gt;해요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확히는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;블로킹&lt;/b&gt; &amp;rarr; 제어권을 넘겨주고 작업 완료까지 반환 안 함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;논블로킹&lt;/b&gt; &amp;rarr; 제어권을 넘겨주긴 하지만, 결과 없으면 즉시 반환해서 호출자가 다시 사용할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  한눈에 정리 (표)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 동기 비동기&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;블로킹&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;작업 끝날 때까지 기다림 (ex. read())&lt;/td&gt;
&lt;td&gt;콜백/알림을 쓰지만, 호출 자체는 블로킹됨 (드묾)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;논블로킹&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;즉시 반환, 호출자가 반복 확인해야 함 (ex. read() + 반복)&lt;/td&gt;
&lt;td&gt;즉시 반환 + 완료되면 알림/콜백 (ex. 이벤트 기반 I/O)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 정리하면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동기/비동기 &amp;rarr; &lt;b&gt;&amp;ldquo;작업 완료 통보 방식&amp;rdquo;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;블로킹/논블로킹 &amp;rarr; &lt;b&gt;&amp;ldquo;호출 시 제어권 반환 여부&amp;rdquo;&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-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CPU 스케줄링&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU를 프로세스 들 간에 교환함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 프로세스 스케줄링을 뜻함&lt;/p&gt;
&lt;h1&gt;CPU 스케줄러 (CPU Scheduler)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU가 유휴 상태가 될 때마다 **운영체제(OS)**는 **준비 완료 큐(Ready Queue)**에 있는 프로세스들 중 하나를 골라 실행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정은 **단기 스케줄러(Short-term Scheduler)**가 담당합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 메모리 내에서 실행 준비가 된 프로세스 중 하나를 선택 &amp;rarr; CPU에 할당&lt;/li&gt;
&lt;li&gt;&lt;b&gt;목표&lt;/b&gt;: CPU 이용률 극대화, 처리량 증가, 대기 시간&amp;middot;응답 시간 최소화, 공정성 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 스케줄링 종류&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;① 비선점 스케줄링 (Non-preemptive Scheduling)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 프로세스가 CPU를 할당받으면 &lt;b&gt;자신이 종료되거나 대기 상태로 전환될 때까지&lt;/b&gt; CPU를 계속 사용&lt;/li&gt;
&lt;li&gt;다른 프로세스는 기다려야 함&lt;/li&gt;
&lt;li&gt;장점: 컨텍스트 스위칭 오버헤드가 적음&lt;/li&gt;
&lt;li&gt;단점: 응답 시간이 길어질 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시 알고리즘&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FCFS (First Come First Serve)&lt;/li&gt;
&lt;li&gt;SJF (Shortest Job First)&lt;/li&gt;
&lt;li&gt;HRN (Highest Response Ratio Next)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;② 선점 스케줄링 (Preemptive Scheduling)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 중인 프로세스가 있더라도 &lt;b&gt;우선순위가 더 높은 프로세스가 도착하면 CPU를 빼앗아 올 수 있음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;장점: 응답 시간이 짧아져 대화형 시스템에 적합&lt;/li&gt;
&lt;li&gt;단점: 잦은 컨텍스트 스위칭으로 오버헤드 증가, 교착 상태(deadlock)나 기아(starvation) 발생 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에이징(Aging)&lt;/b&gt; 기법으로 낮은 우선순위 프로세스의 기아 문제를 완화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시 알고리즘&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SRTF (Shortest Remaining Time First)&lt;/li&gt;
&lt;li&gt;Priority Scheduling&lt;/li&gt;
&lt;li&gt;Round Robin (RR)&lt;/li&gt;
&lt;li&gt;Multilevel Queue / Feedback Queue&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 디스패처 (Dispatcher)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 단기 스케줄러가 선택한 프로세스에게 실제로 CPU 제어권을 넘겨주는 모듈&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주요 역할&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨텍스트 스위칭 (context switching)&lt;/li&gt;
&lt;li&gt;사용자 모드 전환&lt;/li&gt;
&lt;li&gt;프로그램의 올바른 위치(PC, 레지스터)에서 실행 재개&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디스패처 지연 (Dispatcher Latency)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 프로세스에서 다른 프로세스로 CPU 제어가 넘어가는 데 걸리는 시간&lt;/li&gt;
&lt;li&gt;&amp;rarr; 너무 길면 시스템 성능 저하&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  정리하면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;단기 스케줄러&lt;/b&gt;: 어떤 프로세스가 CPU를 쓸지 선택&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디스패처&lt;/b&gt;: 실제로 CPU를 넘겨주는 실행자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비선점/선점&lt;/b&gt; 여부에 따라 응답성과 공정성이 달라짐&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;임계구역 문제&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;임계구역 문제 (Critical Section Problem)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 프로세스가 공유 자원(메모리, 파일, I/O 장치 등)에 접근할 때 **경쟁 조건(Race Condition)**을 피하기 위해 필요한 규칙을 정의한 것. 이를 위해 운영체제는 임계구역에 대한 접근을 제어하는 &lt;b&gt;프로토콜&lt;/b&gt;을 설계해야 함.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 요구 조건 (3가지 조건)&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;상호 배제 (Mutual Exclusion)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 번에 하나의 프로세스만 임계구역에 진입할 수 있어야 함.&lt;/li&gt;
&lt;li&gt;다른 프로세스가 이미 임계구역에 있으면, 나머지는 대기해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;진행 (Progress)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;임계구역에 들어가려는 프로세스가 없을 경우, 들어갈 프로세스를 결정하는 데 불필요한 지연이 없어야 함.&lt;/li&gt;
&lt;li&gt;즉, CPU가 놀고 있는데도 임계구역 진입을 막으면 안 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;한정된 대기 (Bounded Waiting)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 프로세스가 임계구역 진입을 무한정 기다리게 두어서는 안 됨.&lt;/li&gt;
&lt;li&gt;언젠가는 반드시 임계구역에 들어갈 수 있어야 한다는 &lt;b&gt;공정성 보장 조건&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;커널의 선점 여부&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제의 &lt;b&gt;커널이 프로세스를 언제까지 실행시키는지&lt;/b&gt;와 관련 있음.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;비선점형 커널 (Non-preemptive Kernel)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널 모드에 들어간 프로세스는 &lt;b&gt;스스로 CPU를 양보하거나 작업이 끝날 때까지&lt;/b&gt; 계속 실행.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;: 동기화가 상대적으로 단순 &amp;rarr; 임계구역 충돌 발생 확률 낮음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점&lt;/b&gt;: 한 프로세스가 오래 점유하면 다른 프로세스 대기 시간이 길어짐 &amp;rarr; 시스템 반응성 저하.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. &lt;b&gt;선점형 커널 (Preemptive Kernel)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커널 모드에서 실행 중이더라도 운영체제가 &lt;b&gt;강제로 CPU를 빼앗아 다른 프로세스 실행 가능&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;: 시스템 반응성 &amp;uarr; (특히 실시간 시스템에 적합).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점&lt;/b&gt;: 임계구역에서 선점되면 &lt;b&gt;동기화 문제&lt;/b&gt; 발생 &amp;rarr; 세마포어, 뮤텍스, 모니터 같은 동기화 도구 필요.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 요약&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;임계구역 문제 &amp;rarr; 상호배제, 진행, 한정된 대기 조건 충족 필요&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비선점형 커널&lt;/b&gt;은 단순하지만 비효율적, &lt;b&gt;선점형 커널&lt;/b&gt;은 효율적이지만 동기화 기법 필요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;피터슨 알고리즘&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;피터슨 알고리즘 (Peterson&amp;rsquo;s Algorithm)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 두 개의 프로세스가 하나의 공유 자원을 안전하게 사용할 수 있도록 보장하는 &lt;b&gt;소프트웨어 기반 임계구역 해결 알고리즘&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;아이디어&lt;/b&gt;: &quot;상호 배제&quot;를 위해 &lt;b&gt;플래그 변수 + turn 변수&lt;/b&gt;를 이용해 락(Locking) 개념을 구현.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 기본 구조&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;flag[2]&lt;/b&gt;: 프로세스가 임계구역에 들어가고 싶다는 의사를 표시 (true/false)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;turn&lt;/b&gt;: 두 프로세스 중 &lt;b&gt;누구 차례인지&lt;/b&gt;를 알려주는 변수&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;// 프로세스 i의 코드 (i = 0 or 1)
do {
    flag[i] = true;              // 임계구역 진입 의사 표시
    turn = j;                    // 상대방 차례로 설정
    while (flag[j] &amp;amp;&amp;amp; turn == j); // 상대방이 원하고 차례이면 대기

    // ---- 임계구역 시작 ----
    critical_section();
    // ---- 임계구역 끝 ----

    flag[i] = false;             // 임계구역 나옴
    remainder_section();
} while (true);

&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 특징 (3대 조건 충족 여부)&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;상호 배제 (Mutual Exclusion)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 프로세스가 동시에 임계구역에 진입할 수 없음.&lt;/li&gt;
&lt;li&gt;flag와 turn 조합으로 보장.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;진행 (Progress)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;임계구역을 원하지 않는 프로세스는 다른 프로세스의 진입을 방해하지 않음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;한정된 대기 (Bounded Waiting)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 프로세스가 무한정 기다리지 않도록 보장 (turn 변수가 번갈아 기회를 줌).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 장단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순수 &lt;b&gt;소프트웨어적 방법&lt;/b&gt; (하드웨어 지원 필요 없음).&lt;/li&gt;
&lt;li&gt;임계구역 문제의 3대 조건을 모두 만족.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;두 프로세스 환경에서만 동작&lt;/b&gt; (N개 프로세스는 불가능).&lt;/li&gt;
&lt;li&gt;현대의 멀티코어 환경에서는 &lt;b&gt;메모리 재정렬/캐시 동기화 문제&lt;/b&gt; 때문에 실제로는 쓰이지 않음.&lt;/li&gt;
&lt;li&gt;대신 하드웨어 기반 &lt;b&gt;Test-and-Set, Compare-and-Swap&lt;/b&gt; 같은 명령어나 &lt;b&gt;세마포어, 뮤텍스, 모니터&lt;/b&gt;를 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 락킹과의 관계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Peterson 알고리즘은 &lt;b&gt;락(Lock) 개념을 소프트웨어적으로 구현한 초기 방식&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;단일 CPU 환경에서는 &quot;인터럽트 금지&quot; 방식으로도 해결 가능했지만, 멀티코어&amp;middot;멀티프로세서 환경에서는 하드웨어 락 지원 없이는 Peterson 알고리즘이 깨질 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  정리: &lt;b&gt;Peterson 알고리즘은 교과서적 중요성&lt;/b&gt;이 크고, 실제 시스템에서는 &lt;b&gt;하드웨어 명령어나 동기화 도구&lt;/b&gt;가 더 많이 사용됨.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;뮤텍스 락 (Mutex Lock)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Mutual Exclusion&lt;/b&gt;의 줄임말.&lt;/li&gt;
&lt;li&gt;임계구역(critical section)에 진입하기 전에 **락(lock)**을 획득해야 하고, 임계구역에서 나오면서 반드시 **락을 해제(unlock)**해야 함.&lt;/li&gt;
&lt;li&gt;한 시점에는 오직 &lt;b&gt;하나의 프로세스/스레드만 락을 보유&lt;/b&gt;할 수 있음 &amp;rarr; &lt;b&gt;상호 배제 보장&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 기본 원리&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;// Pseudo code
acquire(lock);     // 임계구역 들어가기 전에 락 획득
critical_section();
release(lock);     // 임계구역 빠져나올 때 락 반환

&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;acquire()&lt;/b&gt;: 락을 얻을 수 있을 때까지 기다림.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;release()&lt;/b&gt;: 락을 다른 프로세스가 사용할 수 있도록 반환.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구현이 단순하고 직관적.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;선점형 커널 환경&lt;/b&gt;에서도 안전하게 임계구역 보호 가능.&lt;/li&gt;
&lt;li&gt;현대 운영체제에서 &lt;b&gt;스레드 동기화 기본 도구&lt;/b&gt;로 널리 사용됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 단점&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;바쁜 대기 (Busy Waiting, Spin Lock)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스가 락을 얻을 때까지 &lt;b&gt;계속 루프를 돌며 기다림&lt;/b&gt; &amp;rarr; CPU 낭비.&lt;/li&gt;
&lt;li&gt;예:&lt;/li&gt;
&lt;li&gt;while (lock == 1); // 다른 스레드가 락 반환할 때까지 계속 반복&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데드락(Deadlock)&lt;/b&gt; 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;락을 해제하지 못하거나, 여러 락을 교착 상태로 요청할 경우 발생.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;우선순위 역전(Priority Inversion)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;낮은 우선순위 프로세스가 락을 보유하면, 높은 우선순위 프로세스도 기다려야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 개선 방법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;세마포어(Semaphore)&lt;/b&gt;: 대기 상태를 큐에 넣고 블록(block) &amp;rarr; 바쁜 대기 해결.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모니터(Monitor)&lt;/b&gt;: 고수준 언어에서 동기화 지원.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;혼합 기법&lt;/b&gt;: 짧은 시간은 스핀 락, 오래 걸리면 블록 (하이브리드 락).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 요약&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;뮤텍스 락은 상호 배제를 보장하는 가장 단순한 방법&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;하지만 기본 구현은 &lt;b&gt;바쁜 대기(Spin Lock)&lt;/b&gt; 문제를 가진다.&lt;/li&gt;
&lt;li&gt;실제 시스템에서는 세마포어나 모니터 등과 함께 개선된 형태로 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;세마포어 (Semaphore)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1965년 &lt;b&gt;Dijkstra&lt;/b&gt;가 제안한 &lt;b&gt;동기화 기법&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;공유 자원에 대한 접근을 제어하기 위해 **정수 변수 S와 두 개의 원자적 연산(wait, signal)**을 사용.&lt;/li&gt;
&lt;li&gt;커널이 제공하는 &lt;b&gt;원자적 연산&lt;/b&gt;이기 때문에 동시 실행 환경에서도 안전하게 동작.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 두 가지 연산&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;wait (P 연산)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원을 얻기 전 검사&lt;/li&gt;
&lt;li&gt;사용 가능 자원이 없으면 대기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;wait(S) { while (S &amp;lt;= 0); // 바쁜 대기 (Spin) or 블록 S--; }&lt;/li&gt;
&lt;li&gt;&lt;b&gt;signal (V 연산)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원 사용이 끝난 후 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;signal(S) { S++; }&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 세마포어의 종류&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;이진 세마포어 (Binary Semaphore)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값이 &lt;b&gt;0 또는 1&lt;/b&gt;만 가짐.&lt;/li&gt;
&lt;li&gt;사실상 &lt;b&gt;뮤텍스 락과 동일하게 동작&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;임계구역 보호에 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;계수 세마포어 (Counting Semaphore)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값이 &lt;b&gt;0 이상 정수&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;동시에 여러 개의 프로세스가 공유 자원에 접근할 수 있도록 허용.&lt;/li&gt;
&lt;li&gt;예: DB 연결 풀, 프린터 3대 &amp;rarr; 초기값 S=3.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 특징&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;뮤텍스보다 일반적&lt;/b&gt;: 여러 자원 동시 관리 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;바쁜 대기 문제 해결 가능&lt;/b&gt;: 대기 중인 프로세스를 큐에 넣어 블록시키고, signal 시 깨움.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그래밍 실수 위험 (wait/signal 불일치 &amp;rarr; 데드락, 기아 문제).&lt;/li&gt;
&lt;li&gt;관리가 어렵기 때문에 고수준 언어에서는 **모니터(Monitor)**가 더 선호됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Mutex vs Semaphore 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 뮤텍스(Mutex) 세마포어(Semaphore)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;자원 수&lt;/td&gt;
&lt;td&gt;1개만 보호&lt;/td&gt;
&lt;td&gt;N개 자원까지 보호 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;값&lt;/td&gt;
&lt;td&gt;0/1 (binary)&lt;/td&gt;
&lt;td&gt;0 이상 정수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;소유권&lt;/td&gt;
&lt;td&gt;스레드가 소유 (owner만 unlock 가능)&lt;/td&gt;
&lt;td&gt;소유 개념 없음&lt;/td&gt;
&lt;/tr&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&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 요약&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;세마포어 = 정수 변수 + wait/signal 연산&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이진 세마포어 = 뮤텍스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;계수 세마포어 = 여러 자원 관리 가능&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;하지만 프로그래밍 복잡성 때문에 실무에서는 주로 &lt;b&gt;뮤텍스 + 조건변수, 모니터&lt;/b&gt;를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 모니터(Monitor)란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;고수준 언어에서 제공하는 동기화 도구&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;세마포어처럼 직접 wait/signal을 다루는 대신, &lt;b&gt;언어 차원에서 임계구역 진입/대기/신호를 관리&lt;/b&gt;해줌.&lt;/li&gt;
&lt;li&gt;즉, 프로그래머가 동기화 로직을 일일이 짜는 대신, &lt;b&gt;모니터가 자동으로 상호배제를 보장&lt;/b&gt;해 줌.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ &lt;b&gt;세마포어의 단점&lt;/b&gt;(코드 복잡성, wait/signal 불일치 &amp;rarr; 교착상태 가능)을 해결하기 위한 &lt;b&gt;추상화 기법&lt;/b&gt;.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 모니터의 구성 요소&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;공유 변수 (Shared Variables)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모니터 내부에서만 접근 가능한 자원(데이터 구조).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로시저 (Procedures)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공유 변수를 접근할 수 있는 루틴.&lt;/li&gt;
&lt;li&gt;임계구역은 이 루틴 안에서만 존재하며, 자동으로 &lt;b&gt;상호배제&lt;/b&gt; 보장.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조건 변수 (Condition Variables)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모니터 안에서 &lt;b&gt;프로세스 동기화&lt;/b&gt;를 위해 사용.&lt;/li&gt;
&lt;li&gt;wait() : 현재 프로세스를 조건 대기 큐에 넣고, 다른 프로세스에게 제어권 넘김.&lt;/li&gt;
&lt;li&gt;signal() : 대기 중인 프로세스를 깨움.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 모니터 동작 방식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 번에 &lt;b&gt;하나의 프로세스만 모니터 내부 실행 가능&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;다른 프로세스가 들어오면 자동으로 블록됨 (상호배제 보장).&lt;/li&gt;
&lt;li&gt;조건 변수로 대기/신호를 제어 &amp;rarr; &lt;b&gt;세마포어 wait/signal과 유사하지만 자동 관리됨&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 예시 (생산자-소비자 문제)&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;monitor ProducerConsumer {
    int buffer[N];
    int count = 0;
    condition notFull, notEmpty;

    procedure insert(item) {
        if (count == N) wait(notFull);  // 버퍼가 꽉 찼으면 대기
        buffer[count++] = item;
        signal(notEmpty);               // 소비자에게 알림
    }

    procedure remove() {
        if (count == 0) wait(notEmpty); // 버퍼가 비었으면 대기
        item = buffer[--count];
        signal(notFull);                // 생산자에게 알림
        return item;
    }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생산자는 insert() 호출 &amp;rarr; 버퍼 꽉 차면 wait(notFull).&lt;/li&gt;
&lt;li&gt;소비자는 remove() 호출 &amp;rarr; 버퍼 비면 wait(notEmpty).&lt;/li&gt;
&lt;li&gt;모니터는 &lt;b&gt;상호배제 + 동기화&lt;/b&gt;를 자동 관리.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 장단점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상호배제 자동 보장 &amp;rarr; 프로그래머가 실수로 놓칠 위험 감소.&lt;/li&gt;
&lt;li&gt;코드 가독성 높고, 동기화 오류 줄어듦.&lt;/li&gt;
&lt;li&gt;고급 언어(Java, C#, Python 등)에서 널리 지원 (synchronized, lock 구문 등).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구현이 복잡해 하드웨어/저수준 언어(C)에서는 직접 지원 어렵다.&lt;/li&gt;
&lt;li&gt;잘못된 조건 변수 사용 시 &lt;b&gt;기아 가능성&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 현대 운영체제와 모니터&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Java&lt;/b&gt; &amp;rarr; synchronized 블록, wait() / notify()&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C#&lt;/b&gt; &amp;rarr; lock, Monitor.Wait() / Monitor.Pulse()&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Python&lt;/b&gt; &amp;rarr; threading.Condition&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 세마포어는 OS 수준의 원시적 도구라면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모니터는 언어/런타임 수준의 고수준 동기화 도구&lt;/b&gt;라 할 수 있음.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 요약&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;모니터&lt;/b&gt;는 세마포어보다 추상화된 동기화 도구.&lt;/li&gt;
&lt;li&gt;프로세스/스레드가 동시에 모니터 안에 들어올 수 없도록 &lt;b&gt;상호배제를 자동 보장&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;조건 변수(wait, signal)를 통해 세밀한 동기화 제어 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;교착상태 &amp;amp; 기아&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 교착상태 (Deadlock)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 프로세스들이 &lt;b&gt;서로가 가진 자원을 기다리며 무한 대기 상태&lt;/b&gt;에 빠진 것.&lt;/li&gt;
&lt;li&gt;예: P1은 프린터를 가지고 플로터를 기다리고, P2는 플로터를 가지고 프린터를 기다리는 경우.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;발생 조건 (Coffman의 4가지 조건 &amp;ndash; 모두 만족해야 발생)&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;상호 배제 (Mutual Exclusion)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;자원은 한 번에 한 프로세스만 사용 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;점유 대기 (Hold and Wait)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;최소 하나의 자원을 점유한 채로 다른 자원을 기다림.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비선점 (No Preemption)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;할당된 자원은 강제로 빼앗을 수 없음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순환 대기 (Circular Wait)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;프로세스들이 원형으로 서로가 가진 자원을 기다림.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 기아 (Starvation)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 특정 프로세스가 &lt;b&gt;우선순위 문제나 자원 할당 정책&lt;/b&gt; 때문에 무한히 자원을 얻지 못하고 기다리는 상태.&lt;/li&gt;
&lt;li&gt;예: 우선순위 스케줄링에서 낮은 우선순위 프로세스가 계속 밀려 실행되지 못하는 경우.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;원인&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우선순위 기반 스케줄링&lt;/li&gt;
&lt;li&gt;자원 할당 시 특정 프로세스에 불리한 정책&lt;/li&gt;
&lt;li&gt;무한 대기 큐 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 우선순위 역전 (Priority Inversion)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: &lt;b&gt;낮은 우선순위 프로세스&lt;/b&gt;가 자원을 가지고 있어서, &lt;b&gt;높은 우선순위 프로세스&lt;/b&gt;가 그 자원을 기다리며 실행되지 못하는 상황.&lt;/li&gt;
&lt;li&gt;중간 우선순위 프로세스가 계속 실행되면 높은 우선순위 프로세스는 더 오래 기다리게 됨 &amp;rarr; &lt;b&gt;실질적 기아&lt;/b&gt; 발생.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결 방법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Priority Inheritance (우선순위 상속)&lt;/b&gt;:&lt;/li&gt;
&lt;li&gt;낮은 우선순위 프로세스가 자원을 가지고 있으면 &lt;b&gt;임시로 높은 우선순위&lt;/b&gt;를 부여해 빠르게 자원 반환하도록 함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Priority Ceiling (우선순위 천장)&lt;/b&gt;:&lt;/li&gt;
&lt;li&gt;공유 자원에 대해 &lt;b&gt;최대 우선순위&lt;/b&gt;를 미리 지정해, 해당 자원에 접근 시 우선순위를 높여줌.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 교착상태 vs 기아 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 교착상태 (Deadlock) 기아 (Starvation)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&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&gt;
&lt;td&gt;원인&lt;/td&gt;
&lt;td&gt;자원 할당의 원형 대기&lt;/td&gt;
&lt;td&gt;우선순위 정책, 불공정 스케줄링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;발생 조건&lt;/td&gt;
&lt;td&gt;Coffman 4조건 필요&lt;/td&gt;
&lt;td&gt;특정 조건 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;해결&lt;/td&gt;
&lt;td&gt;예방, 회피, 탐지 및 회복&lt;/td&gt;
&lt;td&gt;Aging(우선순위 점진 상향), 공정 스케줄링&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 요약&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;교착상태&lt;/b&gt;: 여러 프로세스가 서로 자원을 기다리며 꼼짝 못하는 상태 (시스템 전체 멈춤).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기아&lt;/b&gt;: 특정 프로세스가 무한히 자원을 못 얻는 상태 (불공정성).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;우선순위 역전&lt;/b&gt;은 기아의 한 사례 &amp;rarr; 우선순위 상속/천장 기법으로 해결 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;교착상태 해결 방법&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착상태를 다루는 방법은 크게 네 가지로 나눌 수 있습니다:&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 예방 (Deadlock Prevention)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Coffman의 4가지 필요 조건&lt;/b&gt; 중 하나 이상을 아예 성립하지 않도록 설계하는 방식.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;상호 배제(Mutual Exclusion) 부정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원을 여러 프로세스가 동시에 사용할 수 있게 설계 (현실적으로 모든 자원에 불가능).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;점유 대기(Hold &amp;amp; Wait) 부정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스가 실행 전에 필요한 모든 자원을 한 번에 할당.&lt;/li&gt;
&lt;li&gt;단점: 자원 활용률&amp;darr;, 기아 발생 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비선점(No Preemption) 부정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원을 빼앗을 수 있게 함 (ex: CPU 스케줄링 선점형, 메모리 페이지 스왑).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순환 대기(Circular Wait) 부정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원에 번호를 붙여, 오름차순으로만 할당.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ &lt;b&gt;장점&lt;/b&gt;: 교착상태 자체를 원천적으로 막음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ &lt;b&gt;단점&lt;/b&gt;: 자원 낭비, 활용률 저하.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 회피 (Deadlock Avoidance)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;교착상태가 발생하지 않도록 &lt;b&gt;자원 할당을 신중히 결정&lt;/b&gt;하는 방식.&lt;/li&gt;
&lt;li&gt;대표적 방법: &lt;b&gt;은행가 알고리즘 (Banker&amp;rsquo;s Algorithm)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원 요청 시, 현재 상태가 **안전 상태(Safe State)**인지 검사 후 허용.&lt;/li&gt;
&lt;li&gt;안전하지 않으면 요청을 거절.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ &lt;b&gt;장점&lt;/b&gt;: 교착상태 자체를 피할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ &lt;b&gt;단점&lt;/b&gt;: 프로세스의 &lt;b&gt;최대 자원 요구량을 미리 알아야 함&lt;/b&gt; &amp;rarr; 비현실적.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 탐지 후 회복 (Deadlock Detection &amp;amp; Recovery)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;교착상태 발생을 허용하되, &lt;b&gt;탐지 알고리즘&lt;/b&gt;으로 발견하고 이후 회복.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;탐지 방법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;자원 할당 그래프(Resource Allocation Graph)&lt;/b&gt; 활용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순환(Cycle)이 있으면 교착상태 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;회복 방법&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;프로세스 종료&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;교착상태에 연루된 프로세스들을 강제로 종료.&lt;/li&gt;
&lt;li&gt;한 번에 모두 종료 vs 하나씩 종료.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자원 선점(Preemption)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일부 프로세스에서 자원을 빼앗아 다른 프로세스에 할당.&lt;/li&gt;
&lt;li&gt;단점: 프로세스 상태 rollback 필요 &amp;rarr; 오버헤드 발생.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 무시 (Deadlock Ignorance)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;교착상태를 해결하는 비용이 너무 크기 때문에, &lt;b&gt;실제로는 무시하는 방법&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;대부분의 범용 OS (Windows, Linux, macOS)는 이 방법 사용.&lt;/li&gt;
&lt;li&gt;교착상태 발생 빈도가 낮고, 발생 시 시스템을 재부팅하면 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ &lt;b&gt;장점&lt;/b&gt;: 구현 단순, 오버헤드 없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ &lt;b&gt;단점&lt;/b&gt;: 일부 프로세스가 멈출 수 있음.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;✅ 요약&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법 특징 장점 단점&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;예방 (Prevention)&lt;/td&gt;
&lt;td&gt;4조건 중 하나 제거&lt;/td&gt;
&lt;td&gt;교착상태 절대 발생 X&lt;/td&gt;
&lt;td&gt;자원 낭비, 비효율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;회피 (Avoidance)&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&gt;
&lt;td&gt;탐지 &amp;amp; 회복 (Detection &amp;amp; Recovery)&lt;/td&gt;
&lt;td&gt;교착상태 허용 후 탐지&amp;middot;복구&lt;/td&gt;
&lt;td&gt;자원 활용률 &amp;uarr;&lt;/td&gt;
&lt;td&gt;탐지&amp;middot;복구 비용 큼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;무시 (Ignore)&lt;/td&gt;
&lt;td&gt;그냥 무시&lt;/td&gt;
&lt;td&gt;단순, 효율 &amp;uarr;&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;메모리 관리 전략&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU는 PC(program counter)가 지시하는데로 메모리에서 다음 수행할 명령어를 가져옴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주 메모리 &amp;harr; 프로세서 자체에 내장한 레지스터는 CPU의 유일한 범용 저장장치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주 메모리 접근시 속도 차이로 cpu클록 틱 사이클이 소요되고, 지연(stall) 현상이 발생함&lt;/p&gt;
&lt;h1&gt;논리, 물리 주소&lt;/h1&gt;
&lt;h1&gt;1. CPU와 메모리 접근&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU는 **프로그램 카운터(PC, Program Counter)**가 가리키는 메모리 주소에서 명령어를 가져와 실행.&lt;/li&gt;
&lt;li&gt;CPU 내부에는 **레지스터(Register)**가 있어서 연산에 직접 사용되는 데이터를 저장.&lt;/li&gt;
&lt;li&gt;*주 메모리(Main Memory, RAM)**는 CPU가 데이터를 읽고 쓰는 기본 저장 장치지만, **CPU 클록 대비 속도가 느려 지연(stall)**이 발생.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이를 줄이기 위해 **캐시 메모리(Cache)**가 등장 (CPU &amp;harr; 캐시 &amp;harr; 메모리 구조).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 논리 주소와 물리 주소&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;논리 주소(Logical Address, 가상주소)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 생성하는 주소 (프로그램 관점).&lt;/li&gt;
&lt;li&gt;각 프로세스는 독립적인 주소 공간을 가진다고 &quot;착각&quot;할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;물리 주소(Physical Address)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 메모리 하드웨어(RAM)가 갖는 주소.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주소 변환(Address Translation)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;*MMU (Memory Management Unit)**가 논리 주소 &amp;rarr; 물리 주소 변환을 담당.&lt;/li&gt;
&lt;li&gt;보통 **재배치 레지스터(Relocation Register)**를 사용해서 시작 위치를 보정.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 이를 통해 다중 프로세스 환경에서도 서로 간섭하지 않고 메모리 사용 가능.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 동적 적재 (Dynamic Loading)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스 전체를 메모리에 올리지 않고, &lt;b&gt;필요한 부분만 메모리에 적재&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;장점: 메모리 사용 효율 &amp;uarr;, 다중 프로그래밍에 유리.&lt;/li&gt;
&lt;li&gt;예: 라이브러리를 호출할 때 실제 필요한 함수만 메모리에 로드.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. 메모리 할당 기법 (연속 메모리 할당)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스들을 메모리에 배치할 때, 빈 공간(free hole)을 어떻게 선택할지 결정하는 방식.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;최초 적합(First Fit)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음 발견한 충분히 큰 공간에 배치.&lt;/li&gt;
&lt;li&gt;속도 빠름, 하지만 단편화(fragmentation) 발생 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적 적합(Best Fit)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;크기가 가장 작은, 딱 맞는 공간에 배치.&lt;/li&gt;
&lt;li&gt;메모리 낭비 최소화, 그러나 작은 조각(외부 단편화) 많이 생김.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최악 적합(Worst Fit)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 큰 공간에 배치.&lt;/li&gt;
&lt;li&gt;큰 공간을 나눠 사용 &amp;rarr; 큰 프로세스를 위한 공간 확보 가능.&lt;/li&gt;
&lt;li&gt;하지만 실제 효율은 떨어짐.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;✅ 요약&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU &amp;harr; 메모리&lt;/b&gt; 속도 차이를 줄이기 위해 캐시가 필요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;논리 주소&lt;/b&gt;는 CPU가 보는 주소, &lt;b&gt;물리 주소&lt;/b&gt;는 실제 메모리 주소.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MMU&lt;/b&gt;가 주소 변환 수행.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동적 적재&lt;/b&gt;로 메모리 효율성을 높임.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리 배치 기법&lt;/b&gt;: 최초 적합, 최적 적합, 최악 적합 &amp;rarr; 각각 속도/효율/낭비 측면에서 장단점 다름.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*** 동적 할당 &amp;rarr; 외부 단편화 발생&lt;/p&gt;
&lt;h1&gt;1. 단편화(Fragmentation)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 할당 과정에서 생기는 &lt;b&gt;사용하지 못하는 빈 공간&lt;/b&gt; 문제.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(1) 외부 단편화 (External Fragmentation)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 번의 메모리 할당/해제로 인해 &lt;b&gt;자잘한 빈 공간이 여기저기 흩어져&lt;/b&gt; 전체적으로는 충분한 메모리가 있어도 큰 프로세스를 넣을 수 없는 상황.&lt;/li&gt;
&lt;li&gt;예: 10KB 프로세스 필요 &amp;rarr; 빈 공간이 2KB+3KB+5KB로 나뉘어 있으면 수용 불가.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해결 방법&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;압축(Compaction)&lt;/b&gt;: 메모리 내용을 옮겨서 빈 공간을 하나로 모음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(2) 내부 단편화 (Internal Fragmentation)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;할당된 블록이 실제 요구보다 큰 경우 발생&lt;/b&gt; &amp;rarr; 블록 내에 낭비된 공간 존재.&lt;/li&gt;
&lt;li&gt;예: 12KB 요청 &amp;rarr; 16KB 단위 블록 할당 &amp;rarr; 4KB 낭비.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 세그멘테이션 (Segmentation)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;*프로그래머가 논리적으로 프로그램을 나눈 단위(세그먼트)**를 메모리에 배치하는 기법.&lt;/li&gt;
&lt;li&gt;세그먼트 = 코드, 데이터, 스택 등 &lt;b&gt;가변 크기 블록&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;CPU가 생성하는 주소 = (세그먼트 번호, 오프셋)&lt;/li&gt;
&lt;li&gt;*세그먼트 테이블(Segment Table)**을 통해 물리 주소 변환.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 장점:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그래머 관점 그대로 메모리 관리 가능 (논리적 단위 유지).&lt;/li&gt;
&lt;li&gt;외부 단편화 발생하지만, 내부 단편화는 적음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 페이징 (Paging)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리를 &lt;b&gt;고정 크기 블록&lt;/b&gt;으로 나누는 기법.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프레임(Frame)&lt;/b&gt;: 물리 메모리를 나눈 블록.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;페이지(Page)&lt;/b&gt;: 프로세스의 논리 주소 공간을 나눈 블록.&lt;/li&gt;
&lt;li&gt;크기 동일 (예: 4KB).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ CPU가 생성하는 주소 = (페이지 번호, 페이지 오프셋)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ &lt;b&gt;페이지 테이블(Page Table)&lt;/b&gt;: 페이지 번호 &amp;rarr; 프레임 번호 변환.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 장점:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 단편화 없음 (모두 같은 크기).&lt;/li&gt;
&lt;li&gt;내부 단편화만 발생 (마지막 페이지 일부 낭비).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. TLB (Translation Lookaside Buffer)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 테이블 접근은 메모리 참조이므로 느림 &amp;rarr; 매번 하면 &lt;b&gt;2번 메모리 접근(페이지 테이블 + 실제 데이터)&lt;/b&gt; 필요.&lt;/li&gt;
&lt;li&gt;이를 줄이기 위해 &lt;b&gt;TLB&lt;/b&gt;라는 &lt;b&gt;고속 캐시&lt;/b&gt; 사용.&lt;/li&gt;
&lt;li&gt;최근 변환된 페이지 번호 &amp;harr; 프레임 번호를 저장해 &lt;b&gt;주소 변환 속도 향상&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;✅ 요약&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;단편화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 단편화: 작은 조각 흩어짐 &amp;rarr; 압축 or 페이징/세그멘테이션으로 해결.&lt;/li&gt;
&lt;li&gt;내부 단편화: 블록 단위 때문에 남는 공간 발생.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세그멘테이션&lt;/b&gt;: 논리적 단위(코드, 데이터, 스택)를 가변 크기로 관리. &amp;rarr; 프로그래머 친화적, 외부 단편화 존재.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;페이징&lt;/b&gt;: 고정 크기 블록(Frame/Page)으로 관리. &amp;rarr; 외부 단편화 없음, 내부 단편화 존재.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 테이블 필요 &amp;rarr; 성능 저하 &amp;rarr; &lt;b&gt;TLB로 보완&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;h1&gt;. 가상 메모리(Virtual Memory)란?&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프로세스 전체가 물리 메모리에 적재되지 않아도 실행 가능&lt;/b&gt;하게 하는 기법.&lt;/li&gt;
&lt;li&gt;사용자 입장에서는 매우 큰 &amp;ldquo;연속적인 메모리 공간&amp;rdquo;을 쓰는 것처럼 보이지만, 실제로는 물리 메모리(RAM)와 보조기억장치(디스크, SSD 등)를 조합해서 구현.&lt;/li&gt;
&lt;li&gt;*논리 주소(가상 주소)**와 &lt;b&gt;물리 주소&lt;/b&gt;를 분리하여 관리.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 필요성&lt;/h1&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;메모리 효율성 향상&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전체 프로그램을 메모리에 올릴 필요 없이 필요한 부분만 적재 &amp;rarr; 더 많은 프로세스를 동시에 실행 가능 (멀티프로그래밍).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보호(Protection)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스마다 독립적인 주소 공간 제공 &amp;rarr; 서로 침범 불가.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유연성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 메모리보다 큰 프로그램도 실행 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;1. 요구 페이징 (Demand Paging)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 프로세스 전체를 메모리에 적재하지 않고, &lt;b&gt;실제로 필요할 때 해당 페이지를 메모리에 적재&lt;/b&gt;하는 기법.&lt;/li&gt;
&lt;li&gt;프로그램 실행 시 처음에는 필요한 최소한의 페이지만 로드 &amp;rarr; 나머지는 실행 도중 필요할 때 디스크에서 불러옴.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(1) 참조의 지역성(Locality of Reference)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시간 지역성(Temporal Locality)&lt;/b&gt;: 최근 접근한 데이터는 곧 다시 접근될 가능성 &amp;uarr;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공간 지역성(Spatial Locality)&lt;/b&gt;: 접근한 주소 근처의 데이터가 곧 참조될 가능성 &amp;uarr;&lt;/li&gt;
&lt;li&gt;요구 페이징은 이 성질을 활용 &amp;rarr; 성능이 실제로는 꽤 좋음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(2) 페이지 부재(Page Fault)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 요청한 페이지가 메모리에 없을 때 발생.&lt;/li&gt;
&lt;li&gt;처리 과정:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CPU &amp;rarr; 페이지 없음 감지 (트랩 발생).&lt;/li&gt;
&lt;li&gt;OS &amp;rarr; 디스크에서 해당 페이지 적재.&lt;/li&gt;
&lt;li&gt;페이지 테이블 갱신 후 재실행.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(3) 유효 접근 시간 (Effective Access Time, EAT)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 메모리 접근 시간은 **페이지 부재율(p)**에 비례.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EAT=(1&amp;minus;p)&amp;times;메모리&amp;nbsp;접근&amp;nbsp;시간+p&amp;times;페이지&amp;nbsp;폴트&amp;nbsp;처리&amp;nbsp;시간EAT = (1 - p) \times \text{메모리 접근 시간} + p \times \text{페이지 폴트 처리 시간}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EAT=(1&amp;minus;p)&amp;times;메모리&amp;nbsp;접근&amp;nbsp;시간+p&amp;times;페이지&amp;nbsp;폴트&amp;nbsp;처리&amp;nbsp;시간&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 폴트 처리 시간은 &lt;b&gt;디스크 I/O&lt;/b&gt;가 포함되므로 매우 크다.&lt;/li&gt;
&lt;li&gt;따라서 페이지 부재율은 &lt;b&gt;극히 낮아야&lt;/b&gt; 성능 유지 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 쓰기 시 복사 (Copy-on-Write, COW)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 프로세스가 fork()나 exec()로 복제될 때, &lt;b&gt;모든 페이지를 처음부터 복사하지 않고&lt;/b&gt; &amp;rarr; 부모와 자식이 &lt;b&gt;같은 물리 페이지를 공유&lt;/b&gt;하다가 &lt;b&gt;실제로 쓰기(write) 연산이 발생하는 순간 복사&lt;/b&gt;하는 기법.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(1) 동작 원리&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;fork() 시 자식 프로세스는 부모의 페이지를 그대로 참조. (읽기 전용)&lt;/li&gt;
&lt;li&gt;어느 한쪽이 해당 페이지를 &lt;b&gt;쓰기(write)&lt;/b&gt; 시도 &amp;rarr; 페이지 부재 발생.&lt;/li&gt;
&lt;li&gt;OS가 그 시점에만 페이지를 새로 복사해서 분리.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(2) 장점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불필요한 페이지 복사를 방지 &amp;rarr; &lt;b&gt;메모리 절약&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;fork() 후 exec()가 곧바로 이어지는 경우(자식이 새로운 프로그램 실행) &amp;rarr; 부모 메모리 복사는 거의 필요 없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;✅ 요약&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;요구 페이징(Demand Paging)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필요한 페이지만 적재 &amp;rarr; 메모리 효율 &amp;uarr;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참조의 지역성&lt;/b&gt; 때문에 실제 성능이 만족스러움&lt;/li&gt;
&lt;li&gt;하지만 페이지 부재율이 높아지면 성능 저하 (스래싱 위험)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쓰기 시 복사(Copy-on-Write, COW)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부모-자식이 페이지를 공유하다가 &lt;b&gt;쓰기 시점에만 복사&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;fork() + exec() 최적화에 매우 효과적&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;1. 페이지 교체(Page Replacement)란?&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;가상 메모리&lt;/b&gt; 시스템에서, 새로운 페이지를 메모리에 불러와야 하는데 빈 프레임이 없을 때 &amp;rarr; 기존에 있던 페이지 중 하나를 교체하는 과정.&lt;/li&gt;
&lt;li&gt;어떤 페이지를 교체하느냐에 따라 **페이지 부재율(Page Fault Rate)**이 크게 달라짐.&lt;/li&gt;
&lt;li&gt;목표: &lt;b&gt;페이지 부재율을 최소화하는 알고리즘 선택&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 프레임 할당 (Frame Allocation)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 프로세스에 &lt;b&gt;얼마나 많은 프레임을 줄 것인지&lt;/b&gt; 결정.&lt;/li&gt;
&lt;li&gt;너무 적으면 &amp;rarr; 페이지 폴트 잦음.&lt;/li&gt;
&lt;li&gt;너무 많으면 &amp;rarr; 다른 프로세스가 부족해짐.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 주요 페이지 교체 알고리즘&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(1) 최적 교체 (Optimal Replacement, OPT)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;앞으로 &lt;b&gt;가장 오랫동안 사용하지 않을 페이지&lt;/b&gt;를 교체.&lt;/li&gt;
&lt;li&gt;이론적으로 가장 좋은 성능 &amp;rarr; &lt;b&gt;페이지 부재율 최소&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;하지만 미래 참조를 알 수 없으므로 &lt;b&gt;실제 구현 불가&lt;/b&gt;, 비교 기준으로 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(2) FIFO (First-In First-Out)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리에 가장 오래 있던 페이지를 교체.&lt;/li&gt;
&lt;li&gt;구현 단순하지만, 성능이 나쁠 수 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Belady의 모순(Belady&amp;rsquo;s Anomaly)&lt;/b&gt;: 프레임 수를 늘렸는데도 페이지 폴트가 증가할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(3) LRU (Least Recently Used)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;가장 오랫동안 사용하지 않은 페이지&lt;/b&gt;를 교체.&lt;/li&gt;
&lt;li&gt;과거 사용 이력이 미래 사용 가능성과 연관 있다는 &quot;참조의 지역성(Locality)&quot;에 기반.&lt;/li&gt;
&lt;li&gt;일반적으로 가장 널리 쓰임.&lt;/li&gt;
&lt;li&gt;구현 방식:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;카운터 기반 (최근 접근 시간 기록)&lt;/li&gt;
&lt;li&gt;스택 기반 (최근 사용된 페이지를 스택 상단에 유지)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(4) LFU (Least Frequently Used)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;사용 빈도가 가장 낮은 페이지&lt;/b&gt;를 교체.&lt;/li&gt;
&lt;li&gt;문제: 최근 집중적으로 쓰였지만 앞으로 필요 없는 페이지도 남아있을 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(5) Clock 알고리즘 (Second Chance)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;FIFO 변형&lt;/b&gt;: 교체 대상 페이지에 &lt;b&gt;참조 비트(Reference Bit)&lt;/b&gt; 확인.&lt;/li&gt;
&lt;li&gt;참조된 페이지는 한 번 기회를 주고 다음 후보로 넘김.&lt;/li&gt;
&lt;li&gt;성능은 LRU에 근접하면서 구현은 단순.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. 선택 기준&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 운영체제에서는 &lt;b&gt;LRU 또는 Clock 알고리즘&lt;/b&gt;이 주로 사용.&lt;/li&gt;
&lt;li&gt;이유:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OPT는 이상적이지만 불가능.&lt;/li&gt;
&lt;li&gt;FIFO는 성능 불안정.&lt;/li&gt;
&lt;li&gt;LRU는 locality 가정 하에 안정적으로 좋은 성능.&lt;/li&gt;
&lt;li&gt;Clock은 LRU 근사치로 구현 효율성 높음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;✅ 요약&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 교체는 &lt;b&gt;빈 프레임이 없을 때 어떤 페이지를 제거할지 결정하는 문제&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;목표: &lt;b&gt;페이지 부재율 최소화&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;대표 알고리즘: OPT, FIFO, LRU, LFU, Clock.&lt;/li&gt;
&lt;li&gt;실제 OS는 **LRU(또는 근사 알고리즘)**을 가장 많이 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;1. 쓰레싱(Thrashing)이란?&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과도한 페이지 부재(Page Fault)&lt;/b&gt; 때문에 CPU가 &lt;b&gt;실제 작업보다 페이징 처리에 더 많은 시간&lt;/b&gt;을 소모하는 현상.&lt;/li&gt;
&lt;li&gt;결과적으로 &lt;b&gt;CPU 이용률 급격히 저하&lt;/b&gt;, 시스템 성능이 심각하게 떨어짐.&lt;/li&gt;
&lt;li&gt;즉, 프로세스가 필요한 페이지가 메모리에 거의 없어서 계속 디스크 &amp;harr; 메모리 스왑이 일어나는 상태.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 원인&lt;/h1&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;메모리 과다 할당 부족&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스들이 동시에 실행되면서 &lt;b&gt;각 프로세스에 충분한 프레임을 배정하지 못한 경우&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지역성(Locality) 위반&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요구 페이징은 참조의 지역성을 가정하는데, 프로그램이 메모리 전체를 자주 건드리면 페이지 폴트 &amp;uarr;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다중 프로그래밍 정도(Multiprogramming Degree) 과도&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;너무 많은 프로세스를 동시에 메모리에 올려두면 각 프로세스가 필요한 최소 프레임을 확보하지 못함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3. 증상&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 부재율(Page Fault Rate) &amp;uarr;&lt;/li&gt;
&lt;li&gt;CPU 이용률(CPU Utilization) &amp;darr;&lt;/li&gt;
&lt;li&gt;디스크 I/O 폭증&lt;/li&gt;
&lt;li&gt;프로그램 실행 속도 급격히 저하&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. 해결 방법&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(1) 최소 프레임 보장&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 프로세스에 필요한 &lt;b&gt;최소 프레임 수&lt;/b&gt;를 보장해야 함.&lt;/li&gt;
&lt;li&gt;예: 페이지 교체 알고리즘과 함께 최소 프레임 개수를 할당.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(2) 작업 집합 모델 (Working Set Model)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스가 일정 시간 동안 자주 참조하는 페이지 집합 = &lt;b&gt;작업 집합(Working Set)&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;이 집합을 모두 메모리에 적재 &amp;rarr; 페이지 폴트 감소.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(3) PFF (Page Fault Frequency) 방식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 폴트율을 측정해 임계값 초과 시 &amp;rarr; 프레임을 늘려주고, 낮으면 줄임.&lt;/li&gt;
&lt;li&gt;동적으로 프레임 수를 조절해 thrashing 방지.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;(4) 다중 프로그래밍 정도 조절&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템에 동시에 실행되는 프로세스 수를 줄임.&lt;/li&gt;
&lt;li&gt;즉, 일부 프로세스를 swap-out 해서 나머지 프로세스가 충분한 프레임 확보하도록 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;✅ 요약&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Thrashing = CPU가 일 못 하고 페이징만 하는 상태&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;원인: 프레임 부족, 지역성 위반, 다중 프로그래밍 과도.&lt;/li&gt;
&lt;li&gt;해결: 최소 프레임 보장, 작업 집합(Working Set), PFF(Page Fault Frequency), 다중 프로그래밍 정도 조절.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>CS/운영체제</category>
      <author>lodado</author>
      <guid isPermaLink="true">https://lodado.tistory.com/107</guid>
      <comments>https://lodado.tistory.com/107#entry107comment</comments>
      <pubDate>Mon, 29 Sep 2025 21:59:35 +0900</pubDate>
    </item>
    <item>
      <title>네트워크 관련 정리</title>
      <link>https://lodado.tistory.com/106</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;이전에 면접 준비하며 정리했던 내용 공유합니다.&lt;/p&gt;
&lt;h1&gt;  CORS란?&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Cross-Origin Resource Sharing(교차 출처 리소스 공유)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;브라우저 보안 정책인 **SOP(Same-Origin Policy, 동일 출처 정책)**을 완화해주는 메커니즘&lt;/li&gt;
&lt;li&gt;기본적으로 브라우저는 &lt;b&gt;다른 출처(origin)의 리소스 요청을 제한&lt;/b&gt;합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출처 = 프로토콜 + 도메인 + 포트&lt;/li&gt;
&lt;li&gt;예: &lt;a href=&quot;http://example.com:3000&quot;&gt;http://example.com:3000&lt;/a&gt; &amp;ne; &lt;a href=&quot;https://example.com:3000&quot;&gt;https://example.com:3000&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  즉, CORS는 &amp;ldquo;다른 출처의 리소스를 클라이언트가 안전하게 요청할 수 있도록 서버가 허용하는 정책&amp;rdquo;이에요.&lt;/p&gt;
&lt;h1&gt;  CORS 동작 방식&lt;/h1&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;단순 요청 (Simple Request)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 조건 만족 시(예: GET/POST + 특정 헤더만) 브라우저가 바로 요청을 보냄&lt;/li&gt;
&lt;li&gt;서버가 응답 헤더에 Access-Control-Allow-Origin을 포함해야 함&lt;/li&gt;
&lt;li&gt;예:&lt;/li&gt;
&lt;li&gt;Access-Control-Allow-Origin: &amp;lt;&lt;a href=&quot;https://myapp.com&quot;&gt;https://myapp.com&lt;/a&gt;&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  주요 헤더 정리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access-Control-Allow-Origin: 허용할 출처 (* 또는 특정 도메인)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access-Control-Allow-Methods: 허용할 HTTP 메서드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access-Control-Allow-Headers: 허용할 요청 헤더&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access-Control-Allow-Credentials: 인증정보(쿠키, 토큰) 허용 여부&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Access-Control-Max-Age: 프리플라이트 응답 캐시 시간&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;프리플라이트 요청 (Preflight Request)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조건을 벗어난 요청(예: PUT, DELETE, 커스텀 헤더 포함)일 경우&lt;/li&gt;
&lt;li&gt;브라우저가 먼저 OPTIONS 메서드로 서버에 &lt;b&gt;&amp;ldquo;이 요청 해도 되나요?&amp;rdquo;&lt;/b&gt; 물어봄&lt;/li&gt;
&lt;li&gt;서버가 허용하면 실제 요청 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;oxygene&quot;&gt;&lt;code&gt;OPTIONS /api/data HTTP/1.1
Origin: &amp;lt;https://myapp.com&amp;gt;
Access-Control-Request-Method: PUT

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 응답:&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;Access-Control-Allow-Origin: &amp;lt;https://myapp.com&amp;gt;
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization

&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Credential 요청 (쿠키/인증 포함)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fetch나 XHR에서 credentials: include 설정&lt;/li&gt;
&lt;li&gt;서버가 반드시 다음 헤더 필요:&lt;/li&gt;
&lt;li&gt;Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: &amp;lt;&lt;a href=&quot;https://myapp.com&quot;&gt;https://myapp.com&lt;/a&gt;&amp;gt; (와일드카드 * 사용 불가)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  OSI 7계층 구조&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;물리 계층 (Physical Layer)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 데이터의 &lt;b&gt;비트(0/1)&lt;/b&gt; 신호를 실제 전송 매체(케이블, 전파 등)를 통해 송수신.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장비 예시&lt;/b&gt;: 허브, 리피터, 케이블, 커넥터&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단위&lt;/b&gt;: 비트 (Bit)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. &lt;b&gt;데이터 링크 계층 (Data Link Layer)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 물리 계층에서 전송된 비트를 &lt;b&gt;프레임(Frame)&lt;/b&gt; 단위로 관리. 에러 검출/수정, 흐름 제어 수행.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MAC 주소&lt;/b&gt; 사용 &amp;rarr; 동일 네트워크 내에서 장치 식별.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장비 예시&lt;/b&gt;: 스위치, 브리지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단위&lt;/b&gt;: 프레임 (Frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. &lt;b&gt;네트워크 계층 (Network Layer)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 데이터의 목적지까지의 &lt;b&gt;경로 선택(라우팅)&lt;/b&gt;, 논리적 주소(IP) 부여.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IP 주소&lt;/b&gt; 사용 &amp;rarr; 다른 네트워크 간 통신 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로토콜 예시&lt;/b&gt;: IP, ICMP, ARP, RARP&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장비 예시&lt;/b&gt;: 라우터&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단위&lt;/b&gt;: 패킷 (Packet)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. &lt;b&gt;전송 계층 (Transport Layer)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 종단 간(end-to-end) 통신 제공. 데이터의 신뢰성 보장.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주요 프로토콜&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP(연결지향, 신뢰성 보장, 흐름/혼잡 제어)&lt;/li&gt;
&lt;li&gt;UDP(비연결성, 빠르지만 신뢰성 낮음)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단위&lt;/b&gt;: 세그먼트 (TCP) / 데이터그램 (UDP)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. &lt;b&gt;세션 계층 (Session Layer)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 통신 세션(대화)의 생성, 유지, 종료 관리.&lt;/li&gt;
&lt;li&gt;예: 로그인 세션, 원격 프레젠테이션 연결&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 동기화, 체크포인트, 복구&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. &lt;b&gt;표현 계층 (Presentation Layer)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 데이터의 표현 방식 통일. 암호화, 압축, 인코딩/디코딩.&lt;/li&gt;
&lt;li&gt;예: JPEG, GIF, MP3, TLS/SSL 암호화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;키워드&lt;/b&gt;: 번역기 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. &lt;b&gt;응용 계층 (Application Layer)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 최종 사용자와 직접 맞닿아 있는 계층. 네트워크 서비스 제공.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로토콜 예시&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP/HTTPS (웹)&lt;/li&gt;
&lt;li&gt;FTP (파일 전송)&lt;/li&gt;
&lt;li&gt;SMTP/IMAP/POP3 (이메일)&lt;/li&gt;
&lt;li&gt;DNS (도메인 네임 변환)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  정리 (계층별 단위 &amp;amp; 장비)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층 단위 주요 장비/기술&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7. 응용&lt;/td&gt;
&lt;td&gt;데이터&lt;/td&gt;
&lt;td&gt;웹 브라우저, 앱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. 표현&lt;/td&gt;
&lt;td&gt;데이터&lt;/td&gt;
&lt;td&gt;암호화/압축&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. 세션&lt;/td&gt;
&lt;td&gt;데이터&lt;/td&gt;
&lt;td&gt;API 세션 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. 전송&lt;/td&gt;
&lt;td&gt;세그먼트/데이터그램&lt;/td&gt;
&lt;td&gt;TCP, UDP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. 네트워크&lt;/td&gt;
&lt;td&gt;패킷&lt;/td&gt;
&lt;td&gt;라우터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. 데이터링크&lt;/td&gt;
&lt;td&gt;프레임&lt;/td&gt;
&lt;td&gt;스위치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1. 물리&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;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&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;애플리케이션 구조&lt;/h1&gt;
&lt;h1&gt;  애플리케이션 구조 (Application Architecture)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 구조는 &lt;b&gt;개발자가 설계한 방식에 따라 다양한 종단 시스템(End System)에서 애플리케이션이 어떻게 조직되는지&lt;/b&gt;를 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적으로 &lt;b&gt;클라이언트-서버 구조&lt;/b&gt;와 &lt;b&gt;P2P 구조&lt;/b&gt;가 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt; 클라이언트-서버 구조 (Client&amp;ndash;Server Architecture)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;서버(Host)&lt;/b&gt;: 항상 켜져 있고, 클라이언트의 요청을 처리하는 중심 시스템&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클라이언트(Client)&lt;/b&gt;: 다수의 호스트에서 실행되며, 서버에 요청을 보내는 역할&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중앙 집중형 구조&lt;/li&gt;
&lt;li&gt;보안, 데이터 관리, 성능 최적화에 유리&lt;/li&gt;
&lt;li&gt;서버 부하가 집중되면 확장 비용 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  P2P 구조 (Peer-to-Peer Architecture)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;항상 켜져 있는 기반 서버에 최소한만 의존&lt;/li&gt;
&lt;li&gt;&lt;b&gt;피어(Peer)&lt;/b&gt;: 간헐적으로 연결되는 호스트 쌍이 직접 서로 통신&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자가 확장성(Self-Scalability)&lt;/b&gt;: 네트워크에 참여하는 피어 수가 늘어날수록 자원도 함께 증가&lt;/li&gt;
&lt;li&gt;탈 중앙화된 구조로 확장성과 유연성이 뛰어남&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  프로세스 (Process)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 종단 시스템에서 실행되는 프로그램 단위&lt;/li&gt;
&lt;li&gt;&lt;b&gt;관심 대상&lt;/b&gt;: 프로세스 간 통신
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 종단 시스템 내부 프로세스 간 통신&lt;/li&gt;
&lt;li&gt;다른 종단 시스템 간 프로세스 간 통신&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클라이언트 &amp;amp; 서버 개념&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;클라이언트(Client)&lt;/b&gt;: 통신 세션을 &lt;b&gt;초기화하는 프로세스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서버(Server)&lt;/b&gt;: 통신 세션을 시작하기 위해 &lt;b&gt;접속을 기다리는 프로세스&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 요약하면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;클라이언트-서버 구조&lt;/b&gt;는 중앙 집중형으로 관리가 용이하지만 서버 부하가 커짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;P2P 구조&lt;/b&gt;는 분산형으로 확장성이 뛰어나지만 관리와 보안이 상대적으로 복잡&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로세스 관점&lt;/b&gt;에서는 누가 먼저 접속을 시도하는지(클라이언트)와 기다리는지(서버)에 따라 역할이 나뉨&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;  프로세스와 컴퓨터 네트워크 사이의 인터페이스&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  소켓 (Socket)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 애플리케이션과 네트워크 사이의 &lt;b&gt;API&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 프로세스가 네트워크를 통해 메시지를 주고받을 수 있도록 하는 인터페이스&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  애플리케이션 계층 프로토콜&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;호스트 식별&lt;/b&gt;: 인터넷에서는 &lt;b&gt;IP 주소&lt;/b&gt;로 호스트를 식별&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주요 요구 사항&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;신뢰적 데이터 전송&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;손실 없는 데이터 보장을 원할 때: &lt;b&gt;TCP&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;손실 허용 애플리케이션(예: 스트리밍): &lt;b&gt;UDP&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;처리량(Throughput)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안(Security)&lt;/b&gt;: SSL/TLS 계층에서 제공&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터넷에서 대표적으로 사용되는 프로토콜&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TCP, UDP&lt;/b&gt; (트랜스포트 계층)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HTTP&lt;/b&gt; (애플리케이션 계층)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  HTTP (HyperText Transfer Protocol)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;온-디맨드(On-Demand)&lt;/b&gt; 방식&lt;/li&gt;
&lt;li&gt;웹에서 사용하는 대표적 &lt;b&gt;애플리케이션 계층 프로토콜&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;기본적으로 &lt;b&gt;TCP(HTTP/2.0 이하)&lt;/b&gt; 위에서 동작&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비상태성(Stateless)&lt;/b&gt; &amp;rarr; 쿠키(Cookie)로 상태 관리 보완&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  HTTP 버전 별 특징&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ HTTP 1.0&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비 지속 연결 (Non-Persistent Connection)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;요청&amp;ndash;응답마다 TCP 연결을 새로 설정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지속 연결 (Persistent Connection)&lt;/b&gt; 지원 시작&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ HTTP 1.1&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기본적으로 지속 연결(Persistent)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Keep-Alive&lt;/b&gt; 헤더를 통해 연결 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ HTTP 2.0&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;멀티플렉싱(Multiplexing)&lt;/b&gt;: 하나의 연결에서 다중 요청/응답 처리&lt;/li&gt;
&lt;li&gt;성능 개선: 지연 감소, 헤더 압축, 서버 푸시(Server Push) 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** 하나의&amp;nbsp;&lt;b&gt;TCP&lt;/b&gt;&amp;nbsp;연결을 통해 여러 데이터 요청을 병렬로 전송&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 요약하면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;소켓&lt;/b&gt;은 프로세스와 네트워크의 인터페이스&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TCP/UDP&lt;/b&gt;가 신뢰성과 속도의 기준을 결정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HTTP&lt;/b&gt;는 웹의 핵심 애플리케이션 프로토콜로, &lt;b&gt;버전 업그레이드마다 성능 최적화&lt;/b&gt;와 &lt;b&gt;연결 효율성&lt;/b&gt;이 강화됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쿠키&lt;/b&gt;로 Stateless 한 HTTP를 보완&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;  웹 캐싱 (Web Caching)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  정의&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;웹 캐시(Web Cache, Proxy Server)&lt;/b&gt;:&lt;/li&gt;
&lt;li&gt;웹 서버 대신 클라이언트의 &lt;b&gt;HTTP 요청을 처리&lt;/b&gt;하는 네트워크 개체&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동작 원리&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;브라우저가 요청한 객체(HTML, CSS, JS, 이미지 등)를 &lt;b&gt;캐시에 저장&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;같은 요청이 다시 오면 &lt;b&gt;원 서버(origin server)에 가지 않고 캐시에서 응답&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;성능 향상&lt;/b&gt;: 지리적으로 가까운 캐시 서버에서 응답 &amp;rarr; 지연 시간 감소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대역폭 절약&lt;/b&gt;: 동일 콘텐츠 반복 요청 시 원 서버로의 전송 감소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부하 분산&lt;/b&gt;: 원 서버의 트래픽을 줄여 부하 완화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;운영 주체&lt;/b&gt;: 일반적으로 &lt;b&gt;ISP(Internet Service Provider)&lt;/b&gt; 가 구입 및 설치&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  조건부 GET (Conditional GET)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 캐시가 저장된 객체가 여전히 &lt;b&gt;최신인지&lt;/b&gt; 확인하기 위해 사용되는 HTTP 요청 방식&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;ETag(Entity Tag)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버가 객체에 대해 생성하는 &lt;b&gt;고유 식별자&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;요청 시 If-None-Match 헤더로 전달&lt;/li&gt;
&lt;li&gt;서버는 ETag 비교 후 같으면 304 Not Modified 응답 &amp;rarr; 캐시된 데이터 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Last-Modified&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 최종 수정 시간 정보를 제공&lt;/li&gt;
&lt;li&gt;요청 시 If-Modified-Since 헤더로 전달&lt;/li&gt;
&lt;li&gt;변경 없으면 304 Not Modified 응답&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  요청 흐름 요약&lt;/h2&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;클라이언트 ──HTTP 요청──&amp;gt; 캐시 서버
             │
             ├─ 캐시에 있으면 &amp;rarr; 바로 응답
             │
             └─ 캐시에 없거나 만료되면 &amp;rarr; 원 서버에 요청
                                   │
                                   └─ 최신 여부 확인 (조건부 GET: ETag, Last-Modified)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 정리하면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;웹 캐시&lt;/b&gt;는 프록시처럼 동작하여 성능과 효율을 개선&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조건부 GET&lt;/b&gt;은 캐시된 콘텐츠의 유효성을 확인하는 핵심 메커니즘&lt;/li&gt;
&lt;li&gt;&lt;b&gt;304 Not Modified&lt;/b&gt; 응답으로 불필요한 데이터 전송을 줄임&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Cache-Control 헤더&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  정의&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;HTTP/1.1부터 도입된 캐싱 정책 제어 헤더&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;서버가 응답 시 Cache-Control 헤더를 포함하면, 브라우저나 프록시 캐시가 &lt;b&gt;리소스를 얼마나, 어떤 방식으로 캐싱할지&lt;/b&gt; 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  주요 지시자(Directives)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 캐싱 가능 여부&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;public
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 캐시(브라우저, 프록시, CDN)에서 저장 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;private
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 사용자 브라우저에서만 캐싱 가능 (공유 캐시 불가, 예: 개인화 페이지)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;no-store
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아예 저장 금지 (민감 정보: 로그인, 금융 데이터)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 유효 기간&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;max-age=&amp;lt;초&amp;gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리소스를 &lt;b&gt;최대 n초 동안&lt;/b&gt; 신선한(fresh) 상태로 간주&lt;/li&gt;
&lt;li&gt;예: max-age=3600 &amp;rarr; 1시간 동안 캐시 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;s-maxage=&amp;lt;초&amp;gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공유 캐시(CDN, 프록시)에만 적용되는 max-age&lt;/li&gt;
&lt;li&gt;브라우저 캐시에는 적용되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;must-revalidate
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캐시 만료 후 반드시 원 서버에 검증 요청&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) 재검증 정책&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;no-cache
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;저장할 수는 있지만&lt;/b&gt;, 재사용 전 반드시 원 서버 검증 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;proxy-revalidate
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공유 캐시가 만료된 콘텐츠를 재사용할 때 반드시 서버 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) 캐싱 우선순위 (HTTP/2 이상에서 활용)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stale-while-revalidate=&amp;lt;초&amp;gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만료된 캐시라도 재검증 요청하는 동안 &lt;b&gt;임시로 사용 가능&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;stale-if-error=&amp;lt;초&amp;gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원 서버 에러 발생 시 만료된 캐시를 지정된 시간 동안 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 일반적인 정적 파일 (이미지, JS, CSS)&lt;/h3&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Cache-Control: public, max-age=31536000, immutable
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;public&lt;/b&gt; &amp;rarr; 공유 캐시 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;max-age=31536000&lt;/b&gt; &amp;rarr; 1년 캐싱&lt;/li&gt;
&lt;li&gt;&lt;b&gt;immutable&lt;/b&gt; &amp;rarr; 파일이 변경되지 않는다는 가정 (버전 변경 시 파일명에 hash 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 사용자 맞춤형 페이지&lt;/h3&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;Cache-Control: private, no-store
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;private&lt;/b&gt; &amp;rarr; 브라우저 캐시만 허용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;no-store&lt;/b&gt; &amp;rarr; 실제로는 캐시 불가 &amp;rarr; 로그인 페이지, 결제 페이지 등에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) API 응답 (짧은 캐싱 허용)&lt;/h3&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;Cache-Control: no-cache, must-revalidate, max-age=0
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저장은 가능하지만 매번 서버 검증 필요&lt;/li&gt;
&lt;li&gt;최신성이 중요한 JSON API 응답 등에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지시자 의미&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;public&lt;/td&gt;
&lt;td&gt;모든 캐시 저장 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;private&lt;/td&gt;
&lt;td&gt;개인 브라우저만 저장 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;no-store&lt;/td&gt;
&lt;td&gt;저장 자체 금지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;no-cache&lt;/td&gt;
&lt;td&gt;캐시 가능하나 재사용 전 검증 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;max-age=&amp;lt;초&amp;gt;&lt;/td&gt;
&lt;td&gt;캐시 유효 시간 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s-maxage=&amp;lt;초&amp;gt;&lt;/td&gt;
&lt;td&gt;공유 캐시 전용 유효 시간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;must-revalidate&lt;/td&gt;
&lt;td&gt;만료 후 반드시 서버 검증&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stale-while-revalidate&lt;/td&gt;
&lt;td&gt;만료 중에도 임시 사용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stale-if-error&lt;/td&gt;
&lt;td&gt;서버 에러 시 만료된 캐시 사용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;  메일 프로토콜 (Email Protocols)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  SMTP (Simple Mail Transfer Protocol)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 메일 &lt;b&gt;전송(송신)&lt;/b&gt; 프로토콜&lt;/li&gt;
&lt;li&gt;&lt;b&gt;위치&lt;/b&gt;: 클라이언트 &amp;rarr; 메일 서버, 메일 서버 &amp;rarr; 메일 서버 간 전송&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;푸시(push) 방식: 발신자가 수신자 메일 서버로 직접 전달&lt;/li&gt;
&lt;li&gt;전송 전용 &amp;rarr; 수신에는 사용하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포트&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본: 25&lt;/li&gt;
&lt;li&gt;보안: 465(SSL), 587(TLS)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  POP3 (Post Office Protocol v3)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 메일 &lt;b&gt;수신(받기)&lt;/b&gt; 프로토콜&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메일 서버에서 클라이언트로 다운로드 후 &amp;rarr; 기본적으로 서버에서 삭제&lt;/li&gt;
&lt;li&gt;단일 기기에서 사용하기 적합 (ex: PC Outlook에서만 확인)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포트&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본: 110&lt;/li&gt;
&lt;li&gt;보안: 995(SSL/TLS)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  IMAP (Internet Message Access Protocol)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 메일 &lt;b&gt;수신 및 관리&lt;/b&gt; 프로토콜&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메일 서버와 동기화 (서버에 메일 보관)&lt;/li&gt;
&lt;li&gt;여러 기기에서 동일 메일함 동기화 가능 (PC, 모바일, 웹메일)&lt;/li&gt;
&lt;li&gt;폴더 관리, 읽음/안읽음 상태 동기화 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포트&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본: 143&lt;/li&gt;
&lt;li&gt;보안: 993(SSL/TLS)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  비교 표&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토콜 주요 역할 동작 방식 장점 단점&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SMTP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;메일 송신&lt;/td&gt;
&lt;td&gt;클라이언트 &amp;rarr; 서버, 서버 &amp;harr; 서버&lt;/td&gt;
&lt;td&gt;전송 표준&lt;/td&gt;
&lt;td&gt;수신 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;POP3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;메일 수신&lt;/td&gt;
&lt;td&gt;서버 &amp;rarr; 클라이언트 (다운로드 후 삭제)&lt;/td&gt;
&lt;td&gt;단순, 서버 부하 적음&lt;/td&gt;
&lt;td&gt;여러 기기 동기화 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;IMAP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;메일 수신&lt;/td&gt;
&lt;td&gt;서버 &amp;harr; 클라이언트 동기화&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 정리하면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SMTP&lt;/b&gt; = 메일 보내기 (송신)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;POP3&lt;/b&gt; = 메일 받기 (다운로드, 단일 기기)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IMAP&lt;/b&gt; = 메일 받기 + 동기화 (멀티 기기, 서버 유지)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;DNS&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호스트에 대한 하나의 식별자 - 호스트네임(hostname)&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DNS는 DNS 서버들의 계층 구조로 구현된 분산 데이터베이스&lt;/li&gt;
&lt;li&gt;호스트가 분산 데이터베이스로 질의하도록 허락하는 애플리케이션 계층 프로토콜&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP, SMTP, FTP등 사용자가 제공한 호스트 네임을 IP 주소로 변환하기 위해 주로 이용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 질의는 UDP로 보내짐&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;분산 데이터베이스&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층 형태로 구성되며 전세계에 분산됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/** AI한테 도식 요구 **/&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;root (TLD, top level domain) 아래에 계단 식으로 DNS 서버 구성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TYPE A = 호스트 네임에 대한 IP 주소 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TYPE CNAME = 별칭 호스트네임에 대한 정식 호스트네임 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;  트랜스포트 계층 (Transport Layer)&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  개요&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;위치&lt;/b&gt;: 애플리케이션 계층 &amp;harr; 네트워크 계층 사이&lt;/li&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 다른 호스트에서 실행 중인 &lt;b&gt;애플리케이션 프로세스 간의 논리적 통신 제공&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구현 위치&lt;/b&gt;: &lt;b&gt;종단 시스템(End System)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;트랜스포트 다중화(Multiplexing)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&amp;rarr; 여러 애플리케이션 데이터 스트림을 하나의 네트워크 계층 연결로 전달&lt;/li&gt;
&lt;li&gt;&lt;b&gt;역다중화(Demultiplexing)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&amp;rarr; 받은 세그먼트를 올바른 애플리케이션 프로세스로 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  UDP (User Datagram Protocol)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비연결형(Connectionless) &amp;rarr; 연결 설정/유지 X&lt;/li&gt;
&lt;li&gt;비신뢰성(Unreliable) &amp;rarr; 패킷 손실, 순서 뒤바뀜 발생 가능&lt;/li&gt;
&lt;li&gt;혼잡 제어 X &amp;rarr; 애플리케이션 계층이 직접 제어&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오류 검출&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UDP 체크섬(Checksum)으로 종단 간 오류 검출 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장점&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오버헤드 적음 (헤더 8바이트)&lt;/li&gt;
&lt;li&gt;빠른 전송에 적합 (스트리밍, DNS, 게임 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  TCP (Transmission Control Protocol)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신뢰성 있는 연결형 프로토콜(Connection-oriented)&lt;/li&gt;
&lt;li&gt;패킷 손실 시 재전송 보장&lt;/li&gt;
&lt;li&gt;흐름 제어, 혼잡 제어 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 전송 방식&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파이프라이닝(Pipelining)&lt;/b&gt;: 다수 패킷을 연속적으로 전송&lt;/li&gt;
&lt;li&gt;&lt;b&gt;슬라이딩 윈도우(Sliding Window) 프로토콜&lt;/b&gt; 기반
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수신 ACK을 받아 누적 확인 응답 사용 (Go-Back-N 방식)&lt;/li&gt;
&lt;li&gt;또는 개별 확인 응답 사용 (Selective Repeat 방식)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  신뢰적 데이터 전송: GBN vs SR&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Go-Back-N (GBN)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;송신자는 &lt;b&gt;윈도우 크기 N&lt;/b&gt;만큼 패킷 전송 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;누적 확인 응답(Cumulative ACK)&lt;/b&gt; 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ACK n = n까지 모든 패킷 정상 수신&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;손실 발생 시&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;손실 지점 이후 모든 패킷을 &lt;b&gt;다시 전송&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;송신자: [1][2][3][4][5] ...
수신자: [1][2][X][4][5] ...
          └── ACK 2 (3번 손실)
송신자: 3 이후 패킷 모두 재전송
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 구현 간단&lt;/li&gt;
&lt;li&gt;단점: 불필요한 재전송 많음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Selective Repeat (SR)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;송신자는 윈도우 크기 N만큼 패킷 전송 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개별 확인 응답(Individual ACK)&lt;/b&gt; 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 패킷 별도로 ACK 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;손실 발생 시&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 패킷만 &lt;b&gt;선택적으로 재전송&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;송신자: [1][2][3][4][5] ...
수신자: [1][2][X][4][5] ...
          ├── ACK 1
          ├── ACK 2
          ├── ACK 4
          └── ACK 5
송신자: [3]만 재전송

&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 불필요한 재전송 &amp;darr; &amp;rarr; 효율 &amp;uarr;&lt;/li&gt;
&lt;li&gt;단점: 구현 복잡, 수신자는 out-of-order 패킷을 &lt;b&gt;버퍼링&lt;/b&gt;해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  전송 프로토콜 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 UDP TCP&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&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;연결형 (3-way handshake)&lt;/td&gt;
&lt;/tr&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&gt;
&lt;td&gt;흐름 제어&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;있음&lt;/td&gt;
&lt;/tr&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&gt;
&lt;td&gt;속도&lt;/td&gt;
&lt;td&gt;빠름&lt;/td&gt;
&lt;td&gt;상대적으로 느림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대표 사용처&lt;/td&gt;
&lt;td&gt;DNS, VoIP, 스트리밍, 게임&lt;/td&gt;
&lt;td&gt;웹(HTTP/HTTPS), 이메일(SMTP, IMAP), 파일 전송(FTP)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 정리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UDP&lt;/b&gt;: 빠르고 단순, 하지만 신뢰성 없음 &amp;rarr; 애플리케이션이 직접 보완해야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TCP&lt;/b&gt;: 신뢰성&amp;middot;순서&amp;middot;흐름 제어&amp;middot;혼잡 제어까지 제공하는 완전한 전송 프로토콜&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TCP 연결 - 연결 지향형 프로토콜&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;TCP는 연결 지향형 프로토콜&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;데이터 전송 전, 송&amp;middot;수신 양측이 논리적 연결(Connection)을 수립해야 함&lt;/li&gt;
&lt;li&gt;이 과정을 &lt;b&gt;3-Way Handshake&lt;/b&gt; 라고 부름&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  3-Way Handshake 과정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1️⃣ &lt;b&gt;SYN (synchronize)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 &amp;rarr; 서버&lt;/li&gt;
&lt;li&gt;클라이언트가 연결을 요청하며 SYN 플래그 설정&lt;/li&gt;
&lt;li&gt;초기 시퀀스 번호(ISN, Initial Sequence Number)를 함께 보냄&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2️⃣ &lt;b&gt;SYN + ACK&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 &amp;rarr; 클라이언트&lt;/li&gt;
&lt;li&gt;클라이언트의 SYN을 수락하고, 자신의 ISN과 함께 응답&lt;/li&gt;
&lt;li&gt;SYN=1, ACK=1 플래그 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3️⃣ &lt;b&gt;ACK (acknowledgement)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 &amp;rarr; 서버&lt;/li&gt;
&lt;li&gt;서버의 SYN을 수락했다는 의미로 ACK를 전송&lt;/li&gt;
&lt;li&gt;이 시점에서 &lt;b&gt;TCP 연결 수립 완료&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  흐름도 (간단 도식)&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;[Client]                                  [Server]
   | ----------- SYN(seq=x) -------------&amp;gt; |
   | &amp;lt;----- SYN(seq=y), ACK(ack=x+1) ----- |
   | -------- ACK(ack=y+1) --------------&amp;gt; |
   |                                       |
   |     [TCP Connection Established]      |

&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신뢰성 있는 연결 수립 (양쪽 모두 송수신 준비 완료 보장)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;3번의 왕복 메시지&lt;/b&gt;로 동기화 &amp;rarr; 최소한의 오버헤드로 안정성 확보&lt;/li&gt;
&lt;li&gt;이후 데이터 전송(데이터 세그먼트 교환) 시작&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3️⃣ TCP 연결 종료 (4-Way Handshake)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결을 종료하고 싶은 host가 active closer, 종료 당하는 주체가 passive closer&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Active Closer&lt;/b&gt; &amp;rarr; FIN 송신 (FIN_WAIT_1)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Passive Closer&lt;/b&gt; &amp;rarr; ACK 응답 (CLOSE_WAIT / Active=FIN_WAIT_2)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Passive Closer&lt;/b&gt; &amp;rarr; FIN 송신 (LAST_ACK)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Active Closer&lt;/b&gt; &amp;rarr; ACK 응답 후 TIME_WAIT 진입 &amp;rarr; 종료&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4️⃣ TIME_WAIT 상태&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Active Closer가 마지막 ACK를 보낸 후 일정 시간(보통 2MSL, 30~60초) 대기&lt;/li&gt;
&lt;li&gt;이유:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;지연 패킷 제거&lt;/b&gt; (이전 연결 패킷이 새 연결에 섞이지 않도록)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;마지막 ACK 보장&lt;/b&gt; (ACK 손실 시 상대방의 FIN 재전송 처리 가능)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;3-Way Handshake&lt;/b&gt;: TCP 연결 수립&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ISN&lt;/b&gt;: 시퀀스 번호의 시작점, 순서&amp;middot;보안 보장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;4-Way Handshake&lt;/b&gt;: TCP 연결 종료&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TIME_WAIT&lt;/b&gt;: 지연 패킷/ACK 손실 대비 안전 대기&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  SSL/TLS Handshake 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 아이디어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;*초기에는 비대칭 암호화(RSA, ECDHE 등)**를 사용해 &quot;세션 키(대칭키)&quot;를 안전하게 합의&lt;/li&gt;
&lt;li&gt;*그 이후부터는 대칭 암호화(AES 등)**로 실제 데이터 통신 수행 (빠르고 효율적)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  상세 단계 (TLS 1.2 기준 예시)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1️⃣ &lt;b&gt;Client Hello&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 &amp;rarr; 서버&lt;/li&gt;
&lt;li&gt;클라이언트가 지원하는 암호화 알고리즘 목록, TLS 버전, 난수(Random) 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2️⃣ &lt;b&gt;Server Hello + 인증서 전송&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 &amp;rarr; 클라이언트&lt;/li&gt;
&lt;li&gt;서버가 사용할 암호화 알고리즘 선택&lt;/li&gt;
&lt;li&gt;서버 인증서(X.509, 공개키 포함) 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3️⃣ &lt;b&gt;인증서 검증&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트는 받은 서버 인증서를 &lt;b&gt;CA(인증기관)의 공개키&lt;/b&gt;로 검증&lt;/li&gt;
&lt;li&gt;올바르면 서버의 공개키를 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4️⃣ &lt;b&gt;세션 키 생성 &amp;amp; 전송&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(RSA 방식일 경우)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트가 **대칭키(Pre-Master Secret)**를 생성&lt;/li&gt;
&lt;li&gt;서버의 공개키로 암호화해서 서버로 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;(Diffie-Hellman/ECDHE 방식일 경우)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;양쪽이 난수 교환을 통해 동일한 세션 키를 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5️⃣ &lt;b&gt;서버가 세션 키 복호화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버는 자신의 개인키(Private Key)로 클라이언트가 보낸 대칭키를 해독&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6️⃣ &lt;b&gt;Finished 메시지 교환&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서로 &amp;ldquo;이제부터 대칭키 암호화를 사용한다&amp;rdquo;는 신호 교환&lt;/li&gt;
&lt;li&gt;이후부터는 AES, ChaCha20 같은 &lt;b&gt;대칭키 암호화&lt;/b&gt;로 통신&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;흐름 제어 (Flow Control)&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  개념&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;송신자가 &lt;b&gt;너무 많은 데이터를 빠르게 보내지 않도록 제어&lt;/b&gt;하는 메커니즘&lt;/li&gt;
&lt;li&gt;목적: &lt;b&gt;수신자의 버퍼 오버플로우 방지&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  TCP에서 흐름 제어 방식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;수신 윈도우(Receive Window, rwnd)&lt;/b&gt; 사용&lt;/li&gt;
&lt;li&gt;수신 측은 자신이 현재 &lt;b&gt;얼마나 데이터를 더 받을 수 있는지&lt;/b&gt;를 rwnd 값으로 송신자에게 알려줌&lt;/li&gt;
&lt;li&gt;송신자는 이 윈도우 크기를 참고하여 데이터 전송량을 조절&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  동작 예시&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;수신 버퍼가 여유로움 &amp;rarr; rwnd 크게 설정 &amp;rarr; 송신자 많은 데이터 전송 가능&lt;/li&gt;
&lt;li&gt;수신 버퍼가 가득 참 &amp;rarr; rwnd=0 통보 &amp;rarr; 송신자는 전송 중단&lt;/li&gt;
&lt;li&gt;수신자가 버퍼를 비우면 &amp;rarr; rwnd 갱신 &amp;rarr; 송신자가 다시 전송 재개&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;End-to-End 제어&lt;/b&gt;: 송신자 &amp;harr; 수신자 간 직접 협력&lt;/li&gt;
&lt;li&gt;흐름 제어 &amp;ne; 혼잡 제어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;흐름 제어: &lt;b&gt;수신자 능력&lt;/b&gt;에 맞게 제어&lt;/li&gt;
&lt;li&gt;혼잡 제어: &lt;b&gt;네트워크 상황&lt;/b&gt;에 맞게 제어&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP는 **수신 윈도우(rwnd)**를 통해 흐름 제어를 제공&lt;/li&gt;
&lt;li&gt;수신자가 처리 가능한 만큼만 데이터를 전송하게 만들어 &lt;b&gt;버퍼 오버플로우 방지&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  TCP 혼잡 제어 (Congestion Control)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 내 혼잡(패킷 손실, 지연)을 피하기 위해 송신자가 전송 속도를 조절하는 메커니즘.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 개념은 **혼잡 윈도우(cwnd, Congestion Window)**를 유지하면서 네트워크 상황에 맞게 변화시키는 것.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  1. 슬로 스타트 (Slow Start)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음 연결 시 cwnd = 1 MSS (최소 단위)로 시작&lt;/li&gt;
&lt;li&gt;ACK를 받을 때마다 &lt;b&gt;cwnd 두 배로 증가 (지수적 증가)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;너무 빠르게 늘어나므로 특정 임계값(ssthresh)에 도달하면 혼잡 회피 단계로 전환&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;cwnd: 1 &amp;rarr; 2 &amp;rarr; 4 &amp;rarr; 8 &amp;rarr; 16 ... (ACK마다 배 증가)

&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  2. 혼잡 회피 (Congestion Avoidance)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cwnd가 ssthresh에 도달한 이후부터는 &lt;b&gt;선형 증가 (1 MSS씩)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;네트워크를 과도하게 밀어넣지 않고 안정적으로 성장&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;cwnd: 17 &amp;rarr; 18 &amp;rarr; 19 ... (매 RTT마다 +1)

&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  3. 빠른 재전송 &amp;amp; 빠른 회복 (Fast Retransmit &amp;amp; Fast Recovery)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(1) 빠른 재전송 (Fast Retransmit)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 패킷에 대한 &lt;b&gt;중복 ACK 3개&lt;/b&gt;를 받으면 손실로 판단 (슬라이딩 윈도우)&lt;/li&gt;
&lt;li&gt;타이머 만료 기다리지 않고 즉시 재전송&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(2) 빠른 회복 (Fast Recovery)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;혼잡 발생 시 ssthresh = cwnd / 2 로 낮춤&lt;/li&gt;
&lt;li&gt;cwnd도 절반으로 줄이고 &amp;rarr; 이후 선형 증가(혼잡 회피 모드로)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  동작 흐름 요약&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;슬로 스타트&lt;/b&gt;: 지수적 증가 (빠른 속도 확보)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;혼잡 회피&lt;/b&gt;: 임계치 이후 선형 증가 (안정적 성장)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패킷 손실 발생&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타임아웃 발생 &amp;rarr; cwnd = 1로 리셋, 다시 슬로 스타트&lt;/li&gt;
&lt;li&gt;중복 ACK 3개 &amp;rarr; 빠른 재전송 + 빠른 회복&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  그림으로 이해&lt;/h2&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;혼잡 윈도우 크기 (cwnd)
│
│        /''''''''''''''''''' 혼잡 회피 (선형 증가)
│      /
│    /      &amp;larr; 슬로 스타트 (지수적 증가)
│  /
│/________________________________ RTT

&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 정리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;슬로 스타트&lt;/b&gt;: 빠른 시작 (지수적 증가)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;혼잡 회피&lt;/b&gt;: 네트워크 보호 (선형 증가)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빠른 재전송 &amp;amp; 빠른 회복&lt;/b&gt;: 손실 시 즉시 대응, 성능 저하 최소화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;링크 계층&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  ARP (Address Resolution Protocol)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: IP 주소(논리 주소)를 실제 하드웨어 주소(MAC 주소)로 변환.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이유&lt;/b&gt;: IP만 알면 목적지까지 경로를 잡을 수 있지만, 실제로 같은 네트워크에서 패킷을 보내려면 MAC 주소가 필요하기 때문.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;흐름&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;송신자가 &amp;ldquo;이 IP 주소 가진 애 누구냐?&amp;rdquo; 하고 브로드캐스트 요청(ARP Request)을 보냄.&lt;/li&gt;
&lt;li&gt;해당 IP를 가진 장치가 자기 MAC 주소를 알려줌(ARP Reply).&lt;/li&gt;
&lt;li&gt;송신자는 이 매핑(IP &amp;harr; MAC)을 &lt;b&gt;ARP 캐시&lt;/b&gt;에 저장해 두고, 이후 재사용.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  즉, &lt;b&gt;IP &amp;rarr; MAC 변환&lt;/b&gt;.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  RARP (Reverse Address Resolution Protocol)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 반대로, MAC 주소(물리 주소)만 알고 있을 때 IP 주소를 알아내는 프로토콜.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 사례&lt;/b&gt;: 예전에는 디스크가 없는 얇은 클라이언트(디스크리스 워크스테이션)가 부팅할 때 자기 MAC은 알지만, IP는 몰라서 서버한테 &amp;ldquo;내 MAC은 이건데, 내 IP 좀 알려줘&amp;rdquo;라고 요청할 때 사용.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;흐름&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;클라이언트가 RARP 요청(자기 MAC 주소 포함)을 브로드캐스트.&lt;/li&gt;
&lt;li&gt;RARP 서버가 해당 MAC에 맞는 IP를 응답으로 알려줌.&lt;/li&gt;
&lt;li&gt;클라이언트는 그 IP를 사용해 네트워크 시작.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  즉, &lt;b&gt;MAC &amp;rarr; IP 변환&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  REST(Representational State Transfer)란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2000년 &lt;b&gt;Roy Fielding 박사 논문&lt;/b&gt;에서 제안된 웹 아키텍처 스타일&lt;/li&gt;
&lt;li&gt;자원을 &amp;ldquo;&lt;b&gt;URI로 표현&lt;/b&gt;&amp;rdquo;하고, 해당 자원에 대한 행위는 &amp;ldquo;&lt;b&gt;HTTP 메서드&lt;/b&gt;&amp;rdquo;로 구분해 처리하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  RESTful API란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;REST 원칙을 잘 지켜 구현한 API&lt;/li&gt;
&lt;li&gt;즉, &lt;b&gt;HTTP의 특징을 최대한 활용&lt;/b&gt;해 **일관적이고, 확장 가능하며, 무상태(stateless)**로 설계된 API&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  RESTful API의 핵심 특징&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;클라이언트-서버 분리 (Client-Server)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UI와 데이터 저장/처리가 명확히 분리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;무상태성 (Stateless)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버는 요청 간 상태(Session)를 유지하지 않음&lt;/li&gt;
&lt;li&gt;모든 요청은 필요한 정보를 자체적으로 포함해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;캐시 가능성 (Cacheable)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 캐시(Cache-Control, ETag) 등을 활용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;계층화 (Layered System)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로드밸런서, 프록시, 게이트웨이 등을 중간에 껴도 동작 보장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터페이스 일관성 (Uniform Interface)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;URI로 자원을 식별하고, HTTP 메서드로 행위 표현&lt;/li&gt;
&lt;li&gt;예:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GET /users/1 &amp;rarr; 사용자 조회&lt;/li&gt;
&lt;li&gt;POST /users &amp;rarr; 새 사용자 생성&lt;/li&gt;
&lt;li&gt;PUT /users/1 &amp;rarr; 사용자 전체 수정&lt;/li&gt;
&lt;li&gt;PATCH /users/1 &amp;rarr; 사용자 일부 수정&lt;/li&gt;
&lt;li&gt;DELETE /users/1 &amp;rarr; 사용자 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  RESTful하지 않은 API 예시&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GET /getUser?id=1 &amp;rarr; ❌ 동작이 URI에 들어감&lt;/li&gt;
&lt;li&gt;POST /updateUser/1 &amp;rarr; ❌ 메서드와 URI 의미가 중복&lt;/li&gt;
&lt;li&gt;GET /users/delete/1 &amp;rarr; ❌ 조회 메서드(GET)로 삭제 동작&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  RESTful API에서는 &lt;b&gt;자원(Resource)&lt;/b&gt; 은 URI로, &lt;b&gt;행위(Action)&lt;/b&gt; 는 HTTP 메서드로 표현해야 함.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  면접 답변 예시&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;RESTful API란, REST 아키텍처 스타일을 잘 지켜 구현한 API를 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자원을 URI로 표현하고, HTTP 메서드로 행위를 구분하며, 서버는 무상태성을 유지합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 GET /users/1은 사용자 1 조회, DELETE /users/1은 사용자 1 삭제를 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 설계하면 API가 일관되고, 확장성과 재사용성이 높아집니다.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;  HATEOAS란?&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;HATEOAS (Hypermedia As The Engine Of Application State)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;REST 아키텍처의 제약 조건 중 하나&lt;/li&gt;
&lt;li&gt;클라이언트가 서버와 상호작용할 때, &lt;b&gt;응답에 포함된 하이퍼미디어(링크)를 통해 다음 행동을 발견&lt;/b&gt;하도록 하는 원칙&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;  실무에서는?&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사실 많은 API가 &lt;b&gt;&amp;ldquo;RESTful&amp;rdquo;이라고 하지만 HATEOAS까지 구현하지는 않음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;대부분은 Swagger/OpenAPI 문서로 엔드포인트를 공유하는 방식&lt;/li&gt;
&lt;li&gt;HATEOAS는 Hypermedia API (예: HAL, JSON:API, Siren) 같은 규격에서 사용됨&lt;/li&gt;
&lt;li&gt;복잡한 클라이언트-서버 통신이나 &lt;b&gt;동적으로 상태 변화가 많은 시스템&lt;/b&gt;에서는 유용하지만,&lt;/li&gt;
&lt;li&gt;단순 CRUD API에서는 오버엔지니어링일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;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;풀링/SSE/web socket&lt;/p&gt;
&lt;h1&gt;  1. Polling&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;방식&lt;/b&gt;: 클라이언트가 주기적으로 서버에 요청(Are there any updates?) &amp;rarr; 서버가 응답&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구현이 가장 단순 (기본 HTTP 요청/응답)&lt;/li&gt;
&lt;li&gt;하지만 불필요한 요청이 많음 &amp;rarr; 네트워크/서버 리소스 낭비&lt;/li&gt;
&lt;li&gt;지연(latency)는 짧게 잡으면 실시간성이 있지만, 트래픽 비용&amp;uarr;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  2. SSE (Server-Sent Events)&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;방식&lt;/b&gt;: 서버가 &lt;b&gt;단방향으로&lt;/b&gt; 클라이언트에 지속적으로 이벤트를 푸시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트는 EventSource 객체로 연결&lt;/li&gt;
&lt;li&gt;서버는 text/event-stream MIME 타입으로 메시지 스트림 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단방향(서버 &amp;rarr; 클라이언트)만 지원&lt;/li&gt;
&lt;li&gt;HTTP/1.1 기반, TCP 위에서 동작&lt;/li&gt;
&lt;li&gt;자동 재연결, 이벤트 스트림 지원 (id, retry, event)&lt;/li&gt;
&lt;li&gt;브라우저 네이티브 지원 좋음&lt;/li&gt;
&lt;li&gt;한계: &lt;b&gt;양방향 통신 불가&lt;/b&gt;, 바이너리 데이터 전송 불편&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  3. WebSocket&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;방식&lt;/b&gt;: HTTP 연결을 업그레이드(Handshake) &amp;rarr; 이후는 &lt;b&gt;TCP 소켓 기반 양방향 통신&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;양방향 통신 (서버 &amp;harr; 클라이언트 모두 자유롭게 메시지 전송)&lt;/li&gt;
&lt;li&gt;헤더 오버헤드가 적어 효율적&lt;/li&gt;
&lt;li&gt;바이너리/텍스트 전송 모두 가능&lt;/li&gt;
&lt;li&gt;실시간 채팅, 게임, 주식 시세 스트리밍에 적합&lt;/li&gt;
&lt;li&gt;단점: 구현 복잡도&amp;uarr;, 인프라/보안/프록시 설정 주의 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  비교 표&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 Polling SSE (Server-Sent Events) WebSocket&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&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;서버 &amp;rarr; 클라이언트 단방향&lt;/td&gt;
&lt;td&gt;양방향 (Full-duplex)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;프로토콜&lt;/td&gt;
&lt;td&gt;HTTP&lt;/td&gt;
&lt;td&gt;HTTP (text/event-stream)&lt;/td&gt;
&lt;td&gt;HTTP Handshake &amp;rarr; TCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터 포맷&lt;/td&gt;
&lt;td&gt;제한 없음&lt;/td&gt;
&lt;td&gt;UTF-8 텍스트&lt;/td&gt;
&lt;td&gt;텍스트 + 바이너리&lt;/td&gt;
&lt;/tr&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&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&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&gt;
&lt;td&gt;단점&lt;/td&gt;
&lt;td&gt;낭비 많음&lt;/td&gt;
&lt;td&gt;단방향 한계, 바이너리 불편&lt;/td&gt;
&lt;td&gt;구현/인프라 복잡도&amp;uarr;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  면접 답변 예시&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;Polling은 클라이언트가 주기적으로 서버에 요청하는 방식이라 단순하지만 비효율적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSE는 서버가 지속적으로 클라이언트에 이벤트를 보내주는 단방향 스트리밍으로, 알림/피드 업데이트에 적합합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebSocket은 HTTP 연결을 업그레이드해서 양방향 통신을 지원하며, 채팅이나 게임 같이 빠른 상호작용이 필요한 서비스에 많이 쓰입니다.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>CS/네트워크</category>
      <author>lodado</author>
      <guid isPermaLink="true">https://lodado.tistory.com/106</guid>
      <comments>https://lodado.tistory.com/106#entry106comment</comments>
      <pubDate>Mon, 29 Sep 2025 21:55:31 +0900</pubDate>
    </item>
    <item>
      <title>커서 룰(Cursor Rule), 팀 문서 퀄리티 자동으로 챙기는 꿀팁</title>
      <link>https://lodado.tistory.com/105</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 회사에서 커서를 구매해줘서 써봤는데, 인생이 달라졌습니다.. 지금까진 뗀석기로 개발한 기분인데요&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 cursor를 쓰면서, 내가 원하는 스크립트를 미리 입력하는 방법을 찾고 있었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;rule&quot; 이라는 방법을 찾아서 간단히 공유하고, 제가 실제로 어떻게 쓰는지 몇가지 케이스를 공유해볼려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 data-end=&quot;117&quot; data-start=&quot;80&quot;&gt;Cursor AI IDE의 룰(Rule), 이렇게 활용합니다&lt;/h1&gt;
&lt;p data-end=&quot;346&quot; data-start=&quot;119&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;379&quot; data-start=&quot;156&quot; data-ke-size=&quot;size16&quot;&gt;Cursor AI IDE의 룰(Rule)은 개발자가 원하는 코딩 원칙과 팀 규칙을 AI에게 전달하는 일종의 &amp;ldquo;가이드라인 문서&amp;rdquo;입니다.&lt;/p&gt;
&lt;p data-end=&quot;379&quot; data-start=&quot;156&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;보통 코드 스타일이나 문법 규칙은 ESLint, Prettier 같은 도구가 처리합니다. 하지만 Cursor 룰은 그보다 상위 개념으로, AI가 코드를 생성하는 순간부터 개발자 또는 팀의 철학과 컨벤션을 반영할 수 있게 해주는 것이 특징입니다.&lt;/p&gt;
&lt;p data-end=&quot;428&quot; data-start=&quot;381&quot; data-ke-size=&quot;size16&quot;&gt;즉, 룰을 정의해두면 AI는 단순히 문법적으로 맞는 코드를 제안하는 것이 아니라,&lt;/p&gt;
&lt;p data-end=&quot;428&quot; data-start=&quot;381&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;512&quot; data-start=&quot;429&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;449&quot; data-start=&quot;429&quot;&gt;팀의 아키텍처 구조를 지키고,&lt;/li&gt;
&lt;li data-end=&quot;478&quot; data-start=&quot;450&quot;&gt;특정 라이브러리 사용을 강제하거나 금지하며,&lt;/li&gt;
&lt;li data-end=&quot;512&quot; data-start=&quot;479&quot;&gt;에러 처리 방식이나 테스트 작성 원칙까지 고려한 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;593&quot; data-start=&quot;514&quot; data-ke-size=&quot;size16&quot;&gt;를 처음부터 작성해줍니다. 이로써 코드 리뷰에서 반복되는 지적을 줄이고, 개발자가 진짜 중요한 로직과 설계에 집중할 수 있도록 도와줍니다.&lt;/p&gt;
&lt;p data-end=&quot;593&quot; data-start=&quot;514&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;628&quot; data-start=&quot;600&quot; data-ke-size=&quot;size26&quot;&gt;Cursor 룰은 어떻게 구성되어 있을까?&lt;/h2&gt;
&lt;p data-end=&quot;757&quot; data-start=&quot;629&quot; data-ke-size=&quot;size16&quot;&gt;Cursor IDE에서 룰은 보통 프로젝트 루트에 .cursor/rules/ 폴더 형태로 관리됩니다. 이 안에 마크다운(.mdc) 파일을 작성해 규칙을 기술하게 되며, 각 파일은 하나의 주제를 담당할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;767&quot; data-start=&quot;759&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;894&quot; data-start=&quot;768&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;803&quot; data-start=&quot;768&quot;&gt;architecture.mdc &amp;rarr; 폴더 간 의존성 규칙&lt;/li&gt;
&lt;li data-end=&quot;835&quot; data-start=&quot;804&quot;&gt;performance.mdc &amp;rarr; 성능 관련 제안&lt;/li&gt;
&lt;li data-end=&quot;864&quot; data-start=&quot;836&quot;&gt;security.mdc &amp;rarr; 보안 체크리스트&lt;/li&gt;
&lt;li data-end=&quot;894&quot; data-start=&quot;865&quot;&gt;testing.mdc &amp;rarr; 테스트 작성 가이드&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;960&quot; data-start=&quot;896&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 여러 개의 룰 파일을 만들어두면, Cursor가 코드 생성 시 해당 규칙들을 참고해 반영합니다.&lt;/p&gt;
&lt;p data-end=&quot;593&quot; data-start=&quot;514&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;291&quot; data-start=&quot;215&quot; data-ke-size=&quot;size16&quot;&gt;룰 파일은 기본적으로 Markdown(.mdc) 문서지만, 맨 위에는 아래와 같은 frontmatter 블록을 가집니다.&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756743167194&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
description: 대시보드 UI 접근성 가이드
globs: [&quot;app/(dashboard)/**&quot;, &quot;**/*.tsx&quot;]
alwaysApply: false
---
# 규칙
- 데이터 테이블에는 캡션/헤더 스코프를 명시합니다.
- 대용량 리스트는 가상화 시 aria-rowcount/aria-rowindex 검토.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-end=&quot;520&quot; data-start=&quot;477&quot; data-ke-size=&quot;size16&quot;&gt;이 영역이 바로 룰의 동작 방식과 적용 범위를 제어하는 옵션입니다.&lt;/p&gt;
&lt;p data-end=&quot;593&quot; data-start=&quot;514&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;853&quot; data-start=&quot;800&quot; data-ke-size=&quot;size16&quot;&gt;.mdc 파일 상단의 --- 구간(프런트매터)으로 적용 범위와 방식을 제어합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1182&quot; data-start=&quot;855&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;909&quot; data-start=&quot;855&quot;&gt;description: 룰의 요약/설명(Agent가 룰을 선택&amp;middot;요약할 때 사용)&lt;/li&gt;
&lt;li data-end=&quot;1025&quot; data-start=&quot;910&quot;&gt;globs: 이 패턴에 매칭되는 파일이 대화/작업에 등장할 때 자동 첨부
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1025&quot; data-start=&quot;967&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1025&quot; data-start=&quot;967&quot;&gt;예) [&quot;app/(dashboard)/**&quot;, &quot;**/*.tsx&quot;, &quot;!**/*.test.ts&quot;]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1182&quot; data-start=&quot;1026&quot;&gt;alwaysApply: true면 항상 컨텍스트에 포함&lt;br /&gt;이 3개가 룰 동작의 핵심입니다. (Cursor UI의 &amp;ldquo;Rule Type&amp;rdquo; 드롭다운도 내부적으로 이 속성 조합을 바꿔줍니다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;986&quot; data-start=&quot;967&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-end=&quot;986&quot; data-start=&quot;967&quot; data-ke-size=&quot;size26&quot;&gt;어떻게 활용할 수 있을까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1535&quot; data-start=&quot;988&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1172&quot; data-start=&quot;988&quot;&gt;팀 컨벤션 문서화&lt;br /&gt;기존에는 Notion이나 Wiki에만 적어두던 &amp;ldquo;팀 규칙&amp;rdquo;을 Cursor 룰로 옮겨 AI에게 직접 인식시킬 수 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;1172&quot; data-start=&quot;1084&quot;&gt;예: &amp;ldquo;새 페이지는 반드시 app/(dashboard)/ 구조를 따를 것&amp;rdquo;,&lt;br /&gt;&amp;ldquo;데이터 패칭에는 TanStack Query를 활용할 것&amp;rdquo;&lt;/li&gt;
&lt;li data-end=&quot;1331&quot; data-start=&quot;1174&quot;&gt;AI 코드 생성 품질 향상&lt;br /&gt;단순한 함수 작성 요청에도 AI가 미리 정의한 룰을 참고해 구조적이고 일관성 있는 코드를 제안합니다.&lt;/li&gt;
&lt;li data-end=&quot;1331&quot; data-start=&quot;1264&quot;&gt;예: &amp;ldquo;API 호출 시 반드시 Result&amp;lt;T, E&amp;gt; 타입으로 감싸고, 실패 시 로깅 + 사용자 메시지 제공&amp;rdquo;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;1430&quot; data-start=&quot;1333&quot;&gt;리뷰 비용 절감&lt;br /&gt;코드 리뷰 단계에서 발생하는 반복적인 스타일 및 규칙 지적이 줄어들어, 리뷰어는 아키텍처 적합성이나 로직 검증에 집중할 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;1535&quot; data-start=&quot;1432&quot;&gt;지속적인 팀 학습 도구&lt;br /&gt;신입 개발자나 새로운 팀원이 투입될 경우, 룰에 의해 생성되는 코드만 보더라도 팀이 어떤 방식을 선호하는지 자연스럽게 익힐 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;593&quot; data-start=&quot;514&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;967&quot; data-end=&quot;986&quot; data-ke-size=&quot;size26&quot;&gt;실제로 어떻게 활용하고 있는지?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. PR 리뷰&lt;/p&gt;
&lt;pre id=&quot;code_1756743363128&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
description: &quot;실무형 PR 템플릿&quot;
alwaysApply: false
---

#   실무형 PR 템플릿

## 목적

- PR 문서를 일관된 구조와 충분한 근거로 작성한다.
- 변경 이유(Why) &amp;rarr; 설계(How) &amp;rarr; 검증(Proof) 흐름을 따른다.
- 문서는 **마크다운** 형식으로 작성한다.

---

##   필수 섹션

### Description

- 변경 범위를 한 줄로 요약한다.
- 핵심 키워드를 포함한다.

### 배경

- 기존 동작의 한계나 문제점을 설명한다.
- 개선이 필요한 이유를 명확히 기술한다.

### 주요 변경사항

- 개선된 동작 방식을 요약한다.
- 데이터 구조, 처리 방식, 정책 등 변경된 규칙을 나열한다.

### 테스트

- 주요 시나리오 목록을 항목으로 나열한다.
- 실행 방법을 간단히 명시한다.
- 현재 테스트 결과를 요약한다.

### 성능 분석 (필수)

- **시간복잡도**와 **공간복잡도**를 명시한다.
- 계산 결과가 `O(n^2)` 이상일 경우, **주의가 필요하다는 경고 문구**를 반드시 포함한다.
  - 예: `이 PR은 최악의 경우 O(n^2) 복잡도를 가질 수 있으므로, 대규모 데이터 환경에서는 성능 저하에 유의해야 함.`

---

##   선택 섹션 (대규모/구조 변경 PR 시 작성)

### 타입/구조 변경

- 변경 전/후 구조를 항목으로 정리한다.
- 호환성 영향과 범위를 명확히 기술한다.

### 동작 규칙

- 포함/제외 조건을 단계별로 기술한다.
- 결과 반영 조건과 불변성 원칙을 기록한다.

### 구현 파일

- 변경된 파일 경로를 나열한다.
- 각 파일의 역할과 변경 이유를 요약한다.

### 검증 방법

- 테스트 통과 확인 절차를 적는다.
- 샘플 데이터나 실제 UI 확인 절차를 체크리스트로 작성한다.

### 변경 파일 요약

- 파일별 변경 의도를 불릿 형태로 정리한다.

---

## 작성 규칙 (Do/Don&amp;rsquo;t)

- **Do**

  - 필수 섹션은 항상 작성한다.
  - 선택 섹션은 변경 규모&amp;middot;영향에 따라 추가한다.
  - 구조 변경은 호환성 영향까지 반드시 기록한다.
  - 불변성 원칙은 필요 시 명시한다.
  - 시간&amp;middot;공간복잡도는 항상 기록하고, `O(n^2)` 이상일 경우 반드시 경고 문구를 추가한다.

- **Don&amp;rsquo;t**
  - 근거 없는 성능 수치를 기재하지 않는다.
  - 불필요하게 긴 코드 조각을 문서에 직접 삽입하지 않는다(파일 경로나 링크로 대체).

---

## 리뷰어 체크리스트

- [ ] 필수 섹션이 모두 포함되었는가?
- [ ] 변경 이유와 개선 방법이 명확하게 연결되는가?
- [ ] 구조 변경 시 영향 범위가 기술되었는가?
- [ ] 테스트 시나리오가 주요 변경사항을 커버하는가?
- [ ] 시간/공간복잡도가 기록되었는가?
- [ ] 복잡도가 `O(n^2)` 이상일 경우, 경고 문구가 포함되었는가?
- [ ] 성능 및 추후 과제가 현실적으로 기술되었는가?&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 가장 강력한 부분이죠. 분석엔 강력하지만 상대적으로 창조엔 약합니다. 가장 만족스러운 부분인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cursor는 문서화에 큰 강점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기획 문서 내용과 &quot;지금까지 작업한 내용을 main 브랜치와 지금 브랜치의 차이를 기반으로 분석해서 PR 문서를 마크다운으로 만들어줘&quot; 라고 위 룰과 함께 명령을 내리면,&amp;nbsp; 작업 컨택스트가 없는 리뷰어도 손쉽게 맥락 파악이 가능해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 리뷰어 혹은 개발자가 성능 병목사항을 일일히 짚어내기 어려운데, 시간복잡도 공간복잡도 측면에서 코드를 분석해주니&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 품질도 높일 수 있고 주니어/신입 개발자에게는 어떻게 개발해야하는지 피드백을 AI한테 받아서 개발이 가능해집니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Test 코드 작성&lt;/p&gt;
&lt;pre id=&quot;code_1756743781905&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
description: Documentation and testing guidelines, available on demand
alwaysApply: false
---

## Documentation

- After defining any function, method, or component:
  - Write a JSDoc comment explaining its purpose, parameters, and return value.
  - Keep it concise but informative.

## Testing

- Test code with various inputs, including edge cases.
- use **vitest** for testing, not jest
- Include both positive and negative scenarios.
- Use a clear &quot;as is &amp;rarr; when &amp;rarr; to be/should&quot; structure:
  - `describe('&amp;lt;Unit&amp;gt;')`
    - `describe('as is: &amp;lt;current state&amp;gt;')`
      - `describe('when &amp;lt;condition&amp;gt;')`
        - `it('to be: &amp;lt;expected&amp;gt;, should &amp;lt;assertions&amp;gt;')`
- Avoid testing implementation details &amp;mdash; focus on public behavior.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 가장 강력한 부분 2죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘개 쪼개져서 격리된 모듈과 순수함수로 코드를 구현하고, 작은 context 토큰 범위와 기획 문서를 제공한다면 비교적 정확한 테스트케이스를 뽑아낼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 컨벤션 강제&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1756744086078&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
description: Always apply modularization and abstraction principles for maintainable frontend architecture
alwaysApply: true
---

## Core Principles

### 1. Side Effect Isolation

- Treat code that depends on environment (time, network, browser API) as **side effects**.
- Isolate side effects into separate modules or inject them as parameters.
- In tests, mock side-effect modules to avoid flaky results.
- Keep core functions as pure as possible.

### 2. Component Layer Separation

- Split each component into the following logical layers:
  1. **UI (Render)** &amp;ndash; Pure presentational JSX, no business logic.
  2. **State** &amp;ndash; State management hooks, selectors, store.
  3. **Domain Logic** &amp;ndash; Business rules and computations.
  4. **Network (API)** &amp;ndash; Data fetching/mutations, isolated into API modules.
- Ensure that these layers communicate via explicit interfaces.

### 3. Strategy Pattern &amp;amp; Dependency Injection

- For business policies or algorithms that may change (e.g., payment calculation, discount rules):
  - Define them as strategy interfaces.
  - Implement strategies separately.
  - Inject the strategy into components/hooks instead of hardcoding.
- Components should depend only on the interface, not concrete implementations.

### 4. Domain Policy Ownership

- Avoid embedding business policy data directly in frontend code.
- Fetch policies from backend whenever possible.
- Frontend focuses on **how** to display/use the data, backend controls **what** policy applies.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 코드들이 규칙대로 잘 짜여졌다면 더욱 강력해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 짤때, 팀이 원하는 스타일 및 컨밴션으로 코드를 구현하도록 권장합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 마구잡이로 코드를 짜는걸 방지해주죠&lt;/p&gt;
&lt;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;1880&quot; data-start=&quot;1872&quot; data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2043&quot; data-start=&quot;1881&quot; data-ke-size=&quot;size16&quot;&gt;정리하자면, Cursor 룰은 &amp;ldquo;AI에게 우리 팀의 개발 문화를 주입하는 장치&quot;라고 볼 수 있습니다.&lt;br /&gt;단순한 스타일 교정이 아니라, 아키텍처, 성능, 보안, 접근성, 테스트 등 다양한 영역의 원칙을 미리 정의해두고 이를 코드 생성 단계에 반영할 수 있다는 점이 큰 장점입니다.&lt;/p&gt;
&lt;p data-end=&quot;2128&quot; data-start=&quot;2045&quot; data-ke-size=&quot;size16&quot;&gt;덕분에 개발팀은 규칙을 반복적으로 확인하거나 리뷰에서 같은 지적을 주고받을 필요가 줄어들고, 진짜 중요한 설계와 문제 해결에 집중할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으론 문서화가 제일 마음에 드네요. 코드 리뷰 전 코드 품질을 높이기 위한 하나의 셀프 피드백 단계를 추가한 느낌입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 클로드 코드도 대단하다는데 거기까진 못써봤네요&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다만 오픈소스에서 클로드코드로 나온 결과물 코드를 몇개 봤는데 장난 아닌듯 싶습니다..&lt;/p&gt;</description>
      <category>Front-end/work</category>
      <author>lodado</author>
      <guid isPermaLink="true">https://lodado.tistory.com/105</guid>
      <comments>https://lodado.tistory.com/105#entry105comment</comments>
      <pubDate>Tue, 2 Sep 2025 01:34:17 +0900</pubDate>
    </item>
    <item>
      <title>다국어 지원(i18n)과 SEO 향상 가이드</title>
      <link>https://lodado.tistory.com/104</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1391&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lovol/btsOa3vgcb9/BANIs6gq0yAefKYqzyyODK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lovol/btsOa3vgcb9/BANIs6gq0yAefKYqzyyODK/img.png&quot; data-alt=&quot;다국어 홈페이지 사이드 프로젝트에 접속한 전세계 유저 리스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lovol/btsOa3vgcb9/BANIs6gq0yAefKYqzyyODK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flovol%2FbtsOa3vgcb9%2FBANIs6gq0yAefKYqzyyODK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1391&quot; height=&quot;483&quot; data-origin-width=&quot;1391&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;다국어 홈페이지 사이드 프로젝트에 접속한 전세계 유저 리스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전 세계 사람들이 나에게 1원씩만(광고 수익) 주면 부자가 되지 않을까..? 싶어서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;16개국 다국어 지원을 통하여 사이드 프로젝트 홈페이지를 만들고 테스트해봤는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느정도 만족스러운 결과가 나와서 그 과정을 이 글에 공유해봅니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다국어 지원은 chatgpt AI로 번역했고, SEO 다국어 지원이 가능한지 가설 및 검증은 아래 링크의 &quot;두루미스&quot; 플랫폼을 참고해서 구현했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.naver.com/dreamyoungs_inc/223425945113&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://blog.naver.com/dreamyoungs_inc/223425945113&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748160239260&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;두루미스에 글을 작성하면 다른 언어들로 검색이 잘 될까요?&quot; data-og-description=&quot;두루미스(durumis) 블로그 서비스를 개발하면서 저희도 가끔 고민했던 부분은 구글 검색에 다양한 언어로 ...&quot; data-og-host=&quot;blog.naver.com&quot; data-og-source-url=&quot;https://blog.naver.com/dreamyoungs_inc/223425945113&quot; data-og-url=&quot;https://blog.naver.com/dreamyoungs_inc/223425945113&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bU097N/hyYYthYknn/FslmjKCK85pF8CSL8HXQ9k/img.png?width=743&amp;amp;height=390&amp;amp;face=0_0_743_390&quot;&gt;&lt;a href=&quot;https://blog.naver.com/dreamyoungs_inc/223425945113&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.naver.com/dreamyoungs_inc/223425945113&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bU097N/hyYYthYknn/FslmjKCK85pF8CSL8HXQ9k/img.png?width=743&amp;amp;height=390&amp;amp;face=0_0_743_390');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;두루미스에 글을 작성하면 다른 언어들로 검색이 잘 될까요?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;두루미스(durumis) 블로그 서비스를 개발하면서 저희도 가끔 고민했던 부분은 구글 검색에 다양한 언어로 ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 이 글에서는 &quot;i18n을 어떻게 적용하는지&quot;까지 내용에 넣으면 글이 너무 길어지기 때문에 다루지 않습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;next-intl등 여러 좋은 방식을 찾아보길 추천드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SEO란?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;SEO&lt;/b&gt;(Search Engine Optimization, 검색엔진 최적화)는 우리가 작성한 블로그 글이 &lt;b&gt;구글&lt;/b&gt; 같은 검색 엔진 결과에서 더 잘 보이도록 만들어주는 과정입니다. 처음에는 다소 복잡해 보일 수 있지만, 하나씩 따라 해 보시면 분명 홈페이지 노출에 큰 도움이 될 거예요. 이 글에서는 &lt;b&gt;SEO의 기초 개념&lt;/b&gt;부터 &lt;b&gt;온페이지/테크니컬/오프페이지 SEO&lt;/b&gt;, &lt;b&gt;구조화 데이터 활용&lt;/b&gt;, &lt;b&gt;유용한 도구&lt;/b&gt;, 그리고 &lt;b&gt;배포 전 체크리스트&lt;/b&gt;까지 차근차근 설명해 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;403&quot; data-start=&quot;383&quot; data-ke-size=&quot;size23&quot;&gt;1. SEO 기본 용어 이해하기&lt;/h3&gt;
&lt;p data-end=&quot;483&quot; data-start=&quot;405&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;먼저 SEO를 공부할 때 자주 접하는 &lt;b&gt;핵심 용어&lt;/b&gt;들을 알아보겠습니다. 어려운 영어 용어도 많지만, 최대한 쉽게 풀어서 설명해 드릴게요.&lt;/p&gt;
&lt;p data-end=&quot;483&quot; data-start=&quot;405&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3226&quot; data-start=&quot;485&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;714&quot; data-start=&quot;485&quot;&gt;&lt;b&gt;크롤링 (Crawling)&lt;/b&gt;: 검색 엔진의 로봇 프로그램인 &lt;b&gt;크롤러&lt;/b&gt;(crawler)가 웹사이트의 페이지들을 &lt;b&gt;찾아다니며 콘텐츠를 수집&lt;/b&gt;하는 과정입니다. 예를 들어 구글의 크롤러인 &lt;b&gt;Googlebot&lt;/b&gt;이 여러분의 블로그 글을 발견하고 내용을 긁어가는 작업이죠. 크롤링이 잘 되어야 내 블로그 글이 검색엔진에 알려지게 됩니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;944&quot; data-start=&quot;716&quot;&gt;&lt;b&gt;인덱싱 (Indexing)&lt;/b&gt;: 크롤링한 페이지들을 &lt;b&gt;검색 엔진의 데이터베이스에 저장하고 정리&lt;/b&gt;하는 과정입니다. 검색 엔진은 수집된 정보를 분류하고 색인(인덱스)을 만들어 두는데, 도서관에서 책을 분류해 두는 것과 비슷합니다.&lt;br /&gt;&amp;nbsp;페이지의 &lt;b&gt;키워드&lt;/b&gt;나 내용에 따라 잘 정리되어야 사용자가 검색할 때 해당 페이지가 나타날 수 있어요.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;1280&quot; data-start=&quot;946&quot;&gt;&lt;b&gt;검색 결과 페이지 (SERP)&lt;/b&gt;: &lt;b&gt;Search Engine Results Page&lt;/b&gt;의 줄임말로, 말 그대로 사용자가 어떤 키워드로 검색했을 때 나오는 &lt;b&gt;검색 엔진 결과 페이지&lt;/b&gt;를 뜻합니다. 특히 &lt;b&gt;첫 번째 페이지 결과&lt;/b&gt;를 SERP라고 부르는 경우가 많습니다. 대부분의 사용자들은 검색 결과 첫 페이지까지만 보고 끝내기 때문에(75% 이상이 첫 페이지에서 검색을 마친다고 합니다).&amp;nbsp;내 블로그 글이 SERP 상위에 노출되는 것이 매우 중요합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;1490&quot; data-start=&quot;1282&quot;&gt;&lt;b&gt;메타 태그 (Meta Tag)&lt;/b&gt;: 웹페이지의 &amp;lt;head&amp;gt; 영역에 들어가는 메타데이터(정보)로서, 검색 엔진과 브라우저에게 페이지 정보를 제공합니다. 대표적으로 제목(title)과 &lt;b&gt;설명(description)&lt;/b&gt; 메타태그가 중요합니다. 메타 태그는 방문자 눈에는 직접 보이지 않지만, 검색 결과 목록에 표시되는 &lt;b&gt;제목과 설명&lt;/b&gt;을 결정합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;1912&quot; data-start=&quot;1492&quot;&gt;&lt;b&gt;캐노니컬 태그 (Canonical Tag)&lt;/b&gt;: 동일하거나 매우 비슷한 콘텐츠가 &lt;b&gt;여러 URL로 중복&lt;/b&gt;돼 있을 때, &lt;br /&gt;검색 엔진에 &quot;이 페이지의 원본은 이것이에요!&quot; 하고 알려주는 태그입니다. &amp;lt;head&amp;gt; 안에 &amp;lt;link rel=&quot;canonical&quot; href=&quot;정규 URL&quot;&amp;gt; 형태로 넣습니다. 이 태그를 지정하면 검색 엔진은 중복 페이지들 중 &lt;b&gt;canonical로 지정된 URL을 대표 페이지&lt;/b&gt;로 간주하여 랭킹 신호를 집중시킵니다.&amp;nbsp;예를 들어, example.com?page=1이나 example.com/index.html 등 여러 주소로 접속되는 같은 내용의 페이지가 있다면 하나를 canonical로 지정해야 불필요한 중복 색인을 막을 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;** 찾아본 결과, 다국어 홈페이지는 각각 번역한 페이지가 자신의 canoinical Tag 주인이 되는게 유리합니다.!&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;2277&quot; data-start=&quot;1914&quot;&gt;&lt;b&gt;사이트맵 (sitemap.xml)&lt;/b&gt;: 웹사이트의 &lt;b&gt;모든 페이지 목록을 모아둔 파일&lt;/b&gt;로, 책의 목차 같은 역할을 합니다. 주로 XML 형식으로 작성되며 사이트의 최상위 경로(예: https://내블로그/sitemap.xml)에 위치합니다. 사이트맵을 검색 엔진에 제출해 두면 &lt;b&gt;크롤러가 사이트 구조를 한눈에 파악&lt;/b&gt;하여, 평소 찾기 어려운 페이지도 빠짐없이 크롤링하고 인덱싱할 수 있게 됩니다&lt;br /&gt;&amp;nbsp;(※ 티스토리의 경우 기본적으로 RSS 피드가 사이트맵 역할을 하지만, 필요에 따라 직접 sitemap.xml을 제작해 Search Console에 제출할 수도 있습니다.)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;2694&quot; data-start=&quot;2279&quot;&gt;&lt;b&gt;robots.txt&lt;/b&gt;: 웹사이트 최상위 경로(루트 디렉터리)에 두는 &lt;b&gt;텍스트 파일&lt;/b&gt;로, &lt;b&gt;검색 엔진 크롤러의 접근을 제어&lt;/b&gt;하는 지침을 적어둡니다. 예를 들어 &quot;이러이러한 곳은 크롤링하지 마!&quot; 혹은 &quot;이 사이트맵 파일 위치는 여기야!&quot; 하는 내용을 담습니다.&lt;br /&gt;&lt;b&gt;robots.txt&lt;/b&gt; 파일이 없으면 크롤러는 웹사이트에서 접근할 수 있는 모든 페이지를 자유롭게 크롤링하며 특정 페이지를 검색 결과에 나오지 않게 막고 싶다면 robots.txt에 경로를 지정해 차단할 수 있습니다. &lt;br /&gt;또한 robots.txt 맨 아래에 Sitemap: 지시어를 넣어 사이트맵 위치도 알려줄 수 있어요.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;3226&quot; data-start=&quot;2696&quot;&gt;&lt;b&gt;구조화 데이터 (Structured Data)&lt;/b&gt;: 페이지의 내용을 검색 엔진이 더 &lt;b&gt;체계적으로 이해할 수 있도록&lt;/b&gt; 추가하는 특별한 형식의 데이터입니다. 예를 들어 블로그 글이 어떤 주제의 &lt;b&gt;기사인지, 작성자는 누구인지, 게시 날짜는 언제인지&lt;/b&gt; 등을 구조화된 형식으로 마크업하면, 검색 엔진이 그것을 읽고 이해하여 검색 결과에 풍부한 정보(리치 결과)를 보여줄 수 있습니다. 구조화 데이터는 주로 &lt;b&gt;스키마.org&lt;/b&gt; 형태로 표현하며, HTML &amp;lt;script&amp;gt; 태그 안에 &lt;b&gt;JSON-LD&lt;/b&gt; 형식으로 넣는 방법이 권장됩니다. 이를 적용하면 검색 결과에서 별점, 자주 묻는 질문(FAQ), 빵부스러기 경로 등 &lt;b&gt;추가 정보&lt;/b&gt;가 표시될 수 있어 클릭률을&lt;/li&gt;
&lt;li data-end=&quot;3226&quot; data-start=&quot;2696&quot;&gt;높이는 데 도움이 됩니다. (실제로 &lt;b&gt;리치 결과&lt;/b&gt;로 표시된 페이지는 일반 결과보다 클릭률이 &lt;b&gt;82%&lt;/b&gt; 높았다는 사례도 있습니다)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 용어가 뭘 뜻하는지 글 아래에서 차근차근 알려드릴게요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;3302&quot; data-start=&quot;3284&quot; data-ke-size=&quot;size23&quot;&gt;2. 온페이지 SEO 최적화&lt;/h3&gt;
&lt;p data-end=&quot;3451&quot; data-start=&quot;3304&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;온페이지 SEO&lt;/b&gt;는 말 그대로 &lt;b&gt;페이지 내부에서 할 수 있는 최적화 작업&lt;/b&gt;입니다. 블로그 글의 콘텐츠와 HTML 구조를 잘 정돈하여 &lt;b&gt;검색 엔진 친화적&lt;/b&gt;으로 만드는 것을 의미합니다. 특히 티스토리 블로그 글을 작성할 때 아래 요소들을 신경 써 보세요.&lt;/p&gt;
&lt;p data-end=&quot;3451&quot; data-start=&quot;3304&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;3502&quot; data-start=&quot;3453&quot; data-ke-size=&quot;size20&quot;&gt;메타 태그 최적화: 제목(title)과 &lt;b&gt;설명(description)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3660&quot; data-start=&quot;3504&quot; data-ke-size=&quot;size16&quot;&gt;온페이지 SEO의 첫 걸음은 &lt;b&gt;메타태그&lt;/b&gt; 설정입니다. 검색 엔진은 페이지의 &amp;lt;title&amp;gt; 태그와 &amp;lt;meta name=&quot;description&quot;&amp;gt; 태그를 읽어 해당 페이지의 제목과 요약을 이해합니다. 이 두 가지를 잘 써주는 것만으로도 SEO 효과를 크게 볼 수 있습니다:&lt;/p&gt;
&lt;p data-end=&quot;3660&quot; data-start=&quot;3504&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4209&quot; data-start=&quot;3662&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3916&quot; data-start=&quot;3662&quot;&gt;&lt;b&gt;제목 태그&lt;/b&gt;: 블로그 글 제목은 &amp;lt;title&amp;gt;에 해당하며, 검색 결과에 &lt;b&gt;파란색 큰 제목&lt;/b&gt;으로 표시됩니다. 글 내용과 밀접하며 &lt;b&gt;핵심 키워드&lt;/b&gt;를 포함한 제목을 작성하세요. 예를 들어 이 글의 제목이 &amp;lt;title&amp;gt;티스토리 초보 개발자를 위한 블로그 SEO 가이드&amp;lt;/title&amp;gt;라면, &quot;티스토리&quot;, &quot;개발자&quot;, &quot;SEO 가이드&quot; 같은 키워드가 담겨 있죠. 너무 길지 않게 (권장 50~60자 이내) 명확한 제목을 정하는 것이 좋습니다.&lt;/li&gt;
&lt;li data-end=&quot;4209&quot; data-start=&quot;3918&quot;&gt;&lt;b&gt;메타 설명&lt;/b&gt;: &amp;lt;meta name=&quot;description&quot; content=&quot;...&quot;&amp;gt; 부분에 글 요약을 넣을 수 있습니다. 이 내용은 검색 결과의 &lt;b&gt;회색 설명문구&lt;/b&gt;로 나타나며, 사용자들이 이 글을 클릭할지 결정하는 데 큰 영향을 줍니다. &lt;b&gt;간결하면서도 흥미를 끄는 요약&lt;/b&gt;을 1~2문장 정도 작성해 보세요. (티스토리에서는 글 작성 시 &lt;b&gt;본문 요약&lt;/b&gt; 또는 &lt;b&gt;설명&lt;/b&gt; 입력란이 있다면 활용하시면 됩니다.) 만약 메타 설명을 직접 작성하지 않으면, 검색 엔진이 본문 일부를 자동으로 발췌해 보여줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4240&quot; data-start=&quot;4211&quot; data-ke-size=&quot;size16&quot;&gt;예시로 HTML 메타태그를 작성하면 다음과 같습니다&lt;/p&gt;
&lt;pre id=&quot;code_1748160474471&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;티스토리 초보 개발자를 위한 블로그 SEO 가이드&amp;lt;/title&amp;gt;
  &amp;lt;meta name=&quot;description&quot; content=&quot;티스토리에서 기술 블로그를 시작한 초심자 개발자를 위한 SEO 최적화 방법을 소개합니다.&quot;&amp;gt;
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 제목과 설명을 명확히 해 두면, 검색 엔진에 내 콘텐츠를 잘 소개하고 사용자도 클릭하기 전에 내용을 파악하기 쉬워집니다. 티스토리도 잘 찾아보시면 위 태그가 존재해요.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-end=&quot;4507&quot; data-start=&quot;4478&quot; data-ke-size=&quot;size20&quot;&gt;2-1) 시멘틱 태그 및 헤딩 태그 활용: &lt;b&gt;H1~H3 구조 잡기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4600&quot; data-start=&quot;4509&quot; data-ke-size=&quot;size16&quot;&gt;블로그 글을 작성할 때 시멘틱 태그를 체계적으로 사용하는 것도 중요합니다. 예시 한가지로 &lt;b&gt;헤딩(heading)&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;태그를 들어볼게요.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;4600&quot; data-start=&quot;4509&quot; data-ke-size=&quot;size16&quot;&gt;헤딩은 글의 &lt;b&gt;제목과 소제목&lt;/b&gt;들을 나타내는 HTML 태그인데요:&lt;/p&gt;
&lt;p data-end=&quot;4600&quot; data-start=&quot;4509&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4890&quot; data-start=&quot;4602&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4710&quot; data-start=&quot;4602&quot;&gt;&amp;lt;h1&amp;gt;: 한 페이지에 &lt;b&gt;단 한 번만&lt;/b&gt; 사용하는 &lt;b&gt;최상위 제목&lt;/b&gt;입니다. 일반적으로 블로그 글의 제목이 h1에 해당합니다 (티스토리에서는 글 제목을 자동으로 h1으로 처리해줍니다).&lt;/li&gt;
&lt;li data-end=&quot;4890&quot; data-start=&quot;4711&quot;&gt;&amp;lt;h2&amp;gt;, &amp;lt;h3&amp;gt;: 글의 주요 섹션 제목(h2)과 그 하위 소제목(h3)에 사용합니다. 글의 흐름을 논리적으로 나누어 주며, &lt;b&gt;중요한 키워드&lt;/b&gt;를 적절히 포함해 주는 게 좋습니다. 예를 들어 지금 보고 계신 글도 각 큰 챕터 제목이 h2, 그 안의 작은 주제가 h3 태그로 구성되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;5068&quot; data-start=&quot;4892&quot; data-ke-size=&quot;size16&quot;&gt;검색 엔진은 헤딩 구조를 통해 이 페이지가 어떤 &lt;b&gt;주요 주제와 하위 주제&lt;/b&gt;들로 이루어져 있는지 파악합니다. 따라서 헤딩을 계층적으로 잘 쓰면 검색엔진이 콘텐츠를 이해하기 쉽고, 독자들도 글을 한눈에 보기 편해집니다. 아래는 간단한 예시입니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748160592731&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;h1&amp;gt;블로그 글 제목 (예: 웹 접근성 가이드)&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;여는 문단...&amp;lt;/p&amp;gt;

&amp;lt;h2&amp;gt;1. 접근성이란 무엇인가?&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;...설명...&amp;lt;/p&amp;gt;

&amp;lt;h3&amp;gt;접근성의 중요 요소&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;...설명...&amp;lt;/p&amp;gt;

&amp;lt;h2&amp;gt;2. 접근성을 향상시키는 방법&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;...설명...&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 h1 -&amp;gt; h2 -&amp;gt; h3 순으로 &lt;b&gt;논리적인 아웃라인&lt;/b&gt;을 만들고, 단순히 글자 크기를 키우는 용도로 쓰지 않도록 주의하세요. 디자인을 위해 글자 크기를 키울 때는 CSS를 사용하고, 의미적인 구조는 헤딩 태그로 표현하는 것이 SEO에 좋습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;5429&quot; data-start=&quot;5397&quot; data-ke-size=&quot;size20&quot;&gt;2-2) 내부 링크 구성하기: &lt;b&gt;사이트 내 유기적 연결&lt;/b&gt;&lt;/h4&gt;
&lt;p data-end=&quot;5565&quot; data-start=&quot;5431&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내부 링크&lt;/b&gt;란 내 블로그의 다른 글이나 페이지를 본문 중에 연결하는 것입니다. 예를 들어 &lt;b&gt;이전 글&lt;/b&gt;이나 &lt;b&gt;관련 글&lt;/b&gt;이 있다면 본문에서 해당 키워드에 하이퍼링크를 걸어두는 식이죠. 내부 링크 최적화를 위한 팁은 다음과 같습니다:&lt;/p&gt;
&lt;p data-end=&quot;5565&quot; data-start=&quot;5431&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;6067&quot; data-start=&quot;5567&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5704&quot; data-start=&quot;5567&quot;&gt;&lt;b&gt;관련 글 연결&lt;/b&gt;: 현재 작성 중인 글과 주제가 비슷하거나 참고하면 좋을 &lt;b&gt;이전 글이 있다면 링크&lt;/b&gt;를 거세요. 예를 들어 &quot;지난 번에 HTTP와 HTTPS 차이에 대해 다뤘는데, 자세한 내용은 &lt;span data-end=&quot;5690&quot; data-start=&quot;5681&quot;&gt;이 글&lt;/span&gt;에서 확인하세요.&quot;처럼요.&lt;/li&gt;
&lt;li data-end=&quot;5907&quot; data-start=&quot;5705&quot;&gt;&lt;b&gt;키워드 앵커텍스트&lt;/b&gt;: 링크를 걸 때 클릭 here 같은 문구 대신 &lt;b&gt;해당 페이지를 잘 나타내는 키워드&lt;/b&gt;로 링크를 거는 것이 좋습니다. 예를 들어 데이터베이스 성능 튜닝 글이라면 &quot;데이터베이스 인덱싱 기법에 대해서는 이전 포스팅 &lt;b&gt;인덱싱 최적화 방법&lt;/b&gt;을 참고하세요.&quot; 이렇게 &lt;b&gt;굵은 키워드 부분에 링크&lt;/b&gt;를 거는 것이 SEO에 도움이 됩니다.&lt;/li&gt;
&lt;li data-end=&quot;6067&quot; data-start=&quot;5908&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;/ul&gt;
&lt;p data-end=&quot;6186&quot; data-start=&quot;6069&quot; data-ke-size=&quot;size16&quot;&gt;내부 링크를 너무 과하게 걸 필요는 없지만, &lt;b&gt;자연스럽게 연결될 수 있는 부분이 있으면 적극 활용&lt;/b&gt;해 보세요. 티스토리에서는 글 작성 시 편집기에서 링크 아이콘을 눌러 쉽게 본문 링크를 추가할 수 있습니다.&lt;/p&gt;
&lt;blockquote data-end=&quot;6345&quot; data-start=&quot;6188&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;6345&quot; data-start=&quot;6190&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고:&lt;/b&gt; 온페이지 SEO에서는 이 외에도 이미지의 대체 텍스트(alt 속성)를 넣어주는 것, &lt;b&gt;모바일 친화적 디자인&lt;/b&gt;을 사용하는 것, &lt;b&gt;페이지 로딩 속도&lt;/b&gt;를 높이는 것 등이 모두 포함됩니다. 하지만 이러한 부분은 아래 테크니컬 SEO에서 추가로 다루겠습니다.&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;** 글을 잘 쓰면 자발적으로 사람들이 레퍼런스로 참조하겠죠? 글 품질이 중요한 부분입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;6382&quot; data-start=&quot;6347&quot; data-ke-size=&quot;size23&quot;&gt;3. 테크니컬 SEO (Technical SEO) 고려사항&lt;/h3&gt;
&lt;p data-end=&quot;6549&quot; data-start=&quot;6384&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이제 &lt;b&gt;테크니컬 SEO&lt;/b&gt; 분야로 넘어가 보겠습니다. 테크니컬 SEO는 말 그대로 &lt;b&gt;사이트 기술적 요소들을 최적화&lt;/b&gt;하여 검색 엔진이 사이트를 더 잘 크롤링/인덱싱하고, 사용자에게도 더 나은 경험을 제공하도록 하는 작업들입니다. 초심자 개발자 분들도 알아두면 좋은 주요 항목을 살펴보겠습니다.&lt;/p&gt;
&lt;p data-end=&quot;6549&quot; data-start=&quot;6384&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;6573&quot; data-start=&quot;6551&quot; data-ke-size=&quot;size20&quot;&gt;3-1) Canonical URL 설정하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;6848&quot; data-start=&quot;6575&quot; data-ke-size=&quot;size16&quot;&gt;앞서 용어 설명에서 다룬 &lt;b&gt;캐노니컬 태그&lt;/b&gt;를 다시 한 번 강조합니다. 만약 티스토리 블로그에서 &lt;b&gt;동일한 콘텐츠가 여러 경로&lt;/b&gt;로 접근될 수 있다면 canonical 설정을 고려해야 합니다. 예를 들어, &quot;http://&quot;로도 열리고 &quot;https://&quot;로도 열리거나, ?category=... 같은 파라미터에 따라 같은 글이 다른 URL로 보이는 경우가 있을 수 있습니다. 이런 상황에서는 페이지 &amp;lt;head&amp;gt;에 다음과 같이 원본 URL을 지정하는 캐노니컬 태그를 넣습니다:&lt;/p&gt;
&lt;p data-end=&quot;6848&quot; data-start=&quot;6575&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748160676846&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;link rel=&quot;canonical&quot; href=&quot;https://yourblog.tistory.com/원본글주소&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;6848&quot; data-start=&quot;6575&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;6848&quot; data-start=&quot;6575&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 검색 엔진은 중복된 여러 URL 중 &lt;b&gt;canonical로 지정된 주소만 대표로 취급&lt;/b&gt;하고 나머지는 중복으로 판단하여 &lt;b&gt;랭킹에 불이익이 없도록&lt;/b&gt; 처리해줍니다&lt;span data-state=&quot;closed&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p data-end=&quot;6848&quot; data-start=&quot;6575&quot; data-ke-size=&quot;size16&quot;&gt;티스토리 기본 도메인을 사용하는 경우에는 큰 문제는 없지만, &lt;b&gt;개인 도메인&lt;/b&gt;을 연결한 경우 yourblog.tistory.com와 www.yourdomain.com 두 가지 주소로 접속되는 이슈가 생길 수 있으니 이럴 때 canonical 태그로 하나로 정해주시면 좋습니다.&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;811&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clbGZq/btsObRf15p1/XXC35k56xjsOken1XkSOCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clbGZq/btsObRf15p1/XXC35k56xjsOken1XkSOCK/img.png&quot; data-alt=&quot;사이드 프로젝트에서 적용한 canonical Tag&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clbGZq/btsObRf15p1/XXC35k56xjsOken1XkSOCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclbGZq%2FbtsObRf15p1%2FXXC35k56xjsOken1XkSOCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;811&quot; height=&quot;442&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사이드 프로젝트에서 적용한 canonical Tag&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 대표 언어만 canonical tag로 설정해야할지 아니면 각 언어마다 canonical tag를 설정해야할지 헷갈렸었는데, 여러 페이지(&lt;a href=&quot;https://webmasters.stackexchange.com/questions/140553/use-of-canonical-tag-on-website-with-different-language-versions-and-separate-mo&quot;&gt;https://webmasters.stackexchange.com/questions/140553/use-of-canonical-tag-on-website-with-different-language-versions-and-separate-mo&lt;/a&gt;) 를 참고해보면 각 언어마다 canonical tag를 설정해주는게 옳은 방식이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이드 프로젝트에서 기본주소/{언어} 로 각 언어로 번역한 동일한 페이지를 만들어놓고, 각 페이지 별로 각각 카노니컬 태그를 설정해줬습니다. 예를 들어 /ko(한국어) 페이지에는 /ko가 canonical Tag 주인으로 설정되어 있고 다른 언어를 alternate로 설정해두었고, /ja(일본어) 페이지에선 /ja가 canonical Tag로 지정되어 있고 다른 언어들이 alternate로 지정되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;7257&quot; data-start=&quot;7229&quot; data-ke-size=&quot;size20&quot;&gt;3-2) 사이트맵 파일과 robots.txt 설정하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;7372&quot; data-start=&quot;7259&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;sitemap.xml&lt;/b&gt;과 &lt;b&gt;robots.txt&lt;/b&gt; 파일은 테크니컬 SEO의 기본이라 불립니다. 티스토리 블로그도 마찬가지로 이 개념을 이해하고 활용하면 검색 엔진 크롤러 친화적인 사이트가 됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;9086&quot; data-start=&quot;7374&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;8385&quot; data-start=&quot;7374&quot;&gt;&lt;b&gt;사이트맵(sitemap.xml)&lt;/b&gt;: 내 블로그의 글 목록(및 페이지 목록)을 모두 나열한 XML 파일입니다. 직접 작성하기 어렵다면 검색하면 &lt;b&gt;사이트맵 자동 생성 도구&lt;/b&gt;도 많으니 활용하시면 돼요. 완성된 sitemap.xml 파일은 &lt;b&gt;Search Console에 제출&lt;/b&gt;해서 구글에 알려줄 수 있습니다. 사이트맵을 제출해 두면 구글이 내 블로그의 &lt;b&gt;새 글도 빠르게 발견&lt;/b&gt;할 수 있고, 혹시 내부 링크가 부족해 못 찾는 페이지도 색인될 수 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;7698&quot; data-start=&quot;7679&quot;&gt;사이트맵 예시 (XML 형식):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1748161287095&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;urlset xmlns=&quot;http://www.sitemaps.org/schemas/sitemap/0.9&quot;&amp;gt;
  &amp;lt;url&amp;gt;
    &amp;lt;loc&amp;gt;https://yourblog.tistory.com/&amp;lt;/loc&amp;gt;
    &amp;lt;lastmod&amp;gt;2025-05-25&amp;lt;/lastmod&amp;gt;
    &amp;lt;priority&amp;gt;1.0&amp;lt;/priority&amp;gt;
  &amp;lt;/url&amp;gt;
  &amp;lt;url&amp;gt;
    &amp;lt;loc&amp;gt;https://yourblog.tistory.com/예시글1&amp;lt;/loc&amp;gt;
    &amp;lt;lastmod&amp;gt;2025-05-20&amp;lt;/lastmod&amp;gt;
    &amp;lt;priority&amp;gt;0.8&amp;lt;/priority&amp;gt;
  &amp;lt;/url&amp;gt;
  &amp;lt;!-- ...다른 URL들... --&amp;gt;
&amp;lt;/urlset&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;8385&quot; data-start=&quot;7374&quot;&gt;위 예시는 사이트의 홈 페이지와 어떤 글 하나를 목록에 넣은 것입니다. &amp;lt;lastmod&amp;gt;는 마지막 수정 날짜, &amp;lt;priority&amp;gt;는 페이지 중요도를 표시하는데 필수는 아니라서 없어도 괜찮습니다. 티스토리의 경우 기본 제공되는 RSS 피드를 이용해 Search Console에서 &lt;b&gt;사이트맵으로 등록&lt;/b&gt;할 수 있습니다. (티스토리 RSS가 글 목록을 제공하므로 사실상 사이트맵 역할을 일부 합니다.)&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;9086&quot; data-start=&quot;8387&quot;&gt;&lt;b&gt;robots.txt&lt;/b&gt;: 사이트의 루트(최상위 경로)에 robots.txt라는 텍스트 파일을 두면 검색 로봇들이 먼저 이를 확인합니다. 이 파일 안에는 &lt;b&gt;크롤링 허용/비허용 규칙&lt;/b&gt;과 &lt;b&gt;사이트맵 위치&lt;/b&gt; 등을 기술할 수 있습니다&lt;span&gt;&lt;/span&gt;&amp;nbsp;티스토리 공식 도메인은 기본적인 robots.txt가 자동으로 설정되어 있어 수정할 순 없지만, &lt;b&gt;개인 도메인&lt;/b&gt;을 사용하면서 직접 서버를 운영한다면 robots.txt를 직접 만들어야 합니다.&lt;br /&gt;&lt;br /&gt;robots.txt 예시:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1748161355530&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;User-agent: *
Disallow: /admin/
Allow: /

Sitemap: https://yourblog.tistory.com/sitemap.xml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용은 모든 크롤러(User-agent: *) 에게 /admin/ 경로는 크롤링하지 말라고 지시하고, 그 외는 모두 허용(Allow)하는 설정입니다. 마지막 줄에는 사이트맵 URL을 명시했습니다. 대다수의 경우 특별히 숨기고 싶은 페이지가 없다면 Disallow 지시자 없이 &lt;b&gt;모두 허용&lt;/b&gt;하는 것이 좋습니다. 참고로 &lt;b&gt;robots.txt를 잘못 설정해서 전체 사이트를 Disallow해버리면 검색 유입에 치명적&lt;/b&gt;이니, 항상 조심해서 다뤄주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;9131&quot; data-start=&quot;9088&quot; data-ke-size=&quot;size20&quot;&gt;3-3) Core Web Vitals 지표 개선하기 (LCP, INP, CLS)&lt;/h4&gt;
&lt;p data-end=&quot;9310&quot; data-start=&quot;9133&quot; data-ke-size=&quot;size16&quot;&gt;구글은 사용자 경험을 중시하기 때문에, &lt;b&gt;웹 성능 지표&lt;/b&gt;들도 검색 순위에 반영하고 있습니다. 특히 Core Web Vitals(코어 웹 바이탈)라는 세 가지 주요 지표를 정의하여 사이트 품질을 평가하고 있는데요, 각각 다음을 의미합니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;10094&quot; data-start=&quot;9312&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;9553&quot; data-start=&quot;9312&quot;&gt;&lt;b&gt;LCP (Largest Contentful Paint)&lt;/b&gt;: &lt;b&gt;최대 콘텐츠 표시 시간&lt;/b&gt;으로, 페이지 로드 시작 후 가장 큰 콘텐츠 요소(이미지 또는 큰 텍스트 블록 등)가 화면에 나타나는 데 걸리는 시간입니다. 쉽게 말해 &lt;b&gt;본격적인 내용이 로딩되는 속도&lt;/b&gt;라고 볼 수 있어요. &lt;b&gt;2.5초 이내&lt;/b&gt;에 LCP가 발생하면 좋은 것으로 평가됩니다.&lt;/li&gt;
&lt;li data-end=&quot;9847&quot; data-start=&quot;9555&quot;&gt;&lt;b&gt;INP (Interaction to Next Paint)&lt;/b&gt;: &lt;b&gt;다음 페인트까지의 상호작용&lt;/b&gt;으로, 사용자가 페이지에서 어떤 동작(클릭 등)을 했을 때 다음 화면이 그 동작에 반응하여 렌더링되기까지의 시간입니다. 이는 &lt;b&gt;인터랙션 반응성&lt;/b&gt;을 측정하는 지표입니다. &lt;b&gt;0.2초(200ms) 미만&lt;/b&gt;이면 우수한 것으로 간주됩니다.&amp;nbsp;(기존에는 FID(첫 입력 지연) 지표를 사용했지만, INP가 보다 포괄적인 지표로 새롭게 도입되었습니다.)&lt;/li&gt;
&lt;li data-end=&quot;10094&quot; data-start=&quot;9849&quot;&gt;&lt;b&gt;CLS (Cumulative Layout Shift)&lt;/b&gt;: &lt;b&gt;누적 레이아웃 이동&lt;/b&gt; 점수로, 페이지 로딩 중 &lt;b&gt;예상치 못한 레이아웃 변경&lt;/b&gt;이 얼마나 발생하는지를 수치화한 것입니다. 예를 들어 이미지가 늦게 로드되어 텍스트가 밀려난다거나, 광고 삽입으로 화면 요소들이 튀는 경우 CLS 점수가 높아집니다. &lt;b&gt;0.1 이하&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-end=&quot;10219&quot; data-start=&quot;10096&quot; data-ke-size=&quot;size16&quot;&gt;이 세 가지 지표는 사용자에게 &lt;b&gt;쾌적한 페이지 경험&lt;/b&gt;을 제공하는지를 나타내며, 구글 검색에서도 중요한 참고 신호로 사용되고 있습니다. &lt;b&gt;그렇다면, 각 지표를 어떻게 개선할 수 있을까요?&lt;/b&gt; 몇 가지 팁을 소개합니다:&lt;/p&gt;
&lt;p data-end=&quot;10219&quot; data-start=&quot;10096&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;10953&quot; data-start=&quot;10221&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;10448&quot; data-start=&quot;10221&quot;&gt;&lt;b&gt;LCP 개선&lt;/b&gt;: 가장 큰 요소가 빨리 나타나도록 사이트를 최적화하세요. 예를 들어 &lt;b&gt;첫 화면에 보이는 이미지&lt;/b&gt; 용량을 줄이고, 필요한 경우 지연 로드(lazy-load)는 아래쪽 이미지에만 적용합니다. 또, 서버 응답속도를 높이거나 CDN을 이용해 콘텐츠 전송을 빠르게 하는 것도 LCP 향상에 도움이 됩니다. 한마디로 &lt;b&gt;사용자가 첫 콘텐츠를 빨리 볼 수 있게&lt;/b&gt; 해주는 작업들입니다.&lt;/li&gt;
&lt;li data-end=&quot;10696&quot; data-start=&quot;10450&quot;&gt;&lt;b&gt;INP 개선&lt;/b&gt;: 자바스크립트 등의 &lt;b&gt;대응 속도를 높이기&lt;/b&gt; 위해 노력합니다. 너무 무거운 스크립트는 비동기로 로드하거나 필요한 부분만 실행하고, 사용자가 상호작용할 때 메인 쓰레드를 오랫동안 블로킹하지 않도록 코드를 최적화합니다. 복잡한 작업은 Web Worker 등으로 분산하거나, 애니메이션 및 이벤트 핸들러를 효율적으로 작성하는 등의 방법이 있습니다. 결과적으로 &lt;b&gt;사용자 조작에 즉각 반응하는 페이지&lt;/b&gt;를 만들자는 것이죠.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;10953&quot; data-start=&quot;10698&quot;&gt;&lt;b&gt;CLS 개선&lt;/b&gt;: 로딩 중 &lt;b&gt;레이아웃이 튀지 않도록&lt;/b&gt; 미리 대비합니다. 예를 들어 &lt;b&gt;이미지에는 width/height 속성&lt;/b&gt;을 지정하여 자리가 미리 확보되게 하고, 광고나 동적 콘텐츠가 삽입되는 공간도 최소한의 높이를 미리 예약해 둡니다. 글꼴이 로드되며 갑자기 텍스트가 커지는 경우도 있으니, 웹폰트 사용 시 FOIT/FOUT 현상도 신경 쓰는 것이 좋습니다. 핵심은 &lt;b&gt;사용자 스크롤 중에 내용이 밀려서 불편하지 않게&lt;/b&gt; 만드는 것입니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;11163&quot; data-start=&quot;10955&quot; data-ke-size=&quot;size16&quot;&gt;위 개선 사항들은 모두 개발 단계에서 조금씩 신경 써야 하는 부분이지만, 초심자 분들도 이미지 크기 최적화나 불필요한 스크립트 최소화, 그리고 티스토리에서 제공하는 &lt;b&gt;반응형 스킨&lt;/b&gt; 등을 활용하는 것으로도 충분히 시작할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;11163&quot; data-start=&quot;10955&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;11185&quot; data-start=&quot;11165&quot; data-ke-size=&quot;size20&quot;&gt;3-4) HTTPS 보안 적용의 필요성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;11364&quot; data-start=&quot;11187&quot; data-ke-size=&quot;size16&quot;&gt;마지막 테크니컬 요소로 &lt;b&gt;HTTPS&lt;/b&gt;에 대해 짚고 넘어가겠습니다. &lt;b&gt;HTTPS&lt;/b&gt;는 HTTP에 보안 프로토콜(TLS)이 추가된 것으로, 사용자와 서버 사이의 통신을 암호화하여 도청이나 위변조를 방지합니다. 오늘날 웹 환경에서 &lt;b&gt;HTTPS는 사실상 기본&lt;/b&gt;이며, &lt;b&gt;SEO 측면에서도 매우 중요&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-end=&quot;11364&quot; data-start=&quot;11187&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;11621&quot; data-start=&quot;11366&quot; data-ke-size=&quot;size16&quot;&gt;구글은 이미 2014년에 HTTPS 사용 여부를 &lt;b&gt;랭킹 신호&lt;/b&gt;로 활용하기 시작했다고 발표한 바 있습니다&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. 비록 영향력은 작다고 했지만 시간이 지날수록 중요도가 커지고 있고, 현재는 &lt;b&gt;HTTPS가 기본이 된 사이트&lt;/b&gt;들이 검색에서 유리한 것은 확실합니다. 사용자의 &lt;b&gt;신뢰도&lt;/b&gt; 측면에서도 주소창에 자물쇠 아이콘이 보이지 않는 사이트는 클릭을 꺼리기 때문에 방문자 유치에도 불리해요.&lt;/p&gt;
&lt;p data-end=&quot;11621&quot; data-start=&quot;11366&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;11912&quot; data-start=&quot;11623&quot; data-ke-size=&quot;size16&quot;&gt;티스토리 자체는 https:// 프로토콜을 지원하므로, &lt;b&gt;개인 도메인을 연결한 경우에도 SSL 설정&lt;/b&gt;을 꼭 하셔야 합니다. (티스토리 &lt;b&gt;관리자 설정 &amp;gt; 블로그&lt;/b&gt;에서 HTTPS 사용 여부를 확인할 수 있습니다. 또는 Cloudflare 같은 서비스를 이용해 개인 도메인에 무료 SSL을 적용할 수도 있습니다.) 사이트 전체가 HTTPS로 제공되지 않고 일부만 HTTP라면 &lt;b&gt;혼합된 콘텐츠 경고&lt;/b&gt;가 뜨면서 사용자에게 불안감을 줄 수도 있으니, 블로그 자산(이미지 등)도 가급적 https 주소를 사용하세요.&lt;/p&gt;
&lt;p data-end=&quot;11912&quot; data-start=&quot;11623&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;12043&quot; data-start=&quot;11914&quot; data-ke-size=&quot;size16&quot;&gt;요약하면, &lt;b&gt;속도/보안 등 기술적인 부분도 SEO의 일부&lt;/b&gt;입니다. 검색엔진은 &lt;b&gt;양질의 콘텐츠&lt;/b&gt;와 함께 &lt;b&gt;빠르고 안전한 사이트&lt;/b&gt;를 사용자에게 제공하고자 하므로, 우리 블로그도 이에 맞게 기술적인 토대를 다져두면 좋겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;12072&quot; data-start=&quot;12045&quot; data-ke-size=&quot;size20&quot;&gt;3-5) 구조화 데이터(JSON-LD) 적용하기&lt;/h4&gt;
&lt;p data-end=&quot;12161&quot; data-start=&quot;12074&quot; data-ke-size=&quot;size16&quot;&gt;앞서 &lt;b&gt;구조화 데이터&lt;/b&gt;에 대해 간단히 설명드렸는데요, 이번에는 &lt;b&gt;왜 구조화 데이터를 써야 하는지&lt;/b&gt;와 &lt;b&gt;어떻게 적용하는지&lt;/b&gt; 조금 더 살펴보겠습니다.&lt;/p&gt;
&lt;p data-end=&quot;12161&quot; data-start=&quot;12074&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;12183&quot; data-start=&quot;12163&quot; data-ke-size=&quot;size18&quot;&gt;구조화 데이터를 사용하는 이유&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-end=&quot;12310&quot; data-start=&quot;12185&quot; data-ke-size=&quot;size16&quot;&gt;일반적인 웹페이지는 &lt;b&gt;사람이 읽기 위한 HTML 콘텐츠&lt;/b&gt;로 작성되지만, &lt;b&gt;구조화 데이터&lt;/b&gt;는 &lt;b&gt;검색엔진이 기계적으로 이해하기 쉽도록&lt;/b&gt; 추가로 제공하는 데이터입니다. 이 데이터를 추가하면 다음과 같은 이점이 있습니다:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;12903&quot; data-start=&quot;12312&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;12449&quot; data-start=&quot;12312&quot;&gt;&lt;b&gt;콘텐츠 명확한 이해&lt;/b&gt;: 예를 들어 블로그 글에 구조화 데이터를 넣으면, 이 글의 제목, 저자, 발행일, 본문 요약 등이 어떤 것인지 명시적으로 표시할 수 있습니다. 검색 엔진은 이를 참고하여 해당 정보를 &lt;b&gt;보다 정확하게 파악&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li data-end=&quot;12756&quot; data-start=&quot;12451&quot;&gt;&lt;b&gt;리치 결과(Rich Results)&lt;/b&gt;: 구조화된 데이터를 활용하면, 구글 검색 결과에 &lt;b&gt;별점, 썸네일 이미지, 방문자 리뷰, 레시피 조리 시간, FAQ 항목&lt;/b&gt; 등 다양한 추가 정보를 노출시킬 수 있습니다&lt;span&gt;&lt;/span&gt;. 이런 풍부한 결과는 사용자 눈길을 끌어 &lt;b&gt;CTR(클릭률)&lt;/b&gt; 상승에 도움이 됩니다. (실제로 앞서 언급했듯이, 리치 결과가 일반 결과보다 &lt;b&gt;클릭률이 82% 높다&lt;/b&gt;는 분석도 있습니다.)&lt;/li&gt;
&lt;li data-end=&quot;12903&quot; data-start=&quot;12758&quot;&gt;&lt;b&gt;음성 검색 및 AI 활용&lt;/b&gt;: 구조화 데이터로 콘텐츠를 잘 정리해 두면, 구글 어시스턴트 같은 음성 검색이나 향후 AI 검색 기능에서도 내 콘텐츠를 &lt;b&gt;적절한 답변으로 활용&lt;/b&gt;할 확률이 높아집니다. 이는 미래를 대비한 포인트이긴 하지만 알아두면 좋겠죠.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;13072&quot; data-start=&quot;12905&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면, 이렇게 좋은 구조화 데이터를 어떻게 추가할까요? 구글에서는 &lt;b&gt;JSON-LD 형식&lt;/b&gt;을 사용할 것을 권장하고 있습니다. JSON-LD는 자바스크립트 객체 표기 형태로 데이터를 표현하기 때문에, 따로 페이지의 화면에 보이지 않고 &amp;lt;script&amp;gt; 태그 안에 정보를 넣어두기만 하면 됩니다.&lt;/p&gt;
&lt;p data-end=&quot;13072&quot; data-start=&quot;12905&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;13105&quot; data-start=&quot;13074&quot; data-ke-size=&quot;size23&quot;&gt;구조화 데이터 간단 예제&amp;nbsp;&lt;/h3&gt;
&lt;pre id=&quot;code_1748161711341&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script type=&quot;application/ld+json&quot;&amp;gt; 
{
  &quot;@context&quot;: &quot;https://schema.org&quot;,
  &quot;@type&quot;: &quot;WebApplication&quot;,
  &quot;applicationCategory&quot;: &quot;EntertainmentApplication&quot;,
  &quot;name&quot;: &quot;Simmey - 우리의 얼굴 매칭 AI를 사용하여 부모님과 얼마나 닮았는지 확인해보세요!&quot;,
  &quot;description&quot;: &quot;우리의 얼굴 매칭 AI를 사용하여 부모님과 얼마나 닮았는지 확인해보세요! 재미있고 흥미로운 가족 닮은꼴 비교를 시작할 수 있는 메인 페이지입니다.&quot;,
  &quot;author&quot;: {
    &quot;@type&quot;: &quot;Person&quot;,
    &quot;name&quot;: &quot;lodado&quot;
  },
  &quot;keywords&quot;: &quot;face matching, ai, fun, family&quot;,
  &quot;url&quot;: &quot;https://mamapapa.vercel.app/&quot;,
  &quot;datePublished&quot;: &quot;2025-05-25T08:11:55.646Z&quot;,
  &quot;isAccessibleForFree&quot;: true,
  &quot;publisher&quot;: {
    &quot;@type&quot;: &quot;Organization&quot;,
    &quot;name&quot;: &quot;lodado&quot;,
    &quot;logo&quot;: {
      &quot;@type&quot;: &quot;ImageObject&quot;,
      &quot;url&quot;: &quot;https://mamapapa.vercel.app/Logo.svg&quot;
    }
  },
  &quot;operatingSystem&quot;: &quot;ALL&quot;,
  &quot;browserRequirements&quot;: &quot;A modern browser with JavaScript enabled&quot;,
  &quot;offers&quot;: {
    &quot;@type&quot;: &quot;Offer&quot;,
    &quot;price&quot;: &quot;0.00&quot;,
    &quot;priceCurrency&quot;: &quot;USD&quot;
  }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위는 제가 실제로 사이드프로젝트에 적용한 JSON-LD&amp;nbsp; 태그입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Tip:&lt;/b&gt; 구조화 데이터를 추가한 후에는 &lt;b&gt;구글 리치 결과 테스트 도구&lt;/b&gt;를 사용해서 올바르게 구현되었는지 검증해 보세요. 오류가 있다면 검색엔진에 반영되지 않을 수 있으니, 반드시 확인하는 습관을 들이는 것이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-6) 메타태그 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Open Graph 태그&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/h4&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;942&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wv9PV/btsObrIPWXA/KJiTxG6F3Ffdbnw9Ry2JKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wv9PV/btsObrIPWXA/KJiTxG6F3Ffdbnw9Ry2JKk/img.png&quot; data-alt=&quot;twitter meta tag&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wv9PV/btsObrIPWXA/KJiTxG6F3Ffdbnw9Ry2JKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWv9PV%2FbtsObrIPWXA%2FKJiTxG6F3Ffdbnw9Ry2JKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;942&quot; height=&quot;351&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;twitter meta tag&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에도 twitter, facebook등 여러 소셜 미디어에서 사용하는 메타 태그 - Open Graph 태그 (og:title, og:description, og:image 등) 를 추가하면 SEO 향상에 도움이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;14529&quot; data-start=&quot;14504&quot; data-ke-size=&quot;size23&quot;&gt;4) 오프페이지 SEO 개념과 실천 방법&lt;/h3&gt;
&lt;p data-end=&quot;14693&quot; data-start=&quot;14531&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;지금까지는 내 블로그 &lt;b&gt;내부에서 할 수 있는 SEO&lt;/b&gt;에 집중했다면, 이제 &lt;b&gt;오프페이지 SEO&lt;/b&gt;에 대해 이야기해보겠습니다. &lt;b&gt;오프페이지 SEO&lt;/b&gt;란 내 사이트 외부의 요소들로 검색 순위에 영향을 주는 것들을 말합니다. 그중 가장 대표적인 것이 &lt;b&gt;백링크(Backlink)&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;h4 data-end=&quot;14710&quot; data-start=&quot;14695&quot; data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;오프페이지 SEO란?&lt;/h4&gt;
&lt;p data-end=&quot;14942&quot; data-start=&quot;14712&quot; data-ke-size=&quot;size16&quot;&gt;간단히 말해, &lt;b&gt;다른 사이트로부터 내 사이트로 연결되는 링크&lt;/b&gt;와 &lt;b&gt;외부에서의 평판&lt;/b&gt;을 관리하는 것입니다. 구글 같은 검색 엔진은 어떤 사이트에 좋은 콘텐츠가 많으면, 다른 사이트들도 그 사이트를 많이 링크한다고 판단합니다. 그래서 품질 좋은 백링크가 많을수록 신뢰도와 권위가 높다고 보고 랭킹을 올려주는 것이죠. 반대로 출처가 의심스러운 스팸 링크가 많으면 오히려 패널티를 받을 수도 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;15008&quot; data-start=&quot;14944&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;15008&quot; data-start=&quot;14944&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;15841&quot; data-start=&quot;15010&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;15195&quot; data-start=&quot;15010&quot;&gt;&lt;b&gt;콘텐츠 공유&lt;/b&gt;: 내가 쓴 유용한 글이 있다면 &lt;b&gt;SNS에 직접 공유&lt;/b&gt;하세요. 트위터, 페이스북, 링크드인, 개발자 커뮤니티 등 관련된 곳에 포스팅해서 사람들의 관심을 끌면 자연스럽게 방문자도 늘고, 누군가 내 글을 인용해갈 가능성도 생깁니다. 처음부터 큰 영향은 아니어도 &lt;b&gt;노출 기회를 넓힌다&lt;/b&gt;는 측면에서 중요합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;15465&quot; data-start=&quot;15197&quot;&gt;&lt;b&gt;커뮤니티 참여 및 링크&lt;/b&gt;: 개발자라면 Stack Overflow나 Hashnode, Reddit, 또는 국내 개발자 커뮤니티(예: OKky, Dev.to, Velog 등)에 활동하면서 관련 질문에 답변을 달거나 글을 쓰며 &lt;b&gt;자연스럽게 내 블로그 글 링크&lt;/b&gt;를 남길 수도 있습니다. 단, &lt;b&gt;무턱대고 홍보 링크만 남기는 것은 스팸&lt;/b&gt;으로 보일 수 있으니 주의하세요. 정말 해당 질문에 도움이 되는 상세한 답변을 제공하면서 참고 링크로 내 글을 언급하는 식이 바람직합니다.&lt;/li&gt;
&lt;li data-end=&quot;15675&quot; data-start=&quot;15467&quot;&gt;&lt;b&gt;게스트 포스팅 &amp;amp; 협업&lt;/b&gt;: 기회가 된다면 다른 블로그에 &lt;b&gt;게스트 포스트&lt;/b&gt;를 기고하고 내 블로그를 소개하거나, 지인들의 블로그와 &lt;b&gt;교차로 링크 교환&lt;/b&gt;을 할 수도 있습니다. 예를 들어 다른 분의 블로그에 내가 쓴 글을 올리면서 &quot;원문: 내 블로그 링크&quot;를 남기는 방식입니다. 이는 어느 정도 컨텐츠 신뢰를 쌓은 후에 가능하겠지만, 하나의 방법이 될 수 있어요.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;15841&quot; data-start=&quot;15677&quot;&gt;&lt;b&gt;디렉토리 및 프로필 활용&lt;/b&gt;: 기술 블로그들의 모음 디렉토리에 내 블로그를 등록하거나(국내에 SEO 디렉토리는 흔치 않지만, 해외엔 alltop 같은 사이트들이 있음), 개발 관련 프로필(GitHub, LinkedIn)에 블로그 주소를 넣어두는 것도 링크 노출을 늘리는 소소한 팁입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;16030&quot; data-start=&quot;15843&quot; data-ke-size=&quot;size16&quot;&gt;무엇보다 중요한 것은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;고퀄리티 콘텐츠 생산&lt;/b&gt;&lt;/span&gt;입니다. 콘텐츠가 좋아야 사람들이 자발적으로 공유하고 링크해 주기 때문에, 이것이 가장 이상적인 오프페이지 SEO라 할 수 있습니다. 처음부터 백링크 숫자에 집착하기보다는 &lt;b&gt;블로그에 유용한 글을 꾸준히 쌓고, 커뮤니티에서 신뢰를 얻는 것&lt;/b&gt;이 장기적으로 SEO에 큰 도움이 될 거예요.&lt;/p&gt;
&lt;p data-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;br /&gt;가장 어려운 부분일꺼 같은데 운칠기삼이라고 봅니다. &lt;br /&gt;제 사이드 프로젝트도 이유는 모르겠지만 러시아 검색엔진쪽에서 많이 유입되는거 같네요..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;19509&quot; data-start=&quot;19485&quot; data-ke-size=&quot;size26&quot;&gt;배포 전 SEO 체크리스트&lt;/h2&gt;
&lt;p data-end=&quot;19597&quot; data-start=&quot;19511&quot; data-ke-size=&quot;size16&quot;&gt;마지막으로, 이제 홈페이지를 발행하기 전에 &lt;b&gt;중요 요소들을 하나씩 체크&lt;/b&gt;해 봅시다. 아래 &lt;b&gt;SEO 체크리스트&lt;/b&gt;를 통해 빠뜨린 부분은 없는지 확인해보세요:&lt;/p&gt;
&lt;p data-end=&quot;19597&quot; data-start=&quot;19511&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;21240&quot; data-start=&quot;19599&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;19712&quot; data-start=&quot;19599&quot;&gt;&lt;b&gt;제목 태그와 메타 설명 작성&lt;/b&gt;: 글의 주제를 명확히 담은 제목(title)을 정했고, 매력적인 메타 설명(description)을 추가하셨나요? (검색 결과에 표시될 문구입니다.)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;19900&quot; data-start=&quot;19714&quot;&gt;&lt;b&gt;URL 주소 확인&lt;/b&gt;: 티스토리에서 자동 생성된 제 글 URL(슬러그)이 의미있게 잘 설정되어 있나요? (가능하다면 영문으로 간단히 키워드를 포함하는 게 좋지만, 티스토리는 자동으로 생성됩니다. 예: &lt;a href=&quot;https://myblog.tistory.com/15&quot;&gt;https://myblog.tistory.com/15&lt;/a&gt;보다는 .../seo-guide 처럼 식별 가능하면 좋습니다.)&lt;/li&gt;
&lt;li data-end=&quot;20008&quot; data-start=&quot;19902&quot;&gt;&lt;b&gt;헤딩 구조 점검&lt;/b&gt;: 본문에 &lt;b&gt;h1은 하나만&lt;/b&gt; 있고, h2/h3 등의 소제목이 논리적으로 계층을 잘 이루고 있나요? 혹시 글씨 크기를 키우려고 헤딩을 남용하지 않았는지 확인하세요.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;20138&quot; data-start=&quot;20010&quot;&gt;&lt;b&gt;키워드 최적화&lt;/b&gt;: 글 내용 중에 주요 &lt;b&gt;키워드가 자연스럽게 포함&lt;/b&gt;되어 있나요? 제목, 첫 문단, 헤딩 등에 핵심 단어가 들어가면 좋습니다. 다만 &lt;b&gt;키워드 과다 남용은 금물&lt;/b&gt;입니다. 독자를 위한 글쓰기가 우선이에요.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;20255&quot; data-start=&quot;20140&quot;&gt;&lt;b&gt;내부 링크 추가&lt;/b&gt;: 관련있는 다른 포스팅이 있다면 서로 &lt;b&gt;링크를 연결&lt;/b&gt;해 두었나요? 새로운 글에서는 이전 관련 글을, 그리고 나중에라도 이전 글에 이 새로운 글의 링크를 추가하면 더욱 좋습니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;20373&quot; data-start=&quot;20257&quot;&gt;&lt;b&gt;이미지 대체 텍스트(Alt)&lt;/b&gt;: 글에 이미지나 그림을 넣었다면 &amp;lt;img alt=&quot;...&quot;&amp;gt; 속성에 이미지 설명을 넣었는지 확인합니다. 이는 시각장애인용 보조기기에도 필요하고 SEO에도 유용합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;20505&quot; data-start=&quot;20375&quot;&gt;&lt;b&gt;모바일 환경 확인&lt;/b&gt;: 모바일에서 내 블로그가 &lt;b&gt;읽기 편한지&lt;/b&gt; 확인해 보셨나요? 화면 크기에 따라 레이아웃이 깨지거나 글씨가 너무 작지 않은지 점검하세요. 모바일 친화적(모바일 프렌들리) 사이트는 검색 순위에도 유리합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;20664&quot; data-start=&quot;20507&quot;&gt;&lt;b&gt;페이지 속도 확인&lt;/b&gt;: PageSpeed Insights 등으로 페이지 점수가 너무 낮게 나오지는 않았나요? &lt;b&gt;이미지 최적화&lt;/b&gt;나 &lt;b&gt;필요없는 스크립트 지우기&lt;/b&gt; 등을 통해 속도를 개선해 보세요. LCP/CLS 지표가 나쁘게 나오면 해당 요소를 수정하는 것도 잊지 마세요.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;20813&quot; data-start=&quot;20666&quot;&gt;&lt;b&gt;HTTPS 적용 여부&lt;/b&gt;: 블로그 주소가 http://가 아닌 &lt;b&gt;https://로 접속되고 있는지&lt;/b&gt; 확인합니다. 티스토리 기본 도메인은 HTTPS이지만, 개인 도메인은 SSL 설정을 해야 합니다. 브라우저 주소창에 자물쇠가 뜨는지 꼭 확인하세요.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;20942&quot; data-start=&quot;20815&quot;&gt;&lt;b&gt;구조화 데이터 추가&lt;/b&gt;: 가능하다면 JSON-LD 형태의 &lt;b&gt;구조화 데이터 스크립트&lt;/b&gt;를 페이지에 넣었는지 확인합니다. (티스토리에서는 스킨 편집이나 개별 글 HTML 모드에서 추가 가능) 나중에라도 한 번 도전해보세요.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;21069&quot; data-start=&quot;20944&quot;&gt;&lt;b&gt;Search Console 색인 요청&lt;/b&gt;: 글을 발행했다면 Google Search Console에 가서 새 URL을 &lt;b&gt;색인 요청&lt;/b&gt; 해보세요. 이렇게 하면 크롤러가 비교적 빨리 방문해서 색인해갈 확率이 높아집니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li data-end=&quot;21240&quot; data-start=&quot;21071&quot;&gt;&lt;b&gt;SNS 공유 준비&lt;/b&gt;: 마지막으로, &lt;b&gt;소셜 미디어에 공유&lt;/b&gt;할 준비가 되었나요? Open Graph 태그 (og:title, og:description, og:image 등)도 자동 설정되도록 스킨을 구성하면 좋습니다. 공유했을 때 미리보기 카드가 깔끔히 나오면 클릭률 상승에 도움이 되니까요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내용이 다소 많았지만, 요약하자면 검색엔진이 내 블로그를 잘 찾아가도록 돕고, 방문자에게 좋은 경험을 주는 것이 SEO의 핵심입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 제가 테스트한 사이드 프로젝트 공유하고 글 마쳐봅니다..!&lt;/p&gt;
&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://mamapapa.vercel.app/ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mamapapa.vercel.app/ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748162382550&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Simmey - 우리의 얼굴 매칭 AI를 사용하여 부모님과 얼마나 닮았는지 확인해보세요!&quot; data-og-description=&quot;우리의 얼굴 매칭 AI를 사용하여 부모님과 얼마나 닮았는지 확인해보세요! 재미있고 흥미로운 가족 닮은꼴 비교를 시작할 수 있는 메인 페이지입니다.&quot; data-og-host=&quot;mamapapa.vercel.app&quot; data-og-source-url=&quot;https://mamapapa.vercel.app/ko&quot; data-og-url=&quot;https://mamapapa.vercel.app&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://mamapapa.vercel.app/ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mamapapa.vercel.app/ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Simmey - 우리의 얼굴 매칭 AI를 사용하여 부모님과 얼마나 닮았는지 확인해보세요!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;우리의 얼굴 매칭 AI를 사용하여 부모님과 얼마나 닮았는지 확인해보세요! 재미있고 흥미로운 가족 닮은꼴 비교를 시작할 수 있는 메인 페이지입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mamapapa.vercel.app&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지 자체는 닮은 얼굴 매칭 - 테스트 결과를 보여주는 단순한 웹앱인데요. 사실 광고 및 마케팅을 안해서 SEO를 적용시키더라도 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;방문자가 별로 없을줄 알았는데, YAndex라고 러시아 검색 엔진에서 자동으로 크롤링해가고 많은 유저(?)들이 들어와서 놀랬네요&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reference&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;https://wormwlrm.github.io/2023/05/07/SEO-for-Technical-Blog.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wormwlrm.github.io/2023/05/07/SEO-for-Technical-Blog.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748162310079&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;기술 블로그를 위한 SEO - 재그지그의 개발 블로그&quot; data-og-description=&quot;개인 기술 블로그에 적용한 SEO 방법들을 소개하고, 그 결과물을 공유합니다.&quot; data-og-host=&quot;wormwlrm.github.io&quot; data-og-source-url=&quot;https://wormwlrm.github.io/2023/05/07/SEO-for-Technical-Blog.html&quot; data-og-url=&quot;https://wormwlrm.github.io/2023/05/07/SEO-for-Technical-Blog.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lJn4E/hyYW5V2f4S/TdfjMmvJg3rKtWE5kSTMK0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/EAp7S/hyYYG2F3O4/uaBUvwQNAsLWRpASHjYj2K/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ieojH/hyYYHHhTcz/6HCmbrt0PiDVU1uJO9UAP0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://wormwlrm.github.io/2023/05/07/SEO-for-Technical-Blog.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://wormwlrm.github.io/2023/05/07/SEO-for-Technical-Blog.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lJn4E/hyYW5V2f4S/TdfjMmvJg3rKtWE5kSTMK0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/EAp7S/hyYYG2F3O4/uaBUvwQNAsLWRpASHjYj2K/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ieojH/hyYYHHhTcz/6HCmbrt0PiDVU1uJO9UAP0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;기술 블로그를 위한 SEO - 재그지그의 개발 블로그&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개인 기술 블로그에 적용한 SEO 방법들을 소개하고, 그 결과물을 공유합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;wormwlrm.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://searchadvisor.naver.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://searchadvisor.naver.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748162323375&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;네이버 서치어드바이저&quot; data-og-description=&quot;네이버 서치어드바이저와 함께 당신의 웹사이트를 성장시켜보세요&quot; data-og-host=&quot;searchadvisor.naver.com&quot; data-og-source-url=&quot;https://searchadvisor.naver.com/&quot; data-og-url=&quot;https://searchadvisor.naver.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XZLIO/hyYYAaiU6g/hwgHJK8RDuImVz7ZwBig7k/img.png?width=500&amp;amp;height=408&amp;amp;face=0_0_500_408&quot;&gt;&lt;a href=&quot;https://searchadvisor.naver.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://searchadvisor.naver.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XZLIO/hyYYAaiU6g/hwgHJK8RDuImVz7ZwBig7k/img.png?width=500&amp;amp;height=408&amp;amp;face=0_0_500_408');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;네이버 서치어드바이저&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;네이버 서치어드바이저와 함께 당신의 웹사이트를 성장시켜보세요&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;searchadvisor.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;및 구글 서치어드바이저 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;</description>
      <category>Front-end/브라우저</category>
      <author>lodado</author>
      <guid isPermaLink="true">https://lodado.tistory.com/104</guid>
      <comments>https://lodado.tistory.com/104#entry104comment</comments>
      <pubDate>Sun, 25 May 2025 16:59:38 +0900</pubDate>
    </item>
  </channel>
</rss>