<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>sang_94.log</title>
        <link>https://velog.io/</link>
        <description>어렵다</description>
        <lastBuildDate>Sun, 21 Sep 2025 12:52:55 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>sang_94.log</title>
            <url>https://velog.velcdn.com/images/sang_94/profile/4c8ec1ba-e7b8-4b05-9b00-ce34357d0500/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. sang_94.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sang_94" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 26주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-26%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-26%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Sun, 21 Sep 2025 12:52:55 GMT</pubDate>
            <description><![CDATA[<p> @Async에서 403 에러 해결하기: SecurityContext 전파 문제와 해결책</p>
<p><strong>진행 기간:</strong> 2025.09.15 ~ 2025.09.19
<strong>주제:</strong> Spring Boot에서 비동기 처리와 Spring Security의 상호작용 문제 해결</p>
<p>이번 주는 팀에서 성능 개선을 위해 도입한 비동기 처리가 Spring Security와 만나면서 예상치 못한 문제를 일으키고, 이를 해결해나가는 과정이었다. 처음엔 단순한 설정 문제라고 생각했지만, ThreadLocal과 SecurityContext의 깊은 원리를 이해해야 하는 복잡한 문제였다. 이 과정에서 &#39;모르는 것을 인정하고 함께 배우는&#39; 협업의 소중함을 다시금 깨달았다.</p>
<h2 id="1-문제-발견-성공한-db-작업-실패한-http-응답">1. 문제 발견: 성공한 DB 작업, 실패한 HTTP 응답</h2>
<h3 id="초기-상황과-혼란">초기 상황과 혼란</h3>
<p>팀원이 성능 개선을 위해 구현한 비동기 템플릿 생성 기능에서 이상한 현상이 발생했다.</p>
<pre><code class="language-java">@PostMapping(&quot;/templates/{workspaceId}/async&quot;)
public CompletableFuture&lt;ResponseEntity&lt;IndividualTemplateResponse&gt;&gt; createEmptyTemplateAsync(...) {
    return individualTemplateService.createTemplateAsync(workspaceId)
           .thenApply(ResponseEntity::ok);
}</code></pre>
<p><strong>기이한 현상들:</strong></p>
<ul>
<li>✅ 데이터베이스에 INSERT 성공 (로그로 확인됨)</li>
<li>❌ Swagger UI에서 403 Forbidden 에러 반환  </li>
<li>✅ 동기 API는 정상 작동</li>
</ul>
<p>처음에는 &quot;권한 설정을 잘못했나?&quot;라고 생각했다. 하지만 동기 API는 정상 작동한다는 점이 의아했다. 뭔가 근본적인 문제가 있다는 직감이 들어 팀원과 함께 원인 분석에 나섰다.</p>
<h3 id="문제의-핵심-threadlocal의-특성">문제의 핵심: ThreadLocal의 특성</h3>
<p>원인을 파악하기 위해 Spring Security의 동작 원리를 깊이 들여다봤다.</p>
<pre><code class="language-java">// SecurityContext의 구조
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();

// ThreadLocal 기반 관리
public class SecurityContextHolder {
    private static final ThreadLocal&lt;SecurityContext&gt; contextHolder = new ThreadLocal&lt;&gt;();

    public static SecurityContext getContext() {
        return contextHolder.get(); // 현재 스레드의 SecurityContext만 반환
    }
}</code></pre>
<p><strong>ThreadLocal의 특징이 문제였다:</strong></p>
<ul>
<li>각 스레드는 자신만의 독립적인 변수 공간을 가짐</li>
<li>부모 스레드 → 자식 스레드로 자동 전파되지 않음</li>
<li>메인 스레드의 SecurityContext가 비동기 스레드에서는 <code>null</code></li>
</ul>
<p>이 지점에서 &quot;아!&quot; 하는 깨달음이 왔다. 비동기 처리의 본질적인 특성과 Spring Security의 구조적 한계가 충돌한 것이었다.</p>
<h2 id="2-원인-분석-스레드-간-인증-정보-단절">2. 원인 분석: 스레드 간 인증 정보 단절</h2>
<h3 id="실행-흐름-추적">실행 흐름 추적</h3>
<p>문제의 정확한 원인을 파악하기 위해 스레드별 실행 흐름을 추적해봤다.</p>
<pre><code class="language-java">// 1단계: 메인 스레드 (HTTP 요청 처리)
@PostMapping(&quot;/templates/{workspaceId}/async&quot;)
public CompletableFuture&lt;...&gt; createEmptyTemplateAsync(@AuthenticationPrincipal JwtClaims claims) {
    // JWT 필터가 이미 SecurityContext 설정 완료
    SecurityContext context = SecurityContextHolder.getContext();
    // ✅ context에 사용자 인증 정보 존재: claims.getUserId() = 123

    return individualTemplateService.createTemplateAsync(workspaceId);
}

// 2단계: 비동기 스레드 (@Async 메서드)
@Async
public CompletableFuture&lt;IndividualTemplateResponse&gt; createTemplateAsync(Integer workspaceId) {
    // ❌ 문제 지점: 새로운 스레드에서 실행됨
    SecurityContext context = SecurityContextHolder.getContext();
    // context가 비어있음! null 또는 익명 사용자

    // DB 작업은 성공 (JPA는 인증과 무관)
    IndividualTemplate saved = individualTemplateRepo.save(entity); // ✅ 성공

    // HTTP 응답 생성 시 Spring Security가 권한 체크 → 인증 정보 없음 → ❌ 403 에러
    return CompletableFuture.completedFuture(response);
}</code></pre>
<h3 id="db-성공-vs-http-응답-실패의-미스터리">DB 성공 vs HTTP 응답 실패의 미스터리</h3>
<p>팀원과 함께 분석한 결과, 이 현상의 원인을 명확히 파악할 수 있었다:</p>
<ul>
<li><strong>DB 작업 성공</strong>: JPA는 Spring Security와 독립적으로 동작</li>
<li><strong>HTTP 응답 실패</strong>: Spring Security가 응답 생성 시 권한을 재검증하는데, SecurityContext가 비어있어 403 에러 발생</li>
</ul>
<p>이 부분에서 Spring의 계층적 구조와 각 레이어의 독립성을 이해하게 되었다.</p>
<h2 id="3-해결책-탐색-delegatingsecuritycontextasynctaskexecutor-발견">3. 해결책 탐색: DelegatingSecurityContextAsyncTaskExecutor 발견</h2>
<h3 id="공식-문서-탐방과-해답-찾기">공식 문서 탐방과 해답 찾기</h3>
<p>원인을 파악한 후, 팀원과 함께 Spring Security 공식 문서를 뒤지기 시작했다. &quot;비동기 처리에서 SecurityContext 전파&quot;를 키워드로 검색하다가 <code>DelegatingSecurityContextAsyncTaskExecutor</code>라는 해답을 찾았다.</p>
<p><strong>이름부터 명확했다:</strong></p>
<ul>
<li><code>Delegating</code>: 위임하는</li>
<li><code>SecurityContext</code>: 보안 컨텍스트</li>
<li><code>AsyncTaskExecutor</code>: 비동기 작업 실행기</li>
</ul>
<p>즉, SecurityContext를 비동기 작업에 위임해주는 실행기였다.</p>
<h3 id="delegatingsecuritycontextasynctaskexecutor의-동작-원리">DelegatingSecurityContextAsyncTaskExecutor의 동작 원리</h3>
<pre><code class="language-java">public class DelegatingSecurityContextAsyncTaskExecutor implements AsyncTaskExecutor {

    private final AsyncTaskExecutor delegateExecutor;

    @Override
    public void execute(Runnable task) {
        // 1단계: 현재 스레드의 SecurityContext 캡처
        SecurityContext currentContext = SecurityContextHolder.getContext();

        // 2단계: SecurityContext를 전파하는 새로운 작업 생성
        Runnable wrappedTask = () -&gt; {
            try {
                // 3단계: 새로운 스레드에 SecurityContext 설정
                SecurityContextHolder.setContext(currentContext);
                // 4단계: 원래 작업 실행 (이제 인증 정보 사용 가능!)
                task.run();
            } finally {
                // 5단계: 작업 완료 후 SecurityContext 정리 (메모리 릭 방지)
                SecurityContextHolder.clearContext();
            }
        };

        // 6단계: 실제 Executor에 위임하여 실행
        delegateExecutor.execute(wrappedTask);
    }
}</code></pre>
<p><strong>Wrapper 패턴의 완벽한 활용:</strong></p>
<ul>
<li>기존 Executor의 기능은 그대로 유지</li>
<li>SecurityContext 전파 기능만 추가</li>
<li>원본 코드 수정 없이 기능 확장</li>
</ul>
<p>이 구조를 보며 디자인 패턴의 실용적 활용을 체감할 수 있었다.</p>
<h2 id="4-완전한-해결책-구현-asyncconfig를-통한-시스템-레벨-해결">4. 완전한 해결책 구현: AsyncConfig를 통한 시스템 레벨 해결</h2>
<h3 id="asyncconfigurer-vs-bean-방식-비교">AsyncConfigurer vs @Bean 방식 비교</h3>
<p>해결책을 구현하면서 두 가지 방식을 고민했다:</p>
<table>
<thead>
<tr>
<th>항목</th>
<th>@Bean 방식</th>
<th>AsyncConfigurer 방식</th>
</tr>
</thead>
<tbody><tr>
<td><strong>빈 등록</strong></td>
<td>필요 (<code>@Bean</code>)</td>
<td>불필요 (콜백 메커니즘)</td>
</tr>
<tr>
<td><strong>Spring 관리</strong></td>
<td>컨테이너에서 빈으로 관리</td>
<td>Spring이 직접 메서드 호출</td>
</tr>
<tr>
<td><strong>사용 방법</strong></td>
<td>타입/이름으로 빈 검색</td>
<td><code>@Async</code>가 자동으로 연결</td>
</tr>
<tr>
<td><strong>우선순위</strong></td>
<td>낮음</td>
<td><strong>높음 (전용 설정)</strong></td>
</tr>
<tr>
<td><strong>명시성</strong></td>
<td>범용적</td>
<td><strong>@Async 전용 (더 명확)</strong></td>
</tr>
</tbody></table>
<p>결론적으로 AsyncConfigurer 방식이 더 명시적이고 <code>@Async</code> 전용 설정이라는 점에서 채택했다.</p>
<h3 id="최종-asyncconfig-구현">최종 AsyncConfig 구현</h3>
<pre><code class="language-java">@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    /**
     * @Async 메서드에서 사용할 기본 Executor 설정
     * DelegatingSecurityContextAsyncTaskExecutor를 사용하여 SecurityContext를 비동기 스레드로 전파
     */
    @Override
    public Executor getAsyncExecutor() {
        // 1단계: 가상 스레드를 사용하는 SimpleAsyncTaskExecutor 생성
        SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
        executor.setVirtualThreads(true); // JDK 21 가상 스레드 활성화
        executor.setThreadNamePrefix(&quot;async-&quot;);

        // 2단계: SecurityContext를 전파하는 DelegatingSecurityContextAsyncTaskExecutor로 래핑
        return new DelegatingSecurityContextAsyncTaskExecutor(executor);
    }

    /**
     * 비동기 실행 중 발생한 예외를 처리할 핸들러
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -&gt; {
            System.err.println(&quot;비동기 메서드 실행 중 예외 발생: &quot; + method.getName());
            ex.printStackTrace();
        };
    }
}</code></pre>
<h3 id="api-응답-패턴-개선">API 응답 패턴 개선</h3>
<p>기존의 문제가 있던 방식:</p>
<pre><code class="language-java">// ❌ CompletableFuture를 그대로 반환 → 클라이언트가 대기
public CompletableFuture&lt;ResponseEntity&lt;IndividualTemplateResponse&gt;&gt; createEmptyTemplateAsync(...)</code></pre>
<p>개선된 Fire-and-Forget 패턴:</p>
<pre><code class="language-java">// ✅ 즉시 202 응답 → 비동기 작업은 백그라운드에서 처리
@ApiResponse(responseCode = &quot;202&quot;, description = &quot;요청 접수됨&quot;)
public ResponseEntity&lt;String&gt; createEmptyTemplateAsync(...) {
    // 비동기 작업 시작만 하고 즉시 응답
    individualTemplateService.createTemplateAsync(workspaceId);

    return ResponseEntity.status(202).body(&quot;Template creation started&quot;);
}</code></pre>
<p>이 변경으로 사용자 경험이 크게 개선되었다.</p>
<h2 id="5-핵심-학습-정리-원리-이해의-중요성">5. 핵심 학습 정리: 원리 이해의 중요성</h2>
<h3 id="기술적-핵심-개념들">기술적 핵심 개념들</h3>
<p><strong>1. SecurityContext와 ThreadLocal의 관계</strong></p>
<pre><code class="language-java">// ThreadLocal은 스레드 간 자동 공유되지 않음
메인 스레드: SecurityContext = {userId: 123}
비동기 스레드: SecurityContext = null (또는 empty)

// 명시적 전파 필요
DelegatingSecurityContextAsyncTaskExecutor → SecurityContext 복사 및 전파</code></pre>
<p><strong>2. Spring의 설정 메커니즘 이해</strong></p>
<pre><code class="language-java">// 범용적인 빈 등록
@Bean
public ExecutorService taskExecutor() { 
    return new SimpleAsyncTaskExecutor(); 
}

// @Async 전용 설정 (더 명시적이고 우선순위 높음)
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() { 
        return new DelegatingSecurityContextAsyncTaskExecutor(executor);
    }
}</code></pre>
<p><strong>3. Wrapper 패턴의 실용적 활용</strong></p>
<pre><code class="language-java">// 기본 Executor
SimpleAsyncTaskExecutor baseExecutor = new SimpleAsyncTaskExecutor();

// 기능 확장: SecurityContext 전파 기능 추가
DelegatingSecurityContextAsyncTaskExecutor enhancedExecutor = 
    new DelegatingSecurityContextAsyncTaskExecutor(baseExecutor);

// 원래 기능 + 추가 기능을 모두 제공</code></pre>
<h2 id="6-협업과-성장-함께-배우는-가치">6. 협업과 성장: 함께 배우는 가치</h2>
<h3 id="솔직한-반성과-깨달음">솔직한 반성과 깨달음</h3>
<p>이번 경험에서 가장 값진 것은 기술적 해결책이 아니라 협업 과정에서의 학습이었다.</p>
<p><strong>처음의 착각:</strong></p>
<ul>
<li>Spring Security에 대한 깊은 이해 부족을 인정하지 못함</li>
<li>사전에 비동기 처리와 보안의 상호작용을 예상하지 못함</li>
<li>&quot;권한 설정 문제&quot;라는 피상적 접근</li>
</ul>
<p><strong>협업을 통한 성장:</strong></p>
<ul>
<li>팀원과 함께 로그를 분석하며 문제의 본질 파악</li>
<li>공식 문서를 함께 탐방하며 정확한 해결책 발견</li>
<li>서로의 부족함을 인정하고 함께 학습하는 과정</li>
</ul>
<h3 id="앞으로의-다짐">앞으로의 다짐</h3>
<p><strong>기술적 측면:</strong></p>
<ul>
<li>새로운 기술 도입 시 다른 시스템과의 상호작용 미리 고려</li>
<li>Spring Security와 비동기 처리의 조합 시 항상 SecurityContext 전파 검토</li>
<li>문제 발생 시 표면적 현상이 아닌 근본 원인 분석</li>
</ul>
<p><strong>협업적 측면:</strong></p>
<ul>
<li>모르는 것을 부끄러워하지 않고 팀원과 공유</li>
<li>문제 해결 과정을 함께 학습하는 기회로 활용</li>
<li>사전 공유의 중요성과 사후 함께 학습하는 가치 모두 인정</li>
</ul>
<h2 id="7-최종-결론-원리-이해의-힘">7. 최종 결론: 원리 이해의 힘</h2>
<p>이번 주 학습의 가장 큰 성과는 <strong>표면적 해결책이 아닌 원리 이해</strong>를 통한 문제 해결이었다. ThreadLocal의 특성, Spring Security의 구조, 비동기 처리의 본질을 이해함으로써 근본적인 해결책을 찾을 수 있었다.</p>
<p>더불어 <strong>DelegatingSecurityContextAsyncTaskExecutor</strong>라는 Spring Security의 강력한 도구를 발견하고, <strong>Wrapper 패턴</strong>의 실용적 활용을 체감했다. AsyncConfigurer를 통한 시스템 레벨 설정으로 앞으로 모든 <code>@Async</code> 메서드에서 이 문제가 재발하지 않을 것이다.</p>
<p>하지만 무엇보다 소중한 것은 팀원과 함께 문제를 해결해나가며 얻은 <strong>협업의 가치</strong>였다. 혼자서는 절대 도달할 수 없었을 깊은 이해와 견고한 해결책을 함께 만들어낼 수 있었다.</p>
<p>다음 주에는 이번에 해결한 비동기 처리 기반 위에서 실제 비즈니스 로직을 구현하고, 성능 최적화와 모니터링 시스템을 구축해볼 계획이다. 이번 경험을 바탕으로 더 탄탄한 시스템을 만들어나갈 수 있을 것 같다. 🚀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 25주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-25%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-25%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Mon, 15 Sep 2025 13:29:02 GMT</pubDate>
            <description><![CDATA[<p>🔐 JWT 토큰 구현 현실 체크: 이론과 실제 사이의 괴리</p>
<p>진행 기간: 2025.09.08 ~ 2025.09.12</p>
<p>이번 주는 JWT 토큰 설계를 실제로 구현하면서 &#39;아는 것&#39;과 &#39;할 수 있는 것&#39;의 차이를 뼈저리게 느낀 시간이었다. 설계 단계에서는 모든 게 명확해 보였지만, 막상 코드를 작성하다 보니 내가 정말로 JWT를 이해하고 있었는지 의문이 들기 시작했다. 이 과정에서 &#39;아는 척의 위험성&#39;을 절실히 깨달았다. 생각보다 할게 많았던 로그인 로그아웃 보안 구현에 빨리빨리 보고 넘어가며 보고 있을 당시엔 이해했다고 생각했던 것들이 지나고 되돌아보니 머리에 남아있지 않았다..</p>
<ol>
<li><p>JWT 서명 검증: 내가 정말 이해하고 있었나?
처음 JWT 라이브러리를 사용할 때는 단순했다. Jwts.builder()로 만들고 Jwts.parser()로 파싱하면 끝이라고 생각했다. 하지만 실제 구현 과정에서 만난 첫 번째 벽은 서명 검증이었다.
마주한 현실적 문제들
java// 이렇게 간단할 줄 알았는데...
String token = Jwts.builder()
 .setSubject(userId)
 .signWith(secretKey)
 .compact();</p>
<p>알아야 할게 너무 많았다..</p>
<ol>
<li>secretKey는 어떤 형식으로? String? Key객체?</li>
<li>알고리즘은 HS256? RS256? 차이가 뭐지?</li>
<li>서명 검증 실패 시 어떤 예외가 발생하지?</li>
<li>만료된 토큰과 잘못된 서명을 어떻게 구분하지?</li>
</ol>
</li>
</ol>
<p>삽질하며 배운 것들</p>
<p>Key 객체와 String 비밀키의 차이점
HMAC vs RSA 서명 방식의 실제 적용 시나리오
JwtException의 하위 예외들과 각각의 의미
Base64 인코딩된 키 처리 방법</p>
<p>결국 JWT 토큰 하나 제대로 만들기 위해 암호화 기초부터 다시 공부해야 했다.</p>
<ol start="2">
<li>Redis 연동: 이론과 실제의 간극
설계 단계에서 &quot;Redis에 블랙리스트 저장하면 끝&quot;이라고 생각했던 나의 순진함을 반성한다. 실제 구현에서는 예상치 못한 복잡성들이 기다리고 있었다.</li>
</ol>
<p>예상했던 구현
간단할 줄 알았다
redisTemplate.opsForValue().set(&quot;blacklist:&quot; + tokenId, &quot;true&quot;, Duration.ofMinutes(15));</p>
<p>실제 마주한 문제들</p>
<ol>
<li><p>직렬화 문제
String? Object? 어떤 타입으로 저장하지?</p>
</li>
<li><p>TTL 동기화 문제<br>JWT 만료시간과 Redis TTL이 다르면?</p>
</li>
<li><p>성능 문제
매 API 호출마다 Redis 조회가 필요한데 느리지 않을까?</p>
</li>
<li><p>예외 처리
Redis 연결 실패 시 어떻게 처리하지?
해결 과정에서 배운 것들</p>
</li>
</ol>
<p>RedisTemplate vs StringRedisTemplate의 차이점과 선택 기준
Redis 연결 풀 설정과 성능 최적화
Lettuce vs Jedis 클라이언트 선택의 실제 영향
Redis 장애 시 graceful degradation 구현의 어려움</p>
<ol start="3">
<li>Spring Security 통합: 문서와 현실의 차이
가장 큰 좌절을 맛본 부분이다. Spring Security 공식 문서를 보면 JWT 필터 하나만 추가하면 될 것 같았는데, 실제로는 완전히 다른 세상이었다.</li>
</ol>
<p>java// 간단해 보였던 설정
@Configuration
public class SecurityConfig {
    @Bean
    public JwtAuthenticationFilter jwtFilter() {
        return new JwtAuthenticationFilter();
    }
}</p>
<p>실제 구현에서 만난 현실</p>
<ol>
<li>필터 순서가 왜 이렇게 중요하지?</li>
<li>Authentication 객체를 언제 어떻게 설정하지?</li>
<li>SecurityContext는 언제 저장되고 언제 지워지지?</li>
<li>예외 발생 시 필터 체인이 어떻게 동작하지?</li>
<li>CORS 설정과 JWT 필터가 왜 충돌하지?</li>
</ol>
<p>삽질 과정에서 깨달은 것들</p>
<p>Filter 순서의 중요성과 OncePerRequestFilter의 필요성
Authentication vs Principal의 차이점
SecurityContextHolder의 스레드 로컬 특성
예외 처리를 위한 AuthenticationEntryPoint 커스터마이징</p>
<ol start="4">
<li>가장 큰 깨달음: 내가 모르는 게 너무 많다
이번 주 구현 과정에서 가장 충격적이었던 것은 내가 JWT와 Spring Security를 &#39;안다고 착각&#39;하고 있었다는 사실이다.</li>
</ol>
<p>착각했던 것들</p>
<p>JWT는 그냥 JSON을 Base64로 인코딩한 것 (→ 서명과 암호화 개념 부족)
Spring Security는 설정만 하면 알아서 동작 (→ 내부 동작 원리 무지)
Redis는 key-value 저장소일 뿐 (→ 성능, 메모리, 네트워크 고려사항 간과)</p>
<p> JWT 제대로 이해하기</p>
<ul>
<li><p>Header.Payload.Signature 구조의 실제 의미</p>
</li>
<li><p>서명 검증 과정과 보안 원리</p>
</li>
<li><p>상태 없음(stateless)의 진짜 의미와 한계</p>
<p>Spring Security 동작 원리</p>
</li>
<li><p>Filter Chain의 실행 순서와 각 필터의 역할</p>
</li>
<li><p>Authentication vs Authorization의 구분</p>
</li>
<li><p>SecurityContext 생명주기 관리</p>
<p>Redis 운영 노하우</p>
</li>
<li><p>메모리 사용량 모니터링</p>
</li>
<li><p>연결 풀 튜닝</p>
</li>
<li><p>장애 상황 대응 방안</p>
</li>
</ul>
<p>다음 주 계획: 기초부터 다시
이번 주 경험을 통해 내가 얼마나 기초가 부족한지 깨달았다. 다음 주에는 겉핥기식 구현보다는 근본적인 이해에 집중할 계획이다.</p>
<p>학습 계획</p>
<ol>
<li><p>JWT 스펙 문서 정독: RFC 7519 완전 이해</p>
</li>
<li><p>Spring Security Architecture 깊이 파기: 필터 체인부터 차근차근</p>
</li>
<li><p>Redis 운영 가이드 학습: 단순 사용법을 넘어 운영 관점까지</p>
</li>
<li><p>테스트 코드 작성: 각 컴포넌트의 동작을 검증하며 이해도 높이기</p>
<p>&#39;아는 것&#39;과 &#39;구현할 수 있는 것&#39;의 차이를 체감했고, 기초의 중요성을 다시 한번 깨달았다. 앞으로는 겉핥기를 벗어나기 위해 노력해야겠다..</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 24주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-24%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-24%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Mon, 08 Sep 2025 00:59:41 GMT</pubDate>
            <description><![CDATA[<p>🚀 진행 기간
2025.09.01 ~ 2025.09.05</p>
<p>이번 주 파이널 프로젝트 DB 설계는 완벽한 구조를 꿈꾸는 이상적인 설계와 당장 서비스에 필요한 기능만을 담는 실용적인 설계 사이에서 균형을 찾아가는 과정이었다. 처음엔 사용자 관리의 모든 기능을 담으려 했지만, 팀원들의 피드백을 통해 불필요한 부분을 과감히 덜어내는 용기를 얻었다.  이 과정에서 &#39;과유불급&#39;이라는 교훈을 다시금 깨달았다.</p>
<ol>
<li>USER 테이블 최적화: 필요한 정보만 담는 그릇으로
초기 설계 단계에서 나는 USER 테이블에 사용자의 모든 정보를 담으려 했다. 역할(role), 상태(status), 각종 시간 추적 컬럼(created_at, updated_at 등)을 포함해 관리 시스템의 모든 기능을 녹여내려고 했다. 하지만 &#39;과연 이 모든 것이 지금 당장 필요한가?&#39;라는 질문에 직면했고, 다음과 같은 결정을 내렸다.</li>
</ol>
<p>관리자 기능 관련 컬럼 제거: 현재 프로젝트에서 관리자 기능을 구현할 계획이 없으므로, user_status, created_at, updated_at 등과 같은 관리용 컬럼들을 과감히 삭제했다.</p>
<p>USER와 USER_PROFILE 테이블 통합: 처음에는 성능, 보안, 확장성을 고려해 USER와 USER_PROFILE 테이블을 분리했었다. 하지만 이는 초기 단계 서비스에서는 오버엔지니어링으로 이어질 수 있음을 깨달았다. 불필요한 JOIN 연산을 피하고 개발 효율성을 높이기 위해 두 테이블을 통합하고 단순화했다.</p>
<p>Before (1차 설계)</p>
<p>USER { user_id, user_role, user_status, created_at, updated_at, deleted_at, last_login_at }</p>
<p>USER_PROFILE { profile_id, user_id, user_email, user_name, user_number, user_type }</p>
<p>After (2차 최적화)</p>
<p>USER { user_id, user_email, user_name, user_number, user_role }</p>
<p>이러한 결정으로 쿼리(Query)가 단순해지고 코드 복잡성이 크게 줄었다.</p>
<ol start="2">
<li>휘발성 데이터 관리: Redis의 유연성 활용
로그인 이력과 이메일 인증 코드는 휘발성 데이터라는 공통점을 가진다. 이전 설계에서는 이를 각각 LOGIN_HISTORY와 EMAIL_VERIFICATION 테이블에 저장하려 했지만, 이는 데이터베이스에 불필요한 부하를 줄 수 있다.</li>
</ol>
<p>로그인 이력: DB에 저장하는 대신, Spring의 EventListener와 Slf4j를 이용해 로그 파일로 기록하는 방식을 채택했다. 이는 비즈니스 데이터와 로그 데이터를 명확하게 분리하고 DB 부하를 줄이는 효과가 있다.</p>
<p>이메일 인증: 짧은 시간 내에 사라지는 인증 코드는 DB보다 Redis에 저장하는 것이 훨씬 효율적이다. Redis의 TTL(Time To Live) 기능을 활용하면 설정한 시간(예: 15분)이 지나면 데이터가 자동으로 삭제되어, 만료 로직을 별도로 구현할 필요가 없다.</p>
<p>이러한 접근으로 DB의 부담을 덜고, 데이터의 성격에 맞는 기술을 유연하게 선택하는 법을 배웠다.</p>
<ol start="3">
<li>최종 결론: 실용성을 향한 최적화 여정
이번 주 학습의 가장 큰 성과는 덜어냄의 미학을 배운 것이다. 처음의 6개 테이블과 47개 컬럼은 최종적으로 3개의 핵심 테이블과 21개의 컬럼으로 단순화되었다. 이는 테이블 수 50%, 컬럼 수 55%의 감소를 의미한다.</li>
</ol>
<p>이 과정에서 나는 YAGNI(You Aren&#39;t Gonna Need It) 원칙, 즉 &quot;당장 필요 없는 기능은 만들지 말자&quot;는 교훈을 깊이 새겼다. 더불어, 오버엔지니어링을 경계하고 데이터의 특성에 맞는 적절한 기술(DB vs. Redis)을 선택하는 안목을 기를 수 있었다.</p>
<p>아직 미숙한 부분이 많지만, 단순한 스키마 정의를 넘어 서비스 시나리오와 운영 관점을 반영한 설계 고민을 했다는 점에서 이번 주 경험은 매우 값지다. 다음 주에는 이 최적화된 ERD를 기반으로 실제 엔티티를 구현하고 API 프로토타입을 제작하며 한 단계 더 나아갈 계획이다. 🚀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 23주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-23%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-23%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Mon, 01 Sep 2025 00:58:46 GMT</pubDate>
            <description><![CDATA[<p>🚀 진행 기간
2025.08.24 ~ 2025.08.29</p>
<p>📌 이번 주 활동</p>
<p>파이널 프로젝트: B2B 알림톡 템플릿 생성 AI 서비스 DB 인증 설계</p>
<p>로컬 인증 vs 소셜 인증 관리 방식 분석</p>
<p>분리 설계(LOCAL_AUTH &amp; SOCIAL_AUTH)와 통합 설계(USER_AUTH) 트레이드오프 비교</p>
<p>최종 ERD 초안 작성 (user, user_profile, user_auth, login_history 등)</p>
<p>데이터 정합성 및 보안 고려 → 유효성 검증 로직 구상</p>
<p>💬 회고</p>
<p>이번 주는 파이널 프로젝트 DB 인증 설계에 집중했다.
서비스의 주요 사용자가 소상공인과 기업 담당자라는 점에서 시작된 고민은 단순한 로그인 방식 차이가 아니라, 계정 인수인계라는 중요한 시나리오로 이어졌다.</p>
<p>소상공인 → 카카오/구글 로그인, 전화번호 기반 간편 가입 선호</p>
<p>기업 담당자 → 회사 이메일 기반 로컬 가입, 구글 로그인 선호</p>
<p>문제는 기업 담당자가 퇴사하거나 휴가를 가는 상황이었다. 만약 서비스 계정을 개인 소셜 계정으로만 관리한다면, 업무 인수인계가 불가능해지는 리스크가 발생한다. 이 문제를 해결하기 위해 로컬 계정과 소셜 계정을 유연하게 연동 및 통합할 수 있는 구조가 필요했고, 결국 DB 인증 설계 방식을 근본적으로 고민하게 되었다.</p>
<ol>
<li>분리 설계 (LOCAL_AUTH &amp; SOCIAL_AUTH)</li>
</ol>
<p>장점: NULL 최소화, 데이터 정합성 확보, 책임 분리 명확</p>
<p>단점: JOIN 필요, 조회/통합 로직 복잡, 계정 이관 로직 어려움</p>
<ol start="2">
<li>통합 설계 (USER_AUTH)</li>
</ol>
<p>장점: 단순한 조회/관리, 계정 통합 로직 간단, 개발 및 유지보수 효율적</p>
<p>단점: NULL 값 증가, 데이터 정합성 검증 필요, 인덱싱 비효율 발생 가능</p>
<p>결국 통합 설계를 선택했다.
그 이유는 다음과 같다:</p>
<p>계정 통합이 간단하고 직관적이다.</p>
<p>인증 로직을 한 곳에서 관리할 수 있어 개발 속도와 유지보수가 쉬워진다.</p>
<p>NULL 값과 정합성 문제는 DBMS 성능과 애플리케이션 레벨(@PrePersist, @Valid 검증)로 충분히 극복 가능하다.</p>
<p>또한 ERD를 작성하면서 user / user_profile 분리도 중요한 의사결정이었다.</p>
<p>성능: 권한 확인 시 user만 조회하면 되도록 최소화</p>
<p>보안: 개인정보는 분리해 보호</p>
<p>확장성: 사용자 정보 확장 시 user 테이블 비대화 방지</p>
<p>관리 효율성: 개인정보 변경 주기를 고려해 관리 편의성 확보</p>
<p>아직 미숙한 부분도 있지만, 단순 스키마 설계가 아니라 서비스 시나리오를 반영한 설계 고민이라는 점에서 값진 경험이었다.</p>
<p>📚 배운 점</p>
<p>DB 설계는 단순 테이블 정의가 아니다 → 서비스 시나리오와 운영 관점까지 고려해야 한다.</p>
<p>분리 vs 통합 설계는 트레이드오프 관계 → 정합성/명확성 ↔ 개발 효율성/유연성 사이에서 균형을 잡아야 한다.</p>
<p>NULL 문제는 반드시 단점만은 아니다. 현대 DBMS 성능과 애플리케이션 검증 로직을 활용하면 충분히 제어 가능하다.</p>
<p>user / user_profile 분리는 성능, 보안, 확장성 모두에 영향을 주는 중요한 설계 패턴이다.</p>
<p>🎯 다음 주 목표</p>
<p>ERD를 기반으로 실제 엔티티 구현 및 JPA 매핑</p>
<p>통합 설계 방식에 따른 유효성 검증 로직(Entity + DTO) 구현</p>
<p>로그인/회원가입 API 프로토타입 제작</p>
<p>온라인 서점 프로젝트 마이페이지 보완 (Spring Security + 사용자 정보 연동)</p>
<p>RAG 프로젝트 문서 정리 (API 명세서 업데이트)</p>
<p>👉 이번 주는 <strong>“DB 인증 설계라는 본질적 고민”</strong>에 집중한 시간이었다. 단순히 돌아가는 코드가 아니라, 사용자의 실제 시나리오와 운영 관점까지 반영된 설계를 고민할 수 있었던 점이 가장 큰 성과다. 다음 주는 이를 실제 코드와 API로 풀어내며 한 단계 더 나아가고자 한다. 🚀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 22주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-22%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-22%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Mon, 25 Aug 2025 01:01:25 GMT</pubDate>
            <description><![CDATA[<p>🚀 진행 기간
2025.08.18 ~ 2025.08.22</p>
<p>📌 이번 주 활동</p>
<p>JVM &amp; VisualVM 활용 경험 정리 및 이력서 반영</p>
<p>온라인 서점 프로젝트 일부 리팩터링 (디자인 패턴 적용)</p>
<p>운영체제 &amp; 배포 수업 복습 (프로세스, 스케줄링, Docker)</p>
<p>Java 심화 주제 학습: 동시성 &amp; 가상 쓰레드 (Virtual Threads)</p>
<p>블로그 포스팅: “Java 동시성과 Virtual Thread”</p>
<p>💬 회고
이번 주는 지난주에 다듬었던 이력서를 한 단계 발전시켜, 단순 기술 나열이 아니라 내가 어떻게 성능 개선과 디버깅 경험을 했는지 구체적으로 녹여내는 데 집중했다. 특히 JVM 튜닝과 VisualVM 활용 경험을 문서화하면서, 단순히 &quot;툴을 써봤다&quot;가 아니라 어떤 문제 상황에서 왜 필요했는지, 어떻게 개선했는지를 스토리로 정리할 수 있었다.</p>
<p>온라인 서점 프로젝트 리팩터링에서는 전략 패턴과 팩토리 패턴을 적용했다. 결제 방식 분기 처리와 객체 생성 로직을 패턴으로 풀어내면서, 코드가 단순히 돌아가는 수준에서 유지보수성과 확장성을 고려한 구조로 바뀌는 걸 체감했다. 과제 프로젝트라고 해도, 이런 시도가 실제 실무 역량으로 연결된다는 점이 뿌듯했다.</p>
<p>운영체제 &amp; 배포 파트는 이론만 흘려듣던 개념을 다시 복습하면서, 프로세스 스케줄링과 컨텍스트 스위칭이 Java의 쓰레드 모델과 어떻게 맞닿아 있는지 연결할 수 있었다. 또한 Docker로 배포 실습을 하면서, &quot;운영 환경에서 컨테이너가 왜 필요한가&quot;라는 점을 다시 확인했다.</p>
<p>마지막으로, Java 동시성 심화 학습에서 Virtual Thread를 직접 실험해봤다. 기존 Thread 대비 훨씬 가볍게 동작하는 구조 덕분에, 동시 접속자가 많은 서비스에 어떻게 적용할 수 있을지 그림이 그려졌다. 단순히 “신기능”이 아니라, 실무에서 Blocking I/O와 고비용 쓰레드 문제를 어떻게 해소할지 고민하게 된 점이 가장 큰 수확이었다.</p>
<p>📚 배운 점</p>
<p>이력서에 경험을 녹일 때는 “툴/기술” → “문제 상황” → “해결 방법” → “성과” 구조가 설득력을 높인다.</p>
<p>디자인 패턴은 실제 프로젝트 코드에서 리팩터링할 때 가장 효과적으로 체득된다.</p>
<p>운영체제 개념은 서버 성능/배포 환경 이해와 직결된다.</p>
<p>Virtual Thread는 동시성 프로그래밍을 단순화하면서도 확장성을 크게 높일 수 있는 Java 21의 핵심 기능이다.</p>
<p>🎯 다음 주 목표</p>
<p>온라인 서점 프로젝트 마이페이지 기능 보완 (Spring Security + 사용자 정보 연결)</p>
<p>RAG 프로젝트 문서 정리 (ERD + API 명세서 업데이트)</p>
<p>이력서 최종 마무리 후 멘토 피드백 받기</p>
<p>Java 병렬 처리(CompletableFuture, Structured Concurrency) 학습 및 블로그 정리</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 21주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-21%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-21%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Thu, 14 Aug 2025 08:08:00 GMT</pubDate>
            <description><![CDATA[<p>🚀 진행 기간</p>
<p>2025.08.11 ~ 2025.08.15</p>
<p>📌 이번 주 활동</p>
<p>이력서/포트폴리오 보완 작업</p>
<p>Java 21 최신 문법 학습</p>
<p>함수형 프로그래밍(람다 &amp; 스트림) 심화</p>
<p>디자인 패턴 정리 및 사례 학습</p>
<p>예외 처리 구조 복습</p>
<p>💬 회고</p>
<p>이번 주는 이력서를 조금 더 다듬고, 그 안에 어떤 학습 경험을 녹여낼지 고민하는 시간이었다. 단순히 기술 스택만 나열하는 게 아니라, 실제로 내가 배우고 써본 것들을 어떻게 스토리로 풀어낼지가 중요하다는 걸 다시 느꼈다.</p>
<p>특히 Java 21 최신 기능을 하나씩 정리하면서, “아 내가 최신 버전을 이해하고 있다는 걸 어떻게 어필할 수 있을까?”라는 고민을 했다. 그냥 switch문이 바뀌었다 정도가 아니라, 패턴 매칭이나 레코드 패턴, 가상 쓰레드 같은 기능이 실무에서 어떻게 쓰일 수 있을지 연결하려고 노력했다.</p>
<p>또한 람다와 스트림을 단순히 코드 축약 문법으로만 보던 시각에서 벗어나, “함수형 인터페이스와 결합해서 컬렉션 데이터를 선언적으로 처리하는 도구”라는 점을 다시금 체감했다. 이 과정에서 Predicate, Function, Supplier 같은 인터페이스들을 구체적으로 이해한 게 큰 수확이었다.</p>
<p>이력서를 쓰다 보니 디자인 패턴도 단순히 교재 속 지식이 아니라, 프로젝트 리팩터링에서 어떻게 활용할 수 있을지 생각하게 됐다. 예를 들어, 싱글톤은 DB 연결에, 전략 패턴은 정책 추천 알고리즘 분기에, 옵저버 패턴은 이벤트 처리 구조에 쓸 수 있겠다는 식으로 연결해봤다.</p>
<p>마지막으로, 예외 처리를 다시 보면서 단순히 try-catch로 끝내는 게 아니라, 예외 계층 구조 설계와 메시지 전달 방식도 중요하다는 걸 깨달았다. 예외 처리가 단순한 방어가 아니라 “협업에서 의도를 전달하는 수단”이라는 관점이 인상 깊었다.</p>
<p>📚 배운 점</p>
<p>이력서를 쓰는 과정은 내 학습을 되짚는 과정이 될 수 있다.</p>
<p>Java 21의 변화는 단순히 문법 개선이 아니라, OOP와 FP의 조화를 가능하게 하는 방향으로 나아가고 있다.</p>
<p>람다와 스트림은 코드 축약이 아니라 데이터 처리 패러다임을 바꾸는 도구다.</p>
<p>디자인 패턴은 프로젝트에 녹여야 의미가 있다. 단순 암기가 아니라 실제 활용 맥락이 중요하다.</p>
<p>예외 처리는 코드 품질뿐 아니라 협업 가독성에도 직결된다.</p>
<p>🎯 다음 주 목표</p>
<p>이력서에 JVM, VisualVM 활용 경험 추가</p>
<p>온라인 서점 프로젝트 리팩터링 (디자인 패턴 적용)</p>
<p>운영체제 &amp; 배포 수업 복습</p>
<p>Java 심화 주제(동시성, 가상 쓰레드) 블로그 정리</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 20주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-20%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-20%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Sun, 10 Aug 2025 08:46:27 GMT</pubDate>
            <description><![CDATA[<p>🚀 진행 기간
2025.08.04~2025.08.08</p>
<p>📌 이번 주 활동
AI 챗봇 프로젝트 종료</p>
<p>이력서 및 포트폴리오 작성 시작</p>
<p>휴가 및 재충전</p>
<p>자바 기초 복습</p>
<p>💬 회고
이번 주는 프로젝트를 마무리하고 커리어 준비에 집중하는 주간이었다.
휴가도 다녀오며 리프레시했고, 그동안 놓쳤던 자바 공부도 병행했다.</p>
<p>일요일까지 이력서를 제출하라는 안내를 받았지만, 프로젝트 완성도가 낮아 포트폴리오로 쓰기 어렵다고 생각했던 터라 처음엔 의욕이 크지 않았다.
하지만 막상 프로젝트를 처음부터 되짚어 보니, 아무것도 모르는 상태에서 설계·구현까지 해낸 점은 나름 괜찮지 않았나 하는 생각이 들었다.</p>
<p>그 과정에서 요구사항을 맞추느라 급하게 넘겼던 부분</p>
<p>GPT가 준 코드를 이유 없이 썼던 부분
등을 다시 보며, 왜 그렇게 작성했는지, 아쉬운 점은 무엇인지 조금씩 이해할 수 있었다.
또한 이 기능은 생각보다 잘 만들었네 싶은 부분도 발견했다.</p>
<p>결국 이력서는 프로젝트 리팩터링이 됐다는 가정하에 반영된 형태로 제출했고, 일종의 TODO 리스트가 본의 아니게 된 것 같다.
부정적인 생각보다는 긍정적으로 바라보고, 하나씩 개선하며 뒤돌아봤을 때 많이 성장해 있길 바란다.</p>
<p>📚 배운 점
지나간 프로젝트라도 다시 보면 성장 포인트를 찾을 수 있다.</p>
<p>처음에 완성도가 부족하다고 느껴도 그 속에 배운 점과 성취는 분명 존재한다.</p>
<p>코드의 의도와 아쉬운 점을 스스로 판단할 수 있는 시야가 조금은 생겼다.</p>
<p>🎯 다음 주 목표
이력서 기반 프로젝트 리팩터링 본격 착수
운영체제 , 배포 수업 복습 잘 하기
자바 복습 + 심화 주제 학습</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 19주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-19%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-19%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Thu, 31 Jul 2025 09:58:57 GMT</pubDate>
            <description><![CDATA[<p>🚀 진행 기간
2025.07.28 ~ 2025.08.01</p>
<p>이번 주는 단순 구현을 넘어, <strong>AI 시스템을 실제 “운영 가능하고 발전 가능한 형태로 만드는 것”</strong>에 집중했다. 지난주가 가능성 중심의 탐색기였다면, 이번 주는 명확한 방향성과 근거를 갖춘 구조화를 통해 RAG 시스템의 신경망을 실제로 엮어낸 시간이었다.</p>
<p>🔹 1. 하이브리드 RAG 구조 개선
문제: “서울 사는 20대 청년에게 맞는 주거 정책”처럼 복합 조건을 가진 질문은 벡터 검색만으로 정확한 결과를 내기 어려움</p>
<p>해결:</p>
<p>RDB(PostgreSQL) 로 나이, 지역, 소득 등 정형 조건 필터링</p>
<p>벡터 DB(Chroma) 로 감성적/의미 기반 정책 검색</p>
<p>FastAPI 서비스에서 sql_first / vector_first / hybrid 전략을 LLM이 의도 분석 후 동적으로 선택</p>
<p>했으나 정형데이터를 비정형데이터로 변환한 후 임베딩 하는 방안이 필요로 해보였다 시간 부족으로 해내지 못해서 아쉽다</p>
<p>🔹 2. 동적 프롬프트 시스템 구축
기존 하드코딩된 프롬프트 구조를 개선하여,</p>
<p>DB에 저장된 prompts 테이블에서 관리</p>
<p>intent_category에 따라 분류하여 재사용</p>
<p>ab_test_configs를 활용해 프롬프트 A/B 테스트까지 자동화 설계</p>
<p>실험과 개선 사이클이 가능한 구조를 갖추었으며, 향후 프롬프트 품질 향상에 기반이 될 것으로 기대</p>
<p>🔹 3. 상세 로깅 시스템 도입
hybrid_search_logs 테이블을 통해 아래 항목을 모두 저장</p>
<p>사용자 질문</p>
<p>의도 분석 결과</p>
<p>선택된 검색 전략</p>
<p>각 단계별 처리 시간(SQL/Vector/LLM)</p>
<p>최종 응답</p>
<p>추후 병목 분석, 프롬프트 개선, 사용자 피드백 반영 등 실질적 개선을 위한 기초 데이터 수집 체계 완성</p>
<p>🤔 배운 점 &amp; 느낀 점</p>
<p>검색과 생성을 단순히 “붙이는” 것이 아니라, 사용자 의도에 따라 어떤 경로로 정보를 찾을 것인지 설계해야 한다는 점을 절실히 느꼈다.</p>
<p>이 과정에서 정형 데이터의 가치를 재발견했다. AI 시대에도 RDB는 여전히 강력한 무기다.</p>
<p>🧩 RAG에서의 임베딩 대상은 “비정형 데이터”임을 실감
주제 특성상 구조화된 정책 데이터 위주라, 벡터 임베딩 효과를 충분히 살리기 어려웠다.</p>
<p>정형 데이터 조건 필터링이 중요하긴 했지만, 비정형 설명문이 충분하지 않아 의미 기반 검색의 강점을 충분히 보여주긴 어려운 구조였다.</p>
<p>→ RAG 프로젝트에선 오히려 비정형 데이터가 많을수록 유리하다는 사실을 실감</p>
<p>📉 주제 선정에 대한 회고
처음에는 “정책 데이터라 정보가 정확하고 좋겠다”고 생각했지만, 데이터 양이 부족하고 비정형성이 떨어지는 구조였기 때문에, 결과적으로 RAG 주제로는 적합하지 않았을 수도 있다는 생각이 들었다.</p>
<p>더 방대한 비정형 문서를 가진 도메인(의료, 민원, 백과 등)이었다면 더 풍부한 검색 결과와 LLM 조합을 실현할 수 있었을 것 같다.</p>
<p>🔄 역할 분담에 대한 고민
초반에는 역할을 분리하려 했지만, 주제가 단순한 구조에서 크게 벗어나지 않아 자연스럽게 각자가 전체 기능을 다루게 되는 방식으로 진행됐다.</p>
<p>이게 좋은 선택이었는지는 아직 잘 모르겠다. 개인의 학습 효율은 좋았지만, 팀 기반 협업 훈련이라는 측면에서는 아쉬운 점도 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 18주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-18%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-18%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Fri, 25 Jul 2025 09:54:26 GMT</pubDate>
            <description><![CDATA[<p>🤖 18주차 회고
기간: 7/21 ~ 7/25
주제: 하이브리드 RAG와 동적 프롬프트 시스템 구축</p>
<p>지난주 LLM과 RAG의 세계에 첫발을 내디뎠다면, 이번 주는 그 가능성을 실현 가능한 시스템으로 확장한 시간이었다. 단순한 벡터 검색의 한계를 절감하며, 보다 정교하고 유연한 AI 시스템을 만들기 위한 구체적인 리팩터링과 설계를 진행했다.</p>
<p>✅ 주요 개선 및 구현
이번 주는 시스템의 ‘뇌’를 설계하고, ‘신경망’을 연결하는 작업에 집중했다. MVP를 넘어서 실사용 가능한 AI 시스템의 기반을 다진 한 주였다.</p>
<ol>
<li>하이브리드 RAG 도입
문제 인식: “서울 사는 20대 청년에게 맞는 주거 정책 알려줘”와 같은 복합 질문은 벡터 검색만으로는 정확한 결과를 내기 어려웠다.</li>
</ol>
<p>해결 전략:</p>
<p>RDB(PostgreSQL)로 나이, 지역, 소득 등 정형 조건 필터링</p>
<p>벡터 DB(Chroma)로 “위로가 되는 정책” 같은 의미 기반 검색</p>
<p>LLM이 사용자의 질문을 분석하여 sql_first, vector_first, hybrid 전략을 동적으로 선택하도록 구성 (hybrid_rag_service.py)</p>
<p>성과: 검색 정확도와 속도가 모두 향상되었고, 사용자 의도에 맞는 유연한 대응이 가능해졌다.</p>
<ol start="2">
<li>동적 프롬프트 시스템 구축
문제 인식: 프롬프트가 코드에 하드코딩되어 있었다</li>
</ol>
<p>개선 방안:</p>
<p>모든 프롬프트를 DB(prompts)로 관리</p>
<p>상황별 프롬프트를 intent_category 기준으로 분류</p>
<p>ab_test_configs 테이블을 활용해 A/B 테스트 자동화 → 성능 기반으로 프롬프트 선택</p>
<p> 프롬프트 수정과 실험이 체계적 관리가 가능하다고 하는데 정확한건 테스트를 더 해보며 내가 체감해야 할 것 같다</p>
<ol start="3">
<li>상세 로깅 시스템 도입
필요성: LLM과 RAG의 내부 작동 과정을 모르면 개선이 불가능</li>
</ol>
<p>구현: hybrid_search_logs를 통해</p>
<p>사용자의 질의</p>
<p>의도 분석 결과</p>
<p>선택된 검색 전략</p>
<p>각 단계(SQL, Vector, LLM)의 응답 시간</p>
<p>검색 결과 및 최종 응답
등을 모두 저장</p>
<p>활용: 추후 병목 분석, 프롬프트 개선, A/B 테스트 효과 분석의 기반 데이터로 사용 가능</p>
<p>🤔 이번 주에 배운 것들
RAG는 검색 + 생성 그 이상: 단순히 정보를 찾아서 요약하는 게 아닌, 검색 전략 자체를 설계하고 개선하는 과정이 핵심임을 체감했다.</p>
<p>정형 데이터의 가치: AI 시대에도 RDB의 정확한 조건 필터링은 벡터 DB의 약점을 보완해주는 훌륭한 도구가 될 수 있다.</p>
<p>운영 데이터 기반 개선의 중요성: 살아있는 AI 시스템은 로깅, 실험, 피드백 루프를 통해 스스로 발전할 수 있어야 한다는 점을 절감했다.</p>
<p>📈 성장?...
지난주는 “무엇을 구현할 것인가”에 집중했다면, 이번 주는 “왜 이 구조가 필요한가”를 생각하며 방향성을 정립하는 데 집중했다.</p>
<p>팀원은 어떻게 했나 참고하고 의견을 구하며 개발 속도와 이해도도 높아졌고...? 얻은게 있는 거 같다</p>
<p>🚀 다음 주 계획
관리자 대시보드 개발:
hybrid_search_logs, prompt_analytics 데이터를 시각화하여 시스템 성능과 개선 포인트를 한눈에 볼 수 있는 대시보드 구현 예정</p>
<p>프롬프트 A/B 테스트 본격화:
특히 ‘금융’ 카테고리 프롬프트에 대해 두 가지 버전을 비교 실험하고, 응답 품질 차이를 분석할 계획</p>
<p>💭 마무리
&quot;코드가 부끄러우면 성장하고 있는 것이다&quot; 라는 말처럼, 이번 주는 지난 코드를 리팩터링하며 많은 성찰이 있었다.</p>
<p>처음에는 막연했던 RAG 프로젝트가 이제는 자신의 판단과 데이터를 바탕으로 발전할 수 있는 시스템으로 느껴진다. 팀원들과 함께 이 시스템을 어떻게 진화시킬지 고민하는 과정이 정말 즐겁다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 17주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-17%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-17%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Mon, 21 Jul 2025 01:11:21 GMT</pubDate>
            <description><![CDATA[<h1 id="🤖-17주차-회고">🤖 17주차 회고</h1>
<p><strong>기간</strong>: 7/14 ~ 7/18 <strong>주제</strong>: LLM과 RAG - AI의 새로운 세계로</p>
<p>AI 팀프로젝트의 팀장을 맡으면서 LLM과 RAG를 본격적으로 학습한 한 주. 처음 접하는 AI 영역이라 시행착오가 많았지만, 그만큼 배운 것도 많았다.</p>
<h2 id="✅-주요-학습-내용">✅ 주요 학습 내용</h2>
<h3 id="llmlarge-language-model-기초">LLM(Large Language Model) 기초</h3>
<ul>
<li>대규모 언어 모델의 작동 원리</li>
<li>자연어 이해/생성 능력과 한계점</li>
<li>최신 정보 부족, 환각(Hallucination) 현상</li>
</ul>
<h3 id="langchain-활용법">LangChain 활용법</h3>
<ul>
<li><strong>Chain</strong>: 프롬프트 → 모델 호출 → 출력 처리 파이프라인</li>
<li><strong>Agents</strong>: LLM이 도구를 자율적으로 선택 사용</li>
<li><strong>Memory</strong>: 대화 맥락 유지</li>
<li><strong>Tool Integration</strong>: 외부 시스템 연동</li>
</ul>
<h3 id="ragretrieval-augmented-generation">RAG(Retrieval-Augmented Generation)</h3>
<ul>
<li><strong>검색</strong> → <strong>보강</strong> → <strong>생성</strong>의 3단계 프로세스</li>
<li>벡터 DB를 활용한 정보 검색</li>
<li>LLM 한계 극복을 위한 핵심 기술</li>
</ul>
<h2 id="🚧-팀장으로서-겪은-초기-시행착오">🚧 팀장으로서 겪은 초기 시행착오</h2>
<h3 id="1-잘못된-방향성-설정">1. 잘못된 방향성 설정</h3>
<p><strong>문제</strong>: LLM과 RAG 개념 이해 없이 막연한 목표만 설정<br><strong>결과</strong>: 작업 진행 방향성, 순서를 명확히 잡지 못하고 헤맸음
<strong>깨달음</strong>: 팀장이 기술을 제대로 모르면 팀 전체가 헤맨다</p>
<h3 id="2-과도한-완벽주의">2. 과도한 완벽주의</h3>
<p><strong>문제</strong>: 처음부터 완성도 높은 시스템을 만들려고 시도<br><strong>결과</strong>: 복잡한 아키텍처 설계로 개발 진행 지연<br><strong>해결</strong>: MVP 방식으로 전환, 기본 RAG 구조부터 구현</p>
<h3 id="3-역할-분담의-어려움">3. 역할 분담의 어려움</h3>
<p><strong>문제</strong>: AI 프로젝트 특성상 기존 웹 개발과 다른 역할 분담 필요<br><strong>시행착오</strong>: 팀원들 개개인에 학습을 목표로 각자 A~Z 까지 해보며 스터디 느낌으로 피드백 주고받고 구현 마친 뒤 병합 목표</p>
<h2 id="💡-의외의-발견들">💡 의외의 발견들</h2>
<h3 id="ai-개발의-특이점">AI 개발의 특이점</h3>
<ul>
<li>확률적 결과 → 지속적 실험과 개선 필요</li>
<li>프롬프트 엔지니어링의 중요성</li>
<li>전통적 디버깅과 완전히 다른 접근법</li>
</ul>
<h2 id="📈-팀장으로서-배운-것들">📈 팀장으로서 배운 것들</h2>
<p><strong>기술 이해의 중요성</strong><br>팀장이 기술을 정확히 모르면 잘못된 방향으로 팀을 이끌 수 있다.</p>
<p><strong>유연한 계획 수립</strong><br>AI 프로젝트는 예상과 다른 결과가 자주 나오므로 계획을 수시로 조정해야 한다.</p>
<p><strong>팀원 학습 시간 확보</strong><br>새로운 기술 영역이라 개개인의 학습 시간을 충분히 배려해야 한다.</p>
<h2 id="🚀-다음-주-계획">🚀 다음 주 계획</h2>
<ul>
<li>프로젝트 완성도 높이기</li>
<li>AI 기술과 기존 웹 개발 지식 융합</li>
</ul>
<h2 id="💭-마무리">💭 마무리</h2>
<p>팀장 역할과 새로운 기술 학습을 동시에 하는 것은 쉽지 않았지만, <strong>&quot;모르는 것을 인정하고 팀과 함께 배워가는 것&quot;</strong>이 더 나은 리더십일 수 있다는 걸 깨달았다.</p>
<p>완벽한 계획보다는 빠른 시행착오와 지속적 개선이 AI 프로젝트에서는 더 중요하다는 것도 배웠다. 아직 갈 길이 멀지만, 팀원들과 함께 성장하고 있다는 느낌이 든다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 16주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-16%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-16%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Sun, 13 Jul 2025 23:46:25 GMT</pubDate>
            <description><![CDATA[<h1 id="🗓-16주차-회고">🗓 16주차 회고</h1>
<p><strong>기간</strong>: 7/7 ~ 7/11<br><strong>주제</strong>: Spring Boot 온라인 서점 프로젝트 총정리 및 한 학기 회고</p>
<p>이번 주는 과제 온라인 서점을 마무리하며, 지금까지의 학습 여정을 되돌아보는 시간이었다. 비록 프로젝트를 완성하지 못하고 제출했지만, 그 과정에서 얻은 깨달음이 더 소중했다.</p>
<h2 id="✅-온라인-서점-프로젝트-현황">✅ 온라인 서점 프로젝트 현황</h2>
<h3 id="완성된-부분-약-65">완성된 부분 (약 65%)</h3>
<ul>
<li><strong>도메인 설계</strong>: Book, Member, Order 등 핵심 엔티티 완전 구현</li>
<li><strong>기본 아키텍처</strong>: Spring Boot + JPA + Security + Thymeleaf 구조 완성</li>
<li><strong>관리자 기능</strong>: 상품 목록 조회, 검색, 페이징, 정렬 기능 구현</li>
<li><strong>사용자 기능</strong>: 메인페이지, 베스트셀러, 인기검색어, 기본 인증 시스템</li>
</ul>
<h3 id="미완성된-부분">미완성된 부분</h3>
<ul>
<li><strong>프론트엔드</strong>: 관리자 폼 페이지들, 상품 상세 페이지</li>
<li><strong>결제 시스템</strong>: 카카오페이 연동 등 외부 API 통합</li>
<li><strong>세부 기능</strong>: 리뷰 시스템, 장바구니 완성도</li>
</ul>
<h2 id="💡-15주간의-학습-연결고리-발견">💡 15주간의 학습 연결고리 발견</h2>
<h3 id="구조적-사고의-진화">구조적 사고의 진화</h3>
<ul>
<li><strong>8주차 게시판</strong>: DTO → Service → Controller 구조 학습</li>
<li><strong>14주차 LangChain</strong>: 프롬프트 → 체인 → 도구 → 에이전트 구조</li>
<li><strong>16주차 서점</strong>: Domain → Repository → Service → Controller → View 5계층 구조</li>
</ul>
<p>모든 프로젝트가 결국 <strong>&quot;작은 구성요소들의 조합&quot;</strong>이라는 공통 원리를 따르고 있음을 깨달았다.</p>
<h3 id="문제-해결-접근법의-일관성">문제 해결 접근법의 일관성</h3>
<pre><code>1. 요구사항 분석 → 설계 → 구현 → 테스트 → 디버깅</code></pre><p>이 과정이 게시판에서나, AI 에이전트에서나, 서점 프로젝트에서나 동일했다.</p>
<h2 id="🚧-이번-주-특별한-어려움들">🚧 이번 주 특별한 어려움들</h2>
<h3 id="1-완벽주의의-함정">1. 완벽주의의 함정</h3>
<p>초기에 모든 기능을 완벽하게 구현하려다가 시간 관리에 실패했다. 이번엔 우선순위 설정의 중요성을 배웠다.</p>
<h3 id="2-프론트엔드와-백엔드의-균형">2. 프론트엔드와 백엔드의 균형</h3>
<p>백엔드 로직에 집중하느라 사용자가 실제로 보고 사용할 화면 구현에 소홀했다. 기능이 아무리 완벽해도 인터페이스가 없으면 의미가 없다는 걸 체감했다.</p>
<h3 id="3-외부-연동의-복잡성">3. 외부 연동의 복잡성</h3>
<p>카카오페이 API, 이메일 발송 등 외부 시스템과의 연동이 예상보다 복잡했다. 단순한 CRUD와는 다른 차원의 문제들이 있었다.</p>
<h2 id="긍정적인-생각-하자">긍정적인 생각... 하자..</h2>
<h3 id="1-미완성의-가치-인정">1. <strong>&quot;미완성의 가치&quot; 인정</strong></h3>
<p>이전엔 완성하지 못한 프로젝트를 실패로 여겼지만, 이제는 과정에서의 학습과 시행착오도 소중한 경험이라는 걸 안다.</p>
<h3 id="2-문제-해결-패턴-인식">2. <strong>문제 해결 패턴 인식</strong></h3>
<p>어떤 새로운 기술을 마주해도 &quot;구조 파악 → 작은 단위로 분해 → 단계별 구현&quot;이라는 접근법을 자연스럽게 적용하게 되었다.</p>
<h3 id="3-학습-연결고리-만들기">3. <strong>학습 연결고리 만들기</strong></h3>
<p>각 주차의 학습 내용들이 독립적이 아니라 서로 연결되어 있음을 발견하고, 이를 의식적으로 연결시키려 노력하게 되었다.</p>
<h2 id="🚀-앞으로의-계획">🚀 앞으로의 계획</h2>
<h3 id="단기-목표">단기 목표</h3>
<ol>
<li><strong>서점 프로젝트 완성</strong>: 제출기한은 지났으나.. 카카오페이 연동과 프론트엔드 완성</li>
<li><strong>포트폴리오 도전..?</strong>: 게시판 → AI 에이전트 → 서점으로 이어지는 성장 스토리 문서화</li>
</ol>
<h3 id="장기-목표">장기 목표</h3>
<p><strong>기초 원리 심화</strong>: 자바, 스프링, 파이썬, 네트워크, 데이터베이스, 알고리즘 등 컴퓨터 과학 기초 강화</p>
<h2 id="💭-마무리-미완성도-하나의-완성">💭 마무리: 미완성도 하나의 완성</h2>
<p>16주간 가장 큰 깨달음은 <strong>&quot;완벽한 프로젝트보다 성장하는 과정이 더 중요하다&quot;</strong>는 것이다. </p>
<p>서점 프로젝트는 미완성으로 제출했지만, 그 과정에서:</p>
<ul>
<li>프로젝트의 복잡성을 경험했고</li>
<li>시간 관리와 우선순위 설정의 중요성을 배웠으며  </li>
<li>기존 학습 내용들이 어떻게 연결되고 확장되는지 체감했다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 15주차 -회고,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-15%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-15%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Mon, 07 Jul 2025 00:01:21 GMT</pubDate>
            <description><![CDATA[<p>🗓 기간: 6/30 ~ 7/4
주제: LangChain 에이전트 이해 및 디버깅
이번 주는 2주 전 게시판 구현과는 완전히 다른 영역인 AI 에이전트를 학습했다. &quot;AI가 스스로 도구를 선택해서 문제를 해결한다&quot;는 개념 자체가 신선했고, 전통적인 웹 개발과는 다른 접근이 필요했다.
✅ 주요 학습 내용
LangChain 핵심 구조 이해:</p>
<p>프롬프트 템플릿 → 체인 → 도구 → 에이전트의 단계별 구조
에이전트의 사고 과정: 생각(Thought) → 행동(Action) → 관찰(Observation) → 재시도</p>
<p>실습한 기능들:</p>
<p>인구 조회, 간단한 2연산 함수</p>
<p>해보면 좋을 것 같은 것들 :</p>
<p>기본 도구 만들기 (계산기, 검색, 날씨 조회)
verbose=True로 AI 사고과정 실시간 관찰
에이전트 실패 → 재시도 과정 디버깅
도구 설명 최적화를 통한 정확도 향상</p>
<p>디버깅 방법들:</p>
<p>단계별 실행 과정 추적
도구별 에러 처리 로직 구현
성능 모니터링 및 성공률 측정</p>
<p>💡 깨달은 점
구조적 유사성 발견:
2주 전 게시판의 DTO → Service → Controller 구조와 LangChain의 구성 요소들이 본질적으로 유사하다는 점을 깨달았다. 복잡한 시스템도 결국 작은 구성 요소들의 조합이라는 원리는 동일했다.
도구 설명의 중요성:
AI가 올바른 도구를 선택하려면 각 도구의 역할과 사용 조건을 명확히 기술해야 한다는 점이 게시판에서 메소드명, 변수명을 명확히 했던 것과 비슷했다.
예외 처리의 일관성:
게시판에서 권한 체크, null 체크를 했던 것처럼 AI 도구에서도 예외 상황을 미리 고려한 안전장치가 필요함을 확인했다.
🚧 어려웠던 점
추상적 개념의 구체화:
에이전트가 스스로 판단한다는 개념이 처음엔 추상적이었지만, verbose=True로 사고과정을 관찰하면서 결국 고도화된 조건문 로직이라는 걸 이해할 수 있었다.
디버깅 방식의 차이:
기존 코드는 break point로 단계별 확인이 가능했지만, AI 에이전트는 &quot;왜 이 선택을 했는지&quot; 파악하는 게 어려워서 새로운 디버깅 접근법이 필요했다.
🎯 2주 전과의 비교
공통점:
기본적인 구조적 사고, 예외 처리, 디버깅 접근법은 동일했다. 기존에 배운 개발 원칙들이 AI 개발에도 그대로 적용되었다.
차이점:
이번엔 구성 요소 중 하나가 &quot;생각하는 AI&quot;였고, 결정론적 로직 대신 확률적 판단을 다뤄야 했다.</p>
<p> 느낀 점
AI 개발도 결국 기본기의 연장선이다. 2주 전 게시판에서 배운 구조적 사고와 예외 처리 경험이 AI 에이전트 이해에 직접적으로 도움이 되었다. 새로운 기술이지만 근본적인 개발 원칙은 변하지 않는다는 걸 확인했다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 14주차 -회고 ,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-14%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-14%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Mon, 30 Jun 2025 00:34:32 GMT</pubDate>
            <description><![CDATA[<h2 id="커널아카데미백엔드-부트캠프-12기-14주차---회고-학습블로그">[커널아카데미]백엔드 부트캠프 12기 14주차 - 회고, 학습블로그</h2>
<h3 id="🗓-기간-623--627">🗓 기간: 6/23 ~ 6/27</h3>
<p>이번 주는 팀 프로젝트 마무리 주간이자 최종 발표가 진행된 주였다. 지난주까지 기능 구현과 병행해 준비했던 작업들을 모두 마무리하며, 전체적인 흐름을 되짚고 마지막 다듬기에 집중했다.</p>
<hr>
<h3 id="✅-내가-맡은-주요-업무">✅ 내가 맡은 주요 업무</h3>
<ul>
<li><p>게시판 도메인 전반 구현 (FAQ, 공지사항, QnA)</p>
</li>
<li><p>공통 기능 적용:</p>
<ul>
<li>페이징 처리</li>
<li>검색 기능 (제목+내용)</li>
<li>소프트 딜리트 로직 (게시글 상태값 관리)</li>
<li>조회수 증가 처리 (비관리자만 해당)</li>
</ul>
</li>
<li><p>공지사항:</p>
<ul>
<li>메인 배너용 최신 공지 1건 출력 (공지 없을 경우 예외 처리)</li>
<li>우선순위 기반 상단 고정 기능 구현</li>
<li>관리자만 등록/수정/삭제 가능하도록 권한 분기</li>
</ul>
</li>
<li><p>FAQ:</p>
<ul>
<li>카테고리별 필터링 기능</li>
<li>수정일, 등록일 구분 출력 처리</li>
<li>상세 페이지 CSS 구조 개선</li>
</ul>
</li>
<li><p>QnA:</p>
<ul>
<li>고객 문의 등록, 비밀글 설정 기능</li>
<li>관리자 답변 등록 및 수정</li>
<li>비밀글 접근 권한 제어 (작성자+관리자만 열람 가능)</li>
<li>상태값이 &#39;DEL&#39;인 경우 전면 비노출 처리</li>
</ul>
</li>
</ul>
<hr>
<h3 id="💡-고민했던-부분">💡 고민했던 부분</h3>
<ul>
<li>게시판 공통 구조를 어떻게 정의하고 재사용성 높일 것인지</li>
<li>비회원/회원/관리자 각각의 권한 분기에 따라 어떤 데이터가 보여야 하는지</li>
<li>고정글 우선순위 처리: SQL 정렬 로직과 Mapper 내 다중 조건 처리</li>
<li>예외 처리: 공지사항이 없을 경우 graceful한 안내 문구 처리</li>
<li>게시글 상태값과 연동된 조회 제한, 삭제 처리 흐름 정리</li>
</ul>
<hr>
<h3 id="🧠-배운-점--느낀-점">🧠 배운 점 &amp; 느낀 점</h3>
<ul>
<li>단순한 기능도 실제 구현해보면 연관된 계층이 많다 (DTO → Mapper → Service → Controller → View)</li>
<li>Mapper alias, 컬럼명이 조금만 어긋나도 Null 또는 Binding 오류가 나는 등 디테일이 중요함을 체감함</li>
<li>기획 → 설계 → 구현 → 예외처리 → 프론트연동까지의 전체 흐름을 이해한 후 구현해야 예측 가능한 결과를 만들 수 있다</li>
<li>발표가 끝이라고 끝이 아니라, 실제로 구현을 통해 다시 설계를 검증하는 과정이 포함되어 있음을 느꼈다</li>
<li>지금 당장은 이해가 더딜 수 있지만, 제대로 이해한 후 구현에 들어가는 것이 결국 더 빠른 길이라는 것을 다시금 실감함</li>
</ul>
<hr>
<h3 id="😓-아쉬운-점">😓 아쉬운 점</h3>
<ul>
<li>발표 당일, 시연을 사전에 연습하지 못해 흐름이 매끄럽지 못했고,
팀원들이 구현한 주요 기능 일부를 제대로 보여주지 못해 아쉬움이 남았다</li>
<li>전체적으로 CSS, JSP, Mapper, Service, DTO, Java 간의 연관 관계에 대한 깊은 이해가 부족했고,
Git 등의 협업 툴에 대한 숙련도도 낮아 기여보다는 도움을 받은 부분이 많았다</li>
<li>다음 프로젝트에서는 이번 경험을 바탕으로 전체 구조에 대한 선이해와 협업 준비에 더 집중할 계획이다</li>
</ul>
<hr>
<h3 id="🌱-다음을-위한-다짐">🌱 다음을 위한 다짐</h3>
<blockquote>
<p>&quot;완벽하지 않아도, 흐름을 잡고 하나씩 구현해나가면 결국 끝이 보인다.
다음 프로젝트에서는 구조 이해와 협업 숙련도를 높여 더 주도적으로 참여하겠다.&quot;</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 13주차 -회고 ,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-13%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-13%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Sun, 22 Jun 2025 11:10:27 GMT</pubDate>
            <description><![CDATA[<p>🗓 13주차 회고 (6/16 ~ 6/20)
이번 주는 팀 프로젝트 2주차. 지난주에 숙소/객실/정책 설계를 맡았다면, 이번 주는 메인페이지와 게시판 기능 구현에 집중했다.
특히 공지사항 배너와 상세 페이지 연결을 맡았는데, 이 단순해 보이는 기능도 실제로 구현해보니 고려할 게 꽤 많았다.</p>
<p>공지사항 배너에는 항상 최신 글이 떠야 하고, 해당 제목을 누르면 상세 페이지로 이동해야 한다.
또한, &quot;공지사항이 존재하지 않을 때는 안내 문구가 떠야 한다&quot;는 예외 처리까지 필요했다.
이걸 구현하기 위해 DTO 수정 → Mapper SQL 수정 → Controller/Service 로직 수정까지 하나하나 손봤다.</p>
<p>사실 이번 주 구현을 바로 들어간 게 아니라, 강사님의 게시판 만들기 강의를 먼저 복습하면서 흐름을 다시 정리하는 데 시간을 좀 썼다.
공지사항이 단순한 게시판처럼 보여도 실제로는 다양한 예외 처리, 흐름 제어, 데이터 구조가 엮여 있었기 때문에
내가 이해가 부족한 채로 덤비면 오히려 비효율적일 것 같다는 판단 때문이었다.
덕분에 실제 구현 흐름은 잘 따라갔지만, 그만큼 구현 시작이 늦어졌다는 아쉬움도 남는다.</p>
<p>📌 내가 맡은 주요 업무
메인페이지의 공지사항 배너 구현</p>
<p>가장 최신 공지 1건만 표시</p>
<p>공지사항 없을 시 예외 문구 출력 처리</p>
<p>클릭 시 상세 페이지로 이동</p>
<p>공지사항 DTO 구조 정의 및 DB 컬럼 정비</p>
<p>상단 고정 여부(isNeedPin), 메인 고정 여부(isMain), 게시글 상태(noticeStatus), 우선순위(priority) 등</p>
<p>NoticeMapper 및 Service 전반 수정</p>
<p>공지 상세/목록 기능 흐름 이해 및 정리</p>
<p>추후 리뷰 게시판 설계를 염두한 공통 항목 정리</p>
<p>💡 고민했던 부분
공지사항이 DB에 없을 때의 흐름 처리 (메인 배너에서 graceful하게 처리해야 함)</p>
<p>게시판 공통 구조를 어떻게 정의할 것인지</p>
<p>상단 고정글을 어떻게 우선순위와 함께 처리할 것인지 (SQL에서 정렬 포함 고려)</p>
<p>작성자, 수정일자 등 시스템 컬럼을 어떻게 관리할지</p>
<p>🧠 배운 점 &amp; 느낀 점
단순한 기능도 실제 구현해보면 연관된 계층이 많다 (DTO, Mapper, Controller, Service, View까지)</p>
<p>Mapper에서 alias 설정을 꼼꼼히 하지 않으면 예상치 못한 바인딩 오류가 발생할 수 있다</p>
<p>게시판 하나를 만들기 위해선 &quot;표현 → 전달 → 저장&quot; 흐름 전체를 이해하고 있어야 한다</p>
<p>발표가 끝났다고 해서 끝이 아니라, 구현을 통해 다시 설계의 정답을 검증하고 있다는 걸 느꼈다</p>
<p>지금 당장은 이해가 느릴 수 있어도, 돌아가더라도 확실히 이해하고 가는 게 결국 더 빠른 길이라는 걸 체감한 한 주였다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 12주차 -회고 ,학습 블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-12%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-12%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%ED%95%99%EC%8A%B5-%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Sun, 15 Jun 2025 07:19:05 GMT</pubDate>
            <description><![CDATA[<p>🗓 12주차 회고 (6/9 ~ 6/13)
이번 주는 팀 프로젝트 주간이었다.
내가 맡은 숙소/리뷰/가격/정책 파트도 신경 쓸 게 많았지만 더 부담이 됐던건 발표도 맡게 되었다는 점이었다.</p>
<p>발표 준비는 정말 쉽지 않았다.
ERD나 DB 모델링 공부가 아직 많이 부족한 상태였고, 과제를 하면서 급하게 개념을 정리한 터라 전체를 이해하고 설명하는 데 많은 어려움이 있었다.
덕분에 발표하면서 팀원들이 잘한 부분을 더 부각시켜주지 못한 점이 가장 아쉬움으로 남는다.</p>
<p>과제 제출도 버벅거리고, 내가 부족한 걸 너무 많이 느낀 한 주였다.
‘잘하고 싶은데 아직 역량이 안 되는 것 같다’는 생각이 들었고, 그만큼 부담도 컸다.</p>
<p>다음 발표는 더 잘하고 싶다.
“우리 팀은 정말 열심히 했고, 이런 걸 잘했다”
이걸 잘 보여줄 수 있는 사람이 되고 싶다.
그리고 팀에 더 도움이 되는 사람이 되고 싶다.</p>
<p>📌 내가 맡은 주요 업무</p>
<p>숙소(ACCOMMODATION)와 객실(ROOM) 테이블 구조 설계</p>
<p>숙소 카테고리 3단계 분류 체계(L1~L3) 정리</p>
<p>시설/정책/이미지/리뷰 등 서브 테이블 분리</p>
<p>가격 정책 방식 단순화 (기존 시즌/가격 테이블 → 하나의 정책 테이블로 통합)</p>
<p>정책 우선순위/조건 적용 방식 정의</p>
<p>샘플 데이터 20개 이상 작성 (숙소, 객실, 이미지, 정책 등)</p>
<p>💡 고민했던 부분</p>
<p>객실이 숙소의 옵션인지, 독립적인 상품으로 볼 것인지</p>
<p>가격 정책 우선순위와 중복 조건(예: 성수기 + 주말)의 처리 방식</p>
<p>시설을 숙소와 객실 모두에서 사용할 때 null 값 문제 → 다대다 관계로 해결</p>
<p>정책, 시즌, 가격을 나누는 게 과한 설계인지 판단하기 어려웠지만, 결국 단순한 구조가 유지 관리에 더 낫다고 판단함</p>
<p>🧠 배운 점 &amp; 느낀 점</p>
<p>단순한 설계가 더 명확하다: 너무 쪼개면 도리어 관리 포인트만 늘어난다</p>
<p>ERD만 그릴 줄 알면 되는 게 아니라 왜 이렇게 설계했는지 설명할 수 있어야 한다</p>
<p>팀원들과 역할을 나누고, 각자의 데이터를 연결하는 과정에서 커뮤니케이션의 중요성도 크게 느꼈다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 11주차 -회고,학습블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-11%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-11%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Fri, 06 Jun 2025 10:41:26 GMT</pubDate>
            <description><![CDATA[<p>🗓 11주차 회고 (6/2 ~ 6/6)</p>
<p>이번 주는 디자인 패턴, 스프링 ,모델링, 그리고 자료구조까지 폭넓게 다뤘다. 어느새 이론 수업이 마무리되고 첫 팀 프로젝트가 시작되는 시점이라, 한 주 동안 배운 내용을 되짚어보며 정리해두는 게 더 중요하게 느껴졌다.</p>
<p>백엔드 부트캠프에 참여하게 된지 벌써 11주차가 지나가고 있고, 시작 당시에는 회사 퇴사 일정과 겹쳐 예습은 전혀 하지 못한 상태였다. 수업 초반엔 개념을 겉핥기로 따라가기 바빴고, 모르는 게 너무 많아서 한참 헤매기도 했다.</p>
<p>그런데도 수강생 리더로 추천되어 리더 역할을 맡게 됐었고, 이번 주부터는 팀 프로젝트 리더 역할까지 맡게 됐다. 전공자도 많은 상황에서 내 부족한 배경지식이 팀에 도움이 되지 못할까 걱정도 컸지만, &#39;일단 해보자&#39;는 마음으로 해볼 것이다. 아직도 갈 길이 멀지만, 모르는 만큼 팀원들과 더 많이 소통하고 함께 맞춰가며 배우고 발전해야겠다.</p>
<p>🧠 학습 내용 요약</p>
<p>✅ 디자인 패턴</p>
<p>Iterator 패턴: 컬렉션 탐색을 추상화하여 외부에서 동일한 방식으로 접근 가능하게 함. Visitor 패턴과 구조적 유사성이 있음.</p>
<p>Adapter 패턴: 기존 인터페이스와 호환되지 않는 클래스 간 중간 연결자 역할을 수행</p>
<p>Factory Method: 객체 생성 로직을 서브 클래스에 위임. 동일한 인터페이스를 구현한 객체를 생성</p>
<p>Builder 패턴: 복잡한 객체 생성을 단계적으로 처리. 생성자 매개변수가 많은 경우 유용함</p>
<p>✅ Spring 프레임워크 개념</p>
<p>프레임워크란? 자주 쓰는 기능을 미리 구현해 둔 구조(틀), 개발자가 구조에 맞춰 개발하면 편리함</p>
<p>Spring은 자바 기반 애플리케이션 개발을 위한 대표적인 프레임워크</p>
<p>Spring Boot는 설정을 최소화하여 웹 개발을 더 쉽게 시작할 수 있도록 지원. JAR 실행 구조 포함</p>
<p>✅ 핵심 원리</p>
<p>IOC (Inversion of Control): 객체 생성과 생명주기 관리 책임을 개발자에서 스프링 컨테이너로 전환</p>
<p>DI (Dependency Injection): 의존 객체를 외부에서 주입받음으로써 객체 간 결합도 감소</p>
<p>Spring MVC 구성요소:</p>
<p>Controller: 요청 수신</p>
<p>Service: 로직 처리</p>
<p>Repository: DB 연동</p>
<p>✅ 자료구조 정리</p>
<p>배열 vs 리스트: 배열은 고정 크기, 리스트는 가변 크기</p>
<p>스택(Stack): LIFO 구조 (push, pop)</p>
<p>큐(Queue): FIFO 구조 (offer, poll)</p>
<p>HashMap: Key-Value 구조, 빠른 탐색 가능</p>
<p>트리(Tree): 계층형 구조, 탐색/정렬 용이</p>
<h2 id="✅-다음-주-목표">✅ 다음 주 목표</h2>
<ul>
<li>팀 프로젝트의 시작을 잘 정리하고 역할 분담을 체계적으로 하기  </li>
<li>ERD 기초공부, DB 시각화 연습</li>
<li>스프링 MVC 흐름을 더 익히고, 실전 프로젝트에 활용  </li>
<li>MyBatis 공부 더 하기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 10주차 -회고,학습블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-10%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-10%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Mon, 02 Jun 2025 01:03:43 GMT</pubDate>
            <description><![CDATA[<p>10주차 회고
5/26~5/30
이번 주는 <strong>DDD(Domain Driven Design)</strong>와 REST API 설계 방식에 대해 학습했다. 처음 접하는 개념도 있었지만, 실습을 통해 전체 구조를 파악할 수 있었던 유익한 한 주였다.</p>
<p>📌 DDD란?
DDD (Domain Driven Design) 는 사용자의 요구사항을 기능 단위로 묶어 도메인을 중심으로 설계하는 방식이다. 단순한 계층적 분리보다 실질적인 비즈니스 중심의 설계를 지향한다.</p>
<p>예를 들어 쇼핑몰을 예로 들면:</p>
<p>회원 관련 기능: 회원 가입, 로그인, 마이페이지 → 회원 서비스</p>
<p>상품 관련 기능: 상품 조회, 등록, 삭제 → 상품 서비스</p>
<p>즉, 도메인(기능 단위)이 중심이 되어 코드가 구성된다.</p>
<p>📌 계층 아키텍처와 역할
Controller: 사용자의 요청을 가장 먼저 받고, 처리 로직을 서비스 계층으로 위임하는 역할</p>
<p>Service: 비즈니스 로직을 처리</p>
<p>Repository: 데이터 저장소 역할 (DB 또는 임시 컬렉션 등)</p>
<p>예시 구조:</p>
<p>mathematica
복사
편집
Product
 ├─ ProductController
 ├─ ProductService
 └─ ProductRepository
실제 DB 없이도 자바 컬렉션(Map)을 활용해 제품 데이터를 임시로 저장하고 관리할 수 있다.</p>
<p>📌 REST API 설계 원칙
REST는 자원의 표현(Representation) 을 주고받는 방식으로, 경로(URL) 자체가 <strong>&quot;무엇을 다루는지&quot;</strong>를 나타내야 한다.</p>
<p>기본 규칙
동작    메서드    URL 예시
상품 조회    GET    <a href="http://localhost:8080/product">http://localhost:8080/product</a>
상품 등록    POST    <a href="http://localhost:8080/product">http://localhost:8080/product</a></p>
<p>product는 다루는 리소스의 종류를 나타내며, /는 &quot;<del>의&quot;, &quot;</del>중에&quot;라는 의미를 갖는다.</p>
<p>📌 HTTP 요청 구성 요소
URL: 요청 대상</p>
<p>Method: 목적 (GET, POST, PUT, DELETE)</p>
<p>Body: 요청 시 전송하는 데이터 (POST, PUT 등)</p>
<p>요청 방식 정리
쿼리 스트링
<a href="http://localhost:8080/products?name=keyboard">http://localhost:8080/products?name=keyboard</a>
→ URL 뒤에 ?와 파라미터로 데이터 전달</p>
<p>PathVariable
<a href="http://localhost:8080/products/%7Bid%7D">http://localhost:8080/products/{id}</a>
→ 경로 자체에 데이터를 포함</p>
<p>RequestBody
POST, PUT 등에서 <strong>객체 형태(JSON)</strong>로 데이터를 전송
→ 자바에서는 @RequestBody를 사용해 바인딩</p>
<p>🧠 10주차 회고
이번 주는 새로운 설계 방식과 HTTP 기반의 통신 구조를 이해하는 데 중점을 뒀다. 특히 DDD 개념을 실제 실습 코드에 녹여보며 추상적인 설계가 어떻게 구체적인 구조로 표현되는지 체감할 수 있었다.</p>
<p>REST API의 설계 원칙을 명확히 이해하면서, 앞으로 백엔드 API 설계 시 기준이 될 수 있는 틀을 얻은 기분이다.</p>
<p>✅ 다음 목표</p>
<p>스프링 부트에서 REST 컨트롤러 실습 계속하기</p>
<p>실제 DB 연동을 고려한 Repository 설계 연습</p>
<p>@RequestBody, @PathVariable, @RequestParam의 사용 방식 정리 및 비교</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 9주차 -회고,학습블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-9%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-9%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Fri, 23 May 2025 09:11:50 GMT</pubDate>
            <description><![CDATA[<p>5/19~5/23
9주차 회고</p>
<p>이번 주는 Spring MVC, HTML, CSS에 대해 학습했다. 아래는 학습한 주요 내용을 정리한 것이다.</p>
<p>📌 Spring MVC 핵심 정리</p>
<p>✅ Spring MVC 흐름</p>
<p>프로그램 등록</p>
<p>자동 등록: @Controller</p>
<p>수동 등록: web.xml 또는 <bean>, <component-scan> 설정</p>
<p>URL과 프로그램 연결 → DispatcherServlet이 매핑</p>
<p>객체 생성 및 메서드 호출</p>
<p>인스턴스 메서드 사용 가능</p>
<p>static도 가능하지만 인스턴스 필드를 위해 인스턴스를 주로 사용</p>
<p>✅ DispatcherServlet 역할</p>
<p>입력 &amp; 변환</p>
<p>모델 생성 및 전달</p>
<p>✅ 주요 애너테이션</p>
<p>@RequestMapping, @GetMapping, @PostMapping</p>
<p>@RequestParam: 요청 파라미터를 자바 매개변수에 연결</p>
<p>@ModelAttribute: 폼 데이터를 객체로 바인딩할 때 사용</p>
<p>✅ View 처리</p>
<p>ViewResolver로 JSP 연결</p>
<p>/WEB-INF/views/*.jsp 구조 사용 (보안상 직접 접근 불가)</p>
<p>return &quot;login&quot; → login.jsp 로 매핑</p>
<p>직접 접근 불가: WEB-INF 내부는 URL 직접 접근이 막혀 있음</p>
<p>✅ 쿠키 vs 세션</p>
<p>항목</p>
<p>쿠키</p>
<p>세션</p>
<p>저장 위치</p>
<p>클라이언트(브라우저)</p>
<p>서버</p>
<p>서버 부담</p>
<p>없음</p>
<p>있음</p>
<p>보안</p>
<p>낮음</p>
<p>높음</p>
<p>유효기간</p>
<p>설정 가능</p>
<p>기본 설정 or 수동 종료</p>
<p>📌 인코딩 개념 정리</p>
<p>✅ URL 인코딩</p>
<p>목적: 특수문자, 비ASCII 문자 안전 전송</p>
<p>%XX 형태로 인코딩</p>
<p>예: 공백 → %20</p>
<p>🧠 비유: 깨지기 쉬운 물건을 포장해서 택배 보내는 것</p>
<p>✅ Base62 인코딩</p>
<p>목적: 바이너리/숫자 데이터를 짧게 표현 (62진법)</p>
<p>URL-safe 고유 키 생성 시 사용 (예: 단축 URL)</p>
<p>🧠 비유: 긴 지하철 노선 이름을 알파벳 번호로 요약</p>
<p>관점</p>
<p>URL 인코딩</p>
<p>Base62 인코딩</p>
<p>목적</p>
<p>문자 안전 전송</p>
<p>짧고 안전한 표현</p>
<p>사용</p>
<p>웹 표준, 쿼리스트링</p>
<p>단축 URL, 식별자</p>
<p>방식</p>
<p>ASCII 외 문자 → %XX</p>
<p>숫자/문자열 → 62진법</p>
<p>📌 JSP 기본</p>
<p>&lt;% %&gt;: 자바 코드</p>
<p>&lt;%! %&gt;: 선언문 (변수/메서드)</p>
<p>&lt;%= %&gt;: 출력</p>
<p>${}: EL (Expression Language)</p>
<p>JSTL: JSP 태그 라이브러리로 자바 코드 없이 출력 가능</p>
<p>📌 Filter</p>
<p>서블릿의 전/후처리 담당</p>
<p>예: 인코딩 필터, 로깅 필터 등</p>
<p>여러 개 사용 가능 (체인 형태로 동작)</p>
<p>📌 URL 매핑 방식</p>
<p>exact: /login</p>
<p>path: /user/*</p>
<p>extension: *.do</p>
<p>default: /</p>
<p>📌 실습에서 느낀 점</p>
<p>JSP는 단독 실행 불가, 컨트롤러를 통해 호출해야 함</p>
<p>Spring MVC 구조를 실습하며 눈에 익힘</p>
<p>뷰는 항상 컨트롤러 통해 접근해야 한다는 원칙이 중요</p>
<p>🧠 9주차 회고</p>
<p>이번 주는 Spring MVC, HTML, CSS 진도를 나갔고, 전체적으로는 진도 따라가기 버거운 주였다.</p>
<p>자바 복습을 소홀히 해서 아직은 큰 어려움이 없었지만, 스프링 심화 과정에 들어가면 기초 부족이 크게 다가올 것 같아 걱정이 된다.</p>
<p>주말에는 자바와 스프링을 총 정리해서 기반을 다시 다질 계획이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 8주차 -회고,학습블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-8%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-8%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Mon, 19 May 2025 05:15:54 GMT</pubDate>
            <description><![CDATA[<h2 id="512516-8주차-회고">5/12~5/16 8주차 회고</h2>
<h2 id="이번-주-성과">이번 주 성과</h2>
<ul>
<li><strong>SQL 튜닝 복습에 집중</strong><ul>
<li>NL 조인, 해시 조인, 소트 머지 조인 등 핵심 내용을 집중적으로 복습했다.</li>
<li>학습한 만큼 머리에 잘 남았다는 느낌이 들어 만족스러웠고, SQL 개념에 대한 자신감이 생겼다.</li>
</ul>
</li>
</ul>
<h2 id="느낀-점">느낀 점</h2>
<ul>
<li>SQL 튜닝에 집중하느라 자바는 소홀했던 것 같다.</li>
<li>자바의 정석 연습문제를 펼쳤을 때, 여태 공부했던 자바 지식이 마치 증발한 것처럼 느껴졌다.</li>
<li>문제 풀이가 쉽게 풀리지 않아 당황했고, 자바 복습의 필요성을 강하게 느꼈다.</li>
</ul>
<h2 id="개선점--계획">개선점 &amp; 계획</h2>
<ul>
<li><p><strong>공부 주제 균형 맞추기</strong></p>
<ul>
<li>앞으로는 한 가지에만 몰입하기보다는 시간과 범위를 정해 병행 학습을 시도할 예정.</li>
<li>예) 오전에는 SQL, 오후에는 자바 문제 풀이 등으로 나누기</li>
</ul>
</li>
<li><p><strong>자바 복습 재개</strong></p>
<ul>
<li>연습문제를 꾸준히 풀면서 감을 되찾는 것이 중요하다고 느꼈다.</li>
<li>다시 기본 문법과 OOP 개념을 복습하면서 문제풀이로 이어갈 계획이다.</li>
</ul>
</li>
<li><p><strong>목표 재설정</strong></p>
<ul>
<li>원래는 이번 주에 자바 연습문제를 <strong>7장까지</strong> 풀려고 했지만, 실제로는 <strong>5장까지만</strong> 완료.</li>
<li>다음 주에는 <strong>9장 이상</strong>을 푸는 것을 목표로 삼는다.</li>
</ul>
</li>
</ul>
<hr>
<p> <strong>요약</strong>: SQL 튜닝은 만족스러웠고, 자바는 다시 달려야 할 때. 공부를 균형 있게 해내자..</p>
<p>풀지 못한 연습문제 오답노트</p>
<p>1</p>
<p>public class Ex3_8 {
    public static void main(String[] args) {
        byte a = 10;
        byte b = 20;
        byte c =(byte)((byte) a+b); // byte 타입에 int연산값을 저장할 수 없으니 연산값을 byte로 형변환</p>
<pre><code>    char ch = &#39;A&#39;;
    ch = (char)(ch+2) ; // ch+2를 하면 int타입의 연산값이 나오므로(자동형변환) 다시 char로 형변환 해줘야함

    float f = 3/2f; // int로 연산하면 1의 값이 나옴. float으로 형변환 해야 1.5 가 나옴
    long l = 3000L * 3000 * 3000; // int의 범위를 초과하는 값이 나오므로 long으로 형변환 필요
    float f2 = 0.1f;
    double d = 0.1;

    boolean result = (float) d==f2;
    //float을 double로 형변환시에 오차 발생


    System.out.println(&quot;c= &quot;+c);
    System.out.println(&quot;ch= &quot; + ch);
    System.out.println(&quot;f= &quot; + f);
    System.out.println(&quot;l= &quot; + l);
    System.out.println(&quot;result= &quot; + result);

}</code></pre><p>}</p>
<p>2</p>
<p>public class Ex4_12 {
    public static void main(String[] args) {
        for (int dan = 2; dan &lt;= 9; dan += 3) { // 2단, 5단, 8단 시작
            for (int i = 1; i &lt;= 3; i++) { // 각 줄: 1~9
                for (int j = dan; j &lt; dan + 3 &amp;&amp; j &lt;= 9; j++) {
                    System.out.printf(&quot;%d*%d=%-4d&quot;, j, i, j * i);
                }
                System.out.println();
            }
            System.out.println();
        }
    }
}</p>
<p>public class Ex5_7 {
    public static void main(String args[])
    {
        if(args.length != 1){
            System.out.println(&quot;USAGE: java Ex5_7 3210&quot;);
            System.exit(0);
        }</p>
<pre><code>    int money = Integer.parseInt(args[0]);

    System.out.println(&quot;money=&quot;+money);

    int[] coinUnit = {500,100,50,10}; //동전의 단위
    int[] coin = {5,5,5,5};// 단위별 동전 개수

    for (int i = 0; i &lt; coinUnit.length; i++) {
        int coinNum = 0 ; // 코인 개수 카운트 변수 선언
        coinNum = money /coinUnit[i]; // 코인 몇개 쓰는지 먼저 구함
    if (coinNum&lt;=coin[i]){ // 코인 개수가 가지고 있는 코인보다 적으면
        coinNum = money /coinUnit[i]; // coinUnit[i]원으로 코인 몇개 쓰는지 구하고
        money = money - coinUnit[i]*coinNum; // 돈 계산
        coin[i] -= coinNum;} // 코인[i]에서 몇 개썼는지 카운트 수를 뺌
    else if (coinNum&gt;coin[i]){ // 개수가 가지고 있는 코인[i]보다 많으면
        coinNum = coin[i]; // 가지고있는 코인을 다쓰고
        money = money - coinUnit[i]*coinNum; // 제공받은 돈에서 가지고있는 코인 다쓴 값을 구함
        coin[i] = 0; // 코인을 다쓰면 남는게 없으니 0으로 표기
    }






        System.out.println(coinUnit[i]+&quot;원 : &quot;+coinNum);
    }

    if (money&gt;0){
        System.out.println(&quot;거스름돈이 부족합니다.&quot;);
        System.exit(0);
    }
    System.out.println(&quot;= 남은 동전의 개수 =&quot;);

    for (int i = 0; i &lt; coinUnit.length; i++) {
        System.out.println(coinUnit[i]+&quot;원 : &quot;+coin[i]);
    }

}</code></pre><p>}</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[커널아카데미]백엔드 부트캠프 12기 7주차 -회고,학습블로그]]></title>
            <link>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-7%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5%EB%B8%94%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@sang_94/%EC%BB%A4%EB%84%90%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%B0%B1%EC%97%94%EB%93%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-12%EA%B8%B0-7%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%ED%95%99%EC%8A%B5%EB%B8%94%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Fri, 09 May 2025 09:45:22 GMT</pubDate>
            <description><![CDATA[<p>5/5~5/9 7주차 회고 </p>
<p>4일,5일 은 휴일이라 공부를 좀 많이 하고 싶었는데
카드게임 만들기 과제가 너무 어려웠다..
4일에 완성하고 5일에 제출 후 공부를 하려고 했으나
5일차에 오류를 발견해서... 열심히 수정하느라 하루를 다 보냈다..
결국 SQL은 시작도 못한 채로 휴일을 보내고 모델링과 튜닝 수업을 듣느라 너무 힘들었고 목요일부터 SQL공부를 시작하면서 수업시간에 못 따라간 내용이 이해가 되기 시작했다.. SQL수업 할 때 오라클 오류로 진행을 못했던 것이 너무 아쉬웠고 앞으론 수업끝나면 바로 복습하는 시간을 짧게 가지고 후에 못다한 공부를 하는게 좋겠다 라는 생각이 들었다</p>
<p>학습내용</p>
<ol>
<li>SQL 기본 구조 및 실행 흐름</li>
</ol>
<ul>
<li>SQL 언어 특징: 선언형, 구조적, 집합 기반</li>
<li>실행 흐름:<ol>
<li>파싱(Parsing): 문법 검사, 구문 검사</li>
<li>옵티마이저 최적화: 실행 계획 수립 (CBO 기반)</li>
<li>실행 (Execution): 기계어로 실행 (로우 레벨)</li>
<li>결과 반환 및 캐싱 (SGA 공유, PGA 개인)</li>
</ol>
</li>
<li>SQL 캐시: 동일한 쿼리를 물음표(?) 바인딩으로 작성하면 파싱 캐시 재사용 가능 → 성능 향상 &amp; 보안 강화</li>
</ul>
<ol start="2">
<li>인덱스(Index)</li>
</ol>
<ul>
<li>역할: WHERE절 검색 성능 향상, 정렬 생략 가능</li>
<li>동작 구조: 수직 탐색(루트~리프), 수평 탐색(리프노드 간)</li>
<li>활용법:<ul>
<li>유니크 스캔: 수직 1번만 타고 내려감 (고속)</li>
<li>풀 테이블 스캔: 수평으로 전체 데이터 읽음</li>
<li>패스트 풀 스캔: 인덱스를 테이블처럼 전체 스캔 (정렬 없음)</li>
<li>스킵 스캔: 선행 인덱스 컬럼이 누락돼도 추정 기반으로 인덱스 탐색</li>
<li>디센딩 스캔: 인덱스를 역순으로 탐색</li>
</ul>
</li>
</ul>
<ol start="3">
<li>뷰(View)</li>
</ol>
<ul>
<li>정의: SELECT문을 테이블처럼 재사용할 수 있는 객체</li>
<li>사용 목적: 보안, 복잡한 쿼리 단순화, 논리적 데이터 분리</li>
<li>WITH READ ONLY: 수정 불가능한 뷰로 생성</li>
<li>주의사항:<ul>
<li>기본적으로 ORDER BY 불가 (인라인뷰로 우회 가능)</li>
<li>FORCE 옵션: 기반 테이블 없어도 뷰 생성 가능 (사용은 불가)</li>
</ul>
</li>
</ul>
<ol start="4">
<li>NVL / DECODE 함수</li>
</ol>
<ul>
<li>NVL(expr1, expr2): expr1이 NULL이면 expr2 반환<ul>
<li>예: 평균 계산 시 NULL 회피</li>
<li>WHERE절, SELECT절 모두 사용 가능</li>
</ul>
</li>
<li>DECODE(expr, val1, ret1, val2, ret2, ..., default): if-else처럼 분기처리<ul>
<li>예: 급여 등급 분류 → DECODE(TRUNC(salary/1000), 1, &#39;D&#39;, 2, &#39;C&#39;, &#39;A&#39;)</li>
</ul>
</li>
</ul>
<ol start="5">
<li>PIVOT 함수</li>
</ol>
<ul>
<li>정의: 행 데이터를 열로 전환</li>
<li>사용 이유: 집계 데이터를 테이블 형태로 가독성 있게 표현</li>
<li>DECODE와의 차이:<ul>
<li>DECODE는 수동 분기 → 코드 길어짐</li>
<li>PIVOT은 자동으로 열 변환</li>
</ul>
</li>
</ul>
<ol start="6">
<li>GROUP BY + ROLLUP / CUBE</li>
</ol>
<ul>
<li>ROLLUP: 계층적 집계 (총합 포함)</li>
<li>CUBE: 모든 조합에 대한 집계 제공</li>
<li>차이:<ul>
<li>ROLLUP은 누적 형태 (예: 소계, 총계)</li>
<li>CUBE는 모든 방향으로의 집계</li>
</ul>
</li>
</ul>
<ol start="7">
<li>상관 서브쿼리 (Correlated Subquery)</li>
</ol>
<ul>
<li>정의: 서브쿼리가 메인쿼리의 값을 참조</li>
<li>예제: WHERE salary &lt; (SELECT AVG(salary) FROM s_emp WHERE dept_id = outer.dept_id)</li>
<li>특징: 서브쿼리가 메인 쿼리의 각 행마다 반복 실행됨 → 느릴 수 있음</li>
</ul>
<ol start="8">
<li>EXISTS / IN / ANY</li>
</ol>
<ul>
<li>EXISTS: 조건을 만족하는 행이 &quot;존재&quot;하는지 여부 (빠름)</li>
<li>IN: 리스트 또는 서브쿼리 결과에 포함되는지 여부</li>
<li>ANY: 조건 중 하나라도 만족하면 TRUE<ul>
<li>예: salary &lt; ANY (SELECT avg(salary) FROM s_emp GROUP BY dept_id)</li>
</ul>
</li>
<li>비교: EXISTS는 존재 여부만 판단, ANY/IN은 값 비교</li>
</ul>
<ol start="9">
<li>SQL 예외 처리</li>
</ol>
<ul>
<li>PL/SQL에서만 예외 처리 가능: BEGIN</li>
<li>-- 실행 코드</li>
<li>EXCEPTION</li>
<li>WHEN OTHERS THEN NULL;</li>
<li>END;</li>
<li></li>
<li>옵티마이저 힌트 오류는 무시됨 (주석 처리이므로 실행 중 오류 X)</li>
</ul>
<ol start="10">
<li>기타</li>
</ol>
<ul>
<li>파싱과 컴파일 비교:<ul>
<li>파싱: SQL 문법 검사 및 실행 계획 생성</li>
<li>컴파일: 프로그래밍 언어 → 기계어 변환</li>
</ul>
</li>
<li>옵티마이저 역할: SQL 파싱 이후 실행 계획 최적화 수립 (CBO 기반)</li>
<li>SGA (System Global Area): 공유 메모리, SQL 캐시 보관</li>
<li>PGA (Program Global Area): 개인 메모리, 세션별 정렬/계산 작업 수행</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>