<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>playername_ltt.log</title>
        <link>https://velog.io/</link>
        <description>개발자에서 엔지니어로, 엔지니어에서 리더로</description>
        <lastBuildDate>Mon, 13 Jul 2026 00:14:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>playername_ltt.log</title>
            <url>https://velog.velcdn.com/images/playername_ltt/profile/6387d941-fd2f-4d97-ad70-1f354aa6beff/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. playername_ltt.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/playername_ltt" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[반드시 알아야 하는 엔지니어링]]></title>
            <link>https://velog.io/@playername_ltt/%EB%B0%98%EB%93%9C%EC%8B%9C-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%98%EB%8A%94-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81</link>
            <guid>https://velog.io/@playername_ltt/%EB%B0%98%EB%93%9C%EC%8B%9C-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%98%EB%8A%94-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81</guid>
            <pubDate>Mon, 13 Jul 2026 00:14:32 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/b79224e6-5672-40c5-b4f1-47461784e933/image.png" alt=""></p>
<blockquote>
<p>본 콘텐츠는 길벗출판사에서 보내준 <a href="https://gilbut.co/c/26066365hC">《바이브 엔지니어링》</a>을 읽고 작성한 콘텐츠입니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/9d5a256c-3d59-4aa1-802b-3b38082da166/image.png" alt=""></p>
<p><a href="https://velog.io/@playername_ltt/AI-%EC%BD%94%EB%94%A9-%ED%88%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%93%B0%EA%B3%A0-%EA%B3%84%EC%8B%A0%EA%B0%80%EC%9A%94">이전에 AI 코딩 툴, 제대로 쓰고 계신가요?</a>라는 글을 작성하며 마지막에 이런 이야기를 했습니다.</p>
<blockquote>
<p>개발은 AI에게 맡기고, 엔지니어링은 사람이 맡아야 한다.</p>
</blockquote>
<p>그리고 얼마 지나지 않아 제목부터 아예 《바이브 엔지니어링》인 책을 읽게 됐습니다.</p>
<p>그래서 이번에는 책의 내용을 순서대로 소개하기보다, 책을 읽으며 이전에 했던 생각이 어떻게 구체화되었는지 이야기해보려고 합니다. 여기에 제가 실제로 AI 코딩 도구를 사용하며 정착시킨 방법도 함께 소개하겠습니다.</p>
<h1 id="바이브-코딩은-너무나-익숙해졌다">바이브 코딩은 너무나 익숙해졌다</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/d2e8037d-aada-4e14-9c00-4762e387bd1c/image.png" alt=""></p>
<p>현시점에서 AI를 전혀 사용하지 않는 개발자는 찾기 힘들 겁니다.</p>
<p>처음에는 브라우저에서 모르는 내용을 물어보고 코드를 복사해오는 정도였다면, 이제는 AI가 코드베이스를 직접 읽고 파일을 수정하며 테스트까지 실행합니다.</p>
<p>우리의 요청도 점점 짧아졌습니다.</p>
<pre><code class="language-markdown">사용자 목록을 조회하는 API를 만들어줘.</code></pre>
<pre><code class="language-markdown">JWT 기반의 로그인 기능을 구현해줘.</code></pre>
<pre><code class="language-markdown">이 에러 원인을 찾아서 고쳐줘.</code></pre>
<p>이 정도만 이야기해도 AI는 꽤 그럴듯한 결과물을 만들어냅니다. 개발 속도만 보면 과거로 돌아가기 어려울 정도로 편리합니다.</p>
<p>문제는 <strong>그럴듯하게 동작하는 코드와 실제 서비스에 배포할 수 있는 코드가 같지 않다</strong>는 것입니다.</p>
<ul>
<li>사용자가 동시에 몰리면 어떻게 되는가?</li>
<li>외부 API가 응답하지 않으면 요청이 계속 쌓이지 않는가?</li>
<li>데이터가 중복으로 저장될 가능성은 없는가?</li>
<li>정상적인 로그인 외에 토큰 탈취와 재사용에도 대응하는가?</li>
<li>지금 만든 구조를 다른 개발자가 수정할 수 있는가?</li>
</ul>
<p>이런 문제는 컴파일 에러처럼 빨간 줄을 보여주지 않습니다. 정상적으로 동작하는 것처럼 숨어 있다가 운영 환경에서 뒤늦게 나타납니다.</p>
<p>바이브 코딩이 <strong>“기능이 돌아가도록 만드는 일”</strong>이라면, 바이브 엔지니어링은 “요구사항과 엣지 케이스, 테스트와 운영까지 통제할 수 있는 상태로 만드는 일”에 가깝습니다.</p>
<p>저는 엔지니어링을 다음과 같이 정의합니다.</p>
<blockquote>
<p>엔지니어링이란, 불확실한 문제를 제약 조건 안에서 재현 가능하고 유지 가능한 해법으로 바꾸는 일입니다.</p>
</blockquote>
<p>그렇다면 AI가 코드를 작성하는 시대에는 어떻게 엔지니어링해야 할까요?</p>
<h1 id="기능이-아니라-완료-조건을-지시하기">기능이 아니라 완료 조건을 지시하기</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/cc4a687e-7030-453a-8acf-a8da688c2cd1/image.png" alt=""></p>
<p>책을 읽으며 가장 먼저 공감했던 부분은 비기능 요구사항에 관한 내용이었습니다.</p>
<p>AI에게 단순히 기능만 요청하면 AI는 기능을 완성하는 데 집중합니다. 3초 이내에 응답해야 하는지, 동시에 몇 건을 처리해야 하는지, 장애가 발생하면 어떻게 복구해야 하는지는 우리가 알려주지 않는 이상 적당히 판단하거나 생략합니다.</p>
<p>예를 들어 다음과 같은 요청이 있습니다.</p>
<pre><code class="language-markdown">OpenAI API를 이용하여 대화 내용 요약 API를 만들어주세요.</code></pre>
<p>기능 자체는 충분히 만들어낼 겁니다. 하지만 실제 서비스에서 사용하려면 적어도 다음과 같은 조건이 추가로 필요합니다.</p>
<pre><code class="language-markdown">OpenAI API를 이용하여 대화 내용 요약 API를 구현해주세요.

- 전체 요청 타임아웃은 5초입니다.
- 429와 5xx 응답에만 최대 2회 재시도합니다.
- 재시도에는 지수 백오프를 적용합니다.
- 외부 API의 동시 요청은 50개를 넘을 수 없습니다.
- 최종 실패 시 일관된 에러 응답을 반환해야 합니다.
- 요청 수, 응답 시간, 재시도 횟수와 최종 실패를 확인할 수 있어야 합니다.
- 정상, 타임아웃, 재시도, 동시 요청 초과 상황의 테스트를 작성해주세요.</code></pre>
<p>두 요청 모두 같은 요약 API를 만들어달라는 내용입니다. 하지만 두 번째 요청에는 <strong>언제 완성되었다고 판단할 수 있는지</strong>가 담겨 있습니다.</p>
<p>물론 매번 처음부터 이 모든 조건을 떠올리기는 어렵습니다. 특히 경험해보지 않은 문제라면 무엇을 빠뜨렸는지조차 알기 어렵죠.</p>
<p>그럴 때는 AI에게 곧바로 구현을 시키기보다 먼저 질문을 시킬 수 있습니다.</p>
<pre><code class="language-markdown">이 기능을 실제 운영 환경에 배포한다고 가정하세요.

바로 구현하지 말고 성능, 동시성, 장애 대응, 보안, 관측 가능성 측면에서
결정해야 할 사항과 누락된 요구사항을 먼저 질문해주세요.
제가 답변하면 요구사항과 테스트 조건을 정리한 뒤 구현 계획을 작성해주세요.</code></pre>
<p>AI에게 더 자세하게 명령하는 것만이 프롬프트를 잘 쓰는 방법은 아닙니다. <strong>내가 모르는 부분을 AI가 질문하게 만드는 것</strong>도 좋은 활용법입니다.</p>
<h1 id="ai를-구현자가-아니라-리뷰어로-사용하기">AI를 구현자가 아니라 리뷰어로 사용하기</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/200558af-00f5-426c-8141-2b87be07b5de/image.png" alt=""></p>
<p>JWT 기반 로그인 기능을 예로 들어보겠습니다.</p>
<pre><code class="language-markdown">JWT 토큰 기반 로그인 API를 만들어주세요.</code></pre>
<p>이 요청만으로도 로그인은 됩니다. 하지만 엔지니어링의 영역으로 들어가면 결정할 내용이 급격히 많아집니다.</p>
<ul>
<li>액세스 토큰과 리프레시 토큰의 만료 시간</li>
<li>클라이언트에서 토큰을 저장하고 전달하는 방법</li>
<li>리프레시 토큰 회전과 재사용 탐지</li>
<li>로그아웃과 강제 만료 처리</li>
<li>여러 기기에서 로그인하는 경우의 정책</li>
<li>인증과 인가 실패 응답</li>
<li>토큰에 포함할 최소한의 정보</li>
</ul>
<p>주니어 개발자가 이 조건을 하나하나 알고 지시하기란 쉽지 않습니다. 저 역시 익숙하지 않은 영역에서는 놓치는 부분이 생깁니다.</p>
<p>그럴 때 AI를 단순 구현자가 아니라 시니어 엔지니어 역할로 사용합니다.</p>
<pre><code class="language-markdown">현재 JWT 인증 로직을 시니어 백엔드 엔지니어의 관점에서 검토해주세요.

- 보안 취약점과 악용 가능한 시나리오
- 동시 요청과 장애 상황에서 발생할 수 있는 문제
- 토큰 발급, 재발급, 폐기 정책의 누락
- 과도하게 복잡하거나 책임이 잘못 배치된 설계
- 테스트되지 않은 성공, 엣지, 실패 케이스

반드시 수정해야 하는 문제와 선택적으로 개선할 문제를 구분하고,
각 항목의 발생 조건과 수정 방향을 함께 설명해주세요.</code></pre>
<p>이렇게 요청하면 단순히 “SOLID 원칙을 지키세요” 같은 추상적인 답변보다 확인할 수 있는 조건이 있는 리뷰를 받을 가능성이 높아집니다.</p>
<p>다만 AI에게 시니어 역할을 부여했다고 결과까지 시니어급이 되는 것은 아닙니다. AI가 제시한 문제의 근거가 맞는지, 현재 서비스에서 정말 필요한 설계인지 판단하는 것은 여전히 사람의 몫입니다.</p>
<p>AI가 모르는 내용을 알려주는 도구라면 좋겠지만, 실제로는 <strong>모르는 내용도 알고 있는 것처럼 말할 수 있는 도구</strong>이기도 하니까요.</p>
<h1 id="코드보다-기획을-먼저-이해시키기">코드보다 기획을 먼저 이해시키기</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/e7a03cb6-9a57-44a1-8607-d6f8b013569b/image.png" alt=""></p>
<p>책에서는 AI에게 도메인 지식을 이해시키며 개발해야 한다고 이야기합니다. 저는 이를 <strong>기획과 개발 의도를 AI에게 주입하는 일</strong>이라고 생각합니다. 결국 같은 의미입니다.</p>
<p>예를 들어 “예약 취소 API를 만들어달라”고 요청하면 기술적으로는 멀쩡한 CRUD 코드가 나올 수 있습니다.</p>
<p>하지만 실제 예약 서비스라면 이야기가 달라집니다.</p>
<ul>
<li>당일에도 취소할 수 있는가?</li>
<li>결제 수단별 환불 방식은 어떻게 다른가?</li>
<li>사용한 쿠폰은 어떤 조건에서 복구되는가?</li>
<li>취소한 수량을 재고에 언제 반영하는가?</li>
<li>이미 사용된 예약을 취소할 수 있는가?</li>
</ul>
<p>AI가 이 정책을 모른다면 아무리 깔끔한 코드를 작성해도 올바른 기능을 만들 수 없습니다.</p>
<p>저도 CMUX 해커톤에서 <code>monix</code>를 개발할 때 비슷한 경험을 했습니다.</p>
<p>tool calling 관련 문제가 계속 발생하여 코드와 에러를 보여주며 수정을 요청했지만, 좀처럼 원하는 방식으로 해결되지 않았습니다. AI는 눈앞에 보이는 오류를 없애는 데만 집중했고, 수정할수록 오히려 기획과 멀어지는 경우도 있었습니다.</p>
<p>그래서 제품이 해결하려는 문제와 전체 사용자 흐름, 각 도구가 호출되어야 하는 이유부터 다시 설명했습니다. 그제야 AI가 단순한 코드 오류가 아니라 구조와 호출 흐름의 문제로 접근하기 시작했습니다.</p>
<p>AI에게 부족했던 것은 코드가 아니라 <strong>왜 이 코드를 만들고 있는지에 대한 정보</strong>였습니다.</p>
<p>이후에는 구현 전에 다음 내용을 먼저 정리해서 전달하려고 합니다.</p>
<pre><code class="language-markdown">구현에 앞서 아래 내용을 읽고 이 기능의 목적을 먼저 요약해주세요.

1. 해결하려는 사용자 문제
2. 핵심 사용자 흐름
3. 반드시 지켜야 하는 비즈니스 규칙
4. 기존 시스템과의 경계
5. 실패해도 되는 것과 절대 실패하면 안 되는 것

모호하거나 서로 충돌하는 내용은 임의로 결정하지 말고 질문해주세요.</code></pre>
<p>AI가 프로젝트의 모든 것을 알 필요는 없습니다. 다만 현재 작성할 코드가 전체 제품에서 어떤 역할을 하는지는 알아야 합니다.</p>
<h1 id="귀찮으니-반복되는-엔지니어링은-자동화하기">귀찮으니 반복되는 엔지니어링은 자동화하기</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/6d2e34af-1ff2-44fc-997f-50a796b5e24b/image.png" alt=""></p>
<p>여기까지 읽으면 한 가지 문제가 생깁니다.</p>
<p><strong>그래서 이걸 매번 프롬프트로 길게 작성해야 하나?</strong></p>
<p>저는 귀차니즘이 꽤 심하기 때문에 같은 내용을 계속 입력하고 싶지는 않습니다. 자주 사용하는 지시는 Skill과 프로젝트 규칙으로 만들어두는 편입니다.</p>
<h2 id="자주-하는-작업은-skill로-만들기">자주 하는 작업은 Skill로 만들기</h2>
<hr>
<p>코드 리뷰를 요청할 때마다 보안, 성능, 동시성, 예외 처리와 테스트를 확인하라고 입력한다면 그 자체가 반복 작업입니다.</p>
<p>이런 절차는 코드 리뷰 Skill로 만들어둘 수 있습니다.</p>
<pre><code class="language-markdown"># 백엔드 코드 리뷰

- 먼저 변경 목적과 영향 범위를 파악한다.
- 정확성, 보안, 동시성, 트랜잭션, 성능, 예외 처리를 검토한다.
- 기존 테스트가 보장하지 못하는 엣지 케이스를 찾는다.
- 반드시 수정할 문제와 개선 제안을 구분한다.
- 문제를 지적할 때 발생 조건과 수정 방향을 함께 제시한다.
- 근거 없는 칭찬과 단순한 취향 차이는 제외한다.</code></pre>
<p>이렇게 만들어두면 필요한 순간에 같은 기준으로 리뷰를 요청할 수 있습니다. 프로젝트 특성에 맞는 규칙을 계속 추가하며 개인이나 팀의 리뷰 기준으로 발전시킬 수도 있습니다.</p>
<p>프롬프트가 그때그때 사용하는 요청이라면 Skill은 <strong>반복해서 실행할 수 있도록 저장한 엔지니어링 절차</strong>에 가깝습니다.</p>
<h2 id="프로젝트-규칙과-작업-절차-분리하기">프로젝트 규칙과 작업 절차 분리하기</h2>
<hr>
<p>이전 글에서는 <code>CLAUDE.md</code>, <code>AGENTS.md</code>와 같은 컨텍스트 파일을 소개했습니다.</p>
<p>프로젝트 규칙에는 다음처럼 항상 지켜야 할 내용을 담습니다.</p>
<pre><code class="language-markdown"># 프로젝트 개발 규칙

- 기존 아키텍처와 패턴을 우선 사용한다.
- 새로운 의존성을 추가하기 전에 필요성과 대안을 설명한다.
- 설정값과 비밀값을 코드에 하드코딩하지 않는다.
- 로그에 개인정보와 인증 정보를 남기지 않는다.
- 변경 후 빌드와 테스트를 실행하고 결과를 보고한다.</code></pre>
<p>반면 Skill에는 코드 리뷰, 장애 분석, API 설계처럼 특정 작업을 수행하는 절차를 담습니다.</p>
<ul>
<li>프로젝트 규칙: <strong>이 프로젝트에서 항상 지켜야 하는 것</strong></li>
<li>Skill: <strong>특정 작업을 어떤 순서와 기준으로 수행할 것인지</strong></li>
</ul>
<p>이 둘을 구분해두면 모든 지시를 하나의 거대한 파일에 넣지 않아도 됩니다. AI에게 필요한 순간에 필요한 기준만 전달하기도 쉬워집니다.</p>
<h2 id="개인적으로-자주-쓰는-skill들">개인적으로 자주 쓰는 Skill들</h2>
<hr>
<p>몇 가지 제가 자주 사용하는, 또는 설치해둔 Skill들입니다.</p>
<ul>
<li>garrytan/gstack: 프로덕션 엔지니어링에 관한 전반적인 품질을 높여줄 수 있는 스킬입니다.</li>
<li>clean-code(자체개발): <a href="https://github.com/ksj000625/template-for-claude-code">https://github.com/ksj000625/template-for-claude-code</a> 에 추가해 두었습니다. 클린 코드 원칙으로 코드리뷰를 할 수 있는 스킬입니다.</li>
</ul>
<p>이 외에 몇가지를 쓰지만 자주쓰지는 않으므로 말았고, 추가적으로 좋은게 있으면 공유해주세요 :)</p>
<h1 id="ai가-만든-결과는-다른-시선으로-검증하기">AI가 만든 결과는 다른 시선으로 검증하기</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/77938411-6119-4f5b-a17e-599407846823/image.png" alt=""></p>
<p>한 번의 요청으로 설계, 구현, 테스트와 리뷰를 모두 끝내면 편리합니다. 하지만 같은 대화에서 AI가 자신이 방금 만든 코드를 검토하면 처음에 세운 잘못된 가정을 그대로 유지하는 경우가 있습니다.</p>
<p>구현 코드의 실수를 정답으로 가정하고 그 코드에 맞는 테스트를 작성해버리는 식입니다. 테스트가 모두 통과하니 더 그럴듯해 보이기까지 합니다.</p>
<p>그래서 저는 가능하면 생성과 검증의 단계를 나누려고 합니다.</p>
<ol>
<li>요구사항을 읽고 모호한 부분을 질문하게 합니다.</li>
<li>구현 계획과 변경 범위를 먼저 검토합니다.</li>
<li>작은 단위로 구현하고 테스트를 실행합니다.</li>
<li>최초 요구사항을 기준으로 결과를 다시 확인합니다.</li>
<li>가능하다면 별도의 에이전트나 새로운 컨텍스트에서 코드 리뷰를 요청합니다.</li>
</ol>
<p>여기서 중요한 것은 AI를 여러 번 사용하는 것이 아닙니다. <strong>코드를 생성하는 일과 그 코드가 맞는지 증명하는 일을 같은 작업으로 취급하지 않는 것</strong>입니다.</p>
<p>테스트 코드도 마찬가지입니다. 테스트 이름과 통과 여부만 볼 것이 아니라, 각 테스트가 어떤 요구사항을 증명하는지 확인해야 합니다.</p>
<h1 id="바이브-엔지니어링은-긴-프롬프트를-쓰는-기술이-아니다">바이브 엔지니어링은 긴 프롬프트를 쓰는 기술이 아니다</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/9643bccf-9bff-425a-8f2e-360b23e296d8/image.png" alt=""></p>
<p>책을 읽기 전에는 바이브 엔지니어링이라는 단어가 바이브 코딩을 조금 더 체계적으로 하는 방법 정도라고 생각했습니다.</p>
<p>읽고 나서 가장 크게 남은 생각은 <strong>AI를 잘 지시하는 능력보다 AI의 결과를 판단할 기준을 갖는 능력이 더 중요하다</strong>는 것이었습니다.</p>
<p>요구사항을 정의하려면 무엇이 정상인지 알아야 합니다. 아키텍처를 선택하려면 선택지의 장단점을 이해해야 합니다. AI가 만든 코드의 문제를 발견하려면 컴퓨터 공학 기초와 도메인 지식이 필요합니다. 테스트를 작성하게 하더라도 무엇을 검증해야 하는지는 사람이 결정해야 합니다.</p>
<p>AI가 주니어 개발자를 단숨에 시니어로 만들어주는 것은 아닙니다.</p>
<p>대신 주니어도 이전보다 훨씬 넓은 범위의 구현을 시도하고, AI에게 질문과 리뷰를 요청하며 더 빠르게 배울 수 있게 해줍니다. 그 과정에서 AI의 답변을 그대로 받아들이지 않고 판단할 수 있는 지식을 쌓는 것이 중요합니다.</p>
<p>이번 글에서는 제가 특히 공감했던 비기능 요구사항, 설계 검토, 도메인 지식과 반복 작업의 자동화를 중심으로 이야기했습니다.</p>
<p>이외에도 아키텍처 설계, 논리 오류와 디버깅, 테스트를 이용해 AI를 통제하는 방법 등은 책에 사례와 프롬프트가 예시와 함께 더 상세하게 정리되어 있으니 참고하시면 많은 도움이 될 것 같습니다.</p>
<h1 id="마무리하며">마무리하며</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/d2d1ff91-64c4-481e-9967-d90224f84686/image.png" alt=""></p>
<p>AI가 작성하는 코드의 양이 늘어날수록 개발자가 직접 작성하는 코드의 양은 줄어들 수 있습니다.</p>
<p>하지만 어떤 기능을 만들어야 하는지 정의하고, 어디까지 허용할지 결정하며, 결과가 정말 올바른지 책임지는 일은 줄어들지 않습니다.</p>
<p>오히려 AI가 빠르게 수많은 코드를 만들어낼 수 있기 때문에 잘못된 방향을 초기에 발견하고 통제하는 능력이 더욱 중요해집니다.</p>
<p>결국 AI 시대에 개발자의 일이 사라지는 것이 아니라, 개발자의 일에서 <strong>코딩보다 엔지니어링이 차지하는 비중이 커지고 있습니다.</strong></p>
<p>개발은 AI가 할 수 있습니다. 그러나 엔지니어링은 아직 사람의 몫입니다.</p>
<p>두서없이 설명했지만, 책에는 정말 상세하게 나와있으니 AI 개발에 맛들리신 분들이 꼭 읽어보셨으면 좋겠습니다.</p>
<p>피드백, 소통은 언제나 환영합니다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AI는 현시점 어디쯤 흘러가는걸까?]]></title>
            <link>https://velog.io/@playername_ltt/AI%EB%8A%94-%ED%98%84%EC%8B%9C%EC%A0%90-%EC%96%B4%EB%94%94%EC%AF%A4-%ED%9D%98%EB%9F%AC%EA%B0%80%EB%8A%94%EA%B1%B8%EA%B9%8C</link>
            <guid>https://velog.io/@playername_ltt/AI%EB%8A%94-%ED%98%84%EC%8B%9C%EC%A0%90-%EC%96%B4%EB%94%94%EC%AF%A4-%ED%9D%98%EB%9F%AC%EA%B0%80%EB%8A%94%EA%B1%B8%EA%B9%8C</guid>
            <pubDate>Thu, 25 Jun 2026 00:16:57 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/1fd9a225-9692-4df0-885c-e255b3e26785/image.png" alt=""></p>
<p>지난 6월 18일을 마지막으로 “Gemini CLI”가 구글의 무덤으로 들어갔습니다.</p>
<p>대신 구글은 “Antigravity”를 사용하라며 들이밀었죠. 마치 “Codex app”과 “Claude Desktop” 처럼요.</p>
<p>심지어는 vscode 스타일이던 앱을 “Antigravity IDE”로 분리하더니 “Antigravity”는 에이전트 앱으로 만들어버리고 기존 IDE는 “Antigravity IDE”로 분리해버렸습니다.</p>
<p>물론 이들의 공통점은 “GUI 기반의 Desktop App” 이라는 겁니다.</p>
<h1 id="ai-플랫폼의-변천사">AI 플랫폼의 변천사</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/af6c4ca4-6eac-4fac-ba70-a4c5aa25cea9/image.png" alt=""></p>
<p>AI 도구는 곰곰히 생각해보면 주된 플랫폼이 바뀌어왔습니다.</p>
<p><strong>웹 플랫폼 → IDE+AI → CLI → GUI기반의 Desktop App</strong> 으로요.</p>
<h2 id="1-웹-플랫폼의-탄생과-번영">1. 웹 플랫폼의 탄생과 번영</h2>
<hr>
<p>2022년 11월 30일, 세상을 뒤바꿀 기술이 공개되었습니다. “Chat GPT” 라고 불리는 그 녀석이요. 물론 “Claude”, “Gemini”들도 세상에 나왔습니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/6f463800-15a8-4b4e-a8fa-626b905a315d/image.png" alt=""></p>
<p>우리는 그 웹사이트에서 프롬프트를 입력하고 AI가 뱉어내는 코드를 복사-붙여넣기 하고, 우리 코드에 맞게 수정하는 등의 작업들을 해왔었습니다.</p>
<p>코드가 조금만 길어져도 컨텍스트가 한계를 맞이했고, 화면을 왔다 갔다 하는 게 너무 귀찮았죠.</p>
<p>개발자들은 생각하기 시작했습니다. “화면 왔다갔다 하기 싫은데…”</p>
<h2 id="2-ide-와-ai의-네이티브-결합">2. IDE 와 AI의 네이티브 결합</h2>
<hr>
<p>이후 몇몇 도구들이 등장했습니다.</p>
<p>github copliot, cursor 등이 나왔어요. 앞서 말했던 화면 전환의 귀찮음을 해결하기 위해 AI를 개발 도구 안으로 끌고 들어와버렸죠.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/7ed3cfb4-d61f-41a0-a73d-8ed38159d4a2/image.png" alt=""></p>
<p>copilot이 코드를 자동완성해주고, 도구 내에서 Q&amp;A할 수 있게 되었습니다. 곧이어서는 직접 코드를 수정해주기도 하죠.</p>
<p>하지만 이 페러다임 역시 “IDE 에디터 창 내부”라는 가두리에 붂여 있었고, 런타임 제어나 시스템 명령어 실행 등에는 제한적이었습니다.</p>
<h2 id="3-터미널의-해방과-cli-자동화">3. 터미널의 해방과 CLI 자동화</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/d9384409-682d-4222-a6db-a917619bcfe6/image.png" alt=""></p>
<p>현재 가장 인기있는 툴이죠. “Claude Code”, “Codex CLI” 등이 있습니다. 개발자들에게 가장 익숙한 터미널에서 구동되는 것이 장점 중 하나였죠.</p>
<p>&quot;IDE 툴 창 안에서만 노는 걸로 부족하다&quot; 해서 터미널로 나왔습니다. 개발자들은 AI로 전체 디렉토리를 싹 스캔해서 명령어 한 줄로 테스트를 돌리고 패키지를 설치하는 강력한 자동화를 맛보게 됩니다.</p>
<p>하지만 단점 또한 명확했습니다. 텍스트 기반의 터미널 구조는 시각적으로 결과물(UI/UX)을 확인할 수 없었고, 복잡한 비동기 멀티 에이전트 오케스트레이션 수행에 한계가 있는 등의 제약이 있었습니다.</p>
<p>이를 해소하기 위한 여러 방법들이 나왔지만 다음 페이즈로 넘어가게 됩니다.</p>
<h2 id="4-gui-기반-데스크탑-에이전트">4. GUI 기반 데스크탑 에이전트</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/dadf420c-22e3-4b81-bcad-a87a006742f1/image.png" alt=""></p>
<p>최근 Google은 오픈소스로 운영하던 “Gemini CLI” 서비스를 완전 종료해버리고, 데스크탑 에이전트인 “Antigravity”를 내세웠습니다.</p>
<p>“Codex App”, “Claude Desktop”도 등장했죠. 아, Cursor 도 Agent mode에 힘을 실으며 GUI 툴들이 점점 늘어나는 추세입니다.</p>
<p>이것들의 특징은 독자적인 샌드박스를 가지고 브라우저를 씌워 UI테스트도 하고, 독립적인 백그라운드 task 등을 직접 조작할 수 있게 되었다는 겁니다.</p>
<h1 id="cli도-좋은데-왜">CLI도 좋은데 왜…</h1>
<hr>
<p>물론 저도 아직 CLI 툴을 메인으로 사용하고 있습니다. 자신의 스타일에 맞는 툴을 쓰는거죠.</p>
<p>그런데 왜 GUI 데스크탑 툴들이 인기를 얻게 된건지 조금 더 살펴보겠습니다.</p>
<h2 id="1-에이전트는-터미널-명령보다-작업-상태">1. 에이전트는 “터미널 명령”보다 “작업 상태”</h2>
<hr>
<p>CLI에서는 다음과 같이 명령합니다.</p>
<pre><code class="language-markdown">&quot;테스트를 돌려보고 실패 원인을 찾아 수정해줘.&quot;</code></pre>
<p>하지만 에이전트는 내부적으로 대략 다음과 같이 동작하죠.</p>
<pre><code class="language-markdown">요구사항 이해
→ 코드베이스 탐색
→ 수정 계획 수립
→ 파일 수정
→ 테스트 실행
→ 실패 분석
→ 재수정
→ diff 제안
→ 커밋/PR 생성</code></pre>
<p>하지만 많은 분들이 겪어 보셨을 겁니다. 이걸 터미널로 하나하나 과정을 추적하기란 꽤나 어렵습니다.</p>
<p>반면 GUI에서는 <strong>현재 어떤 파일을 고쳤는지, 어떤 테스트가 실패했는지, 어떤 diff를 승인해야 하는지, 어느 단계에서 멈췄는지</strong>를 보여주기 좋습니다. 그래서 GUI는 단순 UI가 아니라 <strong>agent harness</strong>, 즉 <strong>에이전트를 감시하고 제어하는 실행 환경</strong>에 가까워집니다.</p>
<h2 id="2-신뢰-통제가-훨씬-쉽다">2. 신뢰, 통제가 훨씬 쉽다</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/71c1df95-6a7e-458b-b720-25f3c3994791/image.png" alt=""></p>
<p>개발자가(바이브코더 아닌) AI에게 코드를 맡길 때 가장 불안한 지점은 “얘가 뭘바꾼거지?”입니다. 결과가 거의 텍스트로만 이루어져 있어, 변경사항 검토가 “git diff”나 IDE로 넘어가서 확인해야 합니다.</p>
<p>하지만, GUI 에이전트는 그렇지 않죠.</p>
<table>
<thead>
<tr>
<th>필요</th>
<th>CLI</th>
<th>GUI/IDE 에이전트</th>
</tr>
</thead>
<tbody><tr>
<td>수정 계획 검토</td>
<td>텍스트로 확인</td>
<td>plan review UI</td>
</tr>
<tr>
<td>변경사항 확인</td>
<td><code>git diff</code>, IDE로 별도 확인</td>
<td>side-by-side diff</td>
</tr>
<tr>
<td>승인/거절</td>
<td>프롬프트/명령 입력</td>
<td>버튼으로 accept/reject</td>
</tr>
<tr>
<td>파일 참조</td>
<td>경로 직접 입력</td>
<td>파일/라인 선택, @mention</td>
</tr>
<tr>
<td>되돌리기</td>
<td>git reset/checkout</td>
<td>checkpoint/rollback</td>
</tr>
<tr>
<td>여러 작업 추적</td>
<td>터미널 세션 여러 개</td>
<td>작업 카드/탭/대시보드</td>
</tr>
</tbody></table>
<p>예를 들어 Claude Code의 VS Code 확장은 Claude의 계획을 검토·수정하고, 선택한 파일/라인을 멘션하고, 제안 변경을 side-by-side diff로 승인/거절할 수 있게 합니다. 아, 물론 데스크탑 앱들도 같고요.</p>
<p>이건 CLI보다 워크플로우를 통제하기 좋은 형태입니다.</p>
<p>저희 팀원 중 한 분은 파일 변경사항 확인이 가장 큰 이유 중 하나라고 하시더군요.</p>
<h2 id="3-대상이-개발자에서-개발-조직-전체로">3. 대상이 개발자에서 “개발 조직 전체”로</h2>
<hr>
<p>CLI는 개발자나 파워 유저에게는 너무 좋습니다. 하지만 AI 개발사가 돈을 벌려면 개발자뿐만 아니라 팀, 기업, 비개발 직군 들도 끌어와야 하죠.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/f6e1c8eb-971d-4d32-bb03-8c6e17c99599/image.png" alt=""></p>
<p>GUI가 필요한 이유는 대략적으로 다음과 같습니다.</p>
<ul>
<li>주니어 개발자도 접근하기 쉬움</li>
<li>PM/디자이너/QA도 작업 상태를 확인하기 수월함</li>
<li>팀장이 AI가 만든 PR을 리뷰하기 쉬움</li>
<li>보안팀/관리자가 권한, 로그, 정책을 관리하기 수월함</li>
<li>엔터프라이즈 고객에게 “통제 가능한 도구”처럼 보임</li>
</ul>
<p>아무래도 비개발자가 쓰기는 GUI가 훨씬 자연스럽죠.</p>
<h1 id="그래도-cli는-여전히-좋다">그래도 CLI는 여전히 좋다</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/195b12c8-b11f-44da-beb2-cc3ef03fc26e/image.png" alt=""></p>
<p>CLI는 사라지지 않고 계속 발전하고 있습니다. 최근에는 Claude Code도 알아서 sub-agent를 돌리며 작업하는게 가능해졌죠.</p>
<p>앞으로는 이런식으로 가지 않을까 싶습니다.</p>
<pre><code class="language-markdown">CLI = 자동화, 파워 유저, headless 실행, CI/CD
GUI = 검토, 승인, 협업, 진행상황 추적</code></pre>
<p>물론 GUI만으로도 CLI만으로도 다 가능하지만, 취향차로 나뉠 것 같기도 하고요.</p>
<p>AI 개발사들이 GUI 기반 에이전트 툴로 이동하는 이유는 <strong>AI 코딩이 “프롬프트를 던지는 행위”에서 “작업을 위임하고 관리하는 행위”로 바뀌고 있기 때문</strong>입니다.</p>
<p>이 흐름은 에이전트 하네스를 어떤 식으로 장악하느냐의 문제인 것 같습니다.</p>
<p>AI 성능은 현재 어느정도 끌어올려졌기 때문에 앞으로 중요한 제품은 “AI가 코드를 잘 짜는가”보다 AI가 안전하게 작업하고, 사람이 적절한 지점에서 개입하고, 팀의 개발 프로세스에 자연스럽게 들어오는가를 잘 설계한 도구가 될 가능성이 큰 것 같아요.</p>
<p>피드백은 언제나 환영합니다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CMUX x AIM 해커톤 회고]]></title>
            <link>https://velog.io/@playername_ltt/CMUX-x-AIM-%ED%95%B4%EC%BB%A4%ED%86%A4-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@playername_ltt/CMUX-x-AIM-%ED%95%B4%EC%BB%A4%ED%86%A4-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 28 Apr 2026 00:09:02 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/f2d2225a-dafc-415f-86b4-22f9603737f5/image.png" alt=""></p>
<h1 id="introduce">Introduce</h1>
<hr>
<p>살면서 처음 해커톤을 나갔습니다.</p>
<p>제가 아는 일반적인 해커톤과는 다르게 8시간이 주어졌고, 거의 full 바이브 코딩으로 이어졌습니다.</p>
<p>트랙은 3가지입니다.</p>
<ol>
<li><strong>Developer Tooling</strong>: CLI 기반 개발자 도구를 만드는 트랙입니다.</li>
<li><strong>Business &amp; Apps</strong>: AI 서비스를 개발하는 트랙입니다.</li>
<li><strong>AI Safety &amp; Security</strong>: AI 취약점을 찾고, 드러내고, 방어하는 트랙입니다.</li>
</ol>
<p>그 중에서도 저희 팀은 “<strong>Developer Tooling</strong>” 트랙으로 결정했습니다.</p>
<h1 id="main-concept">Main Concept</h1>
<hr>
<p>저희 팀은 우선 한 가지 생각을 했습니다.</p>
<blockquote>
<p>우리가 필요한 도구를 만들자.</p>
</blockquote>
<ul>
<li>저희 팀원 중 한명은 <code>Grafana</code>와 같은 서버 모니터링 툴이 필요하지만, 초기 세팅이 많이 불편하다고 했습니다.</li>
<li>저는 로그를 추적하는 데에 있어서 너무 많은 공수가 든다고 했습니다.</li>
</ul>
<p>그래서 저희는 “<strong>Agent CLI 스타일의 모니터링&amp;분석 툴</strong>”을 개발하기로 했습니다.</p>
<h1 id="start-of-monix">Start of “Monix”</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/a73400b4-3310-44e7-bcdb-5de65cb8f01a/image.gif" alt=""></p>
<p><code>Monix</code>는 위에서 말했듯이 “<strong>Agent CLI 스타일의 모니터링&amp;분석 툴</strong>”입니다.</p>
<p>일단 두괄식으로 시작하겠습니다. 저희의 repo &amp; demo영상 입니다.</p>
<p>한번 구경하시고 피드백해주시면 지속적으로 시간 될 때마다 디벨롭해 나갈 생각입니다. 
물론 contribution를 받는것도 고려 중입니다.</p>
<blockquote>
<ul>
<li>Github Repo: <a href="https://github.com/co-tox/monix">monix repository link</a></li>
<li>Demo Video: <a href="https://drive.google.com/file/d/1jE6OPbg0eVTfLMZMoNPrI6TYKX4QiDFZ/view?usp=embed_facebook">monix demo video link</a></li>
</ul>
</blockquote>
<h2 id="development-plan">Development Plan</h2>
<hr>
<p>다들 처음 순수 바이브 코딩으로만 개발하는 것도 익숙하지 않고, 처음 개발 계획을 세우는 것이 난관이었습니다.</p>
<p>우선 저희가 리스트업한 해커톤에서 완성하려고 목표한 기능은 다음과 같았습니다.</p>
<ul>
<li><code>htop</code>처럼 CPU, Memory, Swap Memory 등등 성능을 실시간으로 모니터링 할 수 있는 기능</li>
<li>사용자가 지정한 interval로 성능 매트릭스를 수집하여 이를 기록으로 남기고, 분석할 수 있도록 하는 기능</li>
<li>app, docker, nginx의 로그를 각각 실시간으로 모니터링할 수 있도록 하는 기능</li>
<li>인스턴스 내의 각종 로그를 우리 툴에서 쉽게 확인하고 분석할 수 있도록 하는 기능</li>
<li>자연어로 성능 지표, 로그 등을 LLM과 Q&amp;A할 수 있도록 하는 기능</li>
</ul>
<p>사실상 마지막 기능이 핵심이었습니다. 우리는 <code>Claude Code</code>같은 모니터링 툴을 만들고 싶었으니까요.</p>
<p>저희의 협업 계획은 의외로 간단한 프로세스로 이루어졌습니다.</p>
<ol>
<li>(공통) 초기 디렉토리 셋업 &amp; PRD 정리 &amp; 테스트 코드 작성 및 실행 공통 Skill 추가</li>
<li>A - llm기능 개발 / B - 서버 성능 모니터링 기능 개발 / C - 로그 기능 개발 / D - UI 및 입/출력 관련기능 개발</li>
<li><code>main</code>에서 각자 브랜치 &amp; 디렉토리 하나씩 파서 기능 개발 후, 주기적으로 main에 병합하여 conflict를 최소화</li>
<li>무한반복</li>
</ol>
<p>이론상은 간단하지만 이 과정에 도출하기까지 한 사이클정도 걸렸습니다.</p>
<h2 id="start-developing">Start Developing</h2>
<hr>
<p>저는 위의 기능 중 “로그 기능 개발”을 맡았습니다.</p>
<p>이번 해커톤의 주최사 중 하나가 ‘CMUX’인 만큼 바로 사용하기 시작했습니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/907dc4d4-f1d8-4cbe-81ec-aadefa3d52a2/image.png" alt=""></p>
<p>CMUX는 위와 같이 에이전트 멀티태스킹 개발에 특화된 터미널 개발 툴입니다. 제 실제 해커톤에서 개발중이던 화면입니다.</p>
<p>Claude Code로 기능 개발과 오류 수정, Gemini로 git 관리와 document 관리, 창 하나는 테스트용으로 사용했습니다.</p>
<p>중간중간 작업이 끝날 때마다 <code>cmux</code>에서 이를 확인해 알림을 알려주는 것이 너무 좋더라고요. 아쉽게도 mac에서만 지원합니다.</p>
<h3 id="develop-base-features">Develop base features</h3>
<p>우선 저는 회사에서 여러 서비스의 백엔드 로그를 디렉토리 옮겨다니며 작업하는 것이 불편했기에, 이 툴 하나로 한꺼번에 해결하고 싶었습니다.</p>
<p>제가 선택한 방법은 “alias” 였습니다.</p>
<table>
<thead>
<tr>
<th>명령어</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td><code>/log add @alias -app &lt;path&gt;</code></td>
<td>애플리케이션 로그를 별칭으로 등록</td>
</tr>
<tr>
<td><code>/log add @alias -nginx &lt;path&gt;</code></td>
<td>Nginx 로그 등록</td>
</tr>
<tr>
<td><code>/log add @alias -docker &lt;name&gt;</code></td>
<td>Docker 컨테이너 로그 등록</td>
</tr>
<tr>
<td><code>/log list</code></td>
<td>등록된 모든 별칭 표시</td>
</tr>
<tr>
<td><code>/log @alias [-n N]</code></td>
<td>등록된 로그 tail</td>
</tr>
<tr>
<td><code>/log @alias --search [pattern]</code></td>
<td>에러 / 정규식 패턴 필터링</td>
</tr>
<tr>
<td><code>/log @alias --live</code></td>
<td>라이브 스트리밍</td>
</tr>
<tr>
<td><code>/log /path [-n N] [--live]</code></td>
<td>직접 경로 접근(등록 불필요)</td>
</tr>
<tr>
<td><code>/log remove @alias</code></td>
<td>등록 해제</td>
</tr>
<tr>
<td><code>/logs &lt;path&gt; [N]</code></td>
<td>일회성 tail (레거시 형식)</td>
</tr>
</tbody></table>
<p>위와 같은 기능들을 리스트업해두고, “alias”를 통해 추적하고자 하는 로그 파일을 등록하고 사용하는 방식을 선택했습니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/4b2eaf2b-941b-4d7e-a934-bab9e3d24e33/image.png" alt=""></p>
<p>정신없이 진행한 저만의 개발 프로세스는 다음과 같습니다.</p>
<ol>
<li>claude code 세션 하나로 신규 기능을 개발</li>
<li>다른 claude code 세션 하나로 아쉬운점 피드백을 통한 수정 및 오류 수정</li>
<li>gemini 현재까지의 작업을 git에 push</li>
<li>다른 gemini 하나로 변경사항을 확인해 document 파일 업데이트 또는 다음 개발사항 체크하여 문서화</li>
<li>저는 직접 실사용 테스트 수행</li>
</ol>
<p>세션별로 진행중인 개발상황을 공유하기 위해서는 별도의 개발 진행상황 및 plan 문서를 작성해두어 다른 에이전트가 읽고 수행할 수 있도록 했는데, 이게 일차원적이긴 하지만 꽤나 유용한 방법 중 하나였습니다.</p>
<h3 id="difficulty-in-develop-agent-tool-calling">Difficulty in Develop, Agent Tool calling</h3>
<p>저의 난관은 툴 개발에서 막혔습니다. 제가 잘 모르기 때문에 이건 진짜 하나도 감이 안왔습니다.</p>
<p>일단 하나도 몰랐기 때문에 “llm에서 log 툴을 사용할 수 있도록 개발해줘.”라고 지시를 내렸습니다.</p>
<p>하지만 이후 llm에게 <code>alias</code>와 함께  자연어로 요청을 할 때마다 그냥 단순 로그 출력만 하고 끝나는 상황을 보게 되었습니다. 의도한 방향이 아니었어요.</p>
<p>몇번 버그를 고치려고 명령을 아무리 내려봐도, 결과는 같았습니다.</p>
<p>그래서 저는 “기획 의도”를 에이전트에게 주입했습니다. 우리의 서비스는 “에이전트 기반 성능 모니터링 &amp; 로그 분석 툴”이라고, <strong>모든 베이스는 사용자가 llm에게 내리는 자연어 명령</strong>이라고 말입니다.</p>
<p>에이전트를 제대로 써먹기 위한 핵심은 “기획”을 에이전트에게 얼마나 잘 전달하느냐였습니다.</p>
<h2 id="finish-development">Finish Development</h2>
<hr>
<p>중간중간 팀원과 <code>main</code>브랜치에서 싱크를 맞추고 계속 에러 핸들링을 해가며 개발을 완료했습니다.</p>
<p>아쉬운 점도 있지만, 짧은 시간 내에 이만큼이나 했다는 데에 만족스러웠습니다.</p>
<p>팀원 중 한명의 사이드 프로젝트 인스턴스에 우리 툴을 띄워 테스트했습니다.</p>
<p>마지막은 팀원들과 분배하여 document작성, demo 영상 촬영, PPT 작성, 피칭 계획 등을 진행하고 마무리했습니다.</p>
<p>저희는 아마 이후</p>
<ul>
<li>모니터링하다 문제가 발생할 경우 webhook을 통한 알림 기능(Slack, Discord 등)</li>
<li><code>/커맨드</code>자동완성. 지금 가능한 커맨드는 보여주지만, 자동완성 기능은 제공하지 않습니다.</li>
<li>로컬에서 클라우드 인스턴스를 모니터링하며 문제가 발생할 경우, llm이 직접 조치사항을 제어할 수 있는 mcp 기능</li>
</ul>
<p>기능들을 목표로 추가 개발/유지보수에 들어갈 것 같습니다.</p>
<h1 id="⭐️-what-did-you-get-from-this-hackathon">⭐️ What did you get from this Hackathon?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/c0534b25-c41d-4d83-a9f1-c8dd3ef31679/image.png" alt=""></p>
<p>제가 이번 해커톤에서 얻은 가장 큰 것은 의외로 “자신감” 입니다. 소위 “괴물”이 많았음에도 불구하고요.</p>
<p>솔직히 AI를 원없이 써본 것은 처음이었습니다. full vibe 코딩만으로 뭔가를 만들어낸 것도 처음이고요.</p>
<p>CLI 개발도 처음이었습니다. 이번에 개발자 도구를 만들기로 했지만 걱정이 많이 되었어요.</p>
<p>그런데 그게 무색해질만큼 에이전트는 너무 일을 잘했고, 기본적인 개발 지식과 에이전트만 잘 다룰 줄 안다면 가능했습니다. 처음이 두렵지 시작하고 나면 뭐든 해낼 수 있습니다. AI가 잘 보조할거고, 뚝딱대더라도 버벅거리더라도 언젠가는 목표를 달성할 수 있죠.</p>
<p>바이브 코딩이 힘들거나 에이전트 활용법이 고민되는 분들이 있다면 같이 공유해주시면 너무 좋을 것 같습니다. 모른다면 공부해서라도 같이 싸매며 나아가봐요.</p>
<p>AI는 너무 급격히 발전을 이루었고 이건 이제 멈출 수 없습니다.</p>
<p><strong>“4차 산업혁명”이라는 말이 너무나 와닿는 해커톤이었습니다.</strong></p>
<p>이번일로 많이 고민이 되더라고요. 회사에서 지원하는 ‘Claude Pro’만으로는 너무 부족해서 개인적으로 Max를 결제할까 생각 좀 해봐야겠습니다.</p>
<p><em>이번 해커톤을 계기로 앞으로 재미있는 해커톤이 있다면 찾아서 나가봐야겠습니다. 피드백은 언제나 환영입니다.</em></p>
<p><em>monix의 피드백과 추가 기능 추천도 해주신다면 너무 감사드리겠습니다. 팀원들과 공유하여 디벨롭하겠습니다 :)</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AI 코딩 툴, 제대로 쓰고 계신가요?]]></title>
            <link>https://velog.io/@playername_ltt/AI-%EC%BD%94%EB%94%A9-%ED%88%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%93%B0%EA%B3%A0-%EA%B3%84%EC%8B%A0%EA%B0%80%EC%9A%94</link>
            <guid>https://velog.io/@playername_ltt/AI-%EC%BD%94%EB%94%A9-%ED%88%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%93%B0%EA%B3%A0-%EA%B3%84%EC%8B%A0%EA%B0%80%EC%9A%94</guid>
            <pubDate>Tue, 17 Mar 2026 00:08:04 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>본 컨텐츠는 길벗출판사에서 보내준 <a href="https://gilbut.co/c/26010575Dq">&lt;AI 자율학습 클로드 코드·코덱스 CLI·제미나이 CLI 완전 활용법&gt;</a> 을 읽고 작성한 컨텐츠 입니다.</p>
<p>서평 작성이라서 생각을 많이 했는데 이 활용법을 읽고, 이 학습서의 대략적인 내용을 <strong>저의 추가 활용방안에 대한 생각과 작성해 보려고 합니다.</strong> 아마 독후감과 서평 사이라고 보시면 될 것 같습니다.</p>
<p>마지막에 제가 책을 읽고 직접 만들어본 <strong><code>Claude Code를 위한 Springboot 프로젝트 템플릿</code></strong>을 공유드립니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/1a313273-0e13-456b-842d-11ffe45dc549/image.png" alt=""></p>
<p>언제까지 브라우저 창과 IDE를 오가며 &#39;복사-붙여넣기&#39;의 굴레에 갇혀 있을 수는 없습니다. 이제는 터미널 안에서 코드베이스를 직접 이해하는 AI를 만나야 할 때입니다.</p>
<h1 id="왜-지금-ai-코딩-cli인가">왜 지금 ‘AI 코딩 CLI’인가?</h1>
<hr>
<p>현 시점에서 IT 업계 종사자라면 AI를 사용하지 않아본 분들은 없을 겁니다.</p>
<p>아, 그니까 웹 브라우저에서 사용하는 AI 말입니다.</p>
<p>다들 모르는 문제에 대하여 질문을 작성하고, GPT가 내놓은 답변을 읽고(때때로는 귀찮아 코드만 복사하고), 내용을 붙여넣고, 돌려보고, 안된다고 푸념하고, 다시 작성하고…… 반복해본 경험 있으실 겁니다.</p>
<p>여기서 다루는 가장 큰 세 가지인 <code>Claude Code</code>, <code>Codex CLI</code>, <code>Gemini CLI</code>는 여러분의 코드베이스를 읽어 여러분이 물어본 질문에 답변하고 요청한 작업을 수행합니다.</p>
<p>우선 이 책에서는 AI 코딩 도구를 크게 두 가지 분류로 나누어 말합니다.</p>
<p><code>IDE형</code>과 <code>터미널형</code>으로요.</p>
<p>AI 코딩 도구가 처음 각광받기 시작하던 시점에는 IDE가 시장을 지배했었지만, 현 시점에서는 터미널 기반 툴이 단연코 시장을 압도하고 있습니다.</p>
<p>이 책은 그 “CLI 툴”을 입문부터 실무까지 사용하는 방법을 소개하고 있습니다.</p>
<p>툴 사용을 위한 기초적인 배경지식, 툴 설치부터 프로젝트에 툴 사용하기까지 광범위한 내용을 다루고 있습니다.</p>
<h1 id="cli-툴들-사용해보기">CLI 툴들 사용해보기</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/7525115e-84f2-4899-8d38-e4471640c574/image.png" alt=""></p>
<p>책에서 다루는 가장 첫 번째 툴은 “Claude Code”입니다.</p>
<p>많은 사람들이 입을 모아 “가장 개발을 잘한다”라고 얘기하는 도구이죠.</p>
<blockquote>
<p>이전 글(<a href="https://velog.io/@playername_ltt/%ED%95%9C%EB%8B%AC%EB%A7%8C%EC%97%90-AI%EB%A1%9C-%EC%BD%94%EB%93%9C-3%EB%A7%8C%EB%9D%BC%EC%9D%B8-%EC%A7%9C%EB%A9%B0-%EA%B9%A8%EB%8B%AC%EC%9D%80-%EA%B2%83">한달만에 AI로 코드 3만라인 짜며 깨달은 것</a>)을 작성하던 시점에는 Claude Code를 사용해보지 않았지만, 최근 회사에서 Claude Code를 지원해주기 시작하여 열심히 써먹어보고 있습니다.</p>
</blockquote>
<p>우선 빠르게 각 챕터별 핵심 내용 위주로 소개해드리겠습니다.</p>
<p>처음 써보는 사람도 상세하게 따라 할 수 있도록 책에 상세하게 잘 정리되어있으니 궁금하시면 책 참고하시면 좋을 것 같습니다.</p>
<h2 id="기본-사용법">기본 사용법</h2>
<hr>
<p><strong>“컨텍스트(Context) 관리하기”</strong></p>
<p>쉽게 말해 대화 내용 관리입니다. 최근 RLM(Recursive Language Model)의 발견 등으로 인해 컨텍스트 윈도우의 크기(한 세션에서 AI가 맥락을 이해할 수 있는 길이)가 비약적으로 발전 중이지만, 이는 다 비용으로 이어집니다.</p>
<p>무엇보다 비용이 문제가 아닌, AI가 사용자의 의도를 잘못 이해하기 시작하면 이는 곧 생산성 저하로 이어지기 때문에 이를 제대로 관리하는 것이 핵심이라고 할 수 있습니다.</p>
<p>상황 하나를 가정해봅시다.</p>
<p>AI에게 </p>
<p><em>“이벤트를 날짜별로 조회할 수 있는 기능을 만들어줘”</em> </p>
<p>라고 입력했더니 AI는 이벤트의 조회 조건을 하루하루 끊어서 진짜 순수 날짜별로만 조회할 수 있게 만들어버립니다.</p>
<p>잘못된 기능이기에 다시 요청합니다. </p>
<p><em>“아니 이게 아니고 이벤트 날짜별 조회인데 특정 기간을 지정하고 그 사이에 진행하는 모든 이벤트를 조회하고 싶었던 거야.”</em></p>
<p>이 두 컨텍스트는 AI에게 불필요한 컨텍스트가 되어 AI 기능과 기억력에 사소하게 마이너스 요소로 작동합니다.</p>
<p>이를 해결하기 위해 가장 쉬운 방법은 “Claude Code”에서 <code>/compact</code>를 실행해버리면 끝입니다. 핵심만 추출하고 이전 컨텍스트들은 날려버리거든요.</p>
<p>AI의 성능과 속도를 위해선 <code>/compact</code>가 아니더라도, 컨텍스트 관리가 필수적입니다.</p>
<p>이 부분이 다들 놓치고 넘어갈 수 있는 부분인데 언급하고 사유까지 더 상세하게 이해하기 쉽게 설명해준 부분이 상당히 인상적이었습니다.</p>
<h2 id="프로젝트-운영">프로젝트 운영</h2>
<hr>
<p><strong>“md 파일로 프로젝트 구조잡고 운영하기”</strong></p>
<p>사실 이 부분은 제가 거의 써먹지 않은 방법이었습니다. </p>
<p>멀티모듈 프로젝트를 운영하며 모듈별 관리에 고민이 많았는데, 책에서 제안한 &#39;모듈별 <code>.md</code> 관리 방식&#39;이 무척 유용했습니다.
각 모듈의 폴더 내에 직접 설명 문서를 두는 방식을 최근 적용하기 시작했는데, 확실히 최초 페르소나 부여 및 프로젝트 구조 파악이 빨라지는 효과를 체감하고 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/7e31af85-97c4-433f-be4f-fa12fbd41447/image.png" alt=""></p>
<h3 id="1-계층적-컨텍스트-구조-hierarchical-context">1. 계층적 컨텍스트 구조 (Hierarchical Context)</h3>
<p>가장 대표적인 사례는 Anthropic의 <strong>Claude Code</strong>가 제안하는 <strong><code>CLAUDE.md</code></strong> 기반 구조입니다.</p>
<p>프로젝트 루트에만 가이드를 두는 것이 아니라, <strong>각 모듈이나 디렉토리별로 컨텍스트 파일을 분산 배치</strong>하여 AI가 해당 폴더에 진입했을 때 필요한 정보만 읽게 하는 방식입니다.</p>
<ul>
<li><strong>Root <code>CLAUDE.md</code></strong>: 전체 기술 스택, 빌드 명령어, 전역 코드 스타일.</li>
<li><strong>Module <code>CLAUDE.md</code> (혹은 <code>README.md</code>)</strong>: 해당 모듈의 도메인 로직, 의존 관계, 특정 설계 패턴(예: &quot;이 모듈은 Querydsl만 사용함&quot;).</li>
</ul>
<blockquote>
<p><strong>Claude Code 공식 문서:</strong> <a href="https://code.claude.com/docs/en/best-practices">Best Practices for Claude Code</a></p>
<p>문서에서는 &quot;코드만으로 추론할 수 없는 의도&quot;를 담기 위해 <code>CLAUDE.md</code>를 적극 권장하며, 대규모 프로젝트에서는 하위 디렉토리에 전용 가이드를 둘 것을 제안합니다.</p>
</blockquote>
<h3 id="2-agentsmd-표준화-프로젝트">2. <code>AGENTS.md</code> 표준화 프로젝트</h3>
<p>특정 도구(Claude, Cursor)에 종속되지 않고, 모든 AI 에이전트가 읽을 수 있는 공통 규약을 만들려는 시도입니다.</p>
<p>프로젝트 루트에 <code>AGENTS.md</code>를 두고 아래와 같은 섹션을 명확히 구분합니다.</p>
<ol>
<li><strong>Onboarding:</strong> 프로젝트 목적 및 환경 설정.</li>
<li><strong>Architecture:</strong> 데이터 흐름 및 모듈 구조.</li>
<li><strong>Rules &amp; Standards:</strong> 금지 사항(Anti-patterns) 및 필수 준수 사항.</li>
</ol>
<blockquote>
<p><strong>AGENTS.md 공식 사이트:</strong> <a href="https://agents.md/">agents.md</a></p>
<p>OpenAI Codex, Google, Cursor 등의 개발자들이 협력하여 만든 오픈 형식입니다. 여러 에이전트가 공통으로 참조할 수 있는 &quot;AI 전용 README&quot;의 표준을 제시합니다.</p>
</blockquote>
<h3 id="3-규칙-기반-모듈화-cursorrules-및-clauderules">3. 규칙 기반 모듈화 (<code>.cursorrules</code> 및 <code>.claude/rules/</code>)</h3>
<p>최근에는 설정 파일 하나에 모든 규칙을 때려 넣는 대신, <strong>관심사별로 규칙 파일을 쪼개는 방식</strong>이 주류입니다.</p>
<pre><code># 구조 예시

project-root/
├── .claude/
│   └── rules/
│       ├── testing.md       # 테스트 코드 작성 원칙
│       ├── api-design.md    # API 네이밍 및 DTO 규약
│       └── db-schema.md     # JPA 및 DB 마이그레이션 규칙
├── module-websocket/
│   └── README.md            # WebSocket 명세 및 로직 설명
└── module-api/
    └── README.md            # API 명세 및 인증 흐름</code></pre><blockquote>
<p><strong>Cursor 가이드:</strong> <a href="https://cursor.com/docs/rules">Cursor Rules Best Practices</a></p>
<p>&quot;규칙은 짧고(500라인 이하), 구체적이며, 파일 기반으로 참조(Reference files)해야 한다&quot;고 명시합니다. 특히 복잡한 백엔드 프로젝트에서 AI의 환각을 줄이는 가장 효과적인 방법으로 꼽힙니다.</p>
</blockquote>
<h2 id="고급-기능-활용">고급 기능 활용</h2>
<hr>
<p>MCP 사용법과, 서브에이전트 사용법, Hook 사용법 등을 설명해 주고 있습니다.</p>
<p>이 부분에서는 고급 기능인 만큼 충분히 익숙해지고 이해도를 높인 다음 사용하는 것을 추천드립니다.</p>
<p>(저도 사실 아직 제대로 못써보고 있습니다)</p>
<p>최근 AI의 지나친 권한 부여, 보안 등 이슈가 많았거든요. 발전속도에 비해 못따라오는 듯한 그런 느낌도 있고요.</p>
<ul>
<li><a href="https://www.tomshardware.com/tech-industry/artificial-intelligence/claude-code-deletes-developers-production-setup-including-its-database-and-snapshots-2-5-years-of-records-were-nuked-in-an-instant">개발자의 프로덕션 설정을 날려버린 Claude Code</a></li>
<li><a href="https://zdnet.co.kr/view/?no=20251108141527">AI 보안이슈 보고</a></li>
</ul>
<p>혹시나 읽어보시거나 사용하실 때 공유할만한 팁이 있다면 공유해주세요 :)</p>
<h1 id="ai-워크플로우-자동화-개발-흐름-완성">AI 워크플로우, 자동화 개발 흐름 완성</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/63d8f84c-7992-4d9f-a492-b4386ac9da3e/image.png" alt=""></p>
<p>앞에서 쌓은 지식들을 바탕으로 AI를 만땅으로 사용하는 개발 워크플로우를 순차적으로 상세하게 설명해줍니다.</p>
<h2 id="프로젝트-계획-단계">프로젝트 계획 단계</h2>
<hr>
<blockquote>
<p>PRD 작성 → 실행계획과 WBS 작성 → 컨텍스트 파일 작성</p>
</blockquote>
<h3 id="prd">PRD</h3>
<p>PRD는 문서를 완벽하게 만드는 것이 아니라, AI가 참고할 핵심 기준을 만드는 것을 주요 목적으로 합니다.</p>
<ul>
<li>제품 개요, 핵심 기능, 대상 사용자, 기술 스택 등을 작성합니다.</li>
<li>저같은 경우는 귀찮아서 AI한테 초안 작성하라고 한다음에 수정합니다.</li>
</ul>
<h3 id="실행계획과-wbs-작성">실행계획과 WBS 작성</h3>
<p>실행 계획은 프로젝트를 어떤 순서대로 진행할지 정리하는 로드맵입니다.</p>
<ul>
<li>기존에는 타임라인 정의, 작업 간 의존성 파악, 리소스 배분, 주요 마일스톤 설정이 필수적입니다.</li>
</ul>
<p>WBS는 큰 작업을 작은 작업들로 세분화하고 관리하기 쉽게 만드는 구조입니다.</p>
<ul>
<li>PRD를 잘 작성해 두었다면, Plan 모드를 켜서 실행계획과 WBS 또한 AI가 상세하게 작성해줍니다.</li>
</ul>
<h3 id="컨텍스트-파일-작성">컨텍스트 파일 작성</h3>
<p>PRD로 무엇을 만들지, WBS로 어떻게 만들지를 정의했다면 이를 활용하여 컨텍스트 파일을 작성하여 계획을 마무리짓습니다.</p>
<ul>
<li>AI가 프로젝트를 안정적으로 이해하기 위한 파일문서 입니다.</li>
<li>프로젝트 요약, 기술 스택, 핵심 규칙, 폴더 구조 등을 명시해둡니다.</li>
</ul>
<pre><code>// 컨텍스트 파일 example

# 프로젝트 컨텍스트: [프로젝트 명]

## 1. 프로젝트 요약
- **목적**: [예: 실시간 컨퍼런스 통번역 및 기록 서비스]
- **대상 사용자**: [예: 다국어 행사를 진행하는 운영진 및 참가자]
- **핵심 가치**: 저지연 번역(500ms 이내), 높은 도메인 용어 정확도

## 2. 기술 스택 (Tech Stack)
- **Backend**: Java 21, Spring Boot 3.4
- **Database**: PostgreSQL (Main), Redis (Cache)
- **AI/ML**: Google Gemini API, LangChain4j
- **Infrastructure**: Docker, Kubernetes

## 3. 핵심 개발 규칙 (Core Rules)
- **Architecture**: 멀티모듈 구조를 따르며, 각 모듈의 책임(Domain/API/Infra)을 엄격히 분리한다.
- **Code Style**: Google Java Style Guide를 준수하고, 모든 비즈니스 로직은 Service 계층이 아닌 Domain 엔티티 내부에서 처리하도록 노력한다.
- **Exception**: `CustomException`을 정의하여 사용하며, 모든 API 응답은 `ApiResponse&lt;T&gt;` 포맷으로 통일한다.
- **Testing**: JUnit 5와 AssertJ를 사용하여 핵심 도메인 로직에 대한 단위 테스트를 반드시 작성한다.

## 4. 폴더 구조 (Project Structure)
- `project-api/`: 외부 클라이언트 요청 처리 (Controller, DTO)
- `project-domain/`: 순수 비즈니스 로직 및 엔티티
- `project-infra/`: DB 설정, 외부 API(Gemini) 연동부
- `docs/`: PRD, WBS 등 기획 문서 보관</code></pre><h3 id="추가적인-계획-단계의-팁">추가적인 계획 단계의 팁</h3>
<ul>
<li><strong>&quot;AI에게는 지도가 필요&quot;</strong>: PRD가 &#39;무엇을(What)&#39; 만들지 정의한다면, 컨텍스트 파일은 &#39;어떻게(How)&#39; 유지할지를 정의합니다. 폴더 구조만 명시해줘도 AI가 파일을 찾느라 엉뚱한 곳을 헤매는 시간을 80% 이상 줄일 수 있습니다.</li>
<li><strong>&quot;규칙은 구체적일수록 좋음&quot;</strong>: 단순히 &quot;Clean Code를 지켜줘&quot;라고 하기보다 &quot;Service 계층에서 인터페이스를 쓰지 마&quot;처럼 <strong>도구적으로 명확한 지시</strong>를 담는 것이 핵심입니다.</li>
<li><strong>&quot;살아있는 문서화&quot;</strong>: 프로젝트가 진행되면서 새로운 기술이나 규칙이 추가되면 이 파일을 가장 먼저 업데이트하세요. AI는 항상 최신화된 이 파일을 바탕으로 다음 단계의 코드를 생성합니다</li>
</ul>
<h2 id="실전-프로젝트-수행">실전 프로젝트 수행</h2>
<hr>
<blockquote>
<p>부트스트래핑 → 단계별 개발 → TDD 개발 → 코드 품질 개선 → 배포와 운영</p>
</blockquote>
<p>이 파트에서는 각 파트별 AI로 “무지성 바이브 코딩”이 아닌 “똑똑한 바이브 코딩”하는 법을 예시와 함께 상세하게 안내해 줍니다.</p>
<p>각 예시를 직접 해보며 하는 것을 추천드리며, 이 부분은 책을 따라가서 해보면 좋을 것 같습니다.</p>
<p>아래는 제가 자주 사용하는 코드 리팩토링 프롬프트입니다.</p>
<pre><code>&lt;클래스&gt;를 리팩토링하세요.
- SOLID원칙과 클린코드 원칙 준수
- 디자인패턴 적용이 가능한 포인트 점검 후 적용
- 과도한 추상화 및 클래스 분리 지양</code></pre><h1 id="⭐claude-code를-위한-springboot-프로젝트-템플릿">⭐Claude Code를 위한 Springboot 프로젝트 템플릿</h1>
<hr>
<p>아래는 책을 읽고 제가 나름대로 만들어본 Claude Code를 위한 Springboot 프로젝트 템플릿입니다.</p>
<blockquote>
<p><a href="https://github.com/ksj000625/springboot-for-claude-code-template">Springboot Template for Claude-Code</a></p>
</blockquote>
<p>코드를 보고 편의에 맞게 수정해서 사용하세요.</p>
<p>추후 시간이 될 때 종종 업데이트하고, FastAPI등의 다른 프레임워크의 boilerplate도 추가하겠습니다.</p>
<h1 id="번외-ai-쓰면-공부가-안될-거-같은데요">번외: AI 쓰면 공부가 안될 거 같은데요</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/a3263aa7-e7c7-4ca4-8a20-c16327ad0a69/image.png" alt=""></p>
<p>반은 맞고 반은 틀립니다. 개발자가 되고 싶어 갓 공부를 시작한 대학교 저학년이라면 이게 충분히 맞는 말입니다.</p>
<p>하지만 어느정도 개발에 대한 이해를 하고 나면 AI가 오히려 공부에 도움이 됩니다.</p>
<p>AI 툴은 훌륭한 조수입니다. 여러분의 생각을 보조하고, 필요하다면 방향도 제시해줄 수 있죠.</p>
<p>혼자 작성한 코드만을 바라보며 공부한다면 자신의 스타일과 구현 방법 등에 매몰되어 더딘 성장을 할 거라고 생각합니다.</p>
<p>AI 툴은 여러분이 생각하지 못한 문제 해결 방법과 코드를 제공합니다. 남의 코드를 보는 것은 성장의 발판 중 하나이죠.</p>
<p>또한, 한번이라도 써보고 본인 가치관에 맞는 생각을 해보길 추천합니다.</p>
<h1 id="마무리하며">마무리하며</h1>
<hr>
<p>AI 툴도 공부하며 잘 쓸줄 알아야 하는 시대가 다가오고 있습니다. 개발자는 점점 AI들을 사용하는 기술자이자 지휘자가 되어가고 있습니다.</p>
<p>저는 개발자를 ‘기능을 구현하는 사람’이라고 정의하고, 엔지니어를 ‘문제를 정의하고 해결방법을 찾는 사람’이라과 정의합니다. 이제 ‘개발’은 AI에게 맡기고, ‘엔지니어링’은 사람이 맡아 진행해야 한다고 생각합니다.</p>
<p>미뤄오던 AI 툴 공부, 이제 슬슬 함께 시작해봅시다 :)</p>
<p><em>피드백이나 소개해줄 팁이 있다면 언제든 댓글 달아주세요.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한달만에 AI로 코드 3만라인 짜며 깨달은 것]]></title>
            <link>https://velog.io/@playername_ltt/%ED%95%9C%EB%8B%AC%EB%A7%8C%EC%97%90-AI%EB%A1%9C-%EC%BD%94%EB%93%9C-3%EB%A7%8C%EB%9D%BC%EC%9D%B8-%EC%A7%9C%EB%A9%B0-%EA%B9%A8%EB%8B%AC%EC%9D%80-%EA%B2%83</link>
            <guid>https://velog.io/@playername_ltt/%ED%95%9C%EB%8B%AC%EB%A7%8C%EC%97%90-AI%EB%A1%9C-%EC%BD%94%EB%93%9C-3%EB%A7%8C%EB%9D%BC%EC%9D%B8-%EC%A7%9C%EB%A9%B0-%EA%B9%A8%EB%8B%AC%EC%9D%80-%EA%B2%83</guid>
            <pubDate>Thu, 26 Feb 2026 00:09:02 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/b8dcf195-1602-4e61-adfa-a8f33c523433/image.png" alt=""></p>
<p>우선 제목에서 나왔듯이 약 한달간 spring 약 2만라인, flutter 약 1만라인 정도를 짰습니다.</p>
<p>당연히 손수 3만라인을 작성하기에는 하루 8~9시간으로는 턱도 없어요.</p>
<p>그러면 프로젝트의 메인 기능을 맡게 된 만 1년차 개발자가
AI를 도대체 어떻게 썼는지, 무엇을 깨달았는지 공유해드리겠습니다.</p>
<h1 id="무슨-ai를-사용하셨나요">무슨 AI를 사용하셨나요?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/5fe7fd1e-8c77-4862-8eeb-a52b13341fd6/image.png" alt=""></p>
<p>요즘 다들 <code>Claude</code>에 열광합니다. <code>Claude Code</code>는 현존 최고의 코드 에이전트라고 해도 무방할 정도로 무섭게 명성을 쌓아가고 있죠.</p>
<p>하지만 제가 사용한 툴은 <code>Gemini CLI</code> 와 <code>Cursor</code>입니다.</p>
<p>이유는 간단했습니다. 제가 Gemini pro 6개월 무료이용권을 받아서, Cursor는 회사에서 결제해줘서죠.</p>
<p>만약 AI 코드 에이전트를 써보고 싶은데 돈값 잘 못할까봐 걱정되는 분들은 무료 사용량이 넉넉한 <code>Gemini CLI</code>로 시작하는 것을 강력 추천합니다.</p>
<p>저는 무료 사용기간이 끝나면 그때 <code>Claude Code</code>로 갈아탈 예정입니다.</p>
<h1 id="ai와-협업하는-개발-루틴">AI와 협업하는 개발 루틴</h1>
<hr>
<p>실제 최근에 제가 지시한 내용은 아니고, 간단한 예시들 위주로 저만의 루틴을 공유해드리겠습니다.</p>
<h2 id="1-페르소나-설정-및-업무범위-지시">1. 페르소나 설정 및 업무범위 지시</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/05d5b99e-4077-44e6-9e0e-cf38cda9fdc6/image.png" alt=""></p>
<p>우선 저는 하루의 업무를 시작하기 전, 다음과 같이 지시합니다.</p>
<pre><code>당신은 시니어급 코어 백엔드 엔지니어입니다.
오늘 당신은 저의 지시를 받아 &lt;프로젝트 이름&gt;의 개발을 진행할 부하직원 개발자입니다.

모든 작업은 **근거있는 계획** 하에 이루어져야 하며, 빌드를 통한 테스트를 해야 합니다.
작업 후에는 이전과 이후를 비교하여 **한국어**로 결과보고를 해야 합니다.

우선 오늘은 &lt;프로젝트 이름&gt;의 &lt;하위 패키지&gt;를 개발할 예정입니다.
전체 코드를 대략적으로 읽어 해당 서버의 기술 스택을 이해하고,
&lt;하위 패키지&gt;의 파일을 꼼꼼히 읽어 비즈니스와 로직을 파악하세요.</code></pre><p>이 외에는 업무별로 강조하고 싶은 것을 추가로 작성하는 편입니다.</p>
<p>한국어를 굳이굳이 강조한 이유는 얘가 자꾸 영어를 뱉습니다. 저렇게 해놔도 자꾸 영어로 말할 때가 있긴 해요.</p>
<p>그리고 이렇게 코드를 많이 읽게 한다면 <strong>“토큰은 썩어나냐”</strong> 라고 할 수도 있는데 괜찮은 이유는 다음과 같습니다.</p>
<ol>
<li>코드를 읽어서 파악하게 할 때에는 <code>gemini-3-flash-preview</code>모델로 설정하여 토큰을 잘 사용하지 않는 모델로 파악하게 하여 캐시시켜 둡니다.
개발 시에는 <code>gemini-3-pro-preview</code>모델로 변경하여 진행하기 때문에 캐시된 코드를 읽고 사고하는 것은 pro모델이라 사용량이 별개입니다.</li>
<li>캐시라는 것이 존재하기 때문에 이렇게 해도 진짜 빡세게 하루종일 쓰지 않는 한 거의 부족하지 않습니다.</li>
</ol>
<p>모든 판단을 AI에게 맡기지 않고 로직 설계 후 AI에게 업무지시를 내리는 것이기 때문에 “바이브 코더”분들만큼까지는 많은 토큰을 사용하지 않습니다.</p>
<h2 id="2-1차-작업-지시기초">2. 1차 작업 지시(기초)</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/330c8166-c8cf-4588-b827-368c86c0b159/image.png" alt=""></p>
<p>아무리 AI가 코드를 잘 짜도 100%마음에 드는 코드를 뱉기란 쉽지 않습니다. 그래서 저는 애초에 한 기능을 여러 차례에 걸쳐 진행할 생각을 하고 1차 업무지시를 내립니다.</p>
<h3 id="rest-api-개발-예시희망편">Rest API 개발 예시(희망편)</h3>
<pre><code>&lt;클래스&gt;의 &lt;메소드&gt;에 &quot;이벤트 검색 API&quot;의 엔드포인트만 지정해 둔 껍데기만 만들어두었습니다.
다음 요구사항을 만족하는 API를 개발하세요.
---
* 기능명: 이벤트 검색 API
* 검색 파라메터: 이벤트명, 주최사, 기간(시작일시, 종료일시), 이벤트 상태코드, 장소명
* Response DTO: 이벤트명, 주최사, 이벤트 날짜, 이벤트 상태코드, 장소명, 생성일시, 수정일시
* 상세 요구사항:
- 이벤트의 도메인 클래스는 &quot;Event&quot;입니다
- &quot;시작일시 &lt; 이벤트 날짜 &lt; 종료일시&quot; 인 데이터
- 이벤트 상태코드 클래스는 &quot;EventStatusCode&quot;클래스를 참조하세요</code></pre><p>명확하게 말로 설명하기 쉬운 작업은 위와 같이 깔끔하게 정리하여 요구사항을 전달합니다.</p>
<p>저기서 조금 더 대략적으로 설명해도 됩니다.</p>
<p>추가적으로 저의 팁은, 꽤나 복잡하거나 멋대로 수정하면 곤란한 경우에는
”개발 계획을 세우고 저에게 보고하세요. 저의 승인 후 개발을 진행해야 합니다.” 와 같은 방식을 사용하는 것도 괜찮습니다.</p>
<h3 id="rest-api-개발-예시절망편">Rest API 개발 예시(절망편?)</h3>
<pre><code>Event 도메인 객체를 사용하는 CRUD API를 설계하고 작성하세요.
비슷한 예시로는 &quot;NoticeController&quot;의 전체적인 로직과 비슷하게 짜면 됩니다.
단계적으로 생각하고 꼼꼼히 똑바로 짜세요.</code></pre><p>라는 방식도 괜찮아요. 어차피 잘못된 거는 읽고 수정하라고 하면 되니까요.</p>
<h2 id="3-2차-작업-지시수정">3. 2차 작업 지시(수정)</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/270f2640-fb17-4402-9a6a-08c553c610b3/image.png" alt=""></p>
<p>진짜 쉬운 CRUD를 제외하고는 마음에 100% 들지 않는 결과물이 나올 확률이 꽤나 높습니다.</p>
<p>저는 1차 작업 결과물을 읽어 로직의 흐름을 파악하고 다음과 같은 방식으로 지시합니다.</p>
<h3 id="비즈니스-로직-수정-예시희망편">비즈니스 로직 수정 예시(희망편)</h3>
<pre><code>방금 작업물에서 다음 내용들을 수정해야 합니다.
---
1. 방금 작업한 EventService 클래스의 getEventList 메소드의 검증 로직을 살펴보면,
EventStatusCode가 실제 DB 레코드에는 들어가지 않지만, 조회에만 사용하는 &quot;ALL&quot;이 존재합니다.
해당 케이스를 고려하여 비즈니스 로직을 수정하세요.

2. updateEvent 메소드에서 코드 컨벤션을 준수하기 위해, Domain 객체를 @Builder를 사용하여
메소드 내부에서 생성하여 사용하는데, 이 내용을 EventConverter 클래스에 선언하고 가져다 쓰도록 수정해주세요.

3. (내용은 대충 기억나진 않지만, 제가 생각한 비즈니스 로직의 순서로 수정하라고 지시하기도 합니다.)</code></pre><p>사실 2번같은 자잘한 내용들은 프롬프트 적는 시간에 제가 직접 수정하는 것이 훨씬 빠르지만 예시로 작성했습니다.</p>
<p>코드를 읽고 상세하게 개발 의도를 파악하여 반박해보고 가능한 한 상세하게
(메소드 레벨까지, 필요시 변수도) 수정 흐름을 지시하는 편이 좋습니다.</p>
<h3 id="비즈니스-로직-수정-예시절망편">비즈니스 로직 수정 예시(절망편)</h3>
<pre><code>검색조건에는 &quot;ALL&quot;이 존재합니다. 수정하세요.
또한 updateEvent()에서 Event를 만들어 쓰는 것이 아닌 것 같습니다.
다른 방법 생각해서 수정해주세요.</code></pre><p>바쁠때는 이렇게 하기도 합니다.</p>
<p>프롬프트는 어떻게 짜든 상관 없지만 저의 결론은 다음과 같습니다.</p>
<blockquote>
<p>내용이 어렵고 복잡한 로직일 수록 최대한 상세하고 가독성 좋게 지시한다.</p>
</blockquote>
<h2 id="4-마무리-작업-지시정리">4. 마무리 작업 지시(정리)</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/39f2ca0b-321a-4835-87c0-541f00400476/image.png" alt=""></p>
<p>이건 최근에 너무 복잡한 기능을 짜다보니 코드를 제대로 구조화하지 않으면 AI가 개발한 작업물들을 읽고 판단하기에 어려워집니다.</p>
<p>따라서 요즘에는 다음과 같은 간단한 프롬프트를 추가로 지시합니다.</p>
<pre><code>방금 개발한 코드들을 리팩토링하세요.
SOLID원칙과 클린코드 원칙을 최대한 준수하여 작업하세요.
추가로 디자인패턴 적용이 가능한 포인트가 있는지 한번 검토하세요.
적당한 수준에서 디자인패턴을 적용하세요.</code></pre><p>또는 간단한 수정만 했다면</p>
<pre><code>방금 개발한 updateEvent 메소드는 너무 fat합니다.(혹은, 파라메터가 많아 code smell을 경계해야 합니다)
해당 메소드에서 내부적으로 사용하는 비즈니스 로직들을 책임에 따라 분리하세요.</code></pre><p>이렇게 하여 이후 코드의 가용성과 유지보수성을 최대한 높입니다.</p>
<p>또한 어느정도 작업이 한번 이루어지면 한번 더 지시합니다.
계속 작업하다 보면, 중앙화시킬 수 있는 코드들이 분명 생기기 때문이죠.</p>
<p>사람 뿐만이 아니라 AI도 결국 코드를 읽는 것이기 때문에 의도에 맞게 클래스와 메소드를 분리하고,
한 클래스나 메소드에 책임 등이 너무 몰리는 것을 경계해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/418c2b20-bd16-4934-84e2-7825bb013663/image.png" alt=""></p>
<p><em>번외로 ‘클린코드’라는 책을 추천합니다.</em> </p>
<p><em>사람이 코드 짜는 시대는 저물어가지만, AI의 사용성을 높이기에도 좋은 소프트웨어 개발의 가장 근본적인 책이라고 볼 수 있습니다.</em></p>
<h2 id="번외">번외</h2>
<hr>
<p>제가 위에서 예시로 작성한 코드들을 살펴보면 “하지 마라”라는 키워드는 단 한번도 사용하지 않았습니다.</p>
<p>요즘에는 많이들 알고있듯이, AI도 사람과같이 “하지 마라”등의 부정적인 언어는 그걸 더 생각하게 되는 경향을 보인다는 이야기가 있거든요.</p>
<p>원래 사람도 하지말라는 것을 더 하고 싶어지는 법이잖아요.</p>
<h1 id="ai와-회의하기">AI와 회의하기</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/296da557-d712-4c02-9020-6c31af59bc7f/image.png" alt=""></p>
<p>때때로 특정 기능에 대한 처음 가닥을 잡기가 막막할 때가 있습니다.</p>
<p>이럴 때 사용하는 저만의 방법은 요구사항을 달성하기 위해 “AI와 회의를 하는 것”입니다.</p>
<h3 id="예시">예시</h3>
<pre><code>Redis streams를 사용하여 행사의 상태를 다른 클라이언트에게 전파하고 해당 내용을 저장해야 합니다.
이걸 WebSocket에서 텍스트메세지를 받아 handleTextMessage() 메소드에 구현하려고 하는데,
어떤 방법이 최적의 방법일까요?

또한 scale-out되었을 때를 고려하여
이벤트의 상태 업데이트 시점을 handleTextMessage()에 클라이언트의 요청이 도착했을 때 시점이 아닌,
브로드캐스팅을 위해 구현하 BroadcastService에서 다른 클라이언트에 메세지를 내려주기 직전의
시점에서 구현하는 것이 낫다고 생각하는데, 어떻게 생각하나요? 혹시 다른 좋은 방법이 있을까요?

--- 다른 예시

상태 변경이 비동기 멀티스레딩 환경이라 객체의 원자성이
updateEventStatusCode() 메소드에서 보장이 되나요?

--- 다른 예시

ConcurrentHashMap으로 Event객체들을 관리하는데,
메모리 해제가 제대로 이루어져야 장기적인 운영환경에서 안정적으로 돌아갑니다.
메모리 누수가 일어날 수 있는 부분이 있을까요?
또한 이를 방지하기 위해 배치 스케줄러를 통해 좀비 객체들을 주기적으로 정리하는 것은 어떻게 생각하나요?</code></pre><p>위에는 제가 비슷하게 물어보며 회의했던 질문의 유형들입니다.</p>
<p>이 외에도 몇 가지가 있지만, 직접 AI와 회의하는 것이 의미있기 때문에 이만 줄이겠습니다.</p>
<h1 id="에이전트를-쓰며-내린-결론">에이전트를 쓰며 내린 결론</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/5bacdc62-9fbc-4abc-807f-3e0747124b94/image.png" alt=""></p>
<p>요즘 시대에 AI없이 개발한다는 말은 “저는 시대에 뒤떨어지는 사람입니다”라고 고백한다는 말과 같습니다.</p>
<p>AI를 잘 쓰기 위해서는 많이 써봐야 되고, 자신에게 최적화된 사용법이 중요합니다.</p>
<p>바이브코더처럼 AI로 단기간에 폭발적인 속도로 개발하는 것도 좋지만, 개발자라면 개발자에게 어울리는 AI 활용법이 존재합니다.</p>
<p>비즈니스 로직을 검토하고, 메모리 관리에 더 나은 방법을 검토하고, 오류 발생시 추적하기 쉽도록 하고, fallback로직을 설계하고… 바이브코더와는 다른 개발자만의 장점을 AI로 살릴 수 있을 때 경쟁력이 올라간다고 생각합니다.</p>
<p>AI 에이전트를 사용하는데 익숙하지 않다면, <code>Gemini CLI</code>로 저처럼 개발을 시작해보는 것을 다시 한 번 강력하게 추천드립니다.</p>
<p>다른 AI 활용 팁들이 있다면 공유해주세요.</p>
<p>피드백은 언제나 환영합니다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AI 엔지니어링 재직자 부트캠프 회고]]></title>
            <link>https://velog.io/@playername_ltt/AI-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-%EC%9E%AC%EC%A7%81%EC%9E%90-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@playername_ltt/AI-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-%EC%9E%AC%EC%A7%81%EC%9E%90-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Fri, 13 Feb 2026 12:13:18 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/c5d43738-c00b-4dbb-bff5-a894a40da322/image.png" alt=""></p>
<p>열심히 백엔드 개발자로서 일하고 있었습니다.</p>
<p>AI를 잘 활용하는 편이라고 생각하며 개발해 나가는 와중 링크드인에는 “클로드 코드로 <del>했습니다.”, “Agent가 ~</del>입니다.” 등등 수많은 글이 올라오고 있었고요.</p>
<p>시대가 빠르게 변하는게 하루하루 느껴지고 있었습니다.</p>
<p>저는 단기 목표를 세웠죠.</p>
<blockquote>
<p>바뀐 시대에 걸맞는 AI형 인재가 되자.
그리고 가능하다면 AI 엔지니어까지 도전해보자.</p>
</blockquote>
<h1 id="어디에-왜-지원했나요">어디에 왜 지원했나요?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/b2dfaa35-6061-4a76-ad9f-20429df95c80/image.png" alt=""></p>
<p>우선 저는 몇번 들어본 “스파르타클럽 재직자 부트캠프”의 <strong>“AI 서비스 엔지니어링 트랙”</strong>에 지원했습니다. 2025년 11월 말부터 26년 2월 초까지 진행했습니다.</p>
<p>회사에서 텍스트 후보정한다고 오픈소스인 모델 가져다 쓴 것도 재미있었고, AI가 떠오르기도 하고 해서였습니다. 결론은 재밌어보여서였죠.</p>
<p>처음에는 완전 전문적인 AI 부트캠프 또는 대학원 진학도 고민해봤었습니다.</p>
<p>하지만 현실적으로 일을 관두고 전문적인 부트캠프로 들어가기에는 부담스러웠습니다.</p>
<p>매달 나가는 생활비, 월세, 공과금, 적금 등등.</p>
<p>그래서 재직자 부트캠프를 선택했습니다. </p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/1bfbcac6-8cbf-49d2-8794-aa92f96fd2fd/image.png" alt=""></p>
<p>일하면서 해당 내용 공부를 얕게나마 해볼 수 있다는 점이 메리트로 느껴졌었거든요.</p>
<p>마침 파이썬도 기본적인건 써봤고, 서버지식과 웹지식도 있기에 지원했습니다.</p>
<h1 id="절반은-필요없었습니다">절반은 필요없었습니다</h1>
<hr>
<p>먼저 단점부터 얘기해보자면 저에게는 과정의 절반가까이 필요 없는 내용이었습니다.</p>
<p>아무래도 재직자 부트캠프 특성상 개발자만 오는 것은 아니고, 오히려 비개발자분들이 더 많기도 하기 때문에 파이썬 기초와 API호출하고 사용하는법 등부터 설명해야 했고 그 과정은 저에게 필요 없었습니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/e7341483-2f9e-40ba-8ffd-42671d381562/image.png" alt=""></p>
<p>하지만 강의를 들으며 설명해주시는 튜터분들도 설명을 이해하기 쉽게 해주시고(비개발자라고 생각하고 들어봤을 때) 힘들어하시는 비개발자분들을 열심히 챙겨주셨어요.</p>
<h1 id="절반은-도움-많이-됐습니다">절반은 도움 많이 됐습니다</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/c33b269a-0e33-4c50-addc-aae5eeb3a1c8/image.png" alt=""></p>
<p>물론 앞의 내용은 기본적으로 알고 있는 내용이었지만 뒤의 내용은 도움이 꽤 될 법한 내용들로 구성이 되어있었는데, 진행했던 과제 위주로 설명해보자면</p>
<ul>
<li>RNN 모델 학습</li>
<li>영어-독일어 번역모델 학습</li>
<li>프롬프트 엔지니어링</li>
<li>RAG 챗봇 구현</li>
<li>Multimodal 기초(하이퍼 파라메터 조정)</li>
</ul>
<p>위와 같습니다. 꽤나 알차게 절반의 시간을 보낸거 같고 솔직히 50%정도 이해했나 싶습니다… AI선생님과 함께 혼자 더 공부해봐야죠.</p>
<h1 id="이제-ai-엔지니어-되는건가요">이제 AI 엔지니어 되는건가요?</h1>
<hr>
<p>아직은 한참 부족합니다. 제가 부캠에서 얻은건 사실 전문지식보다는 아이디어와 어떠한 문제를 이런식으로 해결할수 있다는 관점? 같은 느낌을 배워온게 더 크다고 생각합니다.</p>
<p>단적인 예시로 회사에서 LLM 번역 기능을 개발중인데,</p>
<ol>
<li>번역사전 적용</li>
<li>텍스트를 목표 언어로 번역</li>
<li>번역된 텍스트 검증</li>
</ol>
<p>등과 같은 AI 워크플로우를 만들어 사용하고 싶었으나…</p>
<p>시간도 부족하고 실시간으로 제공해줘야 하는 서비스이기에</p>
<ol>
<li>텍스트를 목표 언어로 번역(핵심로직이라 그대로)</li>
<li>OpenNLP 라이브러리로 번역결과 잘못된 언어인지만 검증</li>
</ol>
<p>플로우까지밖에 우선 작성하지 못했습니다. 이후 이 문제를 어떻게 해결할 수 있을지 더 고민해보고 해봐야겠죠.</p>
<p>이런 AI를 이용한 문제 해결 등이 재밌어서 이쪽 공부를 계속 해가며 도전해볼 생각은 있습니다. </p>
<p>제 잡지식이 많은 장점을 살릴 수 있는 것은 Product Engineer (괜시리 있어보이게)처럼 전반적인 개발문제를 다루는 직업이 적합하지 않을까 혼자 생각해봤습니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/9f8a9697-a471-40df-882b-318a032af38c/image.png" alt=""></p>
<p>물론 인생이야 어떻게 흘러갈지 아무도 모르는거죠.</p>
<h1 id="재직자-부트캠프-추천하시나요">재직자 부트캠프, 추천하시나요?</h1>
<hr>
<p>우선 두 가지 유형의 분들에게 추천합니다.</p>
<ol>
<li>IT직종의 비개발자(PM, 디자이너)</li>
<li>AI에 관심은 있지만 어디서부터 시작할지 모르겠는 개발자</li>
</ol>
<p>물론 이 외에도 배우고 싶다는 분들은 당연히 들으셔야죠.</p>
<p>비개발자분들은 많이 힘들어하십니다. 개발에 대한 기본 베이스가 많이 부족하시거든요. </p>
<p>하지만 IT직종의 비개발자분들은 소통을 해오며 완전 기본적인 이야기라도 자주 접하시는 분들이기 때문에 가장 많은 것을 배울 수 있는 분들이지 않을까 싶습니다.</p>
<p>물론 10주는 턱없이 부족한 시간이기에(월화수목 3시간씩 + 토 8시간) 혼자 공부할 시간이 많이 필요할 것 같습니다.</p>
<p>하물며 본업이 있으신 재직자분들은 교육기간에도 야근이 잡히면 따라잡기가 많은 힘이 들긴 합니다.</p>
<p>하지만 이를 견뎌내면 저의 경우에는 “이거 해보고싶다”와 같은 아이디어? 욕구? 같은 것들이 조금 생겼습니다.</p>
<h1 id="이제-뭘-하실건가요">이제 뭘 하실건가요?</h1>
<hr>
<p>제 특기가 일 벌여놓고 수습하기라서, 뭔가 혼자를 뚝딱거리며 만들어볼 것 같습니다.</p>
<p>이론만 주구장창 쳐다보면 재미없거든요. 뭐라도 결과물이 보여야 흥미가 생기는 법이거든요.</p>
<p>이렇게 혼자 뚝딱거리다 어디서든 써먹을 수 있지 않을까 싶을 때 사이드 프로젝트도 해보고, 더 나아가 원한다면 AI 엔지니어로 직무 변환도 할 수 있지 않을까 싶기도 합니다.</p>
<p>약 3달 가까이 퇴근 후의 시간을 반납한 사람의 부트캠프 회고였습니다.</p>
<p><em>조언과 피드백, 좋은 인사이트 공유는 언제나 환영입니다 :)</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[과유불급(過猶不及)과 기술 의사결정: Redis Streams 적용기]]></title>
            <link>https://velog.io/@playername_ltt/%EA%B3%BC%EC%9C%A0%EB%B6%88%EA%B8%89%E9%81%8E%E7%8C%B6%E4%B8%8D%E5%8F%8A%EA%B3%BC-%EA%B8%B0%EC%88%A0-%EC%9D%98%EC%82%AC%EA%B2%B0%EC%A0%95-Redis-Streams-%EC%A0%81%EC%9A%A9%EA%B8%B0</link>
            <guid>https://velog.io/@playername_ltt/%EA%B3%BC%EC%9C%A0%EB%B6%88%EA%B8%89%E9%81%8E%E7%8C%B6%E4%B8%8D%E5%8F%8A%EA%B3%BC-%EA%B8%B0%EC%88%A0-%EC%9D%98%EC%82%AC%EA%B2%B0%EC%A0%95-Redis-Streams-%EC%A0%81%EC%9A%A9%EA%B8%B0</guid>
            <pubDate>Thu, 29 Jan 2026 00:29:55 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/70d2361f-750b-4ad6-8bee-e0b9df7412b2/image.png" alt=""></p>
<h1 id="redis의-두-가지-용도">Redis의 두 가지 용도</h1>
<hr>
<h2 id="1-redis-cachepubsub">1. Redis Cache(Pub/sub)</h2>
<hr>
<p><strong>Redis Pub/Sub</strong>은 메시지를 보내는 <strong>발행자(Publisher)</strong>와 메시지를 받는 <strong>구독자(Subscriber)</strong>가 서로를 알 필요 없이 <strong>채널(Channel)</strong>을 통해 통신하는 구조입니다.</p>
<p>Redis Pub/Sub이 다른 메시징 시스템(Kafka, Redis Streams 등)과 가장 차별화되는 특징은 <strong>&#39;데이터의 비영속성*</strong>과 <strong>&#39;실시간성&#39;</strong>입니다.</p>
<p>자세한 내용은 <a href="https://lucas-owner.tistory.com/60">Redis Pub/Sub</a> 을 참고하세요. 오늘의 핵심 주제는 <strong>Redis Streams</strong>입니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/1754d441-c307-4b7d-bb11-29c3416b52be/image.png" alt=""></p>
<h2 id="2-redis-streams">2. Redis Streams</h2>
<hr>
<p><strong>Redis streams</strong>는 <strong>Append-only Log(추가 전용 로그)</strong> 형태의 ‘자료구조’로, 시간 순서대로 이벤트나 메시지를 저장하고 관리하는 데 특화되어 있습니다.</p>
<p>자세한 설명은 <a href="https://splendidlolli.tistory.com/762">Redis streams</a> 을 참고하면 될 것 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/cc04ec11-3574-475a-bbee-efb6227c5793/image.png" alt=""></p>
<h1 id="그래서-redis-streams를-왜-알아봤는데">그래서 Redis streams를 왜 알아봤는데</h1>
<hr>
<p>제가 담당한 기능의 요구사항은 다음과 같았습니다. 상세하게 다 적기에는 부담스러우니 대략적으로만 정리해보겠습니다.</p>
<ol>
<li>대화 종료 시, 약 1시간분량의 대화내역을 파일로 다운로드받아볼 수 있어야 함</li>
<li>실시간으로 대화내역도 모니터링 할 수 있어야 함</li>
</ol>
<p>기존에 Redis pub/sub을 이용하여 간단한 메세지 전달만 수행하고 있던 저에게 난관이 봉착했습니다.</p>
<p>기존에 유명한 해결책은 바로 ‘<strong>Kafka</strong>’. 바로 도입해봐야겠다 싶었는데, 혹시나 하는 마음에 요구사항을 프롬프트로 풀어 GPT에게 입력한 결과. 그는 ‘Redis streams’라는 키워드를 뱉었습니다.</p>
<h1 id="kafka-vs-redis-streams">Kafka vs Redis streams</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/65e24c98-2e8d-48cd-8211-6b2bf6d41f2b/image.png" alt=""></p>
<p>이 둘을 비교하며 고민해봅시다.</p>
<h2 id="1-아키텍처-및-데이터-저장-방식-architecture--data-storage"><strong>1. 아키텍처 및 데이터 저장 방식 (Architecture &amp; Data Storage)</strong></h2>
<hr>
<ul>
<li><strong>Apache Kafka</strong>:<ul>
<li><strong>디스크 기반 (Disk-based)</strong>: 데이터를 디스크에 저장하며 메모리 캐싱을 활용합니다. 이로 인해 대용량 데이터의 장기 보관(수일~수년)에 적합합니다.</li>
<li><strong>분산 로그 구조</strong>: 분산 커밋 로그(Commit Log)로 작동하며, 브로커(Broker), 토픽(Topic), 파티션(Partition)으로 구성된 분산 아키텍처를 가집니다.</li>
</ul>
</li>
<li><strong>Redis Streams</strong>:<ul>
<li><strong>인메모리 기반 (In-memory)</strong>: 데이터를 주 메모리(RAM)에 저장합니다. 이로 인해 속도가 매우 빠르지만, 메모리 용량에 의해 데이터 저장량이 제한됩니다.</li>
<li><strong>자료구조</strong>: Redis의 Append-only 로그 데이터 구조(Radix Tree 기반)로, Redis 서버의 단일 스레드 이벤트 루프 내에서 동작합니다. 데이터 영속성(AOF/RDB)은 선택 사항입니다.</li>
</ul>
</li>
</ul>
<p>말이 어렵습니다. </p>
<p>쉽게 정리하면, 양이 많고 오래 보관해야 하면 Kafka</p>
<p>양이 적고, 단시간 보관해야 하면 Redis streams 가 적합해 보였습니다.</p>
<h2 id="2-성능-특성-performance-characteristics"><strong>2. 성능 특성 (Performance Characteristics)</strong></h2>
<hr>
<p>성능 측면에서는 <strong>처리량(Throughput)</strong>과 <strong>지연 시간(Latency)</strong> 사이의 트레이드오프가 존재합니다.</p>
<table>
<thead>
<tr>
<th>특성</th>
<th>Redis Streams</th>
<th>Apache Kafka</th>
</tr>
</thead>
<tbody><tr>
<td><strong>지연 시간 (Latency)</strong></td>
<td><strong>1ms 미만 (Sub-millisecond)</strong>. 메모리에서 직접 처리하므로 즉각적인 응답이 가능</td>
<td><strong>밀리초 단위 (Low, but higher than Redis)</strong>. 디스크 I/O 및 복제 과정 등으로 인해 Redis보다는 높음</td>
</tr>
<tr>
<td><strong>처리량 (Throughput)</strong></td>
<td><strong>높음</strong>. 하지만 메모리와 단일 스레드 구조의 한계가 있음</td>
<td><strong>매우 높음</strong>. 대규모 데이터 스트리밍 처리에 최적화되어 있으며, 초당 수백만 건의 이벤트를 처리할 수 있음</td>
</tr>
</tbody></table>
<p>요약하자면,</p>
<ul>
<li>지연시간: Redis streams &gt; Kafka</li>
<li>처리량: Redis streams &lt; Kafka</li>
</ul>
<p>입니다.</p>
<h2 id="3-메시지-소비-및-처리-모델-consumption-model"><strong>3. 메시지 소비 및 처리 모델 (Consumption Model)</strong></h2>
<hr>
<p>두 시스템 모두 <strong>컨슈머 그룹(Consumer Group)</strong> 개념을 지원하지만, 작동 방식에는 차이가 있습니다.</p>
<ul>
<li><strong>Kafka</strong>:<ul>
<li><strong>Pull 방식</strong>: 컨슈머가 브로커로부터 데이터를 가져옵니다(Poll). 이를 통해 컨슈머가 처리 속도를 제어할 수 있습니다.</li>
<li><strong>파티션 기반 분산</strong>: 컨슈머 그룹 내의 각 컨슈머는 특정 <strong>파티션</strong>에 할당됩니다. 파티션 내에서의 순서는 보장되지만, 파티션이 나뉘면 전체 순서는 보장되지 않을 수 있습니다.</li>
</ul>
</li>
<li><strong>Redis Streams</strong>:<ul>
<li><strong>Push 방식 (대기 가능)</strong>: 클라이언트가 차단(Blocking) 모드로 대기하면 새 메시지가 도착하는 즉시 전달받습니다.</li>
<li><strong>로드 밸런싱 방식</strong>: Redis의 컨슈머 그룹은 파티션 개념 없이 하나의 스트림 키에서 메시지를 여러 컨슈머에게 <strong>로드 밸런싱</strong>하여 분배합니다. 따라서 특정 컨슈머가 더 빠르면 더 많은 메시지를 가져갈 수 있으며, 이 경우 그룹 전체의 처리 순서가 섞일 수 있습니다.</li>
</ul>
</li>
</ul>
<p>핵심은 순서 보장 관련이었습니다. 이것 같은 경우는 요구사항에 따라 중요한 것이 달라질 수 있을 것 같습니다.</p>
<h2 id="4-확장성-및-데이터-보존-scalability--retention"><strong>4. 확장성 및 데이터 보존 (Scalability &amp; Retention)</strong></h2>
<hr>
<ul>
<li><strong>Kafka</strong>:<ul>
<li><strong>수평적 확장</strong>: 파티션을 여러 브로커에 분산시켜 처리량과 저장 용량을 무제한에 가깝게 확장할 수 있습니다.</li>
<li><strong>데이터 보존</strong>: 디스크 기반이므로 설정에 따라 데이터를 영구적으로 보존하거나 매우 긴 기간(수년) 동안 저장할 수 있습니다.</li>
</ul>
</li>
<li><strong>Redis Streams</strong>:<ul>
<li><strong>수직적 확장 중심</strong>: 단일 노드의 메모리 크기에 제한을 받습니다. 수평 확장을 위해서는 클러스터링이나 샤딩을 직접 구현해야 하는 복잡함이 있을 수 있습니다.</li>
<li><strong>데이터 보존</strong>: 메모리 효율을 위해 주로 짧은 기간(수시간~수일)의 데이터를 보관하며, <code>MAXLEN</code> 등을 사용해 오래된 데이터를 정리하는 것이 일반적입니다</li>
</ul>
</li>
</ul>
<p>솔직히 둘다 직접 만져보지 않는 한 모르겠습니다. 우선 이렇구나 라고 넘어가겠습니다.</p>
<h1 id="아-그래서-redis-streams를-선택했구나">아 그래서 Redis streams를 선택했구나</h1>
<hr>
<p>맞습니다. 위의 요구사항에서 살펴보았다시피,</p>
<ol>
<li>데이터를 오래 보관할 필요 없고</li>
<li>바로바로 데이터 소모 후 채널을 초기화 할 예정이기에 대용량 아키텍처 또한 필요 없습니다</li>
</ol>
<p>기존에 Redis Pub/Sub을 사용하고 있었기에 기술학습비용이 적기도 하고, 인프라 비용 측면에서도 고려해 보았을 때, Redis Streams이 적합하다고 판단했습니다.</p>
<p>‘과유불급’, 멋있는말로는 ‘오버테크놀로지’를 피하는 것 또한 역량 중 하나이니까요.</p>
<h1 id="redis-streams만-사용하면-끝나는-거네-이제">Redis streams만 사용하면 끝나는 거네 이제?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/d9a28db1-12cc-4cd4-b7dd-2b71998b2317/image.png" alt=""></p>
<p>아쉽게도 아니었습니다. TTS 음성데이터도 처리를 했어야 하기 때문입니다.</p>
<blockquote>
<p>TTS데이터도 Redis streams로 관리하면 안되는거야?</p>
</blockquote>
<p>네. 안됩니다. 저장할 필요가 없는 데이터이기 때문입니다.</p>
<blockquote>
</blockquote>
<p>이유는 다음과 같습니다.</p>
<h2 id="기본적으로-redis-streams는-자료구조">기본적으로 Redis streams는 ‘자료구조’</h2>
<hr>
<p>Redis streams는 자료구조입니다. Redis streams로 Produce한 데이터는 내부에 쌓이게 됩니다.</p>
<p>이는 수동으로 비우지 않으면 계속해서 쌓이기 때문에 메모리의 성능이 저하됩니다. (메모리가 빨리 차기 때문)</p>
<p>특정 개수를 지정해놓고 관리하는 방법도 있다(GPT피셜)고는 하지만 그다지 효율적이라고 생각되지 않았습니다.</p>
<p>결국 장기적으로는 잠재 결함(latent defect)과 비결정적 장애 요인을 누적시켜 시스템의 안정성과 예측 가능성을 구조적으로 저하시킬 위험이 있기 때문이죠.</p>
<p>말이 어려웠습니다. 결론은 “예상치 못한 문제가 발생할 수 있기 때문”입니다.</p>
<h1 id="문제를-해결하기-위한-해결책">문제를 해결하기 위한 해결책</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/33455a0b-3749-4c81-b844-0ba028ce1a99/image.png" alt=""></p>
<p>답은 의외로 간단했습니다.</p>
<p>Redis streams와 Redis Pub/Sub을 동시에 사용하면 되는 것입니다.</p>
<ul>
<li>저장해야 하는 텍스트 데이터 → Redis streams</li>
<li>휘발되어야 하는 binary 데이터 → Redis Pub/Sub</li>
</ul>
<p>하나의 Redis 서버는 각각 streams나 cache 방식으로 단일 목적으로 사용하는 것이 가장 안정성이 좋다고 하여(GPT피셜) 서버를 각각 다르게 설정하고 띄웠습니다.</p>
<h2 id="springboot-설정">Springboot 설정</h2>
<hr>
<p>구글링해보니 하나를 <code>@Primary</code>설정을 하여 하나를 우선으로 쓰는 다중 Redis 설정법이 대부분이길래, 제 상황과 맞는 솔루션이 아니기에, GPT에게 물어가며 진행했습니다.</p>
<h3 id="yml">.yml</h3>
<pre><code class="language-yaml">spring:
  redis:
    cache:
      host: {redis_cache_server_url} # pub/sub
      port: {redis_cache_port}
      password: {redis_cache_password}
    stream:
      host: {redis_streams_server_url} # streams
      port: {redis_streams_port}
      password: {redis_streams_password}</code></pre>
<p>각 Properties는 </p>
<p><code>@ConfigurationProperties(prefix = &quot;spring.redis.stream&quot;)</code> 
<code>@ConfigurationProperties(prefix = &quot;spring.redis.cache&quot;)</code>로 별도의 property 객체를 만들어줬습니다.</p>
<h3 id="multiredisconfig">MultiRedisConfig</h3>
<pre><code class="language-java">@Configuration
@EnableConfigurationProperties({
        RedisCacheProperties.class,
        RedisStreamProperties.class
})
public class MultiRedisConfig {

    @Primary // 기본 연결 공장으로 지정
    @Bean(&quot;redisCacheConnectionFactory&quot;)
    public RedisConnectionFactory redisCacheConnectionFactory(RedisCacheProperties props) {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(props.getHost(), props.getPort());
        config.setPassword(props.getPassword());

        return new LettuceConnectionFactory(config);
    }

    @Bean(&quot;redisStreamConnectionFactory&quot;)
    public RedisConnectionFactory redisStreamConnectionFactory(RedisStreamProperties props) {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(props.getHost(), props.getPort());
        config.setPassword(props.getPassword());

        return new LettuceConnectionFactory(config);
    }

    @Bean(&quot;redisCacheTemplate&quot;)
    public StringRedisTemplate redisCacheTemplate(
            @Qualifier(&quot;redisCacheConnectionFactory&quot;) RedisConnectionFactory factory) {
        return new StringRedisTemplate(factory);
    }

    @Bean(&quot;redisStreamTemplate&quot;)
    public StringRedisTemplate redisStreamTemplate(
            @Qualifier(&quot;redisStreamConnectionFactory&quot;) RedisConnectionFactory factory) {
        return new StringRedisTemplate(factory);
    }
}</code></pre>
<h3 id="streamsconfig">StreamsConfig</h3>
<pre><code class="language-java">@Slf4j
@Configuration
public class StreamConfig {

    @Bean
    public StreamMessageListenerContainer&lt;String, MapRecord&lt;String, String, String&gt;&gt;
    streamListenerContainer(
            @Qualifier(&quot;redisStreamConnectionFactory&quot;)
            RedisConnectionFactory factory
    ) {
        StreamMessageListenerContainer.StreamMessageListenerContainerOptions&lt;String, MapRecord&lt;String, String, String&gt;&gt;
                options = StreamMessageListenerContainer.StreamMessageListenerContainerOptions.builder()
                .pollTimeout(Duration.ofSeconds(1))
                .build();

        StreamMessageListenerContainer&lt;String, MapRecord&lt;String, String, String&gt;&gt; container =
                StreamMessageListenerContainer.create(factory, options);

        // Consumers are now managed dynamically by ConferenceStreamManager.
        // We only start the container here.
        container.start();
        return container;
    }
}</code></pre>
<p>저는 Consumer Group을 동적으로 할당하기 위해 위와 같이 설정해두었습니다.</p>
<h3 id="cacheconfig">CacheConfig</h3>
<pre><code class="language-java">@Configuration
public class CacheConfig {

    @Bean
    public RedisMessageListenerContainer pubSubContainer(
            @Qualifier(&quot;redisCacheConnectionFactory&quot;)
            RedisConnectionFactory factory,
            MessageListenerAdapter subscriber
    ) {
        RedisMessageListenerContainer container =
                new RedisMessageListenerContainer();
        container.setConnectionFactory(factory);
        container.addMessageListener(subscriber, new PatternTopic(&quot;conference:*&quot;));
        return container;
    }

    @Bean
    public MessageListenerAdapter subscriber(CacheSubscriber subscriber) {
        return new MessageListenerAdapter(subscriber, &quot;onMessage&quot;);
    }
}</code></pre>
<p>이후 Streams의 <code>Producer</code>와 <code>Consumer</code>, Pub/Sub의 <code>Publisher</code>와 <code>Subscriber</code>로직은 각자에 맞는 방식으로 구현하면 됩니다.</p>
<p>물론 설정도 각자에 맞게 하는 것이지만요.</p>
<h1 id="결론">결론</h1>
<hr>
<p>Kafka의 명성에 가려져 주목받지 못하는 Redis streams를 상황에 맞게 적절히 선택하여 사용해보기에 충분히 매력적인 기술이라고 생각합니다.</p>
<p><a href="%5Bhttps://velog.io/@playername_ltt/1%EB%85%84%EC%B0%A8-%EC%A3%BC%EB%8B%88%EC%96%B4%EA%B0%80-%EC%8B%A4%EC%A0%9C-%EC%82%AC%EB%A1%80%EB%A1%9C-%EB%B3%B4%EC%97%AC%EC%A3%BC%EB%8A%94-%EA%B8%B0%EC%88%A0%EC%A0%81-%EC%9D%98%EC%82%AC%EA%B2%B0%EC%A0%95-%EA%B3%BC%EC%A0%95%5D(https://velog.io/@playername_ltt/1%EB%85%84%EC%B0%A8-%EC%A3%BC%EB%8B%88%EC%96%B4%EA%B0%80-%EC%8B%A4%EC%A0%9C-%EC%82%AC%EB%A1%80%EB%A1%9C-%EB%B3%B4%EC%97%AC%EC%A3%BC%EB%8A%94-%EA%B8%B0%EC%88%A0%EC%A0%81-%EC%9D%98%EC%82%AC%EA%B2%B0%EC%A0%95-%EA%B3%BC%EC%A0%95)">1년차 주니어가 실제 사례로 보여주는 기술적 의사결정 과정</a>에서 설명했다시피, 모든 기술 결정에는 근거가 필요하다고 생각합니다.</p>
<p>모든 기술 좋고 유행한다고 쓰는 것이 아니라 필요 여부에 따라 명확하게 나누어 오버테크놀로지를 경계하고 적합한 기술을 채택하는 것이 중요한 역량 중 하나라고 생각합니다.</p>
<p><em>피드백은 언제나 환영입니다 :)</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[당신의 AI는 이제 금붕어가 아니다(feat. RLM)]]></title>
            <link>https://velog.io/@playername_ltt/%EB%8B%B9%EC%8B%A0%EC%9D%98-AI%EB%8A%94-%EC%9D%B4%EC%A0%9C-%EA%B8%88%EB%B6%95%EC%96%B4%EA%B0%80-%EC%95%84%EB%8B%88%EB%8B%A4feat.-RLM</link>
            <guid>https://velog.io/@playername_ltt/%EB%8B%B9%EC%8B%A0%EC%9D%98-AI%EB%8A%94-%EC%9D%B4%EC%A0%9C-%EA%B8%88%EB%B6%95%EC%96%B4%EA%B0%80-%EC%95%84%EB%8B%88%EB%8B%A4feat.-RLM</guid>
            <pubDate>Tue, 06 Jan 2026 15:40:17 GMT</pubDate>
            <description><![CDATA[<p>이 글은 LLM 추론의 새로운 지평, “Recursive Language Model(RLM)”에 관한 글입니다.</p>
<h1 id="1-서론-llm-추론은-어디에서-한계에-부딪히는가">1. 서론: LLM 추론은 어디에서 한계에 부딪히는가</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/50712714-acfb-4bcd-aab5-5bbefd0b3984/image.png" alt=""></p>
<h2 id="11-우리가-이미-잘-아는-llm-추론-패턴">1.1 우리가 이미 잘 아는 LLM 추론 패턴</h2>
<hr>
<p>지금까지 우리는 LLM의 성능을 극대화하기 위해 몇 가지 주요 패턴을 사용해 왔습니다.</p>
<ul>
<li><strong>CoT(Chain-of-Thought):</strong> &quot;단계별로 생각해보자&quot;는 프롬프트를 통해 선형적인 사고 과정을 유도합니다.</li>
<li><strong>Self-Refinement:</strong> 생성된 결과물을 모델이 다시 검토하고 수정하게 합니다.</li>
<li><strong>Agent Loop:</strong> LLM이 외부 도구(Search, SQL 등)를 사용하고 그 결과를 받아 다음 행동을 결정하는 루프를 돕습니다.</li>
</ul>
<p>이 방식들은 훌륭하지만 공통점이 있습니다. </p>
<p>바로 <strong>구조적으로 외부에서 제어되는 반복(Externally controlled loops)</strong>이라는 점입니다. </p>
<p>즉, 모델 자체가 재귀적인 사고 구조를 가진 것이 아니라, 우리가 프롬프트나 파이프라인으로 그렇게 시키고 있는 것입니다.</p>
<h2 id="12-기존-방식의-공통적인-구조적-한계">1.2 기존 방식의 공통적인 구조적 한계</h2>
<hr>
<p>이러한 외부 제어 방식은 다음과 같은 태생적 한계를 가집니다.</p>
<ul>
<li><strong>컨텍스트 윈도우 의존성:</strong> 사고 과정이 길어질수록 이전의 모든 단계를 컨텍스트에 담아야 하므로 효율성이 급격히 떨어집니다.</li>
<li><strong>상태 일관성 문제:</strong> 반복 호출 사이에서 이전의 상태(State)를 관리하기 위해 외부 데이터베이스나 복잡한 상태 머신이 필요합니다.</li>
<li><strong>고정된 추론 깊이:</strong> 개발자가 사전에 설계한 워크플로우 이상의 깊이 있는 추론을 수행하기 어렵습니다.</li>
</ul>
<h2 id="13-rlm이라는-문제의식의-등장">1.3 RLM이라는 문제의식의 등장</h2>
<hr>
<p>&quot;왜 추론의 흐름을 밖에서 관리해야 하는가? 모델이 스스로 문제를 정의하고, 필요하다면 자기 자신을 다시 호출하며 문제를 해결할 수는 없을까?&quot;</p>
<p>RLM은 단순한 성능 향상을 위한 기법이 아닙니다. 추론의 <strong>오케스트레이션(Orchestration) 주체를 모델 내부로 옮기려는 시도</strong>에서 출발한 개념입니다.</p>
<h1 id="2-rlm이란-무엇인가-정의와-핵심-아이디어">2. RLM이란 무엇인가: 정의와 핵심 아이디어</h1>
<hr>
<h2 id="21-recursive-language-model의-개념과-등장-배경">2.1 Recursive Language Model의 개념과 등장 배경</h2>
<hr>
<h3 id="211-rlm의-등장-배경-왜-더-큰-컨텍스트만으로는-부족한가">2.1.1 RLM의 등장 배경: 왜 &#39;더 큰 컨텍스트&#39;만으로는 부족한가?</h3>
<p>지금까지 LLM 업계의 지표는 &quot;얼마나 더 많은 텍스트를 한 번에 집어넣을 수 있는가(Context Window Scaling)&quot;에 집중되어 왔습니다. 하지만 컨텍스트가 1M, 10M로 커짐에 따라 새로운 문제들이 수면 위로 떠올랐습니다. </p>
<p>이를 <strong>MIT</strong>와 <strong>Prime Intellect</strong>에서 제안한 Python REPL 환경에서 LLM이 스스로 컨텍스트를 재귀적으로 탐색하고 조합하는 새로운 방법론, Recursive Language Models (RLM)을 공개했습니다.</p>
<ol>
<li><strong>정보 밀도의 한계 (Lost in the Middle):</strong> 컨텍스트가 길어질수록 모델은 중간에 위치한 중요한 정보를 놓치는 경향이 있습니다. 단순히 &#39;읽을 수 있다&#39;는 것과 &#39;완벽히 이해하고 추론한다&#39;는 것 사이의 간극이 발생한 것입니다.</li>
<li><strong>비용과 자원의 비효율성:</strong> 10M 토큰에 달하는 방대한 데이터를 매번 전체 컨텍스트에 넣고 추론하는 것은 엄청난 컴퓨팅 비용과 지연 시간(Latency)을 초래합니다.</li>
<li><strong>비선형적 문제 해결의 필요성:</strong> 현실 세계의 복잡한 문제는 &#39;A 다음 B&#39; 식의 선형 구조가 아닙니다. 큰 문제 안에 작은 문제가 있고, 그 안에 또 다른 변수가 얽혀 있는 <strong>계층적(Hierarchical) 구조</strong>입니다.</li>
</ol>
<p>이러한 한계를 돌파하기 위해 <strong>&quot;컨텍스트를 무작정 늘리는 대신, 문제를 계층적으로 쪼개어 효율적으로 처리하자&quot;</strong>는 패러다임의 전환이 일어났고, 그 결과물이 바로 RLM입니다.</p>
<h3 id="212-rlm의-개념적-정의">2.1.2 RLM의 개념적 정의</h3>
<p>RLM은 <strong>&quot;자기 자신을 재귀적으로 호출하여 복잡한 문제를 더 작은 하위 문제로 분해하고 해결하는 추론 실행 모델&quot;</strong>입니다. 단순히 문맥을 길게 유지하는 것이 아니라, 필요할 때마다 새로운 추론 스택을 쌓아 올림으로써 <strong>기존 LLM(약 200K대 토큰) 대비 50~100배에 달하는 10M+ 토큰 급의 정보 처리 능력</strong>을 효율적으로 구현합니다.</p>
<h2 id="22-rlm을-구성하는-3가지-핵심-요소">2.2 RLM을 구성하는 3가지 핵심 요소</h2>
<hr>
<ol>
<li><strong>자기 호출(Self-Invocation):</strong> 모델이 문제를 해결하다가 너무 복잡하다고 판단되면, 하위 문제를 정의하고 자기 자신을 다시 호출합니다.</li>
<li><strong>자기 상태 갱신(Self-State Update):</strong> 하위 문제의 결과를 받아 원래의 문제 상태를 업데이트합니다.</li>
<li><strong>재귀적 추론(Recursive Reasoning):</strong> 위 과정이 종료 조건(Base case)을 만날 때까지 반복됩니다.</li>
</ol>
<blockquote>
<p>Key Insight: RLM은 &quot;생각을 길게 이어가는 것&quot;이 아니라, <strong>&quot;문제를 더 단순한 단위로 쪼개어 나에게 다시 맡기는 것&quot;</strong>입니다.</p>
</blockquote>
<h1 id="3-기존-llm-추론-방식과의-구조적-비교">3. 기존 LLM 추론 방식과의 구조적 비교</h1>
<hr>
<table>
<thead>
<tr>
<th><strong>구분</strong></th>
<th><strong>Chain-of-Thought (CoT)</strong></th>
<th><strong>Agent Loop (External)</strong></th>
<th><strong>Recursive LM (RLM)</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>추론 구조</strong></td>
<td>선형적 (Linear)</td>
<td>반복적 (Iterative)</td>
<td><strong>재귀적 (Nested/Recursive)</strong></td>
</tr>
<tr>
<td><strong>상태 관리</strong></td>
<td>단일 컨텍스트 내 유지</td>
<td>외부 Orchestrator가 관리</td>
<td><strong>모델 내부의 스택 구조 활용</strong></td>
</tr>
<tr>
<td><strong>복잡도 대응</strong></td>
<td>사고가 길어질수록 혼동 증가</td>
<td>외부 로직에 의존</td>
<td><strong>문제를 작게 쪼개어 단순화</strong></td>
</tr>
<tr>
<td><strong>제어 주체</strong></td>
<td>프롬프트</td>
<td>코드/워크플로우 엔진</td>
<td><strong>모델 내부의 &#39;RECURSE&#39; 행동</strong></td>
</tr>
</tbody></table>
<h1 id="4-rlm의-실제-추론-흐름">4. RLM의 실제 추론 흐름</h1>
<hr>
<h2 id="41-단계적-추론-흐름-예시">4.1 단계적 추론 흐름 예시</h2>
<hr>
<ol>
<li><strong>입력:</strong> &quot;2024년 노벨 물리학상 수상자의 연구가 현대 반도체 산업에 미친 영향은?&quot;</li>
<li><strong>분해:</strong> 모델이 문제를 보고 <code>RECURSE</code> 결정.<ul>
<li>하위 문제 1: &quot;2024년 노벨 물리학상 수상자와 그들의 핵심 연구는 무엇인가?&quot;</li>
<li>하위 문제 2: &quot;해당 연구가 반도체 기술과 어떻게 연결되는가?&quot;</li>
</ul>
</li>
<li><strong>재귀 호출:</strong> 하위 문제 1을 해결하기 위해 모델이 자신을 다시 호출.</li>
<li><strong>결과 합성:</strong> 하위 문제들의 답을 모아 최종 답변 생성.</li>
</ol>
<h2 id="42-rlm-추론의-의사코드pseudocode">4.2 RLM 추론의 의사코드(Pseudocode)</h2>
<hr>
<p>엔지니어의 관점에서 RLM의 로직은 다음과 같이 표현될 수 있습니다.</p>
<pre><code class="language-python">def RLM(problem_state):
    # 1. 종료 조건 평가 (Base Case)
    if is_simple_enough(problem_state):
        return solve_directly(problem_state)

    # 2. 문제 분해 (Decomposition)
    sub_problems = decompose(problem_state)

    # 3. 재귀 호출 및 결과 수집 (Recursive Call)
    sub_results = []
    for sub in sub_problems:
        sub_results.append(RLM(sub))

    # 4. 상태 갱신 및 최종 답변 (State Update &amp; Synthesis)
    final_answer = synthesize(problem_state, sub_results)
    return final_answer</code></pre>
<h1 id="5-시스템-아키텍처-관점에서-본-rlm">5. 시스템 아키텍처 관점에서 본 RLM</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/87738cf0-0b7d-4b92-b88c-1b736eb3f27b/image.png" alt=""></p>
<p>기존의 LLM 에이전트 시스템은 <strong>Orchestrator</strong>가 모든 중심을 잡고 있었습니다. 하지만 RLM은 이 복잡성을 모델 내부로 밀어 넣습니다.</p>
<ul>
<li><strong>기존 아키텍처:</strong> <code>Python/LangGraph/CrewAI</code> 등이 루프와 조건문을 관리.</li>
<li><strong>RLM 기반 아키텍처:</strong> 인프라 레이어는 단순히 모델의 <code>RECURSE</code> 신호를 처리하고 새로운 컨텍스트 스택을 생성해 주는 <strong>실행 환경(Runtime)</strong> 역할만 수행.</li>
</ul>
<p>이로 인해 외부 워크플로우 엔진의 의존도는 낮아지지만, 모델이 재귀를 멈추지 않거나 잘못된 방향으로 문제를 쪼갤 경우 디버깅이 매우 어려워지는 트레이드오프가 발생합니다.</p>
<h1 id="6-rlm의-주요-성과와-냉정한-평가">6. RLM의 주요 성과와 냉정한 평가</h1>
<hr>
<p>RLM은 단순한 이론적 제안을 넘어, 실제 벤치마크와 대규모 데이터 처리에서 압도적인 수치를 증명하고 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/8c7757ab-768c-466e-a440-93f765f97d20/image.png" alt=""></p>
<h2 id="61-핵심-성과-하이라이트">6.1 핵심 성과 하이라이트</h2>
<hr>
<ul>
<li>✅ <strong>10M+ 토큰 처리:</strong> 기존 LLM이 가진 컨텍스트 한계를 <strong>50~100배</strong> 뛰어넘는 방대한 데이터를 처리할 수 있습니다.</li>
<li>✅ <strong>압도적인 성능 우위:</strong> 단순한 직접 LLM 호출(Direct Call) 대비 정답률과 논리적 완결성에서 큰 차이를 보입니다.</li>
<li>✅ <strong>검증된 강건성(Robustness):</strong> 다양한 장문 컨텍스트 태스크(Long-context tasks)에서 일관되게 안정적인 성능을 입증했습니다.</li>
<li>✅ <strong>탁월한 효율성:</strong> RAG나 단순 Context Scaling 등 다른 방법론과 비교했을 때, 추론의 정확도와 자원 활용 면에서 우수한 성능을 보여줍니다.</li>
</ul>
<h2 id="62-장점-왜-rlm인가">6.2 장점: 왜 RLM인가</h2>
<hr>
<ul>
<li><strong>동적 추론 깊이:</strong> 문제의 난이도에 따라 모델이 스스로 얼마나 깊게 파고들지 결정합니다.</li>
<li><strong>컨텍스트 효율성:</strong> 전체 추론 과정을 하나에 담지 않고, 하위 문제별로 독립된 컨텍스트를 가질 수 있어 &quot;압축된 정보&quot;만 상위로 전달합니다.</li>
</ul>
<h2 id="63-단점-한계와-비용-문제">6.3 단점: 한계와 비용 문제</h2>
<hr>
<ul>
<li><strong>비용 폭증:</strong> 재귀 호출은 기하급수적으로 호출 횟수를 늘릴 수 있습니다.</li>
<li><strong>무한 루프:</strong> 종료 조건을 제대로 인식하지 못하면 모델이 영원히 자기를 호출할 위험이 있습니다.</li>
<li><strong>학습의 어려움:</strong> <code>RECURSE</code> 토큰을 언제 쓰고 상태를 어떻게 요약할지 학습시키기 위해 고도의 SFT와 RL이 필요합니다.</li>
</ul>
<h1 id="7-기존-llm-시스템과의-연결과-확장-가능성">7. 기존 LLM 시스템과의 연결과 확장 가능성</h1>
<hr>
<p>RLM은 기존 시스템을 대체하기보다는 <strong>강력한 &#39;추론 코어&#39;</strong>로 작동할 것입니다.</p>
<ul>
<li><strong>RLM + Tool Calling:</strong> 재귀의 어느 단계에서 모델이 특정 도구를 호출하여 사실 관계를 확인하고 다시 재귀를 이어가는 방식.</li>
<li><strong>RLM + Agent:</strong> 에이전트의 &#39;Planning&#39; 단계를 RLM으로 구현하여 훨씬 정교한 계획 수립 가능.</li>
</ul>
<h1 id="8-결론-rlm은-만능-해법이-아니다">8. 결론: RLM은 만능 해법이 아니다</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/f4e65e00-5ac6-488b-ba58-ea1dd33a9332/image.png" alt=""></p>
<p>RLM은 &quot;다음 세대의 LLM 모델&quot;이라기보다, <strong>복잡한 추론 문제를 해결하기 위한 고도화된 설계 패턴이자 학습 방식</strong>입니다.</p>
<p>단순한 질의응답이나 요약 태스크에 RLM을 도입하는 것은 오버엔지니어링일 가능성이 큽니다. 하지만 수학 문제 풀이, 복잡한 코드 아키텍처 설계, 다단계 논리 추론이 필요한 영역에서는 기존 CoT의 한계를 돌파할 핵심 열쇠가 될 것입니다. </p>
<p>특히 최근 주목받는 <strong>MCP(Model Context Protocol)</strong>를 활용하는 AI Coding Agent들에게는 RLM이 가뭄의 단비 같은 해법이 될 수도 있을 것 같습니다. 이제 &#39;Ultra&#39; 모델을 넘어선 <strong>&#39;Super Ultra&#39;나 &#39;Reasoning Max&#39;</strong> 같은 이름으로 무장하고, 수천 줄의 코드를 재귀적으로 분석하는 괴물 같은 모델이 등장하려나요? (그때가 되면 우리는 프롬프트 대신 재귀 종료 조건(Base Case)을 잘 써달라고 기도해야 할지도 모르겠네요)</p>
<h1 id="9-reference">9. Reference</h1>
<hr>
<ul>
<li>[[[Hada.io] Recursive Language Model: LLM 추론의 새로운 패러다임] (<a href="https://news.hada.io/topic?id=25563)%5D(https://news.hada.io/topic?id=25563)">https://news.hada.io/topic?id=25563)](https://news.hada.io/topic?id=25563)</a></li>
<li><a href="https://www.aitimes.com/news/articleView.html?idxno=205307">[AI Times] 프라임 인텔렉트, &#39;재귀적 언어 모델(RLM)&#39; 발표</a></li>
<li><a href="https://www.primeintellect.ai/blog/rlm">[Prime Intellect Blog] RLM: Training Language Models to Solve Complex Tasks via Recursion</a></li>
<li><a href="https://arxiv.org/pdf/2512.24601">[Arxiv] Recursive Language Models (2512.24601)</a></li>
<li><a href="https://alexzhang13.github.io/blog/2025/rlm/">Alex L. Zhang Github Pages</a></li>
<li>그 외 기타 기술 블로그…</li>
</ul>
<p>제가 잘못 알고 있거나, 부족한 내용을 알려주시면 감사하겠습니다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2025 회고] 무너져도 덤덤하게 일어나기]]></title>
            <link>https://velog.io/@playername_ltt/2025-%ED%9A%8C%EA%B3%A0-%EB%AC%B4%EB%84%88%EC%A0%B8%EB%8F%84-%EB%8D%A4%EB%8D%A4%ED%95%98%EA%B2%8C-%EC%9D%BC%EC%96%B4%EB%82%98%EA%B8%B0</link>
            <guid>https://velog.io/@playername_ltt/2025-%ED%9A%8C%EA%B3%A0-%EB%AC%B4%EB%84%88%EC%A0%B8%EB%8F%84-%EB%8D%A4%EB%8D%A4%ED%95%98%EA%B2%8C-%EC%9D%BC%EC%96%B4%EB%82%98%EA%B8%B0</guid>
            <pubDate>Mon, 29 Dec 2025 00:17:12 GMT</pubDate>
            <description><![CDATA[<p>연말이라면 빼놓을 수 없는 주제가 있죠. </p>
<p>그건 바로 “회고”입니다.</p>
<p>2025년은 저에게 &#39;롤러코스터&#39; 같은 한 해였습니다. 불안함에 밤잠을 설치기도 했고, 번아웃의 문턱에서 모든 것을 내려놓기도 했지만, 결국 뭔가 진짜 소소한 것들이라도 이루어냈습니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/d0d25c98-4f9b-44c6-9de0-9b0582d430d7/image.png" alt=""></p>
<h1 id="🚀-인턴에서-정직원으로의-제대로-된-시작">🚀 인턴에서 정직원으로의 제대로 된 시작</h1>
<hr>
<p>올해의 시작은 &#39;인턴&#39;이었습니다. 1월과 2월, 실무를 배우는 기쁨도 컸지만 마음 한구석은 늘 불안했습니다.</p>
<ul>
<li><strong>멘탈의 위기:</strong> 제가 한 IPP 일학습병행은 기본적으로 ‘채용연계형 인턴십’이었기에 정규직 자리는 당연히 따고 있었다고 생각했는데, &quot;인턴 끝나면 뭐 할 예정이에요?&quot;라는 대표님의 질문은 저를 참 작아지게 만들었습니다. &#39;내가 부족해서 하시는 말씀인가?&#39; 하는 생각에 멘탈이 흔들리기도 했죠.</li>
<li><strong>전환의 순간:</strong> 하지만 묵묵히 제 몫을 해내려 노력했고, 다행히 3월에 <strong>정직원 전환</strong>이라는 값진 결과를 얻었습니다.</li>
</ul>
<h2 id="무엇을-개발했나">무엇을 개발했나?</h2>
<hr>
<ul>
<li><strong>사내 업무:</strong> 앱 서비스 운영용 관리자 웹 풀스택 개발 (<code>Spring Boot</code>, <code>Vue.js</code>)</li>
<li><strong>사이드 프로젝트:</strong> 중고 장비 대여 플랫폼 백엔드 개발 (<code>Spring Boot</code>)</li>
</ul>
<p>사내 업무에서는 비즈니스 개발의 전반적인 역량을 늘릴 수 있었고, 가장 값지게 얻은 것은 “비즈니스를 고려한 개발자의 설계 안목”이라고 생각합니다. 물론 아직은 부족하겠지만요.</p>
<p>사이드 프로젝트에서는 제가 깊이 있게 해보고 싶은 백엔드 분야에 집중했습니다. 물론 서비스를 제대로 운영할 환경까지는 갖춰지지 못했지만, 팀원들과도 소통해보며 재밌게 진행했었습니다 :)
<a href="%5Bhttps://velog.io/@playername_ltt/%ED%9A%8C%EA%B3%A0-IPP-%EC%9D%BC%ED%95%99%EC%8A%B5%EB%B3%91%ED%96%89%EC%9D%84-%EB%A7%88%EC%B9%98%EB%A9%B0%5D(https://velog.io/@playername_ltt/%ED%9A%8C%EA%B3%A0-IPP-%EC%9D%BC%ED%95%99%EC%8A%B5%EB%B3%91%ED%96%89%EC%9D%84-%EB%A7%88%EC%B9%98%EB%A9%B0)"><strong>[회고] IPP 일학습병행을 마치며…</strong></a></p>
<h2 id="정직원-되고-나서는-뭘-했는가">정직원 되고 나서는 뭘 했는가?</h2>
<hr>
<ul>
<li><strong>사내 업무:</strong> 실시간 통/번역 서비스 개발(<code>Springboot</code>, <code>FastAPI</code>, <code>Flutter</code>)</li>
<li><strong>퇴근 후:</strong> 코테 재활훈련(?) - 효과는 크게 없던 것 같습니다… 한번 플랜 제대로 세워서 해봐야겠습니다.</li>
</ul>
<p>개발자로서 차근차근 성장해나가기 시작했다고 생각합니다. 모르던 기술도 배우고, 이것저것 성장에 가속을 붙이기 시작했었죠.</p>
<h1 id="🍞-잠시-멈춤-토스트-아웃의-시기">🍞 잠시 멈춤, &quot;토스트 아웃&quot;의 시기</h1>
<hr>
<p>정직원이 된 후 앞만 보고 달려온 탓일까요? 6월쯤 개인적인 사유와 함께 소위 말하는 <strong>&#39;토스트 아웃(Toast-out)&#39;</strong>이 찾아왔습니다. 완전히 타버린 번아웃은 아니지만, 노릇하게 구워진 토스트처럼 더 이상 무언가를 채울 여력이 없는 상태였죠.</p>
<p>결국 공부를 잠시 쉬기로 결정했습니다. 처음에는 뒤처질까 봐 무서웠지만, 이 휴식 덕분에 다시 달릴 에너지를 얻을 수 있었던 것 같아요.</p>
<h1 id="📈-다시-시작된-기록">📈 다시 시작된 기록</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/20b49bf7-9aca-4d57-a411-d83311fd0afc/image.png" alt=""></p>
<p>9월 말, 다시 기지개를 켰습니다. 멈춰있던 블로그를 재활성화하고 생소했던 링크드인을 시작했습니다. 결과는 “뿌듯했다” 라고 정의하겠습니다.</p>
<ul>
<li><strong>블로그의 성장:</strong> 일 평균 “5회”였던 방문자 수가 ”<strong>50~60회”</strong>로 10배 이상 증가했습니다. 누군가 내 기록을 보고 도움을 얻는다는 사실이 큰 동기부여가 되었습니다.</li>
<li><strong>네트워크의 확장:</strong> 개발자 인맥이 전무했던 제가 링크드인 일촌을 <strong>6~7명에서 약150명</strong>까지 늘리며 세상과 연결되는 즐거움을 알게 되었습니다. 멋진 분들이 판치는 링크드인에 뻔뻔하게 얼굴에 철판깔고 제 생각을 공유하기 시작했죠.</li>
</ul>
<h2 id="나는-도대체-뭘-쓰고-공유하는가">나는 도대체 뭘 쓰고 공유하는가</h2>
<hr>
<p>개인적으로 제가 공유하는 이야기는 다음과 같습니다.</p>
<ul>
<li>최신 기술 트렌드 정리</li>
<li>기술적 이슈 트러블슈팅</li>
<li>간단한 회고</li>
</ul>
<p>제가 처음 대학교 시절 개발 배울때 트렌드였던 “교과서적으로”기술을 알려주는 블로그는 이미 트랜드가 지났다고 생각하기에, 흔한 내용은 최대한 덜 다루려고 합니다.</p>
<h1 id="🤖-새로운-도전-ai-서비스-엔지니어링">🤖 새로운 도전, AI 서비스 엔지니어링</h1>
<hr>
<p>현재에 안주하지 않기 위해 11월 말부터 <strong>&#39;AI 서비스 엔지니어링&#39; 재직자 부트캠프</strong>에 참여하고 있습니다. 단순한 웹 개발을 넘어 AI를 서비스에 어떻게 녹여낼지 고민하며 매일 새로운 자극을 받는 중입니다.</p>
<p>AI를 활용하여 서비스를 개발해내는 엔지니어로 성장하길 바라며 공부 중에 있습니다.</p>
<h2 id="2026년을-준비하며">2026년을 준비하며</h2>
<hr>
<p>지금은 제가 무엇을 더 잘 할 수 있을지, 어떤 가치를 만드는 개발자가 될지 고민하며 다음 계획들을 수립하고 있습니다.</p>
<p>몇 가지 개인적인 목표들이 있습니다.</p>
<ol>
<li>멈췄던 다이어트</li>
<li>개인으로 서비스 사이드 프로젝트 개발해서 수익 100원 이상 내보기</li>
<li>책 3권 이상 읽기</li>
<li>자격증 1개 이상 따기</li>
</ol>
<p>잘 해내보겠습니다 :)</p>
<h1 id="무너짐은-무능함이-아닌-성장의-과정">무너짐은 무능함이 아닌 성장의 과정</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/2ea9a55c-b1b6-44fc-a63b-3dfd9a5ae8ca/image.png" alt=""></p>
<blockquote>
<p>시작은 미약하였으나 그 끝은 창대하리라</p>
</blockquote>
<p>올해를 되돌아보니 참 많이 무너져보기도 했고, 일을 손에서 놓아버린 순간도 있었습니다. 하지만 지금은 압니다. <strong>그 모든 순간이 제가 더 높이 점프하기 위해 무릎을 굽혔던 과정이었다는 것을요.</strong></p>
<p>지금은 별 거 없어보이는 제가, 어디까지고 한 번 올라가보겠습니다.</p>
<p>2025년의 밑거름을 발판 삼아, 2026년에는 더 깊이 있고 단단한 개발자로 성장하겠습니다. 모두 고생 많으셨습니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1년차 주니어가 실제 사례로 보여주는 기술적 의사결정 과정]]></title>
            <link>https://velog.io/@playername_ltt/1%EB%85%84%EC%B0%A8-%EC%A3%BC%EB%8B%88%EC%96%B4%EA%B0%80-%EC%8B%A4%EC%A0%9C-%EC%82%AC%EB%A1%80%EB%A1%9C-%EB%B3%B4%EC%97%AC%EC%A3%BC%EB%8A%94-%EA%B8%B0%EC%88%A0%EC%A0%81-%EC%9D%98%EC%82%AC%EA%B2%B0%EC%A0%95-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@playername_ltt/1%EB%85%84%EC%B0%A8-%EC%A3%BC%EB%8B%88%EC%96%B4%EA%B0%80-%EC%8B%A4%EC%A0%9C-%EC%82%AC%EB%A1%80%EB%A1%9C-%EB%B3%B4%EC%97%AC%EC%A3%BC%EB%8A%94-%EA%B8%B0%EC%88%A0%EC%A0%81-%EC%9D%98%EC%82%AC%EA%B2%B0%EC%A0%95-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Fri, 12 Dec 2025 01:22:21 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/3f37dcd0-cc2d-4023-b77a-896935f3b794/image.png" alt=""></p>
<h1 id="introduce-비동기-로직을-적용은-해보았다만">Introduce: 비동기 로직을 적용은 해보았다만…</h1>
<hr>
<p>현재 맡고 있는 프로젝트는 음성 데이터를 실시간으로 처리하는 파이프라인을 가지고 있습니다. </p>
<p>처음에는 별 생각 없이 기존 서버들에 구성되어 있는 환경인 <strong>“Spring Boot 3.4.4 &amp; Java 17”</strong> 환경에서 개발을 진행하고 있었습니다. 기능적으로 필요해서 만든 서버였기에 처음에는 버전과 환경, 최적화 등에 대한 생각을 크게 하고 있지 않았습니다.</p>
<p>그러다 추가적인 진행방향 기획 등을 듣고 나니 걱정들이 생겨납니다.</p>
<ol>
<li>트래픽이 몰려도 성능적으로 괜찮나?</li>
<li>구조상 외부 네트워크 API를 많이 호출하게 된다. 지연시간이 너무 발생하지 않을까?</li>
<li>오류 상황이 최소화되어야 하는데 스레드 풀 관리를 제대로 할 수 있을까?</li>
</ol>
<p>이러한 고민을 해결하기 위해 <code>Virtual Thread</code>를 어떻게 도입했는지 주니어 개발자의 <strong>“기술적 의사결정 과정”</strong>을 공유해볼까 합니다.</p>
<h1 id="1-프로젝트-배경-및-문제-정의">1. 프로젝트 배경 및 문제 정의</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/866f4f3f-e71d-4df8-b541-5d4bb1d1bdd4/image.png" alt=""></p>
<h2 id="11-서비스-로직-io-bound의-연속">1.1. 서비스 로직: I/O Bound의 연속</h2>
<hr>
<p>제가 담당한 서비스는 다국어 컨퍼런스, 회의 등을 위한 파이프라인으로 다음과 같은 서비스 Flow를 가집니다.</p>
<blockquote>
<p>STT(음성 인식) → Translation API → TTS(음성 합성) API → 결과 Redis Publish</p>
</blockquote>
<p>각 단계는 Redis Publish를 제외하고는 전부 외부 API에 의존하게 되는, 전형적인 I/O Bound 작업입니다.</p>
<h2 id="12-기존-환경의-잠재적-한계java-17--platform-thread">1.2. 기존 환경의 잠재적 한계(Java 17 &amp; Platform Thread)</h2>
<hr>
<p>기존 <code>Java 17</code>환경에서는 OS 스레드와 1:1로 매핑되는 <code>Platform Thread</code>를 사용했었습니다.</p>
<ul>
<li>외부 API 응답을 기다리는 동안 해당 스레드는 <strong>Blocking</strong> 상태가 됩니다.</li>
<li>동시 요청이 그 정도로 늘어날 상황은 많지 않다고 판단했지만, 만약 동시 요청이 급증하게 된다면 <strong>“Thread Pool이 고갈”</strong>되거나 스레드를 늘리면 메모리 사용량과 컨텍스트 스위칭 비용이 급증할 수 있습니다.</li>
</ul>
<h2 id="13-채널별-스레드-할당-방식의-한계">1.3. 채널별 스레드 할당 방식의 한계</h2>
<hr>
<p>제가 개발한 서비스는 회의(Conference)마다 여러 언어(Lang) 채널이 존재합니다. </p>
<p>데이터의 순차적 처리와 채널 간 격리를 위해, 기존에는 다음과 같이 <strong>Key(회의ID+언어코드)별로 단일 스레드(Single Thread Executor)를 생성</strong>하여 캐싱하는 전략을 사용했습니다.</p>
<pre><code class="language-java">// AS-IS: Java 17 (Platform Thread)
// 채널마다 무거운 OS 스레드가 하나씩 생성되어 대기함
public ExecutorService getExecutorForLangGroup(String conferenceId, String langCode) {
    String key = conferenceId + &quot;:&quot; + langCode;
    return langExecutors.computeIfAbsent(key, k -&gt;
        Executors.newSingleThreadExecutor(r -&gt; {
            Thread thread = new Thread(r);
            thread.setDaemon(true); // 채널마다 OS 스레드 점유
            return thread;
        })
    );
}</code></pre>
<p>이 방식은 로직은 단순하고 명확해 보일 수 있지만 단점이 명확했습니다.</p>
<ul>
<li>확장성 한계: 동시 진행되는 회의가 100개이고 각 10개 언어를 지원한다면, 순식간에 <strong>1,000개의 OS 스레드</strong>가 생성됩니다.</li>
<li><strong>리소스 낭비:</strong> 대화가 없는 조용한 방에서도 스레드가 점유된 상태로 대기(Idle)하여 메모리를 낭비합니다.
(물론 이부분은 임시로 방에 활성화된 언어 채널을 계속해서 감시하며 해결했지만, 이 또한 비용에 해당하긴 합니다.)</li>
<li><strong>Context Switching:</strong> 활성 스레드가 많아지면 CPU가 스레드를 교체하는 비용이 작업 처리 비용보다 커집니다.</li>
</ul>
<h1 id="2-해결책-모색-java-21과-virtual-thread">2. 해결책 모색: Java 21과 Virtual Thread</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/8f760674-9c11-40b1-8c8a-3d845aaf7de4/image.png" alt=""></p>
<p>우선 첫 번째로 고민했던 것은 리액티브 프로그래밍(Webflux)이었습니다. </p>
<p>하지만 “기존 코드를 갈아엎어야 한다”라는 것과 “다른 API들은 어떻게 처리해야 하지?”의 두 가지 고민으로 인해 무산되었습니다.</p>
<p>그러다 떠오른 “Java 21에 <code>Virtual Thread</code>라는 것이 있다고 했었는데…”</p>
<p>이게 진짜 가볍고? 빠르고? 아무튼 좋다? 라고 했던 것 같아 냅다 알아봤습니다.</p>
<h1 id="3-virtual-thread란-무엇인가">3. Virtual Thread란 무엇인가</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/a2dd84d7-00f0-4c08-b71f-a45da6e24eb0/image.png" alt=""></p>
<h2 id="31-간단-개념">3.1. 간단 개념</h2>
<hr>
<p>기존의 <code>Platform Thread</code>가 OS 스레드 하나를 점유하는 무거운 객체라면, <code>Virtual Thread</code>는 JVM 내부에서 관리되는 경량 스레드입니다.</p>
<ul>
<li>Platfrom Thread: OS 스레드 = 1:1 매핑(비쌈, 개수 제한)</li>
<li>Virtual Thread: OS 스레드(Carrier) = N:M 매핑(매우 저렴, 수백만 개 생성 가능)</li>
</ul>
<p>Virtual Thread는 I/O Blocking이 발생하면, 실제 OS 스레드(Carrier Thread)를 점유하지 않고 다른 Virtual Thread에게 자리를 양보(Yield)합니다. 덕분에 적은 수의 OS 스레드로도 수많은 동시 요청을 처리할 수 있습니다.</p>
<p><strong>가장 Virtual Thread의 장점이 극대화되는 케이스에 해당했기 때문에 도입하지 않을 이유가 없었습니다.</strong></p>
<ul>
<li>Blocking I/O 를 그대로 사용해도 OS 스레드 점유 시간이 거의 없음</li>
<li>API 응답 대기 중 OS 스레드를 반납하기 때문에 적은 리소스에서 많은 요청 병렬 처리 가능</li>
</ul>
<p>Virtual Thread 참고자료: <a href="https://openjdk.org/jeps/444">Oracle 공식 문서 - Virtual Threads</a></p>
<h1 id="4-도입-과정">4. 도입 과정</h1>
<hr>
<h2 id="41-java-버전-업그레이드">4.1. Java 버전 업그레이드</h2>
<hr>
<p>먼저 Java 17 → Java 21로 변경할때 Springboot 3.4.4가 지원하는데, 다행이도 완벽하게 지원했습니다.</p>
<p>JDK 설치 및 <code>build.gradle</code>설정 변경만으로도 충분했습니다.</p>
<p>물론 이 과정 이후에 Springboot 버전도 검토하여 3.5.6 버전으로 버전업 하였습니다.(가장 큰 사유 LTS 버전이라)</p>
<h2 id="42-springboot-설정-적용">4.2. Springboot 설정 적용</h2>
<hr>
<p>많은 기술블로그들에서 Spring Boot 3.2부터는 옵션 하나로 톰캣(Tomcat)과 TaskExecutor가 Virtual Thread를 사용하도록 설정할 수 있습니다.</p>
<pre><code class="language-yaml"># application.yml
spring:
  threads:
    virtual:
      enabled: true</code></pre>
<p>Chat GPT한테 물어보니 설정 적용 안해도 가능하다고는 합니다.</p>
<h2 id="43--로직-변경">4.3.  로직 변경</h2>
<hr>
<p>기존에 사용하던 <code>getExecutorForLangGroup()</code>을 수정해주었습니다. (1.3. 참고)</p>
<pre><code class="language-java">// TO-BE: Java 21 (Virtual Thread)
public ExecutorService getExecutorForLangGroup(String conferenceId, String langCode) {
    String key = conferenceId + &quot;:&quot; + langCode;
    return langExecutors.computeIfAbsent(key, k -&gt;
        // 더 이상 물리 스레드를 미리 만들지 않음.
        // 작업이 들어올 때마다 가볍게 생성되는 Virtual Thread Executor 사용
        Executors.newVirtualThreadPerTaskExecutor()
    );
}</code></pre>
<h1 id="5-성능-측정-및-수치적-이점">5. 성능 측정 및 수치적 이점</h1>
<hr>
<h2 id="51-변경의-이론적-이점">5.1. 변경의 이론적 이점</h2>
<hr>
<table>
<thead>
<tr>
<th><strong>항목</strong></th>
<th><strong>기존 (newSingleThreadExecutor)</strong></th>
<th><strong>변경 후 (newVirtualThreadPerTaskExecutor)</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>I/O 작업 처리</strong></td>
<td>단일 스레드에서 <strong>순차적</strong> 블로킹</td>
<td>병렬 처리 가능, I/O 대기 시 플랫폼 스레드 <strong>해제 (언마운트)</strong></td>
</tr>
<tr>
<td><strong>처리량 (Throughput)</strong></td>
<td>매우 낮음 (하나의 느린 작업에 종속)</td>
<td><strong>매우 높음</strong> (대부분의 시간을 I/O 대기 없이 활용)</td>
</tr>
<tr>
<td><strong>시스템 Latency</strong></td>
<td>높음 (큐 대기 시간 발생)</td>
<td><strong>낮음</strong></td>
</tr>
<tr>
<td><strong>리소스 효율</strong></td>
<td>비효율적 (플랫폼 스레드 점유)</td>
<td><strong>매우 효율적</strong> (가벼운 가상 스레드 사용)</td>
</tr>
</tbody></table>
<h2 id="52-변경의-수치적-이점">5.2. 변경의 수치적 이점</h2>
<hr>
<p>저는 간이로만 테스트를 진행하겠습니다.</p>
<p>회의 하나에서 언어 2개 채널을 오픈하고 각각 같은 길이의 문장을 처리 완료하는데 걸린 시간을 체크했습니다.</p>
<ul>
<li>As-Is(Platform Thread): 2.5s</li>
<li>To-Be(Virtual Thread): 1.3s</li>
</ul>
<p>약 48%의 속도 개선을 할 수 있었습니다.</p>
<p>부끄럽지만 부하 테스트를 제대로 해 본 적이 없어, 추후 공부하여 제대로 테스트 할 수 있도록 해보겠습니다.</p>
<h1 id="6-수치-이외의-잠재적-이점">6. 수치 이외의 잠재적 이점</h1>
<hr>
<p>수치적인 성능 향상도 향상이지만 잠재적으로 얻을 수 있던 이점은 <strong>개발 생산성</strong>이었습니다.</p>
<ol>
<li><strong>코드의 단순함:</strong> <code>WebFlux</code> 같은 복잡한 비동기 코드나 콜백 지옥 없이, 익숙한 <strong>동기 스타일(Imperative style)</strong>로 코드를 짜도 비동기처럼 동작합니다.</li>
<li><strong>디버깅 용이성:</strong> 스택 트레이스(Stack Trace)가 끊기지 않고 연결되어 있어, 에러 추적이 훨씬 수월합니다.</li>
<li><strong>자원 효율성:</strong> 스레드 풀 사이즈를 고민하거나 튜닝하는 시간이 사라졌습니다.</li>
</ol>
<h1 id="7-주니어-개발자로서의-의견">7. 주니어 개발자로서의 의견</h1>
<hr>
<p>많은 분들이 저와 같을 것이라고 생각합니다. </p>
<ul>
<li>기획대로 기능을 완성하기 위해 우선 설계부터 하는데, 어떻게 설계해야 확장성이 좋지?</li>
<li>DB 테이블은 어떻게 설계하지? 컬럼만 추가할까? 매핑 테이블을 만들까?</li>
<li>병렬 처리를 위해 뭘 해야되는거지?</li>
</ul>
<p>이런 고민들을 거쳐 “기능 완성”이라는 멋진 성과를 내놓습니다.</p>
<p>하지만 이번에 저는 “기능 완성”에서 그치지 않았습니다.</p>
<p>기능개발 이후 집중했던 내용은 “리소스 절약”과 “성능 향상” 이었습니다. </p>
<ul>
<li>현재 방식이 어떤 한계점을 맞을 수 있는지 잠재적인 위협을 고려하고(단순 <code>Platform Thread</code>만을 사용하게 되는 상황 경계)</li>
<li>어떤 기술을 “왜” 선택해야 하는지(Java 21의 명확한 도입 이유)</li>
</ul>
<p>무엇이든 “다들 이렇게 하니까”라는 것은 경계하기로 했습니다. 어떤 기술 스택을 적용할 지에는 “근거”가 필요합니다. “왜”라는 것은 성장의 원동력이 되니까요.</p>
<p>저는 요즘 이틀에 최소 30분씩은 기존 로직을 검토합니다. </p>
<p>성능상 어떤 것을 개선할 수 있을지, 이 부분이 중복되는데 디자인패턴을 적용할 수 있을지, 아니면 진짜 사소하게 Util 클래스에서 DB데이터를 조회해야 하는데 Service로직을 거쳐서 가져올지,  아니면 바로 Mapper로 접근할지 등을 말이죠.</p>
<p>작은 습관이 미래에 더 나은 나를, 멋진 시니어로 성장하는 나를 만들 수 있을 것이라고 믿습니다.</p>
<h1 id="reference">Reference</h1>
<hr>
<ul>
<li><a href="https://openjdk.org/jeps/444">JEP 444: Virtual Threads</a></li>
<li><a href="https://www.google.com/search?q=https://docs.spring.io/spring-boot/docs/current/reference/html/features.html%23features.spring-application.virtual-threads">Spring Boot Virtual Threads Support</a></li>
<li><a href="https://www.google.com/search?q=placeholder">우아한형제들 기술블로그 - Java Virtual Thread 도입기</a></li>
<li><a href="https://techblog.woowahan.com/15398/">우아한형제들 기술블로그 - Java의 미래, Virtual Thread</a></li>
<li><a href="%5Bhttps://velog.io/@juhyeon1114/Java-JDK21%EC%9D%98-Virtual-Thread-%EC%A0%95%EB%A6%AC-w.-%EC%84%B1%EB%8A%A5-%ED%85%8C%EC%8A%A4%ED%8A%B8%5D(https://velog.io/@juhyeon1114/Java-JDK21%EC%9D%98-Virtual-Thread-%EC%A0%95%EB%A6%AC-w.-%EC%84%B1%EB%8A%A5-%ED%85%8C%EC%8A%A4%ED%8A%B8)">[Java] JDK21의 Virtual Thread 정리 (w. 성능 테스트)</a></li>
<li>[virtual thread(jdk21, jdk24)]
(<a href="https://c-king.tistory.com/620">https://c-king.tistory.com/620</a>)</li>
<li>[Oracle Core Libraries]
(<a href="https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html#GUID-2DDA5807-5BD5-4ABC-B62A-A1230F0566E0">https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html#GUID-2DDA5807-5BD5-4ABC-B62A-A1230F0566E0</a>)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Agent 개발의 미래, Google의 ADK]]></title>
            <link>https://velog.io/@playername_ltt/Agent-%EA%B0%9C%EB%B0%9C%EC%9D%98-%EB%AF%B8%EB%9E%98-Google%EC%9D%98-ADK</link>
            <guid>https://velog.io/@playername_ltt/Agent-%EA%B0%9C%EB%B0%9C%EC%9D%98-%EB%AF%B8%EB%9E%98-Google%EC%9D%98-ADK</guid>
            <pubDate>Tue, 02 Dec 2025 00:08:43 GMT</pubDate>
            <description><![CDATA[<p>지난 25.11.30에 <strong>“GDG Devfest Seoul 2025”</strong>에 다녀왔습니다. 들었던 세션 중 <strong>“Building AI Agents with Agent Development Kit Go”</strong>라는 Hands-on 세션에서 소개받은 <strong>“ADK(Agent Development Kit)”</strong>에 대해 소개해볼까 합니다.</p>
<p>기술의 발전 속도는 눈부시며, 그 중심에는 <strong>AI</strong>가 있습니다. 특히 사용자의 의도를 이해하고 복잡한 작업을 자율적으로 수행하는 <strong>에이전트(Agent)</strong> 기술은 AI의 다음 혁명을 이끌 핵심으로 주목받고 있죠. 이러한 흐름 속에서 Google은 개발자들이 혁신적인 AI 에이전트를 보다 쉽고 빠르게 구축할 수 있도록 강력한 도구를 2025년 4월, 세상에 공개했습니다.</p>
<h1 id="그래서-adk가-무엇인가요">그래서 ADK가 무엇인가요?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/edd81b7a-0e16-4c26-821e-42ff6d117a2b/image.png" alt=""></p>
<p><strong>ADK</strong>는 Google의 첨단 <strong>대규모 언어 모델(LLM)</strong>, 즉 <strong>Gemini</strong>를 기반으로 하여, <strong>복잡하고 다단계적인 사용자 요청</strong>을 이해하고 실행하는 <strong>AI 에이전트</strong>를 구축하기 위한 포괄적인 프레임워크이자 도구 모음입니다.</p>
<p>ADK의 핵심 목표는 개발자가 에이전트의 <strong>계획(Planning)</strong>, <strong>도구 사용(Tool Use)</strong>, <strong>기억(Memory)</strong>, 그리고 <strong>사용자 피드백을 통한 학습(Learning)</strong>과 같은 핵심 기능을 손쉽게 통합하고 맞춤 설정할 수 있도록 돕는 것입니다. 쉽게 말해, <strong>ADK는 AI가 단순한 질문에 답하는 것을 넘어, 현실 세계에서 목표를 설정하고 달성할 수 있는 &#39;행동하는 AI&#39;를 만드는 프레임워크</strong>라고 할 수 있습니다.</p>
<p>Gemini 및 Google 생태계에 최적화되어 있지만, 모델에 구애받지 않고(model-agnostic), 배포 환경에 제약이 없고(deployment-agnostic), 다른 프레임워크와의 호환성을 위해 구축되었다고 합니다. 핵심은 Agent개발이 소프트웨어 개발처럼 느껴지도록 설계되었다는 것입니다.</p>
<h2 id="에이전트-개발의-새로운-표준">에이전트 개발의 새로운 표준</h2>
<hr>
<p>Google ADK는 단순히 에이전트를 만드는 도구를 넘어, AI 에이전트의 <strong>상호 운용성</strong>과 <strong>확장성</strong>을 높이는 것을 목표로 합니다. 이는 다양한 애플리케이션과 플랫폼에서 일관되고 강력한 성능을 발휘하는 에이전트를 개발할 수 있게 해줍니다.</p>
<p>ADK를 통해 개발자들은 금융 분석, 개인 비서, 복잡한 데이터 관리 등 <strong>특정 목적에 최적화된 고성능 AI 에이전트</strong>를 구현할 수 있습니다.</p>
<h1 id="langchain은-끝난건가요">LangChain은 끝난건가요?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/2a9101aa-9883-4004-a4d4-4cb5ee6d1757/image.png" alt=""></p>
<p>AI 에이전트 개발 분야에서 Google의 <strong>ADK</strong>가 등장하기 전까지, <strong>LangChain</strong>은 에이전트 구축의 사실상의 표준이었습니다. 두 프레임워크는 모두 대규모 언어 모델(LLM)을 활용하여 복잡한 작업을 수행하는 에이전트를 만드는 것을 목표로 하지만, 그 <strong>접근 방식, 아키텍처, 그리고 통합되는 생태계</strong>에서 차이를 보입니다.</p>
<table>
<thead>
<tr>
<th><strong>특징</strong></th>
<th><strong>LangChain</strong></th>
<th><strong>Google ADK</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>핵심 철학</strong></td>
<td><strong>모듈성 및 범용성</strong></td>
<td><strong>End-to-End 통합 및 확장성</strong></td>
</tr>
<tr>
<td><strong>기반 모델</strong></td>
<td>다양한 LLM 지원 (OpenAI, Anthropic, Google Gemini 등)</td>
<td><strong>Google Gemini</strong> 모델에 최적화 및 깊이 통합됨</td>
</tr>
<tr>
<td><strong>구성 요소</strong></td>
<td><strong>Chains, Agents, Tools, Memory</strong> 등 레고 블록 형태의 모듈</td>
<td>에이전트의 핵심 기능(계획, 도구 사용 등)을 통합된 <strong>서비스</strong> 형태로 제공</td>
</tr>
<tr>
<td><strong>통합</strong></td>
<td>다양한 데이터 소스, 벡터 데이터베이스, LLM Provider와의 유연한 연결</td>
<td>Google의 광범위한 서비스 및 인프라(Google Cloud, Workspace 등)와의 <strong>깊은 통합</strong></td>
</tr>
</tbody></table>
<h1 id="langchain과-adk의-작동-방식-및-개발-흐름의-차이">LangChain과 ADK의 작동 방식 및 개발 흐름의 차이</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/1dac752e-f9e2-4ed8-89d5-0480a5d8bae4/image.png" alt=""></p>
<h2 id="1-langchain의-접근-방식-조합과-유연성">1. LangChain의 접근 방식: 조합과 유연성</h2>
<hr>
<p><strong>LangChain</strong>은 개발자가 에이전트의 각 구성 요소를 <strong>독립적인 모듈</strong>로 정의하고 조합하도록 설계되었습니다.</p>
<ul>
<li><strong>Chains:</strong> 일련의 동작을 연결합니다 (예: 사용자 입력 → 프롬프트 → LLM 응답 → 파싱).</li>
<li><strong>Agents:</strong> 동적으로 어떤 도구(Tool)를 사용할지 결정하는 추론 로직을 제공합니다.</li>
<li><strong>유연성:</strong> 개발자는 추론 방식(ReAct, Zero-shot), 도구, 메모리 유형 등을 자유롭게 선택하고 교체할 수 있어 <strong>최대한의 커스터마이징</strong>이 가능합니다.</li>
</ul>
<pre><code class="language-python"># pip install -qU &quot;langchain[anthropic]&quot; to call the model

from langchain.agents import create_agent

def get_weather(city: str) -&gt; str:
    &quot;&quot;&quot;Get weather for a given city.&quot;&quot;&quot;
    return f&quot;It&#39;s always sunny in {city}!&quot;

agent = create_agent(
    model=&quot;claude-sonnet-4-5-20250929&quot;,
    tools=[get_weather],
    system_prompt=&quot;You are a helpful assistant&quot;,
)

# Run the agent
agent.invoke(
    {&quot;messages&quot;: [{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;what is the weather in sf&quot;}]}
)</code></pre>
<h2 id="2-google-adk의-접근-방식-빌트인-및-최적화">2. Google ADK의 접근 방식: 빌트인 및 최적화</h2>
<hr>
<p><strong>ADK</strong>는 LLM인 <strong>Gemini</strong>가 에이전트의 핵심 지능을 담당하도록 하고, 에이전트가 필요한 기능을 <strong>&#39;서비스&#39;</strong> 형태로 호출하고 통합하는 데 중점을 둡니다.</p>
<ul>
<li><strong>Deep Gemini Integration:</strong> ADK는 특히 <strong>Gemini의 네이티브 멀티모달리티 및 복잡한 추론 능력</strong>을 활용하여 더 정교한 계획(Planning) 및 도구 호출을 수행하도록 설계되었습니다.</li>
<li><strong>Agent Service Model:</strong> ADK는 &#39;계획 수립&#39;, &#39;도구 실행&#39;, &#39;기억 관리&#39; 등의 복잡한 로직을 개발자가 직접 구현하기보다는, <strong>고도로 최적화된 빌트인 구성 요소</strong>를 통해 쉽게 호출하고 확장하도록 합니다. 이는 <strong>대규모 및 엔터프라이즈급 배포</strong>에 유리합니다.</li>
</ul>
<pre><code class="language-go">package main

import (
    &quot;context&quot;
    &quot;log&quot;
    &quot;os&quot;
    &quot;fmt&quot;

    &quot;google.golang.org/adk/agent&quot;
    &quot;google.golang.org/adk/agent/llmagent&quot;
    &quot;google.golang.org/adk/cmd/launcher&quot;
    &quot;google.golang.org/adk/cmd/launcher/full&quot;
    &quot;google.golang.org/adk/model/gemini&quot;
    &quot;google.golang.org/adk/tool&quot;
    &quot;google.golang.org/adk/tool/functiontool&quot;

    &quot;google.golang.org/genai&quot;
)

type getWeatherArgs struct {
    City string `json:&quot;city&quot; jsonschema:&quot;The city to get weather for.&quot;`
}

func getWeather(ctx tool.Context, args getWeatherArgs) (string, error) {
    fmt.Printf(&quot;[Tool] Getting weather for %s...\n&quot;, args.City)
    return fmt.Sprintf(&quot;The weather in %s is Sunny, 25°C&quot;, args.City), nil
}

func main() {
    ctx := context.Background()

    model, err := gemini.NewModel(ctx,
        &quot;gemini-3-pro-preview&quot;,
        &amp;genai.ClientConfig{
            APIKey: os.Getenv(&quot;GOOGLE_API_KEY&quot;),
        })
    if err != nil {
        log.Fatalf(&quot;Failed to create model: %v&quot;, err)
    }

    weatherTool, _ := functiontool.New(functiontool.Config{
        Name: &quot;get_weather&quot;, Description: &quot;Get weather for a city&quot;},
        getWeather,
    )

    sentimentTool, _ := functiontool.New(
        functiontool.Config{Name: &quot;analyze_sentiment&quot;, Description: &quot;Analyze text sentiment&quot;},
        analyzeSentiment)

    myAgent, err := llmagent.New(llmagent.Config{
        Name:  &quot;helper_agent&quot;,
        Model: model,
        Instruction: &quot;You are a helper. If asked about weather, use get_weather.  &quot; +
            &quot;Then analyze the user&#39;s reaction using analyze_sentiment.&quot;,
        Tools: []tool.Tool{weatherTool, sentimentTool},
    })

    if err != nil {
        log.Fatalf(&quot;Failed to create agent: %v&quot;, err)
    }

    config := &amp;launcher.Config{
        AgentLoader: agent.NewSingleLoader(myAgent),
    }

    l := full.NewLauncher()

    if err = l.Execute(ctx, config, os.Args[1:]); err != nil {
        log.Fatalf(&quot;Run failed: %v\n\n%s&quot;, err, l.CommandLineSyntax())
    }
}</code></pre>
<h2 id="3-사용-사례-및-선택-기준">3. 사용 사례 및 선택 기준</h2>
<hr>
<table>
<thead>
<tr>
<th><strong>기준</strong></th>
<th><strong>LangChain 선택 시</strong></th>
<th><strong>Google ADK 선택 시</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>LLM 종속성</strong></td>
<td>특정 LLM에 구애받지 않고 <strong>다양한 모델</strong>을 실험하고 비교하고 싶을 때.</td>
<td><strong>Google Gemini</strong>의 최첨단 기능과 성능을 최대한 활용하고자 할 때. (다른 LLM도 가능함)</td>
</tr>
<tr>
<td><strong>커스터마이징</strong></td>
<td>에이전트의 내부 추론 로직(프롬프트, 파서 등)을 <strong>세밀하게 제어</strong>하고 싶을 때.</td>
<td>복잡한 에이전트를 <strong>더 빠르고 간편하게</strong> 구축하고 배포 시간을 단축하고 싶을 때.</td>
</tr>
<tr>
<td><strong>배포 환경</strong></td>
<td>로컬 환경이나 다양한 클라우드 환경에서 유연하게 운영하고자 할 때.</td>
<td><strong>Google Cloud 또는 Workspace 생태계 내</strong>에서 에이전트를 구축하고 서비스와 깊이 통합해야 할 때.</td>
</tr>
<tr>
<td><strong>주요 목표</strong></td>
<td>연구 개발(R&amp;D) 및 새로운 AI 에이전트 패턴의 신속한 프로토타이핑.</td>
<td><strong>생산 환경에 최적화된</strong> 안정적이고 확장 가능한 엔터프라이즈급 에이전트 구축.</td>
</tr>
</tbody></table>
<p>요약하자면, <strong>LangChain</strong>은 <strong>유연성과 모듈성을 극대화</strong>하여 개발자에게 &#39;무엇이든 만들 수 있는 레고 세트&#39;를 제공하는 반면, <strong>Google ADK</strong>는 <strong>Gemini 기반의 깊은 통합과 최적화</strong>를 통해 &#39;고성능의 완성도 높은 에이전트를 빠르게 제작할 수 있는 통합 엔지니어링 툴킷&#39;을 제공한다고 볼 수 있습니다.</p>
<h1 id="adk의-핵심-기능">ADK의 핵심 기능</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/f63e94da-bacf-4939-9cde-119591093af4/image.png" alt=""></p>
<ul>
<li><strong>코드 기반 제어성</strong>: 에이전트의 동작, 툴 호출, 오케스트레이션 로직을 소스 코드에서 직접 정의할 수 있어 높은 제어력과 정밀한 테스트 전략을 마련할 수 있습니다. Python뿐만 아니라 <strong>Java, Go 등 다양한 언어 SDK</strong>가 제공되므로 팀의 기술 스택에 맞춘 개발이 가능합니다.</li>
<li><strong>다중 에이전트 구조 지원</strong>: 여러 개의 전문화된 에이전트를 계층적 또는 병렬 구조로 구성하여 복잡한 업무 흐름을 분리·모듈화할 수 있습니다. 대규모 애플리케이션에서도 유지보수성과 확장성을 확보할 수 있습니다.</li>
<li><strong>풍부한 도구 통합 능력</strong>: 사전 정의된 기본 도구 세트 외에도 사용자 정의 함수, 외부 API 명세(OpenAPI 등), 사내 시스템을 연결하여 에이전트의 기능을 자유롭게 확장할 수 있습니다. 이를 통해 모델이 실제 업무 시스템에 액세스해 실행 가능한 작업을 수행할 수 있습니다.</li>
<li><strong>유연한 오케스트레이션 옵션</strong>: 고정된 절차 기반 파이프라인을 구성할 수도 있고, LLM 기반 정책을 사용해 상황에 따라 적응적으로 경로를 선택하는 동적 워크플로우도 구현할 수 있습니다. 복잡한 직렬·병렬 실행 구조까지 자연스럽게 표현됩니다.</li>
<li><strong>통합 개발 환경 제공</strong>: CLI 기반 개발 도구와 시각적 웹 UI가 함께 제공되어 로컬에서 에이전트를 실행하고 디버깅하며, 단계별 실행 로그를 시각적으로 추적할 수 있습니다. 개발–테스트–배포 사이의 피드백 루프가 크게 단축됩니다.</li>
<li><strong>평가 기능 내장</strong>: 응답 품질뿐 아니라 단계별 실행 경로, 도구 호출 결과까지 평가할 수 있어 회귀 테스트와 시나리오 기반 비교 분석이 가능합니다. 에이전트의 안정성 및 품질 확보에 중요한 역할을 합니다.</li>
<li><strong>배포 친화적 구조</strong>: 컨테이너화를 기본으로 설계되어 Docker, Cloud Run, Vertex AI Agent Engine 등 다양한 환경에서 실행할 수 있습니다. 서버리스·쿠버네티스 기반 운영에도 적합하여 확장성과 안정성이 뛰어납니다.</li>
<li><strong>네이티브 스트리밍 지원</strong>: 텍스트와 오디오 모두에서 양방향 스트리밍을 제공하므로, 실시간 상호작용이 필요한 대화형 UI, 음성 기반 시스템, 실시간 처리 워크플로우에 자연스럽게 적용할 수 있습니다.</li>
<li><strong>상태·메모리·아티팩트 관리</strong>: 단기 대화 상태, 장기 메모리, 파일 업로드·다운로드, 실행 아티팩트 추적 등 에이전트가 복합적인 문맥을 다룰 수 있도록 상태 관리 기능이 제공됩니다. 복잡한 멀티턴 시나리오에서도 일관된 동작을 유지할 수 있습니다.</li>
<li><strong>확장성 중심 설계</strong>: 콜백 훅과 플러그인 구조를 활용하여 에이전트의 실행 과정, 로깅, 정책 등을 세부적으로 커스터마이즈할 수 있습니다. 또한 서드파티 서비스 및 사내 시스템과의 통합도 용이합니다.</li>
</ul>
<h1 id="에이전트-개발의-패러다임-변화">에이전트 개발의 패러다임 변화</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/515468bb-e8c6-4e6f-8533-0a877648544f/image.png" alt=""></p>
<p>ADK를 이용한 Agent개발을 직접 실습하다 보니 처음 해보는 저도 쉽게 따라할 수 있을 정도로 공부좀 하면 가능할 것 같더군요. ADK는 분명 멀지 않은 미래에 AI Agent 개발의 패러다임 변화를 불러올 수 있을 것 같습니다.</p>
<h2 id="1-ai-엔지니어링의-산업화-industrialization-of-ai-engineering">1. AI 엔지니어링의 산업화 (Industrialization of AI Engineering)</h2>
<hr>
<p>LangChain 등의 초기 프레임워크가 AI 에이전트 개발의 &#39;실험실&#39; 단계였다면, ADK는 이를 <strong>&#39;대량 생산 공장&#39; 단계</strong>로 끌어올리고 있습니다.</p>
<ul>
<li><strong>SW 개발 표준 채택:</strong> ADK는 &#39;에이전트 개발이 소프트웨어 개발처럼 느껴지도록&#39; 설계되었다는 핵심 철학을 실현합니다. <strong>코드 중심 제어, 통합 개발 환경(IDE), 내장된 테스트 및 평가 기능</strong>은 AI 에이전트 개발을 프롬프트 엔지니어링의 영역에서 <strong>정교한 소프트웨어 엔지니어링의 영역</strong>으로 이동시킵니다.</li>
<li><strong>엔터프라이즈 레디:</strong> <strong>배포 친화적 구조(컨테이너화), 멀티 에이전트 아키텍처, 상태 및 메모리 관리</strong> 기능은 기업이 요구하는 <strong>확장성, 안정성, 유지보수성</strong> 기준을 충족합니다. 이는 파일럿 프로젝트가 아닌, 수백만 사용자를 대상으로 하는 실제 프로덕션 시스템에 AI 에이전트를 도입할 수 있는 길을 열어줍니다.</li>
<li><strong>Gemini의 잠재력 극대화:</strong> Google의 최신 LLM인 Gemini가 가진 <strong>복잡한 추론, 멀티모달리티, 장기 컨텍스트 처리</strong> 능력이 ADK를 통해 구조화된 워크플로우 내에서 안정적으로 활용될 수 있게 되었습니다.</li>
</ul>
<h2 id="2-개발팀-구조의-변화-ai와-sw-개발의-융합">2. 개발팀 구조의 변화: AI와 SW 개발의 융합</h2>
<hr>
<p>ADK는 기존의 데이터 과학팀이나 LLM 연구팀뿐만 아니라, <strong>일반 소프트웨어 개발팀(Backend, Frontend)</strong>이 AI 에이전트 개발에 깊이 참여할 수 있도록 합니다.</p>
<ul>
<li><strong>다양한 언어 지원 (Go, Java, Python):</strong> 기존 백엔드 시스템을 운영하는 팀이 익숙한 언어로 에이전트 로직과 도구를 개발할 수 있게 됩니다.</li>
<li><strong>역할 분리:</strong> ADK의 모듈화된 구조는 개발팀 내에서 역할을 분리하기 용이합니다. 예를 들어, <strong>ML 엔지니어</strong>는 LLM 정책 및 평가 로직을, <strong>SW 엔지니어</strong>는 도구 통합 및 오케스트레이션 파이프라인을 담당하는 방식으로 협업할 수 있습니다.</li>
</ul>
<h1 id="마무리하며">마무리하며</h1>
<hr>
<p><strong>“GDG Devfest Seoul 2025”</strong>에서 만난 <strong>&quot;Agent Development Kit&quot;</strong>는 AI 에이전트 개발을 이전보다 훨씬 더 쉽고 체계적인 영역으로 끌어올린 것 같습니다. 당장에 풀스택 개발자인 저도 하루빨리 Agent 개발을 해 보고 싶다는 생각이 무럭무럭 솟네요.</p>
<p>이미 대부분의 서비스에 AI Agent는 ‘옵션’이 아닌 ‘필수’가 거의 되어버렸습니다. 코드 중심의 개발 방식, 뛰어난 확장성, 그리고 Google 생태계의 지원을 등에 업은 ADK는 이 ‘필수’를 쉽게 이끌어줄 강력한 툴이 될 것이라고 생각합니다.</p>
<p>다들 한번 알아보시고 시작해보시길 추천드립니다. 당신의 다음 AI 프로젝트는 ADK 한번 도입해보는 것이 어떨까요.</p>
<h1 id="reference">Reference</h1>
<hr>
<ul>
<li><a href="https://discuss.pytorch.kr/t/google-ai-adk-agent-development-kit/6746">https://discuss.pytorch.kr/t/google-ai-adk-agent-development-kit/6746</a></li>
<li><a href="https://medium.com/@hams_ollo/googles-agent-development-kit-adk-revolutionizing-multi-agent-application-development-f74f9a08cdce">https://medium.com/@hams_ollo/googles-agent-development-kit-adk-revolutionizing-multi-agent-application-development-f74f9a08cdce</a></li>
<li><a href="https://www.langchain.com/">https://www.langchain.com/</a></li>
<li><a href="https://github.com/google/adk-samples">https://github.com/google/adk-samples</a></li>
<li><a href="https://google.github.io/adk-docs/">https://google.github.io/adk-docs/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[당신은 AI 주도 개발을 받아들일 수 있나요? (AIDD)]]></title>
            <link>https://velog.io/@playername_ltt/%EB%8B%B9%EC%8B%A0%EC%9D%80-AI-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C%EC%9D%84-%EB%B0%9B%EC%95%84%EB%93%A4%EC%9D%BC-%EC%88%98-%EC%9E%88%EB%82%98%EC%9A%94-AIDD</link>
            <guid>https://velog.io/@playername_ltt/%EB%8B%B9%EC%8B%A0%EC%9D%80-AI-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C%EC%9D%84-%EB%B0%9B%EC%95%84%EB%93%A4%EC%9D%BC-%EC%88%98-%EC%9E%88%EB%82%98%EC%9A%94-AIDD</guid>
            <pubDate>Thu, 27 Nov 2025 13:34:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/63c0047d-7c41-4508-afd0-60cd0c164156/image.png" alt=""></p>
<p>개발 환경은 지금, 그 어느 때보다 빠르게 변화하고 있습니다. GitHub Copilot, Cursor, Claude Code, Windsurf…</p>
<p><strong>AI 코딩 도구의 춘추전국시대</strong>가 도래한 것이죠.</p>
<p>이제 개발자에게 중요한 질문은 더 이상</p>
<blockquote>
<p>“AI 코딩 도구를 쓰면 기본 지식이 뒤쳐지지 않을까?”</p>
</blockquote>
<p>가 아니라,</p>
<blockquote>
<p>“AI를 어떻게 하면 팀과 개발 프로세스에 맞게 잘 활용할 것인가?”</p>
</blockquote>
<p>로 바뀌고 있습니다.</p>
<p>과거에는 AI 코딩 도구를 사용할 것인지 말 것인지가 논쟁거리였습니다. 하지만 2025년의 개발 환경에서 그 질문은 이미 시대에 뒤처졌습니다.</p>
<p><strong>이제 핵심은</strong> </p>
<p><strong>“AI를 얼마나 잘 활용해 더 나은 개발 사이클을 만드는가?”</strong></p>
<p>그리고 이 질문은 단순 자동완성 다음의, 새로운 개발 패러다임으로 확장되고 있습니다. 그것이 바로 <strong>AI-Driven Development(AIDD)</strong>입니다.</p>
<h1 id="ai가-마구마구-뱉어내는-스파게티-코드">AI가 마구마구 뱉어내는 &quot;스파게티 코드&quot;</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/c0ec103e-2dda-42c1-8b14-73aa3f963dcd/image.png" alt=""></p>
<p>AI 코딩 툴이 마냥 좋기만 할까요? 2024년 발표된 <strong>GitClear의 리포트</strong>는 꽤 충격적인 데이터를 보여줬었는데요.</p>
<blockquote>
<p>&quot;AI 도입 후 코드 이동은 늘었고, 코드 재사용률은 오히려 줄었다.&quot;</p>
</blockquote>
<p>AI가 코드를 너무 쉽게 짜주다 보니, 기존 코드를 재사용하기보다 <strong>&quot;복사/붙여넣기&quot;</strong>하는 경향이 강해졌다는 것입니다. 이는 장기적으로 유지보수가 불가능한 &#39;기술 부채(Technical Debt)&#39;를 가속화합니다.</p>
<ul>
<li><strong>과거:</strong> 고민해서 10줄 작성</li>
<li><strong>현재:</strong> AI가 1초 만에 100줄 생성 -&gt; 검증 없이 Commit -&gt; 레거시 폭탄</li>
</ul>
<p>우리는 <strong>“AI가 짠 코드를 믿지 않는 것&quot;</strong>에서부터 AIDD를 시작해야 합니다. 물론 AI는 점점 발전하며 신뢰성 있는 코드를 짜 나아갈테지만 말이죠.</p>
<h1 id="단순-자동완성의-시대의-끝-aidd란">단순 자동완성의 시대의 끝, AIDD란?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/94c6aab7-7db2-457e-8bfd-cbfc156bf318/image.png" alt=""></p>
<p>이제 막 <strong>Copilot v1</strong>이 다음 변수명이나 함수 시그니처를 추천해주던 시대는 끝났습니다. 단순한 <strong>&#39;코드 스니펫 생성(Code Snippet Generation)&#39;</strong>은 더 이상 AIDD라고 부르지 않습니다.</p>
<p>그렇다면 진정한 AIDD는 무엇일까요? </p>
<p><strong>AI를 개발 프로세스 전반을 주도하는 &#39;사고 파트너(Thought Partner)&#39;로 활용</strong>하는 개발 방법론의 총체를 의미합니다.</p>
<h3 id="aidd가-기존-자동완성과-다른-결정적인-차이점">AIDD가 기존 자동완성과 다른 결정적인 차이점</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>단순 자동완성 (2022년 이전)</th>
<th>AIDD (AI Driven Development)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>인식 범위</strong></td>
<td>현재 파일, 최근 몇 줄의 코드</td>
<td><strong>전체 코드베이스</strong> (프로젝트 구조, 컨벤션, 의존성)</td>
</tr>
<tr>
<td><strong>수행 임무</strong></td>
<td>다음 단어/줄 예측, 단순 함수 생성</td>
<td><strong>아키텍처 변경</strong>, <strong>모듈 간 버그 수정</strong>, <strong>테스트 코드 작성</strong></td>
</tr>
<tr>
<td><strong>개발자 역할</strong></td>
<td>타이핑 속도를 높여주는 보조자</td>
<td>복잡한 문제 해결을 함께 논의하는 <strong>사고 파트너</strong></td>
</tr>
</tbody></table>
<h2 id="aidd의-두-가지-핵심">AIDD의 두 가지 핵심</h2>
<hr>
<p>AIDD는 개발자에게 두 가지 근본적인 변화를 요구합니다.</p>
<h3 id="1-ragretrieval-augmented-generation-기반의-맥락-이해">1. RAG(Retrieval-Augmented Generation) 기반의 &#39;맥락 이해&#39;</h3>
<p>Cursor와 같은 최신 도구들은 <strong><code>RAG</code></strong> 기술을 이용해 단순히 다음 코드를 예측하는 것을 넘어, <strong>프로젝트 전체 파일의 구조와 팀 컨벤션</strong>을 인덱싱합니다.</p>
<p>이로 인해 AI는 &quot;여기에 <code>getUserInfo</code>를 넣으면 되겠네&quot;가 아니라, &quot;<strong>이 로직은 우리 팀의 Redux 아키텍처에서 Store와 Action을 어떻게 변경해야 할지</strong>&quot;까지 이해하고 제안할 수 있게 됩니다. 이는 곧 <strong>&#39;코딩&#39;의 영역에서 &#39;설계 및 리팩토링&#39;의 영역</strong>으로 AI의 역할이 확장되었음을 의미합니다.</p>
<h3 id="2-ai-코드의-신뢰성-확보를-위한-방법론-통합">2. &#39;AI 코드&#39;의 신뢰성 확보를 위한 방법론 통합</h3>
<p>AI는 빠르게 코드를 짜지만, 그 코드가 항상 정확하고 견고하지는 않습니다. 바로 앞서 언급했던 GitClear 리포트의 경고가 여기에 해당됩니다.</p>
<p>따라서 AIDD는 <strong>&#39;AI는 구현 도구, TDD는 검증 도구&#39;</strong>라는 명제를 핵심으로 삼습니다. AI에게 &quot;테스트 통과 코드&quot;를 요청하고, 개발자는 &quot;테스트 코드가 비즈니스 요구사항을 정확히 반영하는지&quot;를 검토하는 방식으로 역할이 재정의됩니다.</p>
<p>AIDD는 곧 <strong>AI를 비판적으로 활용하여 개발 방법론(TDD, Test-Driven Development)에 녹여내는 과정</strong>이라고 할 수 있겠습니다.</p>
<h1 id="ai-driven-development라고-했는데-tdd가-왜-튀어나오나요">AI-Driven Development라고 했는데 TDD가 왜 튀어나오나요?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/f2bf57dc-bde9-467c-90c9-658690dac22f/image.png" alt=""></p>
<p>AIDD(AI Driven Development)의 핵심은 궁극적으로 <strong>&#39;신뢰할 수 있는 소프트웨어&#39;를 빠르고 효율적으로 만드는 것</strong>입니다. 하지만 AI가 코드를 짜는 과정에서 근본적인 한계점이 발생하고, 이 지점에서 <strong>TDD(Test-Driven Development, 테스트 주도 개발)</strong>는 단순한 개발 방법론을 넘어 AIDD의 <strong>안전망이자 핵심 방법론</strong>이 됩니다.</p>
<h2 id="1-ai-코드의-본질적인-한계-불확실성과-환각-hallucination">1. AI 코드의 본질적인 한계: 불확실성과 환각 (Hallucination)</h2>
<hr>
<p>LLM(Large Language Models) 기반의 AI 코딩 도구는 <strong>&#39;가장 확률 높은 다음 토큰&#39;</strong>을 예측하여 코드를 생성합니다. 이 과정에서 발생하는 AI 코드의 가장 큰 위험 요소는 다음과 같습니다.</p>
<ul>
<li><strong>불확실성 (Non-Deterministic):</strong> 같은 프롬프트에도 다른 코드가 나옵니다.</li>
<li><strong>환각 (Hallucination):</strong> 존재하지 않는 API나 라이브러리를 사용하거나, 현재 프로젝트 맥락과 맞지 않는 잘못된 로직을 자신 있게 제시합니다.</li>
<li><strong>오버 엔지니어링 (Over-Engineering):</strong> 요구 사항보다 훨씬 복잡하거나 불필요한 코드를 생성하여 기술 부채를 유발합니다. (앞서 언급된 [GitClear Report]의 핵심 경고입니다.)</li>
</ul>
<p>즉, <strong>AI는 &#39;빠른 코드 작성&#39;이라는 생산성은 제공하지만, &#39;코드의 정확성과 안정성&#39;이라는 품질은 보장하지 못합니다.</strong></p>
<h2 id="2-tdd-ai-코드를-신뢰할-수-있는-코드로-만드는-검증-안전-장치">2. TDD: AI 코드를 &#39;신뢰할 수 있는 코드&#39;로 만드는 검증 안전 장치</h2>
<hr>
<p>TDD는 코드를 짜기 전에 테스트 코드를 먼저 작성하는 개발 방식입니다. AIDD에 TDD가 결합되어야 하는 이유는 AI의 불안정성을 완벽하게 상쇄시키기 때문입니다.</p>
<h3 id="a-ai에-대한-명확한-지시서-역할">A. AI에 대한 명확한 지시서 역할</h3>
<p>AIDD에서 테스트 코드는 단순한 검증 도구가 아닌, AI에게 던지는 <strong>가장 명확하고 구체적인 요구사항 정의서</strong>가 됩니다.</p>
<ul>
<li><strong>일반 프롬프트:</strong> &quot;회원가입 기능을 만들어줘.&quot; (AI에게 넓은 자유도)</li>
<li><strong>TDD 기반 프롬프트:</strong> (테스트 코드를 제시하며) &quot;이 테스트 케이스를 통과하는 <code>UserService.register</code> 함수를 구현해줘.&quot; (AI에게 명확한 목표 제시)</li>
</ul>
<p>이는 AI가 요구사항을 잘못 해석하거나 불필요한 코드를 넣는 <strong>환각의 위험을 최소화</strong>합니다.</p>
<h3 id="b-red-green-refactor-사이클의-생산성-극대화">B. Red-Green-Refactor 사이클의 생산성 극대화</h3>
<p>TDD의 <strong>&quot;빨간불 - 초록불 - 리팩토링&quot;</strong> 사이클이 AI를 만나 혁신적으로 빨라집니다.</p>
<ol>
<li><strong>🔴 Red (빨간불):</strong> 개발자가 실패하는 <strong>테스트 코드</strong>를 작성합니다. (인간의 설계)</li>
<li><strong>🟢 Green (초록불):</strong> AI에게 <strong>&#39;이 테스트를 통과하는 구현 코드&#39;</strong>를 작성하게 합니다. (AI의 구현 속도 극대화)</li>
<li><strong>Refactor (리팩토링):</strong> AI에게 <strong>&#39;방금 생성된 구현 코드를 더 깔끔하게 리팩토링하고 SOLID 원칙을 적용해달라&#39;</strong>고 요청합니다. (인간의 검토 및 AI의 보조 리팩토링)</li>
</ol>
<p>이러한 협력 모델은 <strong>인간의 사고 능력</strong>과 <strong>AI의 구현 속도 및 패턴 인식 능력</strong>을 결합하여, 단순히 속도만 빠른 개발이 아니라 <strong>품질과 속도를 동시에 잡는 개발</strong>을 가능하게 합니다.</p>
<h1 id="바이브-코더와-주니어에게-aidd가-필수인-이유--시니어처럼-일하기">바이브 코더와 주니어에게 AIDD가 &#39;필수&#39;인 이유 = 시니어처럼 일하기</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/33122023-5419-4996-a8a0-fb22dcd0708c/image.png" alt=""></p>
<p>바이브 코더(Vibe Coder)나 개발 경력이 길지 않은 주니어 개발자에게 <strong>AI Driven Development (AIDD)</strong>는 단순한 생산성 도구를 넘어 <strong>&quot;시니어 개발자처럼 일하는 방법&quot;</strong>을 가르쳐주는 핵심적인 성장 수단이 될 수 있다고 생각합니다.</p>
<p>AIDD를 채택해야 하는 구체적인 이유 3가지를 정리했습니다.</p>
<h2 id="시니어-엔지니어의-사고방식-학습">시니어 엔지니어의 &#39;사고방식&#39; 학습</h2>
<hr>
<p>주니어 개발자가 가장 어려움을 느끼는 부분은 <strong>&#39;어떻게 코드를 짜야 하는가&#39;</strong>가 아니라, <strong>&#39;왜 이 코드를 이렇게 짜야 하는가&#39;</strong>에 대한 의사 결정 과정입니다.</p>
<ul>
<li><strong>즉각적인 피드백 루프:</strong> 바이브 코더는 코드를 짠 후 AI에게 &quot;이 코드가 <strong>SOLID 원칙</strong>을 따르나요?&quot;, &quot;이 함수는 <strong>테스트하기 쉽게</strong> 리팩토링할 수 있나요?&quot;라고 질문하고 즉시 피드백을 받을 수 있습니다.</li>
<li><strong>패턴 및 컨벤션 내재화:</strong> Cursor의 <code>.cursorrules</code> , Claude Code의 <code>CLAUDE.md</code>등을 통해 팀의 컨벤션(명명 규칙, 아키텍처 패턴)을 AI에게 학습시키고, AI가 생성한 코드를 분석함으로써 <strong>팀이 중요하게 생각하는 코딩 습관</strong>을 빠르게 체화할 수 있습니다. 물론 작성 후 리뷰를 요청해도 가능합니다. AI가 일종의 <strong>24시간 대기하는 코드 리뷰어이자 멘토</strong> 역할을 하는 것입니다.</li>
</ul>
<h2 id="불안-해소-및-생산성-가속화">불안 해소 및 생산성 가속화</h2>
<hr>
<p>바이브 코더는 새로운 기능을 구현할 때 &#39;어디서부터 시작해야 할지&#39;, &#39;혹시나 심각한 버그를 만들지 않을지&#39;에 대한 불안감을 느끼기 쉽습니다.</p>
<ul>
<li><strong>TDD 기반 개발 습관 획득:</strong> AIDD는 TDD를 강제합니다. 코드를 직접 짜기 전에 테스트 코드를 작성하는 경험을 반복하면, 바이브 코더는 구현보다는 <strong>기능의 설계</strong>에 집중하는 습관을 들이게 됩니다. AI가 빠른 속도로 구현(Green)을 책임지므로, 구현 실패의 부담이 줄어들어 개발 속도가 가속화됩니다.</li>
<li><strong>레거시 코드의 즉각적인 해석:</strong> 난해한 레거시 코드를 만나도 AI에게 &quot;이 모듈의 주요 역할과 의존성은 뭐야?&quot;등을 질문하여 <strong>코드 문맥을 빠르게 파악</strong>할 수 있습니다. 이는 시니어 개발자가 상황을 파악하는 속도, 순서와 유사합니다.</li>
</ul>
<h2 id="풀스택-개발-역량-확장">풀스택 개발 역량 확장</h2>
<hr>
<p>현대 개발 환경은 백엔드(Python/Java), 프론트엔드(React/TypeScript), 인프라(YAML/Terraform) 등 다양한 언어와 기술 스택을 요구합니다.</p>
<ul>
<li><strong>다국어(Polyglot) 코드 생성:</strong> 바이브 코더가 주력 언어가 아닌 다른 스택을 다룰 때, AI는 즉시 해당 언어의 <strong>Idiomatic Code(관용적인 코드)</strong>를 생성해 줍니다. 예를 들어, <strong>&quot;TypeScript로 작성된 React 컴포넌트를 Svelte 컴포넌트로 바꿔줘&quot;</strong>와 같은 요청을 통해, 문법 오류에 대한 걱정 없이 새로운 기술 스택을 빠르게 탐색하고 적용할 수 있습니다.</li>
<li><strong>시간 절약:</strong> 레퍼런스 문서를 뒤지며 사소한 문법이나 설정 파일을 찾는 시간을 절약하고, <strong>&quot;문제 해결&quot;</strong>이라는 본질적인 작업에 에너지를 집중할 수 있게 됩니다.</li>
</ul>
<p>결론적으로, AIDD는 주니어에게 <strong>시니어의 지식과 경험을 복사하고, 실수의 불안감을 줄이며, 빠른 속도로 다양한 기술 스택을 경험하게 해주는</strong> 최고의 개발 방법론이자 교육 환경으로 자리잡고 있습니다.</p>
<h1 id="ai-개발-피할-수-없다면-더-똑똑하게-사용하자">AI 개발, 피할 수 없다면 더 똑똑하게 사용하자</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/9bef5e25-ae80-4d3d-af32-8afcf8c83c3b/image.png" alt=""></p>
<p>풀 AI 개발보다는 사람의 손을 많이 탄 개발을 선호하는 사람들은 대개 이유가 명확합니다.</p>
<ol>
<li>유지보수성이 떨어진다.</li>
<li>구조가 뒤죽박죽이다.</li>
</ol>
<p>이 외에도 여러가지가 있을 수 있지만 이 두가지가 대표적이기에 언급해봤습니다.</p>
<p>반대로 생각해보면 이 두 가지만 해결할 경우 반대하는 사람의 과반수는 마음을 돌릴 수 있게 될 것 같습니다. 무작정 AI 도입을 통해 후회하기 보다는, AI를 제대로 활용하는 다양한 방법들을 익히시고 사용하는 연습을 해보면 좋을 것 같습니다.</p>
<p>AI Agent 사용이 익숙하지 않은 개발자분들은 우선 익숙한 <code>Github Copilot</code>으로 코드 부분부분 작성하는 것부터 익숙해지고, 다음은 <code>Gemini CLI</code> 로, 필요하다면 <code>Claude Code</code>, <code>Cursor</code>, 이번에 나온 <code>AntiGravity</code>등등 필요 여부에 따른 툴들로 확장시켜 나가면 좋을 것 같습니다.</p>
<p>더 이상 <strong>“기본기는 진짜 빵빵한”</strong> 개발자는 메리트가 없는 것 같습니다. 기본기는 이제 AI가 훨씬 잘하니까요.</p>
<h1 id="reference">Reference</h1>
<hr>
<ul>
<li><a href="https://onephase.com/en/ai-driven-software-development-speed-efficiency-and-innovation/">https://onephase.com/en/ai-driven-software-development-speed-efficiency-and-innovation/</a></li>
<li><a href="https://www.itworld.co.kr/article/3996306/lg-cns-ai-%EC%BD%94%EB%94%A9-%ED%94%8C%EB%9E%AB%ED%8F%BC-%EB%8D%B0%EB%B8%8C%EC%98%A8-aidd%EB%A1%9C-%EA%B0%9C%EB%B0%9C-%EC%A0%84-%EB%8B%A8%EA%B3%84%EC%97%90-ai-%ED%88%AC%EC%9E%85.html">https://www.itworld.co.kr/article/3996306/lg-cns-ai-%EC%BD%94%EB%94%A9-%ED%94%8C%EB%9E%AB%ED%8F%BC-%EB%8D%B0%EB%B8%8C%EC%98%A8-aidd%EB%A1%9C-%EA%B0%9C%EB%B0%9C-%EC%A0%84-%EB%8B%A8%EA%B3%84%EC%97%90-ai-%ED%88%AC%EC%9E%85.html</a></li>
<li><a href="https://aws.amazon.com/ko/blogs/tech/ai-driven-development-life-cycle/">https://aws.amazon.com/ko/blogs/tech/ai-driven-development-life-cycle/</a></li>
<li><a href="https://medium.com/effortless-programming/better-ai-driven-development-with-test-driven-development-d4849f67e339">https://medium.com/effortless-programming/better-ai-driven-development-with-test-driven-development-d4849f67e339</a></li>
<li><a href="https://dev.to/bain_forge/tdd-and-ai-enabled-engineering-chl">https://dev.to/bain_forge/tdd-and-ai-enabled-engineering-chl</a></li>
<li><a href="https://www.scribd.com/document/705355560/Coding-on-Copilot-2024-Developer-Research">https://www.scribd.com/document/705355560/Coding-on-Copilot-2024-Developer-Research</a></li>
<li><a href="https://tidyfirst.substack.com/p/the-life-changing-magic-of-tidying">https://tidyfirst.substack.com/p/the-life-changing-magic-of-tidying</a></li>
<li><a href="https://medium.com/bgl-tech/what-are-the-solid-design-principles-c61feff33685">https://medium.com/bgl-tech/what-are-the-solid-design-principles-c61feff33685</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트 파악, 이제 그만두세요.]]></title>
            <link>https://velog.io/@playername_ltt/Repo-%ED%8C%8C%EC%95%85%EB%8F%84-%EC%9D%B4%EC%A0%9C%EB%8A%94-AI%ED%95%9C%ED%85%8C-%EB%A7%A1%EA%B8%B0%EB%9D%BC%EA%B3%A0</link>
            <guid>https://velog.io/@playername_ltt/Repo-%ED%8C%8C%EC%95%85%EB%8F%84-%EC%9D%B4%EC%A0%9C%EB%8A%94-AI%ED%95%9C%ED%85%8C-%EB%A7%A1%EA%B8%B0%EB%9D%BC%EA%B3%A0</guid>
            <pubDate>Fri, 14 Nov 2025 09:01:05 GMT</pubDate>
            <description><![CDATA[<p>개발자의 시간을 가장 많이 잡아먹는 건 새 코드 작성이 아닙니다. 바로 <strong>남이 쓴 코드 읽기</strong>죠. Google은 이 문제를 AI로 풀겠다며 <strong>Code Wiki</strong>를 공개 프리뷰로 출시했습니다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/13b24dbf-5edc-4922-a287-659c76fb4028/image.png" alt=""></p>
<p>Google Cloud Developer 팀이 발표한 이 플랫폼은 코드 레포지토리를 스캔해 자동으로 위키 문서를 생성하고, Gemini 기반 챗봇이 이를 활용해 질문에 답합니다. 신입 개발자가 첫날부터 커밋하고, 시니어 개발자가 몇 분 만에 새로운 라이브러리를 파악할 수 있다는 것이 핵심 메시지입니다.</p>
<p>이건 제가 비슷한 아이디어로 고민 중이었는데, 이번에 공개되었다고 해서 아주 흥미롭네요.</p>
<h1 id="왜-code-wiki가-등장했나">왜 Code Wiki가 등장했나</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/1a55cdfc-1bef-48a3-9b08-0c2f777c9f99/image.png" alt=""></p>
<p>현업 개발자라면 누구나 공감하는 세 가지 현실이 있습니다.</p>
<ul>
<li>새 코드 작성보다 기존 코드 이해에 더 많은 시간이 든다.</li>
<li>문서화는 어렵고, 코드는 빠르게 변하며, 문서는 쉽게 낡는다.</li>
<li>설계자 또는 작성자가 떠난 팀에서는 코드의 &quot;의도&quot;가 사라진다.</li>
</ul>
<p>Google은 “코드를 읽는 것이 소프트웨어 개발에서 가장 큰 병목 중 하나”라고 말하며, Code Wiki를 통해 이 문제를 해결하겠다고 선언했습니다.</p>
<h1 id="code-wiki의-핵심-기능">Code Wiki의 핵심 기능</h1>
<hr>
<h3 id="자동-업데이트--지속적-문서화">자동 업데이트 &amp; 지속적 문서화</h3>
<p>Code Wiki는 레포지토리 전체를 스캔해 <strong>코드 변경 시마다 문서를 자동 재생성</strong>합니다.</p>
<p>누군가 수동으로 문서를 고칠 필요가 없으며, 문서가 코드와 엇나가는 상황을 원천적으로 제거합니다.</p>
<h3 id="컨텍스트를-이해하는-gemini-기반-챗봇">컨텍스트를 이해하는 Gemini 기반 챗봇</h3>
<p>Code Wiki는 위키 전체를 Gemini 챗봇의 <strong>지식 베이스</strong>로 사용합니다.</p>
<p>즉, 다음과 같은 질문을 하면:</p>
<ul>
<li>“이 함수는 왜 존재하나요?”</li>
<li>“이 모듈은 어디서 호출되나요?”</li>
<li>“이 버그를 고치려면 어떤 코드를 봐야 하나요?”</li>
</ul>
<p>Gemini는 코드베이스 전체 맥락을 이해하고 문서화된 구조를 활용해 즉각 답합니다.</p>
<h3 id="아키텍처-다이어그램-자동-생성--하이퍼링크-탐색">아키텍처 다이어그램 자동 생성 &amp; 하이퍼링크 탐색</h3>
<p>생성된 문서는 단순 텍스트가 아닙니다.</p>
<ul>
<li>아키텍처 다이어그램</li>
<li>클래스 다이어그램</li>
<li>시퀀스 다이어그램</li>
</ul>
<p>이 모두가 <strong>현재 코드 상태를 반영한 최신 버전으로 자동 생성</strong>됩니다.</p>
<p>또한 문서의 모든 개념은 <strong>코드 파일, 클래스, 함수 정의로 직접 연결되는 하이퍼링크</strong>를 포함합니다.</p>
<p>즉, 문서 → 코드 → 연관 코드로 자연스럽게 이어지는 탐색이 가능합니다.</p>
<h1 id="기존-문서화-도구들과-무엇이-다른가">기존 문서화 도구들과 무엇이 다른가?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/b8c4d90e-eab2-4230-b0a1-0a9e36c2249d/image.png" alt=""></p>
<p>Doxygen, Sphinx, Javadoc 등 기존 도구들이 수십 년간 쓰여 왔습니다.</p>
<p>그러나 그 방식에는 본질적인 한계가 있습니다.</p>
<ol>
<li><p><strong>개발자가 직접 주석을 작성해야 한다.</strong></p>
<p> 주석이 빠지거나 오래되면 문서도 무용지물이 됩니다.</p>
</li>
<li><p><strong>정적 문서 생성 방식.</strong></p>
<p> 코드가 바뀌어도 문서는 그대로라 항상 뒤처지게 됩니다.</p>
</li>
<li><p><strong>문서-코드 간 맥락 단절.</strong></p>
<p> 문서를 읽다가 궁금한 부분이 생기면 직접 코드를 뒤져야 합니다.</p>
</li>
</ol>
<p>Code Wiki는 이 세 가지 문제를 모두 해결합니다.</p>
<ul>
<li>주석 없이 전체 코드베이스 분석</li>
<li>코드 변경 시 문서 자동 업데이트</li>
<li><strong>AI 챗봇 기반 질의응답</strong></li>
<li>문서-코드 하이퍼링크 통합 탐색</li>
</ul>
<h2 id="ai가-당신의-코드베이스를-완전히-아는-상황">AI가 당신의 코드베이스를 &#39;완전히 아는&#39; 상황</h2>
<hr>
<p>Code Wiki의 Gemini는 범용 AI 챗봇과 다릅니다.</p>
<p><strong>코드베이스 전체를 스캔한 뒤 문서화된 위키를 기반으로 답변</strong>합니다.</p>
<p>따라서 다음과 같은 실질적인 활용이 가능합니다.</p>
<ul>
<li>특정 모듈의 동작 흐름 파악</li>
<li>함수 호출 관계 확인</li>
<li>버그가 발생한 코드 경로 추적</li>
<li>특정 기능이 어디에서 구현되었는지 검색</li>
</ul>
<p>단순한 코드 요약이 아니라 <strong>전체 코드 구조·맥락을 고려한 이해</strong>를 제공합니다.</p>
<h2 id="첫날-커밋과-몇-분-만의-구조-파악">첫날 커밋과 몇 분 만의 구조 파악</h2>
<hr>
<p>Google은 Code Wiki의 핵심 가치를 두 가지로 설명합니다.</p>
<h3 id="1-신입-개발자는-day-1-커밋이-가능해진다">1) 신입 개발자는 “Day 1 커밋”이 가능해진다</h3>
<p>레거시 코드, 문서 없는 시스템 앞에서 며칠씩 헤매지 않아도 됩니다.</p>
<p>필요한 내용을 Gemini에 물으며 필요한 코드만 빠르게 파악할 수 있습니다.</p>
<h3 id="2-시니어-개발자는-새로운-라이브러리를-몇-분-만에-파악">2) 시니어 개발자는 새로운 라이브러리를 몇 분 만에 파악</h3>
<p>외부 오픈소스나 신규 라이브러리를 도입할 때 시간을 크게 단축할 수 있습니다.</p>
<p>전체 구조를 빠르게 이해하고 바로 코드에 활용할 수 있죠.</p>
<h2 id="프라이빗-레포지토리도-곧-지원-예정">프라이빗 레포지토리도 곧 지원 예정</h2>
<hr>
<p>현재 Code Wiki는 <strong>공개 오픈소스 레포지토리</strong>만 지원합니다.</p>
<p>그러나 Google은 <strong>Gemini 기반 CLI 확장</strong>을 개발 중이라고 밝혔습니다.</p>
<p>곧 다음이 가능해질 전망입니다.</p>
<ul>
<li>팀 내부 프라이빗 레포지토리에 Code Wiki 적용</li>
<li>사내 네트워크에서 안전하게 실행</li>
<li>레거시 시스템 분석 자동화</li>
</ul>
<p>특히 작성자가 이미 없는 레거시 코드 유지보수에 큰 가치를 제공할 것으로 보입니다.</p>
<h1 id="문서-작성-부담-vs-코드-이해-속도">문서 작성 부담 vs. 코드 이해 속도</h1>
<hr>
<p>개발자들은 오랫동안 두 가지 중 하나를 선택해야 했습니다.</p>
<ul>
<li>문서를 꼼꼼히 작성해 개발 속도를 낮추거나</li>
<li>빠르게 개발하고 문서를 포기하거나</li>
</ul>
<p>Code Wiki는 이 오랜 트레이드오프를 제거합니다.</p>
<p>문서 작성 부담 없이도 문서는 항상 최신 상태를 유지하고,코드를 이해하는 속도는 극적으로 빨라지게 됩니다.</p>
<p>Google이 &quot;개발자는 더 이상 코드를 해독하는 데 시간을 쓰지 말고, 진짜 개발에 집중하라&quot;고 말하는 이유죠.</p>
<p><a href="https://codewiki.google/">Code Wiki</a></p>
<h1 id="개인적인-생각">개인적인 생각</h1>
<hr>
<p>솔직히 개발자가 코드베이스를 이해하는 과정은 늘 반복되지만, 자동화하기 가장 어려운 영역이었습니다. 기존 문서화 도구들이 API 수준의 정적 정보에 머물렀다면, Code Wiki는 코드 전체를 <strong>“읽고 이해하는 주체”</strong>까지 자동화하려는 시도라는 점에서 큰 방향 전환을 보여줍니다.</p>
<p>특히 위키와 챗봇이 하나의 지식 베이스로 통합된 구조는 ‘문서는 사람이 읽는 것’이라는 패러다임을 넘어, ‘문서는 AI가 대신 읽고 설명하는 것’이라는 새로운 형태의 개발 워크플로를 만들어낼 가능성이 있습니다.</p>
<p>다만 아직은 퍼블릭 프리뷰 단계인 만큼 실제 대규모 프라이빗 레포지토리에서 어느 정도 정확도와 속도를 낼지, 팀마다 다른 개발 표준·스타일을 어떻게 처리할지 등은 남아 있는 과제입니다. 또 “문서가 항상 맞다”는 전제를 두기 어려운 초기 버전에서는, AI가 생성한 설명을 신뢰해도 되는지에 대한 검증 체계도 필요합니다.</p>
<p>그럼에도 불구하고, 만약 Code Wiki가 안정적으로 프라이빗 코드베이스까지 지원하게 된다면, 개발자 온보딩이나 레거시 시스템 유지보수 같은 오랜 난제가 실질적으로 해소될 가능성이 있습니다. 결국 문서화를 위해 시간을 투자하는 대신, <strong>문서화를 자동화해 버리고 개발 자체에 더 집중하는 흐름</strong>이 주류가 될지도 모르겠습니다.</p>
<h1 id="reference">Reference</h1>
<hr>
<ul>
<li><a href="https://developers.googleblog.com/en/introducing-code-wiki-accelerating-your-code-understanding/">https://developers.googleblog.com/en/introducing-code-wiki-accelerating-your-code-understanding</a></li>
<li><a href="https://codewiki.google/">https://codewiki.google/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[바이브 코딩이 죽어가고 있다?]]></title>
            <link>https://velog.io/@playername_ltt/%EB%B0%94%EC%9D%B4%EB%B8%8C-%EC%BD%94%EB%94%A9%EC%9D%98-%ED%98%84%EC%A3%BC%EC%86%8C%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@playername_ltt/%EB%B0%94%EC%9D%B4%EB%B8%8C-%EC%BD%94%EB%94%A9%EC%9D%98-%ED%98%84%EC%A3%BC%EC%86%8C%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 24 Oct 2025 02:02:48 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/34fd69ab-e4f3-4226-94de-3860273e97f6/image.jpg" alt=""></p>
<h1 id="개요">개요</h1>
<hr>
<p>지속적으로 ‘바이브 코딩(Vibe Coding)’이라는 용어가 뜨겁습니다. 개발자가 직접 코드 타이핑하는 대신, 자연어 프롬프트나 AI 모델에게 “이런 기능 만들어줘”라고 말하면 코드가 생성되는 방식입니다. 하지만 <strong>Gary Marcus</strong>는 최근 글에서 이 흐름이 “아마도 끝을 향해 가고 있다”는 관점에서 논의를 펼칩니다.</p>
<p><a href="https://garymarcus.substack.com/p/is-vibe-coding-dying">https://garymarcus.substack.com/p/is-vibe-coding-dying</a></p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/53f5e191-9dd5-4a22-8617-7dd01ce66eab/image.png" alt=""></p>
<p>이 글에서는 그 글의 주요 논점과 기술적 함의, 그리고 우리가 개발자로서 고려할 변화들을 정리해보겠습니다.</p>
<h1 id="바이브-코딩이란-무엇인가">바이브 코딩이란 무엇인가?</h1>
<hr>
<p>먼저 개념 정의부터 짚고 넘어가겠습니다.</p>
<ul>
<li><p>용어의 기원: <strong>Andrej Karpathy</strong>가 2025년 2월에 제안한 개념으로, 개발자가 직접 코드 라인을 작성하기보다는 “감(바이브)”에 따라 AI에게 기능을 설명하면 코드가 자동으로 생성되는 방식입니다.</p>
</li>
<li><p>핵심 특징:</p>
<ul>
<li>자연어 또는 비교적 고수준의 설명으로 기능을 요청</li>
<li>생성된 코드를 사람이 <strong>라인 단위로 설계하거나 전통적 방식으로 구현</strong>하지 않고 실행 결과 중심으로 검토</li>
<li>빠른 프로토타이핑, 비전문가도 어느 정도 기능 구현 가능성 확보</li>
</ul>
</li>
<li><p>기대 효과:</p>
<ul>
<li>코딩 진입 장벽 감소</li>
<li>아이디어 → 실행 빠르게 전환 가능</li>
<li>스타트업이나 프로토타입 단계에서 소규모 팀으로도 기능 구현 가능</li>
</ul>
</li>
</ul>
<p>하지만 동시에 다음과 같은 경고도 병존합니다.</p>
<ul>
<li>코드 품질·유지보수성 저하 위험</li>
<li>설계·아키텍처 이해 부족 → 디버깅 및 확장 시 골치 아픔</li>
<li>보안 및 신뢰성 우려</li>
</ul>
<h1 id="바이브-코딩이-죽어가고-있다">“바이브 코딩이 죽어가고 있다?”</h1>
<hr>
<p>Marcus는 글에서 두 가지 주장을 중심으로 논의를 펼칩니다.</p>
<ol>
<li><p><strong>아마추어가 팀 코더를 대체하지 못할 것</strong></p>
<p> Marcus는 제목에서도 “Amateurs might <strong>not</strong> be replacing teams of coders, after all.”라고 말합니다.</p>
<p> 즉, 바이브 코딩이 비전문가나 아마추어에 의해 기존의 엔지니어링 집단을 대체할 것이란 기대는 과장되었다는 입장입니다.</p>
</li>
<li><p><strong>용도는 제한적이고, ‘생산 시스템’으로는 한계가 있다</strong></p>
<p> 그는 다음과 같이 지적합니다:</p>
<blockquote>
<p>“Vibe coding can be fine if you are building something very familiar, but…”</p>
<p>즉, 익숙한 기능·패턴이라면 바이브 코딩으로 빠르게 구현할 수 있지만, 복잡하거나 새로운 시스템 설계·아키텍처를 요구하는 상황에서는 한계가 드러난다는 이야기입니다.</p>
</blockquote>
</li>
</ol>
<p>이 두 주장으로부터 그는 다음과 같은 의미 있는 시사점을 도출합니다.</p>
<ul>
<li>바이브 코딩을 통해 만들어진 제품이나 코드베이스의 <strong>책임 소재</strong>와 <strong>유지보수 가능성</strong>이 문제될 수 있다.</li>
<li>AI가 자동으로 코딩해주는 것처럼 보이지만, 실제로는 사람이 이해하고 설계하며 운영할 수 있어야 한다는 엔지니어링 본질이 사라질 위험이 있다.</li>
<li>따라서 “바이브 코딩 → 코드 생산 → 팀 불필요”라는 흐름은 현실적으로는 매끄럽지 않다는 경고입니다.</li>
</ul>
<h1 id="왜-바이브-코딩이-지금-끝물이라는-평가인가">왜 바이브 코딩이 지금 ‘끝물’이라는 평가인가?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/41d1c131-fb0c-482c-8be4-5378bf69da94/image.png" alt=""></p>
<p>Marcus의 주장을 기술 트렌드 및 현장 목소리와 연관지어 보면 몇 가지 이유가 보입니다.</p>
<h3 id="1-코드의-이해-가능성-문제">1. 코드의 <strong>이해 가능성</strong> 문제</h3>
<p>AI가 생성한 코드라 해도 결국 사람이 유지보수해야 할 가능성이 높습니다. 그는 “코드를 이해하지 못하는 상태에서 코드베이스를 넘겨받는 것은 자산이 아니라 오히려 부채(liability)”라는 표현을 사용합니다.</p>
<p>즉, 바이브 코딩 방식은 초기 속도는 빠를지 몰라도 장기적 관점에서 문제를 일으킬 수 있다는 뜻입니다.</p>
<h3 id="2-복잡한-시스템·아키텍처에서의-한계">2. 복잡한 시스템·아키텍처에서의 한계</h3>
<p>단순 기능, 익숙한 패턴이라면 AI 코드 생성이 유리하지만, 기존 시스템과의 통합, 비정형 요구사항, 성능 튜닝, 운영·보안 고려 등이 중요한 경우에는 여전히 사람이 주도해야 합니다. Marcus가 이 부분을 강조하고 있습니다.</p>
<h3 id="3-스타트업·초기-프로덕트에서는-가능했지만-스케일업에는-갭이-있다">3. 스타트업·초기 프로덕트에서는 가능했지만 스케일업에는 갭이 있다</h3>
<p>실제로는 일부 신생 스타트업들이 “코드의 95 %가 AI 생성”이라는 사례도 나왔지만, 그 이후 유지보수·확장 과정에서 어려움을 겪고 있다는 보고도 존재합니다.</p>
<p>즉, 바이브 코딩은 ‘아이디어 → 빠르게 기능 확보’의 목적에는 적합하지만, ‘100 만 유저 이상’ 수준의 서비스 안정성 확보 단계에서는 그 효과가 제한적이라는 평가입니다.</p>
<h1 id="그렇다면-개발자와-기업은-어떻게-해야-하나">그렇다면 개발자와 기업은 어떻게 해야 하나?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/ad998c81-41f6-4727-a83d-d69ae14ecba6/image.png" alt=""></p>
<p>Marcus의 글에서 시사되는 실전 과제를 요약하면 다음과 같습니다.</p>
<h3 id="바이브-코딩을-보완적-수단으로-활용">바이브 코딩을 보완적 수단으로 활용</h3>
<p>바이브 코딩이 “코딩을 완전히 대체”하는 방식이 되기보다는,</p>
<ul>
<li><p>빠른 프로토타이핑</p>
</li>
<li><p>아이디어 검증 (MVP)</p>
</li>
<li><p>반복 실험 및 초기 사용자 흐름 점검</p>
<p>  등에서 유리합니다. 하지만 이후에는 전통적 소프트웨어 엔지니어링 방식(설계·코드리뷰·테스트·운영)이 필수입니다.</p>
</li>
</ul>
<h3 id="코드-이해·설계-역량-유지">코드 이해·설계 역량 유지</h3>
<p>AI가 자동으로 코드를 생성하더라도 코드의 <strong>구조, 흐름, 성능, 보안</strong>을 이해할 수 있어야 합니다. Marcus는 “아마추어가 팀을 대체할 수 없다”는 이유로 이 부분을 강조합니다.</p>
<p>따라서 개발자는 프롬프트 입력만 할 뿐 아니라 생성된 코드를 검토하고 이해하는 역량을 유지해야 합니다.</p>
<h3 id="품질·유지보수·보안-체크리스트-마련">품질·유지보수·보안 체크리스트 마련</h3>
<p>특히 아래 이슈들에 대비해야 합니다.</p>
<ul>
<li><p>코드가 <strong>블랙박스화</strong>되어 내부가 보이지 않는 위험</p>
</li>
<li><p>버그, 보안취약점이 숨어 있을 가능성</p>
</li>
<li><p>AI가 생성한 코드가 조직·팀의 표준에 맞지 않을 수 있음</p>
<p>  논문에서도 “속도 대비 품질 트레이드오프”가 존재한다는 결과가 나왔습니다.</p>
</li>
</ul>
<h3 id="조직·프로세스-변화-대비">조직·프로세스 변화 대비</h3>
<p>바이브 코딩이 유행하면서 팀 구성·역할·프로세스도 변화하고 있습니다. 하지만 Marcus의 논점처럼 “기존 팀 + 숙련된 개발자” 구조는 아직 유효합니다.</p>
<p>기업은</p>
<ul>
<li>AI 코드 생성 도구를 도입하되</li>
<li>코드 리뷰 및 아키텍처 설계 역량을 갖춘 인재를 유지하고</li>
<li>AI가 만든 코드를 운영 가능한 상태로 전환할 수 있는 프로세스를 설계해야 합니다.</li>
</ul>
<h1 id="요약-및-결론">요약 및 결론</h1>
<hr>
<ul>
<li>바이브 코딩은 개발 방식에 꽤 큰 변화를 가져왔습니다.</li>
<li>하지만 Gary Marcus는 이 방식이 <strong>기존 코더 집단을 아마추어가 완전 대체한다는 기대는 현실적이지 않다</strong>고 지적합니다.</li>
<li>즉, “바이브 코딩 → 개발자 필요 없음”이라는 흐름은 과장된 면이 있습니다.</li>
<li>개발자, 스타트업, 기업 모두 이 변화를 맞아 <strong>속도만 좇기보다는 품질·이해·유지보수성</strong>을 동시에 고려해야 합니다.</li>
<li>따라서 바이브 코딩은 <strong>도구(tool)</strong>이지, <strong>체계(system)</strong> 그 자체가 아닙니다.</li>
<li>앞으로는 <em>AI가 생성한 코드 + 사람이 설계·운영하는 구조</em>가 표준이 될 가능성이 높습니다.</li>
</ul>
<h1 id="개인적인-내-생각">개인적인 내 생각</h1>
<hr>
<p>바이브 코딩을 둘러싼 논의는 단순히 “이 기술이 죽었는가, 살아 있는가”의 문제는 아닌 것 같습니다.</p>
<p>최근 “바이브 워킹(Vibe Working)”이라는 개념이 함께 언급되고 있는 것처럼, <strong>‘바이브’라는 흐름 자체</strong>는 여전히 유효합니다.</p>
<p>이는 단순히 코드를 자동으로 생성하는 기술적 이슈를 넘어, <strong>일의 방식이 변화하고 있음을 상징하는 키워드</strong>로 볼 수 있습니다.</p>
<p>따라서 “바이브 코딩이 죽었다”는 표현은, 단어 의미 그대로 받아들일 문제는 아닙니다.</p>
<p>오히려 기술의 초점이 <strong>‘코드를 빠르게 만드는 것’에서 ‘AI와 함께 일하는 방식’</strong>으로 옮겨가고 있다고 생각합니다.</p>
<p>둘째로, 바이브 코딩이 효율적이라 하더라도, <strong>AI가 생성한 코드를 이해하고 유지보수하려는 태도</strong>는 여전히 필요합니다.</p>
<p>AI가 자동으로 만들어주는 코드를 “그냥 작동하니까 됐다”로 끝내면, 결국 시스템의 근본을 잃게 됩니다.</p>
<p>결국 진짜 실력은 <strong>AI가 만든 코드를 해석하고, 수정하며, 책임질 수 있는 능력</strong>에서 드러납니다.</p>
<p>마지막으로, 바이브 코딩 시대에는 <strong>올바른 설계 역량</strong>이 더욱 중요해졌습니다.</p>
<p>AI는 요청한 대로 코드를 만들어주지만, <strong>무엇을 요청할지, 어떤 구조로 설계할지</strong>는 전적으로 사람의 몫입니다.</p>
<p>즉, 코드를 치는 능력보다 <strong>문제를 정의하고 구조화하는 능력</strong>, 그리고 <strong>AI를 협업 파트너로 이끌 수 있는 설계 감각</strong>이 새로운 경쟁력이 될 것입니다.</p>
<p>결국, 바이브 코딩은 “AI가 인간을 대체하는 시대”의 상징이 아니라,</p>
<blockquote>
<p>인간이 AI를 통해 더 나은 방식으로 사고하고 일하는 시대의 시작</p>
</blockquote>
<p>이라고 생각합니다.</p>
<h1 id="reference">Reference</h1>
<hr>
<ul>
<li><a href="https://garymarcus.substack.com/p/is-vibe-coding-dying">https://garymarcus.substack.com/p/is-vibe-coding-dying</a></li>
<li><a href="https://en.wikipedia.org/wiki/Vibe_coding">https://en.wikipedia.org/wiki/Vibe_coding</a></li>
<li><a href="https://arxiv.org/abs/2509.12491">https://arxiv.org/abs/2509.12491</a></li>
<li><a href="https://www.businessinsider.com/vibe-coding-wont-replace-software-engineers-openai-research-bob-mcgrew-2025-6">https://www.businessinsider.com/vibe-coding-wont-replace-software-engineers-openai-research-bob-mcgrew-2025-6</a></li>
<li><a href="https://arxiv.org/abs/2510.00328">https://arxiv.org/abs/2510.00328</a></li>
<li><a href="https://www.chosun.com/economy/tech_it/2025/10/20/KNE65PSSNBHOTHFHZULHDMVRIE/">https://www.chosun.com/economy/tech_it/2025/10/20/KNE65PSSNBHOTHFHZULHDMVRIE/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python 환경 관리 가이드]]></title>
            <link>https://velog.io/@playername_ltt/%ED%97%B7%EA%B0%88%EB%A6%AC%EB%8A%94-Python-%ED%99%98%EA%B2%BD-%EA%B4%80%EB%A6%AC-%EA%B0%80%EC%9D%B4%EB%93%9C</link>
            <guid>https://velog.io/@playername_ltt/%ED%97%B7%EA%B0%88%EB%A6%AC%EB%8A%94-Python-%ED%99%98%EA%B2%BD-%EA%B4%80%EB%A6%AC-%EA%B0%80%EC%9D%B4%EB%93%9C</guid>
            <pubDate>Tue, 21 Oct 2025 05:49:20 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/bfafbf15-8d87-42f8-a56e-98c094debba1/image.png" alt=""></p>
<p>Python을 조금만 깊게 써보면, 누구나 한 번쯤 이런 생각을 한다.</p>
<blockquote>
<p>“venv, pipenv, pyenv... 대체 뭐가 다르고, 뭐부터 써야 하지?”</p>
</blockquote>
<p>이 세 가지는 이름이 비슷해서 헷갈렸었는데, <strong>역할이 전혀 달랐다.</strong></p>
<blockquote>
<p>pyenv → Python 버전 관리</p>
<p><code>venv</code> / <code>pipenv</code> → 가상환경(패키지 격리)을 관리</p>
</blockquote>
<h1 id="pyenv">pyenv</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/1300e03f-7208-4971-b657-aee273c91b7f/image.png" alt=""></p>
<p><code>pyenv</code>는 여러 버전의 Python을 설치하고 전환할 수 있는 <strong>버전 관리 도구</strong>이다.</p>
<p>프로젝트마다 다른 Python 버전을 써야 할 때 필수적이다.</p>
<p><a href="https://github.com/pyenv/pyenv">https://github.com/pyenv/pyenv</a></p>
<p>예를 들어,</p>
<ul>
<li>프로젝트 A: Python 3.8</li>
<li>프로젝트 B: Python 3.12</li>
</ul>
<p>이런 경우 시스템 Python 하나로는 관리하기 어렵다.</p>
<p>이럴 때 사용하는 게 <code>pyenv</code>이다. 이걸 활용하면 쉽게 버전 전환이 가능하다.</p>
<h3 id="주요-명령어">주요 명령어</h3>
<pre><code class="language-bash">pyenv install 3.12.3  # 특정 버전 설치
pyenv global 3.12.3   # 전역 기본 버전 지정
pyenv local 3.10.9    # 현재 디렉토리에만 적용</code></pre>
<p>자세한 건 공식 문서나 블로그를 참고하면 된다.</p>
<h3 id="언제-쓰면-좋은가">언제 쓰면 좋은가</h3>
<ul>
<li>여러 버전의 Python을 테스트하거나 유지보수해야 할 때</li>
<li>시스템 Python을 건드리고 싶지 않을 때</li>
<li>macOS, Ubuntu 등에서 Python 버전 충돌이 자주 날 때</li>
</ul>
<h1 id="venv">venv</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/0685d4f3-6452-4c0a-bba2-fe5b45ecf4f8/image.png" alt=""></p>
<p><code>venv</code>는 <strong>Python 표준 라이브러리에 포함된 가상환경 도구</strong>다.</p>
<p>쉽게 말해, “프로젝트마다 패키지를 따로 관리”할 수 있게 해준다.</p>
<p><a href="https://docs.python.org/3/library/venv.html">https://docs.python.org/3/library/venv.html</a></p>
<p>예를 들어,</p>
<ul>
<li>프로젝트 A에서 <code>Django 3.2</code></li>
<li>프로젝트 B에서 <code>Django 5.0</code></li>
</ul>
<p>이렇게 버전이 다를 때, <code>venv</code>를 쓰면 서로 영향을 주지 않는다.</p>
<h3 id="기본-사용법">기본 사용법</h3>
<pre><code class="language-bash">python -m venv venv         # 가상환경 생성
source venv/bin/activate    # macOS / Linux
venv\Scripts\activate       # Windows
deactivate                  # 비활성화</code></pre>
<h3 id="장점">장점</h3>
<ul>
<li>Python 3.3 이상 기본 내장 (추가 설치 불필요)</li>
<li>가볍고 단순함</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li><code>requirements.txt</code>를 직접 관리해야 함</li>
<li>의존성 잠금(lock) 기능이 없음</li>
</ul>
<h1 id="pipenv">pipenv</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/1bcf63b2-36b5-4aac-a3b4-bb525a538a2a/image.png" alt=""></p>
<p><code>pipenv</code>는 <code>venv</code> + <code>pip</code> + 의존성 관리(<code>Pipfile</code>)를 한 번에 해결하는 도구다.</p>
<p>즉, <strong>가상환경 생성부터 패키지 버전 고정까지 자동으로 관리</strong>해준다.</p>
<p><a href="https://pypi.org/project/pipenv/">https://pypi.org/project/pipenv/</a></p>
<p><a href="https://pipenv.pypa.io/en/latest/">https://pipenv.pypa.io/en/latest/</a></p>
<pre><code class="language-bash">pipenv install requests     # 패키지 설치 + 가상환경 자동 생성
pipenv shell                # 가상환경 진입
pipenv uninstall requests   # 패키지 제거
pipenv lock                 # 의존성 잠금 파일 생성</code></pre>
<h3 id="구조">구조</h3>
<ul>
<li><code>Pipfile</code> → 설치할 패키지 목록</li>
<li><code>Pipfile.lock</code> → 정확한 버전 고정 (재현 가능한 환경 보장)</li>
</ul>
<h3 id="장점-1">장점</h3>
<ul>
<li>의존성 관리 자동화</li>
<li>Python 버전 지정 가능 (<code>Pipfile</code> 내 <code>python_version</code>)</li>
<li>CI/CD 환경에서 재현성 보장</li>
</ul>
<h3 id="단점-1">단점</h3>
<ul>
<li>약간 느림</li>
<li>최근에는 <code>poetry</code>로 대체되는 추세</li>
</ul>
<h1 id="정리">정리</h1>
<hr>
<h2 id="비교-요약표">비교 요약표</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>pyenv</th>
<th>venv</th>
<th>pipenv</th>
</tr>
</thead>
<tbody><tr>
<td>주요 기능</td>
<td>Python 버전 관리</td>
<td>가상환경 관리</td>
<td>가상환경 + 패키지 관리</td>
</tr>
<tr>
<td>설치 필요</td>
<td>O</td>
<td>X (기본 내장)</td>
<td>O</td>
</tr>
<tr>
<td>관리 단위</td>
<td>Python 인터프리터</td>
<td>프로젝트</td>
<td>프로젝트</td>
</tr>
<tr>
<td>버전 고정 파일</td>
<td><code>.python-version</code></td>
<td><code>requirements.txt</code></td>
<td><code>Pipfile</code>, <code>Pipfile.lock</code></td>
</tr>
<tr>
<td>대체 도구</td>
<td>asdf, conda</td>
<td>virtualenv</td>
<td>poetry</td>
</tr>
</tbody></table>
<hr>
<h2 id="실제-조합-예시">실제 조합 예시</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>추천 조합</th>
</tr>
</thead>
<tbody><tr>
<td>단순 개인 프로젝트</td>
<td><code>venv</code></td>
</tr>
<tr>
<td>협업 / 회사 프로젝트</td>
<td><code>pipenv</code> 또는 <code>poetry</code></td>
</tr>
<tr>
<td>여러 Python 버전 병행</td>
<td><code>pyenv + venv</code></td>
</tr>
<tr>
<td>안정적이고 깔끔한 환경 구성</td>
<td><code>pyenv + pipenv</code></td>
</tr>
</tbody></table>
<h1 id="결론">결론</h1>
<hr>
<p>Python 환경 관리 도구는 다양하지만, 결국 목표는 하나다.</p>
<blockquote>
<p>“내 개발환경을 깨끗하게, 예측 가능하게 유지하기.”</p>
</blockquote>
<p>처음엔 <code>venv</code>만으로도 충분하다.</p>
<p>하지만 프로젝트가 커지고 협업이나 배포가 필요해지면, <code>pipenv</code>나 <code>poetry</code>로 확장해보자.</p>
<p>그리고 여러 버전의 Python을 다뤄야 한다면 <code>pyenv</code>를 꼭 함께 쓰는 걸 추천한다.</p>
<h1 id="개인적으로-추천하는-세팅">개인적으로 추천하는 세팅</h1>
<hr>
<blockquote>
<p>💡 pyenv + pipenv 조합</p>
</blockquote>
<ul>
<li><code>pyenv</code> → Python 버전 제어</li>
<li><code>pipenv</code> → 가상환경 및 패키지/의존성 관리</li>
<li><code>Pipfile</code> 기반이라 재현성과 협업 환경에 유리</li>
</ul>
<pre><code class="language-bash">pyenv install 3.12.3
pyenv local 3.12.3
pipenv install requests
pipenv shell</code></pre>
<p>이 조합은 <strong>버전 충돌 걱정 없이</strong>,</p>
<p><strong>패키지 관리와 환경 격리까지 한 번에 해결할 수 있는</strong> 가장 현실적인 Python 개발 세팅이라고 생각한다.</p>
<p>질문과 피드백은 언제나 환영입니다. :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[타임 박싱에 대해 알고 있나요?]]></title>
            <link>https://velog.io/@playername_ltt/%ED%83%80%EC%9E%84-%EB%B0%95%EC%8B%B1%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EA%B3%A0-%EC%9E%88%EB%82%98%EC%9A%94</link>
            <guid>https://velog.io/@playername_ltt/%ED%83%80%EC%9E%84-%EB%B0%95%EC%8B%B1%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EA%B3%A0-%EC%9E%88%EB%82%98%EC%9A%94</guid>
            <pubDate>Tue, 14 Oct 2025 08:11:28 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/f79e8853-154c-403a-94a9-6bd698e6be5c/image.png" alt=""></p>
<h1 id="introduce">Introduce</h1>
<hr>
<p>이건 대문자 J인 제가 놀 시간을 확실하게 갖고 싶어 도입하게 된 시간 관리법에 대한 이야기입니다.</p>
<p>많이들 사용하는 TODO리스트는 오늘 해야 할 일을 지정해줄 뿐, 이를 효율적으로 처리하기 위한 시간배분을 확인하기 쉽지 않습니다.</p>
<p>오늘 해야 할 일이 많지만, 왜 정작 중요한 일은 잘 끝내지 못할까? 계획을 세워도 미뤄지고, 메일·카톡·알람에 정신이 팔린 경험이 있을 거예요. 이럴 때 <strong>‘타임 박싱’</strong>이라는 방법을 쓰면 시간과 집중력을 동시에 관리할 수 있습니다.</p>
<h1 id="⌛타임박싱이란">⌛타임박싱이란?</h1>
<hr>
<p><strong>타임 박싱</strong>은 ‘이 일은 25분만 하고 쉬자’, ‘오전 10시~11시는 블로그 글쓰기’처럼 ‘얼마 동안만 한다’고 미리 시간 단위를 정해두고 실행하는 방법입니다. </p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/ed72a419-dbd4-44bb-a441-87e4e9af9f33/image.png" alt=""></p>
<p>오늘의 목표를 설정하고, 이를 시각화하여 시간 계획을 작성하는 방법입니다.</p>
<p>일반적으로 사용하는 TODO 리스트보다, 시간이라는 강제력이 생겨 집중력이 훨씬 높아집니다.</p>
<p>두 번째 기대 효과는 <strong>‘개인 역량 파악’</strong>입니다.</p>
<p>계획했던 타임 박스와 실제 소요된 시간을 비교하면, 어떤 종류의 업무를 할 때 내가 <strong>예상보다 여유로운지</strong>, 혹은 <strong>시간이 부족한지</strong>를 수치로 확인할 수 있습니다. 이를 통해 자신의 일 처리 속도와 집중 패턴을 객관적으로 파악하고, 이후 일정 계획을 더욱 현실적으로 조정할 수 있습니다.</p>
<p>이 기법은 개인적으로만 사용해도 좋지만, 만약 팀원과 함께 ‘타임 박싱 캘린더’를 공유하게 된다면 효율적으로 업무시간을 분배하여 작업할 수 있습니다. 일정과 관련된 커뮤니케이션을 최소화할 수 있기 때문이죠.</p>
<h1 id="📜적용-방법">📜적용 방법</h1>
<hr>
<p>기본적으로 ‘타임 박싱’ 기법을 적용해보는 것은 간단합니다. 저는 아래와 같은 순서로 적용해보는 것을 추천합니다.</p>
<ol>
<li><strong>작업 리스트 작성 :</strong> 오늘/이번 주 해야 할 일들을 모두 적기</li>
<li><strong>시간 단위 설정 :</strong> 15분, 30분, 1시간 등 집중할 시간 블록을 정하기</li>
<li><strong>작업 배치 :</strong> 중요한 일부터, 집중도가 필요한 일부터 시간 블록에 배치</li>
<li><strong>시간 알람 활용 :</strong> 타이머, 스마트폰, PC 앱 등을 활용해 시간 초과 방지 (뽀모도로 타이머 등)</li>
<li><strong>회고 &amp; 조정 :</strong> 실제 걸린 시간과 계획 시간 비교, 다음 계획에 반영</li>
</ol>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/8a932d56-3e92-4bdd-9f4b-dec1d99981d8/image.png" alt=""></p>
<p>이건 제 예시입니다. 구글 캘린더를 쓰는 것을 추천드립니다. 휴대폰, 노트북과 연동하기도 편하거든요.</p>
<p>우선 저는 업무는 ‘일 단위’로, 사이드 프로젝트 등 자기계발 활동은 ‘주 단위’로 시간계획을 작성합니다. 하달받은 업무는 리스트업해 두었다가 여유시간에 타임박싱합니다.</p>
<p>개인별로 편차는 있겠지만 위와 같은 순서로 적용해본다면 괜찮을 것이라 생각합니다. 물론 처음엔 어색하고 시간계획을 작성하는 것이 쉽지 않을 수 있겠지만요.</p>
<h2 id="⚠️-타임-박싱의-함정과-팁">⚠️ 타임 박싱의 함정과 팁</h2>
<hr>
<ul>
<li>너무 빡빡하게 짜면 금방 지칩니다. 완벽주의는 버리고, 70% 완성으로도 괜찮다는 마음가짐이 필요합니다.</li>
<li>예기치 않은 일이 생길 수 있으니, 하루 중 한두 블록은 <strong>‘버퍼(예비 시간)’</strong>으로 남겨두세요.</li>
<li>‘집중 블록’ 사이에는 반드시 <strong>짧은 휴식</strong>을 넣으세요. 25분 일하고 5분 쉬는 <strong>포모도로 방식</strong>이 대표적입니다.</li>
</ul>
<h1 id="마무리">마무리</h1>
<hr>
<p>타임 박싱은 단순히 시간을 쪼개는 기술이 아닙니다. 말 그대로 <strong>‘시간을 다루는 습관’을 만드는 방법</strong>이에요.</p>
<p>처음에는 조금 귀찮게 느껴지실 수도 있어요. “이걸 꼭 다 적어야 하나?” 하고 생각하실 수도 있고요.</p>
<p>하지만 일주일만 꾸준히 해보시면, 하루의 밀도가 확실히 달라지는 걸 느끼실 겁니다.</p>
<p>예전에는 시간에 쫓기면서 허둥지둥 일하셨다면, 이제는 하루를 <strong>직접 설계하고 주도하는 느낌</strong>을 받으실 수 있어요. 머릿속에서 엉켜 있던 해야 할 일들이 퍼즐처럼 딱 맞아떨어지는 경험도 하시게 될 거고요.</p>
<p>타임 박싱은 단순히 열심히 하는 게 아니라, <strong>현명하게 일하는 습관</strong>을 만드는 방법입니다.</p>
<p>오늘 하루도 그냥 흘려보내지 마시고, 내 시간을 직접 디자인해보세요. 엄청 추천드립니다. :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[트러블슈팅] PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException 해결]]></title>
            <link>https://velog.io/@playername_ltt/%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85-PKIX-path-building-failed-sun.security.provider.certpath.SunCertPathBuilderException-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@playername_ltt/%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85-PKIX-path-building-failed-sun.security.provider.certpath.SunCertPathBuilderException-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Mon, 29 Sep 2025 06:22:28 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/29f81ed3-aafa-405f-a4b3-7fa1b2d082db/image.png" alt=""></p>
<h1 id="에러-분석">에러 분석</h1>
<hr>
<p>https 통신을 위해 로컬에서 자체 서명 인증서를 사용하여 개발하고 있었다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/53a7dc5f-37aa-41dd-a372-986e8370f78a/image.png" alt=""></p>
<p><code>WebClient</code>로 다른 서버를 호출하니 위와 같이 에러가 발생했다.</p>
<pre><code>javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:378)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:316)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1351)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1226)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1169)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:396)
&lt;28 folded frames&gt;</code></pre><p>여기서 핵심적으로 볼 파트는 여기다.</p>
<blockquote>
<p>unable to find valid certification path to requested target</p>
</blockquote>
<p>요청한 서버의 SSL 인증서 검증 과정에서 서버 인증서를 신뢰할 수 없어서 발생하는 문제이다.</p>
<p>즉, WebClient가 요청을 보내는 대상 서버의 SSL 인증서가 신뢰할 수 있는 <code>CA(Certificate Authority)</code>로 서명되어 있지 않거나, 로컬 JVM의 <code>cacerts</code>(truststore)에 해당 인증서 체인이 등록되어 있지 않아서 생긴 문제이다.</p>
<h1 id="문제-해결">문제 해결</h1>
<hr>
<pre><code class="language-java">@Configuration
@RequiredArgsConstructor
public class WebClientConfig {
    private final String API_KEY_HEADER = &quot;X-API-KEY&quot;;

    @Bean(name = &quot;formatWebClient&quot;)
    public WebClient formatWebClient() throws SSLException {
            // --- 이부분 추가 ---
        SslContext sslContext = SslContextBuilder
                .forClient()
                .trustManager(InsecureTrustManagerFactory.INSTANCE)
                .build();

        HttpClient httpClient = HttpClient.create()
                .secure(ssl -&gt; ssl.sslContext(sslContext));
            // ---

        return WebClient.builder()
                .baseUrl(&quot;&lt;Other Server&#39;s baseURL&gt;&quot;)
                .defaultHeader(API_KEY_HEADER, apiKeyProvider.getEncryptedApiKey())
                            // --- 이부분 추가 ---
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                            // ---
                .filter((request, next) -&gt; next.exchange(request)
                        .flatMap(response -&gt; {
                            if (response.statusCode().isError()) {
                                return response.bodyToMono(String.class)
                                        .defaultIfEmpty(&quot;Unknown error&quot;)
                                        .flatMap(body -&gt; {
                                            log.error(&quot;API Error Response: {}&quot;, body);
                                            return Mono.error(new RuntimeException(&quot;INTERNAL_SERVER_ERROR&quot;));
                                        });
                            } else {
                                return Mono.just(response);
                            }
                        })
                )
                .build();
    }
}</code></pre>
<p>위와 같이 <strong>WebClientConfig</strong>를 설정해주었다. 물론 권장되는 방법은 아니다.</p>
<pre><code class="language-java">SslContext sslContext = SslContextBuilder
        .forClient()
        .trustManager(InsecureTrustManagerFactory.INSTANCE)
        .build();

HttpClient httpClient = HttpClient.create()
        .secure(ssl -&gt; ssl.sslContext(sslContext));</code></pre>
<p>위의 코드는 코드레벨에서 SSL 검증을 무시하는 코드이다. Spring WebClient에 <code>HttpClient</code>를 커스터마이징해서 SSL 검증을 끈 것이다. 즉, 모든 SSL 인증서를 신뢰한다는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/8e12f57e-ba1d-4700-aab0-93706aa42358/image.png" alt=""></p>
<p>이런 코드가 보안상 좋을 리가 없다. 그래서 테스트 또는 내부망에서만 사용해야 한다.</p>
<p>호출할 서버가 현재 이 서버만 거쳐서(내부망에서만 이용) 이렇게 작성하고 끝내도 괜찮았다.</p>
<p>하지만 JAVA 인증서 저장소에 인증서를 등록하여 해결하고 싶다면</p>
<p><a href="https://ssow93.tistory.com/73">https://ssow93.tistory.com/73</a></p>
<p>위의 블로그 글을 참고해봐도 괜찮을 것 같다.</p>
<h1 id="reference">Reference</h1>
<hr>
<ul>
<li><a href="https://sentry.io/answers/how-to-solve-pkix-path-building-failed-error-in-java/">https://sentry.io/answers/how-to-solve-pkix-path-building-failed-error-in-java/</a></li>
<li><a href="https://spring.io/blog/2023/06/07/securing-spring-boot-applications-with-ssl">https://spring.io/blog/2023/06/07/securing-spring-boot-applications-with-ssl</a></li>
<li><a href="https://howtodoinjava.com/java/java-security/bypass-ssl-certificate-checking-java/">https://howtodoinjava.com/java/java-security/bypass-ssl-certificate-checking-java/</a></li>
<li><a href="https://www.sslcert.co.kr/guides/kb/47">https://www.sslcert.co.kr/guides/kb/47</a></li>
</ul>
<p>질문과 피드백은 언제나 환영입니다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[FastAPI를 배포하는 과정과 트러블슈팅]]></title>
            <link>https://velog.io/@playername_ltt/FastAPI%EB%A5%BC-%EB%B0%B0%ED%8F%AC%ED%95%98%EB%8A%94-%EA%B3%BC%EC%A0%95%EA%B3%BC-%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85</link>
            <guid>https://velog.io/@playername_ltt/FastAPI%EB%A5%BC-%EB%B0%B0%ED%8F%AC%ED%95%98%EB%8A%94-%EA%B3%BC%EC%A0%95%EA%B3%BC-%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85</guid>
            <pubDate>Wed, 24 Sep 2025 05:08:20 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/f3df2808-7aa6-4822-8aad-f2ef757a1ffc/image.png" alt=""></p>
<h1 id="introduce">Introduce</h1>
<hr>
<p>큰 기능이 들어가지 않고, 한번 개발이 끝나면 수정이 크게 들어가지 않는 기능을 수행하는 서버를 <code>FastAPI</code>를 이용하여 만들기로 했다. (사실 파이썬으로 백엔드 서버를 처음 개발하게 됐기에 쉬운거부터 접근한게 크다.)</p>
<p>하지만 배포 과정에서 이런저런 이슈 사항들이 있었다.</p>
<h1 id="1차배포-테스트">1차배포 테스트</h1>
<hr>
<p>우선 현재 프로젝트에서는 <code>Docker</code>를 적용하지 않았다. 그래서 일단은 <code>Docker</code> 이미지로 배포하는 방법은 배제하고 생각하기 시작했다.</p>
<p>그러면 다음으로는 어떻게 해야되지.</p>
<p>우선 기능이 똑바로 돌아가는 것을 로컬로는 확인했으니, 프로젝트 디렉토리를 통째로 서버에 업로드했다.</p>
<p><em>TMI: 나는  SSH툴로 Windows환경에서는 MobaXTerm을, Mac에서는 Termius를 주로 사용한다.</em></p>
<p>그다음 백그라운드에서 돌려봤다.</p>
<pre><code class="language-bash">nohup uvicorn app.main:app --ssl-keyfile=./key.pem --ssl-certfile=./cert.pem --host 0.0.0.0 --port 8000 &amp;</code></pre>
<p>잘 돌아가고, 호출 또한 잘된다. 외부에서 바로 호출을 해봐도, 내부의 다른 서버에서 호출을 해봐도 전부 다 잘 돌아가서 한시름을 놨는데, 뭔가 찝찝하다.</p>
<p>Java의 .jar파일처럼 실행 파일을 따로 만들어서 배포하는 것도 아니고, 디렉토리 통째로 업로드라니…</p>
<p>뭔가 탐탁치 않다.</p>
<h1 id="2차-방안-검토">2차 방안 검토</h1>
<hr>
<p>이 방법은 재배포할 일이 많이 없다지만 보안, 관리상 용이하지 않을 것 같았다. 하지만 큰 제약사항이 두 가지 있는데…</p>
<ol>
<li>현 프로젝트에서는 <code>Docker</code>를 사용하지 않아, 이거 하나때문에 <code>Docker</code>를 적용하기에는 너무 오버다.</li>
<li><code>FastAPI</code>는 <code>Springboot</code>처럼 따로 실행파일을 생성할 수 없다.</li>
</ol>
<p>그래서 우선은 <code>Docker</code>사용을 아예 배제하고 시작해본다. (선임께 얘기했더니 과하다고 컷하신건 비밀)</p>
<h2 id="pyinstaller로-실행파일을-말아볼까">PyInstaller로 실행파일을 말아볼까</h2>
<hr>
<p><a href="https://pyinstaller.org/en/stable/">PyInstaller Manual — PyInstaller 6.13.0 documentation</a></p>
<p>root directory에 <code>app.spec</code> 파일을 추가하고,</p>
<pre><code># -*- mode: python ; coding: utf-8 -*-

a = Analysis(
    [&#39;app/main.py&#39;],
    pathex=[],
    binaries=[],
    datas=[
        (&#39;&lt;Personal Route&gt;\\AppData\\Local\\Programs\\Python\\Python312\\Lib\\site-packages\\jamo\\data\\*.json&#39;, &#39;jamo/data&#39;),
        (&#39;app/libs/g2pk/rules.txt&#39;, &#39;g2pk&#39;),
        (&#39;app/libs/g2pk/idioms.txt&#39;, &#39;g2pk&#39;),
        (&#39;app/libs/g2pk/table.csv&#39;, &#39;g2pk&#39;),
        (&#39;cert.pem&#39;, &#39;.&#39;),
        (&#39;key.pem&#39;, &#39;.&#39;),
        (&#39;.env&#39;, &#39;.&#39;)
    ],
    hiddenimports=[
        &#39;jamo&#39;,
        &#39;jamo.jamo&#39;,
        &#39;jamo.compat&#39;,
        &#39;jamo.data&#39;
    ],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    noarchive=False,
    optimize=0,
)
pyz = PYZ(a.pure)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.datas,
    [],
    name=&#39;app&#39;,
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=True,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)
</code></pre><p>파일 생성 후, 파일 내용 설정</p>
<pre><code class="language-bash">pyinstaller app.spec</code></pre>
<p><code>/dist/app.exe</code> 와 같이 <code>dist</code> directory에 <code>app.exe</code>가 생성되는데, 개발 서버는 <code>Linux</code>이다. 그래서 <code>PyInstaller</code>로 .sh파일을 생성하여 리눅스용 실행 파일을 만들어보려 했는데, <strong>Windows에선 리눅스 실행파일이 생성되지 않는다.</strong></p>
<p>그래서,</p>
<h2 id="linux용-실행파일이면-되겠다">Linux용 실행파일이면 되겠다</h2>
<hr>
<p><code>WSL</code>을 설치했다.</p>
<p>윈도우에서 리눅스를 실행하게 해주는 프로그램인데, 이후 과정을 요약해서 정리하자면</p>
<ol>
<li>wsl에서 venv로 가상환경 설치 후 pyinstall app.spec 실행 → 오류<ol>
<li>jamo.json 머시기를 못찾는다.</li>
</ol>
</li>
<li>app.spec 내부 datas 절대경로 리눅스로 수정<ol>
<li>python -c &quot;import jamo; print(jamo.<strong>file</strong>)&quot;</li>
<li>/home/aroms/stt-api-server-project-linux/.venv/lib/python3.12/site-packages/jamo/<strong>init</strong>.py</li>
<li>/home/aroms/stt-api-server-project-linux/.venv/lib/python3.12/site-packages/jamo/data/*.json</li>
</ol>
</li>
<li>pyinstall app.spec 실행</li>
<li>./dist에 ./app 생성됨</li>
</ol>
<p><code>./app.sh</code>실행이 잘됐다. 그러면 이제 이걸 개발서버에 올려보았지만</p>
<p><strong>“glibc 버전이 맞지 않아 실행이 안된다.”</strong></p>
<pre><code class="language-markdown">[PYI-1436136:ERROR] Failed to load Python shared library &#39;/tmp/_MEIFJuMgk/libpython3.12.so.1.0&#39;: dlopen: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.38&#39; not found (required by /tmp/_MEIFJuMgk/libpython3.12.so.1.0)</code></pre>
<p>개발서버에 설치된 Ubuntu 버전이 낮아 이슈로 할 수가 없다.</p>
<h2 id="docker를-써볼까">Docker를 써볼까?</h2>
<hr>
<p>오케이, 그렇다면 docker로 ubuntu 버전울 낮춰서 빌드해보자.</p>
<p>에러 메세지는 깜빡하여 복사하지 못했지만, docker에서 이미지 만드는 중에 모듈 데이터 일부가 경로 다름 이슈가 발생했다. 이 이슈를 해결한 <code>DockerFile</code>을 작성해보자.</p>
<h3 id="dockerfile-작성">DockerFile 작성</h3>
<pre><code># 실행파일 빌드
FROM ubuntu:20.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt update &amp;&amp; \
    apt install -y python3 python3-pip python3-venv build-essential

WORKDIR /app
COPY . /app

RUN python3 -m venv venv
RUN . venv/bin/activate &amp;&amp; \
    pip install --upgrade pip &amp;&amp; \
    pip install -r requirements.txt

RUN pip install jamo
RUN pip show jamo

RUN pip install pyinstaller &amp;&amp; \
    pyinstaller app.spec</code></pre><pre><code class="language-bash">docker build -t formatter-builder .

docker create --name extract formatter-builder
docker cp extract:/app/dist/app ./dist
docker rm extract

cd dist/app
chmod +x app
./app</code></pre>
<p>일단 결국 빌드되고 실행은 되었다. 하지만 install해뒀던 모든 라이브러리를 잊고야 만 실행파일…</p>
<pre><code class="language-bash">~$ ./app
Traceback (most recent call last):
  File &quot;app/main.py&quot;, line 1, in &lt;module&gt;
ModuleNotFoundError: No module named &#39;fastapi&#39;
[PYI-16153:ERROR] Failed to execute script &#39;main&#39; due to unhandled exception!</code></pre>
<h1 id="결론">결론</h1>
<hr>
<p>이 정도 오면 해결해도 다른 협업하는 분들이 배포 과정을 따라오고 이해하기 힘들다. 수정해야 될 상황이 발생하면 무조건 내가 해야 되는 상황이 발생하기 때문에,</p>
<p> 결국 프로젝트 디렉토리 전부 올려서 해결하는 것으로 결론지었다. (굉장히 맘에 안 들지만)</p>
<p>배포 과정을 그나마 단순화하기 위해 <code>shell</code> 실행파일을 작성했다.</p>
<pre><code class="language-bash">#!/bin/bash

echo &quot;&gt; pid Check&quot;
CURRENT_PID=$(lsof -i | grep uvicorn | grep -v grep | awk &#39;{print $2}&#39;)

echo &quot;&gt; current pid: $CURRENT_PID&quot;

if [ -z &quot;$CURRENT_PID&quot; ]; then
    echo &quot;&gt; No Process&quot;
else
    echo &quot;&gt; sudo kill $CURRENT_PID&quot;
    sudo kill &quot;$CURRENT_PID&quot;
    sleep 4
    if ps -p &quot;$CURRENT_PID&quot; &gt; /dev/null; then
        echo &quot;&gt; server process $CURRENT_PID is not dead&quot;
        echo &quot;&gt; sudo kill -9 $CURRENT_PID&quot;
        sudo kill -9 $CURRENT_PID
        sleep 2
    fi
fi

echo &quot;&gt; installing requirements...&quot;
pip install -r ./&lt;directory name&gt;/requirements.txt

echo &quot;&gt; server deploy&quot;

cd &lt;directory name&gt;/
nohup /home/&lt;username&gt;/.local/bin/uvicorn app.main:app \
  --ssl-keyfile=./key.pem \
  --ssl-certfile=./cert.pem \
  --host 0.0.0.0 \
  --port 8000 &gt; ../nohup.out 2&gt;&amp;1 &amp;
</code></pre>
<p>추후에는 미리 이슈사항들을 예측하고 버전과 배포 과정부터 제대로 체크를 한 후 작업에 들어갈 것 같다. 너무 단편적으로만 고려해서 너무 아쉬운 것 같다.</p>
<p><strong>질문과 피드백은 언제든 환영입니다. :)</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[실시간 미디어 통신을 위한 WebRTC]]></title>
            <link>https://velog.io/@playername_ltt/%EC%8B%A4%EC%8B%9C%EA%B0%84-%EB%AF%B8%EB%94%94%EC%96%B4-%ED%86%B5%EC%8B%A0%EC%9D%84-%EC%9C%84%ED%95%9C-WebRTC</link>
            <guid>https://velog.io/@playername_ltt/%EC%8B%A4%EC%8B%9C%EA%B0%84-%EB%AF%B8%EB%94%94%EC%96%B4-%ED%86%B5%EC%8B%A0%EC%9D%84-%EC%9C%84%ED%95%9C-WebRTC</guid>
            <pubDate>Wed, 24 Sep 2025 04:15:40 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/c4dd311a-eca2-47d6-8475-55c9bc330830/image.png" alt=""></p>
<h1 id="webrtc란">WebRTC란</h1>
<hr>
<p>웹 애플리케이션과 사이트가 중간자 없이, 브라우저 간에 오디오나 영상 미디어를 포착하고 마음대로 스트림할 뿐 아니라, 임의의 데이터도 교환할 수 있도록 하는 기술.</p>
<p>쉽게 생각해보자면, 음성통화, 영상통화, P2P 파일 공유 등으로 활용될 수 있는 <strong>“다양한 플랫폼에서 가능한 실시간 커뮤니케이션 기술”</strong>이라고 정리할 수 있다.</p>
<p>대표적인 서비스로는 Google <strong>Meet, Discord, Zoom</strong> 등이 있다.</p>
<h2 id="주요-개념">주요 개념</h2>
<hr>
<h3 id="시그널링signalling">시그널링(Signalling)</h3>
<p>: P2P로 연결하기 위해 중계 서버가 필요한데, <strong>중걔서버로 클라이언트를 찾고 연결하는 과정</strong>을 시그널링 이라고 함</p>
<p>WebSocket, HTTP 등 알맞은 프로토콜을 개발자가 선택해서 구현하면 된다.</p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/d4f89893-0ea3-465f-ae5a-74c570e35228/image.png" alt=""></p>
<p>두 클라이언트 사이에 Connection을 만들기 위해, 그 둘을 연결시키는 작업을 해주는 <code>시그널링 서버</code>가 필요하다.</p>
<h3 id="stun">STUN</h3>
<ul>
<li>Public IP를 알아내기 위한 <code>NAT</code>환경을 통과하기 위한 서버이다.</li>
<li>가볍고 빠름, 주로 P2P통신이 가능한 경우에 사용된다.</li>
</ul>
<h3 id="turn">TURN</h3>
<ul>
<li><code>STUN</code>만으로 부족할 때에 같은 목적으로 사용하는 서버이다.</li>
<li>방화벽이 강하거나, 복잡한 네트워크 환경 등에서 사용된다.</li>
</ul>
<h3 id="sdp-session-description-protocol">SDP (Session Description Protocol)</h3>
<p>: 연결하고자 하는 <code>Peer</code> 서로간의 미디어와 네트워크에 관한 정보를 이해하기 위해 사용되는 프로토콜. </p>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/966ae9f3-3404-4d1e-8eac-ea2058dc77e9/image.png" alt=""></p>
<p>아까 나온 이 그림은 각각 <code>offer</code>, <code>answer</code>, <code>candidate</code> 의 SDP를 사용하는 예제이다. (직접 구현해봐야 더 자세히 이해할 수 있을 것 같다.)</p>
<p><a href="https://peppo.tistory.com/203">https://peppo.tistory.com/203</a> 이 블로그를 참고해보면 좋을 것 같다.</p>
<h2 id="webrtc의-종류">WebRTC의 종류</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/9677a809-faf2-44d2-a654-e574e2f58346/image.png" alt=""></p>
<p>Mesh, MCU, SFU 방식이 존재한다.</p>
<h3 id="mesh">Mesh</h3>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/37008454-7c62-45b8-ab87-2a90b409204f/image.png" alt=""></p>
<ul>
<li>미디어 정보를 <code>Peer-to-Peer</code>로 클라이언트끼리 주고받는다.</li>
<li>서버는 <code>Peer</code>끼리 연결을 맺기 위한 시그널 정보를 주고받을 수 있게 돕는 역할을 수행한다.</li>
<li><code>Peer</code>끼리 정보를 주고받기 때문에 클라이언트의 부담이 크다.</li>
<li>1:1에서 가장 많이 사용되는 방식으로, 1:N, 1:M 도 가능하지만 <code>Peer</code>의 부담이 더 커질 것이다.</li>
<li>직접 연결로 데이터를 송수신하기 때문에 <strong>실시간 송수신이 보장된다.</strong></li>
</ul>
<h3 id="mcu-multipoint-control-unit">MCU (Multipoint Control Unit)</h3>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/2ddd77a2-871a-4c3b-aef1-a6f07204b1f9/image.png" alt=""></p>
<ul>
<li>서버에서 <strong>미디어 트래픽을 중계</strong>하는 방식</li>
<li>1개의 <code>upstream</code>과 1개의 <code>downstream</code>을 가지는 구조 → 클라이언트의 부담이 적다.</li>
<li>서버에서 <code>Peer</code>의 스트림을 모아 인코딩 &amp; 디코딩 모두를 하기 때문에 서버 성능이 받쳐줘야 한다. 또한 <strong>실시간 송수신 보장이 어려울 수 있다.</strong></li>
<li><code>Peer</code>의 부하가 가장 적음 → 당연히 서버의 부하는 그만큼 커진다.</li>
<li>N:M 연결에서 효율적이다.</li>
<li>미디어 서버가 필수적으로 필요하다.</li>
</ul>
<h3 id="sfu-selective-forwarding-unit">SFU (Selective Forwarding Unit)</h3>
<p><img src="https://velog.velcdn.com/images/playername_ltt/post/5652b6f8-4b9c-4001-b49a-acbbd3f20aa6/image.png" alt=""></p>
<ul>
<li>서버에서 <strong>미디어 트래픽을 중계</strong>하는 방식</li>
<li>1개의 <code>upstream</code>과 N개의 <code>downstream</code>을 가지는 구조</li>
<li>서버가 미디어 트래픽을 중계해주기 때문에 모든 Connection에 대해 클라이언트가 관리할 필요 X → <strong>클라이언트의 부하는 줄고, 서버의 부하는 늘어남</strong></li>
<li><code>Mesh 방식</code>보다는 실시간성이 떨어질 수 있지만, P2P에 걸맞는 <strong>실시간 송수신이 보장된다.</strong></li>
<li><code>Mesh  방식</code>보다 N:M 연결에 있어서 클라이언트의 부하가 줄긴 했지만, 각각의 <code>downstream</code>을 개별적으로 유지해야 하기 때문에, <strong>여전히 클라이언트에 부담이 존재한다.</strong></li>
<li>미디어 서버가 필수적으로 필요하다.</li>
</ul>
<p><code>Mesh</code>방식만으로는 클라이언트가 늘어날 수록 과부하가 기하급수적으로 많이 늘어났기 때문에 SFU와 MCU가 등장하였고, 요구사항에 맞춰 적절하게 활용할 필요성이 있다.</p>
<p>실시간성이 가장 최우선적으로 중요하다면 <code>SFU</code>를, 데이터를 중간에 가공해야 한다면 <code>MCU</code>를 활용해보는 것이 좋을 수 있다. 연결할 클라이언트가 적다면 단순 <code>P2P</code> 방식도 훌륭한 판단일 수 있다.</p>
<h1 id="reference">Reference</h1>
<hr>
<ul>
<li><a href="https://developer.mozilla.org/ko/docs/Web/API/WebRTC_API">https://developer.mozilla.org/ko/docs/Web/API/WebRTC_API</a></li>
<li><a href="https://webrtc.org/?hl=ko">https://webrtc.org/?hl=ko</a></li>
<li>그 외 기술 블로그들</li>
</ul>
<p>오류가 있거나, 잘못 기재된 부분이 있다면 피드백 부탁드립니다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[FastAPI 서버 보안 강화: 무작위 스캔 공격 대응과 개선 기록]]></title>
            <link>https://velog.io/@playername_ltt/FastAPI-%EC%84%9C%EB%B2%84-%EB%B3%B4%EC%95%88-%EA%B0%95%ED%99%94-%EB%AC%B4%EC%9E%91%EC%9C%84-%EC%8A%A4%EC%BA%94-%EA%B3%B5%EA%B2%A9-%EB%8C%80%EC%9D%91%EA%B3%BC-%EA%B0%9C%EC%84%A0-%EA%B8%B0%EB%A1%9D</link>
            <guid>https://velog.io/@playername_ltt/FastAPI-%EC%84%9C%EB%B2%84-%EB%B3%B4%EC%95%88-%EA%B0%95%ED%99%94-%EB%AC%B4%EC%9E%91%EC%9C%84-%EC%8A%A4%EC%BA%94-%EA%B3%B5%EA%B2%A9-%EB%8C%80%EC%9D%91%EA%B3%BC-%EA%B0%9C%EC%84%A0-%EA%B8%B0%EB%A1%9D</guid>
            <pubDate>Mon, 07 Jul 2025 02:41:34 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/playername_ltt/post/e88435b9-60e5-4777-8307-04c7d360e761/image.png" alt=""></p>
<h1 id="fastapi-서버-보안-강화-기록-🛡️">FastAPI 서버 보안 강화 기록 🛡️</h1>
<hr>
<h2 id="1-문제-상황">1. 문제 상황</h2>
<hr>
<p>최근 FastAPI 서버 로그에서 아래와 같은 이상 요청들이 다수 발견되었다.</p>
<pre><code class="language-bash">2025-06-24 01:37:46,904 - app_logger - INFO - ENDPOINT: GET /
2025-06-24 01:37:46,906 - app_logger - INFO - RESPONSE: {&quot;detail&quot;:&quot;Not Found&quot;}
2025-06-24 03:48:44,430 - app_logger - INFO - ENDPOINT: GET /login
2025-06-24 03:48:44,431 - app_logger - INFO - RESPONSE: {&quot;detail&quot;:&quot;Not Found&quot;}
2025-06-24 03:48:45,208 - app_logger - INFO - ENDPOINT: GET /ab2g
2025-06-24 03:48:45,210 - app_logger - INFO - RESPONSE: {&quot;detail&quot;:&quot;Not Found&quot;}
</code></pre>
<p>이러한 요청은 <strong>무작위 스캔 공격 (Random Scan Attack)</strong> 의 일종으로, 공격자가 서버에 존재할 법한 다양한 엔드포인트로 무작위 요청을 보내 취약점을 탐색하는 시도다.</p>
<p>개발서버 자체의 설정을 수정하는 건 부담스러웠고, 우선은 <strong>FastAPI 서버 레벨</strong>에서 이러한 공격에 대한 방어 조치를 적용하기로 했다.</p>
<hr>
<h2 id="2-조치사항-리스트업-✅">2. 조치사항 리스트업 ✅</h2>
<hr>
<h3 id="2-1-서버-간-통신-jwt-→-api-key-인증-방식-전환">2-1. 서버 간 통신: JWT → API Key 인증 방식 전환</h3>
<ul>
<li>기존에는 서버 간 통신도 무조건 JWT를 사용했지만, 현재 시스템에서는 사용자 인증이 필요 없는 <strong>서버 간 단순 인증</strong>만으로 충분하다.</li>
<li><strong>API Key + AES 암호화</strong> 방식으로 인증 방식을 개선함.</li>
</ul>
<p>👉 관련 내용: <a href="https://velog.io/@playername_ltt/%EC%84%9C%EB%B2%84%EA%B0%84-%ED%86%B5%EC%8B%A0-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D-API-Key">서버간 통신 인증 방식 : API Key</a></p>
<hr>
<h3 id="2-2-배포-쉘스크립트-개선">2-2. 배포 쉘스크립트 개선</h3>
<ul>
<li>기존에는 <code>uvicorn</code> 실행 시 <code>-host 0.0.0.0</code> 설정으로 <strong>외부에서도 접근 가능한 상태</strong>였다.</li>
<li>실제로는 <strong>같은 서버 인스턴스 내의 Spring 서버만 요청</strong>을 보내기 때문에 <code>127.0.0.1</code> 로 수정하여 <strong>로컬 접속만 허용</strong>하도록 변경했다.</li>
</ul>
<pre><code class="language-bash">#!/bin/bash

PYTHON=&lt;파이썬 경로&gt;

echo &quot;&gt; FastAPI 서버 프로세스 확인&quot;
CURRENT_PID=$(lsof -i | grep python3 | grep -v grep | awk &#39;NR==2 {print $2}&#39;)

echo &quot;&gt; 현재 PID: $CURRENT_PID&quot;

if [ -z &quot;$CURRENT_PID&quot; ]; then
    echo &quot;&gt; 프로세스 없음&quot;
else
    echo &quot;&gt; 프로세스 종료 시도: $CURRENT_PID&quot;
    sudo kill &quot;$CURRENT_PID&quot;
    sleep 4
    if ps -p &quot;$CURRENT_PID&quot; &gt; /dev/null; then
        echo &quot;&gt; 프로세스가 종료되지 않아 강제 종료&quot;
        sudo kill -9 &quot;$CURRENT_PID&quot;
        sleep 2
    fi
fi

echo &quot;&gt; 패키지 설치&quot;
$PYTHON -m pip install -r ./&lt;Directory Path&gt;/requirements.txt

echo &quot;&gt; 서버 재시작&quot;
cd &lt;Directory Path&gt;/
nohup $PYTHON -m uvicorn app.main:app \
  --ssl-keyfile=./&lt;ssl-keyfile.pem&gt; \
  --ssl-certfile=./&lt;ssl-certfile.pem&gt; \
  --host 127.0.0.1 \
  --port 8000 &gt; ../nohup.out 2&gt;&amp;1 &amp;
</code></pre>
<p>✅ 개선 효과:</p>
<ul>
<li>외부 공격자가 IP와 포트만 알아내도 접근 가능한 상태 → 내부 접근만 가능하도록 변경</li>
</ul>
<hr>
<h3 id="2-3-swagger-문서-비활성화">2-3. Swagger 문서 비활성화</h3>
<ul>
<li>기본적으로 FastAPI는 <code>/docs</code> 또는 <code>/redoc</code> 경로로 API 문서를 제공한다.</li>
<li>공격자는 해당 문서만으로도 API 엔드포인트를 쉽게 유추할 수 있다.</li>
<li><strong>배포 환경에서는 Swagger 문서를 완전히 비활성화</strong>함.</li>
</ul>
<pre><code class="language-python">from fastapi import FastAPI

app = FastAPI(
    docs_url=None,
    redoc_url=None,
    openapi_url=None
)
</code></pre>
<p>✅ 개선 효과:</p>
<ul>
<li>외부인이 Swagger 문서를 통해 API 정보를 탐색하는 위험 차단</li>
</ul>
<hr>
<h3 id="2-4-로깅-미들웨어-개선-ip-주소-포함">2-4. 로깅 미들웨어 개선 (IP 주소 포함)</h3>
<ul>
<li>기존 로깅에는 <strong>요청자의 IP 정보</strong>가 빠져 있어, 누가 요청했는지 알 수 없었다.</li>
<li><strong>요청자의 IP, 포트 정보</strong>까지 함께 로깅하도록 개선했다.</li>
</ul>
<pre><code class="language-python">from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse
from starlette.background import BackgroundTask
from starlette.types import Message
from app.utils.log_util import logger
import traceback

class LogMiddleware(BaseHTTPMiddleware):
    def entry_log_info(self, endpoint: str):
        logger.info(f&quot;REQUEST: {endpoint}&quot;)

    def end_log_info(self, res_body: bytes):
        logger.info(f&quot;RESPONSE: {res_body.decode(errors=&#39;ignore&#39;)}&quot;)

    async def set_body(self, request: Request, body: bytes):
        async def receive() -&gt; Message:
            return {&quot;type&quot;: &quot;http.request&quot;, &quot;body&quot;: body}
        request._receive = receive

    async def dispatch(self, request: Request, call_next):
        req_body = await request.body()
        await self.set_body(request, req_body)

        # IP + 포트 + 요청 경로
        endpoint = f&quot;[{request.client.host}:{request.client.port}] {request.method} {request.url.path}&quot;
        self.entry_log_info(endpoint)

        try:
            response = await call_next(request)
            res_body = b&quot;&quot;
            async for chunk in response.body_iterator:
                res_body += chunk

            task = BackgroundTask(self.end_log_info, res_body)

            return Response(
                content=res_body,
                status_code=response.status_code,
                headers=dict(response.headers),
                media_type=response.media_type,
                background=task,
            )
        except Exception as e:
            logger.error(f&quot;EXCEPTION OCCURRED: {type(e).__name__}: {str(e)}&quot;)
            logger.debug(traceback.format_exc())

            error_response = {&quot;detail&quot;: &quot;Internal Server Error&quot;, &quot;exception&quot;: str(e)}
            res_body = JSONResponse(status_code=500, content=error_response)
            task = BackgroundTask(self.end_log_info, res_body.body)
            res_body.background = task
            return res_body
</code></pre>
<p>✅ 개선 효과:</p>
<ul>
<li>요청자 IP 기록 → 문제 발생 시 빠른 추적 가능</li>
<li>예외 상황까지 상세 로깅</li>
</ul>
<hr>
<h2 id="3-최종-정리-📝">3. 최종 정리 📝</h2>
<hr>
<table>
<thead>
<tr>
<th>조치</th>
<th>내용</th>
<th>효과</th>
</tr>
</thead>
<tbody><tr>
<td>✅ API Key 인증</td>
<td>서버 간 통신에 JWT 대신 API Key 적용</td>
<td>불필요한 JWT 제거, 간편 인증</td>
</tr>
<tr>
<td>✅ Host 제한</td>
<td>0.0.0.0 → 127.0.0.1</td>
<td>외부 접근 차단</td>
</tr>
<tr>
<td>✅ Swagger 비활성화</td>
<td><code>docs_url=None</code></td>
<td>API 정보 노출 방지</td>
</tr>
<tr>
<td>✅ 로깅 강화</td>
<td>요청 IP 및 포트 기록</td>
<td>공격/오류 추적 가능</td>
</tr>
</tbody></table>
<hr>
<h2 id="4-앞으로의-보완-아이디어-💡">4. 앞으로의 보완 아이디어 💡</h2>
<hr>
<ul>
<li><strong>Fail2Ban 적용</strong>: 비정상 IP 차단 자동화</li>
<li><strong>API Rate Limiting</strong>: 요청 횟수 제한 적용</li>
<li><strong>SSL 인증서 갱신 자동화</strong>: 장기적 서비스 안정화</li>
<li><strong>서버간 Mutual TLS</strong>: 강력한 상호 인증 고려</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>