<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>kiyo.log💗</title>
        <link>https://velog.io/</link>
        <description>"개발자는 해결사이자 발견자이다✨" - Michael C. Feathers</description>
        <lastBuildDate>Tue, 13 Oct 2026 14:11:41 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>kiyo.log💗</title>
            <url>https://velog.velcdn.com/images/kiteof_park/profile/06af089b-d4a1-4f88-b875-ea39b5a878bd/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. kiyo.log💗. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/kiteof_park" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[내일배움캠프] TIL - MSA(Microservice Architecture)🧩]]></title>
            <link>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL-MSAMicroservice-Architecture</link>
            <guid>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL-MSAMicroservice-Architecture</guid>
            <pubDate>Tue, 13 Oct 2026 14:11:41 GMT</pubDate>
            <description><![CDATA[<h2 id="msa">MSA</h2>
<p><strong>MSA는 업무 기능별 서비스를 나누고, 각 서비스를 독립적으로 개발·배포·운영하는 아키텍처</strong> </p>
<p><strong>1. 먼저 이해할 개념</strong></p>
<p>쇼핑몰을 예로 들면 주문, 결제, 재고를 각각 서비스로 나눌 수 있습니다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>모놀리식</th>
<th>MSA</th>
</tr>
</thead>
<tbody><tr>
<td>구성</td>
<td>주요 기능이 하나의 애플리케이션에 포함</td>
<td>업무별로 여러 서비스 구성</td>
</tr>
<tr>
<td>배포</td>
<td>애플리케이션 단위 배포</td>
<td>서비스별 독립 배포</td>
</tr>
<tr>
<td>확장</td>
<td>애플리케이션 전체 확장</td>
<td>부하가 큰 서비스만 확장 가능</td>
</tr>
<tr>
<td>통신</td>
<td>주로 프로세스 내부 호출</td>
<td>네트워크를 통한 API·메시지 통신</td>
</tr>
<tr>
<td>복잡성</td>
<td>내부 코드와 모듈 관리</td>
<td>서비스 간 통신·데이터·장애 관리</td>
</tr>
</tbody></table>
<p>MSA에서는 독립 배포와 선택적 확장이 쉬워지는 대신, 네트워크 장애와 데이터 일관성 같은 분산 시스템 문제를 다뤄야 합니다. <a href="https://learn.microsoft.com/en-us/azure/architecture/guide/architecture-styles/microservices">Microsoft 아키텍처 개요</a></p>
<p><strong>2. 서비스를 나누는 기준</strong></p>
<p>핵심은 <strong>업무 책임과 함께 변경되는 기능을 기준으로 경계를 정하는 것</strong>입니다.</p>
<ul>
<li><strong>도메인:</strong> 주문, 결제, 배송처럼 비즈니스가 다루는 영역</li>
<li><strong>DDD:</strong> 비즈니스 개념을 중심으로 소프트웨어를 설계하는 접근</li>
<li><strong>Bounded Context:</strong> 특정 용어와 모델이 일관된 의미를 갖는 경계</li>
</ul>
<p>예를 들어 주문 서비스의 ‘상품’에는 주문 당시의 가격이 중요하고, 재고 서비스의 ‘상품’에는 가용 수량이 중요합니다. 같은 이름이라도 책임과 모델은 다를 수 있습니다. <a href="https://learn.microsoft.com/en-us/azure/architecture/microservices/model/domain-analysis">도메인 분석 학습 자료</a></p>
<p>학습 과제: 쇼핑몰 기능을 주문·결제·재고로 분류하고, 각 서비스가 책임질 규칙을 세 가지씩 적어보세요.</p>
<p><strong>3. 서비스 간 통신과 데이터 소유권</strong></p>
<table>
<thead>
<tr>
<th>방식</th>
<th>예시</th>
<th>고민할 점</th>
</tr>
</thead>
<tbody><tr>
<td>동기 통신</td>
<td>주문 서비스가 결제 API를 호출하고 응답을 기다림</td>
<td>지연, 타임아웃, 장애 전파</td>
</tr>
<tr>
<td>비동기 통신</td>
<td>주문 생성 이벤트를 발행하고 다른 서비스가 처리</td>
<td>중복 메시지, 처리 순서, 실패 복구</td>
</tr>
</tbody></table>
<p>각 서비스는 자신의 데이터를 소유하고, 다른 서비스는 API나 이벤트를 통해 접근하는 것이 기본 원칙입니다. DB 서버를 반드시 각각 마련해야 한다는 뜻은 아니며, 데이터 소유권과 접근 경계를 분리하는 것이 핵심입니다. <a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/architect-microservice-container-applications/data-sovereignty-per-microservice">서비스별 데이터 소유권</a></p>
<p><strong>4. 반드시 공부할 데이터 패턴</strong></p>
<ul>
<li><strong>최종적 일관성:</strong> 서비스 간 데이터가 즉시 같아지지 않아도, 처리가 완료되면 일관된 상태에 도달하는 방식</li>
<li><strong>Saga:</strong> 여러 서비스의 로컬 트랜잭션을 연결하고, 실패하면 업무상 보상 작업을 수행하는 패턴. 예를 들어 결제 실패 시 재고 예약을 해제합니다. <a href="https://microservices.io/patterns/data/saga.html">Saga 설명</a></li>
<li><strong>Transactional Outbox:</strong> 업무 데이터와 발행할 이벤트를 같은 DB 트랜잭션으로 기록한 뒤, 별도 처리기가 이벤트를 전달하는 패턴. DB 저장 성공과 메시지 발행 실패가 엇갈리는 문제를 다룹니다. <a href="https://microservices.io/patterns/data/transactional-outbox.html">Outbox 설명</a></li>
<li><strong>멱등성:</strong> 같은 요청이나 메시지를 여러 번 처리해도 결제·재고 차감 등의 효과가 중복 발생하지 않도록 설계하는 성질</li>
</ul>
<p>Saga의 보상 작업은 전체 DB 트랜잭션을 되돌리는 롤백과 다릅니다. 이미 수행된 작업을 업무 규칙에 따라 취소하거나 상쇄하는 것입니다.</p>
<p><strong>5. 운영에서 알아야 할 항목</strong></p>
<ul>
<li><strong>타임아웃·재시도:</strong> 응답 지연과 일시적 실패 처리</li>
<li><strong>Circuit Breaker:</strong> 반복적으로 실패하는 서비스 호출을 일시적으로 차단</li>
<li><strong>관측 가능성:</strong> 로그, 메트릭, 분산 추적으로 요청 흐름과 장애 원인 파악</li>
<li><strong>CI/CD·호환성:</strong> 서비스별 배포 자동화와 API 변경 관리</li>
</ul>
<p>이 항목들은 장애 격리와 독립 배포를 실제로 유지하기 위한 기반입니다. <a href="https://learn.microsoft.com/en-us/azure/architecture/guide/architecture-styles/microservices">Microsoft 운영·설계 가이드</a></p>
<p>학습 목표는 <strong>“서비스를 어떻게 나눌까?”, “일부가 실패하면 어떻게 복구할까?”, “서로 독립적으로 배포할 수 있을까?”</strong>에 답할 수 있게 되는 것입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[내일배움캠프] TIL(6) Spring 입문주차🌱 - JPA 범부의 하루(1)]]></title>
            <link>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL6-Spring-%EC%9E%85%EB%AC%B8%EC%A3%BC%EC%B0%A8-JPA-%EB%B2%94%EB%B6%80%EC%9D%98-%ED%95%98%EB%A3%A81</link>
            <guid>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL6-Spring-%EC%9E%85%EB%AC%B8%EC%A3%BC%EC%B0%A8-JPA-%EB%B2%94%EB%B6%80%EC%9D%98-%ED%95%98%EB%A3%A81</guid>
            <pubDate>Thu, 08 Oct 2026 12:02:49 GMT</pubDate>
            <description><![CDATA[<h2 id="jdbc-ormjpa-hibernate-spring-data-jpa">JDBC, ORM,JPA, Hibernate, Spring Data JPA</h2>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/a9d0487a-514e-4cb0-9312-1a6bc9434cc3/image.png" width = 70%>

<h3 id="jdbc">JDBC</h3>
<ul>
<li><strong>자바 애플리케이션에서 데이터베이스에 접근하고 SQL을 실행하기 위한 표준 API</strong></li>
<li>JDBC를 직접 사용하는 경우 개발자는 SQL을 작성하고, 실행 결과를 자바 객체로 변환하는 작업도 처리</li>
<li>JDBC는 자바와 DB가 통신할 수 있는 수단을 제공하지만, 객체와 테이블을 자동으로 매핑<pre><code class="language-java">String sql = &quot;SELECT * FROM memo WHERE id = ?&quot;;
</code></pre>
</li>
</ul>
<p>PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setLong(1, 1L);</p>
<p>ResultSet rs = pstmt.executeQuery();</p>
<p>if (rs.next()) {
    Long id = rs.getLong(&quot;id&quot;);
    String username = rs.getString(&quot;username&quot;);
}</p>
<pre><code>
### ORM 
- **객체지향 프로그래밍의 객체와 관계형 데이터베이스의 테이블을 매핑하는 기술**
- 자바 애플리케이션에서는 객체를 사용하지만, 관계형 DB에서는 테이블과 행(Row)을 사용한다.
이러한 표현 방식의 차이를 해결하고 객체 중심으로 데이터를 다룰 수 있도록 돕는 기술이 ORM이다.

### JPA
- **자바에서 ORM을 사용하기 위한 표준 명세**
- JPA 자체가 ORM 기능을 구현한 프로그램인 것이 아님!
- ORM을 구현하기 위한 인터페이스와 동작 규칙을 정의하고, 실제 동작은 JPA 구현체가 담당

예를 들어 JPA는 다음과 같은 인터페이스와 메서드를 정의한다 : 
- `EntityManager`
- `EntityManagerFactory`
- `persist()`
- `find()`
- `remove()`

### Hibernate
- **JPA를 실제로 구현한 대표적인 ORM 프레임워크**
- JPA API를 사용하여 엔티티의 저장이나 조회를 요청하면 Hibernate가 엔티티 매핑 정보를 바탕으로 
필요한 SQL을 생성하고 실행한다.

### Spring Data JPA
- JPA를 더 편리하게 사용할 수 있도록 지원하는 Spring Data 프로젝트의 모듈
- **JPA만 사용할 경우 개발자가 EntityManager를 이용하여 엔티티 저장, 조회 등의 작업을 직접 구현해야 하는데, 
Spring Data JPA를 사용하면 JpaRepository 인터페이스를 통해 기본적인 CRUD 기능을 간편하게 사용**할 수 있다.
- Repository 구현체를 자동으로 생성하고, 내부적으로 JPA의 EntityManager 등을 이용해 DB 작업 수행

| 구분 | 개념 | 역할 |
|---|---|---|
| 🍀**JDBC** | 데이터베이스 접근 API | SQL 실행 및 DB 통신 |
| 🍀**ORM** | 객체-관계 매핑 기술 | 객체와 관계형 DB 매핑 |
| 🍀**JPA** | ORM 표준 명세 | ORM 사용을 위한 API와 규칙 정의 |
| 🍀**Hibernate** | ORM 프레임워크 | JPA 기능 구현, SQL 생성 및 실행 |
| 🍀**Spring Data JPA** | JPA 추상화 기술 | Repository를 통한 CRUD 및 쿼리 기능 제공 |

--- 
## 엔티티와 테이블
### 엔티티(클래스)
- 데이터베이스 테이블과 매핑되는 자바 클래스
- `@Entity`가 선언된 자바 클래스가 JPA에서 관리할 수 있는 엔티티 클래스가 된다.
- JPA를 사용한다고 **반드시 DB 테이블이 새로 생성되는 것은 아니다.** _- Hibernate 설정에 따라_

### 엔티티와 테이블 간 관계
- 엔티티 클래스 `Memo` 는 memo 테이블과 매핑된다.
- 하나의 엔티티 인스턴스는 테이블의 하나의 행(Row)에 대응한다.
#### 엔티티 클래스</code></pre><p>@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Memo {
    @Id
    @GeneratedValue(stragy = GeneratedType.IDENTITY)
    private Long id;</p>
<pre><code>@Column(nullable = false)
private String username;

@Column(nullable = false)
private String contents;</code></pre><p>}</p>
<pre><code>#### DB 테이블
| id | username | contents |
|-------|-------|-------|     
| 1   | Jude   | Jude memo   |
| 2   | Judy  | Judy memo   |
| 3   | Juice  | Jucie memo   |

## 엔티티 인스턴스 생성
엔티티 클래스와 DB 테이블이 매핑되었다고 해서 엔티티 인스턴스가 자동으로 생성되는 것은 아니다.

### 1. 개발자가 생성하는 경우

```java
Memo memo = new Memo();</code></pre><ul>
<li>개발자가 <code>new</code> 키워드를 사용하여 직접 인스턴스를 생성</li>
<li><strong>이 시점의 객체는 단순한 자바 객체, JPA의 영속성 컨텍스트에서 관리되는 상태❌</strong></li>
</ul>
<pre><code class="language-java">em.persist(memo);       // 영속성 컨텍스트에 등록</code></pre>
<ul>
<li><strong><code>persist()</code>를 호출하면 엔티티가 영속 상태</strong>가 되고, 이후 적절한 시점에 DB에 INSERT SQL 실행</li>
</ul>
<h3 id="2-db에서-데이터를-조회하는-경우">2. DB에서 데이터를 조회하는 경우</h3>
<pre><code class="language-java">Memo memo = em.find(Memo.class, 1L);</code></pre>
<ul>
<li>Hibernate는 필요할 경우 다음 작업을 수행한다:<ul>
<li>엔티티 조회 요청</li>
<li>DB에 SELECT SQL 실행</li>
<li>조회 결과(Row) 확인</li>
<li>Memo 엔티티 인스턴스 생성</li>
<li>Row의 컬럼 값을 인스턴스 필드에 매핑</li>
<li>완성된 인스턴스 반환</li>
</ul>
</li>
</ul>
<p><strong>✨ [참고]</strong>
JPA 영속성 컨텍스트에 이미 해당 엔티티가 존재하면 별도의 DB 조회나 새 인스턴스 생성 없이 
기존 인스턴스를 반환할 수도 있다.</p>
<hr>
<p>JPA 엔티티(Entity) 클래스를 작성할 때 기본 생성자(Default Constructor)를 반드시 포함해야 하는 주된 이유는 무엇입니까?
JPA 구현체는 데이터베이스 조회 결과를 자바 엔티티 객체로 생성할 때 Java Reflection API를 활용합니다. 이때 매개변수가 없는 기본 생성자를 호출하여 객체를 생성한 뒤 리플렉션으로 값을 주입하므로, 기본 생성자가 반드시(최소 protected 접근 제어자 이상으로) 필요합니다.</p>
<p>--</p>
<h2 id="영속성-컨텍스트---persistence-context">영속성 컨텍스트 - <em>Persistence Context</em></h2>
<p>영속성 컨텍스트,
EntityManager,
EntityManagerFactory,
JPA 트랜잭션</p>
<hr>
<h2 id="영속성-컨텍스트의-기능">영속성 컨텍스트의 기능</h2>
<blockquote>
<p>영속성 컨텍스트는 <strong>Entity 객체를 효율적으로 쉽게 관리하기 위해 만들어진 공간</strong></p>
</blockquote>
<h3 id="1차-캐시">1차 캐시</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[[내일배움캠프] TIL(5) Spring 입문주차🌱 - IoC, DI, Bean, IoC Container]]></title>
            <link>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL5-Spring-%EC%9E%85%EB%AC%B8%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL5-Spring-%EC%9E%85%EB%AC%B8%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Wed, 07 Oct 2026 10:52:41 GMT</pubDate>
            <description><![CDATA[<h2 id="ioc와-di">IoC와 DI</h2>
<h4 id="스프링-ioc와-di의-핵심">스프링 IoC와 DI의 핵심</h4>
<blockquote>
<p>객체를 내가 직접 생성하고 연결하지 않고,
<strong>스프링 컨테이너가 객체 생성과 의존관계를 관리하도록 맡기는 것</strong></p>
</blockquote>
<h3 id="🍀-iocinversion-of-control-제어의-역전">🍀 IoC(Inversion of Control, 제어의 역전)</h3>
<p><strong>예제 코드</strong></p>
<pre><code class="language-java">public class OrderService {

    private PaymentService paymentService = new PaymentService();
}
</code></pre>
<p><code>OrderService</code>가 직접:</p>
<ul>
<li><code>PaymentService</code> 객체 생성</li>
<li>객체 관리</li>
<li>어떤 구현체를 사용할지 결정
즉, <strong>제어권이 개발자 코드에 있다.</strong></li>
</ul>
<p><strong>예제 코드</strong></p>
<pre><code class="language-java">@Service
public class OrderService {

    private final PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}</code></pre>
<pre><code class="language-java">@Service
public class PaymentService {
}</code></pre>
<ul>
<li><code>PaymentService</code> 객체를 누가 만드는가?<strong>(생성)</strong> → <strong><em>Spring Container</em></strong></li>
<li><code>OrderService</code>에 누가 넣어주는가?<strong>(주입)</strong> → <strong><em>Spring Container</em></strong></li>
</ul>
<h3 id="ioc-정리">IoC 정리</h3>
<p>객체에 대한 <strong>제어권이 개발자 → 프레임워크로 넘어갔기 때문에 IoC(제어의 역전)</strong>라고 한다.</p>
<h3 id="🍀-didependency-injection-의존성-주입">🍀 DI(Dependency Injection, 의존성 주입)</h3>
<p><strong>DI</strong>는 <strong>IoC를 구현하는 대표적인 방법</strong>으로,
필요한 객체를 내부에서 직접 생성하지 않고 <strong>외부에서 전달받는 것</strong>이다.</p>
<h4 id="예제코드">예제코드</h4>
<pre><code class="language-java">public class OrderService {

    private PaymentService paymentService;
}
</code></pre>
<ul>
<li><code>OrderService</code>가 정상적으로 동작하려면 <code>PaymentService</code>가 필요하다.</li>
<li><code>OrderService</code> → <strong>(의존관계)</strong> → <code>PaymentService</code> </li>
</ul>
<h4 id="예제코드-1">예제코드</h4>
<pre><code class="language-java">public OrderService(PaymentService paymentService) {
    this.paymentService = paymentService;
}</code></pre>
<ul>
<li><code>PaymentService</code>를 외부에서 넣어준다.</li>
</ul>
<h3 id="🍀-ioc와-di의-관계">🍀 IoC와 DI의 관계</h3>
<table>
<thead>
<tr>
<th>개념</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>IoC</td>
<td>객체 생성/관리의 제어권을 Spring에 넘기는 <strong>설계원칙</strong></td>
</tr>
<tr>
<td>DI</td>
<td>필요한 객체를 외부에서 주입하는 <strong>방식</strong></td>
</tr>
<tr>
<td>Spring Container</td>
<td>IoC와 DI를 실제로 수행하는 <strong>주체</strong></td>
</tr>
</tbody></table>
<hr>
<h2 id="bean과-ioc-container">Bean과 IoC Container</h2>
<h3 id="🍀-bean">🍀 Bean</h3>
<ul>
<li>스프링(Spring IoC Container)이 생성하고 관리하는 객체 </li>
<li>관련 어노테이션:<ul>
<li><code>@Service</code>, <code>@Component</code>, <code>@Repository</code>, <code>@Controller</code>이 붙은 클래스는 
Component Scan의 대상이 되어 Spring Bean으로 등록된다.</li>
</ul>
</li>
</ul>
<h3 id="🍀-ioc-container">🍀 IoC Container</h3>
<ul>
<li>애플리케이션에서 사용할 Bean(객체)을 <strong>생성</strong>하고, <strong>보관</strong>하고, 필요한 곳에 <strong>주입</strong>해주는 </li>
<li><em>스프링의 객체 관리 공간*</em></li>
<li>대표적으로 <code>ApplicationContext</code>가 IoC Container 역할을 한다.</li>
</ul>
<h4 id="✨-참고-beanfactory와-applicationcontext">✨ [참고] BeanFactory와 ApplicationContext</h4>
<pre><code> IoC Container
   │
   ├── 📦 BeanFactory
   │      └─ Bean 관리의 가장 기본 기능
   │
   └── 📦 ApplicationContext
          └─ BeanFactory 기능 + 여러 부가 기능
</code></pre><ul>
<li><code>BeanFactory</code> : 기본적인 Bean 생성/조회/관리 기능을 제공<ul>
<li><code>ApplicationContext</code> : BeanFactory를 확장하여 그 기능을 포함하면서 여러 부가 기능 제공</li>
</ul>
</li>
</ul>
<hr>
<h2 id="spring-bean-등록">Spring Bean 등록</h2>
<p>간만에 스프링 공부하니까 개ㅐ어지럽다.
다양한 어노테이션과 개념들이 연달아 쏟아지듯 등장하면서 뇌가 지끈거렸는데 
각각 따로 보면 헷갈리지만 
<strong>결국 모두 스프링이 객체를 생성하고 관리하면서 필요한 객체끼리 연결하는 과정과 관련된 개념</strong>이다.</p>
<h3 id="📍-전체-흐름-먼저-보기">📍 전체 흐름 먼저 보기</h3>
<pre><code>@SpringBootApplication
        ↓
@ComponentScan
        ↓
@Component 계열 클래스 탐색
        ↓
Bean 생성 및 등록
        ↓
ApplicationContext가 Bean 관리
        ↓
생성자 주입 / @Autowired
        ↓
필요한 Bean을 다른 Bean에 주입
</code></pre><h3 id="🍀-component">🍀 @Component</h3>
<ul>
<li>해당 클래스를 스프링이 관리하는 객체인 Bean으로 등록할 대상임을 표시</li>
<li>스프링은 <code>@Component</code>가 붙은 클래스를 발견하면 <strong>객체를 생성</strong>하고 스프링 Container에 <strong>Bean으로 등록</strong>한다.</li>
</ul>
<h3 id="🍀-component-계열-어노테이션">🍀 @Component 계열 어노테이션</h3>
<h4 id="controller"><code>@Controller</code></h4>
<div>
    <img src ="https://velog.velcdn.com/images/kiteof_park/post/2cbac29f-c141-4209-9b27-802c4966db41/image.png" width = 50%>
</div>

<h4 id="service"><code>@Service</code></h4>
<div>
    <img src = "https://velog.velcdn.com/images/kiteof_park/post/38088715-d155-4087-a02b-607f3bc5a79a/image.png" width = 50%>
</div>

<h4 id="repository"><code>@Repository</code></h4>
<div>
    <img src = "https://velog.velcdn.com/images/kiteof_park/post/b08a118f-8e5f-453d-9019-77ddb1ea219a/image.png" width = 50%>
</div>

<h3 id="🍀-componentscan">🍀 @ComponentScan</h3>
<ul>
<li><strong>특정 패키지를 탐색</strong>하면서 <strong><code>@Component</code> 계열 어노테이션이 붙은 클래스를 찾아 Bean으로 등록</strong>한다.</li>
<li>스프링 부트에서 ComponentScan을 직접 작성하지 않는다.</li>
<li>왜? <strong><code>@SpringBootApplication</code>안에 <code>@ComponentScan</code>이 포함</strong>되어 있으니까 !!!<ul>
<li><code>@SpringBootApplication</code>이 있는 현재 패키지+하위 패키지 스캔</li>
</ul>
</li>
<li>그래서 메인 클래스를 최상위 패키지에서 두는 것이 일반적</li>
</ul>
<div>
    <img src = "https://velog.velcdn.com/images/kiteof_park/post/f7d4dec5-4982-48db-acbf-d97bc3638cdf/image.png">
</div>

<h4 id="✨-참고-springbootapplication의-핵심-어노테이션">✨ [참고] @SpringBootApplication의 핵심 어노테이션</h4>
<pre><code>@SpringBootApplication
   ├─ @SpringBootConfiguration
   │      └─ @Configuration
   ├─ @EnableAutoConfiguration
   └─ @ComponentScan</code></pre><ul>
<li><code>@SpringBootConfiguration</code> : 클래스가 Spring Boot의 설정 클래스임을 나타냄<ul>
<li><code>@Configuration</code> : 클래스가 Spring의 설정 클래스임을 나타냄</li>
</ul>
</li>
<li><code>@EnableAutoConfiguration</code> : 클래스 패스와 설정값을 바탕으로 필요한 설정을 자동 구성</li>
<li><code>@ComponentScan</code> : 현재 패키지와 하위 패키지의 <code>@Component</code> 계열 클래스를 탐색해 Bean 등록</li>
</ul>
<h4 id="✨-참고-component-vs-configuration--bean">✨ [참고] @Component vs @Configuration + @Bean</h4>
<p>둘 다 Bean을 등록하는 방법이지만 <strong>누가 Bean 등록을 결</strong>정하느냐가 다름</p>
<table>
<thead>
<tr>
<th>구분</th>
<th><code>@Component</code></th>
<th><code>@Configuration + @Bean</code></th>
</tr>
</thead>
<tbody><tr>
<td>붙이는 위치</td>
<td>클래스</td>
<td>설정 클래스 + 메서드</td>
</tr>
<tr>
<td>등록 대상</td>
<td><strong>해당 클래스 자체</strong></td>
<td><strong><code>@Bean</code> 메서드가 반환한 객체</strong></td>
</tr>
<tr>
<td>등록 방식</td>
<td><strong>Component Scan으로 자동 발견</strong></td>
<td><strong>개발자가 직접 Bean 생성 방법 정의</strong></td>
</tr>
<tr>
<td>주로 사용</td>
<td>내가 만든 클래스</td>
<td>외부 라이브러리 객체, 생성 과정 커스터마이징 필요 시</td>
</tr>
</tbody></table>
<h4 id="component">@Component</h4>
<pre><code class="language-java">@Component
public class PaymentService {
}</code></pre>
<h4 id="cofiguration--bean">@Cofiguration + @Bean</h4>
<pre><code>@Configuration
public class AppConfig {

    @Bean
    public PaymentService paymentService() {
        return new PaymentService();
    }
}</code></pre><hr>
<h2 id="의존성-주입di">의존성 주입(DI)</h2>
<p>여러 어노테이션을 통해 Bean을 등록한 다음에는 
<strong>Bean끼리 연결</strong>을 해야하는데 이때 사용하는 것이 <strong>의존성 주입(DI)</strong>이다.</p>
<h3 id="🍀-autowired">🍀 @Autowired</h3>
<ul>
<li><code>@Autowired</code>는 스프링 컨테이너에서 <strong>필요한 타입의 Bean을 찾아 자동으로 주입</strong>하도록 요청한다.</li>
<li>객체를 새로 생성하는 것이 아니라 <strong>컨테이너가 관리하는 빈을 찾아 연결</strong>해준다.</li>
</ul>
<p><strong>예제 코드</strong></p>
<pre><code class="language-java">@RestController
public class UserController {

    @Autowired
    private UserService userService;
}</code></pre>
<ul>
<li>스프링은 <code>UserService</code>타입의 Bean을 찾아 <code>userService</code> 필드에 넣어준다.</li>
</ul>
<hr>
<h2 id="의존성-주입-방법">의존성 주입 방법</h2>
<ol>
<li>생성자 주입</li>
<li>필드 주입</li>
<li>Setter 주입</li>
</ol>
<h3 id="🍀-생성자-주입">🍀 생성자 주입</h3>
<ul>
<li>생성자를 통해 필요한 Bean을 전달받는 방식</li>
<li><strong>객체 생성 시 필요한 의존성을 주입</strong></li>
<li><code>final</code> 필드 사용 가능</li>
<li>필수 의존성이 누락되면 객체를 정상적으로 생성 불가</li>
<li>생성자가 하나라면 <code>@Autowired</code> 생략 가능</li>
</ul>
<pre><code class="language-java">@RestController
public class MemoController {

    private final MemoService memoService;

    @Autowired
    public MemoController(MemoService memoService) {
        this.memoService = memoService;
    }
}</code></pre>
<ul>
<li>Controller <strong>객체가 생성되는 시점에</strong> Serivce를 전달받는다.</li>
</ul>
<h4 id="✨-참고-requiredargsconstructor">✨ [참고] @RequiredArgsConstructor</h4>
<ul>
<li><code>@RequiredArgsConstructor</code>는 <strong><code>final</code> 필드와 <code>@NonNull</code> 필드를 매개변수로 가지는 생성자를 자동으로 만들어</strong>준다.</li>
</ul>
<pre><code class="language-java">@RestController
@RequiredArgsConstrucutor
public class MemoController {

    private final MemoService memoService;

}</code></pre>
<h3 id="🍀-필드-주입">🍀 필드 주입</h3>
<ul>
<li>필드에 직접 <code>@Autowired</code>를 붙여 주입받는 방식</li>
<li><code>final</code> 필드에 일반적인 필드 주입을 적용 불가<ul>
<li><strong>필드 의존성 주입은 객체 생성 후 수행</strong>(리플렉션)되므로 
객체가 생성될 때 초기화되어야 하는 <code>final</code>과 충돌</li>
</ul>
</li>
<li>의존성이 클래스 내부에 숨겨져 있음 <em>- 생성자에 노출X, 필드 내부에 선언</em></li>
<li>따라서 스프링 없이 객체를 직접 생성하면 해당 필드가 <code>null</code></li>
</ul>
<pre><code class="language-java">@RestController
public class MemoController {

    @Autowired
    private MemoService memoService;
}</code></pre>
<pre><code class="language-java">MemoController controller = new MemoController(); // 이때 memoService는 null
</code></pre>
<h3 id="🍀-setter-주입">🍀 Setter 주입</h3>
<ul>
<li><code>Setter</code> 메서드를 통해 의존성을 전달받는 방식</li>
<li>스프링이 객체를 생성한 후 <code>set..()</code>를 호출해서 주입</li>
<li><strong>객체 생성 이후 의존성 주입되므로 의존성을 나중에 변경할 수 있음</strong></li>
<li><code>final</code> 사용 불가</li>
<li>필수가 아닌 선택적 의존성을 설정할 때 활용할 수 있음</li>
</ul>
<pre><code class="language-java">@RestController
public class MemoController {

    private MemoService memoService;

    @Autowired
    public void setMemoService(MemoService memoService) {
        this.memoService = memoService;
    }
}</code></pre>
<h3 id="생성자-주입이-권장되는-이유">생성자 주입이 권장되는 이유</h3>
<h4 id="1-필수-의존성-보장">1. 필수 의존성 보장</h4>
<p>필수 의존성 없이 객체를 생성하는 것을 방지할 수 있음</p>
<h4 id="2-final-사용-가능">2. final 사용 가능</h4>
<p><code>final</code> 필드는 한 번 초기화되면 다른 객체로 재할당이 불가해,
의존성이 실수로 변경되는 것을 방지 할 수 있음 <em>- Setter 주입은 변경이 가능</em></p>
<h4 id="3-기타">3. 기타</h4>
<ul>
<li>테스트 편리</li>
<li>순환 참조 조기 발견 </li>
</ul>
<h3 id="📍-전체-흐름-다시-정리">📍 전체 흐름 다시 정리</h3>
<pre><code>@SpringBootApplication
        │
        └── @ComponentScan
                  │
                  ↓
        Component Scan 수행
                  │
                  ↓
@Component / @Controller / @RestController
@Service / @Repository 클래스 발견
                  │
                  ↓
              Bean 생성
                  │
                  ↓
          ApplicationContext
          ┌─────────────────┐
          │ Bean 관리       │
          │ Bean 조회       │
          │ 의존성 관리     │
          └─────────────────┘
                  │
                  ↓
       생성자 주입 / @Autowired
                  │
                  ↓
           Bean 간 의존성 연결</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[내일배움캠프] TIL - Optinal 타입 처리]]></title>
            <link>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL-Optinal-%ED%83%80%EC%9E%85-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL-Optinal-%ED%83%80%EC%9E%85-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Wed, 07 Oct 2026 06:47:29 GMT</pubDate>
            <description><![CDATA[<h2 id="optionalt">Optional<code>&lt;T&gt;</code></h2>
<ul>
<li><code>Optional&lt;T&gt;</code>는 값이 있을 수도 있고, 없을 수도 있는 상황을 표현하는 타입</li>
<li><code>null</code>로 인한 <strong>(NPE)를 안전하게 처리</strong> 위해 제공되는 래퍼 클래스</li>
<li>실제 객체를 포장하는 <strong>상자</strong>에 비유</li>
</ul>
<h3 id="optional-생성-방법">Optional 생성 방법</h3>
<ul>
<li><code>Optional.empty()</code>: 빈 Optional 객체 생성</li>
<li><code>Optional.of(value)</code>: 값이 있는 Optional 객체를 생성(만약 value가 null이면 NPE 발생)</li>
<li><code>Optional.ofNullable(value)</code>: value가 null일 수도 아닐 수도 있을 때 사용, null이면 빈 Optional을 반환</li>
</ul>
<pre><code class="language-java">Optional&lt;String&gt; empty = Optional.empty();
Optional&lt;String&gt; name = Optional.of(&quot;의연&quot;);
Opitonal&lt;String&gt; unknown = Optional.ofNull(null);
</code></pre>
<h3 id="optional-처리-방법">Optional 처리 방법</h3>
<h4 id="값-확인">값 확인</h4>
<ul>
<li><code>isPresent()</code>: Optional 내부에 값이 있으면 true, 없으면 false를 반환</li>
<li><code>isEmpty()</code>: Optional 내부에 값이 없으면 true, 있으면 false를 반환</li>
</ul>
<pre><code class="language-java">if (optional.isPresent()) {
    System.out.println(optional.get());
}

if (optional.isEmpty()) {
    System.out.println(optional.get());
}</code></pre>
<h4 id="값-꺼내기">값 꺼내기</h4>
<ul>
<li><code>get()</code>: Optional 내부의 값을 반환, 없으면 NoSuchElementException 발생</li>
<li><code>orElse(value)</code>: Optional 내부에 값이 있으면 반환하고, 없으면 전달한 value를 반환</li>
<li><code>orElseGet(...)</code>: Optional 내부에 값이 있으면 반환하고, 없으면 전달한 함수를 실행하여 그 결과를 반환</li>
<li><code>orElseThrow(...)</code>: Optional 내부에 값이 있으면 반환하고, 없으면 지정한 예외를 발생<ul>
<li>Spring Data JPA의 <code>findById()</code>는 <code>Optional</code>을 반환</li>
</ul>
</li>
</ul>
<pre><code class="language-java">String name = optional.get();
String name = optional.orElse(&quot;Guest&quot;);
String name = optional.orElseGet(() -&gt; &quot;Guest&quot;);
User user = userRepository.findById(id)
        .orElseThrow(() -&gt; new IllegalArgumentException(&quot;사용자를 찾을 수 없습니다.&quot;));</code></pre>
<h4 id="값-처리">값 처리</h4>
<ul>
<li><code>ifPresent(...)</code>: Optional 내부에 값이 있을 때만 전달한 동작을 실행</li>
</ul>
<pre><code class="language-java">optional.ifPresent(name -&gt; {
    System.out.println(name);
});</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[내일배움캠프] TIL - record타입의 DTO와 toEntity(), from() 메서드]]></title>
            <link>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL-record%ED%83%80%EC%9E%85%EC%9D%98-DTO%EC%99%80-toEntity-from-%EB%A9%94%EC%84%9C%EB%93%9C</link>
            <guid>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL-record%ED%83%80%EC%9E%85%EC%9D%98-DTO%EC%99%80-toEntity-from-%EB%A9%94%EC%84%9C%EB%93%9C</guid>
            <pubDate>Wed, 07 Oct 2026 06:24:17 GMT</pubDate>
            <description><![CDATA[<h2 id="dtodata-transfer-object">DTO(Data Transfer Object)</h2>
<ul>
<li>계층 간 데이터를 전달하기 위해 사용하는 객체로, 사용하는 이유는<ul>
<li><strong>데이터 전달</strong></li>
<li><strong>데이터 캡슐화</strong> : <code>Entity</code>를 직접 노출하지 않고 필요 데이터만 전달</li>
<li><strong>보안</strong> : 민감한 정보가 응답에 포함되는 것을 방지</li>
<li><strong>유효성 검증</strong> : <code>@NotNull</code>, <code>@NotBlack</code> 등으로 요청 데이터 검증</li>
<li><strong>유지보수</strong> : <code>Entity</code> 구가 변경되어도 API의 요청/응답 구조를 독립적 관리</li>
</ul>
</li>
</ul>
<h3 id="dto-작성-방법--class-vs-record">DTO 작성 방법 : Class vs Record</h3>
<h4 id="class">Class</h4>
<pre><code class="language-java">@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserRequestDto {

    private String name;
    private int age;
}</code></pre>
<ul>
<li>필드 값 변경 가능(<code>Setter</code>사용 시)</li>
<li>생성자, <code>Getter</code>, <code>Setter</code>등을 직접 정의하거나 Lombok으로 생성</li>
<li>상속 가능(<code>final</code>이 아닌 경우)</li>
<li><strong>복잡한 객체 구조나 값 변경이 필요한 경우 적합</strong></li>
</ul>
<h4 id="record">Record</h4>
<pre><code class="language-java">public record UserRequestDto(
    String name,
    int age
) {}</code></pre>
<ul>
<li><code>private final</code> 필드 자동 생성</li>
<li>생성자, 접근자 <code>equals()</code>, <code>hashCode()</code>, <code>toString()</code> 자동 생성</li>
<li><code>Setter</code>가 없으며 생성 이후 필드 값 변경 불가 <strong><em>- 불변</em></strong></li>
<li>다른 클래스 상속 불가</li>
<li><strong>코드가 간결하며 데이터 전달 목적에 적합</strong></li>
</ul>
<h2 id="toentity-from-메서드">toEntity(), from() 메서드</h2>
<blockquote>
<p>record타입으로 DTO를 작성한다면 <code>toEntity()</code>와 <code>from()</code> 메서드를 작성할 수 있다.
둘 다 <strong>DTO ↔ Entity 변환 책임을 DTO 안에 두는 패턴</strong>이다. </p>
</blockquote>
<h3 id="toentity">toEntity()</h3>
<ul>
<li><strong>Request DTO를 Entity로 변환</strong>하는 메서드</li>
<li>클라이언트 요청 JSON → <code>Dto.toEnity();</code> → Entity</li>
<li>Entity 클래스 생성자에 <code>@Builder</code>를 붙여 함께  사용함</li>
</ul>
<p><strong>Memo.java</strong></p>
<pre><code class="language-java">    @Builder
    public Memo(String username, String title, String contents) {
        this.username = username;
        this.title = title;
        this.content = content;
        this.deleteStatus = false;  // 명시용(boolean타입 기본값: false)
    }</code></pre>
<p><strong>MemoCreateRequest.java</strong></p>
<pre><code class="language-java">public record MemoCreateRequest(
        @NotBlank(message = &quot;사용자 이름은 필수입니다.&quot;)
        String username,

        @NotBlank(message = &quot;제목은 필수입니다.&quot;)
        String title,

        @NotBlank(message = &quot;내용은 필수입니다.&quot;)
        String contents
) {
        public Memo toEntity(){
                return Memo.builder()
                        .username(username)
                        .title(title)
                        .contents(contents)
                        .build();
        }
}</code></pre>
<h3 id="from">from()</h3>
<ul>
<li><strong>Entity를 Response DTO로 변환</strong>하는 메서드</li>
<li>Entity → <code>Entity.from(entity)</code> → 클라이언트 응답 JSON</li>
<li><code>from()</code> 메서드는 정적 팩토리 메서드</li>
</ul>
<pre><code class="language-java">public record MemoResponse(
        Long id,
        String username,
        String titile,
        String content
) {
    public static MemoResponse from(Memo memo){
        return new MemoResponse(
                memo.getId(),
                memo.getUsername(),
                memo.getTitle(),
                memo.getContent()
        );
    }
}</code></pre>
<h4 id="✨-참고-정적-팩토리-메서드">✨ [참고] 정적 팩토리 메서드</h4>
<ul>
<li>정적 팩토리 메서드는 <strong><code>new</code> 대신 객체를 생성해서 반환해주는 <code>static</code> 메서드</strong></li>
<li>객체를 만들기 위한 메서드로 아직 객체가 존재하지 않기 때문에 <code>static</code>메서드로 만들어</li>
<li><em>객체 없이 클래스 자체에서 호출*</em>할 수 있도록 함</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[내일배움캠프] TIL(3) Spring 입문주차🌱]]></title>
            <link>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL3-Spring-%EC%9E%85%EB%AC%B8%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL3-Spring-%EC%9E%85%EB%AC%B8%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Tue, 06 Oct 2026 11:55:32 GMT</pubDate>
            <description><![CDATA[<h2 id="🍀-gradle">🍀 Gradle</h2>
<ul>
<li><code>Gradle</code> 은 <strong>빌드 자동화 시스템</strong>으로, 작성한 Java코드를 설정에 맞게 자동으로 빌드해준다.</li>
<li>여기서 빌드란, <strong>소스코드를 실행 가능한 결과물로 만드는 과정</strong>이다. <em>- <code>.jar</code> 파일</em></li>
</ul>
<h4 id="buildgradle">build.gradle</h4>
<ul>
<li>Gradle 기반의 빌드 스크립트(groovy, kotlin 언어로 작성)</li>
<li>소스 코드를 빌드하고 <strong>라이브러리들의 의존성을 쉽게 관리</strong>하도록 한다.</li>
</ul>
<h2 id="🍀-wsweb-server--wasweb-application-server">🍀 WS(Web Server) / WAS(Web Application Server)</h2>
<p><a href="https://velog.io/@kiteof_park/Web%EC%9B%B9-%EC%84%9C%EB%B2%84WS%EC%99%80-%EC%9B%B9-%EC%96%B4%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%84%9C%EB%B2%84WAS">WS와 WAS 관련 포스팅 바로가기</a></p>
<h4 id="wsweb-server">WS(Web Server)</h4>
<ul>
<li>클라이언트의 요청에 <strong>정적 컨텐츠 응답</strong></li>
<li>대표적으로 Apache, Nginx</li>
</ul>
<h4 id="wasweb-application-server">WAS(Web Application Server)</h4>
<ul>
<li>클라이언트의 요청에 <strong>동적 컨텐츠 생성 및 비즈니스 로직 실행</strong></li>
<li>WS의 기능을 WAS에서도 처리 가능</li>
<li>대표적으로 Apache Tomcat, JBoss</li>
</ul>
<h4 id="✨-참고-ws와-was의-협력-관계">✨ [참고] WS와 WAS의 협력 관계</h4>
<p>대부분 실무에서는 WS와 WAS를 함께 사용하는데,
웹 서버가 앞단에서 정적 요청을 먼저 처리하고 동적 처리가 필요할 때만 WAS로 넘겨 <strong>서버 과부하를 방지</strong>한다.</p>
<h2 id="🍀-spring-mvc--front-controller패턴--dispatcher-servlet">🍀 Spring MVC / Front Controller패턴 / Dispatcher Servlet</h2>
<h2 id="🍀-정적-페이지-vs-동적-페이지">🍀 정적 페이지 vs 동적 페이지</h2>
<h4 id="템플릿-엔진-유무에-따른-html-처리">템플릿 엔진 유무에 따른 HTML 처리</h4>
<table>
<thead>
<tr>
<th>구분</th>
<th>템플릿 엔진⭕ (Ex. Thymeleaf)</th>
<th>템플릿 엔진❌</th>
</tr>
</thead>
<tbody><tr>
<td>HTML 위치</td>
<td><code>src/main/resources/templates/</code></td>
<td><code>src/main/resources/static/</code></td>
</tr>
<tr>
<td>HTML 성격</td>
<td>동적 View</td>
<td>정적 HTML</td>
</tr>
<tr>
<td>주 용도</td>
<td>동적 HTML(View) 생성</td>
<td>정적 HTML 제공 또는 API 응답</td>
</tr>
<tr>
<td>처리 방식</td>
<td>템플릿 엔진이 HTML을 렌더링</td>
<td>정적 파일을 그대로 응답</td>
</tr>
<tr>
<td><code>Model</code> 데이터 사용</td>
<td>가능</td>
<td>불가능</td>
</tr>
<tr>
<td>주요 처리 주체</td>
<td><code>ViewResolver</code> + Template Engine</td>
<td>Static Resource Handler</td>
</tr>
</tbody></table>
<ul>
<li><code>templates/</code> : 서버에서 데이터를 적용해 렌더링하는 View</li>
<li><code>static/</code> : 별도의 렌더링 없이 그대로 제공하는 정적 리소스</li>
</ul>
<h4 id="예제코드">예제코드</h4>
<pre><code class="language-java">@Controller
public class HtmlController {

    @GetMapping(&quot;/html/hello&quot;)
    public String hello() {
        return &quot;hello&quot;;
    }
}</code></pre>
<h4 id="템플릿-엔진이-있는-경우">템플릿 엔진이 있는 경우</h4>
<pre><code>HTTP 요청
   ↓
DispatcherServlet
   ↓
Controller
   ↓
return &quot;hello&quot;
   ↓
ViewResolver
   ↓
Template Engine
   ↓
templates/hello.html
   ↓
HTML 응답</code></pre><h4 id="템플릿-엔진이-없는-경우">템플릿 엔진이 없는 경우</h4>
<pre><code>HTTP 요청
   ↓
DispatcherServlet
   ↓
Controller
   ↓
정적 리소스 처리
   ↓
Static Resource Handler
   ↓
static/hello.html
   ↓
HTML 응답
</code></pre><p>@ResponseBody와 Jackson 라이브러리, ObejectMapper까지</p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[[내일배움캠프] TIL - 서블릿 니가 뭔데 날 울려 ,,]]></title>
            <link>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL-%EC%84%9C%EB%B8%94%EB%A6%BF-%EB%8B%88%EA%B0%80-%EB%AD%94%EB%8D%B0-%EB%82%A0-%EC%9A%B8%EB%A0%A4</link>
            <guid>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL-%EC%84%9C%EB%B8%94%EB%A6%BF-%EB%8B%88%EA%B0%80-%EB%AD%94%EB%8D%B0-%EB%82%A0-%EC%9A%B8%EB%A0%A4</guid>
            <pubDate>Tue, 06 Oct 2026 01:18:42 GMT</pubDate>
            <description><![CDATA[<p>강의를 들으면서 가장 거슬렸던 점은 <code>Servlet</code>에 대한 의미이다.
누군가는 서블릿을 <strong>기술</strong>이라고 부르고, 누군가는 <strong>클래스</strong>라고 부르며 또 다른 누군가는 <strong>객체</strong>라고 부른다.</p>
<h2 id="servlet">Servlet</h2>
<p>Servlet은 자바에서 HTTP 요청과 응답을 처리하기 위한 <strong>서버 측 기술</strong>이고
실제 코드에서는 <strong>Servlet 규약을 따르는 클래스</strong>를 만들고
서블릿 컨테이너가 그 클래스의 <strong>객체를 생성</strong>해서 요청을 처리한다.</p>
<h3 id="🍀-기술">🍀 기술</h3>
<ul>
<li>서블릿에 대한 가장 넓은 의미로,
자바 웹 서버에서 HTTP 요청을 처리하기 위한 표준 기술/규악이다.</li>
</ul>
<pre><code class="language-text">클라이언트 요청
   ↓
Servlet 기술
   ↓
Java 코드로 요청 처리
   ↓
응답</code></pre>
<h3 id="🍀-클래스">🍀 클래스</h3>
<ul>
<li>실제 코드로 작성할 때는 보통 <code>HttpServlet</code>을 상속한 클래스를 작성한다.</li>
</ul>
<pre><code class="language-java">public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(
            HttpServletRequest req,
            HttpServletResponse resp
    ) {
        // 요청 처리
    }
}</code></pre>
<ul>
<li>이런 클래스를 <strong>&quot;서블릿 클래스&quot;</strong>라고 부르며, <strong>서블릿으로 동작하도록 작성한 자바 클래스</strong>이다.</li>
</ul>
<h3 id="🍀-객체">🍀 객체</h3>
<ul>
<li>서버가 실행되면 Tomcat같은 <strong>서블릿 컨테이너가 서블릿 클래스(<code>HelloServlet</code>)의 객체를 생성</strong>한다.</li>
<li>실제로 개발자가 직접 관리하지 않고, <strong>Tomcat이 생성/관리</strong>한다.</li>
</ul>
<pre><code class="language-text">GET /hello 요청
    ↓
Tomcat
    ↓
HelloServlet 객체
    ↓
doGet()</code></pre>
<h3 id="✨-전체-흐름-정리">✨ 전체 흐름 정리</h3>
<pre><code class="language-text">Servlet
= 자바 웹 요청 처리 기술/규약
        ↓

HttpServlet
= Servlet 규약을 편하게 구현하도록 제공되는 클래스
        ↓

HelloServlet
= 개발자가 작성한 Servlet 클래스
        ↓

new HelloServlet()
= Tomcat이 생성한 Servlet 객체
        ↓

HTTP 요청이 오면
doGet(), doPost() 등을 호출

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[내일배움캠프] TIL(2) Spring 입문🌱]]></title>
            <link>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL2-Spring-%EC%9E%85%EB%AC%B8</link>
            <guid>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL2-Spring-%EC%9E%85%EB%AC%B8</guid>
            <pubDate>Fri, 02 Oct 2026 11:35:47 GMT</pubDate>
            <description><![CDATA[<h2 id="2-spring-data-jpa-기본">2. Spring Data JPA 기본</h2>
<h3 id="💚-다양한-요청-처리-방식">💚 다양한 요청 처리 방식</h3>
<h4 id="controller-vs-restcontroller"><code>@Controller</code> vs <code>@RestController</code></h4>
<p><code>SSR</code> 방식이 아닌 이상 Spring MVC 패턴에서 <code>Model</code>과 <code>View</code>의 역할을
FE가 처리함에 따라 <strong>BE는 데이터만</strong> 내려주게 된다. <em>- JSON 형식</em></p>
<ul>
<li><code>@Controller</code> : 전통적인 Spring MVC의 컨트롤러, <code>View</code>를 반환하기 위해 사용</li>
<li><code>@RestController</code> : <strong><code>@Controller</code> + <code>@ResponseBody</code></strong></li>
<li><code>@ResponeBody</code> : </li>
<li><em>Controller 메서드가 반환한 Java 객체를 HTTP 응답 Body*</em>에 담아서 보내는 어노테이션
Java 객체 → JSON</li>
</ul>
<p><strong>✨[참고] @RequesetBody</strong></p>
<ul>
<li><code>@RequestBody</code> : </li>
<li><em>HTTP 요청 Body에 담겨온 데이터를 Java 객체로 변환*</em>해서 받는 어노테이션
JSON → Java객체</li>
</ul>
<p><strong>✨[참고] HttpMessageConverter와 Jackson라이브러리</strong>
Spring에서 JSON ↔ Java 실제 변환 작업은 내부의 HttpMessageConverter가 하고,
JSON 변환에는 기본적으로 Jackson 라이브러리가 사용된다</p>
<h4 id="requestmapping">@RequestMapping</h4>
<ul>
<li><code>@RequestMapping</code> 은 특정 URL 요청을 Controller의 클래스/메서드에 연결해준다.</li>
</ul>
<p>사용법1</p>
<pre><code class="language-java">@ResController
@RequestMapping(&quot;/users)
public class UserController{

    @GetMapping    
    @PostMapping 
    @PutMapping 
    @PatchMapping
    @DeleteMapping

}
</code></pre>
<p>사용법2</p>
<pre><code class="language-java">@RestController
public class UserController{

    @RequestMapping(value = &quot;/users&quot;, method = RequestMethod.GET)
    public void getUser(){
        ...
    }
}</code></pre>
<h3 id="💚-데이터-전달-방식과-어노테이션">💚 데이터 전달 방식과 어노테이션</h3>
<h4 id="클라이언트-→-서버-데이터-전달-방식">클라이언트 → 서버 데이터 전달 방식</h4>
<table>
<thead>
<tr>
<th>데이터 전달 방식</th>
<th>어노테이션</th>
<th>주요 속성 / 특징</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>쿼리 파라미터(쿼리 스트링)</td>
<td><code>@RequestParam</code></td>
<td><code>required</code>: 필수 여부 지정<br><code>defaultValue</code>: 값이 없을 때 기본값 지정</td>
<td><code>/users?name=kim</code></td>
</tr>
<tr>
<td>경로 변수</td>
<td><code>@PathVariable</code></td>
<td>URL 경로의 값을 변수로 받음</td>
<td><code>/users/1</code></td>
</tr>
<tr>
<td>요청 본문</td>
<td><code>@RequestBody</code></td>
<td>요청 Body의 JSON 등을 Java 객체로 변환</td>
<td>JSON Body</td>
</tr>
<tr>
<td>폼 데이터</td>
<td><code>@ModelAttribute</code></td>
<td>폼 데이터를 Java 객체에 바인딩</td>
<td>HTML Form 데이터</td>
</tr>
</tbody></table>
<ul>
<li><code>@RequestParam</code>은 디폴트가 <code>required=true</code> 이므로 <code>false</code> 설정을 해주지 않으면 필수값</li>
</ul>
<p><strong>✨[참고] 쿼리 파라미터 vs 경로 변수</strong></p>
<ul>
<li>쿼리 파라미터(<code>@RequestParam</code>) :
URL 경로 <code>?</code> 뒤에 오는 <strong>조건값(선택적)</strong>
검색, 필터링, 정렬, 페이징 용도
예시 : <code>/users?id=1</code></li>
</ul>
<ul>
<li>경로 변수(<code>@PathVariable</code>) :
URL 경로 자체에 값이 포함되는 <strong>필수값</strong>
특정 리소스를 식별하기 위해 사용
예시 : <code>users/1</code></li>
</ul>
<h3 id="💚-dto를-record로-작성기">💚 DTO를 record로 작성기</h3>
<p><code>record</code> 는 <strong>데이터 전달 목적의 객체를 간결</strong>하게 만들기 위한 문법으로 DTO의 성질과 부합한다.
또한 <code>record</code>는 내부 필드가 <strong><code>private final</code></strong>이기 때문에 <strong>불변을 보장</strong>한다.</p>
<pre><code class="language-java">public record UserRequest(
    String name,
    int age
) { }</code></pre>
<p>위와 같이 <code>record</code>를 작성하면 자바가 자동으로 아래 기능을 만들어준다.</p>
<ul>
<li>생성자</li>
<li>getter 역할 메서드</li>
<li><code>equals()</code></li>
<li><code>hashCode()</code></li>
<li><code>toString()</code></li>
</ul>
<h4 id="✨참고--class-vs-record">✨[참고]  class vs record</h4>
<table>
<thead>
<tr>
<th>구분</th>
<th>class</th>
<th>record</th>
</tr>
</thead>
<tbody><tr>
<td>코드 길이</td>
<td>비교적 길음</td>
<td>매우 간결함</td>
</tr>
<tr>
<td>생성자</td>
<td>직접 작성 또는 Lombok 사용</td>
<td>자동 생성</td>
</tr>
<tr>
<td>Getter</td>
<td>직접 작성 또는 Lombok 사용</td>
<td>자동 생성</td>
</tr>
<tr>
<td>Setter</td>
<td>작성 가능</td>
<td>일반적으로 불가능</td>
</tr>
<tr>
<td>값 변경</td>
<td>가능</td>
<td>생성 후 변경 불가</td>
</tr>
<tr>
<td>equals/hashCode</td>
<td>직접 작성 또는 Lombok 사용</td>
<td>자동 생성</td>
</tr>
<tr>
<td>상속</td>
<td>가능</td>
<td>다른 클래스를 상속할 수 없음</td>
</tr>
<tr>
<td>주요 용도</td>
<td>일반적인 객체</td>
<td>데이터 전달용 객체</td>
</tr>
</tbody></table>
<hr>
<h3 id="💚-docker">💚 Docker</h3>
<p>도커는 소프트웨어 개발과 배포를 도와주는 <strong>컨테이너 기술</strong>로
<strong>애플리케이션을 빌드, 배포, 실행하는 과정을 쉽게 관리</strong>하게 해준다.</p>
<h4 id="container">Container</h4>
<ul>
<li><strong>애플리케이션과 그 실행 환경을 함께 패키징</strong>하여 어디서든 동일하게 실행될 수 있도록 하는 기술</li>
</ul>
<h4 id="docker-image--게임-cd">Docker Image = 게임 CD</h4>
<ul>
<li>코드, 라이브러리, 설정 등을 포함하고 있는 읽기 전용(Read-only) 템플릿 <strong><em>- 변경 불가</em></strong> </li>
<li>실행에 필요한 모든 것을 담고 있는 정적 파일(설계도)</li>
<li>‼️하나의 이미지로 여러 개의 컨테이너를 만들 수 있다.</li>
</ul>
<h4 id="docker-container--실행되고-있는-게임">Docker Container = 실행되고 있는 게임</h4>
<ul>
<li>도커 이미지를 <strong>실행(Run)한 상태</strong>로 <strong>독립된 격리 프로세스</strong></li>
<li>이미지를 실제로 실행한 인스턴스</li>
</ul>
<h4 id="docker-file">Docker File</h4>
<ul>
<li>도커 이미지를 생성하기 위한 설정 및 명령어 템플릿 파일</li>
</ul>
<pre><code class="language-text">Dockerfile 작성
   ↓
$ docker build
   ↓
Docker Image 생성
   ↓
$ docker run
   ↓
Docker Container 생성 및 실행
</code></pre>
<hr>
<h3 id="데이터베이스">데이터베이스</h3>
<h4 id="데이터-무결성data-integrity">데이터 무결성(Data Integrity)</h4>
<ul>
<li>엔티티 무결성<ul>
<li>각 행을 유일하게 식별할 수 있어야 한다.</li>
<li><code>PK</code>는 중복❌, NULL❌</li>
</ul>
</li>
<li>참조 무결성<ul>
<li>테이블 간 관계가 올바르게 유지되어야 한다.</li>
<li><code>FK</code>는 실제로 존재하는 <code>PK</code>값을 참조해야 한다.</li>
</ul>
</li>
<li>도메인 무결성<ul>
<li>컬럼에 들어가는 값은 <strong>정해진 데이터 타입, 범위, 조건</strong>을 만족해야 한다.</li>
</ul>
</li>
</ul>
<h4 id="drop-vs-delte-vs-truncate">DROP vs DELTE vs TRUNCATE</h4>
<hr>
<h3 id="3아키텍처-레이어">3아키텍처 레이어</h3>
<p>모든 데이터 클래스는 getter가 필수
스프링 내부적으로 객체를 조작할 때 getter를 사용</p>
<p>영속성 컨텍스트는 트랜잭션 내에서 동작
@Transactional 이 붙이면 그 내부 코드는 트랜잭션으로 관리 및 영속성 컨텍스트가 동작</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[내일배움캠프] TIL(1) Spring 입문🌱 ]]></title>
            <link>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL1-Spring-%EC%9E%85%EB%AC%B8</link>
            <guid>https://velog.io/@kiteof_park/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-TIL1-Spring-%EC%9E%85%EB%AC%B8</guid>
            <pubDate>Thu, 01 Oct 2026 11:59:40 GMT</pubDate>
            <description><![CDATA[<p><del>오리무중 내 인생 ,, 어쩌다보니 내배캠 단기 심화 과정까지 오게되었다 ,,
첫 번째 TIL  화이팅</del></p>
<h2 id="1-spring-시작하기">1. Spring 시작하기</h2>
<h3 id="💚-http">💚 HTTP</h3>
<h4 id="http란">HTTP란,</h4>
<p>클라이언트와 서버가 웹에서 데이터를 주고받기 위해 사용하는 프로토콜</p>
<h4 id="http-특징">HTTP 특징</h4>
<ul>
<li><strong>클라이언트-서버 구조</strong><ul>
<li>Request-Response 구조</li>
</ul>
</li>
<li><strong><code>Stateless</code>(무상태) 프로토콜</strong><ul>
<li>서버가 클라이언트의 상태를 보존❌</li>
<li>장점: 서버 확장성이 높음(스케일 아웃)</li>
<li>단점: 클라이언트가 추가 데이터 전송</li>
</ul>
</li>
<li><strong>비연결성</strong><ul>
<li>&#39;하나의 요청과 응답이 독립적인가?&#39;</li>
</ul>
</li>
<li><strong>HTTP 메세지</strong></li>
<li>단순함</li>
<li>확장 가능</li>
</ul>
<hr>
<h3 id="💚-servlet">💚 Servlet</h3>
<h4 id="servlet이란">Servlet이란,</h4>
<p>자바 진영에서 <strong>HTTP 요청을 받아 처리하고 HTTP 응답을 만들어주는 객체</strong>
예를 들어 <code>GET</code> 요청은 <code>HttpServlet</code>의 <code>doGet()</code> 메서드가 처리한다.</p>
<h4 id="servlet-역할">Servlet 역할</h4>
<ul>
<li>요청 데이터 읽기</li>
<li>필요한 로직 실행</li>
<li>응답 데이터 만들기</li>
</ul>
<p>즉, <strong>요청 처리 담당</strong></p>
<p><strong>💻 예제코드</strong></p>
<pre><code class="language-java">@WebServlet(&quot;/hello&quot;)
public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(
        HttpServletRequest req,
        HttpServletResponse resp
    ) throws IOException {

        resp.getWriter().print(&quot;Hello&quot;);
    }
}</code></pre>
<ul>
<li><code>@WebServlet</code> : 특정 URL 요청을 어떤 Servlet 클래스가 처리할지 연결해주는 어노테이션</li>
<li><code>HttpServletRequest</code> : 클라이언트가 서버로 보낸 HTTP 요청 정보를 담고 있는 객체</li>
<li><code>HttpServletResponse</code> :  서버가 클라이언트에게 보낼 HTTP 응답을 만들기 위한 객체</li>
</ul>
<h4 id="servlet-container란">Servlet Container란,</h4>
<p>Servlet을 실행하고 관리해주는 환경으로 대표적으로 <code>Tomcat</code>이 있다.</p>
<h4 id="servlet-container의-역할">Servlet Container의 역할</h4>
<ul>
<li>HTTP 요청 받기</li>
<li>URL에 맞는 서블릿 찾기</li>
<li><code>HttpServletRequest</code>, <code>HttpServletResponse</code> 객체 생성</li>
<li>메서드 호출(GET 요청이면 <code>doGet();</code>)</li>
<li>서블릿 객체 생성 및 생명주기 관리</li>
<li>서블릿이 만든 응답을 클라이언트에게 전송</li>
</ul>
<h4 id="동작-순서">동작 순서</h4>
<p>클라이언트가 HTTP 요청을 보내면 서블릿 컨테이너가 요청을 받은 뒤, 
해당 요청을 처리할 서블릿을 찾아 실행한다.</p>
<pre><code class="language-text">Client
  ↓
HTTP Request
  ↓
Tomcat(Servlet Container)
  ↓
Servlet 찾기, 실행
  ↓
HTTP Response</code></pre>
<p>✨ <strong>Servlet은 개발자가 아닌 Servelt Container가 Servlet의 실행과 생명주기를 관리</strong>한다.</p>
<h4 id="servletcomponentscan">@ServletComponentScan</h4>
<p>스프링 부트에서 서블릿 관련 어노테이션이 붙은 클래스를 찾아 
<code>Tomcat</code>같은 서블릿 컨테이너에 등록해주는 어노테이션</p>
<p><strong>💻 예제코드</strong></p>
<pre><code class="language-java">@SpringBootApplication
@ServletComponentScan
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}</code></pre>
<p>스프링 부트가 해당 패키지와 하위 패키지를 스캔하면서</p>
<ul>
<li><code>@WebServlet</code></li>
<li><code>@WebFilter</code></li>
<li><code>@WebListener</code></li>
</ul>
<p>가 붙은 클래스를 찾아 <strong>서블릿 컨테이너에 등록</strong>한다</p>
<hr>
<h3 id="💚-csr-ssr-seo">💚 CSR, SSR, SEO</h3>
<h4 id="csrclient-side-rendering">CSR(Client Side Rendering)</h4>
<pre><code class="language-text">브라우저 요청
    ↓
서버에서 HTML + JavaScript 전달
    ↓
브라우저에서 JavaScript 실행
    ↓
API를 통해 필요한 데이터 요청
    ↓
화면 렌더링
</code></pre>
<h4 id="ssrserver-side-rendering">SSR(Server Side Rendering)</h4>
<p><strong>⚙️ 동작 방식</strong></p>
<pre><code class="language-text">브라우저 요청
    ↓
서버에서 데이터 조회
    ↓
서버에서 HTML 생성
    ↓
완성된 HTML 전달
    ↓
브라우저에서 화면 표시
</code></pre>
<hr>
<h3 id="💚-spring-mvc">💚 Spring MVC</h3>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[[클린 아키텍처] 1부 소개]]></title>
            <link>https://velog.io/@kiteof_park/%ED%81%B4%EB%A6%B0-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-1%EB%B6%80-%EC%86%8C%EA%B0%9C</link>
            <guid>https://velog.io/@kiteof_park/%ED%81%B4%EB%A6%B0-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-1%EB%B6%80-%EC%86%8C%EA%B0%9C</guid>
            <pubDate>Mon, 15 Jun 2026 17:33:20 GMT</pubDate>
            <description><![CDATA[<h2 id="1장-설계와-아키텍처란">1장. 설계와 아키텍처란?</h2>
<h2 id="2장-두-가지-가치에-대한-이야기">2장. 두 가지 가치에 대한 이야기</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[[마이밀크] 스탬프 좀 찍어다오]]></title>
            <link>https://velog.io/@kiteof_park/%EB%A7%88%EC%9D%B4%EB%B0%80%ED%81%AC-%EC%8A%A4%ED%83%AC%ED%94%84-%EC%A2%80-%EC%B0%8D%EC%96%B4%EB%8B%A4%EC%98%A4</link>
            <guid>https://velog.io/@kiteof_park/%EB%A7%88%EC%9D%B4%EB%B0%80%ED%81%AC-%EC%8A%A4%ED%83%AC%ED%94%84-%EC%A2%80-%EC%B0%8D%EC%96%B4%EB%8B%A4%EC%98%A4</guid>
            <pubDate>Wed, 10 Jun 2026 18:45:39 GMT</pubDate>
            <description><![CDATA[<p>쉬었음 청년은 매주 커피를 말아서 밥벌이를 하고 있다 ..
근데 브랜드 컨셉인지 뭔지 <strong>아직도 지류 쿠폰에 일일히 스탬프</strong>를 찍어주는데
굉장히 .. 굉장히.. 귀찮다</p>
<p>포트폴리오 프로젝트도 부족하고 일상에서 아이디어를 얻은 김에
<code>모바일 오더 앱 서비스</code>를 만들어서 DX를 해보고자 한다.</p>
<p>이것도 미루다 미루다 새벽에 노트북 토닥이는 김에
메인 로고, 서브 로고, 앱 아이콘, 컬러 팔레트를 GPT로 뽑아냈다.</p>
<p>이미지라도 올려서 서비스 첫 포스팅을 게시하고 열심히 개발해보좌 ~..
무기력 우울증 쉬었음 청년의 취뽀를 위하여 !! 💚💛🧡🤍</p>
<h3 id="🥛메인-로고">🥛메인 로고</h3>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/061d44a1-01c4-48ea-8e58-5bf504c2405b/image.png" width = 60%>


<h4 id="서브로고">서브로고</h4>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/c597ab0f-864f-4865-ad94-cb00dfe88fc6/image.png" width = 50%>


<h4 id="앱-아이콘">앱 아이콘</h4>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/4fcc391b-4f13-4f67-9d7c-5d672eb59c84/image.png" width = 50%>



<h3 id="🎨컬러-팔레트">🎨컬러 팔레트</h3>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/e35d1a44-5ebe-48e0-ab1b-a507d882c2eb/image.png" width = 80%>

<h4 id="hex-코드">HEX 코드</h4>
<table>
<thead>
<tr>
<th>역할</th>
<th>컬러명</th>
<th>HEX</th>
</tr>
</thead>
<tbody><tr>
<td>Primary</td>
<td>Deep Forest</td>
<td><code>#0F5A40</code></td>
</tr>
<tr>
<td>Secondary</td>
<td>Brand Green</td>
<td><code>#1E7B57</code></td>
</tr>
<tr>
<td>Accent</td>
<td>Fresh Sage</td>
<td><code>#5E9F78</code></td>
</tr>
<tr>
<td>Muted</td>
<td>Soft Sage</td>
<td><code>#B7C8B3</code></td>
</tr>
<tr>
<td>Background</td>
<td>Milk Cream</td>
<td><code>#F2EFE4</code></td>
</tr>
</tbody></table>
<h4 id="css-변수">CSS 변수</h4>
<pre><code class="language-css">:root {
  --color-primary: #0F5A40;
  --color-secondary: #1E7B57;
  --color-accent: #5E9F78;
  --color-muted: #B7C8B3;
  --color-background: #F2EFE4;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[따맵] 헥사고날 아키텍처와 도메인 주도 설계(Hexagonal Architecture & Domain-Driven Design)]]></title>
            <link>https://velog.io/@kiteof_park/%EB%94%B0%EB%A7%B5-%ED%97%A5%EC%82%AC%EA%B3%A0%EB%82%A0-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90%EC%99%80-%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%A3%BC%EB%8F%84-%EC%84%A4%EA%B3%84Hexagonal-Architecture-Domain-Driven-Design</link>
            <guid>https://velog.io/@kiteof_park/%EB%94%B0%EB%A7%B5-%ED%97%A5%EC%82%AC%EA%B3%A0%EB%82%A0-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90%EC%99%80-%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%A3%BC%EB%8F%84-%EC%84%A4%EA%B3%84Hexagonal-Architecture-Domain-Driven-Design</guid>
            <pubDate>Wed, 03 Sep 2025 18:34:35 GMT</pubDate>
            <description><![CDATA[<p>따맵 백엔드를 구현하고 코드를 통합하면서 클로드가 헥사고날과 DDD 방향으로
코드를 통합한 잇슈 .. 패키지 구조를 하나도 못알아보겠는 까막눈 잇슈 ..</p>
<h3 id="헥사고날-아키텍처와-ddd">헥사고날 아키텍처와 DDD</h3>
<p>헥사고날 아키텍처와 DDD는 <strong>둘 다 도메인(비지니스 로직)을 중심에 둔다는 공통점</strong>이 있지만,
헥사고날 아키텍처는 <strong>&quot;시스템을 어떻게 계층화하고 의존성을 배치할까?&quot;</strong>에 초점
DDD는 <strong>&quot;도메인을 어떻게 모델링할까?&quot;</strong>에 초점</p>
<h1 id="헥사고날-아키텍처">헥사고날 아키텍처</h1>
<h2 id="hexagonal-architecture">Hexagonal Architecture</h2>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/14e80db2-44ca-4013-bfe1-1f278c36ed26/image.png" width = 90%>


<h2 id="🍀-헥사고날-아키텍처의-필요성">🍀 헥사고날 아키텍처의 필요성</h2>
<p>기존에 주로 개발하던 계층형 구조는 단순하고 직관적이다.</p>
<ul>
<li><code>Controller</code> : 외부 요청을 받는 역할</li>
<li><code>Service</code> : 비지니스 로직</li>
<li><code>Repository</code> : DB 접근</li>
</ul>
<p>하지만 계층형 구조의 문제점은 <strong>의존성 방향</strong>에 있다.
<code>Controller</code> → <code>Service</code> → <code>Repository</code> 순서로
아래로 내려가야 하고, <code>Service</code> 레이어는 DB같은 <strong>외부 인프라에 강하게 의존</strong>하게 된다.
따라서 <strong>비지니스 로직이 DB나 프레임워크에 종속</strong>되는 상황이 발생할 수 있다 ! !</p>
<h2 id="🍀-헥사고날-아키텍처의-핵심-아이디어">🍀 헥사고날 아키텍처의 핵심 아이디어</h2>
<ul>
<li><strong>비지니스 로직(=도메인)을 중심</strong>에 둔다.</li>
<li>DB, UI, 외부 API 등은 <strong>바깥쪽</strong>에 둔다.</li>
<li>도메인이 바깥쪽 인프라에 <strong>직접 의존하지 않는다.</strong></li>
</ul>
<p>따라서 <strong>어떤 프레임워크나 DB를 쓰더라도 비지니스 로직은 흔들리지 않는게 핵심</strong>이다.</p>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/de07d9aa-7b7c-438a-9093-0295f28b3175/image.png">

<ul>
<li><strong>[규칙서]</strong> <code>Domain</code> : 순수한 핵심 규칙(비지니스 로직), DB/웹/프레임워크를 모름</li>
<li><strong>[지시자]</strong> <code>Application</code> : 유스케이스(Service 역할), <code>Domain</code>을 이용해 시나리오 실행</li>
<li><strong>[계약서]</strong> <code>Port</code> : Application이 외부에 기대는 인터페이스(Ex. UserRepository)</li>
<li><strong>[실행자]</strong> <code>Adapter</code> : Port를 구현한 구체체(Ex. JPA 기반 JpaUserRepository)</li>
</ul>
<p>즉, <strong>헥사고날 아키텍처는 비지니스 로직을 외부 기술에서 독립시키는 구조</strong></p>
<hr>
<h1 id="도메인-주도-설계">도메인 주도 설계</h1>
<h2 id="ddd-domain-driven-design">DDD, Domain-Driven Design</h2>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/e8ac7cad-fa13-4548-b4c2-d868b90173b4/image.png">

<h2 id="🍀-ddd의-필요성">🍀 DDD의 필요성</h2>
<p>보통 개발을 하면 발생하는 문제점:</p>
<ul>
<li>코드가 기능 단위로만 작성 → 시간이 지나면 스파게티 코드</li>
<li>비지니스 규칙이 흩어져서 어디서 처리되는지 불명확</li>
<li>요구사항 변경 시 수정해야 할 코드가 여러 군데 </li>
</ul>
<p><strong>DDD는 도메인(비지니스 문제)를 중심에 두고, 이를 코드에 직접 반영하려는 접근</strong>
(뭔 소릴까 ..?)</p>
<h2 id="🍀-ddd의-핵심-아이디어">🍀 DDD의 핵심 아이디어</h2>
<ul>
<li><strong>도메인에 집중한다.</strong><ul>
<li>도메인 = 해결하려는 문제 영역</li>
<li>Ex. 따맵 : 자전거, 대여소, 사용자 / 은행 시스템 : 계좌, 송금, 대출</li>
</ul>
</li>
<li>유비쿼터스 언어<ul>
<li>개발자, 기획자, 현업 담당자 모두 같은 용어를 사용</li>
<li>&#39;결제 승인&#39;이라는 말을 코드에도 그대로 <code>approvePayment()</code>로 반영</li>
</ul>
</li>
</ul>
<h2 id="🍀-ddd의-기본-빌딩-블록">🍀 DDD의 기본 빌딩 블록</h2>
<p>DDD에서는 코드를 도메인 개념에 맞게 나눈다.</p>
<h3 id="1-entity-엔티티">(1) Entity (엔티티)</h3>
<ul>
<li>고유한 <code>ID</code>로 구별되는 객체</li>
<li>값이 변해도 동일성을 유지</li>
<li>Ex. <code>User(id=1, name=&quot;의연&quot;)</code> → 이름 바뀌어도 id=1이면 같은 User</li>
</ul>
<h3 id="2-value-object-값-객체">(2) Value Object (값 객체)</h3>
<ul>
<li>속성 값 자체로만 의미가 있는 객체 (<code>ID</code> 없음❌)</li>
<li>불변(immutable)으로 다루는 게 일반적</li>
<li>Ex. <code>Money(1000, &quot;KRW&quot;)</code>, <code>Email(&quot;velog@gmail.com&quot;)</code></li>
</ul>
<h3 id="3-aggregate">(3) Aggregate</h3>
<ul>
<li>Entity + VO 묶음 → 하나의 비즈니스 단위</li>
<li>항상 <strong>일관성</strong>을 유지해야 함</li>
<li>대표 엔티티 = Aggregate Root</li>
<li>Ex. <code>Order (root)</code> → <code>OrderItem(entity)</code>, <code>Money(VO)</code></li>
</ul>
<h3 id="4-repository">(4) Repository</h3>
<ul>
<li>Aggregate 저장/조회 담당</li>
<li>DB 접근을 추상화 (interface)</li>
<li>Ex. OrderRepository.save(order)</li>
</ul>
<h3 id="5-domain-service">(5) Domain Service</h3>
<ul>
<li>특정 Entity 하나에 속하지 않는 비즈니스 규칙을 담는 곳</li>
<li>Ex. 환율 계산, 결제 승인</li>
</ul>
<p>어렵땅 ...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[매일메일CS] 외부 API 장애 대응 전략 - 타임아웃, 벌크헤드, 서킷 브레이커]]></title>
            <link>https://velog.io/@kiteof_park/%EB%A7%A4%EC%9D%BC%EB%A9%94%EC%9D%BCCS-%EC%99%B8%EB%B6%80-API-%EC%9E%A5%EC%95%A0-%EB%8C%80%EC%9D%91-%EC%A0%84%EB%9E%B5-%ED%83%80%EC%9E%84%EC%95%84%EC%9B%83-%EB%B2%8C%ED%81%AC%ED%97%A4%EB%93%9C-%EC%84%9C%ED%82%B7-%EB%B8%8C%EB%A0%88%EC%9D%B4%EC%BB%A4-c9ytt3i4</link>
            <guid>https://velog.io/@kiteof_park/%EB%A7%A4%EC%9D%BC%EB%A9%94%EC%9D%BCCS-%EC%99%B8%EB%B6%80-API-%EC%9E%A5%EC%95%A0-%EB%8C%80%EC%9D%91-%EC%A0%84%EB%9E%B5-%ED%83%80%EC%9E%84%EC%95%84%EC%9B%83-%EB%B2%8C%ED%81%AC%ED%97%A4%EB%93%9C-%EC%84%9C%ED%82%B7-%EB%B8%8C%EB%A0%88%EC%9D%B4%EC%BB%A4-c9ytt3i4</guid>
            <pubDate>Fri, 01 Aug 2025 07:45:38 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.maeil-mail.kr/question/74">동기 방식으로 외부 서비스를 호출할 때 외부 서비스 장애가 나면 어떻게 조치할 수 있나요?</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[따맵] #1. 따릉이 대여소 저장 및 스케줄링]]></title>
            <link>https://velog.io/@kiteof_park/%EB%94%B0%EB%A7%B5-1.-%EB%94%B0%EB%A6%89%EC%9D%B4-%EB%8C%80%EC%97%AC%EC%86%8C-%EC%A0%80%EC%9E%A5-%EB%B0%8F-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81-5eusbawj</link>
            <guid>https://velog.io/@kiteof_park/%EB%94%B0%EB%A7%B5-1.-%EB%94%B0%EB%A6%89%EC%9D%B4-%EB%8C%80%EC%97%AC%EC%86%8C-%EC%A0%80%EC%9E%A5-%EB%B0%8F-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81-5eusbawj</guid>
            <pubDate>Thu, 31 Jul 2025 11:54:48 GMT</pubDate>
            <description><![CDATA[<h2 id="task">Task</h2>
<ul>
<li>✅ 따릉이 대여소 API 호출 → DB 저장</li>
<li>✅ 신규 및 폐쇄 대여소를 고려해 하루 1회 스케줄링</li>
</ul>
<hr>
<h2 id="외부-api를-호출하려면">외부 API를 호출하려면?</h2>
<p>우선 따릉이 대여소 API를 호출해 우리쪽 DB에 저장하는게 첫 번째 목표였다.
외부 API를 호출하는 방법은 대표적으로 5가지가 있는데,
그 중에서 가장 권장되는 방식인 <code>WebClient</code>를 사용했다.</p>
<p>✨ <a href="https://velog.io/@kiteof_park/Spring-Boot-%EC%99%B8%EB%B6%80-API%EB%A5%BC-%ED%98%B8%EC%B6%9C%ED%95%A0-%EB%95%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-HTTP-Client">외부 API를 호출할 때 사용하는 HTTP Client 정리 포스팅</a></p>
<h3 id="1-applicationyml-작성">1. application.yml 작성</h3>
<p><code>application.yml</code>은 <strong>스프링 부트 애플리케이션이 동작할 때 필요한 설정 값을 선언</strong>하는 곳으로,<br>따릉이 대여소 API를 호출하는 <code>baseUrl</code>과 <code>key</code> 작성했다.
(이 외에 서버, DB, JPA, 로그 설정 등을 <code>yml</code>에 작성한다.)</p>
<pre><code class="language-yml">bikeseoul:
  static:
    key: ${bikeseoul.static.key}
    baseUrl: http://openapi.seoul.go.kr:8088/{apiKey}/json/tbCycleStationInfo

  realtime:
    key: ${bikeseoul.realtime.key}
    baseUrl: http://openapi.seoul.go.kr:8088/{apiKey}/json/bikeList
</code></pre>
<p>✨ 발급받은 <code>key</code>는 <code>application-secret.yml</code>에 별도 저장</p>
<h3 id="2-configurationproperties">2. @ConfigurationProperties</h3>
<p><code>@ConfigurationProperties</code> 어노테이션은 <code>application.yml</code>에 정의된 설정 값을
<strong>자바 객체의 필드로 자동 바인딩</strong>해주는 어노테이션이다.</p>
<p>즉, <code>yml</code>의 설정 값 → <code>@ConfigurationProperties</code>가 붙은 클래스의 객체로 매핑
→ 필요한 클래스(외부 API를 호출하는 클래스)에서 주입받아 사용</p>
<pre><code class="language-java">@Component
@ConfigurationProperties(prefix = &quot;bikeseoul.static&quot;)
@Getter
@Setter
public class StationProperties {
    private String key;
    private String baseUrl;
}</code></pre>
<p>✨ 추후에 <code>StationApiClient</code>에서 <code>StationProperties</code>를 주입받아 외부 API 호출에 사용</p>
<h3 id="3-webclient-설정">3. WebClient 설정</h3>
<p>외부 API를 호출하기 위해서는 다른 서버로 HTTP 요청을 보내고 응답을 받아오는
라이브러리가 필요한데, 그 중 하나가 <code>WebClient</code>다. </p>
<p>✨ 스프링에서는 <strong>재사용 가능한 객체(빈)는 직접 생성하지 않고,
<code>@Configuration</code>에서 설정해놓고 필요할 때 의존성 주입을 통해 사용</strong>한다.</p>
<pre><code class="language-java">@Configuration        // 설정 클래스 명시
public class StationConfig {

    @Bean            // 스프링 빈 객체 등록 대상
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder()
                .exchangeStrategies(ExchangeStrategies.builder()
                        .codecs(configurer -&gt; configurer
                                .defaultCodecs()
                                .maxInMemorySize(10 * 1024 * 1024)) // 10MB
                        .build());
    }
}</code></pre>
<h3 id="4-외부-api-응답-dto-작성">4. 외부 API 응답 DTO 작성</h3>
<p>외부 API를 호출한 뒤에 받는 응답</p>
<h3 id="5-외부-api-호출-클라이언트-구현">5. 외부 API 호출 클라이언트 구현</h3>
<h3 id="6-db-저장">6. DB 저장</h3>
<h2 id="스케줄링">스케줄링</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[[매일메일CS] 동시성 제어와 공유 락(Shared Lock), 배타 락(Exclusive), 데드락(Deadlock) ]]></title>
            <link>https://velog.io/@kiteof_park/%EB%A7%A4%EC%9D%BC%EB%A9%94%EC%9D%BCCS-%EA%B3%B5%EC%9C%A0-%EB%9D%BD%EA%B3%BC-%EB%B0%B0%ED%83%80-%EB%9D%BD-hnkkvcs1</link>
            <guid>https://velog.io/@kiteof_park/%EB%A7%A4%EC%9D%BC%EB%A9%94%EC%9D%BCCS-%EA%B3%B5%EC%9C%A0-%EB%9D%BD%EA%B3%BC-%EB%B0%B0%ED%83%80-%EB%9D%BD-hnkkvcs1</guid>
            <pubDate>Thu, 31 Jul 2025 11:18:24 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.maeil-mail.kr/question/80">공유 락과 배타 락에 대해서 설명해주세요.</a></p>
<h1 id="동시성-제어와-락lock">동시성 제어와 락(Lock)</h1>
<h2 id="♻️동시성-제어concurrency-control">♻️동시성 제어(Concurrency Control)</h2>
<ul>
<li>동시성 제어란 <strong>여러 트랜잭션에 동시에 같은 데이터베이스에 접근</strong>할 때,</li>
<li><em>데이터의 정합성과 일관성을 보장*</em>하는 기법</li>
<li>데이터베이스는 성능을 위해 동시 처리(병행 실행)를 최대한 허용하지만,</li>
<li><em>동시에 실행되면 문제가 발생*</em>할 수 있음</li>
</ul>
<h3 id="대표적인-동시성-문제1---dirty-read">대표적인 동시성 문제1 <em>- Dirty Read</em></h3>
<ul>
<li>다른 트랜잭션이 <strong>아직 커밋하지 않은 변경 데이터를 읽음</strong></li>
<li>만약 T1이 롤백한다면, T2가 읽은 <code>var = 100</code>은 존재하지 않는 값이 되버림</li>
</ul>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/d0ce4a35-5fce-4f48-b6c2-04c42f73bb25/image.jpg">


<h3 id="대표적인-동시성-문제2---non-repeatable-read">대표적인 동시성 문제2 <em>- Non-Repeatable Read</em></h3>
<ul>
<li>한 트랜잭션에서 <strong>같은 데이터를 두 번 읽을 때 값이 다름</strong></li>
<li>첫 번째 <code>SELECT</code>와 두 번째 <code>SELECT</code> 사이에 다른 트랜잭션이 값을 변경</li>
</ul>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/a9014ccc-28e4-4372-85fd-41aeec6de794/image.jpg">


<h3 id="대표적인-동시성-문제3---phantom-read">대표적인 동시성 문제3 <em>- Phantom Read</em></h3>
<ul>
<li>조건에 맞는 행의 개수나 집합이 바뀜</li>
<li>첫 번째 <code>SELECT</code> 후 다른 트랜잭션이 <code>INSERT</code>하여 두 번째 <code>SELECT</code> 결과가 달라짐</li>
</ul>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/1c73aa7a-77ec-4c60-b17c-be83510a978c/image.jpg">


<h3 id="락lock의-필요성">락(Lock)의 필요성</h3>
<ul>
<li><strong>트랜잭션 간 동시 접근으로 인한 데이터 충돌을 방지</strong></li>
<li>DBMS는 <strong>동시성과 일관성 사이의 균형</strong>을 유지 <ul>
<li>락을 너무 강하게 걸면 → 동시성이 떨어져 성능 저하</li>
<li>락을 너무 약하게 걸면 → 데이터 정합성이 깨짐</li>
</ul>
</li>
<li>필요한 데이터 범위와 작업 성격에 따라 락을 선택적으로 걸어줌</li>
</ul>
<h2 id="🔒락의-두-가지-기본-형태">🔒락의 두 가지 기본 형태</h2>
<h3 id="공유-락s-lock-shared-lock">공유 락(S Lock, Shared Lock)</h3>
<ul>
<li><strong>읽기 전용 락</strong></li>
<li><strong>여러 트랜잭션이 동시에 같은 데이터에 공유 락</strong>을 걸 수 있음</li>
<li>공유 락이 걸린 데이터에 쓰기(<code>UPDATE</code>/<code>DELETE</code>)는 불가능</li>
<li>주로 <code>SELECT .. LOCK IN SHARE MODE</code> 같은 읽기 작업에서 사용</li>
</ul>
<pre><code class="language-SQL">T1: SELECT * FROM account WHERE id = 1 LOCK IN SHARE MODE;      -- S Lock 획득
T2: SELECT ... LOCK IN SHARE MODE;                              -- 가능
T3: UPDATE account SET balance = 0 WHERE id = 1;                 -- 대기</code></pre>
<h3 id="쓰기-락x-lock-exclusive-lock">쓰기 락(X Lock, Exclusive Lock)</h3>
<ul>
<li><strong>읽기/쓰기 모두 차단하는 락</strong></li>
<li>해당 데이터는 <strong>오직 락을 가진 트랜잭션만</strong> 읽고 쓸 수 있음</li>
<li>주로 <code>UPDATE</code>, <code>DELETE</code>, <code>INSERT</code>, 또는 <code>SELECT ... FOR UPDATE</code> 시 걸림</li>
<li>데이터 정합성을 위해 읽기조차 막음(Dirty Read 방지)</li>
</ul>
<p>💡<code>SELECT .. FOR UPDATE</code>는 트랜잭션에서 <code>SELECT</code>한 행에 대해 배타 락을 거는 문법으로
<strong>읽는 동시에 그 행을 수정할 권리를 독점</strong>(즉, SELECT 한 뒤에 UPDATE 할거야!)</p>
<pre><code class="language-SQL">T1: UPDATE account SET balance = 0 WHERE id = 1;                   -- X Lock 획득
T2: SELECT ... LOCK IN SHARE MODE;                                 -- 대기
T3: UPDATE account SET balance = 100 WHERE id = 1;                 -- 대기
</code></pre>
<h2 id="⏳-락과-데드락의-관계">⏳ 락과 데드락의 관계</h2>
<ul>
<li>락(Lock)은 동시성 제어를 위해 필요하지만, 잘못 사용되면</li>
<li><em>서로가 서로의 락을 기다리는 교착 상태(Deadlock)*</em>를 만들 수 있음</li>
<li>데드락은 <strong>두 개 이상의 트랜잭션이 서로가 보유한 자원을 기다리며 무한 대기에 빠지는 상황</strong></li>
</ul>
<pre><code>T1: account.id = 1 행의 S Lock → 그 다음 account.id = 2 행을 X Lock 하려고 함
T2: account.id = 2 행의 S Lock → 그 다음 account.id = 1 행을 X Lock 하려고 함
</code></pre><h3 id="데드락-해결예방-방법1---트랜잭션-설계-단계에서-예방">데드락 해결/예방 방법1 <em>- 트랜잭션 설계 단계에서 예방</em></h3>
<ul>
<li><strong>항상 동일한 순서로 자원을 잠금(락 획득 순서를 일관적으로 정해둠)</strong>
(Ex. 모든 트랜잭션에서 1번 데이터, 2번 데이터 순으로 락을 획득)</li>
<li>트랜잭션을 최소화 해 락을 오래 점유하지 못하도록 함</li>
<li>조건절 최적화, 범위 줄이기를 통해 불필요한 락 범위 줄이기</li>
</ul>
<h3 id="데드락-해결예방-방법2---db-설정으로-완화">데드락 해결/예방 방법2 <em>- DB 설정으로 완화</em></h3>
<ul>
<li><strong>Lock Timeout 설정</strong> : 일정 시간 기다렸다가 락이 안풀리면 ROLLBACK</li>
<li><strong>격리 수준 낮추기</strong> : READ COMMITED나 MVCC를 활용해 불필요한 대기 감소</li>
</ul>
<h3 id="데드락-해결예방-방법3---데드락-감지자동-해제">데드락 해결/예방 방법3 <em>- 데드락 감지&amp;자동 해제</em></h3>
<ul>
<li><code>InnoDB</code>, <code>PostgreSQL</code>, <code>Oracle</code> 등 대부분 DB는 주기적으로 <strong>데드락 감지 스레드</strong>가 돌아감</li>
<li>감지 시 둘 중 하나의 트랜잭션을 강제 ROLLBACK</li>
</ul>
<h3 id="next-step">NEXT STEP</h3>
<p>트랜잭션에 대해서 더 깊게 학습이 필요하다 ..!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[매일메일CS] 데이터베이스 커넥션 풀(Connection Pool)]]></title>
            <link>https://velog.io/@kiteof_park/%EB%A7%A4%EC%9D%BC%EB%A9%94%EC%9D%BCCS-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%BB%A4%EB%84%A5%EC%85%98-%ED%92%80Connection-Pool-zgkzmqp1</link>
            <guid>https://velog.io/@kiteof_park/%EB%A7%A4%EC%9D%BC%EB%A9%94%EC%9D%BCCS-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%BB%A4%EB%84%A5%EC%85%98-%ED%92%80Connection-Pool-zgkzmqp1</guid>
            <pubDate>Thu, 31 Jul 2025 11:17:33 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.maeil-mail.kr/question/88">데이터베이스 커넥션 풀(Connection Pool)을 사용하지 않으면 어떤 문제가 발생할 수 있나요?</a></p>
<h2 id="🔗-데이터베이스-커넥션">🔗 데이터베이스 커넥션</h2>
<ul>
<li>서버는 DB와 통신할 때 <code>Connection</code> 이라는 <strong>연결 통로</strong>가 필요하다.</li>
<li>즉, 커넥션은 <strong>애플리케이션 서버와 데이터베이스 사이의 통신선</strong></li>
<li>커넥션을 통해 SQL 쿼리를 전송하고 결과를 받아온다.</li>
<li>즉 <strong>애플리케이션과 DB 사이의 연결 세션으로, 쿼리를 보내고 응답을 받기 위한 통신 통로</strong></li>
<li>하나의 커넥션은 DB와의 <strong>TCP 커넥션 + 세션 컨텍스트</strong>를 의미한다.<strong>(TCP + DB 세션 연결)</strong></li>
<li><strong>커넥션을 열고 닫는 데는 네트워크 연결, 인증, 세션 설정 등의 작업으로 비용이 크다.</strong></li>
</ul>
<h3 id="커넥션의-특징과-문제점">커넥션의 특징과 문제점</h3>
<p><strong>1. 비싼 비용💸</strong></p>
<ul>
<li>매 요청 마다 커넥션을 열고 닫으면, DB와 네트워크에 부하가 크다.</li>
</ul>
<p><strong>2. 제한된 커넥션 수🚫</strong></p>
<ul>
<li>DB 서버는 동시에 처리할 수 있는 커넥션 수가 정해져 있어,
웹 서버 트래픽이 몰릴 때 커넥션이 부족한 문제가 발생할 수 있다.
(<code>Connection refused</code>, <code>Too many connections</code>)</li>
</ul>
<h2 id="🔗-커넥션-풀">🔗 커넥션 풀</h2>
<p><img src="https://velog.velcdn.com/images/kiteof_park/post/bf88f3c7-fc2e-4b63-864d-5896d3f62769/image.png" alt=""></p>
<ul>
<li>커넥션의 특징/문제점으로 인해 필요한 개념이 <code>Connection Pool</code>이다.</li>
<li>커넥션 풀은 <strong>미리 커넥션을 만들어두고 재사용</strong>해서 <strong>커넥션 생성/삭제 비용을 줄이고,
커넥션 수를 안정적으로 관리</strong>하는 방식이다.</li>
<li>대표적인 구현체로는 Java/Spring의 <code>HikariCP</code> <em>- 자주봤죵~?</em></li>
</ul>
<h3 id="커넥션-풀-주요-설정">커넥션 풀 주요 설정</h3>
<ul>
<li><code>maximumPoolSize</code> : 풀에 유지할 최대 커넥션 수</li>
<li><code>minimumIdle</code> : 유휴 상태로 유지할 커넥션 수</li>
<li><code>connectionTimeout</code> : 커넥션을 못 얻어올 떄까지 기다릴 최대 시간</li>
<li><code>idleTimeout</code> : 유휴 커넥션을 얼마나 오래 유지할지</li>
<li><code>maxLifetime</code> : 커넥션 객체가 살아있을 수 있는 최대 시간</li>
</ul>
<p>💡 <strong>커넥션 유휴 상태</strong>란 DB 커넥션이 열려있지만, 아무 작업도 하지 않는 <strong>대기 상태</strong></p>
<h3 id="커넥션-풀-작동-방식">커넥션 풀 작동 방식</h3>
<ul>
<li>서버 시작 시 DB 커넥션을 미리 일정 개수 열어둠</li>
<li>HTTP 요청이 들어오면 풀에서 커넥션을 꺼내서 사용</li>
<li>처리 후 커넥션을 닫는게 아니라 <strong>풀에 반환</strong></li>
</ul>
<h3 id="커넥션-누수">커넥션 누수</h3>
<ul>
<li>커넥션을 반환하지 않으면 누수가 발생해 커넥션 고갈 문제 발생</li>
<li>이슈 발생 시 <code>Hikari Pool - Connection timeout</code>, <code>connection leak detected</code> 경고</li>
</ul>
<h2 id="🍀-커넥션-풀을-사용하지-않는다면">🍀 커넥션 풀을 사용하지 않는다면?</h2>
<h3 id="1-매-요청마다-커넥션-생성종료-→-성능저하">1. 매 요청마다 커넥션 생성/종료 → 성능저하</h3>
<ul>
<li><strong>커넥션 생성 과정</strong>은<ol>
<li><code>TCP</code> 소켓 연결</li>
<li><code>DB</code> 인증</li>
<li>세션 초기화</li>
</ol>
</li>
<li>이 과정은 수 ms ~ 수백 ms 걸릴 수 있는 과정</li>
<li><strong>매 HTTP 요청마다 이 과정을 반복하면 응답 속도가 급격히 느려짐</strong></li>
<li><strong>TPS가 떨어져서 같은 서버 성능으로 처리할 수 있는 요청 수 감소</strong></li>
</ul>
<h3 id="2-db-부하-증가">2. DB 부하 증가</h3>
<ul>
<li>매번 커넥션을 새로 만들면 DB 서버는 계속 새 세션을 생성/삭제해야 함</li>
<li>세션 생성/삭제도 DB의 CPU, 메모리 자원을 많이 소모</li>
<li><strong>동시에 수백~수천 요청이 들어오면 DB가 세션 생성 처리만 하다가 병목 발생</strong></li>
</ul>
<h3 id="3-커넥션-폭주--제한-초과">3. 커넥션 폭주 &amp; 제한 초과</h3>
<ul>
<li>DB는 동시 접속 수(<code>max_connections</code>)가 제한됨</li>
<li><strong>커넥션 풀 없이 무제한 생성은 순간적으로 DB 동시 접속 한도를 초과</strong></li>
<li>결과적으로 <code>Too many connections</code> 오류로 서비스 전체 장애</li>
</ul>
<h3 id="4-커넥션-재사용-불가-→-리소스-낭비">4. 커넥션 재사용 불가 → 리소스 낭비</h3>
<ul>
<li>커넥션은 만들기 비싼 자원인데, 매번 만들고 바로 버리면 낭비</li>
<li>풀을 쓰면 한 번 만든 커넥션을 여러 요청이 재사용 가능</li>
<li><strong>재사용이 없으면 네트워크, DB, CPU 낭비 + 응답속도 지연</strong></li>
</ul>
<p>❗ 이 외에도 커넥션 풀을 사용하지 않아 커넥션을 관리하지 않으면
<strong>확장성(Scalability) 문제, 장애 복구 및 안정성 저하 문제</strong>를 초래할 수 있음</p>
<h2 id="정리">정리</h2>
<p>매일메일 스터디에서 <code>커넥션 타임아웃(Connection Timeout)</code>과 관련된 질문을 받았을 때,
명확한 답변을 하지 못했는데, 그 이유는 커넥션을 DB에 중점을 두고 생각했기 때문이다.</p>
<p><strong>커넥션은 애플리케이션과 DB간의 통신선</strong>이라고 위에서 정리했는데,
그 통신의 기반이 <code>TCP</code>라는 부분을 간과했던 것 같다.</p>
<p>다시 정리하자면,</p>
<p>✅ <strong>커넥션 = 애플리케이션 ↔ DB 간의 통신선</strong>
✅ <strong>DB 커넥션은 TCP 연결 + DB 세션 상태까지 포함한 개념</strong>
✅ <strong>애플리케이션과 DB의 통신 기반은 TCP(TCP 소켓 연결)</strong></p>
<pre><code class="language-markdown">[애플리케이션]                  [DB 서버]
    |                               |
    | 1. TCP 연결 (소켓 open)       |
    |------------------------------&gt;|
    |                               |
    | 2. DB 인증 &amp; 세션 생성        |
    |------------------------------&gt;|
    |                               |
    | ← 커넥션(=TCP + 세션) -------- |
    |                               |
    ▼                               ▼
 ┌─────────────────────────────────────────┐
 │             커넥션 풀(Connection Pool)  │
 │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
 │ │Conn #1    │ │Conn #2    │ │Conn #3    │ │  ← 미리 만든 커넥션들
 │ │TCP + 세션 │ │TCP + 세션 │ │TCP + 세션 │ │
 │ └───────────┘ └───────────┘ └───────────┘ │
 └─────────────────────────────────────────┘
         ▲                 ▲
         |                 |
   요청 시 꺼내서 사용   요청 끝나면 반환
</code></pre>
<h3 id="next-step">NEXT STEP</h3>
<p>DB 세션을 공부해야겠다 ..!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring Boot] 외부 API를 호출할 때 사용하는 HTTP Client]]></title>
            <link>https://velog.io/@kiteof_park/Spring-Boot-%EC%99%B8%EB%B6%80-API%EB%A5%BC-%ED%98%B8%EC%B6%9C%ED%95%A0-%EB%95%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-HTTP-Client</link>
            <guid>https://velog.io/@kiteof_park/Spring-Boot-%EC%99%B8%EB%B6%80-API%EB%A5%BC-%ED%98%B8%EC%B6%9C%ED%95%A0-%EB%95%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-HTTP-Client</guid>
            <pubDate>Thu, 17 Jul 2025 18:57:36 GMT</pubDate>
            <description><![CDATA[<h3 id="외부-api와-httpclient">외부 API와 HttpClient</h3>
<p>각종 프로젝트에서 서비스를 개발하다보면 외부 API를 호출해야하는 일이
심심치 않게 발생하는데, 이렇게 Spring Boot에서 외부 API를 호출할 때 사용하는
다양한 <code>Http Client</code>에 대해 알아보자!</p>
<h2 id="http-client란">HTTP Client란?</h2>
<ul>
<li><code>HTTP Client</code>는 다른 서버(보통 HTTP 서버)로 <strong>HTTP 요청을 보내고, 
응답을 받아오는</strong> 프로그램 또는 라이브러리를 의미한다.</li>
<li>다시 말해 Java나 Spring 진영에서 <strong>클라이언트 역할</strong>을 하는게 <code>Http Client</code>다.</li>
</ul>
<h3 id="http-client의-작업">HTTP Client의 작업</h3>
<table>
<thead>
<tr>
<th>역할</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>요청 구성(method, header, body)</td>
<td>GET, POST, PUT 같은 메서드, 요청 헤더, 요청 본문 지정</td>
</tr>
<tr>
<td>요청 전송</td>
<td>네트워크를 통해 외부 서버로 전송</td>
</tr>
<tr>
<td>응답 수신</td>
<td>응답 코드(200, 404 등)와 본문(body) 등을 수신</td>
</tr>
<tr>
<td>응답 파싱</td>
<td>JSON, XML을 Java 객체로 변환 가능</td>
</tr>
</tbody></table>
<h2 id="🌼1-resttemplatedeprecated-예정">🌼1. RestTemplate(Deprecated 예정)</h2>
<ul>
<li>동기적 요청 처리</li>
<li>Spring에서 오래된 기본 <code>Http Client</code></li>
<li>사용법이 간단하지만 deprecated 예정 <em>- <code>WebClient</code>로 대체되는 추세</em></li>
</ul>
<pre><code class="language-java">@RestController
public class ApiController {

    private final RestTemplate restTemplate = new RestTemplate();

    @GetMapping(&quot;/call-api&quot;)
    public String callApi() {
        String url = &quot;https://api.example.com/data&quot;;
        // 해당 url로 GET 요청
        ResponseEntity&lt;String&gt; response = restTemplate.getForEntity(url, String.class);
        return response.getBody();
    }
}
</code></pre>
<h2 id="🌼2-webclient">🌼2. WebClient</h2>
<ul>
<li><strong>비동기(Reactive)&amp; 논블로킹 지원 <em>- Mono, Flux</em></strong></li>
<li>동기 방식으로도 사용 가능 <em>- <code>.block()</code></em></li>
<li>Spring이 권장하는 최신 방식</li>
</ul>
<h3 id="비동기-방식">비동기 방식</h3>
<pre><code class="language-java">@RestController
public class ApiController {

    private final WebClient webClient = WebClient.create();

    @GetMapping(&quot;/call-api&quot;)
    public Mono&lt;String&gt; callApi() {
        return webClient.get()                // GET 요청
                .uri(&quot;https://api.example.com/data&quot;)
                .retrieve()                    // 응답 처리
                .bodyToMono(String.class);    // Mono로 래핑된 결과
    }
}
</code></pre>
<h3 id="동기-방식">동기 방식</h3>
<pre><code class="language-java">@GetMapping(&quot;/call-api-blocking&quot;)
public String callApiBlocking() {
    return webClient.get()
            .uri(&quot;https://api.example.com/data&quot;)
            .retrieve()
            .bodyToMono(String.class)
            .block(); // 동기 방식
}</code></pre>
<h3 id="mono가-모에요">Mono가 모에요?</h3>
<ul>
<li><code>Mono</code>는 Reactor(비동기, 논블로킹 라이브러리)에서 제공하는 <strong>비동기 데이터 처리용 객체</strong></li>
<li><strong>0개 또는 1개의 데이터를 비동기적으로 반환</strong></li>
</ul>
<h2 id="🌼3-httpclient">🌼3. HttpClient</h2>
<ul>
<li>동기 방식</li>
<li>Apache <code>HttpComponents</code>, <code>CloseableHttpClient</code></li>
<li>Apache의 라이브러리 (spring-core에는 포함되지 않음❌) <em>- 외부 의존성 필요</em></li>
<li>커넥션 풀, 타임아웃 등 세밀한 설정이 가능</li>
<li><code>RestTemplate</code>이나 <code>WebClient</code>의 하위 엔진으로도 사용됨</li>
</ul>
<pre><code class="language-java">@RestController
public class ApiController {

    @GetMapping(&quot;/call-api-apache&quot;)
    public String callApiApache() throws IOException {
        CloseableHttpClient client = HttpClients.createDefault();
        HttpGet request = new HttpGet(&quot;https://api.example.com/data&quot;);
        CloseableHttpResponse response = client.execute(request);
        return EntityUtils.toString(response.getEntity());
    }
}</code></pre>
<h2 id="🌼4-okhttp">🌼4. OkHttp</h2>
<ul>
<li>비동기 방식, 동기 방식 모두 지원</li>
<li>Square사에서 만든 경량 <code>HTTP client</code> <em>- 외부 라이브러리 필요</em></li>
<li>안드로이드나 네이티브 자바에서 많이 사용</li>
<li>간결하고 빠름</li>
</ul>
<pre><code class="language-java">@RestController
public class ApiController {

    private final OkHttpClient client = new OkHttpClient();

    @GetMapping(&quot;/call-api-okhttp&quot;)
    public String callApiOkHttp() throws IOException {
        Request request = new Request.Builder()
                .url(&quot;https://api.example.com/data&quot;)
                .build();
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }
}</code></pre>
<h2 id="🌼5-restclient">🌼5. RestClient</h2>
<ul>
<li>동기 방식</li>
<li><code>RestTemplate</code>의 진화 버전</li>
<li>Java 17 이상의 <code>HttpClient</code> 기반</li>
<li>타입 세이프한 요청 방식, 간결한 코드</li>
<li>Spring Boot 3.2 이상에서 정식 지원</li>
</ul>
<pre><code class="language-java">@RestController
public class ApiController {

    private final RestClient restClient = RestClient.create();

    @GetMapping(&quot;/call-api-restclient&quot;)
    public String callApiRestClient() {
        return restClient.get()
                .uri(&quot;https://api.example.com/data&quot;)
                .retrieve()
                .body(String.class);
    }
}</code></pre>
<hr>
<h2 id="🍀-http-client의-동기비동기-방식">🍀 Http Client의 동기/비동기 방식</h2>
<h3 id="동기-방식resttemplate-webclientblock">동기 방식(RestTemplate, WebClient.block())</h3>
<ul>
<li><strong>요청을 보낸 스레드는 응답이 올 때까지 대기</strong></li>
<li>응답이 온 뒤에 다음 코드 를 실행</li>
<li>요청/응답이 순차적이고 직관적이지만, <strong>많은 요청 처리 시 스레드 낭비 우려</strong></li>
</ul>
<pre><code class="language-java">String body = restTemplate.getForObject(url, String.class)
// ❗ 응답이 올 때까지 기다림(동기 방식)
// ❗ 이 다음 코드는 응답을 받은 후에 실행됨</code></pre>
<h3 id="비동기-방식webclient-mono-okhttp-async-completablefuture">비동기 방식(WebClient, Mono, OkHttp async, CompletableFuture)</h3>
<ul>
<li><strong>요청을 보낸 후 스레드는 바로 다음 코드로 넘어가 실행</strong></li>
<li>응답은 나중에 도착하고, <strong>콜백이나 리액티브 방식</strong>으로 처리됨</li>
<li>응답이 나중에 오더라도 처리할 준비만 해두고,
그동안 CPU는 다른 일을 처리할 수 있어 효율적</li>
</ul>
<pre><code class="language-java">WebClient.create()
    .get()
    .uri(url)
    .retrieve()
    .bodyToMono(String.class)
    .subscribe(body -&gt; System.out.println(&quot;응답: &quot; + body));
// ❗ 응답 기다리지 않고 바로 다음 코드 실행됨</code></pre>
<h2 id="🍀-http-client별-동기비동기-방식-정리">🍀 Http Client별 동기/비동기 방식 정리</h2>
<table>
<thead>
<tr>
<th><strong>Http Client</strong></th>
<th><strong>기본 동작 방식</strong></th>
<th><strong>비동기 지원 여부</strong></th>
<th><strong>비고</strong></th>
</tr>
</thead>
<tbody><tr>
<td>RestTemplate</td>
<td>동기</td>
<td>❌ 지원 안함</td>
<td>Deprecated 예정</td>
</tr>
<tr>
<td>WebClient</td>
<td>비동기(Mono/Flux 기반)</td>
<td>✅ block()으로 동기도 가능</td>
<td>Spring 5+ 추천</td>
</tr>
<tr>
<td>HttpClient</td>
<td>동기</td>
<td>⚠️ async 버전은 따로 있음</td>
<td>설정 유연</td>
</tr>
<tr>
<td>OkHttp</td>
<td>동기</td>
<td>✅ <code>.enqueue()</code>로 비동기 가능</td>
<td>경량 &amp; 빠름</td>
</tr>
<tr>
<td>RestClient</td>
<td>동기</td>
<td>❌ 아직은 비동기 지원 제한</td>
<td>Spring 6+ 추천</td>
</tr>
</tbody></table>
<h3 id="동기비동기-방식에서-고민점">동기/비동기 방식에서 고민점</h3>
<p>사용자가 서비스를 이용하는 UX적인 관점에서 비동기 방식으로 요청을 처리하는게 뭐가 있을까? </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[스프링 핵심 원리 기본] Section02. 객체 지향 설계와 스프링]]></title>
            <link>https://velog.io/@kiteof_park/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8-Section02.-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81</link>
            <guid>https://velog.io/@kiteof_park/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8-Section02.-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81</guid>
            <pubDate>Fri, 20 Jun 2025 16:59:11 GMT</pubDate>
            <description><![CDATA[<h2 id="06-좋은-객체-지향-프로그래밍이란">06. 좋은 객체 지향 프로그래밍이란?</h2>
<h3 id="🍀-역할과-구현을-분리">🍀 역할과 구현을 분리</h3>
<ul>
<li><strong>역할과 구현</strong>으로 구분하면 <strong>단순</strong>해지고, <strong>유연</strong>해지며 <strong>변경</strong>도 편리해진다.</li>
<li>역할과 구현의 분리에서 자바 언어의 <strong>다형성</strong>을 활용<ul>
<li>역할 = 인터페이스</li>
<li>구현 = 인터페이스를 구현한 클래스, 구현 객체</li>
</ul>
</li>
<li>객체를 설계할 때 역할과 구현을 명확히 분리</li>
<li><strong>객체 설계 시 역할(인터페이스)을 먼저 부여하고, 그 역할을 수행하는 구현 객체 만들기</strong></li>
</ul>
<h3 id="🍀-역할과-구현-분리의-장점">🍀 역할과 구현 분리의 장점</h3>
<ul>
<li>클라이언트는 대상의 역할(인터페이스)만 알면 된다</li>
<li>클라이언트는 구현 대상의 <strong>내부 구조를 몰라도 된다</strong></li>
<li>클라이언트는 구현 대상의 <strong>내부 구조가 변경되어도 영향을 받지 않는다</strong></li>
<li>클라이언트는 구현 대상 <strong>자체를 변경해도 영향을 받지 않는다</strong></li>
</ul>
<h3 id="🍀-객체의-협력이라는-관계부터-생각">🍀 객체의 협력이라는 관계부터 생각</h3>
<ul>
<li>혼자 있는 객체는 없다</li>
<li><strong>수 많은 객체 클라이언트와 객체 서버는 서로 협력 관계를 가짐</strong></li>
</ul>
<h3 id="🍀-다형성의-본질">🍀 다형성의 본질</h3>
<ul>
<li>인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경 가능</li>
<li>다형성의 본질을 이해하려면 <strong>협력</strong>이라는 객체 사이의 관계에서 시작</li>
<li><strong>클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있음</strong></li>
</ul>
<h3 id="🍀-정리역할과-구현의-분리">🍀 [정리]역할과 구현의 분리</h3>
<ul>
<li>실세계의 역할과 구현이라는 컨셉 → <strong>다형성</strong>을 통해 객체 세상에 적용</li>
<li>유연성, 변경 용이, 확장 가능한 설계</li>
<li>클라이언트에 영향을 주지 않는 변경 가능</li>
<li>인터페이스를 안정적으로 잘 설계하는 것이 중요</li>
</ul>
<h3 id="🍀-한계역할과-구현의-분리">🍀 [한계]역할과 구현의 분리</h3>
<ul>
<li>역할(인터페이스) 자체가 변하면 클라이언트, 서버 모두에 큰 변경이 발생</li>
<li><strong>✨ 인터페이스를 안정적으로 잘 설계하는 것이 중요</strong></li>
</ul>
<h3 id="🍀-스프링과-객체-지향">🍀 스프링과 객체 지향</h3>
<ul>
<li><strong>다형성이 가장 중요</strong>, 스프링은 다형성을 극대화해 이용할 수 있도록 도와줌</li>
<li><strong>제어의 역전(<code>IoC</code>), 의존관계 주입(<code>DI</code>)은 다형성을 활용해<br>역할과 구현을 편리하게 다룰 수 있도록 지원</strong></li>
</ul>
<hr>
<h2 id="07-좋은-객체-지향-설계의-5가지-원칙solid">07. 좋은 객체 지향 설계의 5가지 원칙(SOLID)</h2>
<blockquote>
<p>OCP(개방 폐쇄 원칙), DIP(의존관계 역전 원칙)이 중요!</p>
</blockquote>
<h3 id="🍀-단일-책임-원칙-srpsingle-responsibility-principle">🍀 단일 책임 원칙, SRP(Single Responsibility Principle)</h3>
<ul>
<li>한 클래스는 하나의 책임만<ul>
<li>하나의 책임이라는 것은 모호하다</li>
<li>클 수도, 작을 수도 있고 문맥과 상황에 따라 다르다</li>
</ul>
</li>
<li><strong>✨ 중요한 기준은 변경, 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른것</strong></li>
<li>범위를 적절히 조절하는게 객체 지향 설계의 묘미</li>
</ul>
<h3 id="🍀-개방-폐쇄-원칙-ocp-open-close-principle">🍀 개방 폐쇄 원칙, OCP, Open Close Principle</h3>
<ul>
<li>✨ 소프트웨어 요소는 <strong>확장에는 열려있으나, 변경에는 닫혀있어야 한다.</strong></li>
<li>다형성, 역할과 구현의 분리를 의미</li>
<li>인터페이스를 구현한 클래스를 하나 만들어서 새로운 기능을 구현</li>
</ul>
<p><strong>개방 폐쇄 원칙의 문제점</strong></p>
<pre><code class="language-java">public class MemberService {
        private MemberRepository memberRepository = new MemoryMemberRepository();
}</code></pre>
<pre><code class="language-java">public class MemberService {
 // private MemberRepository memberRepository = new MemoryMemberRepository();
        private MemberRepository memberRepository = new JdbcMemberRepository();
}</code></pre>
<ul>
<li><code>MemberService</code> 클라이언트가 구현 클래스(레포지토리를 <code>new</code>를 통해 생성)를 직접 선택</li>
<li><strong>구현 객체(<code>MemoryRepository</code> → <code>JdbcRepository</code>)를 변경하려면 클라이언트 코드에 변경이 필요</strong></li>
<li>다형성을 사용했지만 OCP 원칙을 지킬 수 없다.<ul>
<li>이 문제를 해결하려면 객체를 생성하고, 연관관계를 맺어주는 별도의 조립/설정자가 필요</li>
<li>이 역할을 <strong>스프링 컨테이너</strong>가 해줌</li>
</ul>
</li>
</ul>
<h3 id="🍀-리스코프-치환-원칙-lsp-liskov-substitution-principle">🍀 리스코프 치환 원칙, LSP, <strong>Liskov Substitution Principle</strong></h3>
<ul>
<li>프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서,</li>
<li><em>하위 타입의 인스턴스로 바꿀 수 있어야 한다.*</em></li>
<li>다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 한다는 것</li>
<li>다형성을 지원하기 위한 원칙</li>
<li>인터페이스를 구현한 구현체는 믿고 사용하려면 이 원칙이 필요</li>
</ul>
<h3 id="🍀-인터페이스-분리-원칙-isp-interface-segregation-principle">🍀 인터페이스 분리 원칙, ISP, Interface Segregation Principle</h3>
<ul>
<li>특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다</li>
<li>인터페이스가 명확해지고, 대체 가능성이 높아진다.</li>
</ul>
<h3 id="🍀-의존관계-역전-원칙-dip-dependency-inversion-principle">🍀 의존관계 역전 원칙, DIP, Dependency Inversion Principle</h3>
<ul>
<li>추상화에 의존하되 구체화에 의존하면 안된다. <em>- 의존성 주입은 이 원칙을 따르는 방법 중 하나</em></li>
<li><strong>구현 클래스에 의존❌, 인터페이스에 의존⭕</strong></li>
<li>역할에 의존하게 해야 한다는 것</li>
<li><strong>클라이언트가 인터페이스에 의존해야 유연하게 구현체 변경 가능</strong>
구현체에 의존할 경우 변경이 매우 어려워짐</li>
</ul>
<pre><code class="language-java">public class MemberService {
        private MemberRepository memberRepository = new MemoryMemberRepository();
}</code></pre>
<pre><code class="language-java">public class MemberService {
 // private MemberRepository memberRepository = new MemoryMemberRepository();
        private MemberRepository memberRepository = new JdbcMemberRepository();
}</code></pre>
<ul>
<li>이 코드에서 MemberService는 인터페이스에 의존하지만, <strong>구현 클래스도 동시에 의존한다.</strong><ul>
<li>인터페이스 : <code>MemberRepository</code></li>
<li>구현 클래스 : <code>MemoryMemberRepository</code>, <code>JdbcMemberRepository</code></li>
</ul>
</li>
<li>MemberService 클라이언트가 구현 클래스를 직접 선택(직접 의존)<ul>
<li>MemberService가 구현 클래스의 내부 구조를 <strong>알고 있다</strong></li>
</ul>
</li>
</ul>
<h3 id="🍀정리">🍀정리</h3>
<ul>
<li>객체 지향의 핵심은 다형성</li>
<li>다형성만으로 쉽게 부품을 갈아끼우듯이 개발할 수 없다.</li>
<li>다형성만으로는 구현 객체를 변경할 때 클라이언트 코드도 함께 변경해야 한다.</li>
<li>다형성만으로는 <code>OCP</code>, <code>DIP</code>를 지킬 수 없다. 그래서 뭔가가 더 필요하다! <strong><em>- 스프링</em></strong></li>
</ul>
<hr>
<h2 id="08-객체-지향-설계와-스프링">08. 객체 지향 설계와 스프링</h2>
<h3 id="🍀-객체-지향과-스프링">🍀 객체 지향과 스프링</h3>
<ul>
<li>스프링은 <strong>다형성 + <code>OCP</code>, <code>DIP</code></strong>를 가능하도록 기술을 지원<ul>
<li><strong>DI</strong> : 의존관계, 의존성 주입</li>
<li><strong>DI 컨테이너 제공</strong> : 이 컨테이너 내부에서 객체 간 의존 관계 연결 및 주입</li>
</ul>
</li>
<li>클라이언트 코드의 변경없이 기능 확장</li>
<li>쉽게 부품을 교체하듯이 개발</li>
</ul>
<h3 id="🍀-정리">🍀 정리</h3>
<ul>
<li><strong>모든 설계에 역할과 구현을 분리</strong></li>
<li><strong>이상적으로 모든 설계에 인터페이스를 부여</strong></li>
<li>하지만 인터페이스를 도입하면 <strong>추상화라는 비용</strong>이 발생(한번 더 까봐야 된다)<ul>
<li><strong>✅ 장점이 단점을 넘어설 때 선택</strong></li>
</ul>
</li>
<li>기능을 확장할 가능성이 없다면 구체 클래스를 직접 사용하고 향후 인터페이스 도입</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 프로세스]]></title>
            <link>https://velog.io/@kiteof_park/OS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4</link>
            <guid>https://velog.io/@kiteof_park/OS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4</guid>
            <pubDate>Wed, 18 Jun 2025 19:52:24 GMT</pubDate>
            <description><![CDATA[<h2 id="프로세스의-개념">프로세스의 개념</h2>
<p>프로세스(<code>Process</code>)란 컴퓨터에서 연속적으로 <strong>실행되고 있는 프로그램</strong>이다.<br>종종 스케줄링의 대상이 되는 작업(<code>Task</code>)이라는 용어와 거의 같은 의미로 쓰인다.
<em>- 위키백과</em></p>
<h3 id="프로세스의-문맥context">프로세스의 문맥(Context)</h3>
<img src ="https://velog.velcdn.com/images/kiteof_park/post/3227574d-62a6-4081-b6f4-406e9178ef0b/image.png">

<ul>
<li><code>CPU</code> 수행 상태를 나타내는 하드웨어 문맥</li>
<li>프로세스의 <strong>현재 상태</strong>를 의미 <em>- 뭘 해서 지금의 상태까지 왔는가?</em></li>
<li><strong>특정 시점에서 어디까지 수행을 했는지</strong> 규명하는데 필요한 요소</li>
<li>프로세스의 문맥을 나타내기 위해서는 <code>PC</code>(Program Counter)가 가리키는 부분을 참조<ul>
<li><code>PC</code>는 CPU가 다음에 실행할 명령어의 주소를 저장하고 있는 레지스터</li>
<li>현재 프로세스의 실행 위치(명령어)를 추적</li>
</ul>
</li>
<li>프로세스의 문맥은 <code>code</code>, <code>data</code>, <code>stack</code> 의 상태를 저장함<ul>
<li>코드는 어디까지 수행? 어떤 데이터를 저장? 어떤 메서드를 호출?</li>
</ul>
</li>
<li>프로세스는 실행 시 독립적인 주소 공간을 생성한 뒤<br><code>CPU</code>를 할당받으면 PC가 프로세스의 <code>code</code> 영역의 어느 한 부분을 가리키고,<br>매 순간 명령어를 읽어 실행(레지스터에 값을 넣고 연산하고 저장하고 등)</li>
</ul>
<h3 id="프로세스-문맥의-구성요소">프로세스 문맥의 구성요소</h3>
<h4 id="1-하드웨어-문맥hardware-context">1. 하드웨어 문맥(Hardware Context)</h4>
<p>프로세스가 CPU를 사용하던 상태를 저장한 정보</p>
<ul>
<li><code>PC(Program Counter)</code> : 다음에 실행할 명령어의 주소</li>
<li><code>Register</code> : 현재 작업 중인 값들이 저장되어 있음</li>
</ul>
<h4 id="2-주소-공간-문맥memory-context">2. 주소 공간 문맥(Memory Context)</h4>
<p>프로세스의 독립적인 메모리 공간 상태를 나타냄</p>
<ul>
<li><code>Code</code> 영역 : 실행할 명령어</li>
<li><code>Date</code> 영역 : 전역 변수, 정적 변수</li>
<li><code>Stack</code> 영역 : 함수 호출, 지역 변수 등 실행 흐름과 관련된 정보</li>
</ul>
<h4 id="3-커널-문맥kernel-context">3. 커널 문맥(Kernel Context)</h4>
<p>운영체제가 프로세스를 관리하기 위해 유지하는 정보</p>
<ul>
<li><code>PCB(Process Control Block)</code> : 프로세스 ID, 상태, 우선순위 등 관리 정보</li>
<li><code>Kernel Stack</code> : 시스템 콜 처리 중에 사용하는 커널 스택<ul>
<li><strong>프로세스마다 별도의 커널 스택이 존재</strong></li>
<li>시스템 콜 진입 시, PC는 사용자 영역이 아닌 커널 코드 영역을 가리킴</li>
</ul>
</li>
</ul>
<hr>
<h2 id="프로세스의-상태">프로세스의 상태</h2>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/1a40efbf-fd29-4909-aaea-4a5aeb405725/image.png">

<ul>
<li><code>Running</code> : <code>CPU</code>를 잡고 명령어를 수행 중인 상태<ul>
<li>운영체제의 상태를 <code>Running</code>으로 표현하지 않음</li>
</ul>
</li>
<li><code>Ready</code> : (다른 조건을 모두 만족하고) CPU 할당을 기다리는 상태</li>
<li><code>Blocked(wait, sleep)</code> : CPU를 줘도 당장 명령어를 실행할 수 없는 상태<ul>
<li>자신이 요청한 이벤트(I/O 요청 등)가 즉시 만족되지 않아 대기 중인 상태</li>
<li>Ex. 디스크에서 파일을 읽어와야 하는 경우, 메모리에 로드되지 않은 경우</li>
<li>자신이 요청한 이벤트가 만족되면 <code>Ready</code> 상태</li>
</ul>
</li>
<li><code>Suspended(Stopped)</code> : 외부적인 이유로 프로세스 수행이 정지된 상태, 강제 종료<ul>
<li>프로세스는 통째로 디스크에 Swap Out</li>
<li>메모리에 너무 많은 프로세스가 올라와있을 때</li>
<li>외부에서 resume 해줘야 Active 상태로 변화</li>
</ul>
</li>
<li><code>New</code> : 프로세스가 생성 중인 상ㅌ애</li>
<li><code>Terminated</code> : 수행(execution)이 끝난 상태</li>
</ul>
<h2 id="pcbprocess-control-block">PCB(Process Control Block)</h2>
<ul>
<li>운영체제가 각 프로세스를 관리하기 위해 프로세스마다 유지하는 정보</li>
<li>프로세스마다 하나씩 1:1 매핑</li>
<li>구조체로 유지<h3 id="pcb-구성-요소">PCB 구성 요소</h3>
<img src = "https://scaler.com/topics/images/structure-of-process-control-block.webp" width = 80%>

</li>
</ul>
<p><a href="https://www.scaler.com/topics/operating-system/process-control-block-in-os/">이미지 출처</a></p>
<h4 id="1-os가-관리상-사용하는-정보">1. OS가 관리상 사용하는 정보</h4>
<ul>
<li>Process State(<code>Ready</code>, <code>Blocked</code> .. ), Process Id</li>
<li>Scheduling Information, Priority</li>
</ul>
<h4 id="2-cpu-수행-관련-하드웨어-값---프로세스-문맥">2. CPU 수행 관련 하드웨어 값 <em>- 프로세스 문맥</em></h4>
<ul>
<li>Program Counter(<code>PC</code>), Register</li>
</ul>
<h4 id="3-메모리-관련">3. 메모리 관련</h4>
<ul>
<li><code>code</code>, <code>data</code>, <code>stack</code> 위치 정보</li>
</ul>
<h4 id="4-파일-관련">4. 파일 관련</h4>
<ul>
<li>Open File Descriptors, ..</li>
</ul>
<h2 id="context-switch문맥-교환">Context Switch(문맥 교환)</h2>
<img src ="https://velog.velcdn.com/images/yoonuk/post/ba5772b3-73ca-40fa-b7f1-640e53e9d483/image.png">

<p><a href="https://velog.io/@yoonuk/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-PCB%EC%99%80-TCB">이미지 출처</a></p>
<ul>
<li><code>CPU</code>를 <strong>한 프로세스에서 다른 프로세스를 넘겨주는 과정</strong></li>
<li>CPU가 다른 프로세스에게 넘어갈 때 운영체제는 :<ul>
<li><ol>
<li><code>CPU</code>를 뺏기는 프로세스의 상태를 그 프로세스의 <code>PCB</code>에 저장</li>
</ol>
</li>
<li><ol start="2">
<li><code>CPU</code>를 새롭게 얻는 프로세스의 상태를 <code>PCB</code>에서 읽어옴  </li>
</ol>
</li>
</ul>
</li>
<li>⚠️ <strong>시스템 콜이나 인터럽트 발생 시 반드시 문맥 교환이 일어나는 것은 아님</strong><ul>
<li><code>CPU</code>제어권이 사용자 프로세스 → <code>OS</code>로 넘어가는 과정이 문맥교환❌</li>
<li>문맥교환은 사용자 프로세스A ↔ 사용자 프로세스B </li>
</ul>
</li>
</ul>
<h3 id="프로세스를-스케줄링하기-위한-큐">프로세스를 스케줄링하기 위한 큐</h3>
<p>운영체제가 프로세를 효율적으로 관리하고 스케줄링하기 위해 사용하는 대기열</p>
<ul>
<li><code>Job Queue</code> : 현재 시스템 내에 있는 <strong>모든 프로세스</strong>의 집합</li>
<li><code>Ready Queue</code> : <code>CPU</code>를 기다리는 모든 프로세스들의 대기열, 실행 가능한 상태</li>
<li><code>Deviced Queue</code> : I/O 장치의 사용을 기다리는 프로세스들의 대기열</li>
</ul>
<h3 id="큐-간-전이">큐 간 전이</h3>
<ul>
<li>프로그램 시작 → <code>Job Queue</code>에 등록</li>
<li>메모리에 올라오면 → <code>Ready Queue</code>로 이동</li>
<li>CPU 할당 → 실행 (<code>Running</code> 상태)</li>
<li>I/O 요청 → <code>Device Queue</code>로 이동</li>
<li>I/O 완료 → 다시 <code>Ready Queue</code>로 이동</li>
</ul>
<h3 id="스케줄러">스케줄러</h3>
<img src ="https://velog.velcdn.com/images/kiteof_park/post/1a39f0a5-fe27-41ba-b1f2-460bb8ac4944/image.png">

<h4 id="long-term--장기-스케줄러-job-스케줄러">Long-term  (장기 스케줄러, Job 스케줄러)</h4>
<ul>
<li>시작 프로세스 중 어떤 것들을 <code>Ready queue</code>에 보낼지 결정<ul>
<li><code>New</code> → <code>Ready</code></li>
</ul>
</li>
<li>프로세스에 <strong>메모리를 주는</strong> 문제 <em>- 멀티 프로그래밍을 제어</em><ul>
<li>메모리에 몇 개 올릴래?</li>
</ul>
</li>
<li><strong>✨ 시분할 시스템(Time Sharing System)에는 보통 장기 스케줄러가 없고 무조건 <code>ready</code> 상태</strong><ul>
<li>그래서 <code>Medium-term</code> 스케줄러가 필요</li>
</ul>
</li>
</ul>
<h4 id="short-term-scheduler단기-스케줄러-cpu-스케줄러">Short-term scheduler(단기 스케줄러, CPU 스케줄러)**</h4>
<ul>
<li>어떤 프로세스를 다음번에 <code>Running</code> 시킬지 결정</li>
<li>프로세스에 <strong>CPU를 주는</strong> 문제</li>
<li>충분히 빨라야 함</li>
</ul>
<h4 id="medium-term-scheduler중기-스케줄러-swapper">Medium-term scheduler(중기 스케줄러, Swapper)</h4>
<ul>
<li>여유 공간 마련을 위해 프로세스 통째로 메모리에서 디스크로 쫓아냄 <em>- Swap Out</em></li>
<li>프로세스에게서 <strong>메모리를 뺏는</strong> 문제 <em>- 멀티 프로그래밍을 제어</em></li>
<li>중기 스케줄러로 인해 <code>Suspended(stopped)</code>상태가 추가</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Network] 프로토콜과 캡슐화[2]]]></title>
            <link>https://velog.io/@kiteof_park/Network-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C%EA%B3%BC-%EC%BA%A1%EC%8A%90%ED%99%942</link>
            <guid>https://velog.io/@kiteof_park/Network-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C%EA%B3%BC-%EC%BA%A1%EC%8A%90%ED%99%942</guid>
            <pubDate>Wed, 18 Jun 2025 04:06:20 GMT</pubDate>
            <description><![CDATA[<h3 id="패킷-교환-네트워크">패킷 교환 네트워크</h3>
<img src = "https://velog.velcdn.com/images/kiteof_park/post/5b79ccc7-1dc6-4cd4-af3c-c6f6c60d8946/image.png">

<img src ="https://velog.velcdn.com/images/kiteof_park/post/d0e89cf8-ef6c-424e-a99a-02ed678fa61e/image.png">

<ul>
<li>주고받는 정보를 <strong>패킷(packet)</strong>단위로 주고받는 네트워크</li>
<li><strong>패킷</strong>:  패킷 교환 네트워크에서 주고받는 데이터 단위</li>
<li>정보를 <strong>패킷 단위로 분할</strong>해서 송신하고, 수신 측에서 패킷을 재조립</li>
<li><strong>패킷 교환기</strong>: 패킷을 어디로 전송할지(라우팅), 패킷의 손상 유무를 판별</li>
</ul>
<h3 id="회선-교환-네트워크">회선 교환 네트워크</h3>
<img src ="https://velog.velcdn.com/images/kiteof_park/post/0dfdb8cb-bd78-457b-b261-ffa88eb28bd3/image.png">

<ul>
<li><strong>정해진 회선(circuit)으로만 통신</strong>하는 네트워크</li>
<li><strong>사전에 연결 수립 작업</strong></li>
<li>다른 호스트는 도중에 끼어들 수 없음❌</li>
<li><strong>전송률을 보장</strong>하지만 <strong>회선 이용률 저하</strong></li>
</ul>
<h3 id="패킷-구성-요소">패킷 구성 요소</h3>
<ul>
<li><code>Header</code> : 패킷에 붙일 부가 정보</li>
<li><code>Payload</code> : 패킷에 보낼 정보</li>
<li><code>Trailer</code> : 패킷 뒤에 붙일 부가정보</li>
</ul>
<h3 id="프로토콜">프로토콜</h3>
<img src ="https://velog.velcdn.com/images/kiteof_park/post/87bc2b05-b5e9-4b3e-ac28-bfb835a37283/image.png">

<ul>
<li>네트워크에 참여한 장비 간 정보를 주고받을 규칙하는 방법</li>
<li>호스트 간에 합의된 의사소통 규칙 <strong><em>- 노드 간의 언어</em></strong></li>
<li>✨ <strong>패킷 헤더의 내용은 프로토콜의 영향</strong>을 받는다<ul>
<li>헤더는 패킷에 붙일 부가 정보</li>
<li>프로토콜이 달라지면 헤더의 내용이 달라진다 <strong><em>- 프로토콜마다 목적이 다름</em></strong></li>
<li><strong>TCP 프로토콜 헤더와 vs UDP 프로토콜 헤더</strong><ul>
<li><code>TCP</code> : 신뢰성이 보장된 전송</li>
<li><code>UDP</code> : 빠른 전송</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="네트워크-참조-모델---tcpip-4-layer">네트워크 참조 모델 - TCP/IP 4 Layer</h3>
<table>
<thead>
<tr>
<th><strong>계층</strong></th>
<th><strong>설명</strong></th>
</tr>
</thead>
<tbody><tr>
<td>어플리케이션 계층</td>
<td><strong>응용 프로그램</strong>으로부터 송수신하고자 하는 정보를 주고 받는 과정</td>
</tr>
<tr>
<td>전송 계층</td>
<td>정보 송수신 과정에서 <strong>안정성</strong>을 더하는 과정</td>
</tr>
<tr>
<td>인터넷 계층</td>
<td>송수신 하고자 하는 정보의 <strong>발신지/목적지를 결정</strong>하는 과정</td>
</tr>
<tr>
<td>네트워크 액세스 계층</td>
<td>송수신 하고자 하는 정보를 <strong>유/무선 매체</strong>를 통해 주고받는 과정</td>
</tr>
</tbody></table>
<img src ="https://velog.velcdn.com/images/kiteof_park/post/32432acf-985b-4a48-98c5-165539d97401/image.png">

<img src = "https://velog.velcdn.com/images/kiteof_park/post/ae37ef84-f495-4501-aecd-3a6bd4b944ac/image.png">

<h3 id="캡슐화와-역캡슐화">캡슐화와 역캡슐화</h3>
<img src ="https://velog.velcdn.com/images/kiteof_park/post/64440277-984c-4238-bc68-a4e3d13906ca/image.png">

<p><code>PDU(Protocol Data Unit)</code> : 네트워크에서 프로토콜 데이터 단위</p>
<table>
<thead>
<tr>
<th><strong>계층</strong></th>
<th><strong>PDU</strong></th>
<th><strong>기능</strong></th>
</tr>
</thead>
<tbody><tr>
<td>응용<br>표현<br>세션</td>
<td><code>Data</code></td>
<td>애플리케이션의 사용자 데이터 전달<br>데이터의 형식 및 암호화 처리<br>세션 설정 및 관리 담당</td>
</tr>
<tr>
<td>전송</td>
<td><code>Segment</code> <strong><em>- TCP</em></strong> <br><code>Datagram</code> <strong><em>- UDP</em></strong></td>
<td>신뢰성 있는 데이터 전송 및 오류 제어 수행<br>신뢰성 없는 데이터 전송 수행</td>
</tr>
<tr>
<td>네트워크</td>
<td><code>Packet</code></td>
<td>논리적 주소(IP) 기반의 데이터 라우팅 처리</td>
</tr>
<tr>
<td>데이터 링크</td>
<td><code>Frame</code></td>
<td>물리적 주소(MAC) 기반의 데이터 전송 처리</td>
</tr>
<tr>
<td>물리</td>
<td><code>Bits</code></td>
<td>0과 1로 구성된 신호로 변환해 전송</td>
</tr>
</tbody></table>
]]></description>
        </item>
    </channel>
</rss>