<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>dev-emong.log</title>
    <link>https://dev-emong.tistory.com/</link>
    <description>게임 클라이언트에서 시작해 Spring Boot 백엔드, Flutter 앱, AI 활용까지 &amp;mdash; 직접 만들며 배운 것들을 기록하는 개발 로그</description>
    <language>ko</language>
    <pubDate>Fri, 11 Sep 2026 18:13:51 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>dev-emong</managingEditor>
    <image>
      <title>dev-emong.log</title>
      <url>https://tistory1.daumcdn.net/tistory/8996888/attach/557c3c32ea9149b2b3e8cc65639969e8</url>
      <link>https://dev-emong.tistory.com</link>
    </image>
    <item>
      <title>MCP (Model Context Protocol) 정리</title>
      <link>https://dev-emong.tistory.com/182</link>
      <description>&lt;p&gt;AI 기반 개발을 하다 보면 “AI가 프로젝트를 제대로 이해하지 못한다”는 문제를 자주 겪게 된다.&lt;/p&gt;
&lt;p&gt;이 문제를 해결하기 위해 등장한 개념이 바로 **MCP(Model Context Protocol)**이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. MCP란 무엇인가&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;**MCP(Model Context Protocol)**는&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI 모델이 작업을 수행할 때 필요한 **문맥(Context)을 구조적으로 전달하기 위한 규칙(프로토콜)**이다.&lt;/p&gt;
&lt;p&gt;즉,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AI에게 “지금 이 프로젝트에서 무엇을 기준으로, 어떤 정보로 작업해야 하는지”를 명확하게 전달하는 방법이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;2. 왜 MCP가 필요한가&lt;/h2&gt;
&lt;p&gt;AI는 기본적으로 stateless하게 동작한다.&lt;/p&gt;
&lt;p&gt;즉, 이전 맥락을 완벽하게 기억하지 못한다.&lt;/p&gt;
&lt;p&gt;이로 인해 다음과 같은 문제가 발생한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;프로젝트 구조를 이해하지 못함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;어떤 파일을 수정해야 할지 판단 못함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;코드 스타일이 일관되지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;매번 같은 설명을 반복해야 함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;  MCP는 이 문제를 해결하기 위한 &lt;strong&gt;문맥 전달 표준화 방식&lt;/strong&gt;이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3. MCP의 핵심 개념&lt;/h2&gt;
&lt;h3&gt;3-1. Context (문맥)&lt;/h3&gt;
&lt;p&gt;AI가 작업할 때 참고해야 하는 모든 정보&lt;/p&gt;
&lt;p&gt;예시:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;프로젝트 구조&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;코드 규칙&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;현재 작업 목표&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;기존 코드 스타일&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;  MCP는 이 Context를 “정형화해서 전달”한다&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;3-2. Protocol (규칙)&lt;/h3&gt;
&lt;p&gt;Context를 어떻게 전달할지에 대한 규칙&lt;/p&gt;
&lt;p&gt;즉:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;어떤 형식으로 전달할지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;어떤 순서로 전달할지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;어떤 정보까지 포함할지&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;  이걸 표준화한 것이 MCP&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;4. MCP 구조&lt;/h2&gt;
&lt;p&gt;MCP는 보통 다음과 같은 구조로 구성된다.&lt;/p&gt;
&lt;h3&gt;4-1. System Context&lt;/h3&gt;
&lt;p&gt;AI의 기본 행동 규칙&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;코드 스타일&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;금지 사항&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;설계 철학&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;예:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;“DTO는 팩토리 메서드로 생성한다”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“서비스는 비즈니스 로직만 담당한다”&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;4-2. Project Context&lt;/h3&gt;
&lt;p&gt;프로젝트 자체 정보&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;디렉토리 구조&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;주요 모듈 역할&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;기술 스택&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;4-3. Task Context&lt;/h3&gt;
&lt;p&gt;현재 수행할 작업&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;무엇을 만들 것인지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;어떤 문제를 해결할 것인지&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;4-4. Memory Context (선택)&lt;/h3&gt;
&lt;p&gt;이전 작업 기록&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;이전 결정 사항&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;과거 트러블슈팅&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;반복되는 패턴&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;5. MCP를 사용하는 이유 (핵심 장점)&lt;/h2&gt;
&lt;h3&gt;5-1. AI의 이해도 상승&lt;/h3&gt;
&lt;p&gt;AI가 프로젝트를 “처음 보는 코드”가 아니라&lt;/p&gt;
&lt;p&gt;“이미 알고 있는 코드”처럼 처리하게 된다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;5-2. 코드 일관성 유지&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;스타일 통일&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;구조 유지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;규칙 준수&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;5-3. 반복 작업 감소&lt;/h3&gt;
&lt;p&gt;매번 설명할 필요 없이&lt;/p&gt;
&lt;p&gt;MCP만 제공하면 된다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;5-4. 협업 효율 증가&lt;/h3&gt;
&lt;p&gt;팀원 + AI가 같은 기준으로 작업 가능&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;6. MCP vs 그냥 AI 사용&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;일반 AI 사용&lt;/th&gt;
&lt;th&gt;MCP 사용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;문맥 전달&lt;/td&gt;
&lt;td&gt;매번 직접 설명&lt;/td&gt;
&lt;td&gt;구조화된 전달&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일관성&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;td&gt;높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;생산성&lt;/td&gt;
&lt;td&gt;중간&lt;/td&gt;
&lt;td&gt;높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;유지보수&lt;/td&gt;
&lt;td&gt;어려움&lt;/td&gt;
&lt;td&gt;쉬움&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;7. MCP 적용 방식&lt;/h2&gt;
&lt;h3&gt;7-1. 문서 기반 MCP&lt;/h3&gt;
&lt;p&gt;예:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;/docs
 ├─ rules.md
 ├─ architecture.md
 ├─ context.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;AI에게 이 문서를 기반으로 작업하도록 지시&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;7-2. 자동 생성 MCP&lt;/h3&gt;
&lt;p&gt;대표적인 방식:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;프로젝트 분석 → context 문서 자동 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;  예: DeepInit 같은 방식&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;7-3. 프롬프트 기반 MCP&lt;/h3&gt;
&lt;p&gt;프롬프트에 직접 포함&lt;/p&gt;
&lt;p&gt;예:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;[Project Context]
- Spring Boot 기반 프로젝트
- DTO는 팩토리 메서드 사용

[Task]
- 로그인 API 구현
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;8. MCP를 잘 쓰는 방법 (실전 팁)&lt;/h2&gt;
&lt;h3&gt;8-1. 규칙을 먼저 정의한다&lt;/h3&gt;
&lt;p&gt;AI보다 먼저 “팀 기준”이 있어야 한다&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;8-2. 문맥을 작게 쪼갠다&lt;/h3&gt;
&lt;p&gt;한 번에 다 넣지 말고&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;규칙&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;구조&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;작업&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;  분리해서 관리&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;8-3. 자동화한다&lt;/h3&gt;
&lt;p&gt;수동으로 넣으면 결국 안 쓰게 된다&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;8-4. 지속적으로 업데이트한다&lt;/h3&gt;
&lt;p&gt;MCP는 “정적인 문서”가 아니라&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;프로젝트와 함께 성장하는 구조&lt;/strong&gt;다&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;9. 한줄 정리&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;MCP는 AI에게 프로젝트의 “맥락(Context)”을 구조적으로 전달하기 위한 표준화된 방식이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;10. 결론&lt;/h2&gt;
&lt;p&gt;AI를 제대로 활용한 개발을 하려면&lt;/p&gt;
&lt;p&gt;단순히 “코드를 요청하는 것”에서 끝나면 안 된다.&lt;/p&gt;
&lt;p&gt;중요한 건&lt;/p&gt;
&lt;p&gt;  &lt;strong&gt;AI가 이해할 수 있는 형태로 문맥을 설계하는 것&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그리고 그 설계가 바로 &lt;strong&gt;MCP&lt;/strong&gt;다.&lt;/p&gt;</description>
      <author>dev-emong</author>
      <guid isPermaLink="true">https://dev-emong.tistory.com/182</guid>
      <comments>https://dev-emong.tistory.com/182#entry182comment</comments>
      <pubDate>Fri, 11 Sep 2026 10:23:12 +0900</pubDate>
    </item>
    <item>
      <title>JavaScript DOM 요소 선택 메서드 정리</title>
      <link>https://dev-emong.tistory.com/181</link>
      <description>&lt;p&gt;웹 페이지에서 &lt;strong&gt;HTML 요소(DOM)를 선택&lt;/strong&gt;하는 것은 자바스크립트의 가장 기본이자 중요한 기능이다.&lt;/p&gt;
&lt;p&gt;이번 예제에서는 자주 사용하는 DOM 선택 메서드들을 직접 버튼으로 테스트해본다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;1. 예제 목적&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;다양한 DOM 선택 방식 이해&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;단일 요소 vs 여러 요소 선택 차이&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;선택한 요소의 텍스트를 읽어 화면에 출력하기&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;2. 사용된 HTML 구조&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;divid=&amp;quot;myId&amp;quot;class=&amp;quot;box&amp;quot;&amp;gt;ID: myId인 요소&amp;lt;/div&amp;gt;
&amp;lt;divclass=&amp;quot;myClass box&amp;quot;&amp;gt;클래스: myClass인 요소 1&amp;lt;/div&amp;gt;
&amp;lt;divclass=&amp;quot;myClass box&amp;quot;&amp;gt;클래스: myClass인 요소 2&amp;lt;/div&amp;gt;
&amp;lt;divclass=&amp;quot;myClass box&amp;quot;&amp;gt;클래스: myClass인 요소 3&amp;lt;/div&amp;gt;
&amp;lt;pclass=&amp;quot;box&amp;quot;&amp;gt;태그: p인 요소&amp;lt;/p&amp;gt;

&amp;lt;divid=&amp;quot;result&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3&gt;3. 결과 출력 영역&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let resultdom =document.getElementById(&amp;quot;result&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;선택한 DOM 요소의 텍스트를 이 영역에 출력한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;4. DOM 선택 방식 정리&lt;/h3&gt;
&lt;h4&gt;① getElementById / querySelector (ID 선택)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let dom1 =document.querySelector(&amp;quot;#myId&amp;quot;);
resultdom.innerHTML = dom1.innerHTML;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ID는 하나만 선택&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;가장 빠르고 명확한 방식&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;② querySelector (CSS 선택자 방식)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let dom2 =document.querySelector(&amp;quot;#myId&amp;quot;);
resultdom.innerHTML = dom2.innerHTML;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;CSS 선택자 그대로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;첫 번째 요소만 반환&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;③ querySelectorAll (여러 개 선택)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let domlist =document.querySelectorAll(&amp;quot;.myClass&amp;quot;);

let text =&amp;quot;&amp;quot;;
for (let eof domlist) {
  text += e.innerHTML +&amp;quot;&amp;lt;br /&amp;gt;&amp;quot;;
}

resultdom.innerHTML = text;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;여러 개 요소 반환 (&lt;code&gt;NodeList&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;반복문으로 처리 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;④ getElementsByClassName 스타일 (예제에서는 querySelectorAll 사용)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let domlist =document.querySelectorAll(&amp;quot;.box&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;특정 클래스 전체 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;⑤ getElementsByTagName 스타일 (태그 선택)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let domList =document.querySelectorAll(&amp;quot;p&amp;quot;);

let text =&amp;quot;&amp;quot;;
for (let eof domList) {
  text += e.innerHTML +&amp;quot;&amp;lt;br /&amp;gt;&amp;quot;;
}

resultdom.innerHTML = text;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;특정 태그 전체 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;5. 메서드 비교 요약&lt;/h3&gt;
&lt;table&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;getElementById&lt;/td&gt;
&lt;td&gt;단일 요소&lt;/td&gt;
&lt;td&gt;가장 빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;querySelector&lt;/td&gt;
&lt;td&gt;단일 요소&lt;/td&gt;
&lt;td&gt;CSS 선택자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;querySelectorAll&lt;/td&gt;
&lt;td&gt;여러 요소&lt;/td&gt;
&lt;td&gt;NodeList&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;getElementsByClassName&lt;/td&gt;
&lt;td&gt;여러 요소&lt;/td&gt;
&lt;td&gt;HTMLCollection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;getElementsByTagName&lt;/td&gt;
&lt;td&gt;여러 요소&lt;/td&gt;
&lt;td&gt;HTMLCollection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h3&gt;6. 핵심 정리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;하나만 찾을 때&lt;/strong&gt; → &lt;code&gt;getElementById&lt;/code&gt;, &lt;code&gt;querySelector&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;여러 개 찾을 때&lt;/strong&gt; → &lt;code&gt;querySelectorAll&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;최신 개발에서는 &lt;code&gt;querySelector&lt;/code&gt;, &lt;code&gt;querySelectorAll&lt;/code&gt; 사용이 가장 일반적&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;반복문으로 요소들의 내용을 쉽게 조작 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>웹 기초</category>
      <author>dev-emong</author>
      <guid isPermaLink="true">https://dev-emong.tistory.com/181</guid>
      <comments>https://dev-emong.tistory.com/181#entry181comment</comments>
      <pubDate>Fri, 11 Sep 2026 10:22:26 +0900</pubDate>
    </item>
    <item>
      <title>트랜잭션 ACID 4가지 성질 정리</title>
      <link>https://dev-emong.tistory.com/180</link>
      <description>&lt;h3&gt;1️⃣ Atomicity (원자성)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;“모두 성공하거나, 모두 실패한다”&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;트랜잭션 내부의 작업은 &lt;strong&gt;쪼개질 수 없는 하나의 단위&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;중간 상태는 절대 DB에 남지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;예시&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;START TRANSACTION;
INSERT INTO orders (...);
UPDATE productSET stock= stock-1;
-- 여기서 오류 발생
ROLLBACK;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;➡ &lt;code&gt;orders&lt;/code&gt;도 취소, &lt;code&gt;stock&lt;/code&gt;도 원래대로&lt;/p&gt;
&lt;h4&gt;핵심 포인트&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;실패 시 &lt;strong&gt;Undo Log&lt;/strong&gt;를 이용해 복구&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;부분 성공 ❌&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;2️⃣ Consistency (일관성)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;“트랜잭션 전후로 데이터 규칙이 유지된다”&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;트랜잭션 전과 후의 DB 상태는 &lt;strong&gt;항상 유효&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;무효한 데이터 상태로 끝나면 안 됨&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;예시&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;재고(stock)는 음수가 될 수 없음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;외래키(FK)는 반드시 존재해야 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NOT NULL, UNIQUE 제약 유지&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;UPDATE productSET stock=-5;-- ❌
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;➡ 제약 조건 위반 → 트랜잭션 실패&lt;/p&gt;
&lt;h4&gt;핵심 포인트&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;비즈니스 규칙 + DB 제약조건&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;COMMIT되면 항상 “말이 되는 상태”&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;3️⃣ Isolation (격리성)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;“동시에 실행돼도 혼자 실행된 것처럼 보인다”&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;여러 트랜잭션이 동시에 실행돼도&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;서로의 중간 결과를 침범하지 않음&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;예시&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A 트랜잭션이 재고 감소 중&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;B 트랜잭션이 같은 상품 조회&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;➡ B는 &lt;strong&gt;정해진 격리 수준에 맞는 데이터만&lt;/strong&gt; 본다&lt;/p&gt;
&lt;h4&gt;대표적인 문제&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&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;Dirty Read&lt;/td&gt;
&lt;td&gt;커밋 안 된 데이터 읽음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-repeatable Read&lt;/td&gt;
&lt;td&gt;같은 쿼리 결과가 달라짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phantom Read&lt;/td&gt;
&lt;td&gt;갑자기 행이 생김&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;➡ 이를 제어하기 위해 &lt;strong&gt;격리 수준(Isolation Level)&lt;/strong&gt; 존재&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;4️⃣ Durability (지속성)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;“COMMIT되면 절대 사라지지 않는다”&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;COMMIT 완료 후&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DB 서버 다운&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;전원 꺼짐&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;장애 발생&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;➡ 데이터는 반드시 보존됨&lt;/p&gt;
&lt;h4&gt;어떻게 보장하나?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redo Log (WAL)&lt;/strong&gt; 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;디스크에 먼저 기록 → COMMIT&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;핵심 포인트&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;메모리가 아닌 &lt;strong&gt;디스크 기준&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;COMMIT은 “안전 저장 완료” 선언&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;  ACID 한 줄 요약&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&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;Atomicity&lt;/td&gt;
&lt;td&gt;전부 성공 / 전부 실패&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Consistency&lt;/td&gt;
&lt;td&gt;규칙을 깨지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Isolation&lt;/td&gt;
&lt;td&gt;혼자 실행된 것처럼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Durability&lt;/td&gt;
&lt;td&gt;커밋되면 영원히&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h3&gt;  정리&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;트랜잭션의 ACID는&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;원자성(전부 or 실패)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;일관성(규칙 유지)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;격리성(동시성 보호)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;지속성(커밋 보존)을 의미하며&lt;/p&gt;
&lt;p&gt;이를 통해 데이터의 신뢰성과 안정성을 보장합니다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>데이터베이스</category>
      <author>dev-emong</author>
      <guid isPermaLink="true">https://dev-emong.tistory.com/180</guid>
      <comments>https://dev-emong.tistory.com/180#entry180comment</comments>
      <pubDate>Fri, 11 Sep 2026 10:21:34 +0900</pubDate>
    </item>
    <item>
      <title>UI 구조 패턴과 이벤트 성능 최적화 기법 정리</title>
      <link>https://dev-emong.tistory.com/179</link>
      <description>&lt;p&gt;UI(User Interface)는 단순히 화면을 그리는 요소가 아니라&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;사용자 입력 처리, 데이터 표시, 상태 변화 관리&lt;/strong&gt;까지 포함하는 중요한 시스템이다.&lt;/p&gt;
&lt;p&gt;UI가 복잡해질수록 다음과 같은 문제가 발생한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;코드가 뒤섞임&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;유지보수 어려움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;성능 저하&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이벤트 관리 복잡&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 문제를 해결하기 위해 UI 시스템에서는 여러 &lt;strong&gt;구성 기법&lt;/strong&gt;을 사용한다.&lt;/p&gt;
&lt;p&gt;대표적으로 다음 세 가지 영역으로 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;1️⃣ UI 구조 패턴&lt;/p&gt;
&lt;p&gt;2️⃣ UI 이벤트 시스템&lt;/p&gt;
&lt;p&gt;3️⃣ UI 성능 최적화&lt;/p&gt;
&lt;p&gt;이 글에서는 이 세 가지를 중심으로 UI 구성 기법을 정리한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. UI 구조 패턴 (Architecture Pattern)&lt;/h2&gt;
&lt;p&gt;UI 구조 패턴은&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;UI 코드와 로직을 어떻게 분리할 것인가&lt;/strong&gt;에 대한 설계 방식이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;대표적인 패턴은 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;MVC&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MVP&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MVVM&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;MVC (Model - View - Controller)&lt;/h3&gt;
&lt;h4&gt;개념&lt;/h4&gt;
&lt;p&gt;MVC는 UI 구조 패턴 중 가장 오래되고 기본적인 패턴이다.&lt;/p&gt;
&lt;p&gt;구성 요소는 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Model&lt;/strong&gt; : 데이터 및 비즈니스 로직&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;View&lt;/strong&gt; : 사용자에게 보여지는 UI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Controller&lt;/strong&gt; : 사용자 입력 처리 및 흐름 제어&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;구조&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;User Input
    ↓
  View
    ↓
Controller
    ↓
  Model
    ↓
 View Update
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4&gt;특징&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;구조가 단순하다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이해하기 쉽다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;작은 프로젝트에 적합&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;하지만 프로젝트가 커지면&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Controller가 비대해지는 문제&lt;/strong&gt;가 발생할 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;MVP (Model - View - Presenter)&lt;/h3&gt;
&lt;h4&gt;개념&lt;/h4&gt;
&lt;p&gt;MVP는 MVC의 단점을 개선하기 위해 등장한 패턴이다.&lt;/p&gt;
&lt;p&gt;구성 요소&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Model&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;View&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Presenter&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;구조&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;User Input
    ↓
  View
    ↓
Presenter
    ↓
 Model
    ↓
Presenter
    ↓
  View
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4&gt;특징&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;View는 최대한 수동적으로 동작&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Presenter가 화면 로직을 담당&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;테스트하기 쉬운 구조&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;하지만&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter가 커지기 쉽다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;MVVM (Model - View - ViewModel)&lt;/h3&gt;
&lt;h4&gt;개념&lt;/h4&gt;
&lt;p&gt;MVVM은 &lt;strong&gt;데이터 바인딩 기반 UI 패턴&lt;/strong&gt;이다.&lt;/p&gt;
&lt;p&gt;구성 요소&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Model&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;View&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ViewModel&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;구조&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;View ↔ ViewModel ↔ Model
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4&gt;특징&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;ViewModel이 UI 상태 관리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;데이터 바인딩으로 자동 UI 업데이트&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;대규모 UI에 적합&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;대표 사용 환경&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;WPF&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flutter&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Android&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;2. UI 트리 구조 (UI Tree / Widget Tree)&lt;/h2&gt;
&lt;p&gt;대부분의 UI 시스템은&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;UI 요소를 트리 구조로 관리한다.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;즉 UI는 부모-자식 관계로 구성된다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;예시&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;Screen
 ├─ Header
 ├─ Panel
 │   ├─ Button
 │   └─ Text
 └─ Footer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 구조를 &lt;strong&gt;UI Tree&lt;/strong&gt; 또는 &lt;strong&gt;Widget Tree&lt;/strong&gt;라고 한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;특징&lt;/h3&gt;
&lt;h4&gt;부모 - 자식 구조&lt;/h4&gt;
&lt;p&gt;UI 요소는 서로 계층 관계를 가진다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;레이아웃 관리&lt;/h4&gt;
&lt;p&gt;부모 UI가 자식 UI의&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;위치&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;크기&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;정렬&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;을 관리한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;렌더링 순서&lt;/h4&gt;
&lt;p&gt;UI는 보통 &lt;strong&gt;트리 순서대로 그려진다.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Composite Pattern&lt;/h3&gt;
&lt;p&gt;UI 트리는 보통 &lt;strong&gt;Composite Pattern&lt;/strong&gt; 기반이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;UIElement
 ├─ Button
 ├─ Text
 └─ Panel
      ├─ Button
      └─ Text
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Panel도 UIElement이고&lt;/p&gt;
&lt;p&gt;Button도 UIElement이다.&lt;/p&gt;
&lt;p&gt;즉 &lt;strong&gt;개별 요소와 그룹을 동일하게 처리&lt;/strong&gt;할 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3. UI 이벤트 시스템&lt;/h2&gt;
&lt;p&gt;UI는 단순히 보여주는 것뿐 아니라&lt;/p&gt;
&lt;p&gt;사용자 입력을 처리해야 한다.&lt;/p&gt;
&lt;p&gt;이때 중요한 개념이 **이벤트 전파(Event Propagation)**이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;이벤트 버블링 (Event Bubbling)&lt;/h3&gt;
&lt;p&gt;이벤트 버블링은&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;자식 UI에서 발생한 이벤트가 부모 UI로 전달되는 구조&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;구조&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;Screen
 └─ Panel
     └─ Button
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Button 클릭 시&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;Button
 ↓
Panel
 ↓
Screen
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;순서로 이벤트가 전달된다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;이벤트 버블링 장점&lt;/h3&gt;
&lt;h4&gt;이벤트 위임 가능&lt;/h4&gt;
&lt;p&gt;부모 UI 하나만으로&lt;/p&gt;
&lt;p&gt;여러 자식 이벤트를 처리할 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;코드 단순화&lt;/h4&gt;
&lt;p&gt;UI 요소마다 이벤트를 등록할 필요가 없다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;성능 개선&lt;/h4&gt;
&lt;p&gt;이벤트 리스너 수 감소&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;4. UI 성능 최적화&lt;/h2&gt;
&lt;p&gt;UI 시스템에서는 성능 최적화도 매우 중요하다.&lt;/p&gt;
&lt;p&gt;특히 다음과 같은 비용이 발생한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;객체 생성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UI 업데이트&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;레이아웃 계산&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;렌더링&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이를 해결하기 위한 대표적인 기법이&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Object Pool&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dirty Update&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Object Pool&lt;/h2&gt;
&lt;h3&gt;개념&lt;/h3&gt;
&lt;p&gt;Object Pool은&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;객체를 새로 생성하지 않고 재사용하는 방식&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;기존 방식&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;Create
Destroy
Create
Destroy
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4&gt;Object Pool 방식&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;Pool 생성
↓
객체 가져오기
↓
사용
↓
비활성화
↓
Pool 반환
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4&gt;사용 예&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;채팅 메시지 UI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;아이템 슬롯 UI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;알림 UI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;리스트 UI&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;장점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;객체 생성 비용 감소&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GC 감소&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;안정적인 프레임 유지&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Dirty Update&lt;/h2&gt;
&lt;h3&gt;개념&lt;/h3&gt;
&lt;p&gt;Dirty Update는&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;변경된 UI만 업데이트하는 방식&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;예시&lt;/h4&gt;
&lt;p&gt;UI 구조&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;Screen
 ├─ Header
 ├─ Inventory
 └─ Footer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inventory만 변경되면&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;Inventory만 업데이트
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;Dirty Flag&lt;/h4&gt;
&lt;p&gt;UI가 변경되면&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;dirty = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;표시가 되고&lt;/p&gt;
&lt;p&gt;렌더링 단계에서&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;dirty UI만 업데이트
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;된다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;장점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;불필요한 UI 계산 감소&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;렌더링 성능 향상&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;대규모 UI에 유리&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;5. UI 구성 기법 전체 구조&lt;/h2&gt;
&lt;p&gt;지금까지 설명한 UI 구성 기법을 정리하면 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;UI 시스템

├─ UI 구조 패턴
│   ├─ MVC
│   ├─ MVP
│   └─ MVVM
│
├─ UI 구조
│   └─ UI Tree / Widget Tree
│
├─ UI 이벤트 시스템
│   └─ Event Bubbling
│
└─ UI 성능 최적화
    ├─ Object Pool
    └─ Dirty Update
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;핵심 요약&lt;/h2&gt;
&lt;p&gt;UI 구성 기법은 크게 세 가지 영역으로 나눌 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;UI 구조&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;MVC&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MVP&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MVVM&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;UI 코드와 로직을 분리하는 설계 방식&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;UI 구조 관리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;UI Tree&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Composite Pattern&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;UI 요소를 계층 구조로 관리&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;UI 이벤트 시스템&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Event Bubbling&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이벤트를 트리를 따라 전달&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;UI 성능 최적화&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Object Pool&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dirty Update&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;UI 성능을 개선하는 기법&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;UI 시스템은 단순히 화면을 만드는 기술이 아니라&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;구조 설계&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이벤트 처리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;성능 최적화&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;까지 포함된 하나의 &lt;strong&gt;종합적인 시스템 설계 영역&lt;/strong&gt;이다.&lt;/p&gt;
&lt;p&gt;UI가 복잡해질수록&lt;/p&gt;
&lt;p&gt;이러한 구성 기법들을 적절히 활용해야&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;유지보수성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;확장성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;성능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;을 모두 확보할 수 있다.&lt;/p&gt;</description>
      <category>개발기법&amp;middot;CS</category>
      <author>dev-emong</author>
      <guid isPermaLink="true">https://dev-emong.tistory.com/179</guid>
      <comments>https://dev-emong.tistory.com/179#entry179comment</comments>
      <pubDate>Fri, 11 Sep 2026 10:20:40 +0900</pubDate>
    </item>
    <item>
      <title>Ubuntu에서 nginx 구조 확인 &amp;amp; index.html 수정하기</title>
      <link>https://dev-emong.tistory.com/178</link>
      <description>&lt;h3&gt;1️⃣ nginx 설치 위치 찾기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;find / -name nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tG5vP/dJMb998PNhD/2L6JxJYkKHjyYh7zu9q6m0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tG5vP/dJMb998PNhD/2L6JxJYkKHjyYh7zu9q6m0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tG5vP/dJMb998PNhD/2L6JxJYkKHjyYh7zu9q6m0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtG5vP%2FdJMb998PNhD%2F2L6JxJYkKHjyYh7zu9q6m0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h4&gt;✔ 의미&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;시스템 전체에서 nginx 관련 경로 검색&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;주요 경로 확인 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;  대표 경로&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;/etc/nginx          # 설정 파일
/usr/share/nginx    # 정적 파일(html)
/var/log/nginx      # 로그
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3&gt;2️⃣ nginx 설정 폴더 확인&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;cd /etc/nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRSXlA/dJMb998PNhE/ZBpqNhK4wK05Ky49ZbcMmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRSXlA/dJMb998PNhE/ZBpqNhK4wK05Ky49ZbcMmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRSXlA/dJMb998PNhE/ZBpqNhK4wK05Ky49ZbcMmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRSXlA%2FdJMb998PNhE%2FZBpqNhK4wK05Ky49ZbcMmk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h4&gt;✔ 주요 파일&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&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;nginx.conf&lt;/td&gt;
&lt;td&gt;메인 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sites-enabled&lt;/td&gt;
&lt;td&gt;실제 적용되는 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sites-available&lt;/td&gt;
&lt;td&gt;설정 템플릿&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h3&gt;3️⃣ 파일 상세 정보 확인&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;ls
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wAak1/dJMb998PNhF/LksRToNG6xECRWvFSDCdSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wAak1/dJMb998PNhF/LksRToNG6xECRWvFSDCdSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wAak1/dJMb998PNhF/LksRToNG6xECRWvFSDCdSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwAak1%2FdJMb998PNhF%2FLksRToNG6xECRWvFSDCdSk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;ls -l
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj0IK8/dJMcacdrg5u/ZY174g2iEsH1lESPi98PTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj0IK8/dJMcacdrg5u/ZY174g2iEsH1lESPi98PTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj0IK8/dJMcacdrg5u/ZY174g2iEsH1lESPi98PTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj0IK8%2FdJMcacdrg5u%2FZY174g2iEsH1lESPi98PTK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h4&gt;✔ 해석&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;drwxr-xr-x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  의미&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;d → 디렉토리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rwx → 권한&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;4️⃣ index.html 위치 찾기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;find / -name index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LT2gk/dJMcacdrg5y/sber8aY5nhF4uB5xqFzHOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LT2gk/dJMcacdrg5y/sber8aY5nhF4uB5xqFzHOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LT2gk/dJMcacdrg5y/sber8aY5nhF4uB5xqFzHOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLT2gk%2FdJMcacdrg5y%2Fsber8aY5nhF4uB5xqFzHOK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h2&gt;5️⃣ index.html 위치 이동&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;cd /usr/share/nginx/html
ls
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/49fWG/dJMcagtn5C1/KxSqR33EFHpaaXQn4CsdB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/49fWG/dJMcagtn5C1/KxSqR33EFHpaaXQn4CsdB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/49fWG/dJMcagtn5C1/KxSqR33EFHpaaXQn4CsdB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F49fWG%2FdJMcagtn5C1%2FKxSqR33EFHpaaXQn4CsdB0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p&gt;  기본 웹 페이지 파일 존재&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3&gt;6️⃣ index.html 내용 확인&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;cat index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o6Kbc/dJMcagtn5C9/zaM874s6Ks6db9TFbbWRH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o6Kbc/dJMcagtn5C9/zaM874s6Ks6db9TFbbWRH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o6Kbc/dJMcagtn5C9/zaM874s6Ks6db9TFbbWRH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo6Kbc%2FdJMcagtn5C9%2FzaM874s6Ks6db9TFbbWRH0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p&gt;  기본 내용&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;&amp;lt;h1&amp;gt;Welcome to nginx!&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;7️⃣ 파일 수정 준비 (nano 설치)&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;apt install nano
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBypGF/dJMcagtn5Df/oL5OvZWes1o47d3VD0tss1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBypGF/dJMcagtn5Df/oL5OvZWes1o47d3VD0tss1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBypGF/dJMcagtn5Df/oL5OvZWes1o47d3VD0tss1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBypGF%2FdJMcagtn5Df%2FoL5OvZWes1o47d3VD0tss1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h2&gt;8️⃣ index.html 수정&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;nano index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxKb0x/dJMcacdrg5D/EPPkSXnPkAIUkGmKo6H1aK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxKb0x/dJMcacdrg5D/EPPkSXnPkAIUkGmKo6H1aK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxKb0x/dJMcacdrg5D/EPPkSXnPkAIUkGmKo6H1aK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxKb0x%2FdJMcacdrg5D%2FEPPkSXnPkAIUkGmKo6H1aK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h4&gt;✔ 수정 예시&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;&amp;lt;h1&amp;gt;Good Good&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;9️⃣ 저장 및 종료&lt;/h2&gt;
&lt;p&gt;  nano 저장 방법&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;Ctrl + O → Enter → Ctrl + X
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;또는&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;Ctrl + X → Y → Enter
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UY0r6/dJMb998PNhH/OfVOZJeR64Rw8CPhVDH0B0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UY0r6/dJMb998PNhH/OfVOZJeR64Rw8CPhVDH0B0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UY0r6/dJMb998PNhH/OfVOZJeR64Rw8CPhVDH0B0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUY0r6%2FdJMb998PNhH%2FOfVOZJeR64Rw8CPhVDH0B0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kQDqS/dJMcagtn5Dw/gnLRHFRbzxuRrbu3igeZM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kQDqS/dJMcagtn5Dw/gnLRHFRbzxuRrbu3igeZM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kQDqS/dJMcagtn5Dw/gnLRHFRbzxuRrbu3igeZM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkQDqS%2FdJMcagtn5Dw%2FgnLRHFRbzxuRrbu3igeZM0%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;hr&gt;
&lt;h2&gt;  결과 확인&lt;/h2&gt;
&lt;p&gt;  브라우저 접속&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;http://localhost:포트번호
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRjnB0/dJMb998PNhI/hz2JHOJkQneennQClXtAxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRjnB0/dJMb998PNhI/hz2JHOJkQneennQClXtAxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRjnB0/dJMb998PNhI/hz2JHOJkQneennQClXtAxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRjnB0%2FdJMb998PNhI%2Fhz2JHOJkQneennQClXtAxK%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h2&gt;  핵심 개념 정리&lt;/h2&gt;
&lt;h3&gt;1. nginx가 보는 파일 위치&lt;/h3&gt;
&lt;p&gt;  무조건 이거다&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;/usr/share/nginx/html/index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3&gt;2. 구조 이해&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&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;/etc/nginx&lt;/td&gt;
&lt;td&gt;설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/usr/share/nginx/html&lt;/td&gt;
&lt;td&gt;웹 페이지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/var/log/nginx&lt;/td&gt;
&lt;td&gt;로그&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h3&gt;3. Docker에서 중요한 포인트&lt;/h3&gt;
&lt;p&gt;  컨테이너 안에서 수정한 파일은&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;❗ 컨테이너 종료하면 사라진다&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>아키텍처&amp;amp;인프라</category>
      <author>dev-emong</author>
      <guid isPermaLink="true">https://dev-emong.tistory.com/178</guid>
      <comments>https://dev-emong.tistory.com/178#entry178comment</comments>
      <pubDate>Fri, 11 Sep 2026 10:19:51 +0900</pubDate>
    </item>
    <item>
      <title>스프링 AOP 개념과 횡단 관심사 분리 정리</title>
      <link>https://dev-emong.tistory.com/177</link>
      <description>&lt;h3&gt;1. AOP란 무엇인가&lt;/h3&gt;
&lt;p&gt;AOP는 &lt;strong&gt;Aspect Oriented Programming&lt;/strong&gt;, 즉 관점 지향 프로그래밍이다.&lt;/p&gt;
&lt;p&gt;객체 지향 프로그래밍(OOP)이 객체를 중심으로 설계를 나누는 방식이라면,&lt;/p&gt;
&lt;p&gt;AOP는 &lt;strong&gt;공통 기능을 하나의 관점(Aspect)으로 분리하여 관리하는 방식&lt;/strong&gt;이다.&lt;/p&gt;
&lt;p&gt;스프링에서 AOP는 주로 다음과 같은 공통 기능을 처리하기 위해 사용된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;로깅 처리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;트랜잭션 관리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;권한/인증 검사&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;실행 시간 측정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예외 처리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;캐싱 처리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;유효성 검사&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이처럼 여러 기능에 반복적으로 등장하는 로직을 &lt;strong&gt;횡단 관심사(Cross-cutting Concern)&lt;/strong&gt; 라고 한다.&lt;/p&gt;
&lt;p&gt;AOP는 이 횡단 관심사를 분리하여 핵심 비즈니스 로직을 깔끔하게 유지하도록 돕는 기술이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;2. 왜 AOP가 필요한가&lt;/h3&gt;
&lt;p&gt;웹 애플리케이션을 개발하다 보면 다음과 같은 코드가 반복된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;long start=System.currentTimeMillis();
// 실제 비즈니스 로직 실행
long end=System.currentTimeMillis();
System.out.println(&amp;quot;실행 시간: &amp;quot;+ (end-start));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이런 로직이 여러 서비스 메서드에 반복되면 다음과 같은 문제가 발생한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;중복 코드 증가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;유지보수 어려움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;핵심 로직 가독성 저하&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;공통 기능 수정 시 전체 수정 필요&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AOP는 이러한 문제를 해결하기 위해 등장한 개념이다.&lt;/p&gt;
&lt;p&gt;공통 기능을 따로 모아서 필요한 지점에 자동으로 적용함으로써 코드 중복을 제거하는 것이 목적이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;3. AOP의 핵심 개념 정리&lt;/h3&gt;
&lt;p&gt;AOP를 이해하기 위해 반드시 알아야 할 용어들이 있다.&lt;/p&gt;
&lt;h4&gt;3.1 Aspect&lt;/h4&gt;
&lt;p&gt;Aspect는 &lt;strong&gt;공통 기능을 모아놓은 모듈&lt;/strong&gt;이다.&lt;/p&gt;
&lt;p&gt;예를 들어, 로깅 처리 모듈 하나가 하나의 Aspect가 된다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;3.2 Advice&lt;/h4&gt;
&lt;p&gt;Advice는 &lt;strong&gt;공통 기능이 실제로 실행되는 코드&lt;/strong&gt;이다.&lt;/p&gt;
&lt;p&gt;즉, 언제 실행할지를 정의하는 부분이다.&lt;/p&gt;
&lt;p&gt;종류는 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@Before&lt;/code&gt; : 대상 메서드 실행 전에 수행된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@After&lt;/code&gt; : 대상 메서드 실행 후 수행된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@AfterReturning&lt;/code&gt; : 정상 반환 후 수행된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@AfterThrowing&lt;/code&gt; : 예외 발생 시 수행된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@Around&lt;/code&gt; : 대상 메서드를 감싸서 전후 모두 제어한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;실무에서는 &lt;code&gt;@Around&lt;/code&gt;를 가장 많이 사용한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;3.3 Join Point&lt;/h4&gt;
&lt;p&gt;Join Point는 Advice가 적용될 수 있는 지점이다.&lt;/p&gt;
&lt;p&gt;스프링 AOP에서는 기본적으로 &lt;strong&gt;메서드 실행 지점&lt;/strong&gt;이 Join Point가 된다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;3.4 Pointcut&lt;/h4&gt;
&lt;p&gt;Pointcut은 Advice를 적용할 대상을 지정하는 조건이다.&lt;/p&gt;
&lt;p&gt;예를 들어 다음과 같이 설정할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;특정 패키지의 모든 Service 클래스&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;특정 어노테이션이 붙은 메서드&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;특정 이름 패턴을 가진 메서드&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pointcut을 통해 Join Point 중 실제 적용 대상을 선택한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;3.5 Target&lt;/h4&gt;
&lt;p&gt;Target은 공통 기능이 적용되는 실제 객체이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;3.6 Proxy&lt;/h4&gt;
&lt;p&gt;스프링 AOP의 핵심은 Proxy이다.&lt;/p&gt;
&lt;p&gt;스프링은 원본 객체 대신 프록시 객체를 만들어 호출을 가로챈다.&lt;/p&gt;
&lt;p&gt;호출 흐름은 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;클라이언트 → 프록시 → (Advice 실행) → 실제 대상 객체
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;즉, 우리가 호출하는 객체는 실제 객체가 아니라 프록시 객체이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;4. 스프링 AOP의 동작 원리&lt;/h3&gt;
&lt;p&gt;스프링 AOP는 &lt;strong&gt;프록시 기반 방식&lt;/strong&gt;으로 동작한다.&lt;/p&gt;
&lt;p&gt;프록시는 두 가지 방식으로 생성된다.&lt;/p&gt;
&lt;h4&gt;4.1 JDK Dynamic Proxy&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;인터페이스 기반 프록시이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;대상 클래스가 인터페이스를 구현하고 있어야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;4.2 CGLIB Proxy&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;클래스 상속 기반 프록시이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;인터페이스가 없어도 동작한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;final 클래스나 final 메서드는 제한이 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;스프링은 상황에 따라 두 방식 중 하나를 자동으로 선택한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;5. Around Advice가 가장 많이 사용되는 이유&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;@Around&lt;/code&gt;는 대상 메서드를 직접 감싸는 방식이다.&lt;/p&gt;
&lt;p&gt;다음과 같은 작업이 가능하다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;메서드 실행 전 로직 수행&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;메서드 실행 여부 결정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;메서드 실행 후 로직 수행&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예외 처리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;실행 시간 측정&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;즉, 메서드 호출을 완전히 제어할 수 있다.&lt;/p&gt;
&lt;p&gt;그래서 실무에서는 &lt;code&gt;@Around&lt;/code&gt;를 가장 많이 사용한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;6. AOP 사용 예시 영역&lt;/h3&gt;
&lt;p&gt;스프링 내부에서도 AOP가 많이 사용된다.&lt;/p&gt;
&lt;p&gt;대표적인 예시는 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@Transactional&lt;/code&gt; → 트랜잭션 관리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@Cacheable&lt;/code&gt; → 캐시 처리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Spring Security → 권한 검사&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 기능들 모두 내부적으로 프록시 기반 AOP를 활용하고 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;7. AOP 사용 시 주의해야 할 점&lt;/h3&gt;
&lt;h4&gt;7.1 Self Invocation 문제&lt;/h4&gt;
&lt;p&gt;같은 클래스 내부에서 메서드를 호출하면 프록시를 거치지 않는다.&lt;/p&gt;
&lt;p&gt;예를 들어,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;this.methodB();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 경우 AOP가 적용되지 않을 수 있다.&lt;/p&gt;
&lt;p&gt;프록시는 외부에서 호출될 때만 개입하기 때문이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;7.2 final 메서드 문제&lt;/h4&gt;
&lt;p&gt;CGLIB는 상속 기반이므로 final 메서드는 오버라이드가 불가능하다.&lt;/p&gt;
&lt;p&gt;따라서 AOP 적용에 제한이 생길 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;7.3 디버깅 난이도 증가&lt;/h4&gt;
&lt;p&gt;AOP를 과도하게 사용하면 실제 호출 흐름이 보이지 않아 디버깅이 어려워질 수 있다.&lt;/p&gt;
&lt;p&gt;공통 기능에만 사용하는 것이 바람직하다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;8. AOP vs Filter vs Interceptor 차이&lt;/h3&gt;
&lt;table&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;Filter&lt;/td&gt;
&lt;td&gt;서블릿 레벨&lt;/td&gt;
&lt;td&gt;요청/응답 전처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interceptor&lt;/td&gt;
&lt;td&gt;스프링 MVC 레벨&lt;/td&gt;
&lt;td&gt;컨트롤러 전후 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AOP&lt;/td&gt;
&lt;td&gt;스프링 Bean 메서드 레벨&lt;/td&gt;
&lt;td&gt;비즈니스 공통 로직&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;HTTP 요청 흐름을 제어하려면 Filter나 Interceptor를 사용한다.&lt;/p&gt;
&lt;p&gt;비즈니스 로직의 공통 기능을 처리하려면 AOP를 사용한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;9. 정리&lt;/h3&gt;
&lt;p&gt;스프링 AOP는 &lt;strong&gt;프록시 기반으로 동작하는 공통 기능 분리 기술&lt;/strong&gt;이다.&lt;/p&gt;
&lt;p&gt;비즈니스 로직과 횡단 관심사를 분리하여 코드 중복을 제거하고 유지보수를 용이하게 만든다.&lt;/p&gt;
&lt;p&gt;핵심은 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Aspect는 공통 기능 모듈이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Advice는 실제 실행 코드이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pointcut은 적용 대상 조건이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;스프링 AOP는 프록시 기반으로 동작한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;내부 호출(Self Invocation) 문제에 주의해야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AOP를 적절히 활용하면 코드 구조가 훨씬 깔끔해진다.&lt;/p&gt;
&lt;p&gt;그러나 남용하면 디버깅과 유지보수가 어려워질 수 있다.&lt;/p&gt;
&lt;p&gt;공통 기능에만 사용하는 것이 가장 이상적인 활용 방식이다.&lt;/p&gt;</description>
      <category>자바&amp;amp;스프링</category>
      <author>dev-emong</author>
      <guid isPermaLink="true">https://dev-emong.tistory.com/177</guid>
      <comments>https://dev-emong.tistory.com/177#entry177comment</comments>
      <pubDate>Fri, 11 Sep 2026 10:18:50 +0900</pubDate>
    </item>
    <item>
      <title>Dart Record 타입으로 여러 값 반환하기</title>
      <link>https://dev-emong.tistory.com/176</link>
      <description>&lt;p&gt;Dart 3부터는 record 타입을 사용할 수 있다. record는 여러 값을 하나로 묶어 전달할 때 쓰는 가벼운 데이터 구조다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ex02/test05.dart&lt;/code&gt;와 &lt;code&gt;ex02/test06.dart&lt;/code&gt;는 위치 기반 record, 이름있는 record, 그리고 record를 함수 반환값으로 사용하는 방법을 연습한다.&lt;/p&gt;
&lt;h2&gt;위치 기반 record&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;void main() {
  final user = (&amp;quot;코스&amp;quot;, 10);
  print(user.$1);
  print(user.$2);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;출력 결과는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;코스
10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;(&amp;quot;코스&amp;quot;, 10)&lt;/code&gt;은 두 값을 묶은 record다. 각 값에는 &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;처럼 위치 번호로 접근한다.&lt;/p&gt;
&lt;p&gt;이 방식은 간단하지만 값의 의미가 이름으로 드러나지 않는다. &lt;code&gt;$1&lt;/code&gt;이 이름인지, &lt;code&gt;$2&lt;/code&gt;가 나이인지 코드를 읽는 사람이 문맥으로 추측해야 한다.&lt;/p&gt;
&lt;h2&gt;타입을 명시한 record&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;(String, int) user2 = (&amp;quot;메타&amp;quot;, 20);
print(user2.$1);
print(user2.$2);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;출력 결과는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;메타
20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;(String, int)&lt;/code&gt;는 첫 번째 값이 &lt;code&gt;String&lt;/code&gt;, 두 번째 값이 &lt;code&gt;int&lt;/code&gt;인 record 타입을 뜻한다. Dart는 record 안의 각 위치에 들어갈 타입을 알고 있다.&lt;/p&gt;
&lt;h2&gt;이름있는 record&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;({String name, int age}) user3 = (name: &amp;quot;메타&amp;quot;, age: 20);
print(user3.name);
print(user3.age);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;출력 결과는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;메타
20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이름있는 record는 값에 이름을 붙인다. 그래서 &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt; 대신 &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;age&lt;/code&gt;로 접근할 수 있다.&lt;/p&gt;
&lt;p&gt;읽는 입장에서는 이 방식이 훨씬 명확하다. &lt;code&gt;user3.name&lt;/code&gt;은 이름이고, &lt;code&gt;user3.age&lt;/code&gt;는 나이라는 의미가 바로 드러난다.&lt;/p&gt;
&lt;h2&gt;타입 추론과 이름있는 record&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;var user4 = (name: &amp;quot;쌀&amp;quot;, age: 20);
print(user4.name);
print(user4.age);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;출력 결과는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;쌀
20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;예제 주석에서는 이 형태를 많이 쓴다고 적고 있다. &lt;code&gt;var&lt;/code&gt;를 사용해도 Dart가 record의 필드 이름과 타입을 추론한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;var user4 = (name: &amp;quot;쌀&amp;quot;, age: 20);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 코드는 &lt;code&gt;name&lt;/code&gt;이 &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;age&lt;/code&gt;가 &lt;code&gt;int&lt;/code&gt;인 이름있는 record로 추론된다.&lt;/p&gt;
&lt;h2&gt;함수에서 record 반환하기&lt;/h2&gt;
&lt;p&gt;record는 함수가 여러 값을 반환해야 할 때 유용하다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;({int id, String title}) download() {
  return (id: 1, title: &amp;quot;안녕&amp;quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;download()&lt;/code&gt;는 &lt;code&gt;id&lt;/code&gt;와 &lt;code&gt;title&lt;/code&gt;을 함께 반환한다. 별도의 클래스를 만들지 않아도 두 값을 이름있는 구조로 묶어서 반환할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;void main() {
  var data = download();
  print(data.id);
  print(data.title);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;출력 결과는 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;1
안녕
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;data.id&lt;/code&gt;, &lt;code&gt;data.title&lt;/code&gt;처럼 필드 이름으로 접근할 수 있으므로 반환값의 의미가 분명하다.&lt;/p&gt;
&lt;h2&gt;class 대신 record를 써도 되는 경우&lt;/h2&gt;
&lt;p&gt;record는 여러 값을 잠깐 묶어 전달할 때 좋다. 예를 들어 함수 내부에서 계산 결과 두 개를 반환하거나, 작은 값 묶음을 임시로 사용할 때 편하다.&lt;/p&gt;
&lt;p&gt;하지만 앱의 중요한 도메인 개념을 표현한다면 class가 더 적합할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;class User {
  final String name;
  final int age;

  User({required this.name, required this.age});
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;User&lt;/code&gt;처럼 의미가 분명하고 여러 곳에서 재사용될 데이터라면 class로 이름을 붙이는 편이 좋다. record는 가벼운 묶음이고, class는 개념에 이름을 붙인 모델이라고 볼 수 있다.&lt;/p&gt;
&lt;h2&gt;Flutter에서 왜 중요한가&lt;/h2&gt;
&lt;p&gt;Flutter와 Dart 코드를 작성하다 보면 함수에서 두 개 이상의 값을 반환하고 싶은 순간이 생긴다. 예전에는 작은 class를 만들거나 &lt;code&gt;Map&lt;/code&gt;을 반환하는 방식으로 처리하는 경우가 많았다.&lt;/p&gt;
&lt;p&gt;record를 사용하면 타입 안정성을 유지하면서도 간단하게 여러 값을 반환할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;final result = await loadUserSummary();
print(result.name);
print(result.age);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다만 화면 상태나 API 모델처럼 오래 유지되는 데이터 구조는 record보다 class나 DTO로 표현하는 편이 읽기 좋다.&lt;/p&gt;
&lt;h2&gt;핵심 정리&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;record는 여러 값을 하나로 묶는 Dart 3 문법이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;위치 기반 record는 &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;처럼 접근한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이름있는 record는 &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;age&lt;/code&gt;처럼 필드 이름으로 접근한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;var&lt;/code&gt;를 사용해도 record의 필드 이름과 타입을 추론할 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;함수 반환값으로 record를 사용하면 여러 값을 타입 안전하게 반환할 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;잠깐 쓰는 값 묶음에는 record가 편하고, 중요한 도메인 개념에는 class가 더 적합하다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flutter 코드에서도 간단한 다중 반환값을 표현할 때 record가 도움이 된다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Flutter&amp;amp;Dart</category>
      <author>dev-emong</author>
      <guid isPermaLink="true">https://dev-emong.tistory.com/176</guid>
      <comments>https://dev-emong.tistory.com/176#entry176comment</comments>
      <pubDate>Fri, 11 Sep 2026 10:18:08 +0900</pubDate>
    </item>
    <item>
      <title>Claude 모델 구조와 Constitutional AI 정리</title>
      <link>https://dev-emong.tistory.com/175</link>
      <description>&lt;h2&gt;1.   Claude란 무엇인가&lt;/h2&gt;
&lt;h3&gt;✔ 정의&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Claude&lt;/strong&gt;는 Anthropic이 개발한&lt;/p&gt;
&lt;p&gt;  &lt;strong&gt;Transformer 기반 LLM으로, Constitutional AI와 Long Context 처리에 특화된 모델&lt;/strong&gt;이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 한 줄 정의&lt;/h3&gt;
&lt;p&gt;  &lt;strong&gt;자기 검열(Constitutional AI)을 통해 안정성을 강화하고, 긴 문맥을 효율적으로 처리하는 LLM&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 핵심 키워드&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Constitutional AI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Long Context&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alignment 중심 설계&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;2. ⚙️ Claude의 구조 (Architecture)&lt;/h2&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 기본 구조&lt;/h3&gt;
&lt;p&gt;  GPT와 동일 계열&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Transformer 기반&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decoder-only&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Autoregressive&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 핵심 차이&lt;/h3&gt;
&lt;p&gt;  구조 자체보다 “운영 방식”이 다름&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GPT → 성능 + 범용성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Claude → 안정성 + 일관성&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;3.   Constitutional AI (핵심 기술)&lt;/h2&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 개념&lt;/h3&gt;
&lt;p&gt;  사람이 일일이 피드백 주는 대신&lt;/p&gt;
&lt;p&gt;  &lt;strong&gt;AI가 스스로 규칙을 기반으로 답을 평가하고 수정&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 기존 방식 (RLHF)&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;여러 답변 생성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;사람이 좋은 답 선택&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;보상 학습&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;  사람 의존도 높음&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;✔ Claude 방식&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;답변 생성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“헌법(규칙)” 적용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;스스로 수정&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 헌법(Constitution) 예시&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;해로운 내용 금지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;정확성 유지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;편향 최소화&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 결과&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;더 안전한 답변&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;일관성 높은 출력&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;과격한 응답 감소&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;4.   Long Context 처리&lt;/h2&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 개념&lt;/h3&gt;
&lt;p&gt;  매우 긴 입력을 처리하는 능력&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;수십만 ~ 백만 토큰&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 왜 중요한가?&lt;/h3&gt;
&lt;p&gt;기존 LLM:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;긴 입력 → 성능 급감&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Claude:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;긴 문서 유지 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 기술적 배경&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Attention 최적화&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;메모리 효율 개선&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sparse / 효율적 Attention 구조&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 효과&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;코드베이스 분석 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;긴 문서 요약 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;대화 맥락 유지 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;5.   Claude의 동작 방식&lt;/h2&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 기본 흐름&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;입력 → 토큰화&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Transformer 처리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;다음 토큰 생성&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;  여기까지는 GPT와 동일&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 추가 단계 (중요)&lt;/h3&gt;
&lt;p&gt;  Self-critique (자기 평가)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;답변 생성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;규칙 기반 평가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;수정&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 결과&lt;/h3&gt;
&lt;p&gt;  더 보수적이고 안정적인 출력&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;6.   핵심 기술적 특징&lt;/h2&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 1) 안정성 중심 디코딩&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;공격적 생성 ❌&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;보수적 생성 ✅&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 2) 낮은 Hallucination&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;자기 검열 과정 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 3) 긴 문맥 유지&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;context window 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 4) 구조적 단순성&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GPT처럼 Dense 구조 유지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;대신 alignment 강화&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;7. ⚠️ Claude의 한계&lt;/h2&gt;
&lt;hr&gt;
&lt;h3&gt;❌ 1) 과도한 보수성&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;답변이 지나치게 조심스러움&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;❌ 2) 창의성 제한&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;공격적 생성이 약함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;❌ 3) 툴 연동 약함&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;GPT 대비 ecosystem 부족&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;❌ 4) 속도 문제&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;긴 context 처리 비용 큼&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;8. ⚔️ GPT vs Claude 기술 비교&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;GPT&lt;/th&gt;
&lt;th&gt;Claude&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;구조&lt;/td&gt;
&lt;td&gt;Dense&lt;/td&gt;
&lt;td&gt;Dense&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;정렬 방식&lt;/td&gt;
&lt;td&gt;RLHF&lt;/td&gt;
&lt;td&gt;Constitutional AI&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;Hallucination&lt;/td&gt;
&lt;td&gt;있음&lt;/td&gt;
&lt;td&gt;상대적으로 적음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context 길이&lt;/td&gt;
&lt;td&gt;중간&lt;/td&gt;
&lt;td&gt;매우 김&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;9.   설계 철학 차이&lt;/h2&gt;
&lt;hr&gt;
&lt;h3&gt;✔ GPT&lt;/h3&gt;
&lt;p&gt;  &lt;strong&gt;“범용 + 성능 중심”&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;✔ Claude&lt;/h3&gt;
&lt;p&gt;  &lt;strong&gt;“안정성 + 신뢰성 중심”&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;10.   핵심 요약&lt;/h2&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 기술적 핵심&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Transformer (Decoder-only)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Autoregressive 생성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Constitutional AI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Long Context 최적화&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;✔ 구조적 특징&lt;/h3&gt;
&lt;p&gt;  &lt;strong&gt;스스로 답변을 검열하고 수정하는 모델&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;  결론&lt;/h2&gt;
&lt;p&gt;Claude는 Transformer 기반의 LLM이지만,&lt;/p&gt;
&lt;p&gt;기존 GPT 계열과 달리 Constitutional AI를 통해&lt;/p&gt;
&lt;p&gt;모델이 스스로 답변을 평가하고 수정하는 구조를 가진다.&lt;/p&gt;
&lt;p&gt;또한 긴 문맥(Long Context)을 효율적으로 처리할 수 있도록&lt;/p&gt;
&lt;p&gt;Attention 구조를 최적화하여,&lt;/p&gt;
&lt;p&gt;대규모 문서나 코드 분석에 강점을 보인다.&lt;/p&gt;
&lt;p&gt;이러한 설계를 통해 Claude는&lt;/p&gt;
&lt;p&gt;안정성과 신뢰성을 중시하는 LLM으로 자리잡고 있다.&lt;/p&gt;</description>
      <author>dev-emong</author>
      <guid isPermaLink="true">https://dev-emong.tistory.com/175</guid>
      <comments>https://dev-emong.tistory.com/175#entry175comment</comments>
      <pubDate>Fri, 11 Sep 2026 10:17:45 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 변수 선언과 동적 타입 정리</title>
      <link>https://dev-emong.tistory.com/174</link>
      <description>&lt;p&gt;자바스크립트에서 &lt;strong&gt;변수(variable)&lt;/strong&gt; 는 값을 저장하기 위한 공간이다.&lt;/p&gt;
&lt;p&gt;다른 언어(Java, C# 등)와 달리 &lt;strong&gt;타입을 미리 지정하지 않는 동적 타입 언어&lt;/strong&gt;라는 특징을 가진다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;1️⃣ 변수 선언과 초기화&lt;/h3&gt;
&lt;h4&gt;✅ 변수 선언&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let n1;
console.log(n1);// undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;변수를 선언했지만 &lt;strong&gt;값을 넣지 않은 상태&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이때 변수의 값은 자동으로 &lt;code&gt;undefined&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;  &lt;strong&gt;선언은 되었지만 값은 없다&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;✅ 변수 초기화&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let n2 =1;
console.log(n2);// 1
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;변수를 선언하면서 &lt;strong&gt;처음 값을 할당&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이 과정을 &lt;strong&gt;초기화(initialization)&lt;/strong&gt; 라고 한다&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;2️⃣ 자바스크립트의 타입 특징 (동적 타입)&lt;/h3&gt;
&lt;p&gt;자바스크립트는 &lt;strong&gt;변수에 타입을 명시하지 않는다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;값이 들어가는 순간 타입이 결정된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let n3 =10;
console.log(typeof n3);// number
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;정수(int)와 실수(double)를 구분하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;모두 &lt;code&gt;number&lt;/code&gt; 타입&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let n4 =10.5;
console.log(typeof n4);// number
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  &lt;strong&gt;JS에는 숫자 타입이 하나뿐이다 (&lt;/strong&gt;&lt;code&gt;**number**&lt;/code&gt;&lt;strong&gt;)&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;3️⃣ 문자열 (string)&lt;/h3&gt;
&lt;h4&gt;기본 문자열&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let n5 =&amp;quot;문자열&amp;quot;;
console.log(typeof n5);// string
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;문자열 안에 따옴표 포함&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let n6 =&amp;#39;문자열 &amp;quot;안녕&amp;quot;&amp;#39;;
console.log(n6);
console.log(typeof n6);// string
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;작은 따옴표 &lt;code&gt;&amp;#39;&lt;/code&gt; 와 큰 따옴표 &lt;code&gt;&amp;quot;&lt;/code&gt; 모두 사용 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;서로 섞어서 사용하면 편리함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;템플릿 문자열 (Template Literal)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let n7 =`문자열 ${n4}`;
console.log(n7);// 문자열 10.5
console.log(typeof n7);// string
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;백틱(`) 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;${}&lt;/code&gt; 문법으로 &lt;strong&gt;변수 삽입 가능&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;문자열 결합보다 가독성이 좋음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;4️⃣ 불리언 (boolean)&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let n8 =true;
console.log(n8);// true
console.log(typeof n8);// boolean
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;참(&lt;code&gt;true&lt;/code&gt;) / 거짓(&lt;code&gt;false&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;조건문(if), 반복문에서 핵심적으로 사용됨&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;5️⃣ null과 undefined의 차이 ⭐ (중요)&lt;/h3&gt;
&lt;h4&gt;  undefined&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let n1;
console.log(n1);// undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;값이 &lt;strong&gt;아직 할당되지 않음&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;자바스크립트가 자동으로 부여&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;  null&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let n9 =null;
console.log(n9);// null
console.log(typeof n9);// object ❗
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;의도적으로 비어있음을 표현&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;개발자가 직접 넣는 값&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⚠️ &lt;strong&gt;주의&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;typeofnull ===&amp;quot;object&amp;quot;// true
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;자바스크립트의 오래된 버그&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;실제로는 객체가 아님&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;6️⃣ 콘솔 출력 결과 정리&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;값&lt;/th&gt;
&lt;th&gt;typeof 결과&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;undefined&lt;/td&gt;
&lt;td&gt;undefined&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10, 10.5&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;quot;문자열&amp;quot;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;문자열 ${n4}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;null&lt;/td&gt;
&lt;td&gt;object (버그)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h3&gt;7️⃣ 핵심 요약&lt;/h3&gt;
&lt;p&gt;✔ 자바스크립트는 &lt;strong&gt;동적 타입 언어&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;✔ 변수 선언은 &lt;code&gt;let&lt;/code&gt;, 값이 들어가야 타입이 결정됨&lt;/p&gt;
&lt;p&gt;✔ 숫자는 모두 &lt;code&gt;number&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;✔ 문자열은 &lt;code&gt;&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;#39;&lt;/code&gt;, &lt;code&gt;`&lt;/code&gt; 사용 가능&lt;/p&gt;
&lt;p&gt;✔ &lt;code&gt;undefined&lt;/code&gt; = 값이 없음 (자동)&lt;/p&gt;
&lt;p&gt;✔ &lt;code&gt;null&lt;/code&gt; = 비어있다고 명시 (수동)&lt;/p&gt;
&lt;p&gt;✔ &lt;code&gt;typeof null === &amp;quot;object&amp;quot;&lt;/code&gt; 는 유명한 JS 버그&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;✍️ 한 줄 정리&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;자바스크립트의 변수는 타입보다 값이 중요하며, 실행 시점에 타입이 결정된다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>웹 기초</category>
      <author>dev-emong</author>
      <guid isPermaLink="true">https://dev-emong.tistory.com/174</guid>
      <comments>https://dev-emong.tistory.com/174#entry174comment</comments>
      <pubDate>Fri, 11 Sep 2026 10:17:06 +0900</pubDate>
    </item>
    <item>
      <title>JSP 템플릿 엔진과 Model 1 구조 정리</title>
      <link>https://dev-emong.tistory.com/173</link>
      <description>&lt;hr&gt;
&lt;h3&gt;3. JSP란?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;HTML + Java 코드를 섞어서 작성하는 서버 페이지&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;프로젝트 경로&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;C:\workspace\web_history_lab\v3
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;build.gradle의 dependencies에 탬플릿 추가&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;// JSP 엔진(톰캣 Jasper)
implementation &amp;#39;org.apache.tomcat.embed:tomcat-embed-jasper&amp;#39;

// JSTL (EL, core 태그)
implementation &amp;#39;jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api&amp;#39;
implementation &amp;#39;org.glassfish.web:jakarta.servlet.jsp.jstl&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKSqtJ/dJMcaix3q8e/TunDu9a361jA7UiAyMsd01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKSqtJ/dJMcaix3q8e/TunDu9a361jA7UiAyMsd01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKSqtJ/dJMcaix3q8e/TunDu9a361jA7UiAyMsd01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKSqtJ%2FdJMcaix3q8e%2FTunDu9a361jA7UiAyMsd01%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h4&gt;폴더 경로 설정&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;/resources/META-INF/resources
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x7BT5/dJMcacxLEHD/tlVmCSxsmIQTMpNlDODtCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x7BT5/dJMcacxLEHD/tlVmCSxsmIQTMpNlDODtCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x7BT5/dJMcacxLEHD/tlVmCSxsmIQTMpNlDODtCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx7BT5%2FdJMcacxLEHD%2FtlVmCSxsmIQTMpNlDODtCk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h3&gt;4. JSP 예제&lt;/h3&gt;
&lt;h4&gt;index.jsp&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!-- jsp - 자바 서버 페이지 --&amp;gt;
&amp;lt;%@ page language=&amp;quot;java&amp;quot; contentType=&amp;quot;text/html; charset=UTF-8&amp;quot;
pageEncoding=&amp;quot;UTF-8&amp;quot;%&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;index 페이지&amp;lt;/h1&amp;gt;
    &amp;lt;% int num = 10; %&amp;gt;
    &amp;lt;h3&amp;gt;값 : &amp;lt;%=num%&amp;gt;&amp;lt;/h3&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;의미&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&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;&amp;lt;% %&amp;gt;&lt;/td&gt;
&lt;td&gt;자바 코드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;%= %&amp;gt;&lt;/td&gt;
&lt;td&gt;자바 값 출력&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h3&gt;5. JSP는 어떻게 동작할까?&lt;/h3&gt;
&lt;h4&gt;핵심 개념&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;JSP는 바로 실행되지 않는다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;실제 내부 과정&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;index.jsp
   ↓ (템플릿 엔진)
index_jsp.java (서블릿으로 변환)
   ↓
컴파일
   ↓
실행
   ↓
HTML 생성 → 브라우저
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;브라우저에서 바로 열리는것이 아닌 자바에서 컴파일을 통해 브라우저가 읽을 수있는 데이터로 변환한 후 변환된 데이터를 브라우저에게 전달한다&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!-- jsp - 자바 서버 페이지 --&amp;gt;
&amp;lt;%@ page language=&amp;quot;java&amp;quot; contentType=&amp;quot;text/html; charset=UTF-8&amp;quot;
pageEncoding=&amp;quot;UTF-8&amp;quot;%&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;index 페이지&amp;lt;/h1&amp;gt;
    &amp;lt;% int num = 10; %&amp;gt;
    &amp;lt;h3&amp;gt;값 : &amp;lt;%=num%&amp;gt;&amp;lt;/h3&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pAq3l/dJMcacxLEHH/ria3Kgd3BWhQpKhYfINZnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pAq3l/dJMcacxLEHH/ria3Kgd3BWhQpKhYfINZnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pAq3l/dJMcacxLEHH/ria3Kgd3BWhQpKhYfINZnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpAq3l%2FdJMcacxLEHH%2Fria3Kgd3BWhQpKhYfINZnk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h3&gt;6. 그럼 JSP = 서블릿이랑 뭐가 달라?&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;서블릿&lt;/th&gt;
&lt;th&gt;JSP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;HTML 작성&lt;/td&gt;
&lt;td&gt;자바 문자열&lt;/td&gt;
&lt;td&gt;그냥 HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;가독성&lt;/td&gt;
&lt;td&gt;나쁨&lt;/td&gt;
&lt;td&gt;좋음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;유지보수&lt;/td&gt;
&lt;td&gt;어려움&lt;/td&gt;
&lt;td&gt;쉬움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;디자이너 협업&lt;/td&gt;
&lt;td&gt;불가&lt;/td&gt;
&lt;td&gt;가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;내부 동작&lt;/td&gt;
&lt;td&gt;직접 작성&lt;/td&gt;
&lt;td&gt;서블릿으로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;  &lt;strong&gt;JSP는 “서블릿을 자동으로 만들어주는 템플릿”&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;7 JSP를 서블릿으로 직접 바꾸면?&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;package com.example.v3;

import java.io.IOException;
import java.io.PrintWriter;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet(&amp;quot;/index.jsp&amp;quot;)
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int num = 10;
        String html = &amp;quot;&amp;quot;&amp;quot;
                    &amp;lt;!DOCTYPE html&amp;gt;
                    &amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
                    &amp;lt;head&amp;gt;
                        &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;gt;
                        &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;gt;
                        &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
                    &amp;lt;/head&amp;gt;
                    &amp;lt;body&amp;gt;
                        &amp;lt;h1&amp;gt;index 페이지&amp;lt;/h1&amp;gt;

                        &amp;lt;h3&amp;gt;값 : &amp;lt;%=num%&amp;gt;&amp;lt;/h3&amp;gt;
                    &amp;lt;/body&amp;gt;
                    &amp;lt;/html&amp;gt;
                &amp;quot;&amp;quot;&amp;quot;.replace(&amp;quot;&amp;lt;%=num%&amp;gt;&amp;quot;, num + &amp;quot;&amp;quot;);
        resp.setContentType(&amp;quot;text/html; charset=utf-8&amp;quot;);
        PrintWriter pw = resp.getWriter();
        pw.println(html);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;→ JSP 내부적으로 이런 서블릿으로 변환됨&lt;/p&gt;
&lt;p&gt;즉:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JSP = 서블릿 자동 생성기&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이렇게 변환 시켜주는것을 템플릿 엔진이 처리한다&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VnRvg/dJMcaix3q8m/TSNrv8lmzHCEDpkWq8cKd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VnRvg/dJMcaix3q8m/TSNrv8lmzHCEDpkWq8cKd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VnRvg/dJMcaix3q8m/TSNrv8lmzHCEDpkWq8cKd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVnRvg%2FdJMcaix3q8m%2FTSNrv8lmzHCEDpkWq8cKd1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;hr&gt;
&lt;h3&gt;8. JSP의 장점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;HTML 그대로 작성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;자바 코드 삽입 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;생산성 ↑&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;유지보수 ↑&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;협업 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;9. JSP의 단점 (중요)&lt;/h3&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LuCK8/dJMcaix3q8o/eeXkBbiVdEBw6zxzZzAIn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LuCK8/dJMcaix3q8o/eeXkBbiVdEBw6zxzZzAIn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LuCK8/dJMcaix3q8o/eeXkBbiVdEBw6zxzZzAIn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLuCK8%2FdJMcaix3q8o%2FeeXkBbiVdEBw6zxzZzAIn1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;h4&gt;① 공통 로직 처리 불가&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;로그인 검사&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;권한 체크&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;공통 데이터 처리&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;중앙에서 통제 불가&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;② UI + 비즈니스 로직 혼합&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-plain&quot;&gt;HTML + DB 조회 + 조건문 + 반복문
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  코드 스파게티&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;10. 이 구조를 뭐라고 부르냐?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Model 1 패턴&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;특징:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;JSP 하나가 다 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;화면 + 로직 + DB&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;11. 그래서 또 진화함&lt;/h3&gt;
&lt;p&gt;문제 해결:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;MVC 패턴 등장 (Model 2)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3&gt;12. 한 줄 요약&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;JSP는 HTML 안에 자바 코드를 작성하고, 내부적으로 서블릿으로 변환되어 실행되는 3세대 서버 템플릿 기술이다.서블릿과 JSP는 대표적인 서버 사이드 렌더링 방식이다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>개발기법&amp;middot;CS</category>
      <author>dev-emong</author>
      <guid isPermaLink="true">https://dev-emong.tistory.com/173</guid>
      <comments>https://dev-emong.tistory.com/173#entry173comment</comments>
      <pubDate>Fri, 11 Sep 2026 10:16:13 +0900</pubDate>
    </item>
  </channel>
</rss>