<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>끄적이는 개발노트</title>
    <link>https://hbc3869.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 8 Aug 2026 12:49:35 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>크런키스틱</managingEditor>
    <image>
      <title>끄적이는 개발노트</title>
      <url>https://tistory1.daumcdn.net/tistory/4954548/attach/f2ece634eefe4310b7ad8444360467c0</url>
      <link>https://hbc3869.tistory.com</link>
    </image>
    <item>
      <title>260730_강의 정리 (Dart와 Flutter 2)</title>
      <link>https://hbc3869.tistory.com/242</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: #f8f9fa;
    color: #1a1a1a;
    line-height: 1.7;
    padding: 0;
  }
  .blog-wrap { max-width: 720px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

  .hero { border-left: 4px solid #1D9E75; padding: 0.6rem 0 0.6rem 1.25rem; margin-bottom: 2.5rem; }
  .hero-label { font-size: 11px; font-weight: 700; color: #0F6E56; letter-spacing: 0.09em; text-transform: uppercase; margin-bottom: 6px; }
  .hero-title { font-size: 26px; font-weight: 700; color: #111; line-height: 1.3; margin-bottom: 8px; }
  .hero-sub   { font-size: 14px; color: #555; line-height: 1.7; }

  .section { margin-bottom: 2.2rem; }
  .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 1rem; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8; }
  .section-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
  .section-title { font-size: 17px; font-weight: 700; color: #111; }

  .icon-green  { background: #E1F5EE; }
  .icon-amber  { background: #FAEEDA; }
  .icon-purple { background: #EEEDFE; }
  .icon-blue   { background: #E6F1FB; }
  .icon-coral  { background: #FAECE7; }
  .icon-teal   { background: #E0F4F4; }
  .icon-gray   { background: #F0F0F0; }

  .dot-list { list-style: none; padding: 0; margin: 0; }
  .dot-list li { font-size: 13.5px; color: #444; padding: 3px 0 3px 14px; position: relative; line-height: 1.65; }
  .dot-list li::before { content: &quot;·&quot;; position: absolute; left: 0; color: #1D9E75; font-weight: 700; }
  .dot-list.sm li { font-size: 12.5px; color: #555; }
  .dot-list.sm li::before { color: #aaa; }

  .note        { border-left: 3px solid #1D9E75; background: #E1F5EE; border-radius: 0 8px 8px 0; padding: 11px 15px; margin-top: 12px; font-size: 13px; color: #0F6E56; line-height: 1.65; }
  .note.amber  { border-color: #BA7517;  background: #FAEEDA; color: #7a4d0d; }
  .note.purple { border-color: #7F77DD;  background: #EEEDFE; color: #3C3489; }
  .note.blue   { border-color: #185FA5;  background: #E6F1FB; color: #0d3d6e; }
  .note.coral  { border-color: #C1552E;  background: #FAECE7; color: #993C1D; }

  .concept-block  { margin-top: 16px; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; }
  .concept-header { background: #f4f4f4; padding: 8px 14px; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.06em; border-bottom: 1px solid #e0e0e0; }
  .concept-item   { padding: 13px 16px; border-bottom: 1px solid #f0f0f0; }
  .concept-item:last-child { border-bottom: none; }
  .concept-term   { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .concept-term span { font-size: 11px; font-weight: 500; color: #888; margin-left: 5px; }
  .concept-ex     { margin-top: 6px; font-size: 11.5px; color: #999; font-style: italic; padding-left: 14px; position: relative; }
  .concept-ex::before { content: &quot;→&quot;; position: absolute; left: 0; }

  .module-block  { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; margin-bottom: 12px; overflow: hidden; }
  .module-header { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid #f0f0f0; background: #fafafa; }
  .module-tag    { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; padding: 3px 10px; border-radius: 5px; }
  .module-name   { font-size: 13px; font-weight: 700; color: #111; }
  .module-body   { padding: 13px 16px; }
  .module-quote  { font-size: 12.5px; color: #888; font-style: italic; margin-bottom: 10px; padding: 6px 10px; background: #f8f9fa; border-radius: 6px; border-left: 2px solid #ddd; }

  .tag-green  { background: #E1F5EE; color: #0F6E56; }
  .tag-amber  { background: #FAEEDA; color: #BA7517; }
  .tag-purple { background: #EEEDFE; color: #534AB7; }
  .tag-blue   { background: #E6F1FB; color: #185FA5; }
  .tag-coral  { background: #FAECE7; color: #993C1D; }
  .tag-teal   { background: #E0F4F4; color: #0D7A7A; }
  .tag-gray   { background: #F0F0F0; color: #444; }

  .flow-row   { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .flow-box   { background: #f4f4f4; border: 1px solid #ddd; border-radius: 8px; padding: 7px 13px; font-size: 12.5px; color: #333; font-weight: 600; }
  .flow-box.hl { background: #E1F5EE; border-color: #1D9E75; color: #0F6E56; }
  .flow-arrow { font-size: 15px; color: #aaa; }

  .flow-step-list { display: flex; flex-direction: column; gap: 0; }
  .flow-step-item { display: flex; gap: 14px; align-items: flex-start; }
  .step-line      { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
  .step-dot       { width: 28px; height: 28px; border-radius: 50%; background: #E1F5EE; border: 2px solid #1D9E75; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #0F6E56; }
  .step-connector { width: 2px; height: 20px; background: #e0e0e0; margin: 3px 0; }
  .step-body      { padding-top: 4px; padding-bottom: 16px; }
  .step-title     { font-size: 13.5px; font-weight: 700; color: #111; margin-bottom: 3px; }
  .step-desc      { font-size: 12.5px; color: #666; line-height: 1.6; }

  .feature-list { display: flex; flex-direction: column; gap: 7px; margin-top: 4px; }
  .feature-item { background: #fff; border: 1px solid #e8e8e8; border-radius: 8px; padding: 10px 14px; display: flex; gap: 10px; align-items: flex-start; }
  .feature-tag  { font-family: 'Courier New', monospace; font-size: 11.5px; font-weight: 700; color: #0F6E56; background: #E1F5EE; border-radius: 4px; padding: 2px 8px; flex-shrink: 0; white-space: nowrap; }
  .feature-desc { font-size: 12.5px; color: #444; line-height: 1.6; }
  .feature-desc strong { color: #111; }

  .data-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 4px; }
  .data-table th { background: #f4f4f4; padding: 8px 12px; text-align: left; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.04em; border-bottom: 1px solid #e0e0e0; }
  .data-table td { padding: 10px 12px; border-bottom: 1px solid #f0f0f0; font-size: 12.5px; color: #444; vertical-align: top; }
  .data-table tr:last-child td { border-bottom: none; }
  .data-table tr:hover td { background: #fafafa; }

  .card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(155px, 1fr)); gap: 10px; }
  .card       { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; padding: 14px 16px; }
  .card-title { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .card-body  { font-size: 12.5px; color: #555; line-height: 1.7; }

  .pill-row    { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
  .pill        { font-size: 12px; padding: 4px 11px; border-radius: 20px; font-weight: 600; }
  .pill-green  { background: #E1F5EE; color: #0F6E56; }
  .pill-amber  { background: #FAEEDA; color: #BA7517; }
  .pill-purple { background: #EEEDFE; color: #534AB7; }
  .pill-coral  { background: #FAECE7; color: #993C1D; }
  .pill-blue   { background: #E6F1FB; color: #185FA5; }
  .pill-teal   { background: #E0F4F4; color: #0D7A7A; }

  .algo-pill { display: inline-block; font-family: 'Courier New', monospace; font-size: 11.5px; font-weight: 700; padding: 2px 8px; border-radius: 4px; background: #EEEDFE; color: #534AB7; }

  .chip { display: inline-block; background: #f0f0f0; border: 1px solid #ddd; border-radius: 4px; padding: 1px 7px; font-size: 11.5px; font-family: 'Courier New', monospace; color: #555; }

  .divider   { height: 1px; background: #ececec; margin: 2rem 0; }
  .sub-label { font-size: 13px; font-weight: 700; margin-bottom: 8px; color: #333; }
  .sub-green { color: #0F6E56; }
  .sub-coral { color: #993C1D; }

  @media (max-width: 520px) {
    .hero-title  { font-size: 21px; }
    .card-grid   { grid-template-columns: 1fr; }
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;blog-wrap&quot;&gt;

  &lt;div class=&quot;hero&quot;&gt;
    &lt;div class=&quot;hero-label&quot;&gt;mobile · flutter&lt;/div&gt;
    &lt;div class=&quot;hero-title&quot;&gt;Flutter와 Dart 정리 — Widget, State, Lifecycle&lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:6px;&quot;&gt;
      &lt;li&gt;Dart 기반 크로스플랫폼 GUI 프레임워크, Widget 트리로 UI 구성&lt;/li&gt;
      &lt;li&gt;StatelessWidget vs StatefulWidget, setState()로 리빌드 제어&lt;/li&gt;
      &lt;li&gt;Widget Lifecycle과 BuildContext로 화면 생명주기 관리&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;1. Dart 언어와 Flutter 개요&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;Dart 기반으로 동작하는 GUI 프레임워크 — 하나의 코드로 여러 플랫폼 대응&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;GUI programming — 그래픽 기반 사용자 인터페이스 구성&lt;/li&gt;
      &lt;li&gt;Event based programming — 사용자 입력(터치, 클릭)에 반응하는 방식&lt;/li&gt;
      &lt;li&gt;Component(Widget) based programming — 모든 UI 요소를 위젯 단위로 조립&lt;/li&gt;
      &lt;li&gt;Object-oriented programming — 클래스와 객체 기반 설계&lt;/li&gt;
      &lt;li&gt;Cross platform — 하나의 코드베이스로 iOS/Android/Web 대응&lt;/li&gt;
      &lt;li&gt;AOT/JIT 컴파일 지원 — 개발 중엔 JIT(Hot Reload), 배포 시엔 AOT(고속 실행)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;JIT / AOT 컴파일 &lt;span&gt;Just-In-Time / Ahead-Of-Time&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;JIT — 개발 중 실시간 컴파일, Hot Reload 가능&lt;/li&gt;
          &lt;li&gt;AOT — 배포 전 네이티브 코드로 미리 컴파일, 실행 속도 빠름&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;개발할 땐 JIT로 빠르게 수정 확인, 앱스토어 배포 시엔 AOT로 빌드&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;변수 선언 키워드 &lt;span&gt;dynamic / var / final / const&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;dynamic — 타입 자유, 런타임에 타입 결정&lt;/li&gt;
          &lt;li&gt;var — 선언 시 타입 추론, 이후 타입 고정&lt;/li&gt;
          &lt;li&gt;final — 런타임에 한 번 값 할당 후 불변&lt;/li&gt;
          &lt;li&gt;const — 컴파일 타임에 값이 정해지는 완전한 상수&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;final은 실행 중 계산된 값 저장 가능, const는 실행 전부터 값이 고정돼야 함&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note&quot;&gt;Dart는 컴파일 방식을 상황에 따라 전환하며, 개발 속도(JIT)와 실행 속도(AOT)를 동시에 확보하는 전략을 씀&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;2. Widget 기본 개념&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;Flutter의 모든 화면 요소는 Widget이다 — 데이터 표현, 레이아웃, 스타일, 위치 정렬까지 전부 위젯으로 처리&lt;/p&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;span class=&quot;module-tag tag-green&quot;&gt;display&lt;/span&gt;
        &lt;span class=&quot;module-name&quot;&gt;데이터 표현 위젯&lt;/span&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;화면에 보여줄 실제 콘텐츠를 담당&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Text, Image, Icon, Card, ListView, DataTable, Checkbox, Radio&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;span class=&quot;module-tag tag-purple&quot;&gt;layout&lt;/span&gt;
        &lt;span class=&quot;module-name&quot;&gt;레이아웃 위젯&lt;/span&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;다른 위젯들을 배치하는 뼈대 역할&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Row, Column, Scaffold, Stack&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;span class=&quot;module-tag tag-blue&quot;&gt;style&lt;/span&gt;
        &lt;span class=&quot;module-name&quot;&gt;스타일 위젯&lt;/span&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;텍스트나 색상 등 시각적 속성 지정&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;TextStyle, Color&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;span class=&quot;module-tag tag-amber&quot;&gt;align&lt;/span&gt;
        &lt;span class=&quot;module-name&quot;&gt;정렬 위젯&lt;/span&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;자식 위젯의 위치와 여백을 조정&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Center, Padding&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note purple&quot;&gt;위젯은 &quot;화면에 보이는 모든 것&quot;이라고 이해하면 됨 — 텍스트 한 줄도, 버튼도, 화면 전체 레이아웃도 위젯&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-amber&quot;&gt;⚖️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;3. StatelessWidget vs StatefulWidget&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;상태(데이터)가 바뀌는가?&quot; — 두 위젯을 가르는 기준&lt;/p&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;tr&gt;&lt;th&gt;구분&lt;/th&gt;&lt;th&gt;StatelessWidget&lt;/th&gt;&lt;th&gt;StatefulWidget&lt;/th&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;상태 변경&lt;/td&gt;&lt;td&gt;불가능 (한 번 그려지면 고정)&lt;/td&gt;&lt;td&gt;가능 (setState()로 재빌드)&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;build()만 존재&lt;/td&gt;&lt;td&gt;State 객체 별도 존재&lt;/td&gt;&lt;/tr&gt;
    &lt;/table&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;setState()&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;상태 값을 변경하고 Flutter에게 &quot;다시 그려야 한다&quot;고 알리는 함수&lt;/li&gt;
          &lt;li&gt;호출 시 dirty flag가 true로 바뀌며 build() 재실행 트리거&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;카운터 앱에서 버튼 클릭 시 setState(() =&gt; count++)로 화면 숫자 갱신&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note amber&quot;&gt;StatefulWidget 다이어그램에서 STATE가 Widget model을 감싸는 구조로 표현되는 이유는, 위젯 자체는 불변이고 State 객체가 별도로 값을 들고 있다가 재빌드를 트리거하기 때문&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-blue&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;4. Widget Tree와 BuildContext&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;위젯들은 부모-자식 관계의 트리 구조로 조립되며, 각 위젯은 자신의 트리 위치 정보(BuildContext)를 가짐&lt;/p&gt;

    &lt;div class=&quot;flow-step-list&quot;&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;1&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;Scaffold&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;화면 전체 뼈대, 하위에 여러 named parameter를 가짐&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;2&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;appBar 파라미터 → AppBar 위젯&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;화면 상단 바 영역 지정&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;3&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;body 파라미터 → Center → Column → Text&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;중첩 레이아웃 — Center 안에 Column, 그 안에 Text&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;4&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;floatingActionButton 파라미터 → FloatingActionButton → Icon&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;화면 우하단 플로팅 버튼과 그 안의 아이콘&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note blue&quot;&gt;AppBar, Center, FloatingActionButton은 서로 형제 위젯이 아니라, Scaffold의 서로 다른 이름 붙은 파라미터(appBar:, body:, floatingActionButton:)에 각각 들어가는 구조임 — 나란히 그려져 있어도 병렬 관계가 아님&lt;/div&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;BuildContext&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;위젯이 트리 안 어디에 위치하는지를 나타내는 참조 객체&lt;/li&gt;
          &lt;li&gt;부모 위젯 정보 탐색, 테마·미디어쿼리 접근 등에 사용&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;Navigator.of(context).push(...)처럼 항상 context를 통해 트리 정보에 접근&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-coral&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;5. Widget Lifecycle&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;StatefulWidget은 생성부터 소멸까지 정해진 순서의 생명주기를 거침&lt;/p&gt;

    &lt;div class=&quot;flow-step-list&quot;&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;&lt;div class=&quot;step-dot&quot;&gt;1&lt;/div&gt;&lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;createState()&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;StatefulWidget으로부터 State 객체 생성&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;&lt;div class=&quot;step-dot&quot;&gt;2&lt;/div&gt;&lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;initState()&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;State 객체 초기화, 최초 1회만 실행&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;&lt;div class=&quot;step-dot&quot;&gt;3&lt;/div&gt;&lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;didChangeDependencies()&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;의존 데이터 변경 시 호출&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;&lt;div class=&quot;step-dot&quot;&gt;4&lt;/div&gt;&lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;build()&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;실제 UI 렌더링, dirty=true일 때마다 재실행&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;&lt;div class=&quot;step-dot&quot;&gt;5&lt;/div&gt;&lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;setState() / didUpdateWidget()&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;상태 변경 시 dirty=true로 전환 → build() 재호출&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;&lt;div class=&quot;step-dot&quot;&gt;6&lt;/div&gt;&lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;deactivate()&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;트리에서 일시적으로 제거될 때&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;&lt;div class=&quot;step-dot&quot;&gt;7&lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;dispose()&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;완전히 제거, 리소스 정리 (mounted=false)&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note coral&quot;&gt;dirty flag가 true가 되는 경로는 두 가지 — setState() 직접 호출, 또는 부모 위젯이 재빌드되며 didUpdateWidget()이 호출되는 경우&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-teal&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;6. Navigator와 화면 전환&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;화면 이동은 Stack(스택) 구조로 관리됨&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;Navigator — 화면(Route)들을 스택 형태로 관리하는 객체&lt;/li&gt;
      &lt;li&gt;push — 새 화면을 스택 위에 쌓음&lt;/li&gt;
      &lt;li&gt;pop — 현재 화면을 스택에서 제거하고 이전 화면으로 복귀&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Hot Reload vs Hot Restart&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Hot Reload — 코드 변경분만 반영, 상태(State) 유지, 수 초 내 반영&lt;/li&gt;
          &lt;li&gt;Hot Restart — 앱 전체 재시작, 상태 초기화&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;UI 스타일만 바꿀 땐 Hot Reload, 초기화 로직 바꿀 땐 Hot Restart&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;note&quot;&gt;
    &lt;strong&gt;정리&lt;/strong&gt;&lt;br&gt;
    · Flutter는 &quot;모든 것이 Widget&quot;이라는 원칙 위에 설계됨&lt;br&gt;
    · StatelessWidget/StatefulWidget 구분, Widget Tree 구조, Lifecycle 흐름이 서로 맞물려 동작
  &lt;/div&gt;

&lt;/div&gt;</description>
      <category>Flutter</category>
      <author>크런키스틱</author>
      <guid isPermaLink="true">https://hbc3869.tistory.com/242</guid>
      <comments>https://hbc3869.tistory.com/242#entry242comment</comments>
      <pubDate>Thu, 30 Jul 2026 09:26:16 +0900</pubDate>
    </item>
    <item>
      <title>260729_강의 정리 (Dart와 Flutter)</title>
      <link>https://hbc3869.tistory.com/241</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: #f8f9fa;
    color: #1a1a1a;
    line-height: 1.7;
    padding: 0;
  }
  .blog-wrap { max-width: 720px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

  .hero { border-left: 4px solid #1D9E75; padding: 0.6rem 0 0.6rem 1.25rem; margin-bottom: 2.5rem; }
  .hero-label { font-size: 11px; font-weight: 700; color: #0F6E56; letter-spacing: 0.09em; text-transform: uppercase; margin-bottom: 6px; }
  .hero-title { font-size: 26px; font-weight: 700; color: #111; line-height: 1.3; margin-bottom: 8px; }
  .hero-sub   { font-size: 14px; color: #555; line-height: 1.7; }

  .section { margin-bottom: 2.2rem; }
  .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 1rem; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8; }
  .section-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
  .section-title { font-size: 17px; font-weight: 700; color: #111; }

  .icon-green  { background: #E1F5EE; }
  .icon-amber  { background: #FAEEDA; }
  .icon-purple { background: #EEEDFE; }
  .icon-blue   { background: #E6F1FB; }
  .icon-coral  { background: #FAECE7; }
  .icon-teal   { background: #E0F4F4; }
  .icon-gray   { background: #F0F0F0; }

  .dot-list { list-style: none; padding: 0; margin: 0; }
  .dot-list li { font-size: 13.5px; color: #444; padding: 3px 0 3px 14px; position: relative; line-height: 1.65; }
  .dot-list li::before { content: &quot;·&quot;; position: absolute; left: 0; color: #1D9E75; font-weight: 700; }
  .dot-list.sm li { font-size: 12.5px; color: #555; }
  .dot-list.sm li::before { color: #aaa; }

  .note        { border-left: 3px solid #1D9E75; background: #E1F5EE; border-radius: 0 8px 8px 0; padding: 11px 15px; margin-top: 12px; font-size: 13px; color: #0F6E56; line-height: 1.65; }
  .note.amber  { border-color: #BA7517;  background: #FAEEDA; color: #7a4d0d; }
  .note.purple { border-color: #7F77DD;  background: #EEEDFE; color: #3C3489; }
  .note.blue   { border-color: #185FA5;  background: #E6F1FB; color: #0d3d6e; }

  .concept-block  { margin-top: 16px; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; }
  .concept-header { background: #f4f4f4; padding: 8px 14px; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.06em; border-bottom: 1px solid #e0e0e0; }
  .concept-item   { padding: 13px 16px; border-bottom: 1px solid #f0f0f0; }
  .concept-item:last-child { border-bottom: none; }
  .concept-term   { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .concept-term span { font-size: 11px; font-weight: 500; color: #888; margin-left: 5px; }
  .concept-ex     { margin-top: 6px; font-size: 11.5px; color: #999; font-style: italic; padding-left: 14px; position: relative; }
  .concept-ex::before { content: &quot;→&quot;; position: absolute; left: 0; }

  .flow-row   { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .flow-box   { background: #f4f4f4; border: 1px solid #ddd; border-radius: 8px; padding: 7px 13px; font-size: 12.5px; color: #333; font-weight: 600; }
  .flow-box.hl { background: #E1F5EE; border-color: #1D9E75; color: #0F6E56; }
  .flow-arrow { font-size: 15px; color: #aaa; }

  .chip { display: inline-block; background: #f0f0f0; border: 1px solid #ddd; border-radius: 4px; padding: 1px 7px; font-size: 11.5px; font-family: 'Courier New', monospace; color: #555; }

  .divider   { height: 1px; background: #ececec; margin: 2rem 0; }

  @media (max-width: 520px) {
    .hero-title  { font-size: 21px; }
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;blog-wrap&quot;&gt;

  &lt;div class=&quot;hero&quot;&gt;
    &lt;div class=&quot;hero-label&quot;&gt;flutter · dart&lt;/div&gt;
    &lt;div class=&quot;hero-title&quot;&gt;Dart 언어와 Flutter, Fuchsia 정리&lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:6px;&quot;&gt;
      &lt;li&gt;Dart 언어의 핵심 특징과 문법 요소&lt;/li&gt;
      &lt;li&gt;Dart와 Flutter의 관계&lt;/li&gt;
      &lt;li&gt;구글의 실험적 프로젝트, Fuchsia 개요&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;!-- 1. Dart는 어떤 언어인가 --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;1. Dart는 어떤 언어인가&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;Flutter를 구동하는 구글의 크로스 플랫폼 언어&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;크로스 플랫폼 지원 — Web, Mobile, Desktop, Server 모두 대응&lt;/li&gt;
      &lt;li&gt;객체 지향 프로그래밍 기반 — Java·C#처럼 모든 것이 객체&lt;/li&gt;
      &lt;li&gt;C처럼 &lt;span class=&quot;chip&quot;&gt;main()&lt;/span&gt; 함수로 실행 시작&lt;/li&gt;
      &lt;li&gt;클래스 기반 + 함수 기반 프로그래밍 모두 가능 (함수도 일급객체)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;일급객체 &lt;span&gt;First-class function&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;함수를 변수에 담거나 다른 함수의 인자로 전달할 수 있는 성질&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;var add = (int a, int b) =&gt; a + b;&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note&quot;&gt;Dart는 정적 언어의 안정성과 동적 언어의 유연성을 함께 노리는 하이브리드 언어임&lt;/div&gt;
  &lt;/div&gt;

  &lt;!-- 2. 타입 시스템 --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-blue&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;2. 타입 시스템 — var, final, dynamic&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;정적 타입과 동적 타입을 함께 지원하는 하이브리드 구조&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;&lt;span class=&quot;chip&quot;&gt;var&lt;/span&gt; — 타입을 추론한 뒤 이후 타입이 고정됨&lt;/li&gt;
      &lt;li&gt;&lt;span class=&quot;chip&quot;&gt;final&lt;/span&gt; — 런타임에 한 번만 값이 할당되는 불변 변수&lt;/li&gt;
      &lt;li&gt;&lt;span class=&quot;chip&quot;&gt;dynamic&lt;/span&gt; — 타입 검사를 생략하는 완전 동적 타입&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Null Safety &lt;span&gt;Null 안정성&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;&lt;span class=&quot;chip&quot;&gt;?&lt;/span&gt; — nullable 타입임을 표시&lt;/li&gt;
          &lt;li&gt;&lt;span class=&quot;chip&quot;&gt;!&lt;/span&gt; — 값이 null이 아님을 단언&lt;/li&gt;
          &lt;li&gt;&lt;span class=&quot;chip&quot;&gt;late&lt;/span&gt; — 나중에 초기화될 값임을 선언&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;String? name; // null 허용 → String name2 = name!;&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;!-- 3. extension, mixin, interface --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;3. 기능 재사용 — extension, mixin, interface&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;코드를 상속 없이도 확장하고 재사용하는 세 가지 방법&lt;/p&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;extension &lt;span&gt;기존 클래스 확장&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;이미 만들어진 클래스에 새 기능을 나중에 추가하는 문법&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;extension StringExt on String { bool get isEmail =&amp;gt; contains('@'); }&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;mixin &lt;span&gt;다중 상속 대체&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;여러 클래스가 동일한 코드를 공유할 수 있게 해주는 문법&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;class Bird with Flying { }&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;interface &lt;span&gt;암묵적 인터페이스&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Dart는 별도 키워드 없이 모든 클래스가 인터페이스 역할을 겸함&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;class Duck implements Flyable { }&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note purple&quot;&gt;Dart에는 &lt;span class=&quot;chip&quot;&gt;interface&lt;/span&gt; 키워드가 따로 없고, 모든 클래스가 암묵적으로 인터페이스가 됨 — implements로 구현함&lt;/div&gt;
  &lt;/div&gt;

  &lt;!-- 4. 자료구조 &amp; 비동기 처리 --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-teal&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;4. 자료구조 &amp;amp; 비동기 처리&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;다양한 컬렉션 타입과 비동기 처리 문법을 지원함&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;자료구조 — List, Set, Map, Queue, LinkedList, HashSet, HashMap&lt;/li&gt;
      &lt;li&gt;비동기 처리 — Future, Stream, async / await&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Future vs Stream &lt;span&gt;비동기 반환 방식&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Future — 한 번의 비동기 결과값을 반환&lt;/li&gt;
          &lt;li&gt;Stream — 여러 번에 걸쳐 연속적으로 값을 반환&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;Future&amp;lt;String&amp;gt;은 결과 1개, Stream&amp;lt;int&amp;gt;는 연속된 값의 흐름&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;!-- 5. JIT + AOT --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-amber&quot;&gt;⚙️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;5. 컴파일 방식 — JIT + AOT&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;개발 중엔 빠르게, 배포할 땐 최적화되게&lt;/p&gt;

    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box&quot;&gt;개발 단계&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;JIT 컴파일&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;핫 리로드로 즉시 확인&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box&quot;&gt;배포 단계&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;AOT 컴파일&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;네이티브 코드로 최적화&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;JIT &lt;span&gt;Just-In-Time&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;실행 중에 컴파일하여 코드 변경 사항을 빠르게 반영 (핫 리로드)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;AOT &lt;span&gt;Ahead-Of-Time&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;실행 전에 미리 컴파일하여 실행 속도를 최적화&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note amber&quot;&gt;이 두 방식을 함께 지원하기 때문에 Flutter는 빠른 개발 속도와 빠른 실행 속도를 동시에 챙길 수 있음&lt;/div&gt;
  &lt;/div&gt;

  &lt;!-- 6. Dart -&gt; Flutter, Fuchsia --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-coral&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;6. Dart → Flutter, 그리고 Fuchsia&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;Dart 위에 세워진 두 개의 그림 — Flutter와 Fuchsia&lt;/p&gt;

    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;Dart&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;Flutter (크로스 플랫폼 UI 프레임워크)&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box&quot;&gt;C&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;Window Programming (전통적 네이티브 개발 방식)&lt;/div&gt;
    &lt;/div&gt;

    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:14px;&quot;&gt;
      &lt;li&gt;Flutter 특징 — GUI 프로그래밍 / 컴파일 기반 / 객체 지향 / 이벤트 기반 / 컴포넌트 기반 / 크로스 플랫폼&lt;/li&gt;
      &lt;li&gt;&lt;span class=&quot;chip&quot;&gt;pub.dev&lt;/span&gt; — Dart의 패키지 생태계, npm과 유사한 역할&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;note blue&quot;&gt;Fuchsia는 구글이 실험 중인 프로젝트로, 원래는 Dart 기반 차세대 범용 OS를 목표로 했으나 현재는 Nest Hub 등 일부 기기에 한정 적용된 상태임&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

&lt;/div&gt;</description>
      <category>Flutter</category>
      <author>크런키스틱</author>
      <guid isPermaLink="true">https://hbc3869.tistory.com/241</guid>
      <comments>https://hbc3869.tistory.com/241#entry241comment</comments>
      <pubDate>Thu, 30 Jul 2026 09:22:03 +0900</pubDate>
    </item>
    <item>
      <title>260723_강의 정리 (Redux, JWT)</title>
      <link>https://hbc3869.tistory.com/240</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: #f8f9fa;
    color: #1a1a1a;
    line-height: 1.7;
    padding: 0;
  }
  .blog-wrap { max-width: 720px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

  .hero { border-left: 4px solid #1D9E75; padding: 0.6rem 0 0.6rem 1.25rem; margin-bottom: 2.5rem; }
  .hero-label { font-size: 11px; font-weight: 700; color: #0F6E56; letter-spacing: 0.09em; text-transform: uppercase; margin-bottom: 6px; }
  .hero-title { font-size: 26px; font-weight: 700; color: #111; line-height: 1.3; margin-bottom: 8px; }
  .hero-sub   { font-size: 14px; color: #555; line-height: 1.7; }

  .section { margin-bottom: 2.2rem; }
  .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 1rem; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8; }
  .section-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
  .section-title { font-size: 17px; font-weight: 700; color: #111; }

  .icon-green  { background: #E1F5EE; }
  .icon-amber  { background: #FAEEDA; }
  .icon-purple { background: #EEEDFE; }
  .icon-blue   { background: #E6F1FB; }
  .icon-coral  { background: #FAECE7; }
  .icon-teal   { background: #E0F4F4; }
  .icon-gray   { background: #F0F0F0; }

  .dot-list { list-style: none; padding: 0; margin: 0; }
  .dot-list li { font-size: 13.5px; color: #444; padding: 3px 0 3px 14px; position: relative; line-height: 1.65; }
  .dot-list li::before { content: &quot;·&quot;; position: absolute; left: 0; color: #1D9E75; font-weight: 700; }
  .dot-list.sm li { font-size: 12.5px; color: #555; }
  .dot-list.sm li::before { color: #aaa; }

  .note        { border-left: 3px solid #1D9E75; background: #E1F5EE; border-radius: 0 8px 8px 0; padding: 11px 15px; margin-top: 12px; font-size: 13px; color: #0F6E56; line-height: 1.65; }
  .note.amber  { border-color: #BA7517;  background: #FAEEDA; color: #7a4d0d; }
  .note.purple { border-color: #7F77DD;  background: #EEEDFE; color: #3C3489; }
  .note.blue   { border-color: #185FA5;  background: #E6F1FB; color: #0d3d6e; }

  .concept-block  { margin-top: 16px; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; }
  .concept-header { background: #f4f4f4; padding: 8px 14px; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.06em; border-bottom: 1px solid #e0e0e0; }
  .concept-item   { padding: 13px 16px; border-bottom: 1px solid #f0f0f0; }
  .concept-item:last-child { border-bottom: none; }
  .concept-term   { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .concept-term span { font-size: 11px; font-weight: 500; color: #888; margin-left: 5px; }
  .concept-ex     { margin-top: 6px; font-size: 11.5px; color: #999; font-style: italic; padding-left: 14px; position: relative; }
  .concept-ex::before { content: &quot;→&quot;; position: absolute; left: 0; }

  .module-block  { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; margin-bottom: 12px; overflow: hidden; }
  .module-header { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid #f0f0f0; background: #fafafa; }
  .module-tag    { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; padding: 3px 10px; border-radius: 5px; }
  .module-name   { font-size: 13px; font-weight: 700; color: #111; }
  .module-body   { padding: 13px 16px; }
  .module-quote  { font-size: 12.5px; color: #888; font-style: italic; margin-bottom: 10px; padding: 6px 10px; background: #f8f9fa; border-radius: 6px; border-left: 2px solid #ddd; }

  .tag-green  { background: #E1F5EE; color: #0F6E56; }
  .tag-amber  { background: #FAEEDA; color: #BA7517; }
  .tag-purple { background: #EEEDFE; color: #534AB7; }
  .tag-blue   { background: #E6F1FB; color: #185FA5; }
  .tag-coral  { background: #FAECE7; color: #993C1D; }
  .tag-teal   { background: #E0F4F4; color: #0D7A7A; }
  .tag-gray   { background: #F0F0F0; color: #444; }

  .flow-row   { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .flow-box   { background: #f4f4f4; border: 1px solid #ddd; border-radius: 8px; padding: 7px 13px; font-size: 12.5px; color: #333; font-weight: 600; }
  .flow-box.hl { background: #E1F5EE; border-color: #1D9E75; color: #0F6E56; }
  .flow-arrow { font-size: 15px; color: #aaa; }

  .flow-step-list { display: flex; flex-direction: column; gap: 0; }
  .flow-step-item { display: flex; gap: 14px; align-items: flex-start; }
  .step-line      { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
  .step-dot       { width: 28px; height: 28px; border-radius: 50%; background: #E1F5EE; border: 2px solid #1D9E75; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #0F6E56; }
  .step-connector { width: 2px; height: 20px; background: #e0e0e0; margin: 3px 0; }
  .step-body      { padding-top: 4px; padding-bottom: 16px; }
  .step-title     { font-size: 13.5px; font-weight: 700; color: #111; margin-bottom: 3px; }
  .step-desc      { font-size: 12.5px; color: #666; line-height: 1.6; }

  .model-card  { display: flex; align-items: flex-start; gap: 12px; padding: 13px 15px; background: #fff; border: 1px solid #e8e8e8; border-radius: 10px; margin-bottom: 8px; }
  .model-badge { min-width: 64px; height: 25px; border-radius: 5px; display: flex; align-items: center; justify-content: center; font-size: 11.5px; font-weight: 700; flex-shrink: 0; }
  .model-name  { font-size: 13.5px; font-weight: 700; color: #111; margin-bottom: 5px; }

  .feature-list { display: flex; flex-direction: column; gap: 7px; margin-top: 4px; }
  .feature-item { background: #fff; border: 1px solid #e8e8e8; border-radius: 8px; padding: 10px 14px; display: flex; gap: 10px; align-items: flex-start; }
  .feature-tag  { font-family: 'Courier New', monospace; font-size: 11.5px; font-weight: 700; color: #0F6E56; background: #E1F5EE; border-radius: 4px; padding: 2px 8px; flex-shrink: 0; white-space: nowrap; }
  .feature-desc { font-size: 12.5px; color: #444; line-height: 1.6; }
  .feature-desc strong { color: #111; }

  .data-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 4px; }
  .data-table th { background: #f4f4f4; padding: 8px 12px; text-align: left; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.04em; border-bottom: 1px solid #e0e0e0; }
  .data-table td { padding: 10px 12px; border-bottom: 1px solid #f0f0f0; font-size: 12.5px; color: #444; vertical-align: top; }
  .data-table tr:last-child td { border-bottom: none; }
  .data-table tr:hover td { background: #fafafa; }

  .summary-item { display: flex; gap: 12px; padding: 10px 14px; background: #fff; border: 1px solid #e8e8e8; border-radius: 8px; margin-bottom: 7px; align-items: flex-start; }
  .s-key { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; color: #534AB7; min-width: 72px; flex-shrink: 0; padding-top: 1px; }
  .s-val { font-size: 13px; color: #444; line-height: 1.6; }
  .s-val strong { color: #111; }

  .card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(155px, 1fr)); gap: 10px; }
  .card       { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; padding: 14px 16px; }
  .card-title { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .card-body  { font-size: 12.5px; color: #555; line-height: 1.7; }

  .pill-row    { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
  .pill        { font-size: 12px; padding: 4px 11px; border-radius: 20px; font-weight: 600; }
  .pill-green  { background: #E1F5EE; color: #0F6E56; }
  .pill-amber  { background: #FAEEDA; color: #BA7517; }
  .pill-purple { background: #EEEDFE; color: #534AB7; }
  .pill-coral  { background: #FAECE7; color: #993C1D; }
  .pill-blue   { background: #E6F1FB; color: #185FA5; }
  .pill-teal   { background: #E0F4F4; color: #0D7A7A; }

  .algo-pill { display: inline-block; font-family: 'Courier New', monospace; font-size: 11.5px; font-weight: 700; padding: 2px 8px; border-radius: 4px; background: #EEEDFE; color: #534AB7; }

  .chip { display: inline-block; background: #f0f0f0; border: 1px solid #ddd; border-radius: 4px; padding: 1px 7px; font-size: 11.5px; font-family: 'Courier New', monospace; color: #555; }

  .divider   { height: 1px; background: #ececec; margin: 2rem 0; }
  .sub-label { font-size: 13px; font-weight: 700; margin-bottom: 8px; color: #333; }
  .sub-green { color: #0F6E56; }
  .sub-coral { color: #993C1D; }

  @media (max-width: 520px) {
    .hero-title  { font-size: 21px; }
    .card-grid   { grid-template-columns: 1fr; }
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;blog-wrap&quot;&gt;

  &lt;div class=&quot;hero&quot;&gt;
    &lt;div class=&quot;hero-label&quot;&gt;Frontend · Auth&lt;/div&gt;
    &lt;div class=&quot;hero-title&quot;&gt;Redux 상태 관리와 RBAC · JWT 인증 정리&lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:6px;&quot;&gt;
      &lt;li&gt;Redux의 단방향 데이터 흐름과 useDispatch / useSelector 동작 원리&lt;/li&gt;
      &lt;li&gt;역할 기반 접근 제어(RBAC)의 3요소 구조&lt;/li&gt;
      &lt;li&gt;JWT의 Header.Payload.Signature 구조와 토큰 저장 전략&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;!-- 1. Redux 데이터 흐름 --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;1. Redux 데이터 흐름&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;React 컴포넌트끼리 데이터를 주고받는 규칙을 하나로 통일한 것&quot; — 전역 상태 관리 라이브러리&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;&lt;strong&gt;Action&lt;/strong&gt;: 무슨 일이 일어났는지 정의하는 객체 (type + payload)&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Reducer&lt;/strong&gt;: Action을 받아 새로운 State를 계산하는 순수 함수&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Store&lt;/strong&gt;: 앱 전체의 State를 보관하는 단일 저장소&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;View Component&lt;/strong&gt;: Store를 구독하고 화면에 렌더링&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;flow-step-list&quot; style=&quot;margin-top:16px;&quot;&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;1&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;View Component → Action 발송&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;useDispatch 훅으로 Action을 Store에 전달&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;2&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;Reducer가 새 State 계산&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;Action 타입에 따라 이전 State를 기반으로 새 State 반환&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;3&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;Store 업데이트&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;계산된 새 State로 Store 내부 값 교체&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;4&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;구독 컴포넌트 리렌더링&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;useSelector로 구독 중인 컴포넌트만 자동으로 다시 그려짐&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;useDispatch &lt;span&gt;hook&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;컴포넌트에서 Action을 Store로 보내는 훅&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;&quot;편지를 보내는 우체통&quot; 역할&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;useSelector &lt;span&gt;hook&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Store의 State 중 필요한 부분만 선택해 구독하는 훅&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;&quot;진열대에서 원하는 물건만 골라 담는 것&quot;&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Provider &lt;span&gt;(등록 과정)&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;&amp;lt;Provider store={'{'}store{'}'}&amp;gt;로 React 앱 최상단을 감싸 하위 모든 컴포넌트가 Store에 접근 가능하게 함&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;다이어그램의 Store → ReactDOM &quot;등록&quot; 화살표가 이 과정&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note&quot;&gt;Redux는 메모리(런타임) 상태 관리 도구일 뿐, 새로고침하면 초기화됨 → 영구 저장은 별도 처리 필요&lt;/div&gt;
  &lt;/div&gt;

  &lt;!-- 2. Redux와 영구 저장소 --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-blue&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;2. Redux와 영구 저장소&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;Redux 자체는 영구 저장이 불가능 — 브라우저 저장소와 연동해야 데이터가 유지됨&lt;/p&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;저장소&lt;/th&gt;
          &lt;th&gt;특징&lt;/th&gt;
          &lt;th&gt;주의점&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;span class=&quot;chip&quot;&gt;localStorage&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;만료 없음, 용량 약 5~10MB&lt;/td&gt;
          &lt;td&gt;JS로 직접 접근 가능 → XSS 취약&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;span class=&quot;chip&quot;&gt;sessionStorage&lt;/span&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;span class=&quot;chip&quot;&gt;Cookie&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;요청마다 서버로 자동 전송&lt;/td&gt;
          &lt;td&gt;HttpOnly 설정 시 XSS 방어, 단 CSRF 주의 필요&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;span class=&quot;chip&quot;&gt;IndexedDB&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;대용량·구조화 데이터에 적합&lt;/td&gt;
          &lt;td&gt;비동기 API, 사용법이 상대적으로 복잡&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;

    &lt;div class=&quot;note amber&quot;&gt;&lt;strong&gt;인증 토큰 저장 시 유의&lt;/strong&gt;&lt;br&gt;· localStorage는 JS로 접근 가능해 XSS 공격에 취약&lt;br&gt;· HttpOnly Cookie가 상대적으로 안전한 선택지로 많이 사용됨&lt;/div&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;redux-persist &lt;span&gt;middleware&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Redux State를 localStorage 등 브라우저 저장소에 자동으로 동기화해주는 미들웨어&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ 새로고침해도 로그인 상태 등이 유지되도록 함&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;!-- 3. RBAC --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;3. RBAC (Role Based Access Control)&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;역할에 따라 접근 권한을 다르게 부여하는 방식&quot; — 사용자 개별이 아닌 역할 단위로 권한을 관리&lt;/p&gt;

    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;User(Role)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;Permission(Group)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;Resource&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;concept-block&quot; style=&quot;margin-top:16px;&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;User(Role)&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;사용자에게 역할을 부여 (예: admin, editor, viewer)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Permission(Group)&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;역할에 묶인 권한 집합 (예: 읽기, 쓰기, 삭제)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Resource&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;권한이 적용되는 대상 (예: 게시글, 회원정보)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note blue&quot;&gt;사용자마다 권한을 개별 설정하지 않고 역할 단위로 관리 → 확장성과 유지보수성 확보&lt;/div&gt;
  &lt;/div&gt;

  &lt;!-- 4. JWT --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-coral&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;4. JWT (JSON Web Token)&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;로그인 정보를 서버가 저장하지 않고도 검증할 수 있게 만든 토큰&quot; — Stateless 인증 방식&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;구조: &lt;span class=&quot;chip&quot;&gt;Header.Payload.Signature&lt;/span&gt; (Base64URL 인코딩, 점으로 구분)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;Header&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;.&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;Payload&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;.&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;Signature&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;concept-block&quot; style=&quot;margin-top:16px;&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Header&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;알고리즘 및 토큰 타입 정보 (원본 슬라이드에서 Payload로 오기됨 → 수정)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Payload&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;사용자 데이터 및 Claims (예: user_id, exp)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Signature&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;발신자 인증 + 무결성 검증 — 비밀키로 서명해 위변조 여부 확인&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;simplejwt &lt;span&gt;djangorestframework-simplejwt&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Django REST Framework용 JWT 발급·검증 라이브러리&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;백엔드에서 로그인 시 Access/Refresh 토큰 발급을 담당&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note purple&quot;&gt;JWT는 암호화(encryption)가 아닌 인코딩(encoding) — Payload는 디코딩하면 누구나 읽을 수 있어 민감 정보 저장 금지&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;!-- 5. 종합 정리 --&gt;
  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-gray&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;5. 종합 정리&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;pill-row&quot;&gt;
      &lt;div class=&quot;pill pill-green&quot;&gt;Redux · 클라이언트 상태 관리&lt;/div&gt;
      &lt;div class=&quot;pill pill-purple&quot;&gt;RBAC · 서버 권한 체계&lt;/div&gt;
      &lt;div class=&quot;pill pill-blue&quot;&gt;JWT · 인증 토큰 형식&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;flow-row&quot; style=&quot;margin-top:16px;&quot;&gt;
      &lt;div class=&quot;flow-box&quot;&gt;로그인&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;JWT 발급&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;저장(Cookie 등)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;요청 시 토큰 전송&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;RBAC 권한 확인&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;리소스 접근 허용&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note&quot;&gt;Redux, RBAC, JWT는 서로 별개 개념이지만 실무 인증 흐름에서 자연스럽게 함께 사용됨&lt;/div&gt;
  &lt;/div&gt;

&lt;/div&gt;</description>
      <category>JavaScript/React.js</category>
      <author>크런키스틱</author>
      <guid isPermaLink="true">https://hbc3869.tistory.com/240</guid>
      <comments>https://hbc3869.tistory.com/240#entry240comment</comments>
      <pubDate>Thu, 23 Jul 2026 16:09:29 +0900</pubDate>
    </item>
    <item>
      <title>260722_강의 정리 (Component Lifecycle)</title>
      <link>https://hbc3869.tistory.com/239</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: #f8f9fa;
    color: #1a1a1a;
    line-height: 1.7;
    padding: 0;
  }
  .blog-wrap { max-width: 720px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

  .hero { border-left: 4px solid #1D9E75; padding: 0.6rem 0 0.6rem 1.25rem; margin-bottom: 2.5rem; }
  .hero-label { font-size: 11px; font-weight: 700; color: #0F6E56; letter-spacing: 0.09em; text-transform: uppercase; margin-bottom: 6px; }
  .hero-title { font-size: 26px; font-weight: 700; color: #111; line-height: 1.3; margin-bottom: 8px; }
  .hero-sub   { font-size: 14px; color: #555; line-height: 1.7; }

  .section { margin-bottom: 2.2rem; }
  .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 1rem; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8; }
  .section-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
  .section-title { font-size: 17px; font-weight: 700; color: #111; }

  .icon-green  { background: #E1F5EE; }
  .icon-amber  { background: #FAEEDA; }
  .icon-purple { background: #EEEDFE; }
  .icon-blue   { background: #E6F1FB; }
  .icon-coral  { background: #FAECE7; }
  .icon-teal   { background: #E0F4F4; }
  .icon-gray   { background: #F0F0F0; }

  .dot-list { list-style: none; padding: 0; margin: 0; }
  .dot-list li { font-size: 13.5px; color: #444; padding: 3px 0 3px 14px; position: relative; line-height: 1.65; }
  .dot-list li::before { content: &quot;·&quot;; position: absolute; left: 0; color: #1D9E75; font-weight: 700; }
  .dot-list.sm li { font-size: 12.5px; color: #555; }
  .dot-list.sm li::before { color: #aaa; }

  .note        { border-left: 3px solid #1D9E75; background: #E1F5EE; border-radius: 0 8px 8px 0; padding: 11px 15px; margin-top: 12px; font-size: 13px; color: #0F6E56; line-height: 1.65; }
  .note.amber  { border-color: #BA7517;  background: #FAEEDA; color: #7a4d0d; }
  .note.purple { border-color: #7F77DD;  background: #EEEDFE; color: #3C3489; }
  .note.blue   { border-color: #185FA5;  background: #E6F1FB; color: #0d3d6e; }

  .concept-block  { margin-top: 16px; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; }
  .concept-header { background: #f4f4f4; padding: 8px 14px; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.06em; border-bottom: 1px solid #e0e0e0; }
  .concept-item   { padding: 13px 16px; border-bottom: 1px solid #f0f0f0; }
  .concept-item:last-child { border-bottom: none; }
  .concept-term   { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .concept-term span { font-size: 11px; font-weight: 500; color: #888; margin-left: 5px; }
  .concept-ex     { margin-top: 6px; font-size: 11.5px; color: #999; font-style: italic; padding-left: 14px; position: relative; }
  .concept-ex::before { content: &quot;→&quot;; position: absolute; left: 0; }

  .module-block  { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; margin-bottom: 12px; overflow: hidden; }
  .module-header { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid #f0f0f0; background: #fafafa; }
  .module-tag    { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; padding: 3px 10px; border-radius: 5px; }
  .module-name   { font-size: 13px; font-weight: 700; color: #111; }
  .module-body   { padding: 13px 16px; }
  .module-quote  { font-size: 12.5px; color: #888; font-style: italic; margin-bottom: 10px; padding: 6px 10px; background: #f8f9fa; border-radius: 6px; border-left: 2px solid #ddd; }

  .tag-green  { background: #E1F5EE; color: #0F6E56; }
  .tag-amber  { background: #FAEEDA; color: #BA7517; }
  .tag-purple { background: #EEEDFE; color: #534AB7; }
  .tag-blue   { background: #E6F1FB; color: #185FA5; }
  .tag-coral  { background: #FAECE7; color: #993C1D; }
  .tag-teal   { background: #E0F4F4; color: #0D7A7A; }
  .tag-gray   { background: #F0F0F0; color: #444; }

  .flow-row   { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .flow-box   { background: #f4f4f4; border: 1px solid #ddd; border-radius: 8px; padding: 7px 13px; font-size: 12.5px; color: #333; font-weight: 600; }
  .flow-box.hl { background: #E1F5EE; border-color: #1D9E75; color: #0F6E56; }
  .flow-arrow { font-size: 15px; color: #aaa; }

  .flow-step-list { display: flex; flex-direction: column; gap: 0; }
  .flow-step-item { display: flex; gap: 14px; align-items: flex-start; }
  .step-line      { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
  .step-dot       { width: 28px; height: 28px; border-radius: 50%; background: #E1F5EE; border: 2px solid #1D9E75; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #0F6E56; }
  .step-connector { width: 2px; height: 20px; background: #e0e0e0; margin: 3px 0; }
  .step-body      { padding-top: 4px; padding-bottom: 16px; }
  .step-title     { font-size: 13.5px; font-weight: 700; color: #111; margin-bottom: 3px; }
  .step-desc      { font-size: 12.5px; color: #666; line-height: 1.6; }

  .data-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 4px; }
  .data-table th { background: #f4f4f4; padding: 8px 12px; text-align: left; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.04em; border-bottom: 1px solid #e0e0e0; }
  .data-table td { padding: 10px 12px; border-bottom: 1px solid #f0f0f0; font-size: 12.5px; color: #444; vertical-align: top; }
  .data-table tr:last-child td { border-bottom: none; }
  .data-table tr:hover td { background: #fafafa; }
  .algo-pill { display: inline-block; font-family: 'Courier New', monospace; font-size: 11.5px; font-weight: 700; padding: 2px 8px; border-radius: 4px; background: #EEEDFE; color: #534AB7; }

  .chip { display: inline-block; background: #f0f0f0; border: 1px solid #ddd; border-radius: 4px; padding: 1px 7px; font-size: 11.5px; font-family: 'Courier New', monospace; color: #555; }

  .pill-row    { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
  .pill        { font-size: 12px; padding: 4px 11px; border-radius: 20px; font-weight: 600; }
  .pill-green  { background: #E1F5EE; color: #0F6E56; }
  .pill-amber  { background: #FAEEDA; color: #BA7517; }
  .pill-purple { background: #EEEDFE; color: #534AB7; }
  .pill-coral  { background: #FAECE7; color: #993C1D; }
  .pill-blue   { background: #E6F1FB; color: #185FA5; }
  .pill-teal   { background: #E0F4F4; color: #0D7A7A; }

  .divider   { height: 1px; background: #ececec; margin: 2rem 0; }

  @media (max-width: 520px) {
    .hero-title  { font-size: 21px; }
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;blog-wrap&quot;&gt;

  &lt;div class=&quot;hero&quot;&gt;
    &lt;div class=&quot;hero-label&quot;&gt;frontend · react&lt;/div&gt;
    &lt;div class=&quot;hero-title&quot;&gt;React Component Lifecycle — Class와 Hooks 대응 정리&lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:6px;&quot;&gt;
      &lt;li&gt;Render phase와 Commit phase로 나뉘는 이유&lt;/li&gt;
      &lt;li&gt;Class의 3단계 lifecycle이 useEffect 하나로 통합되는 원리&lt;/li&gt;
      &lt;li&gt;props drilling 문제와 useContext를 통한 해결&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt;⚙️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;1. Lifecycle 개요 — Render phase vs Commit phase&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;React는 렌더링을 왜 두 단계로 나누는가?&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;Render phase — 현재 state를 기반으로 화면 구성을 계산하는 단계&lt;/li&gt;
      &lt;li&gt;Commit phase — 계산된 결과를 실제 DOM에 반영하는 단계&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Render phase&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;순수 계산만 수행, side effect(DOM 조작·API 호출 등) 금지&lt;/li&gt;
          &lt;li&gt;중단·재시작이 가능해 우선순위 높은 작업이 끼어들 수 있음&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ constructor, getDerivedStateFromProps, shouldComponentUpdate, render&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Commit phase&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;계산 결과를 실제 DOM에 반영, side effect 허용&lt;/li&gt;
          &lt;li&gt;한번 시작하면 중단 없이 끝까지 실행됨&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ componentDidMount, componentDidUpdate&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-blue&quot;&gt; ️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;2. Class 컴포넌트의 3단계 Lifecycle&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;Mounting → Updating → Unmounting 순서로 진행되는 컴포넌트 생애주기&lt;/p&gt;

    &lt;div class=&quot;flow-step-list&quot;&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;1&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;Mounting&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;constructor → getDerivedStateFromProps → shouldComponentUpdate → render → componentDidMount&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;2&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;Updating&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;New props / setState() / forceUpdate() 발생 → 동일 render 경로 재실행 → componentDidUpdate&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;3&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;Unmounting&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;componentWillUnmount — 컴포넌트 제거 직전 정리 작업 수행&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;tr&gt;&lt;th&gt;메서드&lt;/th&gt;&lt;th&gt;역할&lt;/th&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;getDerivedStateFromProps&lt;/span&gt;&lt;/td&gt;&lt;td&gt;props 변경에 따라 state를 동기화 (드물게 사용)&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;shouldComponentUpdate&lt;/span&gt;&lt;/td&gt;&lt;td&gt;불필요한 리렌더링을 막는 최적화용 훅, false 반환 시 render 생략&lt;/td&gt;&lt;/tr&gt;
    &lt;/table&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;3. Hooks로의 통합 — useState &amp; useEffect&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;3단계 Class lifecycle이 Hooks에서는 어떻게 하나로 합쳐지는가?&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;useState — constructor에서의 state 초기화 역할을 대체&lt;/li&gt;
      &lt;li&gt;useEffect — componentDidMount + componentDidUpdate + componentWillUnmount를 하나의 Hook으로 통합&lt;/li&gt;
    &lt;/ul&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;tr&gt;&lt;th&gt;Class lifecycle&lt;/th&gt;&lt;th&gt;대응 Hook&lt;/th&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;constructor (state 초기화)&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;useState&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;componentDidMount&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;useEffect(fn, [])&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;componentDidUpdate&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;useEffect(fn, [deps])&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;componentWillUnmount&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;useEffect&lt;/span&gt; 내부 cleanup(return) 함수&lt;/td&gt;&lt;/tr&gt;
    &lt;/table&gt;

    &lt;div class=&quot;note purple&quot;&gt;Class는 목적별로 메서드가 나뉘지만, Hooks는 &lt;strong&gt;하나의 useEffect가 의존성 배열에 따라 여러 역할&lt;/strong&gt;을 수행함&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-teal&quot;&gt;⏱️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;4. useEffect 실행 조건 3가지&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;두 번째 인자(의존성 배열)에 따라 실행 시점이 달라짐&lt;/p&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;tr&gt;&lt;th&gt;형태&lt;/th&gt;&lt;th&gt;실행 시점&lt;/th&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;useEffect(() =&amp;gt; {...})&lt;/span&gt;&lt;/td&gt;&lt;td&gt;매 렌더링마다 실행 (최초 마운트 포함)&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;useEffect(() =&amp;gt; {...}, [])&lt;/span&gt;&lt;/td&gt;&lt;td&gt;최초 1회만 실행 — componentDidMount 대응&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;useEffect(() =&amp;gt; {...}, [a, b])&lt;/span&gt;&lt;/td&gt;&lt;td&gt;a 또는 b가 변경될 때만 실행 — 선택적 componentDidUpdate&lt;/td&gt;&lt;/tr&gt;
    &lt;/table&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Cleanup 함수 &lt;span&gt;useEffect 내부 return&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;다음 effect 실행 직전, 또는 컴포넌트 unmount 시 호출되는 정리 함수&lt;/li&gt;
          &lt;li&gt;componentWillUnmount와 동일한 역할 수행&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ useEffect(() =&amp;gt; { const id = setInterval(...); return () =&amp;gt; clearInterval(id); })&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-amber&quot;&gt; ️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;5. Hook 생태계 3대 기능 구역&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;역할에 따라 크게 세 구역으로 분류할 수 있음&lt;/p&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;tr&gt;&lt;th&gt;구역&lt;/th&gt;&lt;th&gt;포함 Hook&lt;/th&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;상태 관리 (State Management)&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;useState&lt;/span&gt; &lt;span class=&quot;algo-pill&quot;&gt;useReducer&lt;/span&gt; &lt;span class=&quot;algo-pill&quot;&gt;useContext&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;사이드 이펙트 제어 (Side Effects)&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;useEffect&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;성능 최적화 및 참조 (Optimization &amp; Refs)&lt;/td&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;useMemo&lt;/span&gt; &lt;span class=&quot;algo-pill&quot;&gt;useCallback&lt;/span&gt; &lt;span class=&quot;algo-pill&quot;&gt;useRef&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
    &lt;/table&gt;

    &lt;div class=&quot;note&quot;&gt;1강에서 다룬 useContext + useReducer 결합 패턴은 모두 &lt;strong&gt;상태 관리 구역&lt;/strong&gt; 안에서의 조합임&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-blue&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;6. Events Handler — App ↔ Virtual DOM ↔ DOM&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;이벤트와 렌더링 결과가 양방향으로 오가는 흐름&lt;/p&gt;

    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box&quot;&gt;DOM (이벤트 발생)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;Virtual DOM&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;App (상태 반영)&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box&quot;&gt;App (상태 변경)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;Virtual DOM&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;DOM (갱신)&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note blue&quot;&gt;양방향 흐름이지만, DOM에 실제 반영될 때는 1강에서 다룬 &lt;strong&gt;Diffing&lt;/strong&gt;을 거쳐 변경분만 최소 적용됨&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-coral&quot;&gt; ️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;7. Props Drilling 문제&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;props를 여러 단계 거쳐 전달해야 할 때 생기는 문제는?&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;최상위 컴포넌트의 데이터를 하위 컴포넌트까지 전달하기 위해, 중간 컴포넌트들이 사용하지도 않는 props를 계속 릴레이해야 하는 상황&lt;/li&gt;
      &lt;li&gt;트리가 깊어질수록 중간 컴포넌트 코드가 불필요하게 복잡해짐&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;note amber&quot;&gt;&lt;strong&gt;해결책&lt;/strong&gt;&lt;br&gt;· 1강에서 다룬 useContext가 대표적 해결 방법 — 중간 단계 없이 필요한 컴포넌트에 직접 데이터 전달 가능&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

&lt;/div&gt;</description>
      <category>JavaScript/React.js</category>
      <author>크런키스틱</author>
      <guid isPermaLink="true">https://hbc3869.tistory.com/239</guid>
      <comments>https://hbc3869.tistory.com/239#entry239comment</comments>
      <pubDate>Wed, 22 Jul 2026 09:34:11 +0900</pubDate>
    </item>
    <item>
      <title>260722_강의 정리 (개발환경, JSX, Virtual DOM 정리)</title>
      <link>https://hbc3869.tistory.com/238</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: #f8f9fa;
    color: #1a1a1a;
    line-height: 1.7;
    padding: 0;
  }
  .blog-wrap { max-width: 720px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

  .hero { border-left: 4px solid #1D9E75; padding: 0.6rem 0 0.6rem 1.25rem; margin-bottom: 2.5rem; }
  .hero-label { font-size: 11px; font-weight: 700; color: #0F6E56; letter-spacing: 0.09em; text-transform: uppercase; margin-bottom: 6px; }
  .hero-title { font-size: 26px; font-weight: 700; color: #111; line-height: 1.3; margin-bottom: 8px; }
  .hero-sub   { font-size: 14px; color: #555; line-height: 1.7; }

  .section { margin-bottom: 2.2rem; }
  .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 1rem; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8; }
  .section-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
  .section-title { font-size: 17px; font-weight: 700; color: #111; }

  .icon-green  { background: #E1F5EE; }
  .icon-amber  { background: #FAEEDA; }
  .icon-purple { background: #EEEDFE; }
  .icon-blue   { background: #E6F1FB; }
  .icon-coral  { background: #FAECE7; }
  .icon-teal   { background: #E0F4F4; }
  .icon-gray   { background: #F0F0F0; }

  .dot-list { list-style: none; padding: 0; margin: 0; }
  .dot-list li { font-size: 13.5px; color: #444; padding: 3px 0 3px 14px; position: relative; line-height: 1.65; }
  .dot-list li::before { content: &quot;·&quot;; position: absolute; left: 0; color: #1D9E75; font-weight: 700; }
  .dot-list.sm li { font-size: 12.5px; color: #555; }
  .dot-list.sm li::before { color: #aaa; }

  .note        { border-left: 3px solid #1D9E75; background: #E1F5EE; border-radius: 0 8px 8px 0; padding: 11px 15px; margin-top: 12px; font-size: 13px; color: #0F6E56; line-height: 1.65; }
  .note.amber  { border-color: #BA7517;  background: #FAEEDA; color: #7a4d0d; }
  .note.purple { border-color: #7F77DD;  background: #EEEDFE; color: #3C3489; }
  .note.blue   { border-color: #185FA5;  background: #E6F1FB; color: #0d3d6e; }

  .concept-block  { margin-top: 16px; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; }
  .concept-header { background: #f4f4f4; padding: 8px 14px; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.06em; border-bottom: 1px solid #e0e0e0; }
  .concept-item   { padding: 13px 16px; border-bottom: 1px solid #f0f0f0; }
  .concept-item:last-child { border-bottom: none; }
  .concept-term   { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .concept-term span { font-size: 11px; font-weight: 500; color: #888; margin-left: 5px; }
  .concept-ex     { margin-top: 6px; font-size: 11.5px; color: #999; font-style: italic; padding-left: 14px; position: relative; }
  .concept-ex::before { content: &quot;→&quot;; position: absolute; left: 0; }

  .module-block  { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; margin-bottom: 12px; overflow: hidden; }
  .module-header { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid #f0f0f0; background: #fafafa; }
  .module-tag    { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; padding: 3px 10px; border-radius: 5px; }
  .module-name   { font-size: 13px; font-weight: 700; color: #111; }
  .module-body   { padding: 13px 16px; }
  .module-quote  { font-size: 12.5px; color: #888; font-style: italic; margin-bottom: 10px; padding: 6px 10px; background: #f8f9fa; border-radius: 6px; border-left: 2px solid #ddd; }

  .tag-green  { background: #E1F5EE; color: #0F6E56; }
  .tag-amber  { background: #FAEEDA; color: #BA7517; }
  .tag-purple { background: #EEEDFE; color: #534AB7; }
  .tag-blue   { background: #E6F1FB; color: #185FA5; }
  .tag-coral  { background: #FAECE7; color: #993C1D; }
  .tag-teal   { background: #E0F4F4; color: #0D7A7A; }
  .tag-gray   { background: #F0F0F0; color: #444; }

  .flow-row   { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .flow-box   { background: #f4f4f4; border: 1px solid #ddd; border-radius: 8px; padding: 7px 13px; font-size: 12.5px; color: #333; font-weight: 600; }
  .flow-box.hl { background: #E1F5EE; border-color: #1D9E75; color: #0F6E56; }
  .flow-arrow { font-size: 15px; color: #aaa; }

  .flow-step-list { display: flex; flex-direction: column; gap: 0; }
  .flow-step-item { display: flex; gap: 14px; align-items: flex-start; }
  .step-line      { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
  .step-dot       { width: 28px; height: 28px; border-radius: 50%; background: #E1F5EE; border: 2px solid #1D9E75; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #0F6E56; }
  .step-connector { width: 2px; height: 20px; background: #e0e0e0; margin: 3px 0; }
  .step-body      { padding-top: 4px; padding-bottom: 16px; }
  .step-title     { font-size: 13.5px; font-weight: 700; color: #111; margin-bottom: 3px; }
  .step-desc      { font-size: 12.5px; color: #666; line-height: 1.6; }

  .data-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 4px; }
  .data-table th { background: #f4f4f4; padding: 8px 12px; text-align: left; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.04em; border-bottom: 1px solid #e0e0e0; }
  .data-table td { padding: 10px 12px; border-bottom: 1px solid #f0f0f0; font-size: 12.5px; color: #444; vertical-align: top; }
  .data-table tr:last-child td { border-bottom: none; }
  .data-table tr:hover td { background: #fafafa; }
  .algo-pill { display: inline-block; font-family: 'Courier New', monospace; font-size: 11.5px; font-weight: 700; padding: 2px 8px; border-radius: 4px; background: #EEEDFE; color: #534AB7; }

  .chip { display: inline-block; background: #f0f0f0; border: 1px solid #ddd; border-radius: 4px; padding: 1px 7px; font-size: 11.5px; font-family: 'Courier New', monospace; color: #555; }

  .pill-row    { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
  .pill        { font-size: 12px; padding: 4px 11px; border-radius: 20px; font-weight: 600; }
  .pill-green  { background: #E1F5EE; color: #0F6E56; }
  .pill-amber  { background: #FAEEDA; color: #BA7517; }
  .pill-purple { background: #EEEDFE; color: #534AB7; }
  .pill-coral  { background: #FAECE7; color: #993C1D; }
  .pill-blue   { background: #E6F1FB; color: #185FA5; }
  .pill-teal   { background: #E0F4F4; color: #0D7A7A; }

  .divider   { height: 1px; background: #ececec; margin: 2rem 0; }

  @media (max-width: 520px) {
    .hero-title  { font-size: 21px; }
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;blog-wrap&quot;&gt;

  &lt;div class=&quot;hero&quot;&gt;
    &lt;div class=&quot;hero-label&quot;&gt;frontend · react&lt;/div&gt;
    &lt;div class=&quot;hero-title&quot;&gt;React 시작하기 — 개발환경, JSX, Virtual DOM 정리&lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:6px;&quot;&gt;
      &lt;li&gt;WSL 기반 개발환경 세팅부터 컴포넌트 개념까지 정리&lt;/li&gt;
      &lt;li&gt;JSX가 실제 브라우저에서 동작하는 원리(Babel 트랜스파일)&lt;/li&gt;
      &lt;li&gt;Virtual DOM이 빠른 진짜 이유 — Diffing(재조정) 과정&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt; ️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;1. 개발 환경 세팅&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;React 프로젝트를 시작하기 전 필요한 기본 도구들 설치 순서&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;Windows 환경에서는 WSL(Windows Subsystem for Linux) 위에 Ubuntu 22.04 LTS를 설치해 리눅스 개발환경 구성&lt;/li&gt;
      &lt;li&gt;Ubuntu 위에 Node.js 설치 → JavaScript를 브라우저 밖(서버·터미널)에서 실행 가능하게 함&lt;/li&gt;
      &lt;li&gt;Node.js 설치 시 함께 제공되는 npm(Node Package Manager)으로 라이브러리 설치·관리&lt;/li&gt;
      &lt;li&gt;프로젝트 루트의 package.json이 설치된 패키지 목록과 버전, 실행 스크립트 관리&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;WSL &lt;span&gt;Windows Subsystem for Linux&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Windows 안에서 리눅스 커널을 직접 실행하는 호환 계층&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;가상머신 없이 Windows에서 Ubuntu 명령어를 그대로 사용&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;npm &lt;span&gt;Node Package Manager&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Node.js용 패키지(라이브러리) 설치·버전 관리 도구&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ npm install react 명령으로 React 라이브러리 설치&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-blue&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;2. HTML programming vs React&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;HTML template를 React가 왜, 어떻게 대체하는가?&quot;&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;기존 HTML programming — 태그 기반, GUI 기반, 이벤트 기반으로 화면 구성&lt;/li&gt;
      &lt;li&gt;React는 컴포넌트 기반(Component base) 프로그래밍 방식&lt;/li&gt;
      &lt;li&gt;컴포넌트 구성 요소: Props(속성), State(상태), JSX(마크업), Side effect(부수효과)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;tr&gt;&lt;th&gt;구현 방식&lt;/th&gt;&lt;th&gt;특징&lt;/th&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;Class 컴포넌트&lt;/span&gt;&lt;/td&gt;&lt;td&gt;ES6 class 문법 기반, this 바인딩 필요, 생명주기 메서드 사용&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;Function + Hooks&lt;/span&gt;&lt;/td&gt;&lt;td&gt;함수 문법 기반, useState·useEffect 등 Hook으로 상태·부수효과 관리, 코드 간결&lt;/td&gt;&lt;/tr&gt;
    &lt;/table&gt;

    &lt;div class=&quot;note amber&quot;&gt;&lt;strong&gt;현재 권장 방식&lt;/strong&gt;&lt;br&gt;· React 공식 문서 기준 신규 프로젝트는 Function 컴포넌트 + Hooks 방식을 권장함&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;3. JSX — JS와 HTML의 결합&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;브라우저는 JSX를 못 읽는데 어떻게 동작하는가?&quot;&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;JavaScript 문법 안에 HTML과 유사한 태그를 직접 작성하는 방식 = JSX&lt;/li&gt;
      &lt;li&gt;브라우저는 JSX 문법을 이해하지 못하므로 그대로 실행 불가&lt;/li&gt;
      &lt;li&gt;Babel이 빌드 시점에 JSX를 순수 JavaScript 함수 호출로 변환&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box&quot;&gt;JSX 코드&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;Babel 변환&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;React.createElement() 호출&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;브라우저 실행&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;JSX &lt;span&gt;JavaScript XML&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;JS 안에서 HTML과 유사한 태그 문법을 쓸 수 있게 해주는 확장 문법&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ &amp;lt;div&amp;gt;Hello&amp;lt;/div&amp;gt; 형태로 JS 안에 마크업 작성&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Babel &lt;span&gt;JS 트랜스파일러&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;최신 문법(JSX 포함)을 구버전 브라우저도 이해할 수 있는 JS로 변환&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ &amp;lt;div&amp;gt;Hello&amp;lt;/div&amp;gt; → React.createElement('div', null, 'Hello')&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-amber&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;4. 빌드 도구 &amp; SPA&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;React 코드를 실제 배포 가능한 형태로 묶어주는 도구들&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;React + Babel + 번들러 조합으로 개발 진행 (React: UI 라이브러리, Babel: 문법 변환, 번들러: 파일 묶음)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;tr&gt;&lt;th&gt;도구&lt;/th&gt;&lt;th&gt;역할&lt;/th&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;webpack&lt;/span&gt;&lt;/td&gt;&lt;td&gt;모듈 번들러, 설정 자유도 높지만 초기 빌드 속도 느린 편&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;Vite&lt;/span&gt;&lt;/td&gt;&lt;td&gt;개발 시 esbuild로 빠른 서버 구동, 프로덕션 빌드 시 Rollup 사용&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;Rollup&lt;/span&gt;&lt;/td&gt;&lt;td&gt;라이브러리 번들링에 특화, 트리 셰이킹 우수&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;esbuild&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Go로 작성된 초고속 번들러/트랜스파일러&lt;/td&gt;&lt;/tr&gt;
    &lt;/table&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;SPA &lt;span&gt;Single Page Application&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;페이지 전체를 새로 불러오지 않고, 클라이언트 측에서 필요한 부분만 갱신하며 라우팅·렌더링&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ 메뉴 클릭 시 화면 깜빡임 없이 콘텐츠만 바뀌는 방식&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-teal&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;5. Virtual DOM ↔ Real DOM&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;왜 Virtual DOM을 쓰면 빠른가?&quot;&lt;/p&gt;

    &lt;div class=&quot;flow-step-list&quot;&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;1&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;이벤트 발생&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;클릭 등 사용자 이벤트로 setState / useEffect / useContext / useReducer 트리거&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;2&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;Virtual DOM 갱신&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;변경된 state를 반영한 새로운 Virtual DOM 트리를 메모리 상에 생성&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;3&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;Diffing(재조정)&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;이전 Virtual DOM과 새 Virtual DOM을 비교해 실제로 바뀐 부분만 찾아냄&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;4&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;Real DOM 반영&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;변경분만 실제 DOM에 적용 → 불필요한 전체 리렌더링 방지&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Virtual DOM &lt;span&gt;가상 DOM&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;실제 DOM 구조를 JS 객체 형태로 메모리에 복제해 둔 것&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ 실제 DOM 조작보다 메모리 상 객체 비교가 훨씬 빠름&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Diffing &lt;span&gt;Reconciliation, 재조정&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;이전·이후 Virtual DOM 트리를 비교해 최소한의 변경 지점만 찾아내는 알고리즘&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ 리스트 100개 중 1개만 바뀌었다면 그 1개만 Real DOM에 반영&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;useRef &lt;span&gt;Real DOM 직접 참조&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Virtual DOM을 거치지 않고 실제 DOM 요소에 직접 접근해야 할 때 사용&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ input 포커스 강제 이동, 스크롤 위치 제어 등에 활용&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note&quot;&gt;Virtual DOM 자체가 빠른 게 아니라, Diffing으로 &lt;strong&gt;필요한 부분만 갱신&lt;/strong&gt;하는 전략이 성능의 핵심임&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-coral&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;6. Component Tree, Props &amp; State&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;컴포넌트는 트리 구조로 중첩되며, Props와 State로 데이터를 관리함&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;Component Tree — 부모 컴포넌트가 자식 컴포넌트를 포함하는 계층 구조&lt;/li&gt;
      &lt;li&gt;부모 → 자식 방향으로 Props 전달, 각 컴포넌트는 자체 State 보유 가능&lt;/li&gt;
    &lt;/ul&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;tr&gt;&lt;th&gt;구분&lt;/th&gt;&lt;th&gt;Props&lt;/th&gt;&lt;th&gt;State&lt;/th&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;가변(useState 등으로 변경)&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;/table&gt;

    &lt;div class=&quot;note blue&quot;&gt;React는 &lt;strong&gt;단방향 데이터 흐름(one-way data flow)&lt;/strong&gt;을 따름 — 데이터는 항상 부모에서 자식으로만 전달되어 흐름 추적이 쉬움&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;7. 전역 상태 관리 — useContext + useReducer 결합&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;Redux 없이 전역 상태를 어떻게 관리할까?&quot;&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;useContext — 컴포넌트 트리 깊숙한 곳까지 props 없이 데이터 전달&lt;/li&gt;
      &lt;li&gt;useReducer — 복잡한 상태 변경 로직을 reducer 함수로 분리 관리&lt;/li&gt;
      &lt;li&gt;두 Hook을 결합하면 Redux와 유사한 전역 상태관리 패턴 구현 가능&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;note amber&quot;&gt;&lt;strong&gt;활용 팁&lt;/strong&gt;&lt;br&gt;· 소규모~중간 규모 프로젝트에서 별도 라이브러리 설치 없이 Redux 대체 수단으로 활용 가능&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

&lt;/div&gt;</description>
      <category>JavaScript/React.js</category>
      <author>크런키스틱</author>
      <guid isPermaLink="true">https://hbc3869.tistory.com/238</guid>
      <comments>https://hbc3869.tistory.com/238#entry238comment</comments>
      <pubDate>Wed, 22 Jul 2026 09:30:02 +0900</pubDate>
    </item>
    <item>
      <title>260710_강의 정리 (TCGA, TCIA, CRDC로 보는 암 유전체 데이터 플랫폼 정리)</title>
      <link>https://hbc3869.tistory.com/237</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: #f8f9fa;
    color: #1a1a1a;
    line-height: 1.7;
    padding: 0;
  }
  .blog-wrap { max-width: 720px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

  .hero { border-left: 4px solid #1D9E75; padding: 0.6rem 0 0.6rem 1.25rem; margin-bottom: 2.5rem; }
  .hero-label { font-size: 11px; font-weight: 700; color: #0F6E56; letter-spacing: 0.09em; text-transform: uppercase; margin-bottom: 6px; }
  .hero-title { font-size: 26px; font-weight: 700; color: #111; line-height: 1.3; margin-bottom: 8px; }
  .hero-sub   { font-size: 14px; color: #555; line-height: 1.7; }

  .section { margin-bottom: 2.2rem; }
  .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 1rem; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8; }
  .section-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
  .section-title { font-size: 17px; font-weight: 700; color: #111; }

  .icon-green  { background: #E1F5EE; }
  .icon-amber  { background: #FAEEDA; }
  .icon-purple { background: #EEEDFE; }
  .icon-blue   { background: #E6F1FB; }
  .icon-coral  { background: #FAECE7; }
  .icon-teal   { background: #E0F4F4; }
  .icon-gray   { background: #F0F0F0; }

  .dot-list { list-style: none; padding: 0; margin: 0; }
  .dot-list li { font-size: 13.5px; color: #444; padding: 3px 0 3px 14px; position: relative; line-height: 1.65; }
  .dot-list li::before { content: &quot;·&quot;; position: absolute; left: 0; color: #1D9E75; font-weight: 700; }
  .dot-list.sm li { font-size: 12.5px; color: #555; }
  .dot-list.sm li::before { color: #aaa; }

  .note        { border-left: 3px solid #1D9E75; background: #E1F5EE; border-radius: 0 8px 8px 0; padding: 11px 15px; margin-top: 12px; font-size: 13px; color: #0F6E56; line-height: 1.65; }
  .note.amber  { border-color: #BA7517;  background: #FAEEDA; color: #7a4d0d; }
  .note.purple { border-color: #7F77DD;  background: #EEEDFE; color: #3C3489; }
  .note.blue   { border-color: #185FA5;  background: #E6F1FB; color: #0d3d6e; }

  .concept-block  { margin-top: 16px; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; }
  .concept-header { background: #f4f4f4; padding: 8px 14px; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.06em; border-bottom: 1px solid #e0e0e0; }
  .concept-item   { padding: 13px 16px; border-bottom: 1px solid #f0f0f0; }
  .concept-item:last-child { border-bottom: none; }
  .concept-term   { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .concept-term span { font-size: 11px; font-weight: 500; color: #888; margin-left: 5px; }
  .concept-ex     { margin-top: 6px; font-size: 11.5px; color: #999; font-style: italic; padding-left: 14px; position: relative; }
  .concept-ex::before { content: &quot;→&quot;; position: absolute; left: 0; }

  .module-block  { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; margin-bottom: 12px; overflow: hidden; }
  .module-header { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid #f0f0f0; background: #fafafa; }
  .module-tag    { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; padding: 3px 10px; border-radius: 5px; }
  .module-name   { font-size: 13px; font-weight: 700; color: #111; }
  .module-body   { padding: 13px 16px; }
  .module-quote  { font-size: 12.5px; color: #888; font-style: italic; margin-bottom: 10px; padding: 6px 10px; background: #f8f9fa; border-radius: 6px; border-left: 2px solid #ddd; }

  .tag-green  { background: #E1F5EE; color: #0F6E56; }
  .tag-amber  { background: #FAEEDA; color: #BA7517; }
  .tag-purple { background: #EEEDFE; color: #534AB7; }
  .tag-blue   { background: #E6F1FB; color: #185FA5; }
  .tag-coral  { background: #FAECE7; color: #993C1D; }
  .tag-teal   { background: #E0F4F4; color: #0D7A7A; }
  .tag-gray   { background: #F0F0F0; color: #444; }

  .flow-row   { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .flow-box   { background: #f4f4f4; border: 1px solid #ddd; border-radius: 8px; padding: 7px 13px; font-size: 12.5px; color: #333; font-weight: 600; }
  .flow-box.hl { background: #E1F5EE; border-color: #1D9E75; color: #0F6E56; }
  .flow-arrow { font-size: 15px; color: #aaa; }

  .flow-step-list { display: flex; flex-direction: column; gap: 0; }
  .flow-step-item { display: flex; gap: 14px; align-items: flex-start; }
  .step-line      { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
  .step-dot       { width: 28px; height: 28px; border-radius: 50%; background: #E1F5EE; border: 2px solid #1D9E75; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #0F6E56; }
  .step-connector { width: 2px; height: 20px; background: #e0e0e0; margin: 3px 0; }
  .step-body      { padding-top: 4px; padding-bottom: 16px; }
  .step-title     { font-size: 13.5px; font-weight: 700; color: #111; margin-bottom: 3px; }
  .step-desc      { font-size: 12.5px; color: #666; line-height: 1.6; }

  .data-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 4px; }
  .data-table th { background: #f4f4f4; padding: 8px 12px; text-align: left; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.04em; border-bottom: 1px solid #e0e0e0; }
  .data-table td { padding: 10px 12px; border-bottom: 1px solid #f0f0f0; font-size: 12.5px; color: #444; vertical-align: top; }
  .data-table tr:last-child td { border-bottom: none; }
  .data-table tr:hover td { background: #fafafa; }

  .card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(155px, 1fr)); gap: 10px; }
  .card       { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; padding: 14px 16px; }
  .card-title { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .card-body  { font-size: 12.5px; color: #555; line-height: 1.7; }

  .pill-row    { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
  .pill        { font-size: 12px; padding: 4px 11px; border-radius: 20px; font-weight: 600; }
  .pill-green  { background: #E1F5EE; color: #0F6E56; }
  .pill-amber  { background: #FAEEDA; color: #BA7517; }
  .pill-purple { background: #EEEDFE; color: #534AB7; }
  .pill-coral  { background: #FAECE7; color: #993C1D; }
  .pill-blue   { background: #E6F1FB; color: #185FA5; }
  .pill-teal   { background: #E0F4F4; color: #0D7A7A; }

  .algo-pill { display: inline-block; font-family: 'Courier New', monospace; font-size: 11.5px; font-weight: 700; padding: 2px 8px; border-radius: 4px; background: #EEEDFE; color: #534AB7; }

  .chip { display: inline-block; background: #f0f0f0; border: 1px solid #ddd; border-radius: 4px; padding: 1px 7px; font-size: 11.5px; font-family: 'Courier New', monospace; color: #555; }

  .divider   { height: 1px; background: #ececec; margin: 2rem 0; }
  .sub-label { font-size: 13px; font-weight: 700; margin-bottom: 8px; color: #333; }
  .sub-green { color: #0F6E56; }
  .sub-coral { color: #993C1D; }

  @media (max-width: 520px) {
    .hero-title  { font-size: 21px; }
    .card-grid   { grid-template-columns: 1fr; }
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;blog-wrap&quot;&gt;

  &lt;div class=&quot;hero&quot;&gt;
    &lt;div class=&quot;hero-label&quot;&gt;bioinformatics · genomics&lt;/div&gt;
    &lt;div class=&quot;hero-title&quot;&gt;TCGA, TCIA, CRDC로 보는 암 유전체 데이터 플랫폼 정리&lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:6px;&quot;&gt;
      &lt;li&gt;NCI(국립암연구소)가 제공하는 분자·영상·임상 데이터 생태계&lt;/li&gt;
      &lt;li&gt;TCGA(분자) · TCIA(영상)를 잇는 Radiogenomics 개념&lt;/li&gt;
      &lt;li&gt;DNA→RNA→단백질→대사체로 이어지는 오믹스 4단계와 CRDC 통합 플랫폼&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt; ️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;1. NCI 개요&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;암 연구 데이터를 누구나 접근할 수 있게&quot; — 미국 NIH 산하 국립암연구소가 운영하는 공개 데이터 생태계&lt;/p&gt;
    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;NIH(National Institutes of Health) 산하 기관인 &lt;strong&gt;NCI(National Cancer Institute)&lt;/strong&gt;가 운영&lt;/li&gt;
      &lt;li&gt;대표 사이트 &lt;span class=&quot;chip&quot;&gt;cancer.gov&lt;/span&gt;를 통해 다양한 암 연구 데이터베이스 제공&lt;/li&gt;
      &lt;li&gt;분자 수준(Micro)부터 영상 수준(Macro)까지 암을 여러 층위에서 데이터화해 연구자에게 개방함&lt;/li&gt;
    &lt;/ul&gt;
    &lt;div class=&quot;note&quot;&gt;이후 섹션에서 다룰 TCGA(분자)·TCIA(영상)·CRDC(통합 플랫폼)가 모두 이 생태계 안에 속해 있음&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-blue&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;2. TCGA vs TCIA — 두 축의 데이터&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;같은 암을 서로 다른 '해상도'로 바라보는 두 데이터베이스&lt;/p&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;div class=&quot;module-tag tag-blue&quot;&gt;TCGA&lt;/div&gt;
        &lt;div class=&quot;module-name&quot;&gt;The Cancer Genome Atlas&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;세포 안에서 무슨 일이 일어나는지를 '문자 서열'로 기록한 데이터&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;분자생물학적·세포적 관점(Micro)의 데이터베이스&lt;/li&gt;
          &lt;li&gt;파일 포맷: &lt;span class=&quot;chip&quot;&gt;FASTQ&lt;/span&gt; &lt;span class=&quot;chip&quot;&gt;BAM&lt;/span&gt; &lt;span class=&quot;chip&quot;&gt;VCF&lt;/span&gt; &lt;span class=&quot;chip&quot;&gt;CSV/TXT&lt;/span&gt;&lt;/li&gt;
          &lt;li&gt;포함 데이터: DNA, RNA, Proteomics, Metabolomics&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;div class=&quot;module-tag tag-coral&quot;&gt;TCIA&lt;/div&gt;
        &lt;div class=&quot;module-name&quot;&gt;The Cancer Imaging Archive&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;몸 전체 또는 조직 수준에서 암이 '어떻게 보이는지'를 이미지로 기록한 데이터&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;형태학적·병리학적 관점(Macro)의 데이터베이스&lt;/li&gt;
          &lt;li&gt;파일 포맷: &lt;span class=&quot;chip&quot;&gt;DICOM&lt;/span&gt; (의료영상 국제 표준 포맷)&lt;/li&gt;
          &lt;li&gt;포함 데이터: MRI, CT, digital histopathology(디지털 병리 슬라이드) 등&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;FASTQ / BAM / VCF &lt;span&gt;Sequencing File Formats&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;FASTQ: 시퀀서가 읽어낸 원본 염기서열 + 품질점수&lt;/li&gt;
          &lt;li&gt;BAM: FASTQ를 참조 유전체에 정렬(align)한 결과&lt;/li&gt;
          &lt;li&gt;VCF: 정렬 결과에서 추출한 변이(variant) 정보만 모은 파일&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ FASTQ(원재료) → BAM(가공) → VCF(핵심 결과물) 순으로 점점 정제됨&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;DICOM &lt;span&gt;Digital Imaging and Communications in Medicine&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;MRI·CT 등 의료영상을 저장·전송하기 위한 국제 표준 포맷&lt;/li&gt;
          &lt;li&gt;영상 데이터 + 촬영 장비·환자 정보 등 메타데이터를 함께 담음&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ 병원마다 장비가 달라도 DICOM 덕분에 영상을 공통 형식으로 주고받을 수 있음&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;3. Radiogenomics — 두 관점을 잇는 다리&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;영상에서 보이는 암의 형태가, 유전자 수준의 어떤 변화와 대응되는가?&quot;&lt;/p&gt;
    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;TCGA(분자 데이터)와 TCIA(영상 데이터)를 연결하는 융합 연구 분야&lt;/li&gt;
      &lt;li&gt;예시: CT 영상에서 종양 경계가 불규칙한 패턴이 특정 유전자 변이와 상관관계를 보이는지 분석&lt;/li&gt;
      &lt;li&gt;의의: 침습적인 생검(biopsy) 없이 영상만으로 분자적 특성을 예측하려는 시도 → '영상 바이오마커' 개발로 이어짐&lt;/li&gt;
    &lt;/ul&gt;
    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;TCGA (분자)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;Radiogenomics&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;TCIA (영상)&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;note purple&quot;&gt;비유: 혈액검사(분자)와 X-ray(영상)를 따로 보지 않고, 두 결과가 서로 어떤 관계인지 함께 분석하는 것과 비슷함&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-coral&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;4. 오믹스(Omics) 4단계&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;분자생물학의 중심원리(Central Dogma): DNA → RNA → 단백질 순으로 유전정보가 흐름 — 각 오믹스는 이 흐름의 서로 다른 단계를 포착하는 스냅샷&lt;/p&gt;

    &lt;div class=&quot;flow-step-list&quot;&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;1&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;DNA — Genomics (유전체)&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;타고난 유전 정보, 돌연변이 존재 여부를 담고 있음 · 대표 기법: WGS(전장유전체시퀀싱), WES(엑솜시퀀싱)&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;2&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;RNA — Transcriptomics (전사체)&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;유전자가 실제로 '발현'되고 있는 정도를 나타내며 BioMarker로 활용됨 · 세포 안팎의 환경 변화나 스트레스, 질병 상태를 반영 · 대표 기법: RNA-seq, microarray&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;3&lt;/div&gt;
          &lt;div class=&quot;step-connector&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;단백질 — Proteomics (단백체)&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;세포 내 공장(리보솜)에서 번역(Translation)되어 만들어진 최종 기능 분자 · 대표 기법: Mass spectrometry(질량분석)&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;flow-step-item&quot;&gt;
        &lt;div class=&quot;step-line&quot;&gt;
          &lt;div class=&quot;step-dot&quot;&gt;4&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;step-body&quot;&gt;
          &lt;div class=&quot;step-title&quot;&gt;대사체 — Metabolomics (대사체)&lt;/div&gt;
          &lt;div class=&quot;step-desc&quot;&gt;포도당·아미노산·지질·젖산 등 대사산물 · 생명체의 '현재 건강 상태'와 '실제 표현형(Phenotype)'을 드러냄 · 대표 기법: NMR, LC-MS&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note&quot;&gt;비유: DNA가 '요리 레시피'라면, RNA는 '지금 만들고 있는 요리의 주문서', 단백질은 '실제 완성된 요리', 대사체는 '그 요리를 먹은 후 몸에 남는 흔적'. DNA는 잘 변하지 않지만 뒤로 갈수록 실시간 변화에 민감해짐&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-teal&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;5. 환자 임상 데이터 — EMR과 HL7 FHIR&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;분자·영상 데이터뿐 아니라 임상 기록도 표준화가 필요함&lt;/p&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;EMR &lt;span&gt;Electronic Medical Record&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;병원에서 관리하는 환자의 진단·처방·검사 이력 등 디지털 기록&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;HL7 FHIR &lt;span&gt;Fast Healthcare Interoperability Resources&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;서로 다른 병원·시스템 간 EMR 데이터를 표준화된 형식으로 주고받기 위한 국제 프로토콜&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ 유전체 데이터가 FASTQ·DICOM으로 표준화되듯, 임상 데이터도 FHIR로 표준화되어야 다기관 연구가 가능해짐&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-amber&quot;&gt; ️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;6. CRDC — 통합 데이터 플랫폼&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;CRDC(Cancer Research Data Commons)는 TCGA·TCIA 등 개별 데이터베이스를 하나의 플랫폼으로 통합해 제공함&lt;/p&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;약어&lt;/th&gt;
          &lt;th&gt;풀네임&lt;/th&gt;
          &lt;th&gt;설명&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;GDC&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;Genomic Data Commons&lt;/td&gt;
          &lt;td&gt;유전체 데이터(TCGA 등) 통합 저장소&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;PDC&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;Proteomic Data Commons&lt;/td&gt;
          &lt;td&gt;단백체 데이터 저장소&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;IDC&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;Imaging Data Commons&lt;/td&gt;
          &lt;td&gt;영상 데이터(TCIA 등) 저장소&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;SB&lt;/span&gt;&lt;/td&gt;
          &lt;td&gt;Seven Bridges (CGC)&lt;/td&gt;
          &lt;td&gt;클라우드 기반 분석 환경 제공 — 데이터를 다운로드하지 않고도 분석 가능&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;

    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:14px;&quot;&gt;
      &lt;li&gt;접근 방법: &lt;strong&gt;Download&lt;/strong&gt;(대용량 파일 직접 다운로드) 또는 &lt;strong&gt;Search&lt;/strong&gt;(조건별 탐색) 기능 제공&lt;/li&gt;
      &lt;li&gt;TCIA 데이터는 별도로 &quot;TCIA Data Retriever&quot; 도구를 통해 다운로드해야 함&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;note amber&quot;&gt;&lt;strong&gt;정정 사항&lt;/strong&gt;&lt;br&gt;· 원본 표에 있던 &quot;GC = Genomic Data Commons&quot; 항목은 GDC와 동일 대상을 가리키는 중복 기재로 판단되어, 위 표에서는 GDC 한 줄로 통합함&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;note&quot;&gt;
    &lt;strong&gt;전체 요약&lt;/strong&gt;&lt;br&gt;
    · TCGA(분자) + TCIA(영상) + EMR(임상) 데이터가 각기 다른 해상도로 암을 기록함&lt;br&gt;
    · Radiogenomics는 분자와 영상 데이터를 잇는 융합 연구 분야&lt;br&gt;
    · DNA→RNA→단백질→대사체 오믹스 4단계는 Central Dogma를 따라 세포 상태를 점점 더 실시간으로 반영함&lt;br&gt;
    · 이 모든 데이터는 CRDC 플랫폼(GDC·PDC·IDC·SB)에서 통합적으로 접근 가능함
  &lt;/div&gt;

&lt;/div&gt;</description>
      <category>머신러닝</category>
      <author>크런키스틱</author>
      <guid isPermaLink="true">https://hbc3869.tistory.com/237</guid>
      <comments>https://hbc3869.tistory.com/237#entry237comment</comments>
      <pubDate>Sat, 11 Jul 2026 04:02:31 +0900</pubDate>
    </item>
    <item>
      <title>260709_강의 정리 (Transformer 구조와 LLM)</title>
      <link>https://hbc3869.tistory.com/236</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: #f8f9fa;
    color: #1a1a1a;
    line-height: 1.7;
    padding: 0;
  }
  .blog-wrap { max-width: 720px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

  .hero { border-left: 4px solid #1D9E75; padding: 0.6rem 0 0.6rem 1.25rem; margin-bottom: 2.5rem; }
  .hero-label { font-size: 11px; font-weight: 700; color: #0F6E56; letter-spacing: 0.09em; text-transform: uppercase; margin-bottom: 6px; }
  .hero-title { font-size: 26px; font-weight: 700; color: #111; line-height: 1.3; margin-bottom: 8px; }
  .hero-sub { font-size: 14px; color: #555; line-height: 1.7; }

  .section { margin-bottom: 2.2rem; }
  .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 1rem; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8; }
  .section-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
  .section-title { font-size: 17px; font-weight: 700; color: #111; }

  .icon-green { background: #E1F5EE; }
  .icon-amber { background: #FAEEDA; }
  .icon-purple { background: #EEEDFE; }
  .icon-blue { background: #E6F1FB; }
  .icon-coral { background: #FAECE7; }
  .icon-teal { background: #E0F4F4; }

  .dot-list { list-style: none; padding: 0; margin: 0; }
  .dot-list li { font-size: 13.5px; color: #444; padding: 3px 0 3px 14px; position: relative; line-height: 1.65; }
  .dot-list li::before { content: &quot;·&quot;; position: absolute; left: 0; color: #1D9E75; font-weight: 700; }
  .dot-list.sm li { font-size: 12.5px; color: #555; }
  .dot-list.sm li::before { color: #aaa; }

  .note { border-left: 3px solid #1D9E75; background: #E1F5EE; border-radius: 0 8px 8px 0; padding: 11px 15px; margin-top: 12px; font-size: 13px; color: #0F6E56; line-height: 1.65; }
  .note.amber { border-color: #BA7517; background: #FAEEDA; color: #7a4d0d; }
  .note.purple { border-color: #7F77DD; background: #EEEDFE; color: #3C3489; }
  .note.blue { border-color: #185FA5; background: #E6F1FB; color: #0d3d6e; }

  .concept-block { margin-top: 16px; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; }
  .concept-header { background: #f4f4f4; padding: 8px 14px; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.06em; border-bottom: 1px solid #e0e0e0; }
  .concept-item { padding: 13px 16px; border-bottom: 1px solid #f0f0f0; }
  .concept-item:last-child { border-bottom: none; }
  .concept-term { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .concept-term span { font-size: 11px; font-weight: 500; color: #888; margin-left: 5px; }
  .concept-ex { margin-top: 6px; font-size: 11.5px; color: #999; font-style: italic; padding-left: 14px; position: relative; }
  .concept-ex::before { content: &quot;→&quot;; position: absolute; left: 0; }

  .module-block { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; margin-bottom: 12px; overflow: hidden; }
  .module-header { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid #f0f0f0; background: #fafafa; }
  .module-tag { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; padding: 3px 10px; border-radius: 5px; }
  .module-name { font-size: 13px; font-weight: 700; color: #111; }
  .module-body { padding: 13px 16px; }
  .module-quote { font-size: 12.5px; color: #888; font-style: italic; margin-bottom: 10px; padding: 6px 10px; background: #f8f9fa; border-radius: 6px; border-left: 2px solid #ddd; }

  .tag-green { background: #E1F5EE; color: #0F6E56; }
  .tag-amber { background: #FAEEDA; color: #BA7517; }
  .tag-purple { background: #EEEDFE; color: #534AB7; }
  .tag-blue { background: #E6F1FB; color: #185FA5; }
  .tag-coral { background: #FAECE7; color: #993C1D; }

  .flow-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .flow-box { background: #f4f4f4; border: 1px solid #ddd; border-radius: 8px; padding: 7px 13px; font-size: 12.5px; color: #333; font-weight: 600; }
  .flow-box.hl { background: #E1F5EE; border-color: #1D9E75; color: #0F6E56; }
  .flow-arrow { font-size: 15px; color: #aaa; }

  .data-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 4px; }
  .data-table th { background: #f4f4f4; padding: 8px 12px; text-align: left; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.04em; border-bottom: 1px solid #e0e0e0; }
  .data-table td { padding: 10px 12px; border-bottom: 1px solid #f0f0f0; font-size: 12.5px; color: #444; vertical-align: top; }
  .data-table tr:last-child td { border-bottom: none; }
  .data-table tr:hover td { background: #fafafa; }

  .algo-pill { display: inline-block; font-family: 'Courier New', monospace; font-size: 11.5px; font-weight: 700; padding: 2px 8px; border-radius: 4px; background: #EEEDFE; color: #534AB7; }
  .chip { display: inline-block; background: #f0f0f0; border: 1px solid #ddd; border-radius: 4px; padding: 1px 7px; font-size: 11.5px; font-family: 'Courier New', monospace; color: #555; }

  .divider { height: 1px; background: #ececec; margin: 2rem 0; }

  @media (max-width: 520px) {
    .hero-title { font-size: 21px; }
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;blog-wrap&quot;&gt;

  &lt;div class=&quot;hero&quot;&gt;
    &lt;div class=&quot;hero-label&quot;&gt;deep learning · llm&lt;/div&gt;
    &lt;div class=&quot;hero-title&quot;&gt;Transformer 구조와 LLM Agent 생태계 정리&lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:6px;&quot;&gt;
      &lt;li&gt;Encoder-only(BERT)와 Decoder-only(GPT) 구조의 차이와 GPT-3의 실제 스케일&lt;/li&gt;
      &lt;li&gt;Agent와 Agentic의 개념 구분, Agent를 구성하는 핵심 요소&lt;/li&gt;
      &lt;li&gt;LangChain · LangGraph · LlamaIndex 3종 프레임워크의 역할 비교&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;1. Transformer 구조 복습 — Encoder vs Decoder&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;같은 Transformer인데 왜 BERT는 이해를 잘하고 GPT는 생성을 잘할까&quot; — 구조를 반쪽만 쓰느냐의 차이임&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;Transformer는 원래 Encoder와 Decoder가 함께 있는 구조로 설계됨&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Encoder-only 모델(BERT)&lt;/strong&gt;: 문장 전체를 양방향으로 한 번에 읽어 문맥을 파악 → 분류, 검색, 임베딩 생성에 강함&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Decoder-only 모델(GPT)&lt;/strong&gt;: 왼쪽에서 오른쪽으로 순차적으로 다음 단어를 예측 → 텍스트 생성에 특화됨&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Encoder / Decoder &lt;span&gt;Encoder / Decoder&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Encoder는 입력을 양방향으로 이해하는 역할, Decoder는 출력을 순차적으로 만들어내는 역할&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;Encoder는 &quot;책 한 권을 다 읽고 이해하는 독자&quot;, Decoder는 &quot;한 글자씩 이어 쓰는 작가&quot;에 비유됨&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;GPT-3의 스케일 &lt;span&gt;d_model, layers, heads&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;파라미터 수: 약 1,750억 개&lt;/li&gt;
          &lt;li&gt;hidden dimension(d_model): 12,288 — 단어 하나가 12,288차원 벡터로 표현됨&lt;/li&gt;
          &lt;li&gt;레이어 수: 96개, attention head: 96개(head당 128차원)&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ d_model = 12,288 은 GPT-3가 각 단어를 얼마나 &quot;풍부한 벡터&quot;로 표현하는지를 나타내는 수치&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note blue&quot;&gt;&lt;strong&gt;정리&lt;/strong&gt;&lt;br&gt;· 같은 Transformer 구조라도 Encoder만 쓰느냐 Decoder만 쓰느냐에 따라 모델의 특기가 갈림&lt;br&gt;· GPT-3의 압도적인 스케일(12,288차원 × 96레이어)이 오늘날 LLM Agent가 가능해진 기반이 됨&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-coral&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;2. LLM Agent란 무엇인가&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;한 번 물어보고 한 번 답하는 것&quot;과 &quot;알아서 계획하고 스스로 고쳐가며 일하는 것&quot;의 차이임&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;&lt;strong&gt;Agent(에이전트)&lt;/strong&gt;: 역할·목표·도구(Tools)를 가지고 스스로 작업을 수행하는 독립적인 소프트웨어 시스템&lt;/li&gt;
      &lt;li&gt;일반 LLM 호출과 달리 &lt;strong&gt;계획 → 실행 → 검토 → 수정&lt;/strong&gt;을 여러 단계에 걸쳐 스스로 반복하는 자율적 프로세스를 가짐&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Agent vs Agentic&lt;/strong&gt;: Agent는 자율 작업을 수행하는 시스템 자체를 가리키고, Agentic은 그 시스템이 &quot;얼마나 자율적으로 계획·판단·행동하는지&quot;의 성질을 가리킴&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Agent의 3요소 &lt;span&gt;Role · Tools · Memory&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Role/Goal — 무엇을, 왜 하는지에 대한 정의&lt;/li&gt;
          &lt;li&gt;Tools — 외부 API, 검색, 코드 실행 등 실제 행동 수단&lt;/li&gt;
          &lt;li&gt;Memory — 이전 상호작용이나 중간 결과를 기억하는 저장소&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ 세 요소가 있어야 Agent가 &quot;한 번의 답변&quot;이 아니라 &quot;여러 단계짜리 작업&quot;을 이어갈 수 있음&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;RAG &lt;span&gt;Retrieval-Augmented Generation&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;LLM이 답변을 만들기 전에 외부 데이터를 먼저 검색하고, 그 내용을 근거로 답을 생성하는 방식&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;→ 시험 볼 때 책을 펼쳐놓고 답을 쓰는 오픈북 방식에 가까움 — LLM이 학습하지 않은 최신 정보나 사내 문서 기반 답변에 필수적&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;계획&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;실행&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;검토&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;수정&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; ️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;3. Agent 프레임워크 3종 비교&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;셋은 경쟁 관계가 아니라 서로 다른 레이어를 담당하는 도구임&lt;/p&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;div class=&quot;module-tag tag-green&quot;&gt;LangChain&lt;/div&gt;
        &lt;div class=&quot;module-name&quot;&gt;범용 Agent 개발 플랫폼&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;&quot;이 모듈이 하는 일을 한 문장으로&quot; — Agent + Tools + Memory + RAG를 자유롭게 조합하는 재료 서랍&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Agent, Tools, Memory, RAG를 자유롭게 조합해 구성 가능&lt;/li&gt;
          &lt;li&gt;커버 범위가 가장 넓은 대신, 복잡한 흐름을 세밀하게 제어하는 기능은 상대적으로 약함&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;div class=&quot;module-tag tag-blue&quot;&gt;LangGraph&lt;/div&gt;
        &lt;div class=&quot;module-name&quot;&gt;상태머신형 Agent 흐름 관리 도구&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;&quot;이 모듈이 하는 일을 한 문장으로&quot; — Agent의 작업 흐름을 그래프로 그려 순서와 반복을 명시적으로 통제&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Graph(노드와 엣지) — 작업 단계를 노드로, 단계 간 연결을 엣지로 표현&lt;/li&gt;
          &lt;li&gt;State(상태 관리) — 단계마다 데이터와 진행 상황을 유지&lt;/li&gt;
          &lt;li&gt;Cycles(순환 루프) — 조건에 따라 이전 단계로 되돌아가는 반복 처리 가능&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;div class=&quot;module-tag tag-purple&quot;&gt;LlamaIndex&lt;/div&gt;
        &lt;div class=&quot;module-name&quot;&gt;RAG 전용 프레임워크&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;&quot;이 모듈이 하는 일을 한 문장으로&quot; — 데이터의 검색·인덱싱에 집중해 RAG 성능을 극대화&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;데이터의 검색, 인덱싱을 통해 RAG 성능 극대화가 목표&lt;/li&gt;
          &lt;li&gt;인덱스 종류: Vector(벡터 유사도), Tree(계층적 요약), Summary(요약 기반), Keyword(키워드 매칭)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;table class=&quot;data-table&quot;&gt;
      &lt;tr&gt;
        &lt;th&gt;구분&lt;/th&gt;
        &lt;th&gt;주 용도&lt;/th&gt;
        &lt;th&gt;강점&lt;/th&gt;
        &lt;th&gt;대표 사용 시점&lt;/th&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;LangChain&lt;/span&gt;&lt;/td&gt;
        &lt;td&gt;Agent 전체 뼈대 구성&lt;/td&gt;
        &lt;td&gt;가장 넓은 범용성, 다양한 조합&lt;/td&gt;
        &lt;td&gt;Agent 시스템을 처음부터 구성할 때&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;LangGraph&lt;/span&gt;&lt;/td&gt;
        &lt;td&gt;작업 흐름 제어&lt;/td&gt;
        &lt;td&gt;분기·반복이 많은 흐름을 명시적으로 관리&lt;/td&gt;
        &lt;td&gt;Agent 로직이 복잡해지고 순환 처리가 필요할 때&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;LlamaIndex&lt;/span&gt;&lt;/td&gt;
        &lt;td&gt;데이터 검색/인덱싱&lt;/td&gt;
        &lt;td&gt;RAG 성능 최적화에 특화&lt;/td&gt;
        &lt;td&gt;외부 문서 기반 검색·질의응답이 핵심일 때&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/table&gt;

    &lt;div class=&quot;note amber&quot;&gt;&lt;strong&gt;선택 기준&lt;/strong&gt;&lt;br&gt;· LangChain은 전체 뼈대, LangGraph는 흐름 제어, LlamaIndex는 데이터 검색 담당으로 함께 조합해서 쓰는 경우가 많음&lt;br&gt;· 단순한 챗봇 수준이면 LangChain만으로 충분하지만, 흐름이 복잡해지면 LangGraph를, 문서 기반 검색이 핵심이면 LlamaIndex를 추가로 결합함&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

&lt;/div&gt;</description>
      <category>머신러닝</category>
      <author>크런키스틱</author>
      <guid isPermaLink="true">https://hbc3869.tistory.com/236</guid>
      <comments>https://hbc3869.tistory.com/236#entry236comment</comments>
      <pubDate>Thu, 9 Jul 2026 17:00:10 +0900</pubDate>
    </item>
    <item>
      <title>260708_강의 정리 (RNN &amp;rarr; LSTM &amp;rarr; Seq2Seq &amp;rarr; NMT &amp;rarr; Self-Attention 정리)</title>
      <link>https://hbc3869.tistory.com/235</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: #f8f9fa;
    color: #1a1a1a;
    line-height: 1.7;
    padding: 0;
  }
  .blog-wrap { max-width: 720px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

  .hero { border-left: 4px solid #1D9E75; padding: 0.6rem 0 0.6rem 1.25rem; margin-bottom: 2.5rem; }
  .hero-label { font-size: 11px; font-weight: 700; color: #0F6E56; letter-spacing: 0.09em; text-transform: uppercase; margin-bottom: 6px; }
  .hero-title { font-size: 26px; font-weight: 700; color: #111; line-height: 1.3; margin-bottom: 8px; }
  .hero-sub   { font-size: 14px; color: #555; line-height: 1.7; }

  .section { margin-bottom: 2.2rem; }
  .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 1rem; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8; }
  .section-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
  .section-title { font-size: 17px; font-weight: 700; color: #111; }

  .icon-green  { background: #E1F5EE; }
  .icon-amber  { background: #FAEEDA; }
  .icon-purple { background: #EEEDFE; }
  .icon-blue   { background: #E6F1FB; }
  .icon-coral  { background: #FAECE7; }
  .icon-teal   { background: #E0F4F4; }
  .icon-gray   { background: #F0F0F0; }

  .dot-list { list-style: none; padding: 0; margin: 0; }
  .dot-list li { font-size: 13.5px; color: #444; padding: 3px 0 3px 14px; position: relative; line-height: 1.65; }
  .dot-list li::before { content: &quot;·&quot;; position: absolute; left: 0; color: #1D9E75; font-weight: 700; }
  .dot-list.sm li { font-size: 12.5px; color: #555; }
  .dot-list.sm li::before { color: #aaa; }

  .note        { border-left: 3px solid #1D9E75; background: #E1F5EE; border-radius: 0 8px 8px 0; padding: 11px 15px; margin-top: 12px; font-size: 13px; color: #0F6E56; line-height: 1.65; }
  .note.amber  { border-color: #BA7517;  background: #FAEEDA; color: #7a4d0d; }
  .note.purple { border-color: #7F77DD;  background: #EEEDFE; color: #3C3489; }
  .note.blue   { border-color: #185FA5;  background: #E6F1FB; color: #0d3d6e; }

  .concept-block  { margin-top: 16px; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; }
  .concept-header { background: #f4f4f4; padding: 8px 14px; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.06em; border-bottom: 1px solid #e0e0e0; }
  .concept-item   { padding: 13px 16px; border-bottom: 1px solid #f0f0f0; }
  .concept-item:last-child { border-bottom: none; }
  .concept-term   { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .concept-term span { font-size: 11px; font-weight: 500; color: #888; margin-left: 5px; }
  .concept-ex     { margin-top: 6px; font-size: 11.5px; color: #999; font-style: italic; padding-left: 14px; position: relative; }
  .concept-ex::before { content: &quot;→&quot;; position: absolute; left: 0; }

  .module-block  { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; margin-bottom: 12px; overflow: hidden; }
  .module-header { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid #f0f0f0; background: #fafafa; }
  .module-tag    { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; padding: 3px 10px; border-radius: 5px; }
  .module-name   { font-size: 13px; font-weight: 700; color: #111; }
  .module-body   { padding: 13px 16px; }
  .module-quote  { font-size: 12.5px; color: #888; font-style: italic; margin-bottom: 10px; padding: 6px 10px; background: #f8f9fa; border-radius: 6px; border-left: 2px solid #ddd; }

  .tag-green  { background: #E1F5EE; color: #0F6E56; }
  .tag-amber  { background: #FAEEDA; color: #BA7517; }
  .tag-purple { background: #EEEDFE; color: #534AB7; }
  .tag-blue   { background: #E6F1FB; color: #185FA5; }
  .tag-coral  { background: #FAECE7; color: #993C1D; }
  .tag-teal   { background: #E0F4F4; color: #0D7A7A; }
  .tag-gray   { background: #F0F0F0; color: #444; }

  .flow-row   { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .flow-box   { background: #f4f4f4; border: 1px solid #ddd; border-radius: 8px; padding: 7px 13px; font-size: 12.5px; color: #333; font-weight: 600; }
  .flow-box.hl { background: #E1F5EE; border-color: #1D9E75; color: #0F6E56; }
  .flow-arrow { font-size: 15px; color: #aaa; }

  .flow-step-list { display: flex; flex-direction: column; gap: 0; }
  .flow-step-item { display: flex; gap: 14px; align-items: flex-start; }
  .step-line      { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
  .step-dot       { width: 28px; height: 28px; border-radius: 50%; background: #E1F5EE; border: 2px solid #1D9E75; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #0F6E56; }
  .step-connector { width: 2px; height: 20px; background: #e0e0e0; margin: 3px 0; }
  .step-body      { padding-top: 4px; padding-bottom: 16px; }
  .step-title     { font-size: 13.5px; font-weight: 700; color: #111; margin-bottom: 3px; }
  .step-desc      { font-size: 12.5px; color: #666; line-height: 1.6; }

  .model-card  { display: flex; align-items: flex-start; gap: 12px; padding: 13px 15px; background: #fff; border: 1px solid #e8e8e8; border-radius: 10px; margin-bottom: 8px; }
  .model-badge { min-width: 64px; height: 25px; border-radius: 5px; display: flex; align-items: center; justify-content: center; font-size: 11.5px; font-weight: 700; flex-shrink: 0; }
  .model-name  { font-size: 13.5px; font-weight: 700; color: #111; margin-bottom: 5px; }

  .feature-list { display: flex; flex-direction: column; gap: 7px; margin-top: 4px; }
  .feature-item { background: #fff; border: 1px solid #e8e8e8; border-radius: 8px; padding: 10px 14px; display: flex; gap: 10px; align-items: flex-start; }
  .feature-tag  { font-family: 'Courier New', monospace; font-size: 11.5px; font-weight: 700; color: #0F6E56; background: #E1F5EE; border-radius: 4px; padding: 2px 8px; flex-shrink: 0; white-space: nowrap; }
  .feature-desc { font-size: 12.5px; color: #444; line-height: 1.6; }
  .feature-desc strong { color: #111; }

  .data-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 4px; }
  .data-table th { background: #f4f4f4; padding: 8px 12px; text-align: left; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.04em; border-bottom: 1px solid #e0e0e0; }
  .data-table td { padding: 10px 12px; border-bottom: 1px solid #f0f0f0; font-size: 12.5px; color: #444; vertical-align: top; }
  .data-table tr:last-child td { border-bottom: none; }
  .data-table tr:hover td { background: #fafafa; }
  .algo-pill { display: inline-block; font-family: 'Courier New', monospace; font-size: 11.5px; font-weight: 700; padding: 2px 8px; border-radius: 4px; background: #EEEDFE; color: #534AB7; }

  .summary-item { display: flex; gap: 12px; padding: 10px 14px; background: #fff; border: 1px solid #e8e8e8; border-radius: 8px; margin-bottom: 7px; align-items: flex-start; }
  .s-key { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; color: #534AB7; min-width: 72px; flex-shrink: 0; padding-top: 1px; }
  .s-val { font-size: 13px; color: #444; line-height: 1.6; }
  .s-val strong { color: #111; }

  .card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(155px, 1fr)); gap: 10px; }
  .card       { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; padding: 14px 16px; }
  .card-title { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .card-body  { font-size: 12.5px; color: #555; line-height: 1.7; }

  .pill-row    { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
  .pill        { font-size: 12px; padding: 4px 11px; border-radius: 20px; font-weight: 600; }
  .pill-green  { background: #E1F5EE; color: #0F6E56; }
  .pill-amber  { background: #FAEEDA; color: #BA7517; }
  .pill-purple { background: #EEEDFE; color: #534AB7; }
  .pill-coral  { background: #FAECE7; color: #993C1D; }
  .pill-blue   { background: #E6F1FB; color: #185FA5; }
  .pill-teal   { background: #E0F4F4; color: #0D7A7A; }

  .chip { display: inline-block; background: #f0f0f0; border: 1px solid #ddd; border-radius: 4px; padding: 1px 7px; font-size: 11.5px; font-family: 'Courier New', monospace; color: #555; }

  .divider   { height: 1px; background: #ececec; margin: 2rem 0; }
  .sub-label { font-size: 13px; font-weight: 700; margin-bottom: 8px; color: #333; }
  .sub-green { color: #0F6E56; }
  .sub-coral { color: #993C1D; }

  @media (max-width: 520px) {
    .hero-title  { font-size: 21px; }
    .card-grid   { grid-template-columns: 1fr; }
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;blog-wrap&quot;&gt;

  &lt;div class=&quot;hero&quot;&gt;
    &lt;div class=&quot;hero-label&quot;&gt;deep learning · sequence models&lt;/div&gt;
    &lt;div class=&quot;hero-title&quot;&gt;RNN → LSTM → Seq2Seq → NMT → Self-Attention 정리&lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:6px;&quot;&gt;
      &lt;li&gt;RNN의 기억력 한계를 LSTM의 게이트 구조로 해결하는 과정&lt;/li&gt;
      &lt;li&gt;Seq2Seq의 context vector 병목을 attention으로 극복하는 흐름&lt;/li&gt;
      &lt;li&gt;NMT attention과 self-attention(Transformer)의 차이점&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;1. RNN Cell과 그 한계&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;하나의 셀이 시간에 따라 정보를 이어받으며 처리하는 것&quot; — 순차 데이터 처리의 기본 구조&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;FFNN(순방향 신경망)에 &lt;strong&gt;내부 피드백(internal feedback)&lt;/strong&gt;을 추가한 구조가 RNN cell임&lt;/li&gt;
      &lt;li&gt;구성 요소 — input(x): 현재 시점 입력값 / hidden(a): 이전 시점 정보를 담은 은닉 상태 / output(y): 현재 시점 출력값&lt;/li&gt;
      &lt;li&gt;하나의 cell은 feedforward network with internal feedback으로 볼 수 있음&lt;/li&gt;
      &lt;li&gt;한계: 시퀀스가 길어질수록 &lt;strong&gt;기울기 소실(vanishing gradient)&lt;/strong&gt; 문제로 먼 과거 정보를 기억하기 어려움&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;내부 피드백 &lt;span&gt;internal feedback&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;이전 시점의 출력이 현재 시점 계산에 다시 사용되는 구조&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;어제 한 말을 기억하면서 오늘 대화를 이어가는 것&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note amber&quot;&gt;&lt;strong&gt;기울기 소실 문제&lt;/strong&gt;&lt;br&gt;· 시퀀스가 길어질수록 초반 정보의 영향력이 점점 희미해짐&lt;br&gt;· 이 문제를 해결하기 위해 LSTM 등장&lt;/div&gt;

    &lt;div class=&quot;sub-label&quot; style=&quot;margin-top:20px;&quot;&gt;RNN의 5가지 입출력 구조&lt;/div&gt;
    &lt;table class=&quot;data-table&quot;&gt;
      &lt;tr&gt;&lt;th&gt;구조&lt;/th&gt;&lt;th&gt;형태&lt;/th&gt;&lt;th&gt;대표 태스크&lt;/th&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;one to one&lt;/span&gt;&lt;/td&gt;&lt;td&gt;입력 1개 → 출력 1개&lt;/td&gt;&lt;td&gt;일반 신경망(FFNN)과 동일&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;one to many&lt;/span&gt;&lt;/td&gt;&lt;td&gt;입력 1개 → 출력 여러 개&lt;/td&gt;&lt;td&gt;이미지 캡셔닝&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;many to one&lt;/span&gt;&lt;/td&gt;&lt;td&gt;입력 여러 개 → 출력 1개&lt;/td&gt;&lt;td&gt;감성 분석, 문서 분류&lt;/td&gt;&lt;/tr&gt;
      &lt;tr&gt;&lt;td&gt;&lt;span class=&quot;algo-pill&quot;&gt;many to many (동기)&lt;/span&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;span class=&quot;algo-pill&quot;&gt;many to many (비동기)&lt;/span&gt;&lt;/td&gt;&lt;td&gt;입력·출력 길이 다름&lt;/td&gt;&lt;td&gt;기계 번역&lt;/td&gt;&lt;/tr&gt;
    &lt;/table&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;2. LSTM (Long Short-Term Memory)&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;RNN의 기억력 문제를 게이트로 해결한 구조&quot; — 장기 의존성을 학습하기 위한 셀 구조&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;RNN은 시퀀스가 길어지면 오래된 정보를 잊어버리는 문제가 있음&lt;/li&gt;
      &lt;li&gt;LSTM은 &lt;strong&gt;cell state(C_t)&lt;/strong&gt;와 3개의 게이트로 정보 흐름을 제어함&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Forget gate &lt;span&gt;f&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;sigmoid 함수 사용, 이전 cell state 중 얼마나 지울지 결정 (0~1)&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;0에 가까우면 완전히 잊음, 1에 가까우면 그대로 유지&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Input gate &lt;span&gt;i&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;sigmoid 함수 사용, 새 정보를 얼마나 반영할지 결정 (0~1)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Candidate gate &lt;span&gt;g&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;tanh 함수 사용, 새로 추가할 후보 값 자체를 생성 (-1~1)&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;i가 &quot;얼마나&quot; 반영할지 정하면, g는 &quot;무엇을&quot; 반영할지 정함&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Output gate &lt;span&gt;o&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;sigmoid 함수 사용, cell state 중 얼마나 hidden state로 내보낼지 결정&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:12px;&quot;&gt;
      &lt;li&gt;&lt;em&gt;→ C_t = f_t * C_(t-1) + i_t * g_t (cell state 업데이트)&lt;/em&gt;&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;→ h_t = o_t * tanh(C_t) (hidden state 출력)&lt;/em&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;note purple&quot;&gt;
      &lt;strong&gt;게이트 요약&lt;/strong&gt;&lt;br&gt;
      · f, i, o는 sigmoid(0~1) — &quot;얼마나&quot;를 결정&lt;br&gt;
      · g는 tanh(-1~1) — &quot;무엇을&quot; 반영할지 결정&lt;br&gt;
      · 네 게이트가 함께 cell state의 장기 기억을 관리함
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-blue&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;3. Seq2Seq (Encoder-Decoder)&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;입력 시퀀스를 하나의 벡터로 압축한 뒤, 그 벡터로 출력 시퀀스를 생성하는 구조&quot; — 번역·요약 등 sequence-to-sequence 태스크의 기본 틀&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;&lt;strong&gt;Encoder&lt;/strong&gt;: 입력 시퀀스를 순차적으로 처리해 마지막 hidden state(=context vector)로 압축&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Decoder&lt;/strong&gt;: context vector를 받아 출력 시퀀스를 한 토큰씩 생성&lt;/li&gt;
      &lt;li&gt;한계: 입력이 길어지면 하나의 고정 크기 context vector에 모든 정보를 담기 어려움&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Context vector&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;encoder의 마지막 hidden state, 입력 시퀀스 전체 정보를 압축한 벡터&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;긴 문장을 한 문장으로 요약해서 통역사에게 전달하는 메모&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note blue&quot;&gt;이 병목을 해결하기 위해 attention 메커니즘이 등장함&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-coral&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;4. NMT (Neural Machine Translation)와 Attention&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;디코더가 매 시점마다 인코더의 모든 정보를 다시 참고하는 것&quot; — 고정된 context vector의 한계를 극복하는 방법&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;NMT(Neural Machine Translation, 신경망 기계 번역): seq2seq 구조 기반 번역 모델&lt;/li&gt;
      &lt;li&gt;기존 seq2seq는 context vector 하나로만 전체 문장을 표현 → 정보 손실 발생&lt;/li&gt;
      &lt;li&gt;Attention 적용 시, decoder가 출력을 생성할 때마다 encoder의 &lt;strong&gt;모든&lt;/strong&gt; hidden state를 다시 참조함&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;div class=&quot;module-tag tag-coral&quot;&gt;flow&lt;/div&gt;
        &lt;div class=&quot;module-name&quot;&gt;Attention 동작 순서&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;decoder가 매 출력마다 encoder를 다시 훑어보는 과정&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;① decoder의 현재 상태와 encoder의 각 hidden state 간 유사도 계산 → attention weight 산출&lt;/li&gt;
          &lt;li&gt;② attention weight로 encoder hidden state들을 가중합 → context vector 생성&lt;/li&gt;
          &lt;li&gt;③ context vector를 이용해 다음 단어 예측&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Attention weight&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;입력의 각 위치가 현재 출력에 얼마나 중요한지를 나타내는 가중치 (합이 1)&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;&quot;Je&quot;를 생성할 때 weight (0.5, 0.3, 0.1, 0.1)로 입력 각 단어를 참조&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;span class=&quot;flow-box&quot;&gt;encoder hidden states&lt;/span&gt;
      &lt;span class=&quot;flow-arrow&quot;&gt;→&lt;/span&gt;
      &lt;span class=&quot;flow-box hl&quot;&gt;attention weight 계산&lt;/span&gt;
      &lt;span class=&quot;flow-arrow&quot;&gt;→&lt;/span&gt;
      &lt;span class=&quot;flow-box&quot;&gt;context vector&lt;/span&gt;
      &lt;span class=&quot;flow-arrow&quot;&gt;→&lt;/span&gt;
      &lt;span class=&quot;flow-box&quot;&gt;decoder 출력&lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;5. Self-Attention&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;같은 문장 안에서 단어끼리 서로 얼마나 관련 있는지 계산하는 것&quot; — Transformer의 핵심 메커니즘&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;NMT attention: &lt;strong&gt;서로 다른 시퀀스&lt;/strong&gt;(encoder ↔ decoder) 간 관계 계산&lt;/li&gt;
      &lt;li&gt;self-attention: &lt;strong&gt;같은 시퀀스 내부&lt;/strong&gt;에서 단어 간 관계 계산&lt;/li&gt;
      &lt;li&gt;Query, Key, Value 세 가지 벡터로 관계를 계산함&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Query&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;현재 기준이 되는 단어가 &quot;무엇을 찾고 있는지&quot;를 나타내는 벡터&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Key&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;각 단어가 &quot;내가 무엇을 갖고 있는지&quot;를 나타내는 벡터, query와의 유사도 계산에 사용&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Value&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;실제로 가중합에 사용되는 정보 벡터&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;도서관에서 검색어(query)로 책 제목(key)을 찾고, 실제 필요한 건 책 내용(value)인 것&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:12px;&quot;&gt;
      &lt;li&gt;① query와 각 key의 유사도로 score 계산&lt;/li&gt;
      &lt;li&gt;② score를 정규화해 가중치 산출&lt;/li&gt;
      &lt;li&gt;③ 가중치로 value들을 가중합(multiplication) → 출력 생성&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;note blue&quot;&gt;
      &lt;strong&gt;NMT attention vs self-attention&lt;/strong&gt;&lt;br&gt;
      · NMT attention → 서로 다른 시퀀스 간 (encoder-decoder)&lt;br&gt;
      · self-attention → 같은 시퀀스 내부&lt;br&gt;
      · 이름은 같지만 목적과 참조 대상이 다름
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-teal&quot;&gt; ️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;6. RNN을 이미지 데이터에 적용하는 예시 (MNIST)&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;이미지를 시퀀스처럼 취급해서 RNN에 입력하는 것&quot; — RNN 활용 예시&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;MNIST 손글씨 숫자 이미지(28×28)를 RNN 입력으로 사용하는 예시&lt;/li&gt;
      &lt;li&gt;이미지의 각 &lt;strong&gt;행(28픽셀)&lt;/strong&gt;을 하나의 timestep 입력으로 취급&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;→ 28×28 이미지 = 28개 timestep × 28차원 벡터 입력&lt;/em&gt;&lt;/li&gt;
      &lt;li&gt;hidden size = 128 (BasicRNNCell의 은닉 차원), batch size = 128 (한 번에 학습하는 이미지 개수)&lt;/li&gt;
      &lt;li&gt;출력: many-to-one 구조로 마지막 timestep의 출력을 one-hot encoding(10, 0~9 숫자 분류)으로 매핑&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;BasicRNNCell&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;TensorFlow/Keras 등에서 제공하는 가장 기본적인 RNN 셀 구현체&lt;/li&gt;
          &lt;li&gt;hidden 차원을 파라미터로 지정해 사용&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note amber&quot;&gt;
      &lt;strong&gt;주의&lt;/strong&gt;&lt;br&gt;
      · hidden size와 batch size는 우연히 같은 숫자(128)일 뿐 다른 개념임&lt;br&gt;
      · 입력 시퀀스 길이(28)는 이미지의 세로 픽셀 수, 벡터 차원(28)은 이미지의 가로 픽셀 수에서 옴
    &lt;/div&gt;
  &lt;/div&gt;

&lt;/div&gt;</description>
      <category>머신러닝</category>
      <author>크런키스틱</author>
      <guid isPermaLink="true">https://hbc3869.tistory.com/235</guid>
      <comments>https://hbc3869.tistory.com/235#entry235comment</comments>
      <pubDate>Wed, 8 Jul 2026 15:41:23 +0900</pubDate>
    </item>
    <item>
      <title>260707_강의 정리 (생성모델 - AE, VAE, GAN)</title>
      <link>https://hbc3869.tistory.com/234</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: #f8f9fa;
    color: #1a1a1a;
    line-height: 1.7;
    padding: 0;
  }
  .blog-wrap { max-width: 720px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

  .hero { border-left: 4px solid #1D9E75; padding: 0.6rem 0 0.6rem 1.25rem; margin-bottom: 2.5rem; }
  .hero-label { font-size: 11px; font-weight: 700; color: #0F6E56; letter-spacing: 0.09em; text-transform: uppercase; margin-bottom: 6px; }
  .hero-title { font-size: 26px; font-weight: 700; color: #111; line-height: 1.3; margin-bottom: 8px; }
  .hero-sub   { font-size: 14px; color: #555; line-height: 1.7; }

  .section { margin-bottom: 2.2rem; }
  .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 1rem; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8; }
  .section-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
  .section-title { font-size: 17px; font-weight: 700; color: #111; }

  .icon-green  { background: #E1F5EE; }
  .icon-amber  { background: #FAEEDA; }
  .icon-purple { background: #EEEDFE; }
  .icon-blue   { background: #E6F1FB; }
  .icon-coral  { background: #FAECE7; }
  .icon-teal   { background: #E0F4F4; }
  .icon-gray   { background: #F0F0F0; }

  .dot-list { list-style: none; padding: 0; margin: 0; }
  .dot-list li { font-size: 13.5px; color: #444; padding: 3px 0 3px 14px; position: relative; line-height: 1.65; }
  .dot-list li::before { content: &quot;·&quot;; position: absolute; left: 0; color: #1D9E75; font-weight: 700; }
  .dot-list.sm li { font-size: 12.5px; color: #555; }
  .dot-list.sm li::before { color: #aaa; }

  .note        { border-left: 3px solid #1D9E75; background: #E1F5EE; border-radius: 0 8px 8px 0; padding: 11px 15px; margin-top: 12px; font-size: 13px; color: #0F6E56; line-height: 1.65; }
  .note.amber  { border-color: #BA7517;  background: #FAEEDA; color: #7a4d0d; }
  .note.purple { border-color: #7F77DD;  background: #EEEDFE; color: #3C3489; }
  .note.blue   { border-color: #185FA5;  background: #E6F1FB; color: #0d3d6e; }
  .note.coral  { border-color: #C1583A;  background: #FAECE7; color: #7a2a13; }
  .note.teal   { border-color: #0D7A7A;  background: #E0F4F4; color: #0D7A7A; }

  .concept-block  { margin-top: 16px; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; }
  .concept-header { background: #f4f4f4; padding: 8px 14px; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.06em; border-bottom: 1px solid #e0e0e0; }
  .concept-item   { padding: 13px 16px; border-bottom: 1px solid #f0f0f0; }
  .concept-item:last-child { border-bottom: none; }
  .concept-term   { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .concept-term span { font-size: 11px; font-weight: 500; color: #888; margin-left: 5px; }
  .concept-ex     { margin-top: 6px; font-size: 11.5px; color: #999; font-style: italic; padding-left: 14px; position: relative; }
  .concept-ex::before { content: &quot;→&quot;; position: absolute; left: 0; }

  .module-block  { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; margin-bottom: 12px; overflow: hidden; }
  .module-header { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid #f0f0f0; background: #fafafa; }
  .module-tag    { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; padding: 3px 10px; border-radius: 5px; }
  .module-name   { font-size: 13px; font-weight: 700; color: #111; }
  .module-body   { padding: 13px 16px; }
  .module-quote  { font-size: 12.5px; color: #888; font-style: italic; margin-bottom: 10px; padding: 6px 10px; background: #f8f9fa; border-radius: 6px; border-left: 2px solid #ddd; }

  .tag-green  { background: #E1F5EE; color: #0F6E56; }
  .tag-amber  { background: #FAEEDA; color: #BA7517; }
  .tag-purple { background: #EEEDFE; color: #534AB7; }
  .tag-blue   { background: #E6F1FB; color: #185FA5; }
  .tag-coral  { background: #FAECE7; color: #993C1D; }
  .tag-teal   { background: #E0F4F4; color: #0D7A7A; }
  .tag-gray   { background: #F0F0F0; color: #444; }

  .flow-row   { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .flow-box   { background: #f4f4f4; border: 1px solid #ddd; border-radius: 8px; padding: 7px 13px; font-size: 12.5px; color: #333; font-weight: 600; }
  .flow-box.hl { background: #E1F5EE; border-color: #1D9E75; color: #0F6E56; }
  .flow-arrow { font-size: 15px; color: #aaa; }

  .divider   { height: 1px; background: #ececec; margin: 2rem 0; }

  .formula-wrap { background: #fff; border: 1px solid #e8e8e8; border-radius: 10px; padding: 14px 16px; margin-top: 12px; }
  .formula-eq { font-size: 14px; color: #111; text-align: center; margin-bottom: 10px; font-family: 'Courier New', monospace; }
  .formula-glossary { font-size: 12px; color: #666; line-height: 1.7; }
  .formula-glossary strong { color: #333; font-family: 'Courier New', monospace; }

  @media (max-width: 520px) {
    .hero-title  { font-size: 21px; }
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;blog-wrap&quot;&gt;

  &lt;div class=&quot;hero&quot;&gt;
    &lt;div class=&quot;hero-label&quot;&gt;deep learning · generative model&lt;/div&gt;
    &lt;div class=&quot;hero-title&quot;&gt;AE, VAE, GAN — 생성 모델의 기초&lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:6px;&quot;&gt;
      &lt;li&gt;지도학습 vs 비지도학습, discriminative vs generative의 근본적 차이&lt;/li&gt;
      &lt;li&gt;AE(압축·복원) → VAE(확률적 잠재공간) → GAN(적대적 학습)으로 이어지는 생성모델 발전&lt;/li&gt;
      &lt;li&gt;잠재변수, KL divergence, upsampling 등 생성모델을 이해하기 위한 핵심 개념&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;1. 지도학습 vs 비지도학습, 그리고 생성모델&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;정답이 있는가 없는가&quot; — 학습 방식을 가르는 가장 근본적인 기준&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;&lt;strong&gt;지도학습&lt;/strong&gt; — 입력-정답(Target) 쌍으로 학습함&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;비지도학습&lt;/strong&gt; — 정답 없이 데이터 자체의 구조를 학습함&lt;/li&gt;
      &lt;li&gt;비지도학습의 목적 — &lt;strong&gt;clustering&lt;/strong&gt;(비슷한 데이터끼리 묶기), &lt;strong&gt;차원 축소/특징 추출&lt;/strong&gt;(핵심 정보만 압축해 후속 작업에 활용)&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;PCA&lt;/strong&gt; — 레이블 없이 데이터의 주요 분산 방향을 찾는 대표적인 비지도학습·차원축소 기법&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Generative vs Discriminative &lt;span&gt;생성 vs 판별&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;Discriminative — 데이터가 주어졌을 때 클래스를 구분함 (P(y|x))&lt;/li&gt;
          &lt;li&gt;Generative — 데이터가 생성되는 과정 자체를 학습해 새 데이터를 만듦 (P(x))&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;분류기는 경계선을 긋고, 생성모델은 데이터 자체를 빚어낸다&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note&quot;&gt;AE, VAE, GAN, RBM은 모두 &quot;데이터를 생성할 수 있는&quot; generative network 계열&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;2. AE (Autoencoder) — 압축과 복원&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;입력을 압축했다가 그대로 복원하도록 학습시켜 핵심 특징만 남기기&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;input → &lt;strong&gt;encode&lt;/strong&gt;(압축) → hidden(병목) → &lt;strong&gt;decode&lt;/strong&gt;(복원) → output&lt;/li&gt;
      &lt;li&gt;hidden layer가 input/output보다 작은 &lt;strong&gt;병목 구조&lt;/strong&gt;라서 데이터의 핵심 정보만 남도록 강제됨&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;잠재변수 &lt;span&gt;latent variable&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;데이터의 본질적 특징을 저차원으로 압축한 표현&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;빙산에서 보이는 부분은 일부고, 본질은 수면 아래(압축된 잠재공간)에 있음&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note purple&quot;&gt;AE는 복원은 잘하지만, 잠재공간이 불연속적이라 &quot;새로운&quot; 데이터를 생성하는 데는 약함&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-blue&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;3. VAE (Variational Autoencoder) — 확률로 압축하기&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;AE와 달리 입력을 하나의 벡터가 아니라 확률분포로 압축함&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;Encoder가 평균(μ)과 표준편차(σ)를 출력함 → 이 분포에서 샘플링: z = μ + εσ&lt;/li&gt;
      &lt;li&gt;Decoder는 샘플링된 z를 입력받아 복원(Recon)함&lt;/li&gt;
      &lt;li&gt;Loss = ReconLoss(복원 오차) + KL divergence(잠재공간을 표준정규분포 N(0,1)에 가깝게 규제)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;KL divergence &lt;span&gt;Kullback-Leibler divergence&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;두 확률분포의 차이를 나타내는 척도임 (거리는 아님 — 비대칭: KL(p‖q) ≠ KL(q‖p))&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;두 분포가 얼마나 다른 모양을 하고 있는지 수치로 나타낸 것&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;formula-wrap&quot;&gt;
      &lt;div class=&quot;formula-eq&quot;&gt;KL(p‖q) = Σ p·log(p) − Σ p·log(q) = −H(p) + H(p,q)&lt;/div&gt;
      &lt;div class=&quot;formula-glossary&quot;&gt;
        &lt;strong&gt;H(p)&lt;/strong&gt; — 분포 p의 엔트로피&lt;br&gt;
        &lt;strong&gt;H(p,q)&lt;/strong&gt; — p와 q 사이의 교차 엔트로피
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note blue&quot;&gt;잠재공간이 매끄러운 확률분포를 이루기 때문에, 학습 후 임의의 z를 샘플링해서 새로운 데이터를 생성할 수 있음 — AE와의 결정적 차이&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-coral&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;4. GAN (Generative Adversarial Network) — 경쟁하며 배우기&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;생성자와 판별자가 서로 속고 속이며 함께 성장하는 구조&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;Noise → &lt;strong&gt;Generator&lt;/strong&gt; → Fake Image 생성&lt;/li&gt;
      &lt;li&gt;Real Image + Fake Image → &lt;strong&gt;Discriminator&lt;/strong&gt; → Real/Fake 판별&lt;/li&gt;
      &lt;li&gt;Generator는 Discriminator를 속이도록, Discriminator는 진짜/가짜를 더 잘 구분하도록 서로 경쟁(적대적 학습)하며 발전함&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;div class=&quot;module-tag tag-coral&quot;&gt;example&lt;/div&gt;
        &lt;div class=&quot;module-name&quot;&gt;특징 연산 (Vector Arithmetic)&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;Man with glasses − Man without glasses + Woman without glasses = Woman with glasses (DCGAN 논문의 대표 실험 결과)&lt;/div&gt;
        &lt;ul class=&quot;dot-list&quot;&gt;
          &lt;li&gt;잠재공간에서 벡터 연산으로 의미 있는 이미지 변형이 가능함&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note coral&quot;&gt;적대적 학습 덕분에 GAN은 AE/VAE보다 훨씬 더 사실적인 이미지를 생성하는 경향이 있음&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-teal&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;5. Upsampling — 작은 걸 다시 키우기&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;Decoder/Generator가 압축된 표현을 다시 원래 크기로 복원하는 방법 중 하나&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;Upsampling에는 max unpooling, transposed convolution, interpolation 등 여러 방법이 있음 (여기서는 max unpooling 예시)&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Max Pooling&lt;/strong&gt; — 영역 내 최댓값만 남기고 나머지는 버림, 이때 최댓값의 &lt;strong&gt;위치를 기억&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Max Unpooling&lt;/strong&gt; — 기억해둔 위치에만 값을 복원하고 나머지는 0으로 채워 원래 크기로 되돌림&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-ex&quot; style=&quot;margin-left:2px;&quot;&gt;pooling에서 기억해둔 위치 정보를 unpooling 때 그대로 활용해 공간 정보를 최대한 보존&lt;/div&gt;

    &lt;div class=&quot;note teal&quot;&gt;Upsampling 방법 선택에 따라 복원된 이미지의 디테일과 학습 난이도가 달라짐&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-gray&quot;&gt; ️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;6. RBM — 초기 생성모델&lt;/div&gt;
    &lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;&lt;strong&gt;RBM(Restricted Boltzmann Machine)&lt;/strong&gt; — AE 이전에 등장한 초기 생성모델 계열&lt;/li&gt;
      &lt;li&gt;오늘날은 AE/VAE/GAN이 더 널리 쓰이지만, 생성모델 발전 계보의 출발점으로 의미가 있음&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-gray&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;정리 — 생성모델의 흐름&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box&quot;&gt;AE (단순 압축·복원)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;VAE (확률적 잠재공간, 생성 능력 획득)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;GAN (적대적 학습, 사실적 생성)&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

&lt;/div&gt;</description>
      <category>머신러닝</category>
      <author>크런키스틱</author>
      <guid isPermaLink="true">https://hbc3869.tistory.com/234</guid>
      <comments>https://hbc3869.tistory.com/234#entry234comment</comments>
      <pubDate>Wed, 8 Jul 2026 15:24:20 +0900</pubDate>
    </item>
    <item>
      <title>260706_강의 정리 (전이학습)</title>
      <link>https://hbc3869.tistory.com/233</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: #f8f9fa;
    color: #1a1a1a;
    line-height: 1.7;
    padding: 0;
  }
  .blog-wrap { max-width: 720px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }

  .hero { border-left: 4px solid #1D9E75; padding: 0.6rem 0 0.6rem 1.25rem; margin-bottom: 2.5rem; }
  .hero-label { font-size: 11px; font-weight: 700; color: #0F6E56; letter-spacing: 0.09em; text-transform: uppercase; margin-bottom: 6px; }
  .hero-title { font-size: 26px; font-weight: 700; color: #111; line-height: 1.3; margin-bottom: 8px; }
  .hero-sub   { font-size: 14px; color: #555; line-height: 1.7; }

  .section { margin-bottom: 2.2rem; }
  .section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 1rem; padding-bottom: 10px; border-bottom: 1px solid #e8e8e8; }
  .section-icon { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; }
  .section-title { font-size: 17px; font-weight: 700; color: #111; }

  .icon-green  { background: #E1F5EE; }
  .icon-amber  { background: #FAEEDA; }
  .icon-purple { background: #EEEDFE; }
  .icon-blue   { background: #E6F1FB; }
  .icon-coral  { background: #FAECE7; }
  .icon-teal   { background: #E0F4F4; }
  .icon-gray   { background: #F0F0F0; }

  .dot-list { list-style: none; padding: 0; margin: 0; }
  .dot-list li { font-size: 13.5px; color: #444; padding: 3px 0 3px 14px; position: relative; line-height: 1.65; }
  .dot-list li::before { content: &quot;·&quot;; position: absolute; left: 0; color: #1D9E75; font-weight: 700; }
  .dot-list.sm li { font-size: 12.5px; color: #555; }
  .dot-list.sm li::before { color: #aaa; }

  .note        { border-left: 3px solid #1D9E75; background: #E1F5EE; border-radius: 0 8px 8px 0; padding: 11px 15px; margin-top: 12px; font-size: 13px; color: #0F6E56; line-height: 1.65; }
  .note.amber  { border-color: #BA7517;  background: #FAEEDA; color: #7a4d0d; }
  .note.purple { border-color: #7F77DD;  background: #EEEDFE; color: #3C3489; }
  .note.blue   { border-color: #185FA5;  background: #E6F1FB; color: #0d3d6e; }
  .note.coral  { border-color: #C1583A;  background: #FAECE7; color: #7a2a13; }

  .concept-block  { margin-top: 16px; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; }
  .concept-header { background: #f4f4f4; padding: 8px 14px; font-size: 11.5px; font-weight: 700; color: #666; letter-spacing: 0.06em; border-bottom: 1px solid #e0e0e0; }
  .concept-item   { padding: 13px 16px; border-bottom: 1px solid #f0f0f0; }
  .concept-item:last-child { border-bottom: none; }
  .concept-term   { font-size: 13px; font-weight: 700; color: #111; margin-bottom: 6px; }
  .concept-term span { font-size: 11px; font-weight: 500; color: #888; margin-left: 5px; }
  .concept-ex     { margin-top: 6px; font-size: 11.5px; color: #999; font-style: italic; padding-left: 14px; position: relative; }
  .concept-ex::before { content: &quot;→&quot;; position: absolute; left: 0; }

  .module-block  { background: #fff; border: 1px solid #e8e8e8; border-radius: 12px; margin-bottom: 12px; overflow: hidden; }
  .module-header { display: flex; align-items: center; gap: 10px; padding: 11px 16px; border-bottom: 1px solid #f0f0f0; background: #fafafa; }
  .module-tag    { font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 700; padding: 3px 10px; border-radius: 5px; }
  .module-name   { font-size: 13px; font-weight: 700; color: #111; }
  .module-body   { padding: 13px 16px; }
  .module-quote  { font-size: 12.5px; color: #888; font-style: italic; margin-bottom: 10px; padding: 6px 10px; background: #f8f9fa; border-radius: 6px; border-left: 2px solid #ddd; }

  .tag-green  { background: #E1F5EE; color: #0F6E56; }
  .tag-amber  { background: #FAEEDA; color: #BA7517; }
  .tag-purple { background: #EEEDFE; color: #534AB7; }
  .tag-blue   { background: #E6F1FB; color: #185FA5; }
  .tag-coral  { background: #FAECE7; color: #993C1D; }
  .tag-teal   { background: #E0F4F4; color: #0D7A7A; }
  .tag-gray   { background: #F0F0F0; color: #444; }

  .flow-row   { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .flow-box   { background: #f4f4f4; border: 1px solid #ddd; border-radius: 8px; padding: 7px 13px; font-size: 12.5px; color: #333; font-weight: 600; }
  .flow-box.hl { background: #E1F5EE; border-color: #1D9E75; color: #0F6E56; }
  .flow-arrow { font-size: 15px; color: #aaa; }

  .divider   { height: 1px; background: #ececec; margin: 2rem 0; }

  .img-wrap { margin: 14px 0; text-align: center; }
  .img-wrap img { max-width: 100%; border-radius: 10px; border: 1px solid #e8e8e8; }
  .img-cap  { font-size: 11.5px; color: #999; margin-top: 6px; }

  @media (max-width: 520px) {
    .hero-title  { font-size: 21px; }
  }
&lt;/style&gt;
&lt;/div&gt;

&lt;div class=&quot;blog-wrap&quot;&gt;

  &lt;div class=&quot;hero&quot;&gt;
    &lt;div class=&quot;hero-label&quot;&gt;deep learning · cnn&lt;/div&gt;
    &lt;div class=&quot;hero-title&quot;&gt;CNN 모델의 발전과 전이학습&lt;/div&gt;
    &lt;ul class=&quot;dot-list&quot; style=&quot;margin-top:6px;&quot;&gt;
      &lt;li&gt;성능 개선의 두 축 — 학습 방식 최적화 vs 네트워크 구조 혁신&lt;/li&gt;
      &lt;li&gt;VGG → ResNet → Inception → Xception/MobileNet → EfficientNet으로 이어지는 발전 흐름&lt;/li&gt;
      &lt;li&gt;전이학습으로 사전학습된 지식을 재사용하는 방법 (fine-tuning, feature-extraction, LoRA)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;1. 전이학습이란&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;이미 학습된 지식을 다른 문제에 재사용하는 것&quot; — 처음부터 다시 배우지 않아도 됨&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;ImageNet 등 대규모 데이터로 미리 학습된 &lt;strong&gt;pre-trained 모델&lt;/strong&gt;을 그대로 활용함&lt;/li&gt;
      &lt;li&gt;데이터가 적거나 학습 시간이 부족할 때 특히 유용함&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Feature-extraction &lt;span&gt;특징 추출 방식&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;pre-trained conv layer는 그대로 고정(freeze)함&lt;/li&gt;
          &lt;li&gt;마지막 분류기 레이어만 새로 학습함&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;이미 완성된 렌즈는 그대로 쓰고 카메라 설정만 바꾸는 것&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Fine-tuning &lt;span&gt;미세 조정&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;일부 또는 전체 레이어를 새 데이터에 맞게 재학습함&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;렌즈까지 새로 조정해서 내 상황에 맞게 다시 맞추는 것&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;LoRA &lt;span&gt;Low-Rank Adaptation&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;전체 가중치 대신 저차원 행렬만 학습해 효율적으로 미세조정함&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;trainable_weights 설정에 따라 학습 범위가 결정됨&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note&quot;&gt;전이학습의 핵심은 &quot;무엇을 얼리고(freeze) 무엇을 학습시킬지&quot; 결정하는 것&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-amber&quot;&gt;⚙️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;2. 학습을 빠르고 정확하게 만드는 기법&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;네트워크 구조를 바꾸지 않고도 학습 자체를 개선하는 방법들&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;&lt;strong&gt;Batch Normalization&lt;/strong&gt; — 레이어마다 입력 분포를 정규화해 학습 안정성과 속도를 높임&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;ReLU&lt;/strong&gt; — 비선형성을 도입하고 gradient vanishing 문제를 완화함&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Optimizer&lt;/strong&gt; — 손실함수를 효율적으로 최소화하는 알고리즘 (SGD, Adam 등)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;note amber&quot;&gt;세 기법 모두 &quot;같은 구조라도 더 빠르고 안정적으로 학습시키기 위한 도구&quot;&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-purple&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;3. VGG-16 — 단순하고 깊게&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;3x3 필터를 반복해서 쌓는 단순한 구조로 깊이를 늘림&lt;/p&gt;

    &lt;div class=&quot;img-wrap&quot;&gt;
      &lt;img src=&quot;이미지1_URL_교체&quot; alt=&quot;VGG-16 네트워크 구조도 — Conv와 Pooling 블록이 반복되는 형태&quot;&gt;
      &lt;div class=&quot;img-cap&quot;&gt;VGG-16 구조 — Conv 블록 + Pooling 반복&lt;/div&gt;
    &lt;/div&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;Conv(3x3) + Pooling 블록을 반복해 깊은 네트워크를 구성함&lt;/li&gt;
      &lt;li&gt;5x5, 7x7 필터 하나 대신 3x3을 여러 겹 쌓으면 같은 수용영역을 더 적은 파라미터로 확보하고, 비선형성도 더 많이 추가됨&lt;/li&gt;
    &lt;/ul&gt;
    &lt;div class=&quot;concept-ex&quot; style=&quot;margin-left:2px;&quot;&gt;3x3 필터 2번 = 5x5 필터 1번과 비슷한 범위를 보되 파라미터는 더 적음&lt;/div&gt;

    &lt;div class=&quot;note purple&quot;&gt;구조는 단순하지만 파라미터 수가 많아 무겁다는 한계가 있음 → 이후 모델들이 이를 개선&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-blue&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;4. ResNet — 깊이의 한계를 넘다&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;왜 네트워크는 깊어질수록 오히려 성능이 나빠질까?&quot;라는 문제에서 출발&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;&lt;strong&gt;Degradation 문제&lt;/strong&gt; — 층이 깊어질수록 vanishing gradient로 학습이 오히려 어려워짐&lt;/li&gt;
      &lt;li&gt;Residual block(skip connection) 도입 → 입력을 그대로 더해줘서(identity) 정보 손실을 막음&lt;/li&gt;
      &lt;li&gt;Resnet-152처럼 매우 깊은 네트워크도 안정적으로 학습 가능해짐&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;img-wrap&quot;&gt;
      &lt;img src=&quot;이미지2_URL_교체&quot; alt=&quot;Residual block 구조도 — weight layer, relu, identity를 더하는 흐름&quot;&gt;
      &lt;div class=&quot;img-cap&quot;&gt;Residual block — F(x) + x&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Residual block &lt;span&gt;잔차 블록&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;F(x) + x 형태로 입력(x)을 그대로 더해줌&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;본채(F(x))를 새로 짓되, 원래 있던 뼈대(x)는 그대로 이어붙이는 것&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note blue&quot;&gt;skip connection 덕분에 &quot;더 깊이 = 더 좋은 성능&quot;이 실제로 성립하게 됨&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-teal&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;5. Inception — 한 층에서 여러 시야로 보기&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;필터 크기를 하나로 고정하지 않고 여러 개를 병렬로 사용함&lt;/p&gt;

    &lt;div class=&quot;img-wrap&quot;&gt;
      &lt;img src=&quot;이미지3_URL_교체&quot; alt=&quot;Inception 모듈 구조도 — 1x1, 3x3, 5x5 conv와 max pooling이 병렬로 배치된 후 concat되는 형태&quot;&gt;
      &lt;div class=&quot;img-cap&quot;&gt;Inception 모듈 기본 개념도&lt;/div&gt;
    &lt;/div&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;1x1, 3x3, 5x5 conv + max pooling을 병렬로 배치한 뒤 결과를 concat함&lt;/li&gt;
      &lt;li&gt;1x1 conv는 단순한 필터가 아니라 &lt;strong&gt;차원 축소(bottleneck)&lt;/strong&gt; 역할을 하며 연산량 절감의 핵심임&lt;/li&gt;
    &lt;/ul&gt;
    &lt;div class=&quot;concept-ex&quot; style=&quot;margin-left:2px;&quot;&gt;그림은 Inception 모듈의 기본 개념도(GoogLeNet 계열)이며, 실제 Inception v4는 여기에 factorized convolution·reduction block이 추가된 구조&lt;/div&gt;

    &lt;div class=&quot;note&quot; style=&quot;border-color:#0D7A7A;background:#E0F4F4;color:#0D7A7A;&quot;&gt;여러 크기의 필터를 동시에 써서 다양한 크기의 패턴을 한 층에서 포착함&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-coral&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;6. Xception &amp;amp; MobileNet — 가볍게 만들기&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;정확도는 유지하면서 연산량을 줄이는 경량화 전략&lt;/p&gt;

    &lt;div class=&quot;module-block&quot;&gt;
      &lt;div class=&quot;module-header&quot;&gt;
        &lt;div class=&quot;module-tag tag-coral&quot;&gt;core&lt;/div&gt;
        &lt;div class=&quot;module-name&quot;&gt;Depthwise Separable Convolution&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class=&quot;module-body&quot;&gt;
        &lt;div class=&quot;module-quote&quot;&gt;하나의 큰 연산을 두 개의 가벼운 연산으로 쪼갠다&lt;/div&gt;
        &lt;ul class=&quot;dot-list&quot;&gt;
          &lt;li&gt;&lt;strong&gt;Depthwise&lt;/strong&gt; — 채널별로 독립적인 공간 필터링을 수행함&lt;/li&gt;
          &lt;li&gt;&lt;strong&gt;Pointwise(1x1)&lt;/strong&gt; — 채널 간 정보를 조합함&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;img-wrap&quot;&gt;
      &lt;img src=&quot;이미지4_URL_교체&quot; alt=&quot;Depthwise convolution과 Pointwise convolution 과정을 보여주는 도식&quot;&gt;
      &lt;div class=&quot;img-cap&quot;&gt;Depthwise + Pointwise convolution 분리 과정&lt;/div&gt;
    &lt;/div&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;목적 — 모바일·임베디드 환경처럼 연산 자원이 제한된 곳에서도 동작 가능하게 함&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;note coral&quot;&gt;일반 conv 대비 연산량이 크게 줄어듦 → 경량 모델의 핵심 아이디어&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-green&quot;&gt;⚖️&lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;7. EfficientNet — 균형 있게 키우기&lt;/div&gt;
    &lt;/div&gt;
    &lt;p style=&quot;font-size:13px;color:#555;margin-bottom:14px;&quot;&gt;&quot;깊이·너비·해상도 중 하나만 키우는 건 비효율적이지 않을까?&quot;라는 질문에서 시작&lt;/p&gt;

    &lt;ul class=&quot;dot-list&quot;&gt;
      &lt;li&gt;기존 방식 — depth, width, resolution 중 하나만 늘리는 unbalanced scaling&lt;/li&gt;
      &lt;li&gt;EfficientNet — 세 가지를 정해진 비율로 동시에 늘리는 &lt;strong&gt;compound scaling&lt;/strong&gt; 제안&lt;/li&gt;
      &lt;li&gt;B0~B7 — compound scaling 계수를 단계적으로 키운 모델 시리즈 (해상도만 다른 것이 아님)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;img-wrap&quot;&gt;
      &lt;img src=&quot;이미지5_URL_교체&quot; alt=&quot;Model Scaling 비교도 — baseline, width scaling, depth scaling, resolution scaling, compound scaling&quot;&gt;
      &lt;div class=&quot;img-cap&quot;&gt;Model Scaling — (a) baseline부터 (e) compound scaling까지&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;concept-block&quot;&gt;
      &lt;div class=&quot;concept-header&quot;&gt;  새 개념&lt;/div&gt;
      &lt;div class=&quot;concept-item&quot;&gt;
        &lt;div class=&quot;concept-term&quot;&gt;Compound scaling &lt;span&gt;복합 스케일링&lt;/span&gt;&lt;/div&gt;
        &lt;ul class=&quot;dot-list sm&quot;&gt;
          &lt;li&gt;depth·width·resolution을 동시에 균형 있게 확장함&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div class=&quot;concept-ex&quot;&gt;사진을 키울 때 가로세로 비율을 유지하며 확대하는 것과 비슷한 원리&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;note&quot;&gt;무작정 크게 만드는 게 아니라 &quot;어떤 비율로 키울 것인가&quot;가 EfficientNet의 핵심 통찰&lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;divider&quot;&gt;&lt;/div&gt;

  &lt;div class=&quot;section&quot;&gt;
    &lt;div class=&quot;section-header&quot;&gt;
      &lt;div class=&quot;section-icon icon-gray&quot;&gt; &lt;/div&gt;
      &lt;div class=&quot;section-title&quot;&gt;정리 — 발전의 흐름&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;flow-row&quot;&gt;
      &lt;div class=&quot;flow-box&quot;&gt;VGG (단순·깊게)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;ResNet (깊이의 한계 해결)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;Inception (효율적 병렬 구조)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box&quot;&gt;Xception/MobileNet (경량화)&lt;/div&gt;
      &lt;div class=&quot;flow-arrow&quot;&gt;→&lt;/div&gt;
      &lt;div class=&quot;flow-box hl&quot;&gt;EfficientNet (균형 스케일링)&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

&lt;/div&gt;</description>
      <category>머신러닝</category>
      <author>크런키스틱</author>
      <guid isPermaLink="true">https://hbc3869.tistory.com/233</guid>
      <comments>https://hbc3869.tistory.com/233#entry233comment</comments>
      <pubDate>Mon, 6 Jul 2026 21:59:40 +0900</pubDate>
    </item>
  </channel>
</rss>