<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel xmlns:content="http://purl.org/rss/1.0/modules/content/"><title>요즘IT » 개발 » 피드</title><link>https://yozm.wishket.com/magazine/list/develop</link><description>쉽고 재미있는 IT 이야기를 다룹니다. 업계 전문가들이 전하는 IT 트렌드, 기획, 디자인, 개발, 인사이트 소식들이 가득합니다.</description><atom:link href="https://yozm.wishket.com/magazine/list/develop/feed/" rel="self"/><language>ko-kr</language><lastBuildDate>Mon, 22 Jun 2026 09:34:55 +0000</lastBuildDate><item><title>개발자는 여전히 수학을 잘해야 할까요?</title><link>https://yozm.wishket.com/magazine/detail/3813</link><description>개발 공부를 시작하려는 분들에게 자주 받는 질문이 있습니다.“수학을 잘하지 못하는데 개발자가 될 수 있을까요?”, “문과 출신인데 프로그래밍을 배워도 괜찮을까요?”, “알고리즘 문제를 풀 때마다 막히는데, 계속 공부해도 될까요?” 저 역시 컴퓨터공학과를 다니면서 비슷한 고민을 했습니다. 그런데 한국과 일본에서 실제로 개발자로 일해보니, 학교에서 상상했던 개발자의 모습과 현장에서 필요한 능력은 조금 달랐습니다. 현업에서 제가 더 자주 마주친 것은 미적분 공식이 아니라 모호한 요구사항이었습니다. 이번 글에서는 과거에는 왜 수학이 중요했는지, 지금의 개발 환경은 어떻게 달라졌는지, 그리고 수학이 약한 개발자는 무엇부터 준비하면 좋을지 현실적인 관점에서 이야기해 보겠습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3813</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;수학 때문에 개발을 망설이는 분들께 전하고 싶은 현실적인 이야기&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;개발 공부를 시작하려는 분들에게 자주 받는 질문이 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;&lt;i&gt;“수학을 잘하지 못하는데 개발자가 될 수 있을까요?”&lt;/i&gt;&lt;br&gt;&lt;i&gt;“문과 출신인데 프로그래밍을 배워도 괜찮을까요?”&lt;/i&gt;&lt;br&gt;&lt;i&gt;“알고리즘 문제를 풀 때마다 막히는데, 계속 공부해도 될까요?”&lt;/i&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;저 역시 컴퓨터공학과를 다니면서 비슷한 고민을 했습니다. 이산수학, 자료구조, 알고리즘 수업을 들을 때마다 개발자는 원래 수학을 잘해야 하는 직업이 아닐까 생각했습니다. 복잡한 수식을 빠르게 이해하는 동기들을 보면 괜히 위축되기도 했습니다. 시험 문제가 잘 풀리지 않는 날에는 개발자로 일하는 미래가 조금 멀게 느껴지기도 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 한국과 일본에서 실제로 개발자로 일해보니, 학교에서 상상했던 개발자의 모습과 현장에서 필요한 능력은 조금 달랐습니다. 현업에서 제가 더 자주 마주친 것은 미적분 공식이 아니라 모호한 요구사항이었습니다. 선형대수보다 고객 문의를 더 많이 다뤘고, 복잡한 수식보다 예상하지 못한 오류의 원인을 찾는 데 더 많은 시간을 사용했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;물론 수학은 중요합니다. 수학을 잘하면 문제를 구조적으로 바라보는 데 도움이 되고, 특정 개발 분야로 성장할 때도 분명한 강점이 됩니다. 다만 모든 개발자가 같은 수준의 수학을 필요로 하는 것은 아닙니다. 개발 분야와 담당 업무에 따라 필요한 수학의 깊이는 크게 달라집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;최근에는 인공지능(AI) 도구가 코드를 제안하는 수준을 넘어, 프로젝트를 분석하고 여러 파일을 수정하며 테스트까지 수행하는 방향으로 발전하고 있습니다. 이제 개발자는 코드를 얼마나 빠르게 입력하는지뿐만 아니라, 무엇을 만들어야 하는지 정의하고 결과물을 판단할 수 있어야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그렇다면 지금 시대에도 수학은 여전히 중요할까요? 수학이 부족하다고 느끼는 사람은 개발자를 포기해야 할까요? 이번 글에서는 과거에는 왜 수학이 중요했는지, 지금의 개발 환경은 어떻게 달라졌는지, 그리고 수학이 약한 개발자는 무엇부터 준비하면 좋을지 현실적인 관점에서 이야기해 보겠습니다.&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;프로그래밍과 수학은 얼마나 가까운 관계일까요?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;프로그래밍의 본질은 문제를 해결하는 과정입니다. 복잡한 문제를 작은 단위로 나누고, 필요한 조건을 정리한 뒤, 컴퓨터가 이해할 수 있는 명령으로 바꾸는 일입니다. 이 과정은 수학 문제를 푸는 흐름과 닮아 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;쇼핑몰의 결제 금액을 계산하는 기능을 예로 들어보겠습니다. 상품 가격을 더하고, 쿠폰 할인 금액을 빼고, 배송비를 추가합니다. 특정 금액 이상을 구매하면 배송비를 무료로 처리할 수도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;겉으로 보기에는 단순한 덧셈과 뺄셈입니다. 하지만 실제 서비스를 만들기 시작하면 고려해야 할 조건이 빠르게 늘어납니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image9.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실무에서는 복잡한 공식을 외우는 능력보다, 이런 예외 상황을 빠짐없이 찾아내는 능력이 중요합니다. 배열을 정렬하는 알고리즘도 비슷합니다. 데이터를 비교하고, 위치를 바꾸고, 다시 비교하는 과정이 반복됩니다. 지도에서 가장 빠른 길을 찾는 기능도 거리와 조건을 비교하는 문제입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;프로그래밍과 수학은 분명 연결되어 있습니다. 하지만 이 관계를 “수학 문제를 빨리 풀어야 코딩도 잘한다”라고 단순하게 해석하면 곤란합니다. 개발자에게 필요한 것은 수학적 재능만이 아닙니다. 복잡한 문제를 정리하고, 해결 가능한 단위로 나누며, 결과를 하나씩 검증하는 사고방식이 더 중요합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image8.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;과거의 프로그래밍에서는 왜 수학이 더 중요했을까요?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;과거의 프로그래밍은 지금보다 컴퓨터와 가까운 작업이 많았습니다. 오늘날에는 다양한 라이브러리와 프레임워크가 복잡한 처리를 대신해 줍니다. 하지만 저수준 프로그래밍 환경에서는 개발자가 메모리와 중앙처리장치(CPU)의 동작을 직접 이해해야 하는 경우가 많았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;어셈블리 언어(Assembly Language)로 두 숫자를 더하는 간단한 예제를 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image7.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 짧은 코드에서도 개발자는 값을 어느 레지스터에 불러올지, 어떤 값을 더할지, 결과를 어디에 저장할지 직접 지정해야 합니다. 저수준 개발에서는 이진법, 논리 연산, 메모리 주소, 자료형의 크기 같은 개념을 이해해야 했습니다. 작은 실수 하나가 예상하지 못한 오류로 이어질 수도 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;그래픽스 분야에서는 벡터와 행렬이 중요했습니다. 게임 개발에서는 좌표와 물리 계산이 필요했고, 암호학에서는 수학적 원리를 이해해야 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 한 가지는 구분해야 합니다. 과거의 개발자에게 필요했던 것이 모두 고급 수학은 아니었습니다. 컴퓨터 구조를 이해하는 능력, 논리적으로 사고하는 습관, 작은 차이를 놓치지 않는 집중력도 함께 중요했습니다. 그래서&lt;strong&gt;“과거에는 수학이 중요했고, 지금은 필요 없다”&lt;/strong&gt;라고 단순하게 나누기는 어렵습니다. 개발 분야에 따라 필요한 능력이 달랐고, 지금도 마찬가지입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image5.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;지금은 모든 것을 직접 만들지 않습니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;지금의 개발 환경은 과거와 크게 달라졌습니다. 웹 개발만 보더라도 리액트(React), 뷰(Vue), 넥스트제이에스(Next.js), 스프링부트(Spring Boot)처럼 잘 만들어진 라이브러리와 프레임워크가 존재합니다. 개발자는 모든 기능을 처음부터 구현하지 않아도 됩니다. 인증, 데이터베이스 연결, 화면 상태 관리, 서버 통신, 배포 자동화처럼 복잡한 기능도 검증된 라이브러리와 서비스를 활용해 빠르게 구성할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;회원가입 기능을 예로 들어볼까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;개발자는 입력값 검사, 비밀번호 암호화, 세션 관리, 이메일 인증, 오류 처리 같은 여러 요소를 고려해야 합니다. 지금은 프레임워크와 외부 서비스를 활용해 많은 부분을 효율적으로 구성할 수 있습니다. 그렇다고 개발자의 일이 단순해진 것은 아닙니다. 오히려 고민해야 할 대상이 달라졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;과거에는&lt;strong&gt;“어떻게 직접 구현할까?”&lt;/strong&gt;를 먼저 고민했다면, 지금은 다음과 같은 질문을 더 자주 하게 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image2.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;직접 모든 것을 만드는 시대에서, 적절한 도구를 선택하고 조합하는 시대로 이동한 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;레고 블록에 비유해 보겠습니다. 과거의 개발자는 블록 자체를 직접 깎아야 했습니다. 지금의 개발자는 이미 만들어진 수많은 블록 중에서 적절한 것을 골라 안정적인 구조물을 완성해야 합니다. 블록을 직접 만들지 않는다고 해서 쉬운 것은 아닙니다. 잘못된 블록을 선택하거나 연결 방식을 이해하지 못하면, 완성된 구조물은 금방 무너질 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image6.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;수학이 중요한 분야는 분명히 존재합니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;“개발자에게 수학이 필요한가요?”&lt;/strong&gt;라는 질문에 하나의 정답을 내리기 어려운 이유는 개발 분야가 매우 넓기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;웹 프론트엔드 개발자가 일반적인 화면을 구현할 때는 고급 미적분을 사용할 일이 많지 않습니다. 관리 시스템을 개발하는 백엔드 개발자도 매일 행렬 계산을 하지는 않습니다. 하지만 AI 모델을 설계하거나, 게임 엔진을 개발하거나, 암호화 알고리즘을 연구하는 개발자는 이야기가 달라집니다. 수학을 이해하지 못하면 문제의 원리 자체를 파악하기 어려울 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image4.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이를 축구에 비유해 볼까요? 메시처럼 드리블, 패스, 골 결정력까지 다양한 능력을 높은 수준으로 갖춘 선수는 극히 드뭅니다. 하지만 모든 선수가 메시처럼 뛰어야만 팀에 기여할 수 있는 것은 아닙니다. 인자기는 뛰어난 위치 선정 능력으로 골을 만들어냈고, 솔샤르는 결정적인 순간에 기회를 놓치지 않는 집중력으로 팀에 기여했습니다. 각자 가진 강점은 달랐지만, 그 강점을 제대로 활용했기 때문에 오래 기억되는 선수가 될 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;개발자도 마찬가지입니다. 모든 개발자가 복잡한 알고리즘을 직접 설계하거나, 고급 수학을 자유자재로 다룰 필요는 없습니다. 고객의 요구사항을 정확하게 이해하는 개발자도 필요하고, 장애 원인을 빠르게 찾아내는 개발자도 필요합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;팀원이 읽기 쉬운 코드를 작성하거나, 새로운 기술을 빠르게 익혀 프로젝트에 적용하는 능력도 충분히 중요한 강점입니다. 수학적 직관이 부족하다고 해서 미리 낙담할 필요는 없습니다. 자신의 강점을 발견하고, 부족한 부분은 조금씩 보완해 나가면 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image10.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;현업에서 더 자주 마주친 것은 따로 있었습니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;한국과 일본에서 웹 개발자로 일하면서, 복잡한 수식을 직접 사용할 일은 생각보다 많지 않았습니다. 대신 고객이 원하는 기능을 정확하게 이해해야 했습니다. 이미 작성된 코드를 읽고 오류의 원인을 찾아야 했고, 예상하지 못한 장애가 발생하면 로그를 분석해야 했습니다. 팀원에게 문제 상황을 설명하는 일도 중요했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;특히 일본 개발 현장에서는 보고·연락·상담을 의미하는 &lt;strong&gt;호렌소(報連相)&lt;/strong&gt;를 중요하게 생각했습니다. 문제가 발생했을 때 혼자 끌어안기보다, 현재 상황과 예상되는 위험을 정리해 공유해야 했습니다. 개발 실력이 뛰어나더라도 설명이 부족하면 팀 전체의 일정이 흔들릴 수 있습니다. 반대로 아직 경험이 많지 않은 개발자라도 문제를 빠르게 공유하고, 필요한 도움을 정확하게 요청하면 프로젝트에 큰 기여를 할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;제가 현장에서 중요하다고 느낀 능력은 다음과 같습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image3.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;흥미로운 점은 이러한 능력도 넓은 의미에서는 수학적 사고와 연결된다는 것입니다. 복잡한 문제를 나누고, 가설을 세우고, 하나씩 검증하는 방식은 수학 문제를 푸는 과정과 닮았습니다. 다만 중요한 것은 빠른 암산이나 어려운 공식이 아닙니다. 문제를 끝까지 포기하지 않고, 구조적으로 바라보는 태도입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image13.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;AI 에이전트가 코드를 만드는 시대에는 무엇이 달라질까요?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;챗GPT(ChatGPT), 클로드(Claude), 제미나이(Gemini)&lt;/strong&gt;같은 생성형 AI 서비스가 등장한 이후, 개발 환경은 빠르게 바뀌었습니다. 최근에는 여기서 한 단계 더 나아가고 있습니다. 단순히 질문에 답하거나 코드 일부를 자동으로 완성해 주는 수준을 넘어, 프로젝트 구조를 파악하고 여러 파일을 수정하며, 테스트까지 수행하는 AI 에이전트가 등장하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;&lt;strong&gt;클로드 코드(Claude Code), 코덱스(Codex), 구글 안티그래비티(Google Antigravity), 커서(Cursor)&lt;/strong&gt;같은 도구가 대표적인 사례입니다. 예전에는 개발자가 오류 메시지를 검색하고, 관련 파일을 직접 찾은 뒤, 하나씩 수정하고 테스트해야 했습니다. 이제는 AI 에이전트에게 요구사항을 전달하면 관련 코드를 분석하고, 수정 방향을 제안하며, 일부 작업은 직접 수행하기도 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;개발자가 코드를 작성하는 방식 자체가 달라지고 있는 것입니다. 저 역시 개발 과정에서 AI 도구를 활용하고 있습니다. 이전에는 검색 결과를 여러 페이지에 걸쳐 확인해야 했던 문제도, AI를 활용하면 필요한 방향을 빠르게 좁힐 수 있습니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그렇다면 기본기를 공부할 필요도 줄어든 걸까요? 오히려 반대에 가깝다고 생각합니다. AI는 그럴듯한 코드를 빠르게 만들어줍니다. 하지만 결과가 항상 정확한 것은 아닙니다. 작은 기능에서는 잘 동작하던 코드가 실제 운영 환경에서는 느려질 수도 있고, 보안상 위험한 방식이 포함될 수도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;AI가 작성한 코드가 왜 동작하는지 이해하지 못하면 수정하기 어렵습니다. 오류가 발생해도 어디부터 확인해야 할지 판단하기 어렵습니다. 내비게이션이 길을 알려준다고 해서 운전자가 교통 표지판을 몰라도 되는 것은 아닙니다. AI 시대의 개발도 비슷합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;도구가 좋아질수록 개발자는 더 빠르게 이동할 수 있습니다. 하지만 어디로 가야 하는지 판단하고, 위험한 길을 피하며, 결과에 책임지는 일은 여전히 개발자의 몫입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image12.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;수학이 약한 개발자는 무엇부터 공부하면 좋을까요?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;수학에 자신이 없다고 해서 갑자기 미적분 교재부터 펼칠 필요는 없습니다. 먼저 자신이 일하고 싶은 분야에서 실제로 필요한 개념을 정리하는 것이 좋습니다. 웹 개발을 목표로 한다면, 고급 수학보다 프로그래밍의 기본 구조와 데이터 흐름을 먼저 이해하는 편이 효과적입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1단계: 조건과 반복을 익혀봅니다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;조건문과 반복문&lt;/strong&gt;은 프로그래밍의 가장 기본적인 도구입니다. 단순한 문법처럼 보이지만, 대부분의 비즈니스 로직은 이 조합에서 시작됩니다. 쇼핑몰의 쿠폰 적용, 회원 등급에 따른 혜택, 예약 가능 시간 확인 같은 기능도 결국 조건을 나누고 반복적으로 데이터를 확인하는 과정입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2단계: 자료구조와 알고리즘의 기초를 이해합니다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;모든 알고리즘 문제를 빠르게 풀 필요는 없습니다. &lt;strong&gt;배열, 객체, 스택, 큐, 정렬, 탐색&lt;/strong&gt;같은 기본 개념부터 익혀도 충분합니다. 중요한 것은 정답을 외우는 것이 아니라, 어떤 상황에서 어떤 구조를 선택하는지 이해하는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3단계: 작은 프로젝트를 직접 완성해 봅니다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;공부한 내용을 실제 기능으로 만들어보면 부족한 부분이 선명하게 보입니다. 회원가입, 게시판, 일정 관리처럼 작은 프로젝트라도 좋습니다. &lt;strong&gt;데이터를 저장하고, 오류를 처리하고, 화면에 결과&lt;/strong&gt;를 보여주는 흐름을 경험해 보는 것이 중요합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;4단계: 필요한 수학은 그때 다시 공부합니다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;데이터 분석이 필요해지면 통계를 공부하고, 그래픽스를 다루게 되면 벡터와 행렬을 공부하면 됩니다. 개발자의 공부는 한 번에 모든 것을 끝내는 시험이 아닙니다. 필요할 때 다시 돌아가 부족한 부분을 채우는 긴 과정입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3813/image11.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며: 완벽한 개발자보다 꾸준한 개발자가 오래갑니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;수학은 프로그래밍에서 분명 중요한 도구입니다. 수학을 잘하면 문제를 구조적으로 바라보는 데 도움이 되고, 알고리즘을 이해하거나 특정 분야로 성장할 때도 유리합니다. 하지만 수학을 잘하지 못한다고 해서 개발자가 될 수 없는 것은 아닙니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;복잡한 알고리즘을 만드는 개발자도 필요하지만, 고객의 요구를 정확하게 이해하는 개발자도 필요합니다. 장애를 빠르게 분석하는 개발자도 필요하고, 팀원들이 읽기 쉬운 코드를 작성하는 개발자도 필요합니다. AI 시대에는 개발자의 역할이 더 빠르게 바뀔 수 있습니다. 하지만 문제를 해결하려는 태도와 꾸준히 배우는 습관은 쉽게 사라지지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;혹시 수학이 부족하다는 이유로 개발을 망설이고 계신가요? 너무 겁먹지 않으셔도 괜찮습니다. 수학을 완벽하게 공부한 뒤에 개발을 시작해야 하는 것은 아닙니다. 먼저 작은 문제부터 해결해보고, 필요한 수학은 그 과정에서 하나씩 다시 배우면 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;완벽한 천재보다 꾸준히 성장하는 사람이 더 오래 개발할 수 있습니다. 저 역시 여전히 부족한 부분을 공부하고 있습니다. 그리고 아마 개발자로 일하는 동안, 이 공부는 계속될 것 같습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>타입 계층과 호환성, extends가 진짜 의미하는 것</title><link>https://yozm.wishket.com/magazine/detail/3807</link><description>타입스크립트를 사용하다 보면 extends라는 키워드를 다양한 곳에서 만나게 됩니다. Conditional Type에서는 T extends U ? X : Y 형태로, 제네릭에서는 T extends string 같은 제약 조건으로 등장합니다. 두 경우 모두 "할당 가능하면"이라는 설명이 따라붙는데, 정확히 어떤 조건에서 할당이 가능하고 어떤 조건에서 불가능한 것일까요? 이번 글에서는 타입 계층도의 전체 구조를 살펴보고, 타입스크립트가 타입 간의 관계를 어떤 기준으로 판단하는지 알아보겠습니다. 이 개념을 이해하고 나면, extends와 타입 좁히기, 유틸리티 타입의 동작 원리가 한층 더 선명해질 것입니다.</description><guid>https://yozm.wishket.com/magazine/detail/3807</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;타입스크립트를 사용하다 보면 extends라는 키워드를 다양한 곳에서 만나게 됩니다. Conditional Type에서는 T extends U ? X : Y 형태로, 제네릭에서는 T extends string 같은 제약 조건으로 등장합니다. 두 경우 모두 "할당 가능하면"이라는 설명이 따라붙는데, 정확히 어떤 조건에서 할당이 가능하고 어떤 조건에서 불가능한 것일까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;타입 좁히기에서도 비슷한 의문이 생깁니다. typeof 검사를 거치면 "타입이 좁아진다"고 하는데, 넓은 타입과 좁은 타입이라는 말은 타입 사이에 일종의 크기 관계가 있다는 뜻입니다. 그렇다면 이 크기 관계는 어디에서 오는 것이고, 타입스크립트는 어떤 기준으로 이를 판단하는 것일까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 관계를 체계적으로 정리한 것이 타입 계층도이고, 이를 기반으로 타입스크립트가 할당 가능 여부를 판단하는 규칙이 타입 호환성입니다. 이번 글에서는 타입 계층도의 전체 구조를 살펴보고, 타입스크립트가 타입 간의 관계를 어떤 기준으로 판단하는지 알아보겠습니다. 이 개념을 이해하고 나면, extends와 타입 좁히기, 유틸리티 타입의 동작 원리가 한층 더 선명해질 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;미리 요점만 콕 집어보면?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;타입스크립트의 모든 타입은 unknown부터 never까지 계층을 이루며, 좁은 타입에서 넓은 타입으로만 안전하게 할당됩니다.&lt;/li&gt;&lt;li&gt;객체 타입은 이름이 아니라 구조를 기준으로 호환성을 판단하며, extends 역시 결국 “할당 가능한가?”를 검사하는 문법입니다.&lt;/li&gt;&lt;li&gt;Conditional Type, 제네릭 제약, 타입 좁히기는 모두 같은 타입 계층과 호환성 규칙 위에서 동작하는 개념입니다.&lt;/li&gt;&lt;/ul&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;타입 계층도, 모든 타입에는 상하 관계가 있다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;타입스크립트에서 사용하는 모든 타입은 하나의 계층 구조 안에 놓여 있습니다. 이 구조를 이해하면 어떤 타입이 어떤 타입에 할당 가능한지, 왜 특정 할당이 오류를 발생시키는지를 체계적으로 파악할 수 있습니다. 이후 섹션에서 다룰 호환성 규칙과 extends의 의미가 모두 이 계층도에 뿌리를 두고 있으므로, 먼저 전체 그림을 잡고 가겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) unknown과 never&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;타입 계층도의 맨 꼭대기에는 unknown이, 맨바닥에는 never가 위치합니다. 이 두 타입은 계층의 양극단을 이루는 특별한 존재입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;unknown은 모든 타입의 슈퍼타입, 즉 최상위 타입입니다. 어떤 값이든 unknown 타입 변수에 할당할 수 있습니다. 외부 API로부터 어떤 형태의 데이터가 들어올지 알 수 없는 상황에서 유용하게 사용됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;let a: unknown;

a = 1;         // number → unknown ✅
a = "hello";   // string → unknown ✅
a = true;      // boolean → unknown ✅&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;모든 값을 받아들일 수 있다는 점에서 any와 비슷해 보이지만, 결정적인 차이가 있습니다. unknown 타입의 값은 다른 타입 변수에 할당할 수 없습니다. 즉, 들어오는 것은 자유롭지만 나가는 것은 엄격하게 제한됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;let a: unknown = "hello";
let b: string = a;
// 오류: 'unknown' 형식은 'string' 형식에 할당할 수 없습니다.&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반대쪽 끝에 있는 never는 모든 타입의 서브타입, 즉 최하위 타입입니다. never는 "절대 존재할 수 없는 값"을 나타내며, 어떤 값도 never 타입 변수에 할당할 수 없습니다. 실제로 never 타입이 되는 대표적인 경우는 항상 예외를 던지거나 무한 루프를 도는 함수의 반환 타입입니다. 이런 함수는 정상적으로 값을 반환하는 일이 절대 없으므로, 반환 타입이 never가 됩니다. 그런데 흥미로운 점은, never 자체는 모든 타입에 할당할 수 있다는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function throwError(): never {
  throw new Error("에러 발생");
}

let a: number = throwError(); // never → number ✅
let b: string = throwError(); // never → string ✅&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Conditional Type을 사용할 때 결과로 never가 자주 등장하는 것을 본 적이 있을 것입니다. type MyExclude&amp;lt;T, U&amp;gt; = T extends U ? never : T에서 조건에 해당하는 멤버를 never로 만들면 유니온에서 자동으로 사라집니다. 이것이 가능한 이유가 바로 never가 최하위 타입이기 때문입니다. never는 값의 집합 관점에서 보면 아무 값도 포함하지 않는 공집합에 해당합니다. 공집합을 다른 집합과 합쳐도 결과가 달라지지 않는 것처럼, never는 유니온에 포함되어도 아무런 영향을 주지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) any&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;any는 앞서 살펴본 타입 계층도 안에 위치한 타입이 아닙니다. unknown이나 never처럼 상하 관계로 설명할 수 있는 타입이 아니라, 타입 검사 자체를 우회하는 특별한 타입입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;let a: any;

// 모든 타입으로부터 할당받을 수 있음
a = 1;
a = "hello";
a = true;

// 모든 타입에 할당할 수도 있음
let b: number = a;  // any → number ✅
let c: string = a;  // any → string ✅&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;모든 타입에 할당할 수도 있고, 모든 타입으로부터 할당받을 수도 있습니다. 얼핏 보면 unknown(모든 것을 받아들이는)과 never(모든 곳에 할당 가능한)의 성질을 동시에 가진 것처럼 보이지만, 실제로는 성격이 완전히 다릅니다. unknown과 never는 계층 규칙을 철저히 따르면서 안정성을 보장하는 반면, any는 그 규칙 자체를 비활성화합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;any를 사용하면 타입 검사가 사실상 무력화됩니다. 숫자가 들어와야 할 자리에 문자열이 들어와도 컴파일러는 아무런 경고를 하지 않습니다. 타입스크립트를 사용하는 가장 큰 이유가 타입 안정성인데, any는 그 안정성을 스스로&amp;nbsp; 포기하는 선택입니다. 따라서 가능한 한 unknown으로 대체하고, 타입 좁히기를 통해 안전하게 사용하는 것이 권장됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) 기본 타입들의 위치&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;unknown과 never 사이에는 우리가 일상적으로 사용하는 타입들이 계층을 이루고 있습니다. string, number, boolean 같은 원시 타입은 계층의 중간에 위치하고, 리터럴 타입은 그 아래에 위치합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;let a: string = "hello";   // 리터럴 → 원시 타입 ✅
let b: "hello" = "hello";  // 리터럴 → 리터럴 ✅

let c: "hello" = a;
// 오류: 'string' 형식은 '"hello"' 형식에 할당할 수 없습니다.&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;"hello"는 string의 서브타입입니다. 따라서 "hello"를 string 변수에 넣는 것은 가능하지만, 반대로 string을 "hello” 변수에 넣는 것은 불가능합니다. string은 “hello" 뿐 아니라 "world", "abc"등 무한히 많은 문자열을 포함하는 더 넓은 타입이기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 관계를 떠올리면, 타입 좁히기가 왜 "좁아진다"는 표현을 쓰는지 자연스럽게 이해됩니다. typeof value === "string" 검사를 통과하면 string | number라는 넓은 타입에서 string이라는 좁은 타입으로 내려가는 것이고, 이는 타입 계층도에서 아래쪽으로 이동하는 것과 같습니다. 숫자 타입도 마찬가지입니다. number는 가능한 모든 숫자를 포함하는 넓은 타입이고, 42는 그중 딱 하나의 값만 허용하는 좁은 타입입니다. 이처럼 리터럴 타입은 원시 타입이 허용하는 값의 범위를 하나로 한정한 것이라고 이해하면 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;정리하면 타입 계층도의 큰 그림은 다음과 같습니다. 위에서부터 unknown -&amp;gt; string, number, boolean 등 원시 타입 -&amp;gt; “hello", 42 등 리터럴 타입 -&amp;gt; never 순서이며, any는 이 계층 바깥에서 모든 규칙을 우회하는 예외적 존재입니다. 참고로 이 계층도는 완전한 트리 구조라기보다, 타입 간의 포함 관계를 나타낸 것으로 이해하는 것이 더 정확합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3807/%E1%84%80%E1%85%B3%E1%84%85%E1%85%B5%E1%86%B71__1_.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, GPT로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;타입 호환성&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;타입 계층도가 타입 간의 상하 관계를 보여주는 지도라면, 타입 호환성은 그 지도를 기반으로 실제 할당이 가능한지를 판단하는 규칙입니다. 이 절에서는 업캐스팅과 다운캐스팅의 개념을 먼저 살펴본 뒤, 객체 타입에서 특히 중요한 구조적 타이핑과 초과 프로퍼티 검사까지 알아보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 업캐스팅과 다운캐스팅&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;타입 호환성의 핵심 규칙은 간단합니다. 좁은 타입에서 넓은 타입으로의 할당은 허용되고, 넓은 타입에서 좁은 타입으로의 할당은 차단됩니다. 좁은 타입을 넓은 타입에 할당하는 것을 업캐스팅이라고 합니다. 리터럴 42를 number 변수에 넣는 것이 대표적인 업캐스팅입니다. 42는 number가 허용하는 값 중 하나이므로 안전합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;let a: number = 42;       // 42(리터럴) → number ✅ 업캐스팅
let b: unknown = "hello"; // string → unknown ✅ 업캐스팅&lt;/code&gt;&lt;/pre&gt;&lt;p style="margin-left:36pt;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반대로 넓은 타입을 좁은 타입에 할당하는 것을 다운캐스팅이라고 합니다. number를 42 타입 변수에 넣으려 하면 오류가 발생합니다. number에는 42 외에도 0, -1, 3.14 등 수많은 값이 포함되어 있으므로, 42만 허용하는 변수에 넣는 것은 안전하지 않기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;let a: number = 100;
let b: 42 = a;
// 오류: 'number' 형식은 '42' 형식에 할당할 수 없습니다.&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 규칙은 모든 타입에 일관되게 적용됩니다. string은 unknown에 할당 가능하고(업캐스팅), unknown을 string에 넣는 것(다운캐스팅)은 불가능합니다. never의 경우에는 앞서 살펴본 것처럼 가능한 값이 하나도 없는 공집합이므로, 모든 타입의 부분집합으로 간주되어 어디에든 할당할 수 있습니다. 반대로 string을 never에 넣는 것은 불가능합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;참고로 여기서 사용한 업캐스팅과 다운캐스팅이라는 용어는 이해를 돕기 위한 비유입니다. 원래 이 용어는 Java나 C#처럼 명목적 상속 구조를 가진 언어에서 유래한 것으로, 구조적 타입 시스템을 사용하는 타입스크립트와 완전히 동일한 개념은 아닙니다. 다만 "좁은 타입에서 넓은 타입으로 올라간다", "넓은 타입에서 좁은 타입으로 내려간다"는 방향성은 같으므로, 직관적으로 이해하기 위해 빌려 쓴 것입니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;왜 이런 규칙이 있는 것일까요? 업캐스팅이 안전한 이유는 간단합니다. 좁은 타입의 값은 넓은 타입이 허용하는 범위 안에 항상 포함되기 때문입니다. 42는 분명히 숫자이므로 number 변수에 넣어도 문제가 없습니다. 하지만 다운캐스팅은 다릅니다. number에는 42뿐 아니라 0, -1, 3.14 등 무수히 많은 값이 포함되어 있으므로, 이를 42만 허용하는 변수에 넣으면 런타임에 예상치 못한 값이 들어올 위험이 있습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;타입스크립트는 이 위험을 컴파일 타임에 미리 차단해 주는 것입니다. 다만 함수 타입에서는 매개변수 위치에 반공변성(contravariance)이 적용되는 등, 값 타입과는 조금 다른 규칙이 존재합니다. 이 글에서는 값 타입 중심의 기본적인 호환성 규칙에 집중하겠습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 객체 타입의 호환성&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;원시 타입의 호환성은 직관적이지만, 객체 타입에서는 조금 다른 기준이 적용됩니다. 타입스크립트는 객체 타입의 호환성을 판단할 때 타입의 이름이 아니라 구조, 즉 어떤 프로퍼티를 가지고 있는지를 기준으로 삼습니다. 이를 구조적 타이핑(Structural Typing)이라고 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface User {
  name: string;
}

interface Employee {
  name: string;
  department: string;
}

let user: User = { name: "kim" };
let employee: Employee = { name: "lee", department: "dev" };

user = employee; // ✅ Employee → User 할당 가능&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;User와 Employee는 이름이 완전히 다른 타입이지만, Employee는 User가 요구하는 name: string 프로퍼티를 모두 갖고 있습니다. 타입스크립트는 이것만으로 할당이 가능하다고 판단합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서 중요한 점은, 대상 타입이 요구하는 구조를 모두 만족하는지가 호환성의 기준이라는 것입니다. 구조적 타입 시스템에서는 대체로 더 많은 요구 사항(프로퍼티)을 가진 타입이 더 구체적(좁은) 타입으로 취급됩니다. Employee는 User가 요구하는 name: string을 갖고 있으면서 department까지 추가로 가지고 있으므로, User보다 더 구체적인 타입이고 따라서 User에 할당 가능합니다. 반대로 User를 Employee에 할당하려 하면 department 프로퍼티가 빠져 있으므로 오류가 발생합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;employee = user;
// 오류: 'department' 속성이 'User' 형식에 없습니다.&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 규칙은 Java나 C#처럼 타입의 이름으로 호환성을 판단하는 명목적 타이핑(Nominal Typing)과 대조됩니다. 명목적 타이핑에서는 User와 Employee가 명시적으로 상속 관계를 선언하지 않는 한 서로 호환되지 않습니다. 이름이 다르면 구조가 아무리 비슷해도 별개의 타입으로 취급합니다. 하지만 타입스크립트는 구조만 맞으면 호환된다고 판단하므로, 별도의 상속 선언 없이도 유연하게 타입을 다룰 수 있습니다. 자바스크립트 생태계에서는 서로 다른 라이브러리가 비슷한 구조의 객체를 주고받는 일이 잦기 때문에, 이러한 구조적 타이핑이 실무에서 큰 장점으로 작용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3807/%EA%B7%B8%EB%A6%BC2__5_.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude AI로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) 초과 프로퍼티 검사&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;구조적 타이핑의 규칙대로라면, 프로퍼티가 더 많은 객체는 항상 할당 가능해야 합니다. 하지만 한 가지 예외가 있습니다. 객체 리터럴을 직접 할당할 때는 정의되지 않은 프로퍼티가 있으면 오류가 발생합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface User {
  name: string;
}

let user: User = {
  name: "kim",
  age: 25,
  // 오류: '{ name: string; age: number; }' 형식은 'User' 형식에 할당할 수 없습니다.
  // 개체 리터럴은 알려진 속성만 지정할 수 있으며 'User' 형식에 'age'이(가) 없습니다.
};&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이를 초과 프로퍼티 검사(Excess Property Check)라고 합니다. 이 검사는 개발자가 오타를 내거나, 존재하지 않는 프로퍼티를 실수로 작성하는 것을 방지하기 위한 안전장치입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 같은 객체를 변수에 먼저 담은 뒤 할당하면 이 검사를 우회할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;const person = { name: "kim", age: 25 };
let user: User = person; // ✅ 오류 없음&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;변수 person에 담긴 시점에서 타입스크립트는 person의 타입을 { name: string; age: number }로 추론합니다. 이후 user에 할당할 때는 일반적인 구조적 타이핑 규칙이 적용되므로, name: string을 갖고 있는 것만 확인하고 통과시킵니다. 초과 프로퍼티 검사는 오직 객체 리터럴을 직접 할당할 때만 동작한다는 점을 기억해 두면 좋습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 동작이 처음에는 일관성이 없어 보일 수 있지만, 실용적인 관점에서 보면 합리적입니다. 객체 리터럴을 직접 작성할 때는 개발자가 의도한 프로퍼티만 정확히 넣었는지 확인하는 것이 유용합니다. 반면에 이미 만들어진 객체를 전달할 때는, 그 객체가 필요한 프로퍼티를 모두 갖고 있다면 추가 프로퍼티가 있어도 문제가 되지 않기 때문입니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;extends 다시 보기&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;타입 계층도와 호환성 규칙을 이해했으니, 이제 extends 키워드의 의미를 정확하게 짚어볼 수 있습니다. extends는 타입스크립트에서 주로 "할당 가능한가(assignable to)?"를 검사하는 데 사용됩니다. 대부분의 경우 이것은 서브타입 관계와 동일하게 동작하지만, 앞서 살펴본 any처럼 계층 규칙을 벗어나는 특수한 타입이 있으므로 엄밀히 말하면 완전히 같은 개념은 아닙니다. 다만 일반적인 타입을 다루는 상황에서는 "서브타입인가?"와 "할당 가능한가?"를 거의 같은 의미로 이해해도 무방합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) Conditional Type의 extends&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Conditional Type의 기본 형태를 다시 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type IsString&amp;lt;T&amp;gt; = T extends string ? true : false;&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서 T extends string은 "T가 string의 서브타입인가?", 다시 말해 "T가 string에 할당 가능한가?"를 묻는 것입니다. 타입 계층도에서 T가 string보다 아래(더 좁은 위치)에 있으면 참이 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type A = IsString&amp;lt;"hello"&amp;gt;; // true — "hello"는 string의 서브타입
type B = IsString&amp;lt;42&amp;gt;;      // false — 42는 string의 서브타입이 아님&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;"hello"가 true가 되는 이유는 앞서 살펴본 것처럼 리터럴 타입이 원시 타입의 서브타입이기 때문입니다. 타입 계층도에서 "hello"는 string 아래에 위치하므로 extends 검사를 통과합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Exclude의 구현에도 같은 원리가 적용됩니다. type MyExclude&amp;lt;T, U&amp;gt; = T extends U ? never : T에서 유니온의 각 멤버가 U의 서브타입인지를 검사하고, 서브타입이면 never로 제거하는 것입니다. 계층 구조를 알고 나면, 이 동작이 더 이상 마법처럼 느껴지지 않습니다. 참고로 분배적 조건부 타입의 동작도 결국 이 서브타입 검사가 유니온의 각 멤버에 개별적으로 적용되는 것이라는 점을 떠올려보면, extends의 의미가 한 층 더 명확해집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 제네릭 제약 조건의 extends&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;제네릭에서 사용되는 extends도 같은 뿌리에서 출발합니다. 다음 예시를 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function getLength&amp;lt;T extends { length: number }&amp;gt;(arg: T): number {
  return arg.length;
}

getLength("hello");    // ✅ string은 length를 가짐
getLength([1, 2, 3]);  // ✅ 배열은 length를 가짐
getLength(42);
// 오류: 'number' 형식은 '{ length: number }' 형식의 제약 조건을 만족하지 않습니다.&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;T extends { length: number }는 "T는 { length: number }의 서브타입이어야 한다"는 제약입니다. 구조적 타이핑의 관점에서 보면, T가 최소한 length: number 프로퍼티를 갖고 있어야 한다는 의미입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;string은 length 프로퍼티를 가지고 있으므로 { length: number }의 서브타입이고, number는 length 프로퍼티가 없으므로 서브타입이 아닙니다. 배열 역시 length 프로퍼티를 가지고 있으므로 제약을 만족합니다. 이처럼 제네릭 제약 조건의 extends도 결국 구조적 타이핑을 기반으로 서브타입 여부를 검사하는 것입니다. 타입 계층도, 구조적 타이핑, 그리고 extends, 이 세 가지가 하나의 맥락으로 연결되는 것을 확인할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 타입스크립트의 타입 계층도와 타입 호환성, 그리고 extends 키워드의 정확한 의미를 살펴보았습니다. 타입스크립트의 모든 타입은 unknown(최상위)부터 never(최하위)까지 하나의 계층을 이루고 있으며, 좁은 타입에서 넓은 타입으로의 할당만 안전하게 허용됩니다. 객체 타입의 경우에는 이름이 아닌 구조를 기준으로 호환성을 판단하는 구조적 타이핑이 적용되고, 대체로 더 많은 프로퍼티를 요구하는 쪽이 더 좁은(구체적인) 타입이 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 규칙을 이해하고 나면, 여러 문법에서 등장하던 개념들이 하나의 원리로 연결됩니다. Conditional Type에서 T extends U는 "T가 U에 할당 가능한가?"를 묻는 것이고, 제네릭의 T extends { length: number }는 "T가 이 구조에 할당 가능해야 한다"는 제약이며, 타입 좁히기에서 타입이 "좁아진다"는 것은 계층도에서 아래쪽의 더 구체적인 타입으로 이동한다는 뜻입니다. 결국 같은 규칙이 서로 다른 문법으로 표현되고 있었던 셈입니다. 타입 계층도라는 하나의 지도를 손에 쥐고 나면, 앞으로 어떤 새로운 타입 문법을 만나더라도 그 동작을 스스로 추론해 볼 수 있을 겁니다.&lt;/p&gt;&lt;hr&gt;&lt;p style="text-align:justify;"&gt;&amp;lt;출처&amp;gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;한 입 크기로 잘라먹는 타입스크립트 - &lt;a href="https://ts.winterlood.com/71f4a577-4340-4994-956d-a7aa47176ffa"&gt;&lt;u&gt;타입 단언&lt;/u&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;한 입 크기로 잘라먹는 타입스크립트 - &lt;a href="https://ts.winterlood.com/1d6906f2-b724-43d0-bc61-8ec455e6d8e8"&gt;&lt;u&gt;타입 계층도와 함께 기본타입 살펴보기&lt;/u&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>클로드 코드를 떠나 오픈소스로 돌아간 이유</title><link>https://yozm.wishket.com/magazine/detail/3801</link><description>데모 마감 2시간 전, 치명적인 버그 앞에서 클로드 코드가 멈췄습니다. 사용 한도 초과, 4시간 후에 다시 시도하라는 메시지가 떴죠. 생계가 걸린 도구가 가장 필요한 순간에 작동하지 않는다면, 과연 그 도구를 믿을 수 있을까요? 예측하기 어려운 사용량 제한과 공지 없는 정책 변경에 지쳐 탈클로드를 결심한 엔지니어가, Ollama·DeepSeek·Qwen 3 Coder 같은 오픈소스 모델로 워크플로우를 다시 짜며 느낀 점을 썼습니다. 심상치 않은 탈클로드 코드 움직임과, 그 해결책으로 떠오르는 오픈소스 코딩 에이전트 활용법을 제 경험 기반으로 소개해보려 합니다.</description><guid>https://yozm.wishket.com/magazine/detail/3801</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;엔지니어들은 왜 다시 오픈소스로 회귀하는가?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;클로드 코드&lt;span style="color:#757575;"&gt;(Claude Code)&lt;/span&gt;, 코덱스&lt;span style="color:#757575;"&gt;(Codex)&lt;/span&gt;와 같은 코딩 에이전트의 인기는 개발자나 바이브 코더들 사이에서 독보적입니다. 유행처럼 번지는 “이제 AI가 웬만한 신입 개발자보다 코딩을 잘한다”는 말 역시, 사실은 클로드의 Opus나 오픈AI의 GPT 같은 고성능 파운데이션 모델, 그리고 이를 기반으로 한 코딩 에이전트에 한정된 이야기 아닐까 싶습니다. 그만큼 다른 경쟁 제품과 비교해 성능이 압도적이고, 사용 경험도 편리합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;저 역시 지난해 말 처음 클로드 코드를 접했을 때의 신선한 충격을 아직도 기억합니다. 무엇보다 VS Code나 IntelliJ 같은 코드 에디터에서 작동하는 Copilot 등과 달리 터미널에서 작동한다는 점이 매우 독특했습니다. 간단한 설치와 권한 부여만 마치면 자연어로 &lt;strong&gt;‘xxxx.py 파일의 124번째 줄 함수를 디버깅하고, main.py 파일에 통합해 줘.’&lt;/strong&gt;라고만 명령해도, 그런 섬세한 작업까지 수행할 수 있다는 점이 꽤 센세이셔널하게 다가왔습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그동안의 코딩 도구가 개발자의 생산성을 높여주는 ‘어시스턴트’에 머물렀다면, 클로드 코드는 ‘내 부하직원처럼 직접 코딩해주는 진짜 AI 에이전트’에 가까운 느낌이라고 할까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3801/image5.png"&gt;&lt;figcaption&gt;Claude code CLI &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;앤트로픽은 저와 같은 클로드 코드 지지자들의 성원에 힘입어, 2026년 기준 연환산 매출 300억 달러&lt;span style="color:#757575;"&gt;(약 41조 원)&lt;/span&gt;를 넘어설 정도로 폭발적인 인기를 누려왔습니다. 그런데 최근 들어 개발자들 사이에서 클로드 구독을 취소하는, 이른바 ‘탈클로드’ 움직임이 빠르게 늘고 있다고 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;지금까지 입이 아플 정도로 클로드 코드의 장점을 이야기했지만, 사실 이 도구는 단점도 분명합니다. 가장 먼저 떠오르는 것은 막대한 토큰 소모량과 만만치 않은 가격입니다. 코덱스 같은 도구가 비교적 적은 소모량으로 인기를 얻었지만, 그 역시 본질적인 해결책은 아닙니다. 저 역시 이러한 문제로 탈 클로드를 결심했습니다. 그렇다면 대안은 있을까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 심상치 않은 탈클로드 코드 움직임과, 그 해결책으로 떠오르는 오픈소스 코딩 에이전트 활용법을 제 경험 기반으로 소개해보려 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;엔지니어들의 탈클로드 러쉬&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;최근 개발자들이 자주 찾는 커뮤니티 레딧&lt;span style="color:#757575;"&gt;(Reddit)&lt;/span&gt;에서 눈에 띄는 스레드 하나를 발견했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;i&gt;I am cancelling my Claude Pro subscription and here's my honest take.&lt;/i&gt;&lt;br&gt;&lt;span style="color:#999999;"&gt;&lt;i&gt;클로드 프로 구독 취소합니다. 솔직한 후기&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3801/image3.png"&gt;&lt;figcaption&gt;&amp;lt;출처: Reddit r/PromptEngineering&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;댓글창은 비슷한 경험담으로 가득했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;나만 그런 게 아니었구나. 어제도 오전에만 제한이 3번 걸렸어.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;Pro 플랜인데 Free tier보다 못한 느낌. 농담 아니고.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;월 20달러 내면서 매일 ‘사용 한도 초과’ 보는 게 정상인가요?&lt;/li&gt;&lt;li style="text-align:justify;"&gt;방금 전환했습니다. DeepSeek + Ollama 조합. 솔직히 후회 없어요.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;한때 “클로드 없이 어떻게 개발해?”라고 말하던 개발자들이, 이제는 집단으로 ‘탈클로드’를 선언하고 있는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 같은 엔지니어들의 탈클로드 움직임은 역설적으로 앤트로픽의 엄청난 성공에서 비롯됐습니다. 클로드 코드는 단순한 대화형 AI보다 훨씬 많은 컴퓨터 자원을 사용합니다. 파일을 읽고, 코드를 분석하고, 여러 파일을 동시에 수정하는 것은 물론 터미널 명령어까지 실행해야 하기 때문입니다. 사용자가 AI에 명령을 내릴 때마다 거대한 서버 자원이 쉬지 않고 돌아가야 하는 셈입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 앤트로픽은 불가피한 선택을 내렸습니다. 바로 사용량 제한&lt;span style="color:#757575;"&gt;(rate limit)&lt;/span&gt;을 대폭 강화한 것입니다. 그로 인해 Pro 플랜 사용자조차 하루 몇 시간만 집중적으로 작업하면 “사용 한도 초과” 메시지를 마주했습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:50%;"&gt;&lt;img src="https://www.wishket.com/media/news/3801/image2_JIrUeed.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 인터넷 커뮤니티&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1. 예측 불가능한 블랙박스&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이런 상황을 키우는 더 큰 문제가 있습니다. 사용량 기준이 완전히 불투명하다는 점입니다. 앤트로픽 지원팀에 “정확히 얼마나 쓸 수 있는 건가요? 요청 횟수, 토큰 수, 아니면 시간?”이라고 문의했을 때 돌아온 답변은 애매했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;i&gt;“구체적인 한도는 공개하지 않습니다. 사용 패턴과 시스템 부하에 따라 달라질 수 있습니다.”&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 사용자는 언제 제한이 걸릴지 예측조차 할 수 없습니다. 똑같은 작업을 해도 어떤 날은 하루 종일 문제없지만, 어떤 날은 2시간 만에 막히기도 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실제로 한 개발자의 실험 결과에 따르면, 중간 규모 프로젝트 리팩터링(refactoring)은 약 2시간 30분 후 제한이 걸렸고, 여러 파일을 수정하는 신규 기능 개발은 약 3시간, 버그 디버깅 작업은 약 4시간 후 제한에 도달했습니다. 풀타임으로 일하는 개발자라면, 점심시간도 오기 전에 소진되는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;저 역시 정확히 같은 문제를 겪었습니다. 데모 마감 2시간 전, AI 에이전트 데모에서 치명적인 버그를 발견했습니다. “괜찮아, 클로드한테 맡기면 10분이면 해결돼”라고 생각하며 코드 수정을 시작했는데, 불과 5분 만에 화면에 메시지가 떴습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;i&gt;You've reached your usage limit. Please try again in 4 hours.&lt;/i&gt;&lt;br&gt;&lt;span style="color:#757575;"&gt;&lt;i&gt;사용 한도에 도달했습니다. 4시간 후에 다시 시도해주세요&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그 순간 머릿속이 하얘졌습니다. 결국 Gemini를 급하게 사용하고 Cursor로 보조한 다음, Stack Overflow를 뒤져가며 간신히 문제를 해결했습니다. 데모는 무사히 끝났지만, 그날 밤 한 가지를 깨달았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;제 생계가 걸린 도구가 가장 필요한 순간에 작동하지 않는다면, 과연 그 도구를 믿을 수 있을까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2. 공지 없는 정책 변경&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;더 강한 결정타는 올해 2월 말 터졌습니다. 갑자기 같은 작업을 해도 이전보다 훨씬 빨리 제한이 걸리기 시작한 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;당시 어제까지 멀쩡하게 쓰던 프로젝트가 오늘은 2시간 만에 막혔다는 불만부터, 사전 공지도 없이 이런 변경을 하는 건 사실상 일방적인 계약 변경 아니냐는 항의까지 이어졌습니다. 하지만 지원팀에 문의한 사람들이 받은 답변은 “시스템 최적화”라는 모호한 설명뿐이었습니다. 트위터에서는 ‘#ClaudeLimits’ 해시태그가 트렌딩에 올랐고, 일부 사용자는 환불을 요구하기 시작했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3801/image6.png"&gt;&lt;figcaption&gt;&amp;lt;출처: &lt;a href="https://www.reddit.com/r/Anthropic/comments/1sgomf6/its_happening_they_cut_the_usage_for_literally/"&gt;reddit r/Anthropic&lt;/a&gt;&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3. 무너진 비용 대비 가치&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;클로드 코드를 사용하려면 Pro는 월 20달러, Max는 월 100~200달러 수준의 구독료를 지불해야 합니다. 초기에는 클로드 코드가 가져다주는 생산성 향상이 이 비용의 가치를 충분히 증명했습니다. 많게는 하루 5~6시간씩 절약되는 시간을 시급으로 환산하면, 오히려 저렴한 투자처럼 느껴졌죠. 물론 지금도 여전히 클로드는 가성비가 좋은 편이라고 생각합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만, 불분명한 사용량과 빠르게 늘어나는 토큰 활용량으로 비용 대비 가치에 의문을 제기하는 목소리도 커지고 있습니다. 같은 돈을 내더라도 실제 사용 가능 시간은 줄어들고, 정작 가장 급한 순간에는 쓸 수 없는 상황이 반복되고 있기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;사실 이 정도 비용이면 클라우드 GPU 인스턴스를 빌려 사용량 제한 없이 오픈소스 모델을 실행할 수 있습니다. 더 나아가 중고 Mac mini를 구매해 로컬 환경에서 Ollama로 모델을 무제한 실행하는 선택지도 있죠. 결국 예측할 수 있으며 통제 가능한 비용 구조가, 오히려 더 합리적인 대안처럼 보이기 시작한 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;앤트로픽은 무리한 서비스 확장 속에서 안정성과 예측 가능성이라는 가장 중요한 요소를 놓치고 있는지도 모릅니다. 클로드 코드의 불확실성에 지친 저는 자연스럽게 오픈소스 모델로 눈을 돌리게 됐습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;오픈소스 모델이 대안이 될 수 있을까?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;솔직히 처음에는 회의적이었습니다. LLM 성능은 상당수 모델 크기에 좌우되는 만큼, SoTA 모델에 훨씬 못 미치는 오픈소스 모델이 과연 그만큼 잘할 수 있을까?라는 의구심이 쉽게 사라지지 않았기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 2026년 현재, 오픈소스 모델 진영의 발전 속도는 제 예상을 훨씬 뛰어넘고 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1. 생각보다 좁혀진 성능 격차&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Meta의 Llama 3.1(405B), DeepSeek의 V3 모델, 그리고 Qwen 3 Coder 같은 오픈소스 모델은 적어도 벤치마크 기준으로는 상용 모델과의 성능 격차를 빠르게 좁히고 있습니다. 특히 코딩 특화 모델인 DeepSeek Coder V2와 Qwen 3 Coder는 HumanEval 벤치마크에서 Claude 3.5 Sonnet과 비교해도 뒤지지 않는 성능을 보여주고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3801/image4.png"&gt;&lt;figcaption&gt;DeepSeek vs SOTA Models &amp;lt;출처: &lt;a href="https://www.bracai.eu/post/deepseek-performance"&gt;bracai&lt;/a&gt;&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;물론 아직 Claude 4.5 Sonnet의 SWE-Bench Pro 점수에는 미치지 못합니다. 다만 그 격차가 점점 빠르게 줄어드는 분위기입니다. 벤치마크 기준으로 좀 더 살펴보면 다음과 같습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;DeepSeek Coder V2:&lt;/strong&gt; Claude 3.5 Sonnet과 유사한 수준입니다. 코딩 작업에서는 거의 동등한 성능을 보여줍니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Qwen 3 Coder:&lt;/strong&gt; GPT-4 Turbo와 Claude 3 Opus 사이 정도의 성능입니다. 복잡한 코딩 작업도 대부분 처리할 수 있습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Llama 3.1 70B:&lt;/strong&gt; GPT-3.5 Turbo나 Claude 3 Haiku 수준입니다. 기본적인 코딩 작업에는 충분하지만, 복잡한 로직에서는 다소 한계가 있습니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실제로 간단한 테스트를 진행해본 결과, 일상적인 코딩 작업에서는 DeepSeek Coder V2나 Qwen 3 Coder 같은 오픈소스 모델도 Claude 3.5 Sonnet 못지않게 충분히 실용적이었습니다. 함수 작성, 버그 수정, 코드 설명, 단위 테스트 생성 같은 작업에서는 체감상 큰 차이를 느끼기 어려웠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Llama 3.1 70B나 Mistral Large 같은 모델을 사용할 때는 분명한 한계도 있었습니다. 복잡한 로직을 설명할 때는 조금 더 명확한 지시사항이 필요했고, 여러 파일을 동시에 다루는 작업에서는 맥락(context)을 놓치는 경우도 있었습니다. 다만 프롬프트를 조금 더 세밀하게 작성하면, 대부분 원하는 결과를 얻을 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;물론 복잡한 아키텍처 설계나 여러 파일에 걸친 대규모 리팩터링 작업에서는 여전히 클로드 계열이 우위에 있습니다. 이런 수준의 작업에서는 클로드 기반 모델의 뛰어난 추론 능력과 장문 맥락 처리 능력이 확실한 강점을 보여줍니다. 반면 오픈소스 모델은 때때로 복잡한 의존성을 놓치거나, 긴 요구사항을 정확히 따르지 못하는 경우가 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 현실의 개발 업무를 들여다보면, 일상적인 작업의 80~90%는 DeepSeek Coder V2나 Qwen 3 Coder 정도의 성능, 즉 Claude 3.5 Sonnet 수준으로도 충분히 처리할 수 있습니다. 반대로 Claude 4.5 Sonnet 수준이 꼭 필요한 작업은 나머지 10~20% 수준의 복잡한 업무에 가깝습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그렇다면 매일 모든 작업에 가장 강력한 모델을 써야 할까요? 아니면 대부분의 업무는 충분한 성능의 모델로 처리하고, 정말 필요한 순간에만 최고 성능 모델을 선택해야 할까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실무 관점에서 보면 후자가 훨씬 합리적입니다. 모든 작업에 안정적으로 활용할 수 없다면, 차라리 무제한 사용이 가능한 중급 성능 모델을 메인으로 사용하고, 정말 중요한 순간에만 클로드를 꺼내 쓰는 편이 더 효율적일 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2. 다양해진 실행 옵션&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;과거에는 오픈소스 모델을 실행하려면 고가의 GPU 서버가 사실상 필수였습니다. 하지만 이제는 상황이 달라졌습니다. 생각보다 적은 컴퓨팅 자원만으로도 로컬 환경에서 충분히 실행할 수 있기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;대표적으로 Ollama 같은 도구를 사용하면 일반 노트북에서도 7B~14B 파라미터를 가진 모델을 쓸만한 속도로 구동할 수 있습니다. 32GB RAM 환경이라면 적절한 양자화(quantization)를 적용해 32B 모델까지도 무리 없이 돌아갑니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3801/image1.png"&gt;&lt;figcaption&gt;Ollama로 오픈소스 모델 활용하기 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;클라우드 GPU를 임대하는 방법도 있습니다. RunPod, Vast.ai 같은 서비스를 이용하면 시간당 약 0.5~1달러 수준으로 고성능 GPU를 빌릴 수 있습니다. 필요할 때만 켜고 끌 수 있어 비용 통제도 비교적 쉽습니다. 단순 계산으로 보면, 클로드 Pro 구독료(월 20달러) 수준의 비용으로 약 20~40시간 정도 GPU를 사용할 수 있는 셈입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한, 오픈소스 모델 호스팅 서비스를 활용하는 선택지도 있습니다. Groq이나 Together AI 같은 플랫폼은 클로드 API보다 훨씬 저렴한 가격으로 오픈소스 모델을 제공합니다. 특히 Groq은 초당 수백 토큰에 이르는 추론 속도를 제공하는 것으로 유명한데, 비용은 Claude API 대비 약 10분의 1 수준입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;게다가 Llama 같은 고품질 모델에 대해서도 사용량 제한이 Claude보다 훨씬 관대한 편입니다. 일부 모델은 사실상 제한 없이 사용할 수 있다는 점도 강점으로 꼽힙니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3801/image7.png"&gt;&lt;figcaption&gt;Groq의 거의 무제한에 가까운 사용량 &amp;lt;출처: &lt;a href="https://groq.com/groqcloud"&gt;Groq&lt;/a&gt;&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3. 진짜 장점은 자유와 통제권&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;제가 여러 오픈소스 모델을 다양한 방법으로 테스트하며 느낀 가장 큰 장점은 성능이나 가격이 아니었습니다. 바로 자유와 통제권입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;우선 이 방식에는 사용량 제한이 없습니다. 로컬에서 돌리든, 클라우드에서 돌리든 24시간 내내 원하는 만큼 쓸 수 있습니다. 급한 작업 도중 “사용 한도 초과” 메시지를 볼 걱정도 없습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;오프라인 환경에서도 작동한다는 점 역시 큰 장점입니다. 인터넷이 끊겨도, 서비스가 다운되어도, 로컬 모델은 계속 돌아갑니다. 보안이 중요한 프로젝트에서 코드를 외부 서버로 전송할 필요도 없습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;마지막 장점은 커스터마이징이 가능하다는 점입니다. 필요하다면 모델을 파인튜닝하거나, 프롬프트를 자유롭게 실험하고, 여러 모델을 조합해 쓸 수도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;처음 클로드 코드를 만났을 때, 저는 진정한 AI 에이전트의 가능성을 목격했습니다. 클로드 모델의 성능은 정말 뛰어납니다. 하지만 뛰어난 성능만으로는 충분하지 않다는 것을 알았습니다. 예측하기 어려운 사용 제한, 공지 없는 정책 변경, 그리고 내가 통제할 수 없는 변수들 앞에서 저는 AI 엔지니어로서의 정체성마저 의심하게 되었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;탈클로드를 결심한 이래, 지난 수개월은 시행착오의 연속이었습니다. 하지만 그 과정에서 생각보다 많은 것을 배웠습니다. 오픈소스로의 전환은 단순히 도구를 바꾸는 일 그 이상입니다. 엔지니어로서 독립성과 안정성을 되찾는 과정이었고, 그만큼 얻은 것도 많았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;제가 현재 운영하는 워크플로우는 이렇습니다. 일상적인 코딩 작업은 로컬 Ollama에서 Qwen 3 Coder를 실행합니다. 복잡한 논리 설계가 필요할 때는 Groq의 호스팅 서비스로 DeepSeek V3를 사용합니다. 그렇게 해도 풀리지 않으면, 정말 필요한 순간에만 클로드 API를 호출합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이렇게 운영하니 비용도 줄었고, 사용량 제한에 걸릴 일도 거의 사라졌습니다. 역설적으로 의존도를 낮추자, 정작 필요할 때 클로드를 더 효과적으로 활용할 수 있게 됐습니다. 수개월간 오픈소스 코딩 에이전트를 사용하며 느낀 점은 분명했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;오픈소스 모델이 클로드의 완벽한 대체재는 아닙니다. 여전히 결과물이 다소 어색하거나 품질이 떨어지는 경우도 많습니다. 복잡한 아키텍처 설계나 대규모 리팩터링에서는 여전히 클로드 코드가 큰 우위에 있습니다. 하지만 현실의 개발 업무는 그런 이분법으로 나뉘지 않습니다. 대부분의 작업은 오픈소스 모델로도 충분히 처리할 수 있을 거라는 가능성을 보았습니다. 부족한 20%를 위해, 나머지 80%를 불안정한 서비스에 맡길 이유는 없다고 느꼈습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;개발자들의 탈클로드 움직임은 단순한 ‘가격 불만’ 때문은 아닙니다. 이것은 선택권을 되찾으려는 엔지니어들의 의식 있는 움직임에 가깝습니다. 한 회사의 정책에 종속되지 않고, 자신의 상황에 맞는 도구를 선택할 자유를 요구하는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;소프트웨어 엔지니어링 역사를 돌아보면, 가장 성공한 기술은 늘 이런 자유도를 제공했습니다. Linux가 Windows를 넘어 서버 운영 체제의 표준이 된 이유도 단순히 가격 때문만은 아닙니다. 사용자가 원하는 방식으로 커스터마이징하고, 직접 통제할 자유가 있었기 때문입니다. 오픈소스 모델의 부상 역시 같은 맥락 안에 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이제 오픈소스 모델은 “충분히 좋은” 수준까지 올라왔습니다. 클로드 코드가 여전히 더 좋다는 점은 인정합니다. 하지만 개발자들은 합리적입니다. “더 좋은” 도구를 하루 3시간만 쓰는 것보다, “충분히 좋은” 도구를 24시간 안정적으로 쓰는 편이 실무에서는 더 가치 있을 지도 모릅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;클로드 코드 독점 시대는 서서히 끝나가고 있습니다. 이제는 개발자가 자신의 필요에 맞는 도구를 선택하는 시대입니다. 그리고 그 전환에 필요한 것은 이미 충분히 갖춰져 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>나만의 세컨 브레인: 옵시디언 기반 LLM 위키 구축기</title><link>https://yozm.wishket.com/magazine/detail/3792</link><description>앞서 기고한 “오늘 뭐부터 하지?” AI 비서 에이전트 만들어봤습니다에서는 흩어진 프로젝트 정보를 한곳에 모아, AI 비서가 매일 아침 프로젝트 현황과 Todo 우선 순위를 브리핑해 주는 시스템을 공유했습니다. 이러한 시스템으로 제 업무에 대한 맥락을 정리했지만, 정작 그 일을 수행하는 '나 자신'에 대한 맥락은 어떻게 효율적으로 정리할지가 고민이었죠. 때마침 안드레 카파시(Andrej Karpathy)가 ‘LLM 위키’라는 아이디어를 제시했고, 그 개념을 저의 컨텍스트 정리에 적용해 보고자 했습니다. 그래서 옵시디언(Obsidian), 깃허브(GitHub), 클로드 코드(Claude Code)의 조합으로 나만의 세컨드 브레인인 LLM 위키를 구축했는데요. 이번 글에서는 그 과정과 LLM 위키 구축 경험에서 얻은 인사이트를 정리해 봤습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3792</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;최근 많은 사람들이 클로드(Claude), 챗지피티(ChatGPT), 제미나이(Gemini) 같은 다양한 AI 도구를 사용하는 것이 일상이 되었습니다. 하지만 사용하는 AI 도구가 늘어날수록 우리는 늘 컨텍스트를 새로 전달해야 하는 번거로움을 겪게 됩니다. 즉, 본인의 상황과 맥락을 &lt;strong&gt;AI에게 매번 설명&lt;/strong&gt;해야 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;앞서 기고한 &lt;a href="https://yozm.wishket.com/magazine/detail/3692/"&gt;“오늘 뭐부터 하지?” AI 비서 에이전트 만들어봤습니다&lt;/a&gt;에서는 흩어진 프로젝트 정보를 한곳에 모아, AI 비서가 매일 아침 프로젝트 현황과 Todo 우선 순위를 브리핑해 주는 시스템을 공유했습니다. 이러한 시스템으로 제 업무에 대한 맥락을 정리했지만, 정작 그 일을 수행하는 &lt;strong&gt;'나 자신'에 대한 맥락&lt;/strong&gt;은 어떻게 효율적으로 정리할지가 고민이었죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;당시 때마침 안드레 카파시(Andrej Karpathy)가 ‘LLM 위키’라는 아이디어를 제시했고, 그 개념을 저의 컨텍스트 정리에 적용해 보고자 했습니다. 그래서 옵시디언(Obsidian), 깃허브(GitHub), 클로드 코드(Claude Code)의 조합으로 나만의 세컨드 브레인인 &lt;strong&gt;LLM 위키를 구축&lt;/strong&gt;했는데요. 이번 글에서는 그 과정과 LLM 위키 구축 경험에서 얻은 인사이트를 정리해 봤습니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;미리 요점만 콕 집어보면?&lt;/strong&gt;&lt;/h4&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;여러 AI에게 매번 나의 상황과 맥락을 설명해야 하는 일은 결국 ‘흩어진 컨텍스트’와 '나 자신을 데이터로 다루는 시스템'이 없기 때문에 발생합니다.&lt;/li&gt;&lt;li&gt;옵시디언, 깃허브, 클로드 코드 CLI의 조합으로 안드레 카파시의 LLM 위키 아이디어를 제 자신만의 세컨드 브레인으로 적용해 구축해 보았습니다.&lt;/li&gt;&lt;li&gt;프로덕트 메이커(Product Maker)에게 개인 컨텍스트의 자산화는 단순히 일회성으로 컨텍스트를 정리하는 것에 그치지 않고, 장기적 관점에서 AI 활용의 생산성을 극대화하는 일에 가깝습니다.&lt;/li&gt;&lt;/ul&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;나만의 LLM 위키를 만든 이유&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 여러 곳에 흩어져 있는 컨텍스트&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;최근에는 다양한 AI 도구들이 저마다의 장단점을 가지고 있어, 사용자들이 &lt;strong&gt;여러 AI 도구를 이용&lt;/strong&gt;하는 경우가 많습니다. 저 역시 서비스 기획이나 비즈니스 아이디어 정리는 클로드 챗의 프로젝트 기능을 사용하고, 가벼운 검색이나 이미지 생성은 챗지피티를, 코드 작업은 클로드 코드, 디자인은 클로드 디자인, 유튜브 요약과 글쓰기 보조 도구로는 제미나이 챗을 사용하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/1__%EC%9D%BC%EA%B4%80%EB%90%9C_%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8_%EA%B4%80%EB%A6%AC%EC%9D%98_%EC%96%B4%EB%A0%A4%EC%9B%80.png"&gt;&lt;figcaption&gt;일관된 컨텍스트 관리의 어려움 &amp;lt;출처: ChatGPT 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이처럼 여러 AI 도구를 병행하다 보니 각 도구마다 저의 상황과 맥락을 반복해서 설명해야 했고, &lt;strong&gt;컨텍스트의 일관성&lt;/strong&gt;을 유지하기도 쉽지 않았습니다. 게다가 정보가 수집되고 정리되는 채널도 제각각이었습니다. 가벼운 메모는 구글 킵(Keep), 회의록은 노션(Notion), 업무 문서는 구글 워크스페이스(Google Workspace), 그리고 코드와 프로젝트 데이터는 깃허브(GitHub)에 흩어져 있는 식이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 분산된 정보의 통합&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;그래서 저는 이번 LLM 위키 구축을 통해 구글 킵, 노션, 구글 스페이스, 깃허브 등 여러 곳에 흩어져 있는 모든 정보를 &lt;strong&gt;하나의 일관된 시스템으로&lt;/strong&gt; 통합해 보기로 했습니다. 분산된 정보는 AI가 '나 자신'의 온전한 맥락을 파악하는 데 가장 큰 장애물이 되며, 이 상태로는 AI 에이전트의 생산성이 제한될 수밖에 없다고 생각했기 때문입니다. 따라서 모든 형태의 개인 데이터를 한곳에 모아 AI가 쉽게 접근하고 활용할 수 있는 세컨드 브레인 구축을 시작했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/2__%EC%98%B5%EC%8B%9C%EB%94%94%EC%96%B8%EC%9D%84_%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC_%EB%B6%84%EC%82%B0%EB%90%9C_%EC%A0%95%EB%B3%B4%EB%A5%BC_%ED%86%B5%ED%95%A9.png"&gt;&lt;figcaption&gt;옵시디언을 이용하여 분산된 정보를 통합 &amp;lt;출처: ChatGPT 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;분산된 정보를 통합하고, 나만의 LLM 위키를 만들기 위한 도구를 고를 때 가장 중요하게 본 기준은 세 가지였습니다. &lt;strong&gt;빠른 속도&lt;/strong&gt;, &lt;strong&gt;안정적인 동기화&lt;/strong&gt;, 그리고 &lt;strong&gt;저의 워크플로우에 적합한 도구&lt;/strong&gt;였습니다. 그렇게 여러 리서치와 테스트를 거쳐 결국 앞선 세 가지를 모두 만족하는 도구로 옵시디언을 선택하게 되었습니다. 사실 많은 이들이 옵시디언을 사용한다고 해서 같은 도구를 선택하고 싶진 않았습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 이런저런 도구를 테스트하며 꽤 많은 시간을 허비하고 나서, 결국 다른 사람들과 같은 선택을 하게 되었습니다. 결론적으로 &lt;strong&gt;옵시디언&lt;/strong&gt;을 중심으로 LLM 위키를 구축하고, 백업 및 동기화는 &lt;strong&gt;깃허브 Private Repo&lt;/strong&gt;, 위키 정리 작업은 &lt;strong&gt;클로드 코드&lt;/strong&gt;가 처리하는 것으로 결정했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;LLM 위키 구축 환경 세팅&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 옵시디언 세팅과 핵심 플러그인&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;옵시디언을 설치하고 가장 먼저 한 작업은 &lt;strong&gt;볼트(Vault) 생성&lt;/strong&gt;과 &lt;strong&gt;테마 설정&lt;/strong&gt;이었습니다. 옵시디언에서 볼트란 노트가 저장되는 폴더를 의미합니다. 테마로는 미니멀(Minimal) 테마를 선택했는데요. 옵시디언 커뮤니티에서 가장 인기 있는 테마이기도 하고, 깔끔하면서도 플러그인을 통해 카드뷰, 갤러리뷰 같은 다양한 세팅이 가능한 테마입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/3__%EB%AF%B8%EB%8B%88%EB%A9%80_%ED%85%8C%EB%A7%88%EB%A5%BC_%EC%A0%81%EC%9A%A9%ED%95%9C_%ED%99%94%EB%A9%B4.png"&gt;&lt;figcaption&gt;미니멀 테마를 적용한 옵시디언 화면 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이후에 제가 옵시디언에 &lt;strong&gt;설치한 플러그인&lt;/strong&gt;은 다음 표와 같습니다. 기본적으로 기기 간 동기화를 위한 깃(Git) 플러그인을 설치했고, 옵시디언 내에서 바로 클로드 코드를 사용하기 위한 터미널(Terminal) 플러그인도 설치했습니다. 추가로 템플릿 관리와 노트의 시각적 표현을 향상시키는 플러그인들도 설치했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/4__%EC%98%B5%EC%8B%9C%EB%94%94%EC%96%B8%EC%97%90_%EC%84%A4%EC%B9%98%ED%95%9C_%ED%95%B5%EC%8B%AC_%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8.png"&gt;&lt;figcaption&gt;옵시디언에 설치한 핵심 플러그인 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;아울러, &lt;strong&gt;자료를 수집하는 경로&lt;/strong&gt;도 옵시디언으로 일원화했습니다. &lt;strong&gt;데스크톱 PC&lt;/strong&gt;에서 웹 서핑하다 발견한 정보는 크롬 확장 프로그램인 ‘옵시디언 웹 클리퍼’를 통해 클릭 한 번으로 위키 볼트에 저장되도록 했습니다. 또한 &lt;strong&gt;모바일 기기&lt;/strong&gt;에서도 웹 서핑이나 유튜브, 스레드, 카카오톡, 페이스북 등을 보다가 유익한 콘텐츠를 발견하면 ‘공유’ 기능을 통해 바로 옵시디언으로 전송되도록 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/5__%EC%9E%90%EB%A3%8C_%EC%88%98%EC%A7%91%EC%9D%84_%EC%98%B5%EC%8B%9C%EB%94%94%EC%96%B8_%EB%B3%BC%ED%8A%B8%EB%A1%9C_%EC%9D%BC%EC%9B%90%ED%99%94.png"&gt;&lt;figcaption&gt;자료 수집을 옵시디언 볼트로 일원화 &amp;lt;출처: ChatGPT 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;만약 콘텐츠에 &lt;strong&gt;공유 버튼이 지원되지 않는 경우&lt;/strong&gt;에는 화면을 캡쳐하거나, 파일을 다운로드하여 옵시디언 볼트 내 임시 폴더에 저장했습니다. 그리고 파일명에 자료를 저장한 의도를 간단히 남기고, 추후 클로드 코드가 일괄적으로 자료를 정리하도록 구성했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 깃허브 연동(Private Repo)&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;앞서 살펴본 것처럼 여러 기기에서 자료를 수집하고, 노트를 사용하기 때문에 옵시디언 &lt;strong&gt;볼트의 동기화&lt;/strong&gt;가 필요합니다. 이를 위해 깃허브 Private Repo를 이용하면 레파지토리를 클라우드 백업 공간으로 활용하면서도 여러 기기에서 볼트를 동기화할 수 있습니다. 단, LLM 위키가 나의 거의 모든 데이터를 담고 있으므로 2단계 인증 등 &lt;strong&gt;보안을 엄격하게 관리해야&lt;/strong&gt; 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/6__%EA%B9%83%ED%97%88%EB%B8%8C_Private_Repo%EB%A5%BC_%ED%86%B5%ED%95%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EA%B5%AC%EC%A1%B0.png"&gt;&lt;figcaption&gt;깃허브 Private Repo를 통한 동기화 구조 &amp;lt;출처: ChatGPT 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;아이폰&lt;/strong&gt;같은 모바일 환경에서는 직접적으로 Git 저장소를 사용할 수 없기 때문에 옵시디언 싱크나 Working Copy라는 앱을 이용해야 합니다. 여기서 저는 &lt;strong&gt;Working Copy&lt;/strong&gt;를 사용하기로 했습니다. Working Copy는 클론(Clone) 기능은 무료이고 푸시(Push) 기능만 일회성 결제(약 $20)를 하면 되는데, 이는 옵시디언 싱크 구독을 1년 결제하는 것보다 장기적 비용 측면에서 저렴하다고 판단했습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Working Copy 앱을 이용하려면 깃허브 개인 액세스 토큰(Personal Access Token)을 Fine-grained 권한으로 발급해 등록해야 합니다. 그러면 Working Copy로 클론한 폴더를 옵시디언 모바일에서 볼트로 열어 사용할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/7__Working_Copy_%EC%86%8C%EA%B0%9C.png"&gt;&lt;figcaption&gt;Working Copy 소개 &amp;lt;출처: https://workingcopy.app/&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) 클로드 코드 CLI와 옵시디언 스킬 활용&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;옵시디언 볼트 안에서 클로드 코드, 코덱스 같은 AI 툴을 실행하면 위키의 작성과 수정, 삭제 등을 자동화할 수 있습니다. 이게 바로 LLM 위키의 핵심입니다. 즉, 사람이 직접 손으로 관리하던 이전의 위키와 달리 LLM 위키는 &lt;strong&gt;AI가 작성하고 관리하는 위키&lt;/strong&gt;인 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/8__%EC%98%B5%EC%8B%9C%EB%94%94%EC%96%B8__%ED%81%B4%EB%A1%9C%EB%93%9C_%EC%BD%94%EB%93%9C_CLI.png"&gt;&lt;figcaption&gt;옵시디언 + 클로드 코드 CLI &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;저는 기존부터 사용하던 웨이브 터미널(&lt;a href="https://www.waveterm.dev/"&gt;&lt;u&gt;Wave Terminal&lt;/u&gt;&lt;/a&gt;)이라는&lt;strong&gt;CLI 툴로 클로드 코드&lt;/strong&gt;를 실행하여 LLM 위키를 구축했습니다. 클로드 코드로 여기저기 흩어져 있는 자료를 LLM 위키에 입력하고, 그렇게 구축된 위키를 바탕으로 질문하거나, 주기적으로 위키를 정리하는 일을 모두 이 CLI 환경 안에서 처리하고 있습니다. 참고로, CLI 사용이 익숙하지 않은 분들은 클로드 데스크톱 앱에 있는 &lt;strong&gt;클로드 코워크&lt;/strong&gt;(Claude Cowork)로도 동일한 작업을 할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/9__%ED%81%B4%EB%A1%9C%EB%93%9C_%EC%BD%94%EC%9B%8C%ED%81%AC%EB%A5%BC_%EC%9D%B4%EC%9A%A9%ED%95%9C_%EC%9C%84%ED%82%A4_%EA%B4%80%EB%A6%AC.png"&gt;&lt;figcaption&gt;클로드 코워크를 이용한 위키 관리 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;클로드 코드를 사용할 때의 핵심은 옵시디언 볼트의 루트 디렉터리에 CLAUDE.md라는 파일을 두고, 새 세션(대화창)을 열 때마다 &lt;strong&gt;시스템 컨텍스트로 자동 주입&lt;/strong&gt;되도록 만드는 것입니다. 이를 통해 CLAUDE.md가 사실상 위키 운영 매뉴얼로서 AI 작업의 일관성을 확보하는 역할을 하게 됩니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/10__%EC%84%B8%EC%85%98_%EC%8B%9C%EC%9E%91_%EC%8B%9C_Hook%EC%9D%84_%ED%86%B5%ED%95%B4_%EC%9C%84%ED%82%A4_%EC%9A%B4%EC%98%81_%EA%B7%9C%EC%B9%99%EA%B3%BC_index_%EC%A6%89%EC%8B%9C_%EC%B0%B8%EC%A1%B0.png"&gt;&lt;figcaption&gt;세션 시작 시 Hook을 통해 위키 운영 규칙과 index 즉시 참조 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만, 가끔 AI가 CLAUDE.md에 적힌 운영 규칙을 제대로 보지 않는 경우가 있습니다. 이런 경우에는 &lt;strong&gt;SessionStart Hook&lt;/strong&gt;을 걸어 세션 시작 시 강제로 운영 규칙을 주입하거나, 위키 index를 즉시 참조하도록 할 수 있습니다. 이를 통해 새로운 대화를 시작하는 경우에도 AI가 별도의 검색 없이 위키 운영 규칙과 나에 대한 질문에 즉답을 할 수 있게 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/11__%ED%81%B4%EB%A1%9C%EB%93%9C_%EC%BD%94%EB%93%9C%EC%9D%98_%EC%98%B5%EC%8B%9C%EB%94%94%EC%96%B8_%EC%8A%A4%ED%82%AC.png"&gt;&lt;figcaption&gt;클로드 코드의 옵시디언 스킬 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한 추가로 클로드 코드에 &lt;strong&gt;옵시디언 스킬&lt;/strong&gt;들을 설치했습니다. 옵시디언 볼트의 일괄 작업을 돕는 obsidian-cli와 콜아웃, 임베드, 프로퍼티 같은 옵시디언 특화 문법을 다루는 obsidian-markdown, 그리고 웹페이지에서 깔끔한 본문만 추출해주는 defuddle 같은 스킬들이 있습니다. 이러한 스킬들은 옵시디언 특화 문법이나 LLM 위키 운영에 최적화된 복잡한 작업이 필요할 때 유용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;LLM 위키 설계와 활용하기&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 카테고리 설계&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이제 LLM 위키 환경 세팅이 끝났으니 구조를 설계할 단계입니다. 처음부터 나에 대한 모든 컨텍스트를 한 번에 만들려고 하면 어렵습니다. 그래서 저는 다음과 같은 프롬프트를 작성하여, 클로드 코드에게 &lt;strong&gt;위키 구조를 설계하도록&lt;/strong&gt; 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;i&gt;내가 누구이고, 어떤 배경과 역사를 가졌으며, 어떤 사람들과 어떤 환경에 있는지, 어떤 생각과 철학을 가지고 있는지, 어떤 자산을 가지고 있는지, 어떤 것들을 메모했고, 어떤 지식과 정보를 가지고 있는지 등을 기록하고 연결할 수 있는 위키 구조가 필요하다. 안드레 카파시의 아이디어를 기반으로 나에 대한 핵심 정보들을 담을 수 있는 LLM 위키 구조를 설계해줘.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이후 클로드가 제안해 준 카테고리를 기반으로 &lt;strong&gt;저에게 맞는 위키 구조&lt;/strong&gt;를 만들어 갔습니다. 현재는 나의 정체성(Identity), 생각(Thoughts), 목표(Goals), 역사(History), 사람(People), 자산(Assets), 일(Works)로 카테고리를 분류하여 사용하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 자료 인입(Ingest)&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;저는 안드레 카파시의 LLM 위키 개념을 클로드 코드에 넘겨, ingest, query, lint 스킬을 만들도록 했습니다. 그중에서 &lt;strong&gt;/ingest&lt;/strong&gt;는 새로 수집된 자료를 읽고, 적절한 위키 페이지로 합성하거나 연결하는 작업을 진행합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/12__%EA%B5%AC%EA%B8%80%ED%82%B5_ingest_%EA%B3%BC%EC%A0%95.png"&gt;&lt;figcaption&gt;구글킵 ingest 과정 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;자료 인입을 위해 저는 먼저 기존에 가지고 있던 노션과 구글 킵 노트를 ingest 했습니다. 즉, 노션과 구글 킵에서 백업한 파일을 raw 폴더에 넣고 /ingest 스킬을 사용했습니다. 여기에 &lt;strong&gt;민감 정보를 분리하는 과정&lt;/strong&gt;을 추가했는데요. 예를 들어, 비밀번호, 카드번호, 주민등록번호 같은 정보가 위키에 무분별하게 삽입되는 것을 방지하고자 했습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/13_%EB%AF%BC%EA%B0%90_%EC%A0%95%EB%B3%B4_%EA%B0%90%EC%A7%80_%EB%B0%8F_%EB%A7%88%EC%8A%A4%ED%82%B9_%EC%B2%98%EB%A6%AC.png"&gt;&lt;figcaption&gt;민감 정보 감지 및 마스킹 처리 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이를 위해 클로드 코드가 민감 정보 패턴을 &lt;strong&gt;정규식&lt;/strong&gt;(Regex)으로 감지해 위키에 삽입 시 &lt;strong&gt;마스킹&lt;/strong&gt;(Masking) 처리를 하도록 했습니다. 다만, 이러한 정규식 감지는 완벽하지 않기 때문에(ex. 주민번호에 공백이 들어간 경우 등) 1차적인 안전장치로만 사용하고, 다음에 살펴볼 Lint 작업으로 재점검하거나, 본인이 직접 검토해야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) 위키 점검 및 정리(Lint)&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;/lint&lt;/strong&gt;는 위키의 상태를 점검하는 작업입니다. 민감한 데이터나 모순된 정보, 어떤 노트에서도 연결되지 않은 고아(Orphan) 페이지, 다른 노트에서 언급만 되고 실제 파일이 없는 페이지 등을 잡아줍니다. 저는 &lt;strong&gt;클로드의 스케쥴 기능&lt;/strong&gt;을 활용해매일 자동으로 린트가 돌도록 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/14__%ED%81%B4%EB%A1%9C%EB%93%9C%EB%A5%BC_%EC%9D%B4%EC%9A%A9%ED%95%9C_Lint_%EC%9E%90%EB%8F%99%ED%99%94.png"&gt;&lt;figcaption&gt;클로드를 이용한 Lint 자동화 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;클로드의 스케쥴 기능을 사용하면, 따로 신경 쓰지 않아도 매일 위키의 깨진 링크나 정합성 문제를 &lt;strong&gt;자동으로 정리&lt;/strong&gt;할 수 있습니다. 비록 클로드가 중간에 Lint의 방향을 물어보는 경우가 있기도 하지만, 클로드의 스케쥴 기능으로 Lint 작업을 자동화하면 LLM 위키의 관리에 들어가는 비용을 줄일 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;4) LLM 위키의 활용&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;/query&lt;/strong&gt; 스킬은 위키 전체를 컨텍스트로 깔고 AI에게 질문하는 워크플로우입니다. 이를 통해 AI에게 질문을 던졌을 때 받는 '일반론적 답변'과는 &lt;strong&gt;결이 다른 답변&lt;/strong&gt;을 받을 수 있습니다. 이는 AI가 제 생각과 철학, 주어진 상황과 배경, 현재 운영 중인 비즈니스 환경, 진행 중인 프로젝트 목록과 우선순위까지 모두 알고 있기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/15__%EC%98%B5%EC%8B%9C%EB%94%94%EC%96%B8%EC%9D%98_%EA%B7%B8%EB%9E%98%ED%94%84_%EB%B7%B0_%EA%B8%B0%EB%8A%A5.png"&gt;&lt;figcaption&gt;옵시디언의 그래프 뷰 기능 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한 LLM 위키에 옵시디언을 활용하면 &lt;strong&gt;그래프 뷰&lt;/strong&gt;(Graph View) 기능을 사용할 수 있습니다. 그래프 뷰는 노트 간의 링크를 시각적으로 보여주는 기능인데요. 어떤 주제가 어떤 내용들과 연결되는지를 확인해 볼 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실제 사용 후기와 한계는?&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 컨텍스트를 이해한 AI의 답변&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;요즘 저는 비즈니스를 위한 법인 설립과 다양한 프로젝트를 동시에 진행하고 있습니다. 그 과정에서 결정해야 할 일이 정말 많았는데요. "지금 법인을 설립하는 게 맞을까", "동시 진행 중인 프로젝트가 너무 많은데 어디서 힘을 빼야 할까", "이 사업 라인을 잠시 보류하는 게 맞을까"처럼 답이 하나로 떨어지지 않는 질문들이 있었습니다. 그리고 LLM 위키를 활용하여 저의 철학, 직전 1년 회고, 현재 진행 중인 프로젝트의 부담, 자녀 양육 사이클까지 고려한 &lt;strong&gt;맞춤형 답변&lt;/strong&gt;을 받을 수 있었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이처럼 LLM 위키를 구축하고, AI에게 나의 컨텍스트 전부 전달함으로써 AI의 답변 품질이 '일반론적인 답변'에서 '&lt;strong&gt;나의 상황에 최적화된 답변&lt;/strong&gt;'으로 바뀐 것을 체감할 수 있었습니다. 아울러 &lt;a href="https://yozm.wishket.com/magazine/detail/3692/"&gt;&lt;u&gt;이전 글&lt;/u&gt;&lt;/a&gt;에서 만들었던 AI 비서 정대리도 LLM 위키를 활용하여 저의 의사결정 도우미로서 한 단계 진화시킬 수 있었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) LLM 위키의 한계점과 고려 사항&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;다만, 기대만큼 매끄럽지 않았던 부분도 있었습니다. 저의 경우에는 AI가 이미지에서 텍스트를 읽어 위키에 ingest할 때 부정확했던 사례가 많았습니다. 개인적으로 직접 손으로 쓰거나 다이어그램을 그린 메모지 사진과 노트 캡처 같은 이미지 기반 자료를 많이 가지고 있었는데요. 이런 자료를 Ingest 한 후 직접 위키를 검토해 봤을 때 &lt;strong&gt;사실관계가 어긋난 부분&lt;/strong&gt;이 상당히 많았습니다. 결국 제가 직접 관련된 항목을 하나하나 확인하며 다시 손으로 고쳐야 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;아울러 위키가 점점 커질수록 그 안에 담기는 &lt;strong&gt;민감 정보도 더 많아진다&lt;/strong&gt;는 문제가 있었습니다. 비록 마스킹 처리를 위한 목적이라도 비밀번호, 카드번호 같은 개인 정보를 AI에게 전부 넘겨야 하고, 민감 정보의 마스킹 처리가 제대로 됐는지도 일일이 확인하기 전까지 확신하기가 어려웠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한 동기화를 위해 깃허브의 비공개 Repository를 사용하지만, 그렇다고 모든 보안 위험이 사라지는 것도 아니었습니다. 만약 &lt;strong&gt;깃허브 계정이 해킹되면&lt;/strong&gt; 나의 모든 정보가 한꺼번에 털리는 문제가 생길 수도 있습니다. 따라서 기본적인 2단계 인증, 토큰(Token) 회전 같은 보호 장치를 반드시 설정해 두어야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;마지막으로 협업 시나리오에서도 또 다른 한계가 있었습니다. 나만의 LLM 위키에는 개인 정보가 많이 담겨 있기 때문에 팀과 공유하기가 어려웠습니다. 결국 팀과 공유할 컨텍스트는 &lt;strong&gt;팀 LLM 위키&lt;/strong&gt;를 다시 만들어야 하는 &lt;strong&gt;이중 작업&lt;/strong&gt;이 생기게 됩니다. LLM 위키에서는 단일 출처(Single source of truth, SSOT)를 원칙으로 표방하지만, 일부 정보는 결국 두 곳에 두게 되는 모순이 발생할 수밖에 없었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3792/16__LLM_%EC%9C%84%ED%82%A4_%EC%82%AC%EC%9A%A9_%ED%9B%84%EA%B8%B0%EC%99%80_%ED%95%9C%EA%B3%84.png"&gt;&lt;figcaption&gt;LLM 위키 사용 후기와 한계 &amp;lt;출처: ChatGPT 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이상으로 안드레 카파시의 아이디어를 적용하여 나만의 세컨드 브레인인 LLM 위키를 만든 과정과 후기를 정리해 봤습니다. 처음에는 단순히 AI에게 매번 나의 컨텍스트를 설명하는 것이 답답해서 시작한 작업이었지만, 만들고 보니 &lt;strong&gt;컨텍스트 정리의 자동화&lt;/strong&gt;와 &lt;strong&gt;AI 답변 품질의 향상&lt;/strong&gt;이라는 효과를 체감할 수 있었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;프로덕트 메이커의 입장에서 볼 때, LLM 위키의 구축은 단순한 일회성 프로젝트라기보다 장기적 관점에서 자신의 컨텍스트를 자산처럼 쌓아가는 과정이라고 생각합니다. 그리고 그렇게 쌓여진 나만의 컨텍스트를 통해서 &lt;strong&gt;AI 도구 활용의 생산성&lt;/strong&gt;을 극대화할 수 있을 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 이번에 제가 수행한 LLM 위키 구축 방식이 모두에게 정답은 아닐 것입니다. 특히 옵시디언이라는 도구는 손에 익기 전까지 학습 비용이 있고, 기기 간 동기화 방식도 다양하게 있기 때문입니다. 아울러 업무에 필요한 컨텍스트 정리의 수준도 개인마다 다르기 때문에 세컨드 브레인 구축에 있어 어떤 특정한 &lt;strong&gt;정답은 없다고 생각&lt;/strong&gt;합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;마지막으로 한 가지 강조하고 싶은 점은 세컨드 브레인 구축 시 처음부터 완벽한 구조를 만들겠다는 욕심을 내려놔야 한다는 것입니다. 위키의 카테고리나 자동화 워크플로우, 동기화 셋업을 한꺼번에 완벽하게 만들겠다고 하다 보면 중간에 포기하게 될 수도 있기 때문이죠. 따라서 &lt;strong&gt;점진적으로 개선&lt;/strong&gt;해 나간다는 느낌으로, 나만의 세컨드 브레인 구축을 시도해 보시길 바랍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>'토큰 맥싱'의 시대는 끝났다: 메타·아마존·우버의 선택</title><link>https://yozm.wishket.com/magazine/detail/3790</link><description>AI를 잘 쓴다는 걸 토큰 사용량으로 증명하던 시대가 있었습니다. 한도 창을 캡처해 자랑하고 사내 리더보드로 줄을 세우던 분위기가, 메타·아마존·우버에서 약속이라도 한 듯 사용량을 제한하기 시작하며 빠르게 무너졌습니다. 사용량은 폭발했는데 성과는 그 속도를 증명하지 못했고, 토큰 사용량을 내 성과로 끌어안는 건 공급자의 매출 지표를 내 것이라 착각하는 일과 다르지 않았죠. 토큰맥싱이 끝난 자리에서 무엇을 봐야 할지 정리했습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3790</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;지금 IT 업계에서 내 경쟁력은 무엇으로 증명하면 좋을까요? 답은 쉽습니다. "AI를 잘 쓴다"겠죠. 그럼 AI를 잘 쓴다는 건 또 무엇으로 증명할까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;2025년 들어 클로드 코드 같은 코딩 에이전트가 퍼지면서, 여기저기서 유행하기 시작한 것이 있습니다. 누가 토큰을 더 많이 태웠는지 줄 세우는 '토큰 사용량 리더보드'입니다. 곧 이 기업 저 기업에서 사내 리더보드 캡처본을 자랑삼아 올리기 시작했습니다. "오늘 사용 한도 다 채웠다"며 한도 창을 찍어 올리는 게시글도 흔했고요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 이 분위기는 최근 빠르게 무너졌습니다. 메타는 직원이 만들어 운영하던 토큰 순위표를 닫았고, 아마존도 비슷한 사내 순위표를 접으며 "AI를 그냥 쓰려고 쓰지는 말라"고 직원들에게 당부했습니다. 우버는 직원 1인당 AI 도구 비용에 한도를 걸었습니다. 언제는 맘껏 쓰라던 회사들이 약속이라도 한 듯 사용량을 제한하기 시작한 것입니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이제 토큰 사용량을 실력의 잣대로 삼던 문화는 끝났습니다. '토큰 맥싱' 시대의 종말이죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3790/image1.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Gemini로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;토큰을 많이 쓰면 AI를 잘 쓰는 걸까?&amp;nbsp;&lt;/strong&gt;&lt;/h3&gt;&lt;h4&gt;&lt;strong&gt;토큰 맥싱이란?&amp;nbsp;&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;‘토큰 맥싱(tokenmaxxing)’이란 단어부터 짚어 봅시다. 외모를 극한까지 가꾸는 행위를 ‘룩스맥싱’이라 부르는 데서 온 말로, ‘-맥싱’은 무언가를 끝까지 밀어붙인다는 의미입니다. 그러니 토큰 맥싱은 AI에게 일을 잔뜩 시켜 토큰을 최대한 많이 쓰는 행위를 가리킵니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이러한 토큰 맥싱이 추구하는 건 결과물이 아니라 사용량 그 자체입니다. 토큰을 많이 썼다는 사실이 곧 'AI를 잘 쓴다'는 증거로 통했고, 그게 토큰맥싱의 출발점이었죠.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4&gt;&lt;strong&gt;토큰 리더보드는 어떻게 퍼졌나&amp;nbsp;&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이 발상이 회사 제도로까지 번진 건 2025년 7월 즈음입니다. 당시 AI-first를 회사 기조로 삼아 이목을 끌었던 쇼피파이에서 ‘리더보드’를 운영한다고 말했습니다. 당연히 나쁜 의도는 아니었습니다. AI로 좋은 성과를 낸 사람을 알아봐 주자는 취지였고, 실제로 꽤 효과를 봤다고 했습니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#999999;"&gt;*참고:&lt;/span&gt; &lt;a href="https://www.youtube.com/watch?v=u-3IILWQPRM"&gt;&lt;span style="color:#999999;"&gt;&lt;u&gt;Farhan Thawar와 함께 Shopify의 소프트웨어 엔지니어링을 변화시키는 AI&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#999999;"&gt;(The Pragmatic Engineer)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;문제는 이 형식이 빠르게 번지면서 변질됐다는 점입니다. 직원을 점수로 줄 세우는 비슷한 리더보드가 여러 회사에 생겼습니다. 메타에는 직원이 직접 만든 토큰 순위표가 있었는데, 사용량 상위 이용자에게 '토큰 레전드(Token Legend)'·'캐시의 마법사(Cache Wizard)' 같은 칭호까지 붙였습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3790/image2.png"&gt;&lt;figcaption&gt;더 인포메이션 메타 담당 기자의 ‘토큰맥싱 리더보드’ 글 &amp;lt;출처:&lt;a href="https://www.linkedin.com/in/jyoti-mann-873a4317b/recent-activity/all/"&gt;&lt;u&gt;Jyoti Mann 링크드인&lt;/u&gt;&lt;/a&gt;&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;마이크로소프트, 디즈니 등도 사내 ‘AI 도입 대시보드’에 사용량과 토큰 수를 띄웠고, 개발자 커뮤니티에도 토큰을 얼마나 썼는지 집계해주는 도구가 등장했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3790/image4.png"&gt;&lt;figcaption&gt;사용자의 토큰 사용량을 추적하는 리더보드 &amp;lt;출처:&lt;a href="https://tokscale.ai/leaderboard"&gt;&lt;u&gt;Tokscale&lt;/u&gt;&lt;/a&gt;&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;왜 토큰 리더보드는 무너졌나&amp;nbsp;&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;애초에 토큰이 AI 활용도를 평가하는 지표 자리에 오른 이유는 단순합니다. 측정하기 쉬웠거든요. AI를 잘 도입했는지 따지는 건 원래 어렵고 눈에 잘 안 보이는데, 토큰은 숫자로 딱 떨어져 대시보드에 바로 뜹니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 그 시작이 쉬웠던 만큼 이런 믿음이 흔들리는 것도 금방이었습니다. 왜 그랬을까요?&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4&gt;&lt;strong&gt;토큰 ≠산출물의 양&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;단순합니다. 토큰을 몇 배 더 태워도 산출물이 그만큼 늘지는 않았던 겁니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이걸 가장 비싼 값을 치르며 확인한 곳이 우버입니다. 우버는 2026년 한 해 쓸 AI 코딩 도구 예산을 첫 4달 만에 전부 소진했습니다. 일부 엔지니어는 토큰 값으로 월 2,000달러까지 썼다고 합니다. 문제는 그렇게 쏟아붓고도 값을 했는지 아무도 자신 있게 답하지 못했다는 점입니다. 우버 COO도 AI 사용은 늘었지만 그 돈이 실제 성과로 이어졌다고 딱 잘라 말하긴 어렵다고 했죠. 사용량은 폭발했는데 성과는 그 속도를 증명하지 못한 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;span style="color:#999999;"&gt;*참고:&lt;/span&gt; &lt;a href="https://techcrunch.com/2026/06/02/uber-caps-employee-ai-spending-after-blowing-through-budget-in-four-months/"&gt;&lt;span style="color:#999999;"&gt;&lt;u&gt;Uber caps employee AI spending after blowing through budget in 4 months&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#999999;"&gt;(Techcrunch)&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실제로 토큰을 많이 써서 코드를 쏟아내면 배포 건수는 늘지만, 그게 버그 없이 살아남는지는 별개의 이야기입니다. 그래서 우버는 직원 한 명당 도구별로 월 1,500달러 한도를 도입했습니다. 클로드 코드와 커서 같은 도구마다 따로 한도를 두고, 내부 대시보드로 사용량을 추적해 예외 승인이 있을 때만 초과를 허용하는 방식이죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4&gt;&lt;strong&gt;토큰 ≠ 정직도&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;아마존에서도 직원들이 사내 도구로 굳이 안 해도 될 작업을 AI에게 떠넘기며 토큰 소비를 늘렸다는 보도가 나왔습니다. 한 직원은 “매니저들이 지켜보고 있고, 사용량 추적이 비뚤어진 동기를 만든다”고 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;span style="color:#999999;"&gt;*참고:&lt;/span&gt; &lt;a href="https://arstechnica.com/ai/2026/05/amazon-employees-are-tokenmaxxing-due-to-pressure-to-use-ai-tools/"&gt;&lt;span style="color:#999999;"&gt;&lt;u&gt;Amazon employees are “tokenmaxxing” due to pressure to use AI tools&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="color:#999999;"&gt;(ArsTechnica)&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;경제학자 찰스 굿하트의 말이 떠오릅니다. 측정하는 잣대가 목표가 되는 순간, 그건 더 이상 좋은 잣대가 아니라는 거죠. 사람은 평가받는 항목에 맞춰 행동을 비틉니다. 토큰 사용량이 평가 기준이 되자, 토큰을 일부러 부풀리는 일이 실제로 벌어진 겁니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4&gt;&lt;strong&gt;토큰 = 공급자의 매출&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;게다가 좀 더 구조적인 문제도 있습니다. 주요 모델을 만든 회사들의 매출은 최근 폭발적으로 늘었고, 그 배경에는 슬금슬금 오른 토큰 비용이 있습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3790/Gemini_Generated_Image_gkl9tygkl9tygkl9.png"&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;표를 보면 최근 나온 신형 모델들이 한 세대 전보다 비싸졌습니다. GPT-5.5는 직전 세대의 두 배, 제미나이 3.5 Flash는 직전 플래시의 약 세 배로 올랐고, 클로드 Opus 4.7은 표시 가격은 그대로지만 새 토크나이저 탓에 같은 글이 토큰을 최대 35%까지 더 먹습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;물론 성능이 좋아졌으니 값이 오르는 게 당연하다고 볼 수도 있습니다. 하지만, 단가만 오른 게 아닙니다. 토큰을 가장 많이 쓰는 코딩 에이전트들이 새 기능을 토큰을 더 소비하는 방향으로 진화시켜 왔거든요. 단가도, 한 작업에 드는 토큰 양도 함께 늘어난 셈입니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3790/image5.png"&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;물론 공급자를 악당으로 몰 일은 아닙니다. 분명 모델이 토큰을 많이 쓴다는 것은 더 많은 일을 처리할 가능성을 높이며, 그 구조를 알아서 만들어 주는 기능은 일을 편하게 해줍니다. 게다가 모델을 한 번 돌릴 때마다 전력과 인프라 비용이 진짜로 들어가니, 가격이 오르는 데는 나름의 근거가 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 이걸 돈 내고 쓰는 사람들의 생각은 다를 겁니다. 돈을 쓰는 만큼 효과가 돌아와야 하는데, 그게 불분명한 구성이었으니까요. 이 구조에서 토큰 사용량을 내 성과라고 끌어안는 건, 남의 매출 지표를 내 성과라고 착각하는 일과 다르지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;토큰 대신 무엇을 봐야 하나&amp;nbsp;&lt;/strong&gt;&lt;/h3&gt;&lt;h4&gt;&lt;strong&gt;적게 쓰고 잘 쓰는 게 실력&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;앤트로픽이 &lt;a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents"&gt;&lt;u&gt;공식 엔지니어링 블로그&lt;/u&gt;&lt;/a&gt;에서 권하는 원칙은 이렇습니다. 원하는 결과가 나올 가능성을 최대로 높이되, 신호가 분명한 정보만 가능한 한 적게 넣으라는 거죠.&amp;nbsp; 토큰을 많이 욱여넣지 말고, 필요한 것만 정확히 골라 넣으라는 뜻이죠. 뜻입니다. 컨텍스트를 가득 채운다고 결과가 좋아지지 않습니다. 오히려 잡음이 끼면 정확도만 떨어지죠.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실제로 에이전트의 동작 환경을 제어하는 ‘하네스 엔지니어링’ 기술이 발전하며, 컨텍스트 주입과 성과 관리, 피드백에 대한 루프가 진화한 것도 '토큰을 많이 쓰면 좋다'는 믿음에 더 큰 의심을 키웠고요.&amp;nbsp; 한국에서도 ‘&lt;a href="https://www.khan.co.kr/article/202604290600081"&gt;&lt;u&gt;토성비&lt;/u&gt;&lt;/a&gt;’, 그러니까 토큰 가성비라는 말이 생겼을 정도입니다. 토큰을 얼마나 썼느냐가 아니라 그 돈으로 무엇을 얻었느냐를 따지기 시작했다는 뜻입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3790/image3.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Gemini로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4&gt;&lt;strong&gt;성과 측정은 새로운 숙제가 아니다&amp;nbsp;&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;결국 다시 봐야 할 건 '토큰을 얼마나 썼나'가 아니라 '내가 풀려는 문제가 뭐고, AI가 내놓은 결과가 그 문제를 풀었나'입니다. 적은 토큰으로 목표를 이루도록 설계하는 능력, 그게 실력이라는 거죠.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그럼 ‘문제를 풀었나’를 어떻게 검증하냐고요? 결과와 목적 달성을 측정하는 일은 조직이 늘 해오던 일입니다. 코드를 몇 줄 썼는지로 개발자를 평가하면 쓸데없이 긴 코드만 양산된다는 걸 모두가 알고 있습니다. 그러니 AI가 왔다고 성과 측정을 바닥부터 새로 발명할 건 없습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하던 대로 하면 됩니다. ‘이 사람은(또는 나는) 고객이나 조직의 어떤 문제를 풀었고, 그래서 제품과 회사에 얼마나 보탬이 됐는가?’ 이걸 평가하면 충분합니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;마치며: 많이 쓰던 시대에서, 무엇을 풀었는지 묻는 시대로&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;토큰 맥싱의 시대가 그저 헛수고였던 것만은 아니라고 생각합니다. AI를 얼마나 쓰는지 줄 세우는 것만으로도, "AI는 무섭고 쓸모없다"던 사람들을 "안 쓰면 도태된다"는 쪽으로 밀어붙이는 역할은 했으니까요. 아직 아무도 AI를 안 쓰려는 회사라면, 이 리더보드가 여전히 제 역할을 할지도 모릅니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그러나 토큰맥싱은 끝났습니다. 더 정확히는, 토큰을 지표로 삼던 시대가 끝났습니다. 토큰은 앞으로도 계속, 어쩌면 더 많이 쓰일 테지만, 이제 그게 자랑거리는 아닙니다. 그러니 혹시 "아, 오늘도 사용 한도 다 채웠으니 열일했다"고 만족하던 분들은, 한 번 더 스스로 물어보면 어떨까요? 그 한도로 무엇을 바꿨는지를요.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;&lt;span style="color:#999999;"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>나만의 유틸리티 타입 만들기: Mapped Type, Conditional Type</title><link>https://yozm.wishket.com/magazine/detail/3789</link><description>타입스크립트는 자바스크립트에 정적 타입 시스템을 더한 언어로, 코드의 안정성과 가독성을 높여주는 다양한 기능을 제공합니다. 그 중에서도 ‘Partial’, ‘Required’, ‘Readonly’, ‘Pick’, ‘Omit’ 같은 내장 유틸리티 타입은 일상적인 개발에서 자주 활용되는 도구입니다. 그런데 프로젝트가 복잡해지면 한 가지 의문이 생깁니다. 내장 유틸리티 타입만으로 모든 상황을 해결할 수 있을까요? 실제로 그렇지 않은 경우가 많습니다. 이러한 상황에서 진가를 발휘하는 도구가 바로 “Mapped Type”과 “Conditional Type”입니다. 이 두 가지는 내장 유틸리티 타입을 구성하는 핵심 재료이기도 합니다. 이번 글에서는 두 도구의 동작 원리를 살펴보고, 이를 토대로 나만의 유틸리티 타입을 만드는 방법까지 함께 알아보겠습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3789</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;타입스크립트는 자바스크립트에 정적 타입 시스템을 더한 언어로, 코드의 안정성과 가독성을 높여주는 다양한 기능을 제공합니다. 그 중에서도 ‘Partial’, ‘Required’, ‘Readonly’, ‘Pick’, ‘Omit’ 같은 내장 유틸리티 타입은 일상적인 개발에서 자주 활용되는 도구입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 프로젝트가 복잡해지면 한 가지 의문이 생깁니다. 내장 유틸리티 타입만으로 모든 상황을 해결할 수 있을까요? 실제로 그렇지 않은 경우가 많습니다. API 응답에서 값의 타입이 ‘string’인 프로퍼티만 골라야 하거나, 일부 필드는 그대로 두고 나머지나 옵셔널로 만들고 싶은 상황이 자주 발생합니다. 이런 순간에 직접 유틸리티 타입을 만들 줄 모르면, 같은 타입을 여러 번 반복해 정의하거나 ‘any’로 우회하게 되고, 결과적으로 타입 안정성이 무너지는 코드가 쌓이기 쉽습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이러한 상황에서 진가를 발휘하는 도구가 바로 “Mapped Type”과 “Conditional Type”입니다. 이 두 가지는 내장 유틸리티 타입을 구성하는 핵심 재료이기도 합니다. 이번 글에서는 두 도구의 동작 원리를 살펴보고, 이를 토대로 나만의 유틸리티 타입을 만드는 방법까지 함께 알아보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;미리 요점만 콕 집어보면?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;‘Mapped Type’과 ‘Conditional Type’은 ‘Partial’, ‘Readonly’, ‘Exclude’, ‘ReturnType’ 같은 내장 유틸리티 타입의 핵심 원리입니다.&lt;/li&gt;&lt;li&gt;‘keyof’, ‘as’, ‘infer’, 분배적 조건부 타입을 활용하면 특정 타입만 추출하거나 일부 필드만 옵셔널로 바꾸는 커스텀 타입을 만들 수 있습니다.&lt;/li&gt;&lt;li&gt;복잡한 타입 추상화는 IDE 성능과 가독성에 영향을 줄 수 있으므로, 실무에서는 재사용성과 유지보수성을 함께 고려해야 합니다.&lt;/li&gt;&lt;/ul&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;먼저 알아야 할 도구들 - Readonly, Exclude, Extract&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;Mapped Type과 Conditional Type을 이해하려면 먼저 내장 유틸리티 타입 몇 가지를 살펴볼 필요가 있습니다. 이들은 모두 위 두 가지 도구로 만들어졌기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) Readonly&amp;lt;T&amp;gt;란?&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Readonly&amp;lt;T&amp;gt;는 객체 타입 T의 모든 프로퍼티를 읽기 전용으로 만들어주는 유틸리티 타입입니다. 즉, 한 번 할당된 값을 변경할 수 없도록 잠그는 역할을 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface User {
  id: number;
  name: string;
}

const user: Readonly&amp;lt;User&amp;gt; = {
  id: 1,
  name: "kim",
};

user.name = "park";
// 오류: 읽기 전용 프로퍼티이므로 'name'에 할당할 수 없습니다.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;이 덕분에 불변성을 보장해야 하는 상태 객체나 설정값을 다룰 때 유용하게 활용할 수 있습니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) Exclude&amp;lt;T, U&amp;gt;와 Extract&amp;lt;T, U&amp;gt;란?&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Exclude&amp;lt;T, U&amp;gt;는 유니온 타입 T에서 U에 해당하는 멤버를 제거합니다. 반대로 Extract&amp;lt;T, U&amp;gt;는 T에서 U와 겹치는 멤버만 남깁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type Status = "loading" | "success" | "error";

type NonError = Exclude&amp;lt;Status, "error"&amp;gt;;
// 결과: "loading" | "success"

type OnlyError = Extract&amp;lt;Status, "error" | "fatal"&amp;gt;;
// 결과: "error"
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 두 타입은 이름에서 알 수 있듯이 서로 대칭되는 동작을 합니다. 어떻게 이런 분기가 가능한지는 뒤에서 살펴볼 Conditional Type을 보면 자연스럽게 이해할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;Mapped Type - 타입을 순회하며 변환하기&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;내장 유틸리티 타입의 상당수는 결국 한 가지 동작을 다른 형태로 풀어낸 것입니다. 바로 “기존 타입의 프로퍼티를 하나씩 훑으면서 일정한 규칙으로 새로운 프로퍼티를 만들어내는” 작업입니다. 이 동작을 직접 표현할 수 있는 문법이 바로 Mapped Type입니다. 이 절에서는 기본 문법부터 시작해, ‘Partial’이나 ‘Readonly’를 직접 구현해보고, 타입스크립트 4.1 이후 추가된 키 재매핑까지 단계적으로 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) Mapped Type의 기본 문법&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Mapped Type은 한 객체 타입의 프로퍼티를 순회하면서 새로운 객체 타입을 만들어내는 문법입니다. 자바스크립트에서 ‘for…in’으로 객체를 순회하는 것과 비슷한 개념이라고 이해하면 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;기본 형태는 다음과 같습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type MyMapped&amp;lt;T&amp;gt; = {
  [K in keyof T]: T[K];
};
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;‘keyof T’는 T의 모든 프로퍼티 키를 유니온으로 묶은 결과이고, [K in keyof T]는 그 키를 하나씩 꺼내 새로운 객체 타입을 구성하라는 의미입니다. 이를 통해 기존 타입의 구조는 유지하면서 각 프로퍼티에 변형을 가할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3789/%EA%B7%B8%EB%A6%BC1.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude ai로 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) Partial과 Readonly 직접 만들어보기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이제 Mapped Type을 사용해 내장 유틸리티 타입인 ‘Partial’과 ‘Readonly’를 직접 구현해 볼 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type MyPartial&amp;lt;T&amp;gt; = {
  [K in keyof T]?: T[K];
};

type MyReadonly&amp;lt;T&amp;gt; = {
  readonly [K in keyof T]: T[K];
};
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;‘?’는 프로퍼티를 옵셔널로 만들고, ‘readonly’는 읽기 전용으로 만듭니다. 단 두 줄로 강력한 유틸리티 타입을 만들 수 있다는 점에서 Mapped Type의 표현력을 확인할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) 키 재매핑과 수식어 제거&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;타입스크립트 4.1 버전부터는 ‘as’ 키워드를 사용해 키 자체를 재매핑할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type Getters&amp;lt;T&amp;gt; = {
  [K in keyof T as `get${Capitalize&amp;lt;string &amp;amp; K&amp;gt;}`]: () =&amp;gt; T[K];
};

interface Person {
  name: string;
  age: number;
}

type PersonGetters = Getters&amp;lt;Person&amp;gt;;
// 결과: { getName: () =&amp;gt; string; getAge: () =&amp;gt; number; }
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한 ‘-?’나 ‘-readonly’처럼 빼기 기호를 붙이면 옵셔널 표시나 읽기 전용 수식어를 제거할 수도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type Concrete&amp;lt;T&amp;gt; = {
  -readonly [K in keyof T]-?: T[K];
};
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이는 ‘Readonly’나 ‘Partial’을 되돌리고 싶을 때 활용할 수 있는 패턴입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;Conditional Type - 조건에 따라 타입 분기하기&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;Mapped Type이 타입의 “구조”를 순회하며 변환하는 도구라면, Conditional Type은 타입의 종류나 타입이 무엇이냐에 따라 결과를 다르게 결정하는 도구입니다. 입력 타입이 무엇이냐에 따라 분기되는 동적인 타입을 만들 수 있어, ‘Exclude’나 ‘ReturnType’ 같은 내장 유틸리티 타입의 토대가 됩니다. 여기서는 기본 문법을 먼저 살펴본 뒤, 유니온과 만났을 때 일어나는 분배 동작과 ‘infer’ 키워드까지 차례대로 알아보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) Conditional Type의 기본 문법&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Conditional Type은 자바스크립트의 삼항 연산자처럼 조건에 따라 타입을 결정하는 문법입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type IsString&amp;lt;T&amp;gt; = T extends string ? true : false;

type A = IsString&amp;lt;"hello"&amp;gt;;
// 결과: true
type B = IsString&amp;lt;42&amp;gt;;
// 결과: false
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;‘T extends U ? X : Y’ 형태로 작성하며, T가 U에 할당 가능한지 검사한 뒤 그 결과에 따라 다른 타입을 반환합니다. 이를 통해 입력 타입에 따라 동적으로 결과 타입을 만들어낼 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 분배적 조건부 타입&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Conditional Type이 유니온 타입과 만나면 흥미로운 일이 일어납니다. 검사 대상이 단일 타입 파라미터인 유니온일 경우, 타입스크립트는 유니온의 각 멤버에 조건을 분배해 적용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type ToArray&amp;lt;T&amp;gt; = T extends any ? T[] : never;

type Result = ToArray&amp;lt;string | number&amp;gt;;
// 결과: string[] | number[]
&lt;/code&gt;&lt;/pre&gt;&lt;p style="margin-left:36pt;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3789/%EA%B7%B8%EB%A6%BC2.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude ai로 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 동작을 활용하면 앞서 살펴본 ‘Exclude’와 ‘Extract’를 다음처럼 직접 만들 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type MyExclude&amp;lt;T, U&amp;gt; = T extends U ? never : T;
type MyExtract&amp;lt;T, U&amp;gt; = T extends U ? T : never;
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;T의 각 멤버에 대해 U에 속하는지를 검사하고, 결과에 따라 never로 제거하거나 그대로 남깁니다. 즉, Conditional Type 한 줄로 두 유틸리티 타입의 동작 원리가 설명됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) infer 키워드 - 타입 안에서 타입 추출하기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;‘infer’는 Conditional Type 안에서만 사용할 수 있는 키워드로, 검사 대상에서 특정 위치의 타입을 추론해 변수처럼 사용하도록 해줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type ReturnTypeOf&amp;lt;T&amp;gt; = T extends (...args: any[]) =&amp;gt; infer R ? R : never;

function getUser() {
  return { id: 1, name: "kim" };
}

type User = ReturnTypeOf&amp;lt;typeof getUser&amp;gt;;
// 결과: { id: number; name: string; }
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 예시에서는 함수의 반환 타입을 ‘R’이라는 이름으로 추출해 결과 타입으로 사용했습니다. 내장 유틸리티 타입인 ‘ReturnType’, ‘Parameters’, ‘Awaited’ 등이 이 원리로 만들어졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;나만의 유틸리티 타입 만들기&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이제 Mapped Type과 Conditional Type을 결합해 실제로 사용할 만한 커스텀 유틸리티 타입을 만들어보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 특정 타입의 프로퍼티만 골라내기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;객체 타입에서 값의 타입이 ‘string’인 프로퍼티만 골라야 하는 상황을 가정해 보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type PickByType&amp;lt;T, V&amp;gt; = {
  [K in keyof T as T[K] extends V ? K : never]: T[K];
};

interface UserProfile {
  id: number;
  name: string;
  email: string;
  isActive: boolean;
}

type StringFields = PickByType&amp;lt;UserProfile, string&amp;gt;;
// 결과: { name: string; email: string; }
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Mapped Type으로 키를 순회하면서, Conditional Type으로 값의 타입을 검사해 조건에 맞지 않는 키는 never로 변환합니다. never로 매핑된 키는 결과 객체에서 자동으로 제거됩니다. 이 점에서 Mapped Type과 Conditional Type이 한 곳에서 자연스럽게 협력하는 모습을 확인할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 일부 필드만 선택적으로 바꾸기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;특정 필드만 옵셔널로 만들고 나머지는 그대로 두는 유틸리티 타입도 만들 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type PartialBy&amp;lt;T, K extends keyof T&amp;gt; = Omit&amp;lt;T, K&amp;gt; &amp;amp; Partial&amp;lt;Pick&amp;lt;T, K&amp;gt;&amp;gt;;

interface Article {
  id: number;
  title: string;
  body: string;
  publishedAt: Date;
}

type DraftArticle = PartialBy&amp;lt;Article, "publishedAt"&amp;gt;;
// 결과: { id: number; title: string; body: string; publishedAt?: Date; }
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Omit으로 대상 키를 제거한 결과와 Pick 후 Partial을 적용해 옵셔널로 만든 결과를 교집합으로 합쳐 새로운 타입을 만들어냅니다. 폼 입력값이나 임시 저장 객체처럼 단계적으로 채워나가는 데이터를 다룰 때 활용하기 좋은 패턴입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실무 활용에서의 주의점&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;지금까지 살펴본 도구들은 표현력이 뛰어나지만, 실무에서 사용할 때 몇 가지 고려할 점이 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;먼저 커스텀 유틸리티 타입은 추상화 수준이 높기 때문에 코드 가독성을 해칠 수 있습니다. 따라서 팀 단위로 코드를 다룰 때는 자주 쓰이는 패턴 정도로만 만들고, 일회성으로 쓰일 만한 타입은 그때그때 인라인으로 작성하는 편이 좋습니다. 또한 Conditional Type을 깊게 중첩하면 타입 추론 비용이 늘어나 IDE 성능이 떨어질 수 있습니다. 큰 프로젝트에서 특히 체감되는 부분이므로, 복잡한 타입은 적절히 분리하고 이름을 붙여 재사용하는 것을 권장합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;마지막으로 분배적 조건부 타입의 동작을 잊는 경우가 많습니다. 유니온 타입에 Conditional Type을 적용할 때 의도하지 않은 분배가 일어날 수 있으므로, 분배를 막고 싶다면 [T] extends [U] ? … : …처럼 튜플로 감싸는 패턴을 기억해 두면 좋습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 Mapped Type과 Conditional Type의 기본 문법부터 분배적 조건부 타입, infer 키워드, 그리고 이들을 결합해 만드는 커스텀 유틸리티 타입까지 살펴보았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;핵심을 정리하면 다음과 같습니다.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Mapped Type은 타입을 순회하면서 새로운 타입을 만드는 도구이며, Partial이나 Readonly의 토대가 됩니다.&lt;/li&gt;&lt;li&gt;Conditional Type은 조건에 따라 타입을 분기하는 도구이며, Exclude, Extract, ReturnType의 토대가 됩니다.&lt;/li&gt;&lt;li&gt;두 도구를 함께 사용하면 내장 유틸리티 타입만으로는 표현하기 어려운 정교한 타입을 만들 수 있습니다.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 두 가지를 이해하면 내장 유틸리티 타입의 동작 원리가 투명하게 드러납니다. 더 이상 내장 도구를 외워서 쓰는 것이 아니라, 필요한 순간에 직접 조립해 쓸 수 있게 되는 셈입니다. 이를 통해 타입스크립트로 작성한 코드의 표현력과 안정성이 한 단계 올라간다는 것을 체감할 수 있습니다.&lt;/p&gt;&lt;hr&gt;&lt;p style="text-align:justify;"&gt;&amp;lt;출처&amp;gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://ts.winterlood.com/"&gt;&lt;u&gt;https://ts.winterlood.com/&lt;/u&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;&lt;span style="color:#999999;"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>AI 시대의 시지프스: 멈추지 못하는 완벽주의자를 위한 안내서</title><link>https://yozm.wishket.com/magazine/detail/3787</link><description>AI 에이전트는 작업물을 검토해 단점을 심각도별로 분류하고 대안까지 내놓는다. 완벽주의 기질이 있는 사람에게 이건 독이 든 성배다. 완벽한 코드란 없는데도 '한 번 더'를 멈추지 못한다. 그런 와중에 모델은 매일 좋아진다. 시지프스의 바위가 멈추지 않는 건 신의 벌이지만, 우리 바위가 멈추지 않는 건 멈추지 않기로 한 선택이다. 마감일을 정하고, 여러 세션을 번갈아 돌리고, 작업을 기록하고, 오늘의 최선에서 손을 떼기까지. 번아웃을 지나며 찾은 멈추는 법을 정리했다.</description><guid>https://yozm.wishket.com/magazine/detail/3787</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3787/image1.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, ChatGPT로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;저녁 6시, 퇴근 시간이다. 내일까지 제출해야 하는 작업물을 완성했지만, 불안한 마음에 한 번 더 살펴본다. 검토하다가 놓친 부분을 발견하고 말았다. 시간이 늦었는데, 지금 수정할 수 있는 범위일까? 제출 기한을 늘려 달라고 요청하는 게 좋을까? 무리해서라도 수정을 마치고 내일 제출을 하는 것과, 안전하게 기한을 늘리는 선택지 사이에서 깊은 고민에 빠진다. 그나마 수정 방향이 금방 생각나면 다행이지만, 좋은 방안이 떠오르지 않는 경우도 있다. 슬프지만 실력의 한계를 느끼며 퇴근하고, 그날의 일은 거기서 마무리된다. 이것은 AI 에이전트가 나타나기 전까지 나의 일상이었다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 최근에는 상황이 많이 달라졌다. AI 에이전트(나의 경우 클로드)는 나의 고민을 듣고 작업물을 검토한 후, 단점을 파악해 심각도에 따라 분류해주며 대안들을 제시해준다. 내가 수정 방향을 고르면, 몇 분 안에 변경이 완료된다. 완벽주의 기질이 심한 나 같은 사람에게 이것은 독이 든 성배다. 완벽한 코드란 존재하지 않는데도 끝없이 질문하고 검토하며 일을 손에서 놓지 못하는 상황에 놓이는 것이다. 나는 모든 문제를 고쳐야 한다는 강박감에 시달리다가 번아웃을 경험했고, 이를 극복하는 과정에서 AI를 대하는 슬기로운 태도에 대해 생각해 보게 되었다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 여러분에게도 질문하고 싶다. 우리는 어디서 멈춰야 할까?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3787/image3.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, ChatGPT로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;한 번 더, 한 번 더, 완벽을 향한 강박&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;나는 오래전부터 불면증이 있었는데, 최근 몇 달간 평소보다 더 늦게 잠자리에 들었다. 클로드랑 대화하다 보면 시간 감각도 무뎌졌다. 바이브 코딩이 재미있는 이유는 피드백이 빠르기 때문이다. 끊임없이 떠오르는 개선 사항을 클로드는 금방금방 반영해 주었다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;최근에 나는 일기를 자동으로 써주는 프로그램을 만들었는데, 그 프로그램은 도무지 완성되지 않았다. 처음에는 그저 캘린더의 일정을 나열하고, 클로드가 코멘트를 달아주는 정도를 원했다. 하지만 이내 한계가 드러났다. 캘린더에는 내가 실제로 한 일과 해야 한다고 적은 일이 뒤섞여있었기 때문에, 일기가 정확하지 않았던 것이다. 그때부터 일기의 정확도를 높일 방법을 고민했고, 텔레그램을 통한 사용자 인터랙션이 추가되었다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;메인 시스템 프롬프트&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;“&lt;/strong&gt;하루봇 메인 파이프라인&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;매일 오후 8시(KST) 실행되어:&lt;/p&gt;&lt;p style="text-align:justify;"&gt;1. Calendar / Notion / GitHub에서 오늘 활동 수집&lt;/p&gt;&lt;p style="text-align:justify;"&gt;2. Claude API로 [오늘의 일정] + [태스크] 두 섹션 생성&lt;/p&gt;&lt;p style="text-align:justify;"&gt;3. Notion 일기 페이지 생성(오늘의 일정은 본문으로, 태스크와 할 일은 체크박스 리스트로)&lt;/p&gt;&lt;p style="text-align:justify;"&gt;4. Telegram에 일정 요약 + 할 일 체크박스 리스트(미완료 항목 + 완료 버튼) 전송&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;5. 사용자가 완료 버튼을 누르면 하루 피드백 생성·저장&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;사용자 답장(코멘트/설정)은 실시간으로 Notion 일기에 반영한다.”&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;일기에는 나의 생각도 담기는 게 좋을 것 같아서 내 답장을 일기에 함께 저장하도록 했다. 또한 ‘설정’은 버그를 간단히 수정하고 싶을 때를 대비해 만든 기능이다. ‘/설정’이라고 시작하는 코멘트는 별도 페이지에 저장되어, 시스템 프롬프트에 추가된다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서 끝이 아니었다. 노션에 있는 오늘의 할 일 목록도 수집하도록 기능을 추가했는데, 할 일이 중복되어 나왔다. 중복 제거를 넣었지만 문자열 비교만으로는 ‘회의 준비’와 ‘회의 준비하기’를 같은 항목으로 인식하지 못해서, 결국 클로드에게 의미가 비슷한 항목을 골라내도록 시켰다. 봇이 요약을 보내기 전에 내가 먼저 메시지를 보내면 일기가 아직 없어서 저장할 곳이 없는 문제도 있었다. 그래서 어느 날짜 일기에 넣을지 물어보는 대화 흐름을 추가했다. 오늘은 할 일 체크 상태가 두 페이지 사이에서 동기화되지 않는 걸 발견해서 또 고쳤다. 분명 내일이 되면 또 부족한 점이 보일 것이다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;만약 이 프로그램을 처음부터 전부 다 직접 코딩했다면 설계 단계에서부터 매우 고민이 많았을 것이다. 한번 구조를 결정하면 변경이 어렵기 때문이다. 하지만 AI와 함께라면 구조 변경이 순식간에 가능하기 때문에, 아이디어가 떠오를 때마다 부담 없이 바로 시도해 볼 수 있었다. 그동안의 코딩과는 차원이 다른 속도로 기능이 완성되는, 정말이지 도파민이 터지는 순간들이었다. 새로운 프로그래밍 방법은 나를 쉴 수 없게 만들었다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 이게 언제쯤 완성될지 잘 모르겠다. 사실 사이드 프로젝트라 굳이 완성 시점을 정해야 하는 것은 아니다. 하지만 만약 이걸 앱스토어에 출시하기로 마음먹었다면, ‘이것만 고치고, 이 기능까지만 넣고’ 하다가 결국 완성하지 못할 것 같다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;가만히 생각해보면 모순적인 상황이다. 분명 아주 빠른 속도로 개발하고 있는데, 완성은 되지 않는 상황이다. “더 나은 버전이 존재한다”라는 사실이 계속 나를 불안하게 만든다. 당장 일주일 만에 수많은 기능들을 개선하고 추가할 수 있고, 완전히 갈아엎고 새로 만들 수도 있다. 그래서 적당한 선에서 완성을 외치기란 더 쉽지 않다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;왜 멈추지 못하는가?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;예전에는 실력의 한계가 곧 완성도의 한계였다. 그때는 내가 할 수 있는 데까지 했으면 “여기까지가 내 최선이다”라고 받아들였다. 또한 이미 만든 결과물이 있으면 되도록 그것을 살리고 약간의 개선을 통해 어떻게든 완성하는 것이 자연스러운 이치였다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 이제는 굳이 그 지점에서 멈춰야 할 이유가 사라졌다. AI와 협업하다 보면 우리 마음속에 슬그머니 이런 불안감이 자리 잡는다. “혹시 프롬프트를 변경하면 더 좋은 결과물이 나오는 것 아닐까?”, “내가 검토시키지 않은 다른 문제는 없을까?” 몇 번 더 작업을 시키는 데에는 약간의 토큰만 들 뿐 시간은 별로 들지 않기에, 계속 붙잡고 있게 된다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;게다가 모델은 매일 좋아지고, 커뮤니티에서는 더 좋은 프롬프트 방법론도 등장한다. 이런 상황에서는 오늘 만든 결과물이 내일도 최선이라고 결코 장담할 수가 없다. 내 작업물이 10년 후의 경쟁작보다 뒤처지는 것은 양보할 수 있는 일이다. 하지만, 당장 내일의 경쟁작에 뒤처지는 것은 쉽게 용납하기가 어렵다. 멈추는 것은 곧 게으른 것이고, 포기하는 것처럼 느껴진다. 그렇게 완성은 요원해진다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그리스 신화의 시지프스는 산꼭대기에 올린 바위가 다시 굴러떨어지기 때문에 그것을 또 밀어 올려야 했다. 그러나 우리는 바위가 꼭대기에 올라갔는데도, 더 높은 산이 보이기 때문에 멈추지 못한다. 시지프스가 받은 것은 신의 벌이지만, 우리가 받은 것은 스스로 선택한 벌이다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그러면 우리는 어디서 멈춰야 하는 걸까?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;강박을 멈추기 위한 나만의 방법&amp;nbsp;&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;마크 엘리슨은 《완벽에 관하여》에서 흠집이 없는 완벽한 상태를 추구하기보단, 그 과정에서 성장하는 게 중요하다고 말한다. 현명한 말이다. 다만 AI 시대의 문제는 그 방향을 따라가는 비용이 너무 저렴해졌다는 점이다. 예전에는 방향만 잡고 한 걸음씩 움직였다면, 지금은 방향만 설정하면 AI가 비행기에 태워서 데려다준다. 그러나 인간의 정신과 신체는 아직 이 속도에 완전히 적응하지 못했다. 너무 빠르게 날면 금방 지치고 만다. 그렇기 때문에 스스로 멈출 정거장과 종점을 정해두는 게 좋다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;① 마감일을 정한다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;당연한 말이지만, 기한이 없으면 끝도 없다. 무한한 개선의 가능성을 유한한 시간 안에 가두는 것이다. 만약 내가 일기 앱을 출시하려고 마음먹는다면, 1차, 2차, 최종 마감일을 정해놓을 것이다. 마감일이 코앞이라면 새로운 개선 사항이 떠오르더라도 일단 백로그에 둔다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;회사 업무에는 정해진 기한이 있으니 그나마 낫지만, 사이드 프로젝트처럼 아무도 재촉하지 않는 작업은 기한을 정하는 게 어렵다. 그리고 바이브 코딩은 자연어로 작업을 하기 때문에 태스크에 소요되는 시간을 산정하는 게 쉬운 일이 아니다. 정확하지 않더라도 일단 적당한 날짜를 선택하고, 프로젝트를 진행하면서 날짜를 산정하는 감을 익히는 것이 좋다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;② 우선순위를 정해서 번갈아 가며 손을 댄다(멀티태스킹)&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이건 아마 모든 사람에게 통용되지는 않을 수 있고, AI 성능이 향상될수록 효용이 떨어질 수 있는 방법론이다. 모델에 따라 차이가 있지만, 대체로 일을 시키면 그에 대한 응답이 돌아올 때까지 시간이 좀 걸린다. 그래서 나는 그 시간을 활용하기 위해 여러 작업창을 띄워두고 번갈아가면서 작업을 시킨다. 원래 멀티태스킹을 선호하는 편은 아니었는데, AI와 협업을 한 이후로는 좋아하게 되었다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;내가 정한 우선순위는 ① 버그 수정 ② 마감이 임박한 일 ③ 난이도 높은 일이다. 버그는 최대한 빨리 고쳐야 하기 때문에, 이 터미널 창을 가장 자주 들여다본다. 이 세션에서 작업을 지시해두고, 마감이 임박한 작업을 또 다른 세션에서 지시한다. 두 세션이 모두 일을 하고 있으면 새 에이전트를 띄워서 다음에 만들 기능에 대해 아이디어 회의를 한다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;참고로 최근에 클로드에서 ‘Agent View’라는 기능을 만들었다. 여러 세션을 한눈에 보는 일종의 대시보드인데, 이 대시보드를 활용하면 좀 더 편리하게 세션을 관리할 수 있다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3787/image2.png"&gt;&lt;figcaption&gt;&amp;lt;출처: &lt;a href="https://claude.com/blog/agent-view-in-claude-code"&gt;Agent view in Claude Code&lt;/a&gt;&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이렇게 멀티태스킹을 하면 같은 시간에 더 많은 일을 끝낼 수 있다. 한 작업을 끝장내려고 매달리는 시간이 줄어든다. 다른 세션의 작업도 진행되고 있기 때문에, 이제는 퇴근 시간에 미련 없이 손을 뗄 수 있게 되었다. 그리고 일 하나에 너무 완벽을 기하다가 다른 일의 시작이 늦어지는 경우도 줄어들었다. 여러 문제에 골고루 시간을 씀으로써 전체 품질은 더 올라가게 되었다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;③ 하나의 작업 단위가 끝날 때마다 작업 내용을 docs에 기록해두도록 시킨다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;일을 멈추지 못하는 이유 중 하나는 다음 날이 되면 컨텍스트를 잊어버리기 때문이다. 물론 클로드는 대화 기록을 빠르게 다시 불러올 수 있지만, 인간의 기억은 좀 더 로딩 시간이 걸린다. 그래서 작업 중간중간 나를 위한 요약본을 정리하게 시켰다. 대강 일이 마무리되었다 싶을 때마다 클로드가 이렇게 묻는다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;“지금까지 한 작업을 기록해 둘까요?”&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이제 나는 언제든 마음 놓고 그날의 일을 끝낼 수 있게 됐다. 다시 돌아왔을 때 이 md 문서를 살펴보면, 금방 기억이 되살아나기 때문이다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3787/image5.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;④ 유한함을 인정하는 마음가짐&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;AI의 작업 속도는 사실상 무한해 보이지만, 그걸 판단하는 나의 체력과 시간은 유한하다. ‘가능한 최선’이 아니라, ‘오늘의 최선’을 기준으로 삼으려고 노력한다. 번아웃을 겪기 전의 나는 이걸 몰랐다. 정신과 신체의 체력이 모두 고갈된 후에야 비로소 내 에너지가 무한하지 않다는 것을 인정하게 되었다. AI는 도구이고, 도구의 성능이 아무리 좋아도 그것을 쥐고 있는 손이 떨리면 소용이 없다. 이 비대칭을 받아들이고 나니 마음이 한결 편해졌다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;멈추는 것은 우리의 선택이다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AI는 분명 우리를 더 나은 결과물에 가까이 데려다준다. 그것은 좋은 일이다. 하지만 더 나아질 수 있는 가능성을 전부 실현하려는 순간, 영원히 완성하지 못하는 사람이 된다. 시지프스의 바위가 멈추지 않는 이유는 신의 벌이지만, 우리의 바위가 멈추지 않는 이유는 멈추지 않기로 한 우리의 선택이다. 그래서 나는 마감일을 정하고, 여러 세션을 번갈아 돌리고, 중간중간 기록을 남기고, 오늘의 최선에서 손을 뗀다. 완벽주의가 나를 잡아먹지 않도록 노력한다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;물론 이 네 가지 방법을 쓴다고 해서 바로 마인드셋이 달라지는 것은 아니다. 나는 여전히 마감 직전에 “하나만 더” 시키고 싶은 마음이 들고, 제출 버튼을 누르는 순간에도 마음 한구석이 불편하다. 하지만 분명히 달라진 것은 어쨌든 그 불편함을 느끼면서도 버튼을 누를 수 있게 되었다는 것이다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 글도 완벽하지 않지만 오늘 나의 최선이다. 내일의 나는 더 잘 쓸 수 있겠지만, 그건 내일의 일이다. 번아웃을 겪지 않는 인공지능에게 미래에 대체될 수도 있겠지만, 그것도 미래의 일이다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 글을 쓰면서 다른 사람들은 어떤지도 궁금해졌다. AI와 함께 일하면서 비슷한 강박을 느끼는 사람도 있을 것이고, 나보다 훨씬 가벼운 마음으로 멈추는 사람도 있을 것이다. 만약 여러분만의 방법이 있다면, 댓글로 공유해 주셔도 좋겠다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3787/image4.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, ChatGPT로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>타입스크립트 타입, 꼭 새로 만들어야 할까?</title><link>https://yozm.wishket.com/magazine/detail/3760</link><description>타입스크립트로 프로젝트를 하다 보면, 기존에 정의해둔 타입을 조금만 바꿔서 쓰고 싶은 순간이 자주 찾아옵니다. 회원 정보 타입에서 비밀번호 필드만 빼고 싶을 때, 모든 필드를 선택적으로 바꿔서 수정 폼에 쓰고 싶을 때, 이미 정의된 타입에서 몇 개의 필드만 골라 목록 화면용 타입을 만들고 싶을 때 등이 대표적입니다. 타입스크립트는 이런 상황을 위해 유틸리티 타입(Utility Types)을 기본으로 제공합니다. 기존 타입을 입력으로 받아 일부를 골라내거나, 제외하거나, 선택적으로 바꿔주는 내장 도구들입니다. 이번 글에서는 그중에서도 실무에서 가장 자주 쓰이는 대표 유틸리티 타입 다섯 가지 Partial, Required, Pick, Omit, Record에 집중해서 살펴보겠습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3760</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;타입스크립트로 프로젝트를 하다 보면, 기존에 정의해둔 타입을 조금만 바꿔서 쓰고 싶은 순간이 자주 찾아옵니다. 회원 정보 타입에서 비밀번호 필드만 빼고 싶을 때, 모든 필드를 선택적으로 바꿔서 수정 폼에 쓰고 싶을 때, 이미 정의된 타입에서 몇 개의 필드만 골라 목록 화면용 타입을 만들고 싶을 때 등이 대표적입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이럴 때마다 새로운 타입을 처음부터 다시 정의하면 코드 중복이 생기고, 원본 타입이 바뀔 때마다 관련된 타입을 전부 찾아서 수정해야 하는 문제가 생기는데요. 이런 중복은 단순히 번거로운 정도를 넘어서, 타입과 실제 데이터가 어긋나는 버그로 이어지기 쉽습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;타입스크립트는 이런 상황을 위해 유틸리티 타입(Utility Types)을 기본으로 제공합니다. 기존 타입을 입력으로 받아 일부를 골라내거나, 제외하거나, 선택적으로 바꿔주는 내장 도구들입니다. 프레임워크나 별도의 라이브러리 없이 타입스크립트 자체에 포함되어 있기 때문에, 별다른 설정 없이 바로 사용할 수 있다는 점도 큰 장점입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 그중에서도 실무에서 가장 자주 쓰이는 대표 유틸리티 타입 다섯 가지 Partial, Required, Pick, Omit, Record에 집중해서 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;미리 요점만 콕 집어보면?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;타입스크립트는 기존 타입을 입력으로 받아 일부를 골라내거나, 제외하거나, 선택적으로 바꿔주는 유틸리티 타입을 기본으로 제공합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;Partial, Required, Pick, Omit, Record를 활용하면 원본 타입 하나만 정의해두고, 다른 타입은 그 원본을 변환해서 만들어 코드 중복과 타입 어긋남 문제를 줄일 수 있습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;유틸리티 타입은 서로 조합해 복잡한 변환도 선언적으로 표현할 수 있지만 중첩이 깊어질수록 가독성이 떨어져, 중간 단계 타입에 이름을 붙여 분리하는 편이 유지보수에 유리합니다.&lt;/li&gt;&lt;/ul&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;유틸리티 타입이 왜 필요한가&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;유틸리티 타입의 필요성을 이해하려면, 먼저 타입 중복이 어떻게 발생하는지부터 살펴봐야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 타입 중복의 문제&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;실무에서 비슷한 모양의 타입을 여러 번 정의하는 경우는 생각보다 흔합니다. 예를 들어, 회원 정보를 다루는 애플리케이션을 만든다고 해봅시다. 가입 화면, 프로필 수정 화면, 관리자용 목록 화면에서 사용하는 타입이 조금씩 다를 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface User {
  id: number;
  email: string;
  password: string;
  name: string;
  phone: string;
  createdAt: Date;
}

interface UserUpdate {
  email?: string;
  name?: string;
  phone?: string;
}

interface UserListItem {
  id: number;
  email: string;
  name: string;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;얼핏 보면 문제가 없어 보이지만, 이 구조에는 함정이 있습니다. User 타입에 새로운 필드(예:address)가 추가되면 UserUpdate와 UserListItem도 함께 수정해야 합니다. 수정을 빠뜨리면 원본 타입과 어긋난 상태가 되어 버그의 원인이 됩니다. 비슷한 타입이 늘어날수록 이 문제는 더 커지고, 타입 정의를 관리하는 데 쓰이는 시간도 급격히 증가합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3760/%EA%B7%B8%EB%A6%BC1__4_.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude design으로 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;게다가 이런 타입은 대부분 원본과 의존 관계를 갖고 있습니다. UserUpdate는 "수정 가능한 필드들"이고, UserListItem은 "목록에 노출할 필드들"입니다. 정말로 독립된 타입이 아니라 User를 재료로 파생된 타입들이라는 뜻입니다. 그렇다면 이 의존 관계를 타입 시스템으로도 명시해두는 편이 훨씬 자연스럽고 안전합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 기존 타입을 변환한다는 발상&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;해결책은 간단합니다. 원본 타입 하나만 잘 정의해두고, 나머지는 그 원본을 변환해서 만드는 것입니다. "이 필드만 골라내줘", "모든 필드를 선택적으로 바꿔줘" 같은 변환 규칙만 선언해두면 원본이 바귈 때 파생 타입도 자동으로 따라옵니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;타입스크립트는 이런 변환을 위한 내장 도구를 제공하는데, 이것이 바로 유틸리티 타입입니다. 예를 들어, 아직 자세히 다루지는 않았지만, 아래 코드를 한 번 살펴봅시다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type UserUpdate = Partial&amp;lt;Pick&amp;lt;User, "email" | "name" | "phone"&amp;gt;&amp;gt;;
type UserListItem = Pick&amp;lt;User, "id" | "email" | "name"&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Pick은 원본에서 특정 필드만 골라내고, Partial은 모든 필드를 선택적으로 바꿔줍니다. 이 두 줄만으로 앞서 별도의 인터페이스로 정의했던 UserUpdate와 UserListItem이 만들어집니다. User 타입의 email이 emailAddress로 바뀌더라도 관련 타입들은 컴파일러가 알아서 추적해주기 때문에, 타입 정의 한 곳만 고치면 됩니다. 이제 각 유틸리티 타입이 어떻게 동작하는지 하나씩 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;모든 필드를 선택적으로 - Partial&amp;lt;T&amp;gt;&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;수정 기능을 구현할 때 가장 먼저 만나게 되는 유틸리티 타입입니다. 업데이트할 필드만 전달받고 나머지는 그대로 두고 싶을 때, Partial&amp;lt;T&amp;gt;가 그 역할을 해줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) Partial의 동작 원리&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Partial&amp;lt;T&amp;gt;는 이름 그대로 "부분적인" 타입을 만들어주는 유틸리티 타입입니다. 타입 T의 모든 프로퍼티를 선택적(optional)으로 바꾼 새 타입을 만들어줍니다. 필드 하나하나에 직접&amp;nbsp; ?를 붙이는 대신, 타입 수준에서 "전부 선택적으로"라는 규칙을 한 번에 적용하는 셈입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface User {
  id: number;
  name: string;
  email: string;
  phone: string;
}

// 모든 필드가 optional로 변환됨
type UserPatch = Partial&amp;lt;User&amp;gt;;
// {
//   id?: number;
//   name?: string;
//   email?: string;
//   phone?: string;
// }
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서 한 가지 짚고 넘어갈 점이 있습니다. 실무에서는 "optional 프로퍼티"와 “undefined를 허용하는 프로퍼티"를 거의 같은 의미로 이해해도 큰 문제가 없지만, 엄밀하게는 완전히 같은 개념은 아닙니다. 특히 exactOptionalPropertyTypes 옵션을 켜면 둘 차이가 명확하게 드러나므로, ?가 붙은 필드와 field: string | undefined가 언제나 호환된다고 단정하지 않는 편이 좋습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 실무 예시: 프로필 수정 함수&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Partial의 프로필 수정 함수에서 가장 전형적으로 활용됩니다. 변경된 필드만 받아서 원본 객체에 병합하는 구조입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function updateUser(user: User, patch: Partial&amp;lt;User&amp;gt;): User {
  return { ...user, ...patch };
}

const current: User = {
  id: 1,
  name: "효빈",
  email: "a@b.com",
  phone: "010",
};

// name만 변경하고 싶을 때
const updated = updateUser(current, { name: "효빈2" });
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;만약 Partial을 쓰지 않고 patch 매개변수 타입을 그냥 User로 받았다면, 호출할 때마다 모든 필드를 채워 넣어야 했을 것입니다. 이름만 바꾸는 경우에도 email, phone, id까지 전부 명시해야 하는 불편한 API가 되는 셈입니다. Partial 덕분에 실제로 바꾸고 싶은 필드만 골라서 넘길 수 있게 된 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 Partial을 사용할 때 한 가지 주의할 점이 있습니다. 모든 필드가 선택적이 된다는 말은, 빈 객체 {}도 유효한 값으로 인정된다는 뜻입니다. "아무것도 바꾸지 않는 업데이트"가 가능해지는 셈이므로, 적어도 하나의 필드는 반드시 받아야 하는 상황이라면 별도의 런타입 검증 로직이 필요합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;모든 필드를 필수로 - Required&amp;lt;T&amp;gt;&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;Partial이 모든 필드를 선택적으로 바꿔주는 도구였다면, Required는 정반대 방향으로 작동합니다. 기본값 병합처럼, 선택적 입력을 확정된 상태로 만드는 시점에서 활용됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) Required의 동작 원리&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Required&amp;lt;T&amp;gt;는 타입 T의 모든 선택적 프로퍼티에서 ?를 제거해, 모든 필드가 반드시 존재하도록 강제하는 타입을 만들어줍니다. 언뜻 보면 쓸 일이 있을까 싶지만, 설정 객체처럼 "기본값과 병합한 이후에는 모든 필드가 반드시 채워져 있어야 하는" 상황에서 유용합니다. 입력 시점에는 선택적이지만, 가공을 거친 이후에는 모든 값이 확정되어 있어야 한다는 흐름을 타입으로 자연스럽게 표현할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 실무 예시: 설정 객체 병합&amp;nbsp;&lt;/strong&gt;&lt;/h4&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface Config {
  host?: string;
  port?: number;
  timeout?: number;
}

const defaultConfig: Required&amp;lt;Config&amp;gt; = {
  host: "localhost",
  port: 3000,
  timeout: 5000,
};

function createClient(userConfig: Config) {
  const config: Required&amp;lt;Config&amp;gt; = { ...defaultConfig, ...userConfig };
  // 이 시점부터 config의 모든 필드는 확정된 값을 가집니다.
  // 내부 구현에서는 host, port, timeout이 undefined일 가능성을 신경 쓰지 않고 바로 사용할 수 있습니다.
  return config;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;userConfig는 선택적으로 받지만, 기본값과 병합한 결과는 Required&amp;lt;Config&amp;gt;로 확정됩니다. 이렇게 되면 이후 코드에서 config.host가 undefined일 가능성을 걱정하지 않고 바로 사용할 수 있습니다. 선택성이라는 불확실성을 경계에서 한 번 제거하고 나면, 내부 구현 코드는 훨씬 단순해집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 패턴은 타입스크립트에서 자주 등장하는 "입력은 느슨하게 받고, 내부에서는 엄격하게 다룬다"는 원칙의 전형적인 예시이기도 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;원하는 필드만 골라내기 - Pick&amp;lt;T, K&amp;gt;&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;기존 타입에서 특정 필드만 뽑아 새 타입을 만들고 싶을 때 사용하는 유틸리티 타입입니다. 컴포넌트 props처럼, 전체 데이터 중 일부만 필요로 하는 인터페이스를 명확하게 표현할 때 특히 유용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) Pick의 동작 원리&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Pick&amp;lt;T, K&amp;gt;에서 T는 원본 타입이고, K는 골라낼 프로퍼티 키의 유니온입니다. 이때 K는 반드시 keyof T에 속하는 키여야 하므로, 원본 타입에 없는 키를 적으면 컴파일 에러가 납니다. 덕분에 오타가 나더라도 타입 단계에서 바로 잡을 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 실무 예시: 게시글 미리보기 타입&amp;nbsp;&lt;/strong&gt;&lt;/h4&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface Post {
  id: number;
  title: string;
  content: string;
  author: string;
  createdAt: Date;
  likeCount: number;
  viewCount: number;
}

type PostPreview = Pick&amp;lt;Post, "id" | "title" | "author" | "createdAt"&amp;gt;;
// {
//   id: number;
//   title: string;
//   author: string;
//   createdAt: Date;
// }

function renderPostList(posts: PostPreview[]) {
  return posts.map((p) =&amp;gt; `${p.title} - ${p.author}`);
}
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Pick의 장점은 타입 이름만 봐도 어떤 필드가 포함되는지 바로 알 수 있다는 것입니다. 별도로 새 인터페이스를 만들고 필드를 나열하는 것보다 훨씬 선언적입니다. 또한 원본 Post 타입의 필드 타입이 바뀌면 PostPreview도 자동으로 같이 바뀌기 때문에, 타입 동기화를 위한 수작업이 사라집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반대로 Pick이 잘 맞지 않는 경우도 있습니다. 원본 타입에서 대부분의 필드를 남기고 일부만 제외하고 싶을 때는, 남길 필드를 일일이 나열해야 해서 오히려 장황해집니다. 이럴 때는 뒤에 소개할 Omit이 더 잘 어울립니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;특정 필드만 제외하기 - Omit&amp;lt;T, K&amp;gt;&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;Pick이 "남길 것을 고르는" 방식이라면, Omit은 "뺄 것만 지정하는" 방식입니다. 빼야 할 필드가 적고 남길 필드가 많을 때, Pick 보다 훨씬 간결합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) Omit의 동작 원리&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Omit&amp;lt;T, K&amp;gt;는 원본 타입 T에서 K에 해당하는 프로퍼티만 빼고 나머지 전부로 새 타입을 만듭니다. Omit은 Pick과 달리 K에 keyof T 제약이 느슨하게 적용되긴 하지만, 실무에서는 원본에 존재하는 키만 지정하는 편이 의도를 명확히 드러내고 안전합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 실무 예시: 생성 요청에서 id 제외하기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;게시글 생성 API의 요청 타입을 만든다고 해봅시다. 서버가 자동으로 생성하는 id, createdAt 같은 필드는 클라이언트가 보내면 안 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface Post {
  id: number;
  title: string;
  content: string;
  author: string;
  createdAt: Date;
}

type CreatePostInput = Omit&amp;lt;Post, "id" | "createdAt"&amp;gt;;
// {
//   title: string;
//   content: string;
//   author: string;
// }

function createPost(input: CreatePostInput) {
  // 서버에 POST 요청
}
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;만약 Pick으로 같은 일을 하려면 Pick&amp;lt;Post, "title" | "content" | "author"&amp;gt; 처럼 남기고 싶은 필드를 전부 나열해야 합니다. 필드가 많아질수록 번거로워지고, 새 필드가 추가될 때마다 이 목록도 유지보수를 해야 합니다. 반면, Omit은 "빼고 싶은 것"만 지정하면 되기 때문에, 원본 타입에 필드가 추가되면 자동으로 새 타입에도 포함됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;비밀번호 같은 민감 정보를 응답에서 제외할 때도 자주 쓰입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface User {
  id: number;
  email: string;
  password: string;
  name: string;
}

type UserResponse = Omit&amp;lt;User, "password"&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 한 가지 주의할 점이 있습니다. 도메인 모델에서 요청 타입이나 응답 타입을 곧바로 파생시키는 방식은 편리하지만, 두 타입이 시간이 지나면서 서로 다른 방향으로 진화할 수도 있습니다. 이럴 땐 굳이 원본에 묶어두기보다는 독립된 타입으로 분리하는 편이 더 나을 수 있습니다. 유틸리티 타입은 강력하지만, 언제나 원본과 강하게 결합하는 것이 최선은 아니라는 점은 기억해 둘 만합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Pick과 Omit 중에 무엇을 쓸지 고민된다면, 간단한 기준을 기억해두면 좋습니다. 보통 "남기고 싶은 필드"가 소수일 때는 Pick, "빼고 싶은 필드"가 소수일 때는 Omit을 선택하는 편이 직관적입니다. 두 경우 모두 코드를 읽는 사람이 한눈에 의도를 파악할 수 있도록, 타입 이름에 의도를 명확하게 드러낸다는 점이 중요합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;키-값 쌍의 타입을 지정하기 - Record&amp;lt;K, V&amp;gt;&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;Record도 당연히 유틸리티 타입이지만, 앞선 네 가지와는 결이 조금 다릅니다. 기존 객체 타입을 변형하기보다는, 키 집합과 값 타입을 선언해 새로운 객체 구조를 만들 때 자주 쓰입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) Record의 동작 원리&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Record&amp;lt;K, V&amp;gt;는 K에 해당하는 키 집합과 V에 해당하는 값 타입으로 구성된 객체 타입을 만들어줍니다. 인덱스 시그니처({ [key: string]: string })와 비슷해 보이지만 중요한 차이가 있습니다. 인덱스 시그니처는 "어떤 문자열 키든 허용한다"는 느슨한 약속이지만, Record는 키를 리터럴 유니온으로 제한할 수 있어서 허용되는 키 집합이 명확하게 고정됩니다. 지정한 키가 누락되면 컴파일 에러가 발생하고, 반대로 허용되지 않은 키를 추가하려 해도 에러가 발생합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type StatusLabel = Record&amp;lt;"loading" | "success" | "error", string&amp;gt;;
// {
//   loading: string;
//   success: string;
//   error: string;
// }

const labels: StatusLabel = {
  loading: "로딩 중",
  success: "성공",
  error: "실패",
};
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;위 예시에서 error 키를 빠뜨리고 선언하면, 타입스크립트가 바로 잡아줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 실무 예시: 상태별 라벨 매핑&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;정해진 키 집합에 대해 모든 값을 매핑해야 하는 상황에서 Record가 유용합니다. 페이지 권한, 상태별 스타일, 언어별 문자열 같은 경우가 그렇습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type Role = "admin" | "member" | "guest";

const permissions: Record&amp;lt;Role, string[]&amp;gt; = {
  admin: ["read", "write", "delete"],
  member: ["read", "write"],
  guest: ["read"],
};
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;새로운 역할이 Role에 추가되면, permissions 객체에도 해당 키를 반드시 채워야 합니다. 이렇게 키 목록과 실제 데이터를 타입으로 강하게 묶어두는 것이 Record의 역할입니다. 새 키 추가와 데이터 반영이 함께 이루어지도록 타입 시스템이 강제해 주므로, 누락된 케이스로 인한 런타임 버그를 미리 차단할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;유틸리티 타입 조합하기&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;유틸리티 타입의 진짜 힘은 서로 조합해서 쓸 때 드러납니다. 각 유틸리티 타입이 작은 도구라면, 조합은 이 도구들을 이어 붙여 더 정교한 변환을 만들어내는 과정이라고 생각해 볼 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 여러 유틸리티 타입을 중첩해서 쓰기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;"일부 필드만 골라서, 그중에서도 전부 선택적으로 받고 싶다"라는 요구사항은 Partial과 Pick의 조합으로 풀립니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;// email, phone만 선택적으로 받아서 업데이트
type ContactUpdate = Partial&amp;lt;Pick&amp;lt;User, "email" | "phone"&amp;gt;&amp;gt;;

function updateContact(id: number, patch: ContactUpdate) {
  // ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;p style="margin-left:36pt;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;유틸리티 타입을 중첩할 때는 안쪽부터 바깥쪽 순서로 적용된다는 점을 기억하면 도움이 됩니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3760/%EA%B7%B8%EB%A6%BC2__4_.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude design으로 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;위 예시에서 Pick&amp;lt;User, "email" | "phone"&amp;gt;이 먼저 계산되어 email과 phone만 가진 타입이 만들어지고, 그 결과에 Partial이 적용되어 두 필드가 모두 선택적이 됩니다. 순서를 바꿔서 Pick&amp;lt;Partial&amp;lt;User&amp;gt;, "email" | "phone"&amp;gt;이라고 써도 결과는 비슷하지만, 변환 의도가 "일단 골라낸 후 선택적으로 만든다"인지 "전부 선택적으로 바꾼 후 일부만 고른다" 인지는 분명히 다릅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;기존 타입에서 몇 개의 필드를 제외한 뒤, 특정 필드를 새로 덧붙이고 싶은 경우에는 Omit과 교차 타입(&amp;amp;)을 함께 사용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;// 기본 User에서 password는 빼고, role 필드는 추가
type AdminUser = Omit&amp;lt;User, "password"&amp;gt; &amp;amp; {
  role: "admin" | "super";
};
&lt;/code&gt;&lt;/pre&gt;&lt;p style="margin-left:36pt;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 지나친 중첩은 오히려 독&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;다만 조합이 깊어질수록 가독성이 떨어지는 점은 주의해야 합니다. 중첩이 서너 단계를 넘어가기 시작하면 타입 이름만 봐서는 의도를 파악하기 어려워집니다. 타입을 읽는 사람이 머릿속에서 여러 변환을 차례대로 적용해 결과를 상상해야 하기 때문입니다. 이런 경우에는 중간 단계 타입에 이름을 붙여서 분리하는 편이 유지보수에 훨씬 유리합니다. 타입에 이름을 붙이는 행위 자체가 일종의 문서 역할을 하기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;// ❌ 한 줄에 전부 다 담기
type A = Partial&amp;lt;Omit&amp;lt;Pick&amp;lt;User, "email" | "phone"&amp;gt;, never&amp;gt;&amp;gt;;

// ✅ 단계별로 이름 붙이기
type Contact = Pick&amp;lt;User, "email" | "phone"&amp;gt;;
type ContactPatch = Partial&amp;lt;Contact&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 실무에서 가장 자주 쓰이는 다섯 가지 유틸리티 타입을 살펴봤습니다. Partial&amp;lt;T&amp;gt;로 모든 필드를 선택적으로 바꾸고, Required&amp;lt;T&amp;gt;로 다시 모든 필드를 필수로 되돌릴 수 있습니다. Pick&amp;lt;T, K&amp;gt;로 원본에서 필요한 필드만 골라낼 수 있고, Omit&amp;lt;T, K&amp;gt;로 특정 필드를 빼낸 나머지 타입을 만들 수 있습니다. 그리고 Record&amp;lt;K, V&amp;gt;는 정해진 키 집합에 대한 값 타입을 강제할 때 유용합니다. 여러 유틸리티 타입을 조합하면 복잡한 변환도 선언적으로 표현할 수 있지만, 중첩이 깊어질 때는 중간 단계에 이름을 붙여 분리하는 편이 더 읽기 좋습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;비슷한 타입을 복사해서 조금씩 수정해가며 쓰고 있다면, 대부분의 경우 유틸리티 타입 한두 개로 중복을 깔끔하게 줄일 수 있습니다. 특히 API 요청/응답 타입, 폼 입력 타입, 상태 매핑 타입처럼 기존 모델에서 파생되는 타입이라면 유틸리티 타입의 활용 효과가 큽니다. 원본 모델 하나만 잘 관리하면, 파생 타입들은 컴파일러가 자동으로 따라와 주기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;유틸리티 타입에 익숙해지는 가장 좋은 방법은, 새 타입을 만들기 전에 한번 멈춰서 "이 타입은 혹시 기존 타입에서 파생된 것은 아닐까?"라고 스스로에게 물어보는 습관을 들이는 것입니다. 이런 질문을 거치다 보면, 인터페이스를 새로 정의하는 대신 유틸리티 타입으로 표현할 수 있는 경우가 생각보다 많다는 것을 알게 됩니다.&lt;/p&gt;&lt;hr&gt;&lt;p style="text-align:justify;"&gt;&amp;lt;참고&amp;gt;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;a href="https://ts.winterlood.com/a5b224e2-3f3e-432c-8bfb-7b338762514f%20,"&gt;&lt;u&gt;한 입 크기로 잘라먹는 타입스크립트&lt;/u&gt;&lt;/a&gt;&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;a href="https://inpa.tistory.com/entry/TS-%F0%9F%93%98-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9C%A0%ED%8B%B8%EB%A6%AC%ED%8B%B0-%ED%83%80%EC%9E%85-%F0%9F%92%AF-%EC%B4%9D%EC%A0%95%EB%A6%AC"&gt;&lt;u&gt;타입스크립트 유틸리티 타입 총정리 (+응용) / 인파&lt;/u&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>에이전틱 엔지니어링 시대에서 살아남기</title><link>https://yozm.wishket.com/magazine/detail/3752</link><description>에이전트는 단순한 챗봇이 아니다. 문서를 읽고, 코드를 바꾸고, 툴을 호출하고, 결과를 다시 평가해 다음 행동을 선택하는 실행 주체다. 이 말은 곧, AI를 잘 쓴다는 것이 “질문을 잘하는 사람”에 머무르지 않는다는 뜻이다. 이제는 AI와 사람이 함께 일해도 무너지지 않는 구조를 설계하는 사람이 오래 살아남을 것이다. 이 글의 핵심은 하나다. 에이전트 시대의 승부처는 모델 이해가 아니라 업무 설계다. 누가 더 멋진 프롬프트를 쓰느냐보다, 누가 더 나은 작업 단위와 검증 루프를 만들 수 있느냐가 훨씬 중요해진다.</description><guid>https://yozm.wishket.com/magazine/detail/3752</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;지금 하는 일에서 AI를 얼마나, 그리고 어떻게 쓰고 있는가? 요즘은 프롬프트, 에이전트, 컨텍스트, 하네스 같은 용어를 이제 개발자만 쓰지 않는다. 기획자도, 디자이너도, 운영 조직도 AI를 “어떻게 붙일지”를 이야기한다. 겉으로 보면 AI는 이미 모두의 도구가 된 것처럼 보인다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 정작 현장에서 벌어지는 일은 조금 다르다. 많은 조직이 아직도 AI를 “답변을 잘 뽑아주는 도구” 정도로 다룬다. 좋은 프롬프트를 쓰는 사람이 앞서고, 모델을 빨리 바꿔 쓰는 사람이 유리하다고 생각한다. 하지만 에이전트가 본격적으로 업무에 들어오면, 경쟁력의 축은 전혀 다른 곳으로 이동한다. 중요한 것은 더 이상 한 번에 더 좋은 답을 뽑는 능력이 아니다. 일을 기계가 다룰 수 있는 단위로 쪼개고, 기준을 명시하고, 실패를 되돌릴 수 있게 설계하는 능력이다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3752/image3.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, 나노 바나나&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;에이전트는 단순한 챗봇이 아니다. 문서를 읽고, 코드를 바꾸고, 툴을 호출하고, 결과를 다시 평가해 다음 행동을 선택하는 실행 주체다. 이 말은 곧, AI를 잘 쓴다는 것이 “질문을 잘하는 사람”에 머무르지 않는다는 뜻이다. 이제는 AI와 사람이 함께 일해도 무너지지 않는 구조를 설계하는 사람이 오래 살아남을 것이다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 글의 핵심은 하나다. 에이전트 시대의 승부처는 모델 이해가 아니라 업무 설계다. 누가 더 멋진 프롬프트를 쓰느냐보다, 누가 더 나은 작업 단위와 검증 루프를 만들 수 있느냐가 훨씬 중요해진다.&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;AI Agent의 등장은 무엇을 바꾸는가&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AI Agent의 등장은 생산성을 올린다. 하지만 더 정확히 말하면, 생산성의 병목을 이동시킨다. 예전에는 결과물을 만드는 실행력이 중요했다면, 이제는 생성보다 검증, 작성보다 조율, 개인 숙련보다 시스템 설계가 더 중요해진다. 에이전트는 많은 일을 빠르게 처리할 수 있지만, 동시에 그럴듯하게 틀릴 수도 있다. 그래서 에이전트를 잘 쓰는 조직은 “무엇을 자동화할 것인가”보다 “어디서 멈추고, 어떻게 검증할 것인가”를 먼저 설계한다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3752/image2.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 젠스파크&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실제로 바뀌는 것은 업무의 단위다. 과거의 자동화가 정해진 규칙을 코드로 옮기는 일이었다면, 에이전트 기반 자동화는 애매한 문맥과 예외를 포함한 채 일을 진행한다. 이때 중요한 것은 모델 자체보다 그 모델이 의존하는 환경이다. 컨텍스트는 단순히 긴 프롬프트가 아니라, 무엇이 최신 정보인지, 어떤 문서가 기준인지, 어떤 툴을 호출할 수 있는지, 어떤 경우에 중단해야 하는지를 포함한 운영 환경 전체다. 하네스는 그 환경을 안전하게 반복 실행하게 만드는 장치다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;예를 들어, 플랫폼 팀이 수백 개 저장소의 설정 파일을 새 표준으로 마이그레이션한다고 해보자. 에이전트는 저장소 구조를 읽고, 필요한 수정 사항을 판단하고, PR까지 만들 수 있다. 하지만 어떤 저장소를 대상에 포함할지, 얼마나 큰 diff를 허용할지, 반드시 통과해야 할 테스트는 무엇인지, 예외 케이스는 누구에게 넘길지, 실패 시 어떻게 롤백할지를 정해두지 않으면 이 작업은 금방 PR 스팸이 된다. 결국 생산성을 가르는 것은 “더 빨리 쓰는 능력”이 아니라, 그 작동 조건을 &lt;strong&gt;설계하는 능력&lt;/strong&gt;이다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또 하나 드러나는 것은 암묵지의 한계다. 사람은 “이 서비스는 원래 이렇게 다뤄야 한다” 같은 구두 규칙으로도 어떻게든 협업하지만, 에이전트는 그런 문맥을 일관되게 따르지 못한다. 그래서 문서화가 약하고, 기준이 사람마다 다르고, 예외 규칙이 정리돼 있지 않은 조직일수록 에이전트를 붙였을 때 혼란이 더 커진다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 AI Agent의 등장은 “일을 대신 해주는 똑똑한 도구”의 추가가 아니라, 일을 설계 가능한 형태로 바꾸라고 요구하는 변화에 가깝다. 잘 정리된 조직은 레버리지를 얻고, 정리되지 않은 조직은 혼돈이 증폭된다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실무자는 무엇을 세팅해야 하는가?&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;일을 잘게 나누고, 기준을 명시하고, 검증 루프를 설계하기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;그러면 실무자는 무엇부터 해야 할까? 실무자가 가장 먼저 해야 할 일은 자기 일을 어떤 상태 전이의 묶음으로 볼 수 있는지 정의하는 것이다. 말하자면 “내 업무를 API처럼 설명할 수 있는가”가 핵심이다. 입력은 무엇이고, 필요한 맥락은 무엇이며, 출력은 어떤 형식이어야 하고, 어느 조건에서 실패로 간주해야 하는지 설명할 수 있어야 한다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이때 일을 나누는 기준은 조직도나 직무명이 아니라, 가역성과 관측 가능성이다. 되돌리기 쉽고 결과를 확인하기 쉬운 일은 에이전트에게 많이 맡길 수 있다. 예를 들어, 포맷팅, 테스트 코드 초안 작성, 규칙 기반 리팩토링, 문서 정리 같은 작업은 비교적 안전하다. 반대로 되돌리기 어렵거나 결과를 바로 검증하기 어려운 일, 예컨대 운영 환경 설정 변경, 고객 커뮤니케이션의 최종 발송, 보안 정책 예외 승인 같은 일은 반드시 사람 승인이나 추가 검증이 필요하다. 문제는 많은 팀이 이 구분 없이 “일단 붙여보자”는 식으로 접근한다는 점이다. 그러면 자동화는 늘어나는데 신뢰는 쌓이지 않는다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;우리가 사람들로 이루어진 조직에서 일을 할 때 생각해보면 팀장과 팀원이 있을 때 처음에 팀장이 일을 받아온다. 팀장은 팀원들의 업무 이해도나 숙련도를 종합적으로 판단해서 업무를 분배하고 기간을 조율한다. 그러면 팀원들은 그 업무를 받아서 수행하고 중간중간 팀장은 팀원들이 막히는 영역을 같이 해결해 준다. 그렇게 팀원들이 각자에게 주어진 업무를 완료하면 팀장은 종합해서 본인의 상사에게 보고한다. 이러한 흐름을 팀장 = 실무자, 팀원 = 에이전트가 하는 것이라고 생각하면 이해가 쉬울 것이다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;기준을 명시하는 것도 중요하다. 대부분의 실패는 에이전트가 멍청해서 생기지 않는다. 성공 조건이 애매해서 생긴다. “좋은 코드로 바꿔줘”는 지시가 아니다. 성능 회귀가 없어야 하는지, 공개 API 호환성을 유지해야 하는지, 마이그레이션 비용을 최소화해야 하는지, 테스트 커버리지를 유지해야 하는지, 로깅 정책을 따라야 하는지가 빠져 있다면 에이전트는 결국 가장 손쉬운 지역 최적화로 흘러간다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;예를 들어, PR 리뷰 에이전트를 생각해 보자. 많은 팀이 이런 시도를 한다. 그런데 대개 초기에 받는 평가는 비슷하다. “말은 많은데 도움이 안 된다.” 이유는 간단하다. 리뷰 기준이 없기 때문이다. 스타일 잔소리를 할지, 동시성 문제를 볼지, 데이터 무결성 리스크를 볼지, API 변경의 파급 범위를 볼지 기준이 없으면 에이전트는 가장 표면적인 문제만 건드린다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반대로 리뷰 기준을 “보안, 동시성, 마이그레이션 리스크, 외부 인터페이스 영향, 테스트 누락” 같은 축으로 명시하고, 각 축마다 어떤 근거를 제시해야 하는지 정해두면 에이전트의 품질은 급격히 달라진다. 중요한 것은 답변의 문장력이 아니라, 판단의 프레임이 구조화되어 있는지다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3752/image1.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, 나노 바나나&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;검증 루프는 더 중요하다. 여기서 많은 팀이 흔히 빠지는 함정이 있다. 같은 모델에게 “다시 확인해봐”라고 시키는 것을 검증이라고 착각하는 것이다. 하지만 자기 자신에게 채점하게 하는 것은 검증이라기보다 자기합리화에 가깝다. 좋은 검증 루프는 생성기와 독립적이어야 한다. 정적 분석기, 테스트 스위트, 샌드박스 실행, 시뮬레이션, 스키마 검증, 정책 룰 엔진, 휴먼 리뷰처럼 다른 종류의 체크포인트가 필요하다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;장애 대응에서도 이 차이는 분명하게 드러난다. 에이전트에게 “장애 원인을 찾아봐”라고 하면 로그를 읽고, 최근 배포를 찾고, 메트릭 변화를 요약하고, 가능한 가설을 정리하는 데는 꽤 유용하다. 하지만 바로 롤백이나 설정 변경까지 맡기면 위험해진다. 잘 되는 팀은 런북을 서술형 문서가 아니라 의사결정 트리처럼 관리한다. 어떤 증상이 보이면 어떤 증거를 먼저 수집하고, 어떤 조건이 충족될 때만 롤백 후보를 제안하며, 어느 선을 넘으면 반드시 당직자가 승인하게 할지를 명시한다. 이 구조 안에서 에이전트는 “판단의 대체자”가 아니라 “관찰과 정리의 가속기”가 된다. 바로 이 지점이 실무적이다. 좋은 팀은 에이전트에게 자율성을 주기 전에, 먼저 실패 반경을 줄인다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또 하나의 실무 포인트는 &lt;strong&gt;컨텍스트를 덜어내는 능력&lt;/strong&gt;이다. 많은 사람이 컨텍스트 엔지니어링을 “관련 자료를 최대한 많이 넣는 일”로 이해한다. 하지만 실제로는 반대다. 많이 넣는 것보다, 충돌하지 않게 넣는 것이 어렵다. 낡은 문서와 최신 정책이 함께 들어가 있고, 예외 규칙이 본문 어딘가에 buried 되어 있고, 동일한 개념이 팀마다 다른 이름으로 쓰이면 에이전트는 높은 확률로 그럴듯한 혼합물을 만든다. 실무자가 해야 할 일은 지식을 더 많이 넣는 것이 아니라, 기준이 되는 지식을 더 작고 더 선명하게 만드는 일이다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 글을 쓰는 시점(2026년 4월)에서 Claude Opus 4.7 모델이 가장 최신인데, 한 번에 1M 토큰까지 컨텍스트를 기억할 수 있다. 그런데 우리가 점점 복잡한 작업을 하다 보면 이 한계치는 생각보다 금방 도달하게 된다. 그렇기 때문에 컨텍스트를 1M 이내에서 적절하게 넣고, 요약하고, 새로운 대화로 옮겨서 이어가는 등의 전략을 사용하는 것이 중요하다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;요약하면, 개인이 에이전트 시대에 세팅해야 할 역량은 세 가지다. 일을 잘게 나누는 분해력, 성공과 실패를 명시하는 명세력, 결과를 믿을 수 있게 만드는 검증 설계력이다. 프롬프트 감각은 그 다음 문제다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;팀과 리더는 무엇을 설계해야 하는가?&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;도입보다 중요한 공통 설정과 운영 체계&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;개인이 AI를 잘 쓴다고 조직 전체가 잘 굴러가지는 않는다. 에이전트가 팀 단위로 들어오는 순간, 누구의 문서를 기준으로 삼을지, 어떤 데이터에 접근할지, 잘못된 행동을 누가 감시할지 같은 운영 문제가 함께 생긴다. 이걸 개인 재량에 맡기면 팀은 금방 “AI를 쓰는 사람”과 “AI가 만든 결과를 뒷수습하는 사람”으로 갈라진다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 리더가 가장 먼저 설계해야 할 것은 &lt;strong&gt;공통 컨텍스트 레이어&lt;/strong&gt;다. 용어 사전, 시스템 경계, API 계약, 운영 정책, 보안 규칙, 예외 승인 절차가 흩어진 위키 문서로 존재해서는 안 된다. 에이전트가 읽을 수 있고 사람도 신뢰할 수 있는 형태로 정리돼야 한다. 결국 조직의 AI 경쟁력은 모델보다 내부 문서의 정합성에서 나온다. 어떤 문서가 최신인지, 같은 개념이 팀마다 다른 이름으로 불리지 않는지, 런북과 실제 운영 상태가 어긋나지 않는지가 기본기이자 레버리지다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다음은 &lt;strong&gt;권한과 책임의 경계&lt;/strong&gt;다. 무엇을 보여줄지보다 무엇을 못 하게 할지가 더 중요하다. 읽기와 쓰기 권한은 분리돼야 하고, 운영 변경은 샌드박스나 드라이런을 거쳐야 하며, 민감한 액션에는 승인 단계가 필요하다. 에이전트 운영은 똑똑함의 문제가 아니라 통제의 문제다. 실패는 종종 모델 한계보다 권한 설계 부실에서 나온다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;기존에 많은 팀에서 사용하는 RBAC(Rule Based Access Control)이나 OAuth 같은 인증, 권한 방식은 사람에게 적합한 방식이다. 예를 들어, CTO가 RBAC에서 최고 관리자 권한을 가지고 있어서 깃헙 레포지토리를 지우거나, 프로덕션 DB를 수정할 수 있다고 하더라도 사람은 그 행동을 일반적인 경우에 하지 않는다. 왜냐하면 그 행동이 위험하고 문제를 일으킬 수 있다는 것을 알기 때문이다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 에이전트는 최고 관리자 권한이 있다면 마음대로 레포지토리를 지우거나 프로덕션 DB 테이블을 수정할지도 모른다. 따라서 이러한 기존의 인증, 권한 방식도 에이전트 기반 워크플로에서는 다른 대안을 찾을 필요가 있다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;평가 체계&lt;/strong&gt;도 필수다. 좋은 팀은 프롬프트보다 평가 셋을 공유한다. 어떤 요청에 어떤 응답이 나와야 하는지, 어떤 행동은 금지인지, 과거에 어디서 실패했는지를 축적한다. 이건 품질 관리가 아니라 회귀 테스트에 가깝다. 예를 들어 보안 취약점 triage를 자동화할 때 자산 중요도 기준, 예외 승인 규칙, 에스컬레이션 정책이 통일돼 있지 않으면 에이전트는 금방 신뢰를 잃는다. 반대로 이 기준들이 정리돼 있으면 업무량을 실제로 줄일 수 있다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;리더가 봐야 할 지표도 달라져야 한다. “몇 명이 AI를 쓰는가”보다, 에이전트 결과의 채택률, 수정 시간, 재오픈율, 롤백률, 리뷰 부담이 줄었는지를 봐야 한다. 팀과 리더의 역할은 AI를 도입하는 것이 아니라, AI가 들어와도 조직이 무너지지 않게 공통 설정과 운영 체계를 만드는 데 있다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;결국 살아남는 사람의 공통점&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;도구 사용자가 아니라 협업 환경 설계자&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;에이전트 시대에 오래 살아남는 사람은 AI를 가장 자주 쓰는 사람이 아니다. 오히려 AI와 사람이 함께 일할 때 어디서 마찰이 생기고, 어디서 오류가 커지며, 무엇을 미리 구조화해야 하는지 아는 사람이다. 이들은 &lt;strong&gt;도구 사용자가 아니라 협업 환경 설계자&lt;/strong&gt;에 가깝다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이런 사람들은 암묵지를 외부화한다. 자기만 아는 요령을 체크리스트, 예시, 금지 규칙으로 바꾼다. 예전에는 “감으로 안다”가 강점이었다면, 이제는 “그 감을 구조로 바꾼다”가 더 큰 강점이 된다. 또한 일을 설명할 때 자연어의 모호함에 기대지 않는다. 입력과 출력, 예외와 중단 조건, 책임이 넘어가는 지점을 분명히 한다. 에이전트를 잘 다루는 사람은 프롬프트 장인이 아니라 인터페이스 설계자다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이들은 복구 가능성도 중시한다. 에이전트가 실수하지 않게 만드는 것만큼, 실수했을 때 빨리 되돌릴 수 있게 만드는 것을 중요하게 본다. 드라이런, 샌드박스, 작은 배치, canary, 롤백 스크립트, 승인 게이트에 집착하는 이유다. 에이전트 시대의 유능함은 정답을 많이 만드는 능력보다 오답의 비용을 낮추는 능력에 더 가깝다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반대로 도태되기 쉬운 사람은 AI를 검색창의 연장선으로만 보고, 맥락 없는 결과물을 대량으로 만드는 데 만족하는 사람이다. “모델이 더 좋아지면 해결될 문제”라고 믿으며 기준과 운영 설계를 미루는 태도도 마찬가지다. 시간이 갈수록 커지는 것은 결과물의 양이 아니라 주변 사람들의 검토 비용이다. 결국 살아남는 사람은 AI를 잘 쓰는 사람이 아니라, AI가 잘 일할 수 있는 환경을 만드는 사람이다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;에이전트 시대의 경쟁력은 기술 이해가 아니라, 일의 방식을 재설계하는 능력이다. 모델 이름을 많이 아는 것, 프롬프트를 그럴듯하게 쓰는 것, 최신 기능을 빨리 시험해 보는 것만으로는 오래 가지 않는다. 진짜 차이는 일을 얼마나 기계가 처리할 수 있는 단위로 나누고, 얼마나 명확한 기준으로 정의하며, 얼마나 튼튼한 검증 루프로 감쌌는지에서 나온다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;에이전트는 엔지니어를 대체하기보다, 엔지니어링이 얼마나 구조화돼 있는지를 시험한다. 기준이 사람 머릿속에만 있고, 예외가 문서화되지 않았고, 검증이 개인의 감각에 의존하던 조직은 에이전트를 붙일수록 불안정해진다. 반대로 일의 경계가 분명하고, 실패가 기록되며, 시스템이 복구 가능하게 설계된 조직은 에이전트를 통해 폭발적인 레버리지를 얻는다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 지금 필요한 질문은 “AI를 쓸 것인가 말 것인가”가 아니다. “우리의 일은 에이전트와 협업 가능한 구조인가”다. 이 질문에 제대로 답할 수 있는 사람, 그리고 그 구조를 실제로 설계할 수 있는 사람이 결국 살아남는다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;에이전트 시대에 강한 사람은 도구를 능숙하게 쓰는 사람이 아니다. 사람과 AI가 함께 일해도 품질과 신뢰가 무너지지 않는 시스템을 만드는 사람이다. 앞으로의 경쟁력은 손이 빠른 사람보다, 기준을 세우는 사람에게 있다. 프롬프트를 잘 쓰는 사람보다, 실패를 설계하는 사람이 오래 남는다. 이 글을 읽는 모든 분들이 에이전트 시대에서 변화에 잘 적응하고 성장할 수 있길 바란다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>스프링 부트(Spring Boot)는 왜 아직도 살아남았을까?</title><link>https://yozm.wishket.com/magazine/detail/3744</link><description>기술 세계는 정말 빨리 바뀝니다. 어제까지 뜨겁던 기술이 몇 년 뒤에는 조용해지고, 또 다른 이름의 프레임워크가 등장합니다. 그래서 백엔드를 처음 공부하는 분들은 종종 이렇게 생각합니다. “스프링은 너무 오래된 거 아닌가?” 저도 처음에는 비슷했습니다. 처음 스프링 프로젝트를 열었을 때 느낀 인상은 솔직히 무겁고, 복잡하고, 파일도 많고, 구조도 딱딱하다는 쪽에 가까웠습니다. 그런데 이상하게도 한국에서 일할 때도 스프링을 봤고, 일본에서 일할 때도 또 스프링을 봤습니다. 더 흥미로웠던 건 단순히 예전부터 쓰던 기술이라서 남아 있는 게 아니라는 점이었습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3744</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;유행은 빨리 바뀌는데, 왜 현장은 아직도 스프링일까요?&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3744/image6.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;기술 세계는 정말 빨리 바뀝니다. 어제까지 뜨겁던 기술이 몇 년 뒤에는 조용해지고, 또 다른 이름의 프레임워크가 등장합니다. 그래서 백엔드를 처음 공부하는 분들은 종종 이렇게 생각합니다. “스프링은 너무 오래된 거 아닌가?” 저도 처음에는 비슷했습니다. 처음 스프링 프로젝트를 열었을 때 느낀 인상은 솔직히 무겁고, 복잡하고, 파일도 많고, 구조도 딱딱하다는 쪽에 가까웠습니다. Controller, Service, Repository, DTO, Entity가 한꺼번에 보이면 괜히 숨이 턱 막히기도 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 이상하게도 한국에서 일할 때도 스프링을 봤고, 일본에서 일할 때도 또 스프링을 봤습니다. 더 흥미로웠던 건 단순히 예전부터 쓰던 기술이라서 남아 있는 게 아니라는 점이었습니다. 회의에서 기술을 고를 때도 “요즘 유행해서”가 아니라 “운영하기 편해서”, “인수인계가 쉬워서”, “기존 시스템과 잘 맞아서”, “장애가 나도 추적이 쉬워서” 같은 이유로 선택되는 장면을 자주 봤습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;한 번은 일본 프로젝트에서 이런 말을 들은 적이 있습니다. “새로운 기술도 좋지만, 이건 5년 뒤에 다른 사람이 들어와도 이해할 수 있어야 합니다.” 그 말을 듣고 조금 뜨끔했습니다. 저는 기술을 볼 때 얼마나 새롭고 멋진가를 먼저 봤는데, 현장은 얼마나 오래 버틸 수 있는가를 먼저 보고 있었기 때문입니다. 그때부터 스프링을 보는 눈이 조금 달라졌습니다. 이건 단순히 오래된 기술이 아니라, 오래 굴려도 쉽게 무너지지 않도록 정리된 구조일 수 있겠다고 느꼈습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 이번 글에서는 스프링 부트 아키텍처를 교과서처럼 설명하기보다, 왜 이 구조가 한국과 일본의 실무 현장에서 여전히 살아남고 있는지 이야기해 보려고 합니다. 중요한 건 “옛날 기술인가?”가 아니라 “왜 아직도 선택되는가?”였기 때문입니다.&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;처음 보면 복잡한데, 왜 이 구조를 계속 쓸까요?&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3744/image4.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;스프링 부트를 처음 배우면 가장 먼저 드는 생각은 아마 이것일 겁니다. “왜 이렇게 나눠놨지?” 간단한 기능 하나를 만들 뿐인데도 Controller가 생기고, Service가 생기고, Repository가 생깁니다. 거기에 Entity와 DTO까지 붙으면 작은 기능 하나가 제법 큰 구조처럼 보입니다. 처음 배우는 입장에서는 솔직히 부담스럽습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 흐름만 놓고 보면 구조 자체는 단순합니다. 사용자가 요청을 보내면 Controller가 받고, 비즈니스 로직은 Service가 처리하고, 데이터 저장과 조회는 Repository가 맡습니다. 이걸 어렵게 느끼게 만드는 건 구조의 개수보다도 아직 역할 감각이 익숙하지 않기 때문입니다. 어떤 코드는 어디에 두는 게 맞는지 감이 안 잡히니까 모든 레이어가 다 비슷해 보이고, 그래서 괜히 복잡해 보이는 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 프로젝트가 조금만 커지면 이 분리가 왜 필요한지 서서히 보이기 시작합니다. 회원가입 기능 하나만 생각해 봐도 입력값 확인, 중복 검사, 암호화, 저장 로직이 전부 한 파일에 들어가면 처음엔 빨라도 나중엔 수정이 무섭습니다. 결국 스프링의 계층형 구조는 멋있게 나누기 위한 구조가 아니라, 나중에 덜 엉키기 위해 미리 나눠두는 구조에 가깝습니다. 저는 예전엔 이걸 정석이라서 따라야 하는 규칙처럼 받아들였는데, 실무를 겪고 나니 헷갈림을 줄이기 위한 약속에 더 가깝다는 걸 알게 됐습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;br&gt;&lt;strong&gt;혼자 만들 때는 귀찮은데, 팀 개발에서는 왜 갑자기 강해질까요?&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3744/image5.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;개인 프로젝트에서는 스프링 구조가 꽤 답답하게 느껴질 수 있습니다. 간단한 API 하나를 추가하려고 해도 파일이 늘어나고, 손이 많이 갑니다. “그냥 한 파일에 다 넣으면 더 빠른데?”라는 생각이 드는 것도 이상한 일이 아닙니다. 그런데 사람이 늘어나는 순간 상황이 완전히 달라집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;프론트엔드 개발자가 요청 형식을 바꿔 달라고 할 수 있고, 기획자가 조건을 수정할 수도 있고, DB 구조가 바뀌는 일도 생깁니다. 이때 코드가 한곳에 뒤엉켜 있으면 수정 범위를 찾는 것부터 오래 걸립니다. 반대로 계층이 나뉘어 있으면 길을 잡기가 쉽습니다. 요청과 응답 모양이 바뀌면 Controller를 보면 되고, 업무 규칙이 바뀌면 Service를 보면 되고, 저장 방식이 바뀌면 Repository를 보면 됩니다. 이건 단순히 코드 스타일의 문제가 아니라 협업 비용이 줄어드는 문제입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;누가 어느 부분을 맡아야 하는지가 보이고, 서로 건드리는 범위가 줄고, 변경 영향도 파악이 쉬워집니다. 팀 프로젝트에서 이 차이는 생각보다 엄청 큽니다. 저는 일본 프로젝트에서 이 장면을 꽤 자주 봤습니다. 설계서가 먼저 나오고, 담당이 나뉘고, 테스트 담당이 따로 붙는 흐름이 많았는데, 구조가 명확하면 문서와 코드가 서로 잘 맞아떨어졌습니다. 반대로 구조가 애매하면 설명도 길어지고, 인수인계도 어려워졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;중간에 투입된 개발자 한 분이 프로젝트를 보더니 “아, 흐름이 보이네요”라고 말한 적이 있었습니다. 그 한마디가 오래 남았습니다. 좋은 구조는 지금 쓰는 사람보다 다음에 들어올 사람이 길을 잃지 않게 해주는 구조라는 뜻처럼 들렸기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;br&gt;&lt;strong&gt;한국에서 스프링이 쉽게 사라지지 않는 이유&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3744/image1.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;한국에서 스프링이 여전히 강한 이유를 “익숙해서”라고만 설명하면 조금 부족합니다. 익숙함은 분명한 이유 중 하나지만, 그것만으로 이렇게 오래 버티기는 어렵습니다. 한국의 실무 환경에서는 여전히 안정성과 표준화가 중요한 영역이 많습니다. 공공, 대기업, SI, 장기 운영 시스템처럼 실패 비용이 큰 프로젝트일수록 “새롭다”보다 “검증됐다”가 더 중요해집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실제 프로젝트에서 자주 나오는 질문도 비슷합니다. 정말 안정적으로 돌아가는가, 기존 시스템과 잘 붙는가, 사람을 구하기 쉬운가, 문서와 사례가 충분한가. 이 기준에서 보면 스프링은 꽤 강합니다. 이미 많은 시스템이 Java와 스프링 기반으로 운영되고 있고, 관련 경험을 가진 개발자도 많습니다. 교육 자료도 많고, 문제 해결 사례도 풍부합니다. 즉, 기술 하나만 있는 게 아니라 운영 경험까지 같이 쌓여 있는 기술입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기에 레거시 시스템도 큰 이유가 됩니다. 이미 잘 돌아가고 있는 시스템이 스프링 기반이라면, 그걸 완전히 다른 기술로 갈아타는 건 생각보다 큰일입니다. 비용도 들고, 리스크도 크고, 연동 문제도 따라옵니다. 그래서 실무에서는 전부 새로 만드는 것보다 기존 구조를 유지하면서 확장하는 쪽이 더 현실적인 선택이 됩니다. 저는 이걸 한국 실무의 특징 중 하나라고 느꼈습니다. 새 기술을 싫어해서가 아니라, 망가지지 않는 기술을 더 높게 평가하는 분위기가 있다는 점입니다. 스프링은 바로 그 기준에서 오래 점수를 받아온 기술이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;br&gt;&lt;strong&gt;일본에서는 왜 더 잘 맞아 보였을까요?&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3744/image7.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;일본에도 스프링이 자주 보입니다. 다만 제가 현장에서 느낀 이유는 한국과 조금 결이 달랐습니다. 한국이 검증된 운영 경험을 중요하게 본다면, 일본은 거기에 더해 예측 가능한 절차를 아주 중요하게 보는 느낌이 있었습니다. 특히 문서 기반 개발 문화가 강한 현장일수록 이 차이가 더 크게 보였습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;일본에서는 설계서가 먼저 나오고, 그 설계서를 기준으로 개발이 이어지는 경우가 많았습니다. 이때 Controller, Service, Repository처럼 역할이 구분된 구조는 문서와 코드가 잘 맞습니다. 요청은 어디서 받고, 규칙은 어디서 처리하고, 저장은 어디서 하는지가 비교적 명확하기 때문입니다. 반대로 구조가 너무 자유롭거나 작성자 취향이 강하면 문서와 실제 구현 사이가 멀어집니다. 그러면 개발도 어렵지만 유지보수는 더 어려워집니다. 결국 설명 비용이 커지고, 인수인계 비용도 커집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;일본에서 긴 프로젝트를 많이 본 것도 인상적이었습니다. 1년 안에 끝나는 일보다 3년, 5년 이상 이어지는 프로젝트가 적지 않았고, 그동안 담당자가 바뀌는 일도 많았습니다. 이런 환경에서는 지금 만든 사람이 제일 잘 아는 구조보다 다음 사람이 빨리 파악할 수 있는 구조가 훨씬 중요합니다. 그 점에서 스프링은 일본 실무와 잘 맞았습니다. 화려하진 않지만 익숙하고, 설명하기 쉽고, 예측하기 좋기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;처음 보는 프로젝트의 백엔드 흐름을 따라가야 했던 적이 있었는데, 구조가 익숙해서 생각보다 빨리 읽혔습니다. 그때 좋은 구조는 천재적인 구조가 아니라 낯선 사람도 들어올 수 있는 구조일 수 있겠구나 싶었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;br&gt;&lt;strong&gt;실무에서 느낀 진짜 장점은 ‘멋짐’보다 ‘안정감’&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3744/image8.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;스프링 부트의 장점을 말할 때 흔히 생산성, 생태계, 확장성을 이야기합니다. 전부 맞는 말입니다. 하지만 현업에서 오래 보다 보면 조금 더 현실적인 장점이 눈에 들어옵니다. 첫 번째는 길을 잃지 않게 해준다는 점입니다. 프로젝트가 커질수록 새 기능을 만드는 시간보다 기존 기능을 수정하거나 버그를 추적하는 시간이 더 길어집니다. 이때 구조가 정리되어 있으면 어디서부터 봐야 할지가 보입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;두 번째는 팀의 대화가 쉬워진다는 점입니다. “이건 Controller에서 처리할까요?”, “이건 Service 책임 같아요”, “DB 쪽은 Repository에서 보면 되겠네요” 같은 말이 통하기 시작하면 회의가 짧아지고 오해도 줄어듭니다. 세 번째는 시간이 지날수록 진가가 드러난다는 점입니다. 신규 프로젝트는 사실 어떤 기술로도 그럴듯하게 만들 수 있습니다. 문제는 2년 뒤, 3년 뒤입니다. 요구사항이 쌓이고, 예외 처리가 늘고, 담당자가 바뀌기 시작하면 구조의 체력이 드러납니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;제가 봤던 프로젝트 중에는 처음엔 정말 세련돼 보였지만, 시간이 지나자 작성자만 이해하는 코드가 되어버린 경우도 있었습니다. 반대로 아주 화려하지는 않아도 구조가 일정해서 오래 읽히는 프로젝트도 있었습니다. 그 경험 이후로는 저도 코드의 첫인상보다 “이거 3년 뒤에도 읽힐까?”를 더 자주 보게 됐습니다. 어쩌면 실무에서 중요한 건 가장 멋진 기술이 아니라 가장 덜 놀라게 하는 기술일지도 모르겠습니다. 스프링은 꽤 자주 그 역할을 해줬습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;br&gt;&lt;strong&gt;단점은 처음 배울 때 지치기 쉽다는 것&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3744/image3.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기까지 보면 스프링이 거의 정답처럼 느껴질 수도 있습니다. 하지만 당연히 단점도 있습니다. 그리고 그 단점은 특히 주니어에게 꽤 크게 다가옵니다. 가장 먼저 느끼는 건 무게감입니다. 작은 기능 하나에도 구조가 커지고, 어노테이션(Annotation)도 많고, 설정도 많습니다. 화면에서 바로 결과가 보이는 프론트엔드와 달리 처음에는 손이 많이 가는데 성과는 천천히 보입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;코드가 장황해지기 쉽다는 점도 있습니다. 정석만 의식하다 보면 간단한 기능까지 과하게 분리하게 되고, 오히려 읽기 어려워지는 경우도 있습니다. 구조가 있다고 해서 자동으로 좋은 코드가 되는 건 아닙니다. 또 많이 겪는 문제가 Service 비대화입니다. 처음에는 Controller를 가볍게 만들겠다고 시작했는데, 나중에는 모든 조건문과 예외 처리, 외부 API 호출이 Service 하나에 몰립니다. 결국 복잡함이 사라진 게 아니라 자리를 옮긴 것뿐인데도 초반에는 이걸 잘 못 느끼기도 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;저 역시 처음에는 Controller, Service, Repository를 그냥 외웠습니다. 그런데 어느 순간 제 코드에서 “왜 이 로직이 여기에 있지?”라는 질문에 스스로 답을 못 하겠더라고요. 그때부터 생각이 조금씩 바뀌었습니다. 스프링은 외울 구조가 아니라, 왜 나누는지를 이해해야 하는 구조였습니다. 그걸 깨닫고 나서야 조금 덜 답답해졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;br&gt;&lt;strong&gt;주니어 개발자라면 이 다섯 가지만 꼭 기억하기&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3744/image2.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;스프링 부트를 공부하거나 실무에서 막 쓰기 시작한 분들에게는 거창한 원칙보다 바로 적용할 수 있는 감각이 더 중요합니다. 제가 실제로 부딪히며 느낀 기준을 다섯 가지로 정리해 보겠습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;첫째, 처음부터 완벽한 구조를 만들려고 하지 않아도 됩니다. 작은 프로젝트에서는 단순함이 더 중요하고, 나중에 분리할 수 있게만 작성해 두면 충분합니다.&lt;/li&gt;&lt;li&gt;둘째, Controller는 최대한 얇게 두는 편이 좋습니다. 요청받고 응답을 내보내는 역할에 집중시키면 흐름이 훨씬 깔끔해집니다.&lt;/li&gt;&lt;li&gt;셋째, Service에 모든 걸 몰아넣지 마세요. 정말 흔한 실수이고, 로직이 커지기 시작하면 기능별로 쪼개고 책임을 다시 나누는 습관이 필요합니다.&lt;/li&gt;&lt;li&gt;넷째, Repository는 DB 접근에 집중시키는 게 좋습니다. 비즈니스 판단까지 Repository에 들어가기 시작하면 나중에 로직 추적이 힘들어집니다.&lt;/li&gt;&lt;li&gt;다섯째, 디버깅할 때는 요청 흐름을 손으로 적어보세요. 요청이 어디로 들어와서 어디를 거쳐 저장되는지 그려보면, 머릿속에서는 복잡하던 것도 생각보다 단순하게 보입니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 다섯 가지는 대단한 비법은 아닙니다. 하지만 실무에서는 이런 기본기가 오래 갑니다. 특히 스프링 같은 구조형 프레임워크는 많이 안다고 잘 쓰는 게 아니라, 책임을 헷갈리지 않게 둘 줄 알아야 잘 쓴다고 느꼈습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;br&gt;&lt;strong&gt;그래서 지금도 배워야 할까요?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;제 대답은 분명합니다. 여전히 배울 가치가 충분합니다. 그 이유는 단순히 아직도 많이 쓰이기 때문만은 아닙니다. 더 중요한 이유는 스프링을 배우는 과정에서 백엔드의 기본 감각을 함께 익히게 되기 때문입니다. 요청 처리와 비즈니스 로직, 데이터 접근을 어떻게 나눌지 고민하는 과정은 특정 프레임워크를 넘어 계속 남습니다. 나중에 다른 언어를 쓰더라도, 다른 구조를 만나더라도 이 감각은 분명히 도움이 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;처음에는 누구나 “어떻게 빨리 만들지?”를 먼저 생각합니다. 그런데 어느 순간부터는 “이걸 어디에 둬야 나중에 안 힘들지?”, “바뀌면 어디를 수정해야 하지?”를 생각하게 됩니다. 그 질문이 생기기 시작하면 개발자는 조금 달라집니다. 바로 그때부터 단순히 코드를 짜는 사람에서 구조를 고민하는 사람으로 넘어가기 시작합니다. 그래서 저는 스프링 부트를 평생 이것만 써야 하는 기술이라기보다, 백엔드 사고방식을 익히게 해주는 좋은 훈련장에 가깝다고 느꼈습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;br&gt;&lt;strong&gt;중요한 건 최신 기술이냐가 아니라, 왜 선택되는가입니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;스프링 부트는 가장 새롭고, 가장 가볍고, 가장 화려한 기술은 아닐 수 있습니다. 하지만 한국과 일본의 실무 현장에서는 여전히 꽤 현실적인 선택지로 남아 있습니다. 그 이유는 생각보다 단순합니다. 협업하기 좋고, 설명하기 쉽고, 유지보수에 유리하기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;우리는 기술을 볼 때 자주 “최신인가, 오래됐는가”를 먼저 묻습니다. 하지만 실무는 조금 다른 질문을 던집니다. 이걸 오래 굴릴 수 있는가, 누가 들어와도 이해할 수 있는가, 문제가 생겼을 때 빨리 찾을 수 있는가. 그리고 바로 그 질문 앞에서 스프링 부트는 아직 꽤 강합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 지금 스프링을 공부하고 계신다면, 단순히 문법이나 어노테이션을 외우는 데서 멈추지 않으셨으면 합니다. 왜 Controller와 Service를 나누는지, 왜 이 로직을 이 위치에 두는지, 왜 이런 구조가 팀에 유리한지까지 생각해 보면 좋겠습니다. 그 질문에 대한 답을 스스로 설명할 수 있게 되는 순간, 스프링은 외워야 할 기술이 아니라 이해할 수 있는 구조가 됩니다. 그리고 그때부터는 단순히 코드를 쓰는 개발자가 아니라, 기술이 왜 선택되는지를 말할 수 있는 개발자로 한 단계 올라갈 수 있죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;스프링 부트가 아직도 쓰이는 이유는 결국 하나입니다. &lt;strong&gt;낡아서 남은 것이 아니라, 버틸 수 있어서 남았습니다.&lt;/strong&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>AI가 코드 짜는 시대, 버전 관리도 바뀐다 (feat. Entire AI)</title><link>https://yozm.wishket.com/magazine/detail/3741</link><description>요즘 개발에서 진짜 중요한 변화는 “AI가 코드를 얼마나 잘 짜주느냐”는 데에만 있지 않다고 생각합니다. 이제 더 중요한 건, “AI가 만든 결과물을 얼마나 설명할 수 있도록 남기느냐”입니다. 다시 말해, 버전 관리의 대상 자체가 바뀌고 있는 셈이죠. 이번 글에서는 그 변화의 흐름을 제대로 보여주는 서비스 사례인 ‘Entire AI’와 함께, 왜 지금 개발자들에게는 ‘코드’보다 ‘맥락’을 관리하는 능력이 더 중요해지고 있는지 이야기해보려 합니다.</description><guid>https://yozm.wishket.com/magazine/detail/3741</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3741/image1.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Gemini로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;예전에는 누가 작성한 코드인지를 알면, 왜 그렇게 짰는지도 대충 감을 잡을 수 있었습니다. 혹시 확실하지 않다 해도 직접 타이핑한 사람이 있었기에 그 사람에게 맥락을 물어볼 수라도 있었습니다. 그런데 지금은 다릅니다. AI가 순식간에 만들어낸 결과물 앞에서 우리는 점점 더 자주, “이거 대체 왜 이렇게 된 거지?”라는 질문을 하게 되었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Copilot, Cursor, Claude Code 같은 도구 덕분에 초안은 정말 빠르게 만들어집니다. 예전 같으면 반나절은 붙잡고 있어야 했을 작업이 몇 분 만에 끝나기도 하죠. 생산성만 놓고 보면 분명 놀라운 변화입니다. 그런데 이상하게도 실무는 마냥 편해지지 않았습니다. 코드는 빠르게 늘어나지만, 그 코드가 어떤 판단과 시도를 거쳐 여기까지 왔는지는 오히려 더 흐려졌기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;문제는 바로 그 지점에서 시작됩니다. 실무에서는 코드를 빠르게 만드는 것보다, 그 코드를 팀이 이해하고 리뷰하며 유지보수할 수 있게 만드는 일이 훨씬 더 중요하거든요. 특히 AI가 개입한 작업은 결과물만으로는 설명이 되지 않는 경우가 많습니다. 어떤 프롬프트에서 시작했는지, 중간에 어떤 선택지를 버렸는지, 어디까지가 에이전트의 판단이고 어디서부터 사람이 개입했는지 알 수 없다면, 나중에 장애가 나거나 인수인계가 필요할 때 곧바로 골치 아픈 상황이 벌어집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;저는 그래서 요즘 개발에서 진짜 중요한 변화는 “AI가 코드를 얼마나 잘 짜주느냐”는 데에만 있지 않다고 생각합니다. 이제 더 중요한 건, “AI가 만든 결과물을 얼마나 설명할 수 있도록 남기느냐”입니다. 다시 말해, 버전 관리의 대상 자체가 바뀌고 있는 셈이죠. 이번 글에서는 그 변화의 흐름을 제대로 보여주는 서비스 사례인 ‘Entire AI’와 함께, 왜 지금 개발자들에게는 ‘코드’보다 ‘맥락’을 관리하는 능력이 더 중요해지고 있는지 이야기해보려 합니다.&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;AI가 코드를 대신 짜주는데, 왜 개발은 더 쉬워지지 않을까&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AI 코딩 도구를 쓰면 확실히 체감되는 변화가 있습니다. 예전 같으면 한참 붙잡고 있어야 했던 작업이 훨씬 빨라졌다는 점이죠. 초안 생성, 테스트 코드 작성, 반복 로직 정리, 간단한 리팩토링까지. 이제 사람이 처음부터 끝까지 손으로 짜기보다, 방향을 잡아주고 결과를 검토하는 느낌에 더 가까워졌습니다. 생산성만 놓고 보면 분명 놀라운 변화입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 이상하게도 실무에서의 개발은 기대만큼 쉬워지지 않았습니다. 오히려 어떤 부분은 더 어려워졌다고 느끼는 분들도 많을 겁니다. 특히 리뷰, 복기, 인수인계 같은 순간에서요. 코드는 빠르게 나왔지만, 정작 그 코드가 어떤 판단과 시도를 거쳐 여기까지 왔는지는 설명하기 어려운 경우가 많아졌기 때문입니다. 이런 코드는 얼핏 보면 잘 돌아가고, 겉으로 보기에도 그럴듯합니다. 그런데 며칠 뒤 다시 보면 낯설게 느껴집니다. “이거 왜 이렇게 했지?”라는 질문이 따라 생깁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AI가 개입한 작업이 기존 작업 방식과 다르기 때문입니다. 프롬프트 몇 개로 방향이 바뀌고, 그 사이에는 여러 시도가 오가다, 그중 일부만 결과물로 남습니다. 결국 Git에는 마지막 코드만 남는데, 정작 중요한 ‘왜 그랬는지’란 정보는 사라지는 경우가 많습니다. 어떤 선택지를 검토했는지, 왜 그 방식이 채택됐는지, 사람은 어디서 개입했고 어디까지가 에이전트의 판단이었는지 같은 맥락 말이죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;문제는 실무에서 정말 중요한 게 바로 그 맥락이라는 점입니다. 개발은 단순히 코드를 생성하는 일로 끝나지 않습니다. 팀원이 코드를 리뷰해야 하고, 나중에는 다른 사람이 이어받아야 하며, 장애가 나면 다시 거슬러 올라가 원인을 파악해야 하죠. 그대신 이때 과정이 빠진 결과물만 덩그러니 남아 있다면, 코드를 읽는 일이 아니라 의도를 추리하는 일이 되어버립니다. 생산성은 올라갔지만, 팀 전체의 이해 비용은 오히려 커지는 셈입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;바로 이 지점에서 새로운 문제의식이 등장합니다. AI가 만든 결과물 자체보다, 그 결과물이 만들어진 흐름과 맥락을 함께 남겨야 한다는 문제의식이죠. 결국 지금 개발이 더 쉬워지지 않는 이유는 AI가 코드를 못 짜서가 아니라, 코드 뒤에 있던 맥락이 너무 쉽게 사라지기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;이제 병목은 ‘생성’이 아니라 ‘맥락 관리’입니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;많은 개발자가 AI 코딩 도구를 이야기할 때, 여전히 “얼마나 결과를 잘 만들어주느냐”에 초점을 맞춥니다. 물론 중요한 부분입니다. 예전보다 훨씬 빠르게 초안을 만들고, 반복 작업도 크게 줄었기 때문이죠. 그런데 실무에서 진짜 시간을 잡아먹는 구간은 생성이 끝난 다음입니다. 누군가는 그 코드를 리뷰해야 하고, 또 누군가는 이어받아 수정해야 합니다. 문제가 생기면 다시 거슬러 올라가 원인을 찾아야 할 때도 있죠. 결국 팀 단위로 일이 돌아가는 순간부터 중요한 것은 코드 그 자체보다, 그 코드가 어떤 맥락에서 나왔는가입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서 병목이 생깁니다. AI는 코드를 빠르게 만들어내지만, 그 과정은 휘발됩니다. 프롬프트를 어떻게 줬는지, 어떤 방향으로 몇 번 수정했는지, 중간에 어떤 선택지를 검토했다가 버렸는지, 어디서부터 사람의 판단이 들어갔는지 같은 정보는 대부분 사라지기 쉽습니다. 결과물만 남고 과정은 사라지는 구조인 셈이죠. 그러다 보니 PR을 열어도 난감한 때가 있습니다. 변경량은 많은데 왜 이런 설계를 택했는지 설명이 없고, 리뷰어는 코드만 붙잡고 의도를 역추적해야 합니다. 생성 속도는 빨라졌지만, 리뷰 속도는 오히려 더 느려지는 이유가 바로 여기에 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;예전에 코드 리뷰는 비교적 단순했습니다. 사람이 직접 짠 코드라면, 최소한 작성자가 어떤 생각으로 접근했는지 대화로 빠르게 되돌릴 수 있었기 때문이죠. 하지만 AI가 깊게 개입한 작업은 다릅니다. 작성자조차 며칠만 지나면 흐름을 모두 기억하지 못하는 경우가 많습니다. “대충 이렇게 하라고 시켰어요” 정도만 남는 경우도 흔하죠. 이런 상태에서는 리뷰가 검토가 아니라 추리에 가까워집니다. 코드 스타일을 보는 것이 아니라 이 변경이 어디서부터 잘못됐는지를 탐정처럼 따라가야 하는 상황이 오는 것이죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;인수인계도 마찬가지입니다. 원래 인수인계가 어려운 이유는 코드가 복잡해서만은 아닙니다. 그 코드 뒤에 있는 판단과 맥락이 충분히 문서화되지 않아서 그렇습니다. AI가 작업 속도를 더 끌어올릴수록 이 문제는 더 커집니다. 팀원 입장에서는 결과물의 양은 갑자기 늘어난 반면, 그 결과물을 이해할 단서는 오히려 줄어들었기 때문입니다. 결국 실무에서는 “생성”보다 “맥락 관리”가 훨씬 더 비용이 큰 일이 되어버립니다. 잘 만든 코드보다, 왜 그렇게 만들었는지를 설명할 수 있는 코드가 더 중요해지는 거죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 저는 지금 개발팀의 핵심 역량이 조금씩 바뀌고 있다고 생각합니다. 예전에는 빠르게 구현하는 사람이 눈에 띄었다면, 이제는 AI가 만든 결과물을 팀이 이해할 수 있는 형태로 정리하고 남기는 사람이 더 중요해지고 있습니다. 맥락을 남기지 못하면 생산성 향상은 개인의 순간적인 속도로 끝나버립니다. 반대로 맥락을 잘 남기면 그 결과물은 팀의 자산이 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;Entire AI는 이 문제를 어떻게 제품으로 풀고 있나&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;새로운 AI 서비스, Entire가 전면에 내세우는 문제의식도 정확히 이 지점에 있습니다. 이제 개발의 병목은 생성이 아니라, 생성 이후의 맥락을 어떻게 다루느냐에 달려 있다는 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Entire는 깃허브의 전 CEO 토마스 돔케(Thomas Domke)가 만든 회사입니다. 2026년 2월 10일 공식 출범 글에서 토마스 돔케는 Entire를 “에이전트 시대의 다음 개발 플랫폼”으로 소개하며, 같은 날 첫 제품으로 Entire CLI를 오픈소스로 공개했습니다. 흥미로운 건 “우리가 더 똑똑한 AI를 만들겠다”가 아니라, 이미 여러 에이전트가 코드를 쏟아내는 현실에서 그 결과물을 어떻게 관리할지 손을 댔다는 점입니다. 그들의 방향은 명확합니다. AI가 만들어낸 코드와 그 맥락을 Git 흐름 안에 붙여놓겠다는 것이었죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;핵심 개념은 &lt;strong&gt;Checkpoints&lt;/strong&gt;입니다. 이 기능은 AI 코딩 세션을 Git 커밋과 연결해 남기는 방식으로 동작합니다. 공식 문서 기준으로 사용자나 에이전트가 &lt;code&gt;git commit&lt;/code&gt;을 실행하면 세션 데이터가 커밋에 붙고, 커밋 메시지에는 &lt;code&gt;Entire-Checkpoint&lt;/code&gt; 트레일러가 추가됩니다. 이어 세션 로그와 메타데이터는 &lt;code&gt;entire/checkpoints/v1&lt;/code&gt; 브랜치에 저장됩니다. 쉽게 말하면 코드 변경만 남기는 게 아니라, 그 변경이 만들어진 대화와 흐름까지 버전 관리의 일부로 삼겠다는 접근입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 구조가 꽤 영리한 이유는 Git 히스토리를 지저분하게 만들지 않기 때문입니다. Entire는 작업 중에는 로컬의 shadow branch에 임시 상태를 잡아두고, 실제로는 사용자가 원래 하던 커밋만 히스토리에 남깁니다. 즉 “도구를 쓰기 위해 새로운 방식으로 일하라”가 아니라, 늘 해오던 Git 워크플로우에 자연스럽게 끼어드는 방식인 셈이죠. 공식 문서에서도 “추가 커밋 없이”, “기존 브랜치에서 안전하게”, “리와인드와 재개를 지원하는” 구조 등을 장점으로 설명합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또 하나 눈에 띄는 건 특정 에이전트 하나에 올인하지 않았다는 점입니다. 현재 공식 문서와 사이트 기준으로 Entire CLI는 Claude Code, Gemini CLI, Cursor, OpenCode, GitHub Copilot CLI를 지원하고, Codex는 프리뷰 상태로 제공됩니다. 자동 캡처가 실패한 세션은 &lt;code&gt;entire attach&lt;/code&gt;로 나중에 연결할 수 있게 해뒀고, 4월에는 직접 원하는 에이전트를 붙일 수 있는 플러그인 방식까지 공개했습니다. 처음부터 “최고의 코딩 에이전트” 경쟁에 들어가기보다 여러 에이전트가 섞여 쓰이는 실제 개발 환경을 전제로 설계한 느낌이 강합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;확장 속도도 꽤 빠릅니다. 3월에는 GitHub Copilot CLI 지원이 추가됐고, 3월 말에는 Codex 프리뷰, Windows 호환성, 플러그인 시스템이 소개됐습니다. 4월에는 Codex 사용 가이드와 외부 에이전트 연결 방식까지 연달아 나왔습니다. 그러니까 Entire는 아직 초기 제품이긴 하지만, 적어도 비전만 존재하는 회사는 아닙니다. 실제로 지금 당장이라도 설치하면 기존 Git 기반 프로젝트에 붙여볼 수 있는 형태로 계속 다듬어지고 있으니까요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;저는 그래서 Entire를 단순한 AI 코딩 도구라기보다, AI 시대에 맞는 새로운 기록 계층을 만들려는 시도로 봅니다. 코드 생성은 이미 충분히 빨라졌습니다. 이제 필요한 건 그 결과물을 팀이 이해하고, 검토하고, 되짚을 수 있게 만드는 장치인데요. Entire가 바로 그 지점을 제품으로 풀어내려는 꽤 본격적인 첫 시도로 보입니다. 아직 정답이라고 단정하긴 이르지만, 최소한 문제를 바라보는 방향만큼은 상당히 정확하다는 생각이 듭니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실제 개발자들은 이 방향을 어떻게 보고 있을까&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;Entire AI가 던진 문제의식은 분명 흥미롭습니다. 그런데 좋은 문제를 짚어 제품을 만드는 일과 시장이 그 제품을 곧바로 받아들이는 건 또 다른 이야기입니다. 실제로 출시 후 몇 달 사이 반응을 보면 평가가 갈립니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;한쪽에서는 “지금 AI 코딩에서 진짜 빠져 있는 조각을 잘 짚었다”는 평가가 나오는 반면 다른 한쪽에서는 “문제는 인정하지만, 이 방식이 얼마나 강력한 해답인지는 아직 모르겠다”는 반응도 있습니다. 저는 이 양면성이 오히려 Entire를 더 흥미롭게 만든다고 봅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;먼저 호의적으로 보는 쪽에서는 Entire가 겨냥한 문제가 정말 현실적이라는 점에 공감합니다. AI가 만들어낸 코드는 점점 늘어나는데, 그 코드가 어떤 프롬프트와 시도, 툴 호출을 거쳐 나왔는지는 쉽게 사라지기 때문입니다. 이런 상황에서 Checkpoints처럼 세션의 흔적을 Git과 함께 남기겠다는 발상은 단순히 “예쁘다”를 넘어 “실무에 필요하다”는 반응을 끌어냅니다. 공식 사이트와 GitHub 저장소 기준으로도, CLI 프로젝트는 빠르게 주목받아온 느낌입니다. 적어도 문제의식 자체에는 많은 개발자가 동의하고 있다는 뜻입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;특히 요즘처럼 여러 에이전트를 섞어 쓰는 환경이 발전하며, 이런 반응이 더 커지고 있습니다. Claude Code로 초안을 만들고, Cursor에서 다듬고, Codex나 Copilot CLI로 보조 작업을 붙이는 흐름이 점점 흔해지고 있기 때문입니다. 그럴수록 팀 입장에서 진짜 필요한 건 “최종 코드가 무엇인가”보다는 “그 코드가 어떤 맥락에서 나왔는가”가 더 중요해질 겁니다. Entire가 출시 직후부터 Codex 지원, 플러그인 시스템, 다양한 CLI 연동을 빠르게 확장한 것도 이런 환경이 실제로 퍼진다는 전제를 반영한 움직임으로 볼 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반대로 회의적인 반응도 만만치 않습니다. 해외 커뮤니티 반응을 보면 가장 많이 나오는 질문은 두 가지 정도입니다. “이게 정말 새로운 해자인가?”, 그리고 “이 문제를 굳이 Entire 같은 별도 레이어로 풀어야 하나?”입니다. 즉, 세션 데이터와 메타데이터를 남기는 아이디어 자체는 이해하지만, 그것이 장기적으로 독립 플랫폼이 될 만큼 큰 가치인지에 대해서는 의문이 간다는 겁니다. 오히려 협업 도구라기보다 나중에 학습용 데이터로 더 가치 있다는 말도 나옵니다. 결국 이들이 짚어낸 문제가 좋은 것과 별개로 그 문제를 가장 잘 푸는 방식인지 아직 모르겠다는 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 회의론도 충분히 이해가 갑니다. 개발자들은 원래 새로운 도구에 쉽게 감동하지 않습니다. 특히 Git, PR, 코드 리뷰처럼 이미 굳어진 습관 위에 무언가를 얹는 제품이라면 더 그렇습니다. ‘좋아 보이는데, 그래서 우리 팀이 진짜 이걸 깔고 쓸까?’라는 질문을 반드시 넘어서야 합니다. 실제로 개인 개발자 차원에서는 흥미로운 실험처럼 보일 수 있어도, 팀 단위 도입으로 넘어가려면 보안, 저장 방식, 운영 부담, 워크플로우 충돌, 실제 리뷰 생산성 개선 같은 훨씬 현실적인 검증이 필요하기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;지금 Entire가 받고 있는 시선은 이쯤 와 있다고 볼 수 있습니다. 물론 저는 이런 반응을 단순히 부정적이라고 보지는 않습니다. 오히려 시장이 “이 문제는 진짜다. 다만 해법은 더 지켜보자”라고 말하고 있는 것에 가깝다고 보입니다. 정말 별로인 제품은 논쟁조차 생기지 않으니까요. 적어도 Entire에 회의적인 쪽도 문제 자체는 인정합니다. 논쟁의 중심이 “문제가 있느냐 없느냐”가 아니라 “이 방식이 그 문제를 풀 수 있느냐”에 있다는 점은 꽤 중요한 신호입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그 때문이라도 이 문제, 그리고 Entire AI를 계속 지켜볼 이유는 있다고 생각합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;앞으로 바뀌는 건 코딩이 아니라 개발팀의 운영 방식일지 모릅니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AI 시대의 개발 변화를 이야기할 때, 대부분 가장 먼저 생산성을 떠올립니다. 얼마나 빨라졌는지, 몇 명이 하던 일을 몇 분 만에 끝내는지, 개발자 수요가 앞으로 얼마나 줄어들지 같은 이야기들이죠. 그런데 저는 진짜 변화가 그런데만 있지는 않다고 생각합니다. 오히려 더 크게 바뀌는 건 개발팀이 일하는 방식, 조금 더 정확히 말하면 결과물에 대한 책임을 나누고 신뢰를 쌓는 방식일 가능성이 큽니다. Entire가 처음부터 Git과 연결된 Checkpoints, 팀 가시성, 검색과 복기 같은 주제를 전면에 둔 것도 같은 맥락으로 읽힙니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;예전에는 코드 작성자와 의사결정자가 거의 같은 사람이었습니다. 누가 만들었는지 알면 왜 그렇게 만들었는지도 대략 따라갈 수 있었죠. 리뷰어도 작성자와 대화하면 빠르게 맥락을 복원할 수 있었고, 인수인계도 “이 부분은 왜 이렇게 구현했는지”를 사람의 기억에 기대어 넘어가는 경우가 많았습니다. 그런데 AI가 깊게 개입하는 순간 이 구조는 달라져야 합니다. 프롬프트를 던진 사람, 중간 결과를 선택한 사람, 최종 머지를 승인한 사람, 이후 운영을 맡는 사람이 서로 달라질 수 있기 때문입니다. 이때부터는 단순히 코드만 남겨서는 책임과 판단을 제대로 설명하기 어려워집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 다시 한 번, 앞으로 중요한 건 “누가 빨리 짰느냐”보다 “누가 설명할 수 있게 남겼느냐”가 될 가능성이 큽니다. AI가 만든 초안을 가져다 쓰는 일 자체는 누구나 할 수 있게 될 것입니다. 하지만 그 결과물을 팀이 이해할 수 있는 형태로 정리하고, 나중에 문제가 생겼을 때 다시 추적할 수 있게 만들고, 리뷰어가 불필요한 추리를 하지 않도록 맥락을 남기는 일은 여전히 사람의 몫입니다. Entire가 제품 차원에서 붙들고 있는 문제도 결국 여기에 있습니다. 코드 생성 경쟁보다, 생성 이후의 기록과 검증, 복기와 감사 가능성에 더 큰 가치를 두고 있는 것이죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 변화는 특히 팀 운영에서 더 크게 다가올 겁니다. 코드 리뷰 방식이 바뀔 수 있고, 온보딩 방식도 달라질 수 있습니다. 예전에는 신입이나 새 팀원이 코드베이스를 읽고 질문하면서 맥락을 익혔다면, 앞으로는 “이 변경이 어떤 세션에서 어떤 판단 끝에 나왔는지”까지 함께 훑는 흐름이 자연스러워질 수 있습니다. 장애 대응도 비슷합니다. 예전에는 커밋 로그와 담당자의 기억을 조합해 원인을 복기했다면, 앞으로는 AI 세션 기록과 결정 흐름까지 함께 보는 방식이 더 익숙해질 수 있죠. 특히 규제 산업과 보안이 중요한 환경에서의 투명성, 팀 단위 검색과 가시성 같은 주제를 반복해서 Entire가 강조하는 이유도 이런 맥락으로 이해할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;저는 Entire가 정말 이러한 문제의 해답이 될지는 아직 모른다고 생각합니다. 실제 팀 도입과 장기적인 경쟁력은 더 지켜봐야 하니까요. 다만 한 가지는 분명해 보입니다. AI가 코드를 쓰는 시대에 버전 관리의 대상은 더 이상 코드만이 아니라는 점입니다. 그리고 그 변화는 생각보다 훨씬 빠르게, 개발자의 손끝이 아니라 개발팀의 운영 방식부터 바꿔놓게 될지도 모릅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그 아래 살아남는 개발자의 기준도 조금씩 바뀔 것 같습니다. 단순히 AI를 잘 쓰는 사람보다, AI와 함께 만든 결과물을 팀의 자산으로 바꿀 수 있는 사람이 더 중요해질 가능성이 큽니다. 설명할 수 있게 만들고, 협업할 수 있게 만들고, 나중에 다시 꺼내 쓸 수 있게 만드는 능력 말입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>소버린 AI와 자체 생태계를 가진 IT 강대국, 러시아를 가다</title><link>https://yozm.wishket.com/magazine/detail/3725</link><description>모스크바의 4월은 계절의 경계가 무색할 만큼 가혹합니다. 저는 작년 이맘때쯤 모든 것이 막혀 있는 이곳 러시아에 주재원으로 처음 넘어왔습니다. 러시아에서는 인터넷이 잘 안되거나, 메신저가 막히는 경우가 참 많습니다. 그뿐만 아니라 우리가 당연하게 여기는 구글의 검색창, 유튜브의 알고리즘, 인스타그램의 피드는 이곳에서 접근할 수 없습니다. 하지만 그 빈자리에 들어선 것은 기술의 퇴보가 아닙니다. 오히려 외부의 간섭 없이 스스로 진화하기 시작한 기묘하고도 강력한 자생적 생태계가 자라나고 있었습니다. 그런 나라에서 개발자로 하루하루를 살아가며 경험한 다양한 것들을 공유하고자 펜을 들었습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3725</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;모스크바의 4월은 계절의 경계가 무색할 만큼 가혹합니다. 저는 작년 이맘때쯤 모든 것이 막혀 있는 이곳 러시아에 주재원으로 처음 넘어왔습니다. 올해의 4월 역시, 눈이 오기도 비가 오기도 하며 많은 사람이 아직 두꺼운 패딩을 입고 다닙니다. 그런 나라에서 개발자로 하루하루를 살아가며 경험한 다양한 것들을 공유하고자 펜을 들었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3725/image7.jpg"&gt;&lt;figcaption&gt;모스크바의 4월 &amp;lt;출처: 작가 촬영&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;러시아에서는 인터넷이 잘 안되거나, 메신저가 막히는 경우가 참 많습니다. 그뿐만 아니라 우리가 당연하게 여기는 구글의 검색창, 유튜브의 알고리즘, 인스타그램의 피드는 이곳에서 접근할 수 없습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 그 빈자리에 들어선 것은 기술의 퇴보가 아닙니다. 오히려 외부의 간섭 없이 스스로 진화하기 시작한 기묘하고도 강력한 자생적 생태계가 자라나고 있었습니다. 러시아 정부의 강력한 지원과 열정이 넘치는 개발자들의 손에서 다양한 IT시스템과 AI 서비스들이 만들어졌습니다. 국제 표준을 따르지는 않지만, 독립국가연합(CIS) 시장을 기반으로 자체 IT 생태계를 추구하며, 결제나 피지컬 AI 부문에서도 강력한 서비스를 가지고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;무엇보다 AI 서비스 분야에서는 얀덱스GPT(YandexGPT), 기가챗(Gigachat) 등 서비스가 활발하게 쓰이고 있으며, 다양한 AI 결합 서비스들도 마찬가지로 나오고 있습니다. 이 모든 변화는 글로벌 외산 AI 시스템 없이 독자적인 개발로 이루어져, 앞으로 이어질 AI 패권 전쟁에서도 러시아는 강력한 경쟁력을 가질 수 있을 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;우리나라 또한 글로벌 서비스 대비 뛰어난 서비스를 가진 영역도 많지만, 열약한 부분도 분명히 있습니다. 러시아의 사례를 발판으로 삼아 한국 또한 독자 개발을 통해 더 강력한 경쟁력을 가질 수 있는 방향으로 갈 수 있으면 좋겠다는 생각이 커졌습니다. 오늘은 그런 이야기를 전해보려고 합니다.&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;1. 구글 없는 모스크바의 아침과 러시아의 IT 생태계&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;러시아가 실리콘밸리 표준을 버리고 독자 노선을 걷게 된 배경에는 생존을 향한 처절한 의지가 자리하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3725/image9.png"&gt;&lt;figcaption&gt;러시아의 주요 BigTech 기업 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;러시아가 글로벌 표준 대신 독자 노선을 택한 이유&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;시작은 서방의 경제 제재였습니다. 그로 인해 글로벌 빅테크 기업들이 하루아침에 서비스를 중단했을 때, 러시아 사회가 직면한 것은 단순한 불편함이 아닌 국가 시스템 전체가 마비될 가능성이었습니다. 러시아는 이 거대한 위기를 기회로 보고 국가 IT 기업에 투자했습니다. 외부 기술에 종속되는 것이 곧 데이터 주권과 국가 안보를 타인에게 양도하는 것임을 뼈저리게 실감한 이들은 자국만의 기술 요새를 쌓기 시작했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이제 모스크바에서 ‘글로벌 표준’은 더 이상 선망의 대상이 아닌 언제든 무기로 돌변할 수 있는 과거의 유물로 취급됩니다. 그 자리를 대신한 것은 러시아산 코드로 촘촘하게 짜인 내수용 소프트웨어들이며, 이들은 빠르게 현지인들의 삶 속에서 떼어낼 수 없는 유기적 결합체가 되었습니다. 얀덱스(Yandex), 카스퍼스키(Kaspersky) 등 이미 글로벌 수준의 앱이 모든 서비스를 제공하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;챗GPT 접근 금지가 불러온 ‘로컬 AI’의 반격&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3725/image10.png"&gt;&lt;figcaption&gt;러시아의 AI &amp;lt;출처: 작가, gemini로 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;오픈AI의 챗GPT를 필두로 한 글로벌 생성형 AI 모델들이 러시아 IP를 차단하자, 러시아인들은 당황하는 대신 자신들의 언어와 문화적 맥락에 최적화된 로컬 AI로 시선을 돌렸습니다. 애초에 영어 중심 사고방식과 서구권의 윤리적 가이드라인이 투영된 글로벌 모델들은 러시아어의 복잡한 굴절과 슬라브 민족 특유의 정서를 담아내는 데 한계가 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반면, 러시아의 얀덱스, 스베르(Sber)가 개발한 모델들은 도스토옙스키와 톨스토이의 문장을 학습하고, 러시아인들만이 이해할 수 있는 역사적 상징과 은유를 이해합니다. 이는 기술적 소외를 극복하는 차원을 넘어 오히려 자국 문화에 가장 적합한 ‘맞춤형 지능’을 소유하게 되는 역설적인 기회를 제공했습니다. 접근 금지라는 장벽이 오히려 러시아만의 독창적인 AI 학습 데이터셋을 구축하는 강력한 동력이 된 셈입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이제 이런 모델은 전 세계가 획일화된 AI 표준을 따라갈 때 러시아만이 가질 수 있는 독보적인 문화적 경쟁력이 되었습니다. 그 어떤 AI보다도 러시아어에 최적화되었으며, 구글 검색이 어려운 러시아 내부 사이트까지 모두 학습의 대상으로 삼아 전체 내용을 아우르는 AI 서비스가 러시아 자국민들에게 제공되고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;우리가 모르는 러시아인들의 필수 앱 리스트&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3725/image4.png"&gt;&lt;figcaption&gt;러시아 필수 앱 목록 &amp;lt;출처: RuStore&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이러한 변화는 스마트폰 홈 화면에서 가장 명확하게 드러납니다. 우리에게 익숙한 앱들은 없지만, 그들이 제공하는 기능은 로컬 슈퍼 앱들이 대신하고 있습니다. 물론 러시아에서도 구글이나 애플의 앱스토어를 이용할 수는 있습니다. 그러나 대부분은 루스토어(RuStore)라는 자국 앱스토어로 앱들을 관리합니다. 또, 러시아에서 필수로 통하는 앱들은 모두 전화번호 하나로 가입하고 관리할 수 있어, 사용 편의성에 있어서는 한국 앱들보다 더 뛰어난 측면도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;러시아의 국민 메신저를 넘어 사회적 소통의 중심이 된 ‘VK’는 이제 SNS 그 이상의 기능을 수행합니다. 메일 서비스에서 시작한 플랫폼 '메일루(Mail.ru)'는 러시아 비즈니스의 혈관 역할을 수행합니다. ‘얀덱스 고(Yandex Go)’란 앱은 택시 호출, 음식 배달, 물류 배송, 심지어는 공과금 결제까지 하나의 앱 안에서 해결하는 거대한 플랫폼으로 성장했습니다. ‘텔레그램(Telegram)’ 역시 단순 메신저의 기능을 넘어 정부 행정 서비스와 금융 채널의 핵심 플랫폼으로 기능하며 러시아의 디지털 주권을 공고히 하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;모두 외부인에게는 낯설고 폐쇄적으로 보일지 모르지만, 이 내수용 앱들은 이미 현지인들의 일상을 완벽하게 지탱할 수 있을 만큼 성숙해졌습니다. 특히 이 모든 앱이 러시아 전화번호 하나로 인증할 수 있으니, 한국이나 미국에서 했던 인증 방식보다 더 편하다고 느끼고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="margin-left:3.2598425196850442pt;text-align:justify;"&gt;&lt;strong&gt;2. 일상을 점령한 러시아표 AI와 핀테크&lt;/strong&gt;&lt;/h3&gt;&lt;p style="margin-left:3.2598425196850442pt;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;알리사(Alisa): 얀덱스가 탄생시킨 러시아판 ‘AI 페르소나’&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3725/image1.png"&gt;&lt;figcaption&gt;Alisa AI &amp;lt;출처: yandex image&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;러시아 AI의 정체성을 가장 상징적으로 보여주는 존재는 얀덱스의 AI 비서 ‘알리사(Alisa)’입니다. 실리콘밸리의 AI 비서들이 기계적이고 가치 중립적인 답변을 내놓는 데 주력하는 것과 달리, 알리사는 마치 살아있는 러시아인처럼 행동합니다. 때때로 고집스럽게 의견을 피력하거나, 러시아 특유의 냉소적인 유머를 섞어 대답하기도 하며 사용자에게 당혹감과 친밀감을 동시에 선사합니다. 이러한 '인격적 페르소나'는 러시아인들에게 단순한 비서 이상의 유대감을 주며 문화적 동질성을 확인시켜 줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한, 알리사는 러시아 내부에 특화된 서비스와 이어집니다. 앱들과의 연계는 자연스러우며, 서비스 속도 역시 자국 내에서 월등히 뛰어납니다. 가격 또한 챗GPT나 제미나이(Gemini)에 대비하여 저렴합니다. 물론 한글 학습량이 절대적으로 부족해 제가 한글을 입력하면 알아듣지 못하는 경우가 많지만, 러시아 자국민만을 놓고 본다면 절대적인 강점을 지닌 AI 서비스임이 틀림없습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="margin-left:-3.826771653543311pt;text-align:justify;"&gt;&lt;strong&gt;미르 페이(Mir Pay): 제재 속에서 꽃피운 독자적 결제 시스템의 생존법&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3725/image8.png"&gt;&lt;figcaption&gt;미르 페이 &amp;lt;출처: yandex image&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;금융 영역에서의 자립은 더욱 극적입니다. 국제 결제망인 SWIFT에서 퇴출당했을 때, 러시아 경제가 순식간에 붕괴할 것이라는 서구권의 예측은 보기 좋게 빗나갔습니다. 러시아는 이미 수년 전부터 준비해 온 독자 결제 시스템 ‘미르(Mir)’를 전면에 내세웠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;요즘 모스크바의 식당이나 지하철역에서 사람들은 비자나 마스터카드 대신 스마트폰의 '미르 페이(Mir Pay)'를 태그합니다. 외부의 금융 압박이 심해질수록 이 시스템은 더욱 정교하게 진화했고, 이제는 실물 카드 없이도 전국 어디서나 경제 활동이 가능한 수준에 이르렀습니다. 곧 미르 페이는 애플 페이, 삼성 페이 등 페이 시스템의 빈자리를 훌륭하게 극복했습니다. 나아가 사용자 편의성을 추구하여 ATM에서 돈을 찾을 때나, 지하철 탑승 시에는 안면 인식을 통한 활용까지도 제공하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="margin-left:-3.826771653543311pt;text-align:justify;"&gt;&lt;strong&gt;로버: 모스크바 길거리를 누비는 자율주행 배달 로봇&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3725/image5.png"&gt;&lt;figcaption&gt;배달하는 로버 &amp;lt;출처: yandex image&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;거리의 풍경 또한 이곳 러시아가 자율주행 기술의 최전선임을 보여줍니다. 모스크바 도심의 무릎 높이까지 차오른 눈길을 얀덱스의 배달 로봇 ‘로버’들이 묵묵히 헤쳐 나가는 모습은 보고 있으면 경이롭기까지 합니다. 영하 20도의 혹한과 빙판길이라는 가혹한 환경은 자율주행 알고리즘에게는 최악의 난제이지만, 러시아의 로봇들은 이를 극복해 냈습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;센서와 알고리즘의 결합체인 이 로봇들은 단순한 기술 과시용이 아니라, 만성적인 인력 부족과 가혹한 기후 조건을 해결하기 위한 실용적인 해답으로 자리 잡고 있습니다. 모스크바 시내에서 돌아다니는 이 조그마한 배달 로봇들은 제재와 테러 등의 위험으로 비싸진 노동력을 대신하고 있는 것입니다. 점점 학습이 나아짐에 따라 더 빠르고 정확하게 상품을 배달하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="margin-left:-0.3070866141732438pt;text-align:justify;"&gt;&lt;strong&gt;3. 철의 장막 뒤에서 진화하는 소버린 AI의 실체&lt;/strong&gt;&lt;/h3&gt;&lt;p style="margin-left:-0.3070866141732438pt;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;얀덱스 vs 기가챗: 러시아 AI의 양대 산맥, 그들의 기술적 차별점&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3725/image2.png"&gt;&lt;figcaption&gt;러시아 최대 IT 기업과 그들의 AI 서비스 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;러시아 소버린 AI의 내부를 들여다보면 얀덱스의 '얀덱스GPT'와 스베르의 '기가챗'이라는 두 거대 산맥이 존재합니다. 민간 기술력의 정점에 서 있는 얀덱스가 방대한 검색 데이터와 정교한 소비자 맞춤형 서비스에 강점을 보인다면, 국영 금융 그룹인 스베르는 국가적인 컴퓨팅 자원과 금융 인프라를 바탕으로 공공 영역의 지능화를 주도합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이들은 서로 경쟁하면서도 외산 AI의 빈자리를 훌륭히 메우며 러시아 기술 생태계를 지탱하는 양대 기둥 역할을 수행합니다. 각기 다른 배경에서 탄생한 두 모델의 기술적 차별성은 러시아 AI 생태계를 더욱 풍성하게 만들고 있으며, 국가가 주도한 기술 발전이 민간의 창의성과 결합했을 때 나타나는 시너지를 잘 보여준다고 느껴집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;러시아가 오픈소스에 진심인 이유: 고립된 땅에서 혁신을 지속하는 법&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3725/image6.png"&gt;&lt;figcaption&gt;러시아의 개발자들 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;러시아가 기술적 고립 속에서도 혁신의 끈을 놓지 않는 비결은 바로 ‘오픈소스’에 대한 집요한 접근에 있습니다. 러시아의 개발자들은 전 세계의 오픈소스 프로젝트를 실시간으로 분석하고 흡수하여 자신들의 폐쇄된 네트워크 안에서 완전히 새로운 형태로 재조립합니다. 외부와의 공식적인 기술 협력 통로는 차단되었을지 몰라도, 공개된 코드를 해체하고 최적화하는 과정을 통해 전 세계의 지능을 자신들의 주권 아래로 끌어들이고 있는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이러한 전략은 고립된 환경이 어쩌면 외부 의존도를 낮추고 기술적 자생력을 키울 자양분이 될 수 있음을 시사합니다. 그들에게 오픈소스는 단순한 참조 도구가 아니라 생존 도구에 가깝습니다. 따라서 늘 오픈소스를 학습하고 개발하는 개발자라면 배워야 할 자세를 가지고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;폐쇄적 개발 환경의 역설: 외부 의존도를 0%로 만드는 극한의 최적화 전략&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;더불어 하드웨어 수급의 한계는 러시아 개발자들에게 소프트웨어의 ‘극한 최적화’라는 과제를 안겨주었습니다. 최신 고성능 GPU를 마음껏 사용할 수 없는 환경은 오히려 독이 아닌 득이 되었습니다. 제한된 연산 자원 내에서 거대 언어 모델을 구동하기 위해 그들은 알고리즘의 군더더기를 깎아내고 메모리 효율을 극대화하는 사투를 벌였습니다. 그 결과 가벼우면서도 강력한 러시아만의 독자적 모델들이 탄생했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;풍요로운 환경에서는 결코 시도하지 않았을 이 결핍의 연금술이 러시아 기술진의 실력을 상향 평준화시켰다고 보입니다. 외부 의존도를 0%로 수렴시키려는 이들의 노력은 결국 기술적 한계가 어떻게 창의적인 혁신으로 변모하는지를 보여주는 역설적인 장면을 연출합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;4. ‘AI 배제 시대’를 준비하는 우리의 자세&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;소버린 AI는 선택이 아닌 생존: 러시아 사례가 던지는 지정학적 메시지&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3725/image3.png"&gt;&lt;figcaption&gt;러시아의 지정학적 위험 &amp;lt;출처:&amp;nbsp;foreignpolicy&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;모스크바 현지에서 몸소 느낀 소버린 AI는, 단순한 기술 자립을 넘어선 국가의 명운을 건 사투 그 자체였습니다. 그러다 보니 특정 국가나 거대 빅테크 기업에 기술의 주도권을 완전히 넘겨주는 것은 앞으로 발생할 어떤 위기 상황에서도 스스로를 방어할 수 있는 수단을 포기하는 것과 같다고 느껴졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;러시아는 비록 강제적인 방식이었지만, 자신들의 데이터와 지능을 스스로 통제함으로써 외부의 압력에 쉽게 굴하지 않을 디지털 요새를 구축하는 데 성공했습니다. 이 사례는 우리에게 AI 주권이 더 이상 선택의 문제가 아니라 국가 안보와 직결된 생존의 필수 조건임을 경고하고 있지는 않을까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;글로벌 종속과 독자 기술 사이: 한국형 소버린 AI가 나아갈 방향&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;우리나라 역시 이제 글로벌 빅테크가 제공하는 편리함이라는 달콤한 유혹과 독자 기술 개발이라는 고단한 길 사이에서 냉정한 선택을 내려야 할 시점에 서 있습니다. 이제는 국가 차원에서 네이버나 카카오 같은 로컬 기업들이 수십 년간 쌓아온 데이터 영토를 보호하고, 한글을 비롯해 한국의 가치를 온전히 반영한 '한국형 소버린 AI'를 국가적 인프라로 육성해야 할 때입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;기술의 주권이 흔들릴 때 우리의 일상이 얼마나 쉽게 타인의 손에 의해 좌우될 수 있는지를 러시아란 나라는 명확히 보여줍니다. 모스크바의 매서운 눈바람을 뚫고 묵묵히 길을 찾아가는 배달 로봇처럼, 우리 역시 우리만의 기술적 해자를 구축하여 다가올 AI 패권 전쟁의 거센 파고를 당당히 넘어서야 합니다. 그것만이 디지털 대항해 시대에 대한민국이 자존감을 지키며 생존할 수 있는 유일한 길이기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;러시아 개발 생태계는 정부가 스스로 막은 것들도, 다른 국가에서 막은 것들도 많다 보니 늘 신기술에 대한 목마름이 넘쳐납니다. 그렇게 자체적으로 여러 세미나를 여는 등 기술 공부의 자리를 만들며 이를 키워 가고 있습니다. 저 또한 러시아에서 많은 것을 배우고 있습니다. 이 글을 읽고 있는 분들을 비롯해 한국 개발자에게 더 넓은 시야와 지식을 전파할 수 있을지 고민하며, 다시 새로운 것을 전달하러 찾아오겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>유니온 타입에서 막히는 순간, 타입 좁히기가 필요하다</title><link>https://yozm.wishket.com/magazine/detail/3719</link><description>타입스크립트를 쓰다 보면 하나의 변수가 여러 타입을 가질 수 있는 상황을 자주 만나게 됩니다. 함수의 매개변수가 string일 수도, number일 수도 있고, API 응답이 성공 데이터일 수도, 에러 객체일 수도 있습니다. 이처럼 다양한 가능성을 안고 있는 변수를 다룰 때, 타입스크립트는 꽤 보수적으로 반응합니다. 해당 변수가 “어떤 타입인지 아직 모르겠으니” 특정 타입 전용 메서드를 사용하지 못하도록 막아버리는 것입니다. 이 문제를 해결하는 방법이 바로 타입 좁히기(Type Narrowing)입니다. 타입 좁히기란 조건문 등을 활용해 넓은 타입을 더 구체적인 타입으로 확정해가는 과정을 말합니다.</description><guid>https://yozm.wishket.com/magazine/detail/3719</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;타입스크립트를 쓰다 보면 하나의 변수가 여러 타입을 가질 수 있는 상황을 자주 만나게 됩니다. 함수의 매개변수가 string일 수도, number일 수도 있고, API 응답이 성공 데이터일 수도, 에러 객체일 수도 있습니다. 이처럼 다양한 가능성을 안고 있는 변수를 다룰 때, 타입스크립트는 꽤 보수적으로 반응합니다. 해당 변수가 “어떤 타입인지 아직 모르겠으니” 특정 타입 전용 메서드를 사용하지 못하도록 막아버리는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 문제를 해결하는 방법이 바로 타입 좁히기(Type Narrowing)입니다. 타입 좁히기란 조건문 등을 활용해 넓은 타입을 더 구체적인 타입으로 확정해가는 과정을 말합니다. 복잡하게 들릴 수 있지만, 사실 우리가 자바스크립트에서 이미 자연스럽게 하고 있던 방어적 코딩 패턴을 타입스크립트가 인식하고 활용해주는 것에 가깝습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 타입 좁히기가 왜 필요한지부터 실무에서 자주 쓰이는 핵심 패턴까지 단계별로 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;미리 요점만 콕 집어보면?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;타입 좁히기란 조건문 등을 활용해 넓은 타입을 더 구체적인 타입으로 확정해가는 과정을 말합니다.&lt;/li&gt;&lt;li&gt;유니온 타입의 변수에는 모든 구성 타입이 공통으로 갖고 있는 프로퍼티와 메서드만 사용할 수 있기 때문입니다.&lt;/li&gt;&lt;li&gt;타입 가드는 조건문 등을 활용하여 타입의 범위를 좁혀나가는 표현들을 말하며 실무에서 자주 쓰이는 패턴입니다.&lt;/li&gt;&lt;/ul&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;타입 좁히기가 필요한 이유&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;타입 좁히기가 왜 필요한지 이해하려면, 먼저 유니온 타입의 한계부터 살펴봐야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 유니온 타입만으로는 부족하다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;유니온 타입은 여러 타입 중 하나가 될 수 있는 변수를 정의할 때 사용합니다. 예를 들어, 문자열과 숫자를 모두 받을 수 있는 함수를 만든다고 해봅시다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function printValue(value: string | number) {
  console.log(value.toUpperCase()); // ❌ 오류
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 코드는 에러가 발생합니다. value가 string일 수도, number일 수도 있기 때문에 타입스크립트는 string 전용 메서드인 toUpperCase()를 호출하지 못하게 막는 것입니다. 반대로 number 전용 메서드인 toFixed()도 마찬가지로 쓸 수 없습니다. 유니온 타입의 변수에는 모든 구성 타입이 공통으로 갖고 있는 프로퍼티와 메서드만 사용할 수 있기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;그렇다면 어떻게 해야 할까요? 이 변수가 string인지 number인지를 먼저 확인하고, 확인된 상태에서 해당 타입의 기능을 사용하면 됩니다. 바로 이것이 타입 좁히기입니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 조건문으로 타입을 좁히면?&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;아래처럼 typeof를 사용한 조건문을 추가해 봅시다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function printValue(value: string | number) {
  if (typeof value === "string") {
    console.log(value.toUpperCase()); // ✅ string 타입으로 확정
  } else {
    console.log(value.toFixed(2)); // ✅ number 타입으로 확정
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;if 블록 안에서 typeof value === "string" 조건을 통과했다면, 타입스크립트는 해당 블록 안의 value를 string 타입으로 확정합니다. else 블록에서는 string이 아닌 나머지, 즉 number 타입으로 확정됩니다. 별도의 타입 단언(as)을 쓰지 않아도, 조건문만으로 타입을 안전하게 구분할 수 있는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3719/%EA%B7%B8%EB%A6%BC1__3_.png"&gt;&lt;figcaption&gt;&amp;lt;출처 : 작가, Claude AI 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이렇게 조건문 등을 활용하여 타입의 범위를 좁혀나가는 표현들을 타입 가드(Type Guard)라고 부릅니다. 타입 좁히기를 실현하는 구체적인 도구가 바로 타입 가드인 셈입니다. 이제 실무에서 자주 쓰이는 타입 가드 패턴들을 하나씩 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;타입 좁히기 기본 패턴&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;타입스크립트에서 제공하는 타입 가드는 여러 종류가 있습니다. 상황에 따라 적합한 패턴이 다르기 때문에, 각 패턴의 특성과 사용 시점을 정리해두면 유용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) typeof 가드&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;typeof는 가장 기본적이고 자주 사용되는 타입 가드입니다. 자바스크립트의 typeof 연산자가 반환하는 문자열을 기준으로 타입을 구분합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function formatInput(input: string | number | boolean) {
  if (typeof input === "string") {
    return input.trim();
  } else if (typeof input === "number") {
    return input.toLocaleString();
  } else {
    return input ? "참" : "거짓";
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;typeof는 "string", "number", "boolean", "undefined", "object", "function", "symbol", "bigint" 중 하나를 반환합니다. 주의할 점은 typeof null이 "object"를 반환한다는 것입니다. 따라서 null과 객체를 동시에 다루는 경우에는 typeof만으로는 정확하게 구분하기 어렵습니다. null 체크를 별도로 추가하거나, 다른 타입 가드를 함께 사용해야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function process(value: string | null) {
  if (typeof value === "string") {
    return value.toUpperCase(); // ✅ null이 아님이 보장됨
  }
  return "빈 값";
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;typeof는 원시 타입을 구분할 때 유용하지만, 객체의 구체적인 종류(Date인지, Array인지, 커스텀 클래스인지)를 구분하기에는 적합하지 않습니다. 객체는 typeof로 확인하면 전부 "object"가 반환되기 때문입니다. 이런 경우에는 다음에 소개할 instanceof를 사용해야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) instanceof 가드&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;instanceof는 어떤 값이 특정 클래스의 인스턴스인지를 확인하는 연산자입니다. 주로 Date, Error 같은 내장 클래스나 직접 정의한 클래스의 인스턴스를 구분할 때 사용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function formatDate(value: string | Date) {
  if (value instanceof Date) {
    return `${value.getFullYear()}년 ${value.getMonth() + 1}월 ${value.getDate()}일`;
  }
  return value;
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;에러 처리에서도 자주 쓰입니다. try-catch 블록에서 catch한 에러가 어떤 종류인지 구분할 때 instanceof가 유용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function handleError(error: unknown) {
  if (error instanceof TypeError) {
    console.log("타입 에러:", error.message);
  } else if (error instanceof RangeError) {
    console.log("범위 에러:", error.message);
  } else {
    console.log("알 수 없는 에러");
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 instanceof는 클래스 기반 타입에만 사용할 수 있습니다. 인터페이스나 타입 별칭 그 자체는 컴파일 과정에서 제거되어 런타임에 남지 않으므로, 이를 직접 instanceof로 검사할 수는 없습니다. 즉, 자바스크립트로 변환된 코드에는 인터페이스에 대한 정보가 남아있지 않으므로 instanceof로 비교할 대상 자체가 없는 것입니다. 물론 해당 인터페이스를 구현한 클래스가 있다면, 그 클래스를 기준으로 instanceof 검사를 하는 것은 가능합니다. 하지만 인터페이스 자체를 직접 검사할 수 없다는 점은 동일합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) in 연산자&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;in 연산자는 객체에 특정 프로퍼티가 존재하는지를 확인하는 방식으로 타입을 좁힙니다. 인터페이스나 타입 별칭으로 정의한 서로 다른 객체 타입을 구분할 때 특히 유용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface Dog {
  name: string;
  bark: () =&amp;gt; void;
}

interface Cat {
  name: string;
  meow: () =&amp;gt; void;
}

function greetPet(pet: Dog | Cat) {
  if ("bark" in pet) {
    pet.bark(); // ✅ Dog 타입으로 확정
  } else {
    pet.meow(); // ✅ Cat 타입으로 확정
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Dog에는 bark가 있고 Cat에는 없기 때문에, "bark" in pet 조건으로 두 타입을 구분할 수 있습니다. 이처럼 in 연산자는 타입마다 고유하게 존재하는 프로퍼티를 기준으로 분기할 때 효과적입니다. 다만, 두 타입이 완전히 동일한 프로퍼티 구조를 갖고 있다면 in만으로는 구분이 어렵습니다. 이런 경우에는 뒤에서 다룰 판별된 유니온 패턴이 더 적합합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;기본 패턴을 정리하면 다음과 같습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3719/%EA%B7%B8%EB%A6%BC2__3_.png"&gt;&lt;figcaption&gt;&amp;lt;출처 : 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실무에서 자주 쓰는 고급 패턴&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;앞서 살펴본 기본 패턴만으로도 많은 상황을 커버할 수 있지만, 실무에서 마주하는 타입 분기는 조금 더 복잡한 경우가 많습니다. 여러 종류의 응답 객체를 구분하거나, 타입스크립트가 자동으로 추론하지 못하는 상황을 직접 처리해야 할 때가 있습니다. 이런 경우에 활용할 수 있는 고급 패턴들을 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 판별된 유니온(Discriminated Union)&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3719/%EA%B7%B8%EB%A6%BC3__2_.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude AI 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실무에서 가장 많이 쓰이는 타입 좁히기 패턴입니다. 유니온을 구성하는 각 타입이 공통적으로 가지고 있는 리터럴 타입 필드를 기준으로 분기하는 방식입니다. 보통 type, status, kind 같은 필드가 이 역할을 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;API 응답 처리를 예로 들어보겠습니다. 대부분의 API는 성공과 실패 시 응답 구조가 다릅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface SuccessResponse {
  status: "success";
  data: {
    id: number;
    name: string;
  };
}

interface ErrorResponse {
  status: "error";
  errorCode: number;
  message: string;
}

type ApiResponse = SuccessResponse | ErrorResponse;&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서 status 필드가 판별자(discriminant) 역할을 합니다. 이 필드의 값이 "success"인지 "error"인지에 따라 타입이 자동으로 확정됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function handleResponse(response: ApiResponse) {
  if (response.status === "success") {
    console.log(response.data.name); // ✅ SuccessResponse로 확정
  } else {
    console.log(`에러 ${response.errorCode}: ${response.message}`); // ✅ ErrorResponse로 확정
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;switch문과 결합하면 더 깔끔하게 분기할 수 있습니다. 상태가 세 가지 이상으로 나뉘는 경우에 특히 유용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface LoadingState {
  status: "loading";
}

interface SuccessState {
  status: "success";
  data: string[];
}

interface ErrorState {
  status: "error";
  message: string;
}

type FetchState = LoadingState | SuccessState | ErrorState;

function renderUI(state: FetchState) {
  switch (state.status) {
    case "loading":
      return "로딩 중...";
    case "success":
      return state.data.join(", ");
    case "error":
      return `오류: ${state.message}`;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;판별된 유니온의 장점은 코드의 의도가 명확하다는 것입니다. status 필드 하나만 보면 어떤 타입인지 바로 알 수 있기 때문에 가독성이 좋고, 새로운 상태가 추가되더라도 switch문에 case만 추가하면 되므로 확장도 용이합니다. 또한 never 타입을 활용한 exhaustive check를 함께 쓰면, 누락된 분기를 컴파일 단계에서 바로 잡아낼 수 있어 더 안전합니다. 리액트에서 API 호출 상태를 관리하거나, Redux 같은 상태 관리 도구에서 액션을 구분할 때도 이 패턴이 자주 사용됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 사용자 정의 타입 가드(is 키워드)&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;지금까지 살펴본 패턴들은 타입스크립트가 조건문을 분석해서 자동으로 타입을 좁혀주는 경우였습니다. 하지만 타입스크립트가 자동으로 추론하지 못하는 상황도 있습니다. 예를 들어, 복잡한 조건을 별도 함수로 분리하면, 그 함수의 반환값이 boolean일 뿐 타입 좁히기로 연결되지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function isString(value: unknown): boolean {
  return typeof value === "string";
}

function process(value: string | number) {
  if (isString(value)) {
    value.toUpperCase(); // ❌ 여전히 string | number
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;위 코드에서 isString 함수는 분명히 문자열 여부를 확인하고 있지만, 타입스크립트 입장에서는 그냥 boolean을 반환하는 함수일 뿐입니다. 조건문 안에서의 타입 좁히기가 작동하지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이런 상황에서 is 키워드를 사용하면 됩니다. 반환 타입을 value is string 형태로 선언하면, 이 함수가 true를 반환할 때 해당 매개변수가 특정 타입임을 타입스크립트에 알려줄 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function isString(value: unknown): value is string {
  return typeof value === "string";
}

function process(value: string | number) {
  if (isString(value)) {
    value.toUpperCase(); // ✅ string 타입으로 확정
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 패턴은 반복적으로 사용되는 타입 체크 로직을 함수로 분리할 때 특히 유용합니다. 여러 곳에서 동일한 타입 확인 조건을 작성하는 대신, 타입 가드 함수 하나를 만들어두면 코드의 중복을 줄이면서도 타입 안전성을 유지할 수 있습니다. 배열에서 null이나 undefined를 걸러내는 필터링 패턴에서도 자주 활용됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function isNotNull&amp;lt;T&amp;gt;(value: T | null): value is T {
  return value !== null;
}

const items = ["사과", null, "바나나", null, "딸기"];
const filtered = items.filter(isNotNull);
// filtered의 타입: string[]&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Array.filter에 일반적인 boolean 반환 함수를 넘기면 타입스크립트가 null이 제거되었다는 것을 대부분 인식하지 못해 (string | null)[] 타입이 유지되는데, is 키워드를 사용한 타입 가드를 넘기면 string[]으로 정확하게 추론됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) 타입 좁히기 사용 시 주의할 점&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;타입 좁히기는 강력한 기능이지만, 실무에서 사용하다 보면 몇 가지 실수하기 쉬운 지점이 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;먼저 첫 번째로 주의할 것은 타입 단언(as)의 남용입니다. 타입 좁히기 대신 as로 강제 변환하면 코드가 짧아지는 것처럼 보이지만, 타입 안전성을 포기하는 것입니다. 실제 런타임 값이 해당 타입이 아닐 경우, 타입스크립트는 에러를 잡아주지 못합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;// ❌ 위험: 실제로 string이 아닐 수 있음
const value = someFunction() as string;
console.log(value.toUpperCase()); // 런타임 에러 가능

// ✅ 안전: 실제로 string인지 확인 후 사용
const value = someFunction();
if (typeof value === "string") {
  console.log(value.toUpperCase());
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="margin-left:36pt;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;두 번째는 콜백 함수 안에서 좁혀진 타입이 풀리는 경우입니다. 바깥 스코프에서 타입을 좁혀놨더라도, 콜백 안에서는 이 정보가 유지되지 않을 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function process(value: string | null) {
  if (value !== null) {
    // 여기서는 string 타입으로 좁혀짐
    setTimeout(() =&amp;gt; {
      console.log(value.toUpperCase()); // ✅ 이 경우는 동작함
    }, 100);
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="margin-left:36pt;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;위 예시처럼 재할당 가능성이 없고 제어 흐름상 안전하다고 판단되는 경우에는 콜백 안에서도 좁혀진 타입이 유지될 수 있습니다. 하지만 let으로 선언된 변수는 콜백이 실행되기 전에 다른 값이 할당될 수 있기 때문에, 타입스크립트의 제어 흐름 분석이 클로저 경계를 넘어서까지 안전하다고 보장하지 못하는 경우가 있습니다. 이런 상황에서는 좁혀진 값을 별도의 const 변수에 담아두는 방법이 안전합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;let value: string | null = getString();

if (value !== null) {
  const confirmed = value; // string 타입으로 확정된 값을 별도 변수에 저장
  setTimeout(() =&amp;gt; {
    console.log(confirmed.toUpperCase()); // ✅ 안전
  }, 100);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 타입스크립트의 타입 좁히기에 대해 살펴보았습니다. 코드를 작성하다 as를 사용하고 싶은 순간이 오면, 잠시 멈추고 타입 좁히기로 해결할 수 있는지 먼저 떠올려보세요. 대부분의 경우 조건문 한두 줄이면 충분하고, 그렇게 작성한 코드가 더 안전하고 읽기 쉬운 코드로 이어집니다. 타입 좁히기에 익숙해질수록 타입스크립트를 더 자신 있게 다룰 수 있게 될 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>에이전트 하네스 완전 해부</title><link>https://yozm.wishket.com/magazine/detail/3718</link><description>이 글은 AI 에이전트 시스템에서 모델을 감싸는 인프라, 즉 '하네스(Harness)'의 개념을 정의하고, 파일시스템·샌드박스·메모리·컨텍스트 관리 등 핵심 구성 요소를 모델의 한계에서 역추적하여 도출하는 과정을 담고 있습니다. LangChain이 자사 코딩 에이전트의 하네스만 변경하여 Terminal Bench 2.0에서 Top 30에서 Top 5로 끌어올린 사례를 포함해, 하네스 엔지니어링의 현재와 미래를 구체적으로 소개합니다.</description><guid>https://yozm.wishket.com/magazine/detail/3718</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;본문은 요즘IT가 Vivek Trivedy(비벡 트리베디) 님의 글&amp;lt;&lt;a href="https://blog.langchain.com/the-anatomy-of-an-agent-harness/"&gt;&lt;u&gt;The Anatomy of an Agent Harness&lt;/u&gt;&lt;/a&gt;&amp;gt;를 번역한 글입니다. 필자는 LangChain의 프로덕트 매니저로, 에이전트·하네스·평가(Evals)를 담당하며 오픈소스 에이전트 프레임워크 개발을 이끌고 있습니다. 이전에는 AWS에서 과학자(Scientist)로 근무하며 Temple University에서 컴퓨터 과학 박사 학위를 취득했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 글은 AI 에이전트 시스템에서 모델을 감싸는 인프라, 즉 '하네스(Harness)'의 개념을 정의하고, 파일시스템·샌드박스·메모리·컨텍스트 관리 등 핵심 구성 요소를 모델의 한계에서 역추적하여 도출하는 과정을 담고 있습니다. LangChain이 자사 코딩 에이전트의 하네스만 변경하여 Terminal Bench 2.0에서 Top 30에서 Top 5로 끌어올린 사례를 포함해, 하네스 엔지니어링의 현재와 미래를 구체적으로 소개합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;span style="color:#757575;"&gt;필자에게 허락을 받고 번역했으며, 글에 포함된 링크는 원문에 따라 표시했습니다.&lt;/span&gt;&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;누가 "하네스"를 좀 정의해줄래요?&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;에이전트 = 모델 + 하네스(harness)&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;모델이 아닌 모든 것이 하네스입니다.&lt;/strong&gt; 하네스란 모델 그 자체가 아닌 모든 코드, 설정, 실행 로직을 말합니다. 날것의 모델(raw model)은 에이전트가 아닙니다. 하지만 하네스가 모델에게 상태(state), 도구 실행, 피드백 루프, 강제 가능한 제약 같은 것들을 부여하는 순간, 모델은 에이전트가 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;구체적으로 하네스는 다음과 같은 것들을 포함합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;시스템 프롬프트&lt;/li&gt;&lt;li style="text-align:justify;"&gt;도구(Tools), 스킬(Skills), MCP와 그 설명들&lt;/li&gt;&lt;li style="text-align:justify;"&gt;번들링된 인프라(파일시스템, 샌드박스, 브라우저)&lt;/li&gt;&lt;li style="text-align:justify;"&gt;오케스트레이션 로직(서브에이전트 생성, 핸드오프, 모델 라우팅)&lt;/li&gt;&lt;li style="text-align:justify;"&gt;결정론적 실행을 위한 훅/미들웨어(compaction, continuation, lint check)&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;에이전트 시스템에서 모델과 하네스의 경계를 나누는 방법은 여러 가지고, 꽤 지저분합니다. 하지만 제 생각에 위 정의가 가장 깔끔합니다. 왜냐하면 이 정의는 &lt;strong&gt;모델의 지능(intelligence)을 중심에 두고 시스템을 설계하도록&lt;/strong&gt; 강제하기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 글의 나머지 부분에서는 하네스의 핵심 구성 요소들을 하나씩 살펴보면서, 모델이라는 핵심 프리미티브(primitive)에서 출발해 각 구성 요소가 왜 존재해야 하는지를 역으로 도출해보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;왜 하네스가 필요한가: 모델의 관점에서&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;우리가 에이전트에게 시키고 싶은 일들 중에는, 모델이 그 자체로는 할 수 없는 것들이 있습니다. 바로 이 지점에서 하네스가 등장합니다. 모델은 (대체로) 텍스트, 이미지, 오디오, 비디오 같은 데이터를 입력받아 텍스트를 출력합니다. 그게 전부입니다. 모델은 기본적으로 다음을 할 수 없습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;상호작용 간에 지속 가능한 상태 유지&lt;/li&gt;&lt;li style="text-align:justify;"&gt;코드 실행&lt;/li&gt;&lt;li style="text-align:justify;"&gt;실시간 지식 접근&lt;/li&gt;&lt;li style="text-align:justify;"&gt;작업 완수를 위한 환경 세팅 및 패키지 설치&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이것들은 모두 하네스 레벨의 기능입니다. LLM이라는 구조 자체가, 유용한 일을 시키려면 모델을 감싸는 어떤 기계 장치를 필요로 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;예를 들어, "대화하기"라는 제품 UX를 만들려면 이전 메시지들을 추적하고 새 사용자 메시지를 덧붙이기 위해 모델을 while 루프로 감싸야 합니다. 이 글을 읽고 있는 분이라면 이미 이런 종류의 하네스를 써본 셈입니다. 핵심은, 우리가 원하는 에이전트의 행동을 하네스의 실제 기능으로 변환한다는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3718/image2.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;원하는 에이전트 행동에서 하네스 엔지니어링으로 역산하기&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;하네스 엔지니어링은 인간이 에이전트의 행동을 유도하기 위한 유용한 사전 지식(prior)을 주입하는 일입니다. 그리고 모델이 더 똑똑해질수록, 하네스는 이전에는 불가능했던 작업을 완수하도록 모델을 정교하게 확장하고 교정하는 용도로 쓰이고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;모든 하네스 기능을 빠짐없이 다루지는 않을 겁니다. 목표는 "모델이 유용한 일을 하게 돕는다"는 출발점에서 일련의 기능들을 도출해보는 것입니다. 다음과 같은 패턴을 따라가 보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;우리가 원하는(또는 고치고 싶은) 행동 → 모델이 그것을 달성하게 돕는 하네스 설계&lt;/strong&gt;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3718/image3.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;지속적 저장과 컨텍스트 관리를 위한 파일시스템&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;우리는 에이전트가 실제 데이터와 상호작용하고, 컨텍스트에 담기지 않는 정보를 덜어내고, 세션을 넘나들며 작업을 지속하도록 하고 싶습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;모델은 컨텍스트 윈도우 안의 지식에 대해서만 직접 작업할 수 있습니다. 파일시스템이 도입되기 전에는 사용자가 모델에게 내용을 복사·붙여넣기 해야 했습니다. UX가 번거롭고, 자율 에이전트에는 적용할 수도 없습니다. 세상은 이미 작업을 위해 파일시스템을 쓰고 있었고, 덕분에 모델은 파일시스템 사용법을 수십억 토큰으로 자연스럽게 학습한 상태였습니다. 그래서 자연스러운 해결책은 이것이 됐습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;하네스는 파일시스템 추상화와 파일 시스템 작업(fs-ops)용 도구를 기본 탑재합니다.&lt;/strong&gt; 파일시스템은 아마도 가장 근본적인 하네스 프리미티브일 것입니다. 다음과 같은 것들을 가능하게 하기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;에이전트에게 데이터, 코드, 문서를 읽을 수 있는 작업 공간이 생깁니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;모든 것을 컨텍스트에 붙들고 있는 대신, 작업을 점진적으로 더하거나 덜어낼 수 있습니다. 중간 산출물을 저장하고, 한 세션을 넘어서는 상태를 유지할 수 있습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;파일시스템은 자연스러운 협업 표면입니다. 여러 에이전트와 인간이 공유된 파일을 통해 협업할 수 있습니다. 에이전트 팀(Agent Teams) 같은 아키텍처가 이 위에서 돌아갑니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;Git을 더하면 파일시스템에 버전 관리가 붙어, 에이전트가 작업을 추적하고, 에러를 롤백하고, 실험을 브랜치로 나눌 수 있게 됩니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;파일시스템은 뒤에서 다시 등장합니다. 알고 보면 이것이 다른 여러 기능의 기반이 되는 핵심 하네스 프리미티브이기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;범용 도구로서의 Bash와 코드&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;우리는 인간이 모든 도구를 미리 설계하지 않아도 에이전트가 자율적으로 문제를 해결하기를 원합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;오늘날 에이전트 실행의 주류 패턴은 &lt;a href="https://docs.langchain.com/oss/python/langchain/agents?ref=blog.langchain.com&amp;amp;_gl=1*1cg3aey*_gcl_au*MTI0NzU3OTgzNi4xNzc1ODEwMDcy*_ga*NjMwMzc2MzQ2LjE3NzU4MTAwNzM.*_ga_47WX3HKKY2*czE3NzY0MTE2NDQkbzkkZzAkdDE3NzY0MTE2NDQkajYwJGwwJGgw"&gt;&lt;u&gt;ReAct 루프&lt;/u&gt;&lt;/a&gt;입니다. 모델이 추론하고, 도구 호출로 행동하고, 결과를 관찰하고, 이를 while 루프 안에서 반복하는 방식입니다. 하지만 하네스는 자기가 로직을 갖고 있는 도구만 실행할 수 있습니다. 사용자에게 가능한 모든 행동에 대한 도구를 일일이 만들라고 요구하는 건 좋은 해결책이 아닙니다. 더 나은 방법은 에이전트에게 bash 같은 범용 도구를 주는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;하네스는 bash 도구를 기본 탑재해, 모델이 코드를 작성하고 실행하며 자율적으로 문제를 풀 수 있게 합니다.&lt;/strong&gt; Bash와 코드 실행은 모델에게 컴퓨터를 쥐여주고 나머지는 알아서 하게 하는 방향으로 가는 큰 도약입니다. 모델은 미리 설정된 고정된 도구 세트에 갇히지 않고, 코드를 통해 즉석에서 자신만의 도구를 설계할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하네스는 여전히 다른 도구들도 함께 제공하지만, 코드 실행은 자율적 문제 해결의 기본 전략으로 자리 잡았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;작업을 실행하고 검증하기 위한 샌드박스와 도구&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;에이전트는 안전하게 행동하고, 결과를 관찰하며, 진전을 이룰 수 있는 적절한 기본 환경이 필요합니다. 모델에게 저장 공간과 코드 실행 능력을 줬지만, 이 모든 것이 &lt;strong&gt;어딘가에서&lt;/strong&gt; 일어나야 합니다. 에이전트가 만든 코드를 로컬에서 그대로 실행하는 건 위험하고, 단일 로컬 환경은 대규모 에이전트 워크로드에는 적합하지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;샌드박스는 에이전트에게 안전한 실행 환경을 제공합니다. 로컬 대신, 하네스가 샌드박스에 연결해 코드를 실행하고, 파일을 살펴보고, 의존성을 설치하고, 작업을 완료합니다. 이 방식은 격리된 안전한 코드 실행을 가능하게 합니다. 보안을 더 강화하려면, 하네스에서 허용 명령어를 화이트리스트로 지정하고 네트워크 격리를 강제할 수도 있습니다. 샌드박스는 확장성도 열어줍니다. 필요할 때 환경을 생성하고, 여러 작업에 병렬로 뿌리고, 끝나면 정리할 수 있기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;좋은 환경은 좋은 기본 도구들과 함께 옵니다. 하네스는 에이전트가 유용한 일을 할 수 있도록 도구를 구성할 책임이 있습니다. 언어 런타임과 패키지 사전 설치, git과 테스트용 CLI, 웹 상호작용 및 검증용 &lt;a href="https://github.com/vercel-labs/agent-browser?ref=blog.langchain.com"&gt;&lt;u&gt;브라우저&lt;/u&gt;&lt;/a&gt; 등이 여기 포함됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;브라우저, 로그, 스크린샷, 테스트 러너 같은 도구는 에이전트가 자기 작업을 관찰하고 분석할 수 있게 해줍니다. 이를 통해 에이전트는 자기 검증 루프를 만들 수 있습니다. 애플리케이션 코드를 작성하고, 테스트를 돌리고, 로그를 살펴보고, 에러를 고치는 식으로요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;모델은 기본적으로 자기 실행 환경을 스스로 구성하지 않습니다. 에이전트가 어디서 동작할지, 어떤 도구를 쓸 수 있을지, 무엇에 접근할 수 있을지, 어떻게 작업을 검증할지는 모두 하네스 수준의 설계 결정입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;지속적 학습을 위한 메모리와 검색&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;에이전트는 이전에 본 것을 기억해야 하고, 학습 시점에는 존재하지 않았던 정보에도 접근할 수 있어야 합니다. 모델은 가중치와 현재 컨텍스트에 담긴 것 외에는 추가 지식이 없습니다. 모델 가중치를 수정할 수 없는 상황에서, "지식을 추가"하는 유일한 방법은 컨텍스트 주입입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;메모리 측면에서도 파일시스템이 다시 핵심 프리미티브로 등장합니다. 하네스는 &lt;a href="http://agents.md"&gt;&lt;u&gt;AGENTS.md&lt;/u&gt;&lt;/a&gt; 같은 메모리 파일 표준을 지원하고, 에이전트 시작 시 이를 컨텍스트에 주입합니다. 에이전트가 이 파일을 추가하고 수정하면, 하네스는 업데이트된 내용을 다음 컨텍스트에 불러옵니다. 이는 일종의 &lt;a href="https://www.ibm.com/think/topics/continual-learning?ref=blog.langchain.com"&gt;&lt;u&gt;지속적 학습&lt;/u&gt;&lt;/a&gt;입니다. 에이전트가 한 세션에서 얻은 지식을 지속 가능하게 저장하고, 그 지식을 이후 세션에 주입하는 방식이죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;지식 컷오프(knowledge cutoff) 때문에, 모델은 사용자가 직접 제공하지 않는 한 새로 업데이트된 라이브러리 버전 같은 데이터에 직접 접근할 수 없습니다. 최신 지식을 위해서는 웹 검색과 &lt;a href="https://context7.com/?ref=blog.langchain.com"&gt;&lt;u&gt;Context7&lt;/u&gt;&lt;/a&gt; 같은 MCP 도구들이 에이전트가 학습 이후에 등장한 정보, 예컨대 최신 라이브러리 버전이나 최신 데이터에 접근하도록 도와줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;웹 검색과 최신 컨텍스트 조회 도구는 하네스에 내장할 만한 유용한 프리미티브들입니다.&lt;/strong&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;컨텍스트 부패와 싸우기&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;작업이 진행될수록 에이전트 성능이 나빠져서는 안 됩니다. &lt;a href="https://research.trychroma.com/context-rot?ref=blog.langchain.com"&gt;&lt;u&gt;컨텍스트 부패(context rot)&lt;/u&gt;&lt;/a&gt;는 컨텍스트 윈도우가 채워질수록 모델이 추론과 작업 수행에서 나빠지는 현상을 말합니다. 컨텍스트는 귀중하고 희소한 자원이기 때문에, 하네스는 이를 관리할 전략이 필요합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;오늘날의 하네스는 사실상 좋은 컨텍스트 엔지니어링을 전달하는 수단입니다.&lt;/strong&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;Compaction&lt;/strong&gt;은 컨텍스트 윈도우가 가득 차려 할 때 무엇을 할지의 문제를 다룹니다. compaction이 없으면 대화가 컨텍스트 윈도우를 초과했을 때 어떻게 될까요? 한 가지 선택지는 API가 에러를 내는 것입니다. 좋지 않죠. 하네스는 이런 상황을 위한 전략이 필요합니다. compaction은 기존 컨텍스트를 똑똑하게 덜어내고 요약해서, 에이전트가 계속 작업할 수 있게 해줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;도구 호출 오프로딩(Tool call offloading)&lt;/strong&gt;은 큰 도구 출력이 유용한 정보 없이 컨텍스트를 어지럽히는 문제를 줄여줍니다. 하네스는 일정 토큰 수 이상인 도구 출력에 대해 앞뒤 토큰만 남기고, 전체 출력은 파일시스템에 옮겨두어 필요할 때만 모델이 접근할 수 있게 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;스킬(Skills)&lt;/strong&gt;은 에이전트 시작 시 너무 많은 도구나 MCP 서버가 컨텍스트에 로드되어, 일을 시작하기도 전에 성능이 떨어지는 문제를 해결합니다. 스킬은 점진적 공개(progressive disclosure)를 통해 이 문제를 푸는 하네스 수준의 프리미티브입니다. 모델이 시작 시 스킬의 front-matter를 컨텍스트에 싣겠다고 선택한 건 아니지만, 하네스가 이를 지원함으로써 모델을 컨텍스트 부패로부터 보호할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;장기 자율 실행&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;우리는 에이전트가 복잡한 작업을, 자율적으로, 정확하게, 긴 시간에 걸쳐 완수하기를 원합니다. 자율적인 소프트웨어 생성은 코딩 에이전트의 성배입니다. 하지만 오늘날의 모델들은 조기 종료(early stopping), 복잡한 문제 분해의 어려움, 여러 컨텍스트 윈도우를 넘어갈 때의 일관성 붕괴 같은 문제들을 겪습니다. 좋은 하네스는 이 모든 것을 설계에 반영해야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서부터는 앞서 다룬 하네스 프리미티브들이 복리처럼 작동하기 시작합니다. 장기 작업은 여러 컨텍스트 윈도우를 넘어 작업을 지속하기 위해 지속 가능한 상태, 계획, 관찰, 검증을 모두 필요로 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;세션을 가로지르는 작업 추적을 위한 파일시스템과 git&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;에이전트는 긴 작업 동안 수백만 토큰을 만들어내기 때문에, 파일시스템이 작업을 지속 가능하게 담아 시간에 따른 진전을 추적합니다. 여기에 git을 더하면, 새로 시작한 에이전트가 프로젝트의 최신 상태와 히스토리를 빠르게 따라잡을 수 있습니다. 여러 에이전트가 함께 일할 때도 파일시스템은 공유된 작업 원장(ledger) 역할을 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;작업을 이어가기 위한 Ralph Loop&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;&lt;a href="https://ghuntley.com/loop/?ref=blog.langchain.com"&gt;&lt;u&gt;Ralph Loop&lt;/u&gt;&lt;/a&gt;은 모델이 종료하려는 시도를 훅으로 가로채, 깨끗한 컨텍스트 윈도우에 원래 프롬프트를 다시 주입해 완료 목표를 향해 계속 일하게 하는 하네스 패턴입니다. 이 패턴이 가능한 건 파일시스템 덕분입니다. 각 반복은 새 컨텍스트로 시작하되, 이전 반복의 상태를 파일에서 읽어오기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;궤도를 유지하기 위한 계획과 자기 검증&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;계획(planning)은 모델이 목표를 여러 단계로 분해하는 일입니다. 하네스는 좋은 프롬프트와, 파일시스템의 계획 파일 사용법에 대한 리마인더 주입을 통해 이를 지원합니다. 각 단계를 완료한 뒤, 에이전트는 자기 검증(self-verification)을 통해 작업의 정확성을 점검할 때 더 잘 동작합니다. 하네스의 훅이 사전 정의된 테스트 스위트를 실행하고, 실패 시 에러 메시지를 담아 모델로 다시 루프를 돌릴 수도 있고, 모델이 스스로 자기 코드를 평가하도록 프롬프트를 설계할 수도 있습니다. 검증은 해결책을 테스트에 뿌리내리게 하고, 자기 개선을 위한 피드백 신호를 만들어냅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;하네스의 미래&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;모델 학습과 하네스 설계의 결합&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;오늘날 Claude Code나 Codex와 같은 에이전트 제품들은 모델과 하네스가 루프 안에 포함된 상태로 사후 학습(Post-trained)됩니다. 이를 통해 모델은 하네스 설계자가 의도한 동작(파일 시스템 조작, Bash 실행, 계획 수립, 하위 에이전트 병렬화 등)을 기본적으로 더 잘 수행하게 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 과정에서 유용한 프리미티브가 발견되어 하네스에 추가되고, 이는 다시 다음 세대 모델 학습에 사용되는 피드백 루프가 형성됩니다. 이 사이클이 반복되면서, 모델은 자기가 학습된 하네스 안에서 점점 더 유능해집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 이 공진화(co-evolution)는 일반화 측면에서 흥미로운 부작용을 낳습니다. 도구 로직을 바꾸면 모델 성능이 떨어지는 현상 같은 것들이죠. 좋은 예가 &lt;a href="https://developers.openai.com/cookbook/examples/gpt-5/codex_prompting_guide/?ref=blog.langchain.com#apply_patch"&gt;&lt;u&gt;Codex-5.3 프롬프팅 가이드&lt;/u&gt;&lt;/a&gt;에 나오는, 파일 편집용 apply_patch 도구 로직에 관한 내용입니다. 진정으로 지능적인 모델이라면 패치 방식을 바꾸는 정도로 문제를 겪을 리 없지만, 하네스를 루프에 넣은 학습은 이런 식의 과적합을 만듭니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그렇다고 해서 모델이 사후 학습될 때 사용된 하네스가 반드시 여러분의 작업에 최적인 것은 아닙니다.&amp;nbsp; &lt;a href="https://www.tbench.ai/leaderboard/terminal-bench/2.0?ref=blog.langchain.com"&gt;&lt;u&gt;Terminal Bench 2.0 리더보드&lt;/u&gt;&lt;/a&gt;가 좋은 예입니다. Claude Code 안에서의 Opus 4.6은 다른 하네스에서의 Opus 4.6보다 한참 낮은 점수를 받습니다. &lt;a href="https://x.com/Vtrivedy10/status/2023805578561060992?s=20&amp;amp;ref=blog.langchain.com"&gt;&lt;u&gt;이전 글&lt;/u&gt;&lt;/a&gt;에서 저희는 코딩 에이전트의 Terminal Bench 2.0 순위를 하네스만 바꿔 Top 30에서 Top 5로 끌어올린 과정을 공유한 적이 있습니다. 여러분의 작업에 맞게 하네스를 최적화하는 일에는 아직 짜낼 수 있는 즙이 많이 남아 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3718/image1.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;하네스 엔지니어링은 어디로 가는가&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;모델이 더 유능해질수록, 지금 하네스에 있는 일부 기능은 모델 안으로 흡수될 것입니다. 모델은 기본적으로 계획 수립, 자기 검증, 장기 일관성 유지 등을 더 잘하게 될 것이고, 결과적으로 컨텍스트 주입과 같은 필요성은 줄어들 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이는 시간이 흐를수록 하네스의 중요성이 낮아질 것임을 시사합니다. 하지만 프롬프트 엔지니어링이 지금도 여전히 가치 있는 것처럼, 하네스 엔지니어링도 좋은 에이전트를 만드는 데 계속 유용할 가능성이 큽니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하네스는 모델의 부족한 점을 보완하기도 하지만, 무엇보다 &lt;strong&gt;모델의 지능을 중심으로 시스템을 설계하여 효율성을 극대화&lt;/strong&gt;하기 때문입니다. 잘 구성된 환경, 적절한 도구, 영구적인 상태, 그리고 검증 루프는 모델의 기초 지능 수준과 상관없이 더 효율적인 에이전트를 만듭니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하네스 엔지니어링은 저희가 LangChain에서 하네스 구축 라이브러리 &lt;a href="https://docs.langchain.com/oss/python/deepagents/overview?ref=blog.langchain.com&amp;amp;_gl=1*1dmk3yc*_gcl_au*MTI0NzU3OTgzNi4xNzc1ODEwMDcy*_ga*NjMwMzc2MzQ2LjE3NzU4MTAwNzM.*_ga_47WX3HKKY2*czE3NzY0MTE2NDQkbzkkZzAkdDE3NzY0MTE2NDQkajYwJGwwJGgw"&gt;&lt;u&gt;deepagents&lt;/u&gt;&lt;/a&gt;를 개선하며 계속 연구하고 있는 매우 활발한 영역입니다. 아래는 저희가 현재 탐색하고 있는 문제들입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;공유 코드베이스 위에서 수백 개의 에이전트가 병렬로 일하도록 오케스트레이션하기&lt;/li&gt;&lt;li style="text-align:justify;"&gt;자기 트레이스를 분석해 하네스 수준의 실패 패턴을 찾아내고 고치는 에이전트&lt;/li&gt;&lt;li style="text-align:justify;"&gt;미리 설정해두는 대신, 주어진 작업에 맞춰 적절한 도구와 컨텍스트를 적시에(just-in-time) 동적으로 조립하는 하네스&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 글은 하네스가 무엇인지 정의하고, 우리가 모델에게 원하는 작업에 따라 하네스가 어떻게 형성되는지 고찰해 보는 과정이었습니다. &lt;strong&gt;모델은 지능을 품고, 하네스는 그 지능을 유용하게 만드는 시스템입니다&lt;/strong&gt;. 더 나은 하네스, 더 나은 시스템, 더 나은 에이전트를 향해.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&amp;lt;원문&amp;gt;&lt;/p&gt;&lt;p&gt;&lt;a href="https://blog.langchain.com/the-anatomy-of-an-agent-harness/"&gt;&lt;u&gt;The Anatomy of an Agent Harness&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>“이걸 누가 관리하나요?” GEO 자동화가 필요한 이유</title><link>https://yozm.wishket.com/magazine/detail/3713</link><description>최근 GEO는 AI 검색 시대의 핵심 전략으로 빠르게 자리 잡고 있습니다. ChatGPT, Gemini, Perplexity와 같은 생성형 AI 서비스는 더 이상 단순히 웹 페이지 링크를 나열하지 않습니다. 대신 사용자의 질문에 대해 직접 “답변 문장”을 생성하며, 이 과정에서 특정 웹 콘텐츠를 인용하여 재구성합니다. 많은 기업이 기존의 SEO뿐만 아니라, GEO를 위한 구조화 정보, 특히 JSON-LD 기반 태그를 활용해 자사 콘텐츠가 AI 답변에 포함되도록 최적화를 시도하고 있습니다. 그러나 실제 서비스 환경에서는 곧 하나의 근본적인 질문과 마주하게 됩니다. “이걸 누가, 어떻게 계속 관리할 것인가?”</description><guid>https://yozm.wishket.com/magazine/detail/3713</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;blockquote&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;GEO가 필요한데, 어떻게 적용할 것인가?&lt;/strong&gt;&lt;/h4&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;최근 GEO(Generative Engine Optimization)는 AI 검색 시대의 핵심 전략으로 빠르게 자리 잡고 있습니다. ChatGPT, Gemini, Perplexity와 같은 생성형 AI 서비스는 더 이상 단순히 웹 페이지 링크를 나열하지 않습니다. 대신 사용자의 질문에 대해 직접 “답변 문장”을 생성하며, 이 과정에서 특정 웹 콘텐츠를 인용하여 재구성합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;이로 따라 많은 기업이 기존의 SEO(Search Engine Optimization)뿐만 아니라, GEO를 위한 구조화 정보, 특히 JSON-LD 기반 태그를 활용해 자사 콘텐츠가 AI 답변에 포함되도록 최적화를 시도하고 있습니다. 그러나 실제 서비스 환경에서는 곧 하나의 근본적인 질문과 마주하게 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;“이걸 누가, 어떻게 계속 관리할 것인가?”&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;정적인 웹 사이트라면 한 번의 작업으로도 어느 정도 유지가 가능하겠지만 포털, 뉴스, 전자상거래, 커뮤니티, SaaS 문서 플랫폼처럼 콘텐츠가 지속적으로 생성되고 수정되며, 때로는 삭제되는 환경에서 웹 페이지마다 지속적으로 구조화 데이터를 관리하는 것이 사실상 불가능합니다.&lt;br&gt;&lt;br&gt;이 글에서는 이러한 문제를 해결하기 위해 현재 사내에서 실험 중인 GEO 자동화 아키텍처를 기반으로, 다음 내용을 알아보고자 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;GEO는 더 이상 전략 문제가 아니라 운영 문제이며, 자동화를 통해 확장할 수 있습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;AI를 활용하면 콘텐츠 분석부터 구조화 데이터 생성까지 전 과정을 자동화할 수 있습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;CDN 엣지와 서버리스(Serverless)를 결합하면 서비스 수정 없이 GEO를 적용할 수 있습니다.&lt;/li&gt;&lt;/ul&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;GEO 전략을 실제 서비스에 적용할 때 마주하는 문제&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;GEO 개념 자체는 비교적 명확합니다. AI가 이해하기 쉬운 구조로 콘텐츠를 제공하고, 이를 통해 인용 가능성을 높이는 것입니다. 그러나 이를 실제 서비스에 적용하는 순간, 문제의 본질은 기술이 아니라 운영으로 이동합니다.&lt;br&gt;&lt;br&gt;첫 번째 문제는 &lt;strong&gt;콘텐츠 규모&lt;/strong&gt;입니다. 하루 수십, 수백 개의 페이지가 생성되는 서비스에서는 페이지마다 적절한 구조화 데이터를 작성하는 것이 불가능합니다. 특히 전자상거래 상품 페이지나 뉴스 기사처럼 데이터가 지속적으로 업데이트되는 환경에서는 메타데이터의 최신성을 유지하는 것 자체가 큰 비용으로 이어집니다.&lt;br&gt;&lt;br&gt;두 번째 문제는 &lt;strong&gt;콘텐츠의 다양성&lt;/strong&gt;입니다. 단순 블로그 글이 아니라 상품, 리뷰, FAQ, 기술 문서 등 다양한 형태의 콘텐츠가 존재할 때, 각각에 맞는 스키마 구조를 설계하고 유지하는 것도 쉽지 않습니다. 이는 단순 반복 작업이 아니라 도메인 이해를 요구하는 작업이기 때문입니다.&lt;br&gt;&lt;br&gt;세 번째 문제는 &lt;strong&gt;조직 구조&lt;/strong&gt;입니다. 대부분의 엔터프라이즈 환경에서는 웹 애플리케이션 코드 수정이 매우 엄격하게 통제됩니다. JSON-LD를 추가하는 단순 작업조차도 배포 승인 프로세스를 거쳐야 하며, 이로 따라 GEO 적용 속도는 조직 구조에 의해 제한됩니다.&lt;br&gt;&lt;br&gt;네 번째 문제는 &lt;strong&gt;효과 측정&lt;/strong&gt;입니다. 기존 SEO는 클릭 수, 클릭 확률, 순위 등 명확한 지표가 존재했습니다. 그러나 GEO는 “인용”이라는 새로운 지표를 중심으로 움직이며, 이는 정량화하기 어렵고 플랫폼별로 측정 방식도 다릅니다.&lt;br&gt;&lt;br&gt;결국 GEO는 “어떻게 잘 만들 것인가”보다 “어떻게 지속적으로 운영하고 개선할 것인가”가 더 중요한 문제로 전환됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;AI 기반 구조화 데이터 생성 파이프라인&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;위에서 언급한 문제의 해결을 위해 사내에서는 AI를 활용한 GEO 자동화 파이프라인을 실험적으로 구축하고 있습니다. 핵심 아이디어는 사람이 직접 GEO 태그를 작성하는 대신, AI가 콘텐츠를 읽고 구조화 데이터를 자동으로 생성하도록 만드는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3713/image2.png"&gt;&lt;figcaption&gt;GEO를 위한 태그 생성 및 제공 프로세스 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;먼저 GEO 태그 생성 프로세스는 크게 네 단계로 구성됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;첫 번째는 &lt;strong&gt;콘텐츠 수집 단계&lt;/strong&gt;입니다. CMS, 내부 API, 혹은 HTML 크롤링을 통해 웹 페이지의 본문 자료를 수집합니다. 이때 중요한 것은 단순 HTML이 아니라 “의미 있는 텍스트”를 추출하는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;두 번째는&lt;strong&gt;크롤링한 콘텐츠의 클렌징 및 MD 형식으로의 변환 단계&lt;/strong&gt;입니다. HTML 내의 광고, 내비게이션, 불필요한 태그 등을 제거하고 LLM이 이해하기 쉬운 형태로 데이터를 변환합니다. 이 단계는 결과 품질에 매우 큰 영향을 미치면서도 사용하는 사용할 소비 토큰을 줄여주는 효과도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;세 번째는 &lt;strong&gt;AI 분석 단계&lt;/strong&gt;입니다. AI 모델은 MD 파일을 분석하여 제목, 작성자, 발행일, 핵심 주제, 키워드, 엔티티 등을 추출합니다. 특히 엔티티 추출은 GEO에서 매우 중요한 역할을 하며, 이는 AI가 콘텐츠를 “지식 단위”로 이해하는 데 도움을 줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;네 번째는 &lt;strong&gt;구조화 데이터 생성 단계&lt;/strong&gt;입니다. 추출된 정보를 기반으로 schema.org 표준에 맞는 JSON-LD를 생성하고, 이를 CDN 엣지 플랫폼 내의 KV 스토어 데이터베이스에 저장합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;다음은 특정 페이지 내용을 태그 생성 프로세스를 통해 저장한 JSON-LD의 예제 일부입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;{
  "@context": "https://schema.org",
  "@graph": [

    {
      "@type": "WebSite",
      "@id": "https://learn-ai.brandonkang.org/#website",
      "url": "https://learn-ai.brandonkang.org/",
      "name": "Learn AI",
      "description": "Learn AI is a practical knowledge hub covering AI fundamentals, large language models, GPU infrastructure, inference optimization, and Kubernetes-based AI systems.",
      "inLanguage": "en",
      "publisher": {
        "@id": "https://learn-ai.brandonkang.org/#person"
      }
    },

    {
      "@type": "Person",
      "@id": "https://learn-ai.brandonkang.org/#person",
      "name": "Brandon Kang",
      "url": "https://learn-ai.brandonkang.org/",
      "jobTitle": "Technical Solutions Architect",
      "knowsAbout": [
        "Artificial Intelligence",
        "Large Language Models",
        "GPU Computing",
        "AI Inference",
        "Kubernetes",
        "Cloud Infrastructure"
      ]
    },
…&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서 중요한 사항은 “완벽성”이 아니라 “일관성”입니다. 일부 필드가 완벽하지 않더라도, 모든 페이지에 일정 수준의 구조화 데이터가 지속적으로 제공되는 것이 GEO 관점에서는 훨씬 더 중요합니다. 또한 이 파이프라인은 이벤트 기반 혹은 주기적 배치 방식으로 동작하여, 콘텐츠가 업데이트될 때 자동으로 메타데이터가 재생성됩니다. 이는 GEO를 단발성 작업이 아닌 데이터 파이프라인으로 전환하는 핵심 요소입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;CDN 엣지 기반 GEO 자동 삽입 아키텍처&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이제 위에서 생성한 데이터를 실제 사용자에게 전달되는 HTML에 포함하는 GEO 태그 제공 프로세스가 필요합니다. 많은 기업에서는 원본 웹 서버나 CMS를 자주 수정하는 것이 쉽지 않습니다. 최종 테스트 및 검수와 배포 프로세스를 지켜야 하기 때문입니다. 그래서 CDN 플랫폼을 활용한 쉬운 배포 방식을 선택했습니다. 사실 이 방식 때문에 동일한 CDN의 엣지에 배포된 KV 스토어를 사용하여 데이터 이동 시간을 최소화한 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AI 에이전트가 웹 페이지를 요청하면 CDN 엣지 서버에서 구동하는 서버리스 함수는 원본 HTML 응답을 가로채고, 사전에 생성된 JSON-LD 데이터를 가져와 해당 페이지의 &amp;lt;head&amp;gt; 태그 내 삽입하여 최종 전달합니다. 아래는 그 과정을 수행하는 함수 예제입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;#rewrite.js
import { HtmlRewritingStream } from 'html-rewriter';
import { httpRequest } from 'http-request';
import { createResponse } from 'create-response';
import { EdgeKV } from 'edgekv';

export async function responseProvider(request) {

  // 1. 원본 HTML 요청
  let htmlResponse = await httpRequest(request);
  if (!htmlResponse.ok) {
    return createResponse(500, {}, `Failed to fetch doc: ${htmlResponse.status}`);
  }

  // 2. EdgeKV 초기화
  const edgeKv = new EdgeKV({
    namespace: "geo",
    group: "jsonld"
  });

  // 3. URL → key
  const url = new URL(request.url);
  const key = url.pathname.replace(/\/$/, "") || "/";

  let jsonLd = null;

  try {
    jsonLd = await edgeKv.getText({ item: key });
  } catch (e) {
    jsonLd = null;
  }

  let rewriter = new HtmlRewritingStream();
  let injected = false;

  // 4. 기존 JSON-LD 체크 (중복 방지)
  rewriter.onElement('script[type="application/ld+json"]', el =&amp;gt; {
    injected = true;
  });

  // 5. &amp;lt;head&amp;gt;에 GEO 블록 삽입
  rewriter.onElement('head', el =&amp;gt; {
    if (!injected &amp;amp;&amp;amp; jsonLd) {
      el.append(`
        &amp;lt;!-- GEO / Structured Data --&amp;gt;
        &amp;lt;script type="application/ld+json"&amp;gt;${jsonLd}&amp;lt;/script&amp;gt;
      `);
    }
  });

  // 6. 응답 반환
  return createResponse(200, {}, htmlResponse.body.pipeThrough(rewriter));
}

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이렇게 수정된 HTML은 짧은 주기 동안 CDN 캐시에 저장되어 다음 AI 에이전트의 요청부터는 별도의 삽입 과정 없이 빠르게 전달됩니다. 원본 콘텐츠가 변경되는 경우 어차피 웹 사이트 관리자는 CDN 캐시를 무력화하는 명령을 수행하기에 새로운 GEO 태그가 적용될 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3713/image3.png"&gt;&lt;figcaption&gt;최종적으로 페이지에 적용된 JSON-LD 태그&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 방식의 가장 큰 장점은 원본 시스템을 전혀 수정하지 않고, 사용자 주변에 가장 가까운 곳에 위치한 CDN에서 모든 작업을 수행한다는 점입니다. 결과적으로 원본 서버의 애플리케이션 코드, CMS, 데이터베이스에 영향을 주지 않으면서 GEO를 적용할 수 있습니다. 오히려 사용자와 가까운 위치에서 캐싱된 응답이 전달되기에 체감 성능이 개선되는 경우도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;이 접근은 GEO를 “콘텐츠 레벨”이 아니라 “플랫폼 레벨”에서 적용하는 방식이라고 볼 수 있습니다. 즉, 웹 사이트 개발팀이 아니라 인프라팀에서 GEO 태그를 통제할 수 있게 되는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;GEO 적용 이후 무엇을 확인해야 하는가?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;GEO를 적용한 이후 가장 중요한 질문은 “그래서 효과가 있는가?”입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3713/image1.png"&gt;&lt;figcaption&gt;GEO 적용 이후 구글 사이트에서의 테스트 예제 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;현재 프로토타입에서는 이를 검증하기 위해 세 가지 관점에서 자료를 수집하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;첫 번째는 &lt;strong&gt;크롤링 패턴&lt;/strong&gt;입니다. AI 에이전트들이 어떤 페이지에 얼마나 자주 접근하는지를 CDN 로그 기반으로 분석합니다. 이는 AI가 어떤 콘텐츠를 “관심 있게 보는지”를 간접적으로 보여줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;두 번째는 &lt;strong&gt;인용 여부&lt;/strong&gt;입니다. 특정 질문에 대해 AI가 자사 콘텐츠를 실제로 인용하는지를 반복적으로 테스트합니다. 이는 기존 SEO의 순위 확인과 유사하지만, 훨씬 더 실험적인 접근이 필요합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;세 번째는 &lt;strong&gt;사용자 행동 변화&lt;/strong&gt;입니다. AI 기반 유입이 실제 트래픽 증가나 브랜드 인지도 향상으로 이어지는지를 분석합니다. 특히 AI 답변을 통한 간접 유입은 기존 분석 도구로는 포착하기 어려운 경우도 많아, 새로운 지표 설계가 필요합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;br&gt;&lt;strong&gt;JSON-LD가 전부는 아니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;한 가지 중요한 사항은 GEO 태그가 적용되었다고 해서 반드시 AI 검색 결과에 바로 반영되는 것은 아니라는 점입니다. 구조화 데이터는 중요한 정보지만, 실제 AI 답변 생성 과정에서는 그것만으로 인용 여부가 결정되지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;특히 많은 조직에서 GEO를 “JSON-LD를 잘 넣는 작업”으로 이해하는 경우가 있는데, 구조화 데이터는 콘텐츠의 의미를 명확하게 전달하는 데 도움을 주는 보조적인 신호일 뿐이며, AI가 실제로 인용할지를 결정하는 핵심 요소는 결국 콘텐츠 자체입니다. 검색 엔진의 AI는 구조화 데이터보다도 본문에 포함된 정보의 명확성, 질문과의 직접적인 연관성, 그리고 문장의 재사용 가능성을 더 중요하게 판단합니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반대로 생각해 보면, 구조화 데이터가 다소 부족하더라도, 특정 질문에 대해 명확하게 답하는 문장이 잘 정리되어 있고, 콘텐츠의 구조가 논리적으로 구성되어 있다면 AI는 해당 콘텐츠를 충분히 활용할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3713/image4.png"&gt;&lt;figcaption&gt;AEO, GEO 적용을 위한 모범 사례 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 중요한 것은 “AI가 이해하기 쉬운 콘텐츠를 만드는 것”입니다. 구조화 데이터는 그 과정을 돕는 도구일 뿐이며, 이를 과도하게 의존하기보다는 콘텐츠 자체의 품질과 구조를 먼저 설계하는 접근이 필요합니다. 이러한 구조를 고려하면, GEO에서 구조화된 메타데이터는 “필수 조건”이 아니라 “가속 장치”에 가깝습니다. 구조화 데이터가 잘 되어 있으면 AI가 콘텐츠를 더 빠르고 정확하게 이해할 수 있지만, 결국 인용 여부를 결정하는 것은 콘텐츠 자체의 품질과 맥락 적합성입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결과적으로 GEO는 더 이상 엔지니어링 팀만의 영역이 아닙니다. 구조화 데이터를 적용하는 기술적인 작업을 넘어, 웹 콘텐츠를 기획하고 작성하는 단계부터 AI가 이해하기 쉬운 형태로 정보를 구성하는 것이 중요해졌습니다. 즉, 콘텐츠 제작자 역시 GEO가 선호하는 정보 구조와 서술 방식, 그리고 문맥(Context)을 고려해야 하는 시대가 된 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이는 단순히 키워드를 잘 배치하는 수준을 넘어, 질문에 직접적으로 답할 수 있는 문장 구조, 명확한 정보 단위, 그리고 AI가 재사용하기 쉬운 콘텐츠 형태를 만드는 방향으로 콘텐츠 전략 자체가 변화하고 있음을 의미합니다. 좀 더 자세한 내용은 기존 요즘IT 글 “&lt;a href="https://yozm.wishket.com/magazine/detail/3654/"&gt;&lt;u&gt;AI 시대 콘텐츠 생존 전략: GEO를 위한 SIFT 프레임워크&lt;/u&gt;&lt;/a&gt;”를 참고하시기 바랍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;GEO는 이제 콘텐츠 전략을 넘어선 플랫폼 전략&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AI 검색 환경에서는 어떤 콘텐츠가 “검색되는가”가 아니라, 어떤 콘텐츠가 “인용되는가”가 더 중요한 시대가 되었습니다. 콘텐츠 규모가 커질수록 이를 수작업으로 관리하는 방식은 한계를 가질 수밖에 없습니다. 따라서 앞으로 기업이 고민해야 할 질문은 GEO를 어떻게 자동화하고 운영할 것인가로 바뀔 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;본문에서 소개한 AI 기반 콘텐츠 분석, 서버리스 컴퓨팅, CDN 엣지 아키텍처를 결합한 접근은 이러한 문제를 해결할 수 있는 현실적인 방법 중 하나입니다. 이러한 흐름에 맞춰 구조화 데이터 생성, 콘텐츠 최적화, AI 인용 분석을 자동화하는 전문 도구와 서비스들이 속속 등장하고 있으며, GEO를 하나의 운영 체계로 관리하려는 시도도 점점 늘어나고 있습니다. 앞으로는 단순히 콘텐츠를 잘 만드는 것을 넘어, AI가 이해하고 활용하기 좋은 형태로 콘텐츠를 설계하고 이를 지속적으로 최적화하는 역량이 기업 경쟁력의 중요한 기준이 될 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>4계층 문서 체계로 만드는 AI Driven 쿠버네티스 운영 표준</title><link>https://yozm.wishket.com/magazine/detail/3710</link><description>바이브 코딩(Vibe Coding)이 자연어로 코드를 생성하는 것이라면, 바이브옵스(VibeOps)는 자연어로 인프라를 운영하는 것입니다. 실제로 진행한 대규모 인프라 변경 프로젝트에서 AI 코파일럿인 Claude Code를 열심히 활용하며 발견한 문제들과 이를 해결하기 위해 자연스럽게 만들어진 4계층 문서 체계(Four-Layer Document Architecture)와 Command Guardrails 패턴을 소개할 예정입니다. 이 구조는 처음부터 설계된 것이 아닙니다. AI와 함께 일하면서 부딪힌 한계를 하나씩 보완한 결과물입니다. AI에게 단순히 명령을 시키는 것이 아니라, AI가 올바르게 행동하도록 구조를 설계하는 방법에 대해 말해 보겠습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3710</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;바이브 코딩&lt;span style="color:#757575;"&gt;(Vibe Coding)&lt;/span&gt;이 자연어로 코드를 생성하는 것이라면, 바이브옵스&lt;span style="color:#757575;"&gt;(VibeOps)&lt;/span&gt;는 자연어로 인프라를 운영하는 것입니다. &lt;a href="https://yozm.wishket.com/magazine/detail/3325/"&gt;이전 글&lt;/a&gt;에서 바이브옵스의 기본 개념과 제미나이 CLI, 클로드 코드를 활용한 기본적인 사용법을 다뤘는데, 이번 글에서는 조금 다른 이야기를 해보려고 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실제로 진행한 대규모 인프라 변경 프로젝트에서 AI 코파일럿인 Claude Code를 열심히 활용하며 발견한 문제들과 이를 해결하기 위해 자연스럽게 만들어진 &lt;strong&gt;4계층 문서 체계&lt;/strong&gt;&lt;span style="color:#757575;"&gt;(Four-Layer Document Architecture)&lt;/span&gt;와 &lt;strong&gt;Command Guardrails 패턴&lt;/strong&gt;을 소개할 예정입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 구조는 처음부터 설계된 것이 아닙니다. AI와 함께 일하면서 부딪힌 한계를 하나씩 보완한 결과물입니다. 따라서 누구나 자신의 환경에서 점진적으로 도입할 수 있다는 것이 핵심입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;AI에게 단순히 명령을 시키는 것이 아니라, AI가 올바르게 행동하도록 구조를 설계하는 방법&lt;/strong&gt;에 대해 말해 보겠습니다.&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;문제 인식: 제한된 리소스의 제약&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;앞서도 저는 이와 유사한 프로젝트를 진행한 적이 있습니다. 24시간 무중단으로 운영하는 중요한 플랫폼의 대규모 변경 작업이었습니다. V1에서 V2로 넘어가는 차세대 프로젝트로 예정된 일이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기에 제약 조건까지 있었습니다. 리소스가 제한적이어서 &lt;strong&gt;DevOps/SRE 1명이 DEV와 PROD를 동시에 구축&lt;/strong&gt;할 뿐만 아니라 운영에 필요한 모든 요소의 배포 설정을 진행해야 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;쿠버네티스 기반의 플랫폼이었기 때문에, 할 일로는 다수의 노드와 수백 개의 파드, 다수의 Helm 릴리스에 Kafka, Redis 같은 데이터 계층의 전환, 옵저버빌리티 스택 전체 재구축, 수십 개의 알림 규칙과 알림 경로까지 포함되어 있었습니다. 단순 복제가 아니라 아키텍처 현대화를 포함하는 전면 재설계 작업이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;전통적 접근의 한계&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;전통적인 DevOps/SRE 워크플로우는 Wiki를 읽고, 터미널에서 수작업을 하고, 결과를 다시 Wiki에 기록하는 순서로 진행됩니다. 그런데 여기에는 문제가 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;IaC&lt;span style="color:#757575;"&gt;(Infrastructure as Code)&lt;/span&gt;는 선언적이지만 상황에 따른 판단은 하지 못합니다. 한편 Runbook은 상황마다 달라서 그대로 실행하기 어렵고, 자동화 스크립트는 그 자체의 유지보수가 또 다른 부담이 됩니다. 그래서 이런 질문을 던졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;만약 runbook을 이해하고, 상황에 맞게 판단하고, 실행까지 하는 동료가 있다면 어떨까?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그에 대한 답으로 Claude Code를 전면에 활용하기로 결정했습니다. 규모가 큰 프로젝트라서 AI를 쓴 것이 아니라 &lt;strong&gt;제한된 리소스라는 제약 속에서 AI를 동료로 삼는 방법을 찾아야 한 것&lt;/strong&gt;입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;4계층 문서 체계의 탄생&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이러한 협업을 위해 만든 4계층 문서 체계는 처음부터 설계된 것이 아닙니다. 단계마다 AI의 한계를 발견하고, 그 한계를 보완하기 위한 계층을 하나씩 추가하면서 자연스럽게 진화한 결과입니다. 각 계층이 왜 필요해졌는지를 순서대로 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;Layer 1: work-plans, 사람이 읽는 계획서&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;가장 먼저 만든 것은 사람이 읽고 판단하기 위한 상세 계획서입니다. 한국어로 쓰며, 각 컴포넌트의 Why, How, 트레이드오프를 문서화합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-plaintext"&gt;work-plans/
├── 00-main/&amp;nbsp;             # 마스터 플랜 + DEV/PROD 런북
├── 10-infrastructure/&amp;nbsp;   # EKS, 스토리지, AWS 연동
├── 20-platform/&amp;nbsp;         # Prometheus, Loki, Tempo, ArgoCD
├── 30-data/&amp;nbsp;             # Valkey, Kafka, Kafka Streams
├── 40-transition/&amp;nbsp;       # 무중단 전환, Weighted Routing
└── 90-future-projects/&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 문서를 AI에게 그대로 주면 어떻게 될까요? 너무 길고, 맥락이 많고, 한국어와 영어가 섞여 있으니, AI가 핵심을 놓치거나 엉뚱한 부분에 집중하는 현상이 발생했습니다. &lt;strong&gt;사람이 보는 문서와 AI가 보는 문서는 달라야 한다는 것을 깨달았습니다.&lt;/strong&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;Layer 2: claude-context, AI를 위해 증류한 문서&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;그래서 work-plans의 핵심만을 영어로, 최소한 증류(distill)한 문서를 만들었습니다. AI가 프로젝트 상태를 즉시 파악하는 대시보드 역할을 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-plaintext"&gt;claude-context/
├── 00-project-summary.md     # 프로젝트 1페이지 요약
├── 01-environment-values.md&amp;nbsp; # 모든 환경 값 (복붙 가능)
├── 02-document-map.md&amp;nbsp;       # 문서 네비게이션 맵
├── 03-current-status.md&amp;nbsp;     # 현재 배포 상태 (라이브)
└── 99-execution-guide.md     # 실행 순서 + 체크리스트&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;work-plans가 교과서라면 claude-context는 시험 범위 요약노트에 가까운 느낌입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 여전히 문제는 있었습니다. AI가 맥락은 이해하는데, 실행할 때 자기 나름대로 명령어를 만들어냈습니다. 예를 들어 “Loki 설치해줘”라고 하면 AI가 &lt;code&gt;helm install&lt;/code&gt; 명령을 자체 생성하는데, 버전이 다른데다 values는 누락되고 네임스페이스가 틀리는 일까지 발생했습니다. &lt;strong&gt;AI가 이해하는 것과 올바르게 실행하는 것은 다른 문제였습니다.&lt;/strong&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;Layer 3: command-guardrails, AI의 행동 제어&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이 계층이 이 글의 핵심인 Command Guardrails 패턴입니다. 각 파일은 단계별 실행 가이드로, 마크다운 안에 bash 블록을 포함하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-plaintext"&gt;command-guardrails/
├── dev/
│   ├── 00-prerequisites/&amp;nbsp;   # KMS, S3, EFS
│   ├── 10-infrastructure/   # EKS, 노드그룹, 애드온
│   ├── 20-platform/         # Helm (Prometheus, Loki...)
│   ├── 30-data/             # Valkey, Kafka
│   ├── 40-transition/       # 알림, 도메인, 트래픽 전환
│   └── 80-rollback/         # 롤백 절차
└── prod/
    └── (동일 구조, PROD 값 + DEV 교훈 반영)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;핵심 설계 원칙은 이렇게 잡았습니다. 기존 V1을 보호하며, get, describe, logs만 허용하고, 순서를 00에서 10, 20, 30, 40으로 강제합니다. 즉, &lt;strong&gt;AI 시대의 인프라 문서는 사람이 읽는 문서가 아니라, AI가 실행하는 문서라고 정의한 것&lt;/strong&gt;입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 문제는 하나 더 있었습니다. Guardrail에 helm upgrade prometheus-stack만 적으면 AI가 &lt;code&gt;--set&lt;/code&gt; 플래그를 창의적으로 만들어냈습니다. 경우의 수가 폭발하니 재현할 수 없는 배포가 되었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;Layer 4: helm-values, IaC에 가까워진 계층&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이 계층은 실제 사고를 2건 겪고 나왔습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;사고 1: Mimir 버전 업그레이드&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;guardrail 문서에 helm upgrade mimir만 적고 --version을 지정하지 않은 일이 있었습니다. AI는 지시를 그대로 실행했고, chart 5.8.0 환경에서 최신 6.0.5로 자동 업그레이드가 됐습니다. Mimir 6.0에는 Kafka 기반 ingest storage 기본 활성화, Nginx 제거 후 Unified Gateway 교체, Rollout-operator 웹훅 기본 활성화라는 세 가지 breaking change가 있어서 기존 5.x의 --set 값들이 6.x 스키마와 맞지 않으면서 ingester, distributor 파드가 전부 CrashLoopBackOff에 빠졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이에 맞춰 다시 6.0으로 올리려면 ingest storage 구성, gateway 마이그레이션, CRD 사전 설치까지 한꺼번에 해야 하는데, 1인 DevOps/SRE가 DEV+PROD 동시 구축하는 상황에서 감당할 수준이 아니었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 helm rollback으로 복구한 다음 5.8.0으로 버전을 고정하고 진행했습니다. 이 사고에서 얻은 교훈이 Layer 4입니다. --version 5.8.0, -f helm-values/mimir.yaml로 버전도 값도 파일로 고정해서 AI에게 해석의 여지를 없앴습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;사고 2: 알림 규칙의 false alarm&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;AI에 “CPU 사용률 80% 넘으면 알림 만들어줘”라고 지시했더니, Grafana alert rule의 &lt;code&gt;relativeTimeRange&lt;/code&gt;을 600초&lt;span style="color:#757575;"&gt;(쿼리 범위 10분)&lt;/span&gt;, for를 5분&lt;span style="color:#757575;"&gt;(조건 지속 시간)&lt;/span&gt;으로 설정했습니다. 10분 범위 안에 순간 스파이크가 하나만 찍혀도 조건이 충족되고, 그 스파이크가 윈도우 안에 남아 있는 동안 5분이면 바로 firing이 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;배포 직후 파드 스케일링 때마다 CPU가 잠깐 튀면서 새벽에도, 배포할 때도 알림이 울렸습니다. 게다가 AI가 같은 패턴으로 알람을 생성했기 때문에, 7개 규칙이 전부 같은 문제를 가지고 있었습니다. 문제를 해결하기 위해 &lt;code&gt;relativeTimeRange&lt;/code&gt;을 300초로 줄이고, for를 10분으로 늘리고, 쿼리를 &lt;code&gt;avg_over_time&lt;/code&gt;으로 바꿔서 수정했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서 얻은 교훈은, 알림 파라미터도 Guardrail 본문에 쓰면 안 된다는 겁니다. AI는 합리적으로 보이는 값을 만들어내지만, 그게 운영 환경에서 맞는지는 별개 문제이기 때문입니다. 그래서 알림 임계값, 평가 주기, for 기간 같은 파라미터를 전부 helm-values 파일로 빼서 관리하게 됐습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;최종적으로 helm 명령어는 다음과 같은 형태가 되었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-plaintext"&gt;helm upgrade loki grafana/loki \
  --version 6.30.0 \&amp;nbsp;       # 버전 고정
  -f helm-values/loki.yaml \ # 값 고정 (IaC)
  -n monitoring \&amp;nbsp;           # 네임스페이스 고정
  --wait --timeout 10m       # 동작 고정&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이렇게 4개의 계층이 완성되었습니다. 정리하면 위에서 아래로 갈수록 추상에서 구체로, 자유도는 감소하되 재현성은 증가하는 구조입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3710/image1.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;Tip. 왜 AI를 위한 문서는 영어로 증류해야 하는가&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;4계층 체계에서 주목할 점 가운데 하나는 Layer 2&lt;span style="color:#757575;"&gt;(claude-context)&lt;/span&gt;가 영어로 작성된다는 것입니다. 이는 단순히 AI가 영어를 더 잘 이해하기 때문만은 아닙니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;첫째, &lt;strong&gt;토큰 효율성&lt;/strong&gt; 문제입니다. 한국어는 영어 대비 동일한 내용을 표현하는 데 더 많은 토큰을 소비합니다. Claude Code의 컨텍스트 윈도우는 유한하기 때문에, 같은 정보를 더 적은 토큰으로 전달하는 영어가 효율적입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;둘째, &lt;strong&gt;기술 용어의 일관성&lt;/strong&gt; 문제입니다. 쿠버네티스 생태계의 용어는 대부분 영어 기반입니다. “노드그룹”과 “nodegroup”, “네임스페이스”와 “namespace”가 혼재되면 AI가 매칭에 실패하는 경우가 있습니다. AI가 읽을 문서에서 기술 용어를 영어로 통일하면 이러한 혼선을 방지할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;셋째, &lt;strong&gt;명령어와의 직접 연결&lt;/strong&gt;입니다. AI가 context 문서를 읽고 바로 셸 명령어를 생성해야 하는데, 한국어 설명에서 영어 명령어로 전환하는 과정에서 오류가 발생할 확률이 높습니다. 영어로 작성된 context는 명령어 생성까지의 경로를 짧게 만들어 줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 이러한 제약으로, 모든 문서를 영어로 써야 한다는 의미는 아닙니다. Layer 1&lt;span style="color:#757575;"&gt;(work-plans)&lt;/span&gt;은 사람이 의사결정을 위해 읽는 문서이므로 한국어가 적합합니다. 즉, &lt;strong&gt;“누가 읽느냐”에 따라 언어를 구분하는 것&lt;/strong&gt;이 핵심입니다.&lt;/p&gt;&lt;hr&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;CLAUDE.md: AI가 가장 먼저 읽는 행동 규칙&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;4계층 문서 체계 외에 한 가지 더 중요한 요소가 있습니다. 바로 &lt;strong&gt;CLAUDE.md&lt;/strong&gt; 파일입니다. 이 파일은 Claude Code가 프로젝트 디렉터리에 진입했을 때 가장 먼저 읽는 파일로, AI의 행동 규칙&lt;span style="color:#757575;"&gt;(Ground Rules)&lt;/span&gt;을 정의합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;a href="https://yozm.wishket.com/magazine/detail/3334/"&gt;이전 글&lt;/a&gt;에서 제미나이 CLI의 GEMINI.md를 다룬 적이 있는데, CLAUDE.md도 동일한 역할을 합니다. 차이가 있다면 4계층 문서 체계와 결합되어 더 구조적으로 동작한다는 점입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;예를 들어, 실제 운영 환경에서 사용되는 CLAUDE.md는 다음과 같은 규칙을 포함합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-plaintext"&gt;# Ground Rules

## 허용되는 명령어
- kubectl get / describe / logs 만 허용
- helm list / helm status 만 허용

## 금지되는 명령어
- kubectl delete / apply / patch 금지
- helm install / upgrade / uninstall 금지

## 문서 참조 순서
1. memory/MEMORY.md를 먼저 읽을 것
2. claude-context/에서 현재 상태 파악
3. command-guardrails/에서 실행 가이드 확인
4. guardrail에 없는 명령은 실행하지 말 것&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이렇게 적어 두면 AI가 자기 마음대로 명령어를 만들어내는 것을 막을 수 있습니다. 특히 &lt;strong&gt;“guardrail에 없는 명령은 실행하지 말 것”&lt;/strong&gt;이라는 규칙이 중요한데, 이는 AI가 할 수 있는 행동의 범위를 명확하게 제한해 줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;settings.local.json&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;여기에 더해서 &lt;strong&gt;.claude/settings.local.json&lt;/strong&gt;을 설정하면 V1 보호를 도구 수준에서 강제할 수 있습니다. CLAUDE.md가 자연어로 된 규칙이라면, settings.local.json은 실제로 명령어 실행 자체를 허용하거나 차단하는 설정입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-plaintext"&gt;{
  "permissions": {
    "allow": [
      "Bash(kubectl --context=sysnet4admin-v1 get *)",
      "Bash(kubectl --context=sysnet4admin-v1 describe *)",
      "Bash(kubectl --context=sysnet4admin-v1 logs *)",
      "Bash(kubectl --context=sysnet4admin-v2 *)",
      "Bash(helm --kube-context=sysnet4admin-v2 *)",
      "Bash(aws * --profile sysnet4admin *)",
      "Bash(eksctl * --profile sysnet4admin *)"
    ],
    "deny": [
      "Bash(kubectl --context=sysnet4admin-v1 apply *)",
      "Bash(kubectl --context=sysnet4admin-v1 delete *)",
      "Bash(kubectl --context=sysnet4admin-v1 patch *)",
      "Bash(kubectl --context=sysnet4admin-v1 edit *)",
      "Bash(kubectl --context=sysnet4admin-v1 scale *)",
      "Bash(kubectl --context=sysnet4admin-v1 exec *)",
      "Bash(helm --kube-context=sysnet4admin-v1 install *)",
      "Bash(helm --kube-context=sysnet4admin-v1 upgrade *)",
      "Bash(helm --kube-context=sysnet4admin-v1 uninstall *)",
      "Bash(helm --kube-context=sysnet4admin-v1 delete *)"
    ]
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;V1&lt;span style="color:#757575;"&gt;(sysnet4admin-v1)&lt;/span&gt;에는 &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;describe&lt;/code&gt;, &lt;code&gt;logs&lt;/code&gt;만 허용하고, &lt;code&gt;apply&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;, &lt;code&gt;patch&lt;/code&gt; 같은 변경 명령은 전부 차단합니다. 반면 V2&lt;span style="color:#757575;"&gt;(sysnet4admin-v2)&lt;/span&gt;에는 모든 명령을 허용해서 자유롭게 작업할 수 있도록 합니다. 이렇게 하면 CLAUDE.md에서 자연어로 안내하는 규칙을 설정 파일이 실제로 강제하게 되므로, AI가 실수로라도 V1 프로덕션에 변경을 가하는 것을 방지할 수 있습니다.&lt;/p&gt;&lt;hr&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;4계층 문서에 기반한 운영 전략과 도입 방법&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이처럼 계층 문서 기반으로 인프라 관리에 접근하다 보니 다양한 변화를 만날 수 있었습니다. AI와 함께 일하며 확장할 수 있는 방향성과 실제 도입 과정에서 느낀 것을 정리했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1. GitAIOps&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이렇게 만들어진 4계층 문서 체계를 Git으로 관리하면 재미있는 부분이 생깁니다. AI를 위해 만든 문서가 동시에 팀 전체의 운영 표준이 되는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3710/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2026-04-14_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_2_20_53.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 개념을 &lt;strong&gt;GitAIOps&lt;/strong&gt;라고 부릅니다. GitOps가 선언적 인프라에서 Git을 Single Source of Truth로 삼는 것이라면, GitAIOps는 여기에 AI가 문서를 이해하고 실행하는 계층을 추가한 것입니다. 누가 실행해도 같은 결과가 나오니 일관성이 보장되고, 변경 이력이 남으니 감사 추적이 가능합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2. AI에게 맡기는 것의 경계&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;4계층 문서 체계를 구축했다고 해서 모든 것을 AI에게 맡길 수 있는 것은 아닙니다. 오히려 이 체계를 운영하면서 AI에게 맡기기 좋은 것과 사람이 판단해야 하는 것의 경계가 더 명확해졌습니다. 무엇보다 AI는 자동 운전이 아니라 운전 보조라는 것을 잊지 말아야 합니다. &lt;strong&gt;핸들은 사람이 잡되, 사각지대를 AI가 잡아준다&lt;/strong&gt;는 느낌으로 써야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3710/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2026-04-14_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_2_21_05.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3. DEV에서 PROD로: Guardrail 재사용 패턴&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;4계층 체계가 가장 효과적인 부분은 &lt;strong&gt;DEV에서 PROD로 넘어갈 때&lt;/strong&gt;입니다. DEV에서 검증된 Guardrail을 PROD에 재사용할 때, 단순 복사가 아니라 DEV에서의 교훈을 반영하는 것이 핵심입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실제로 PROD Guardrail에는 DEV 교훈이란 섹션이 자동으로 추가됩니다. 예를 들어 DEV에서 Mimir 버전 사고가 있었다면, PROD Guardrail에는 해당 버전 고정에 대한 경고와 함께 검증된 버전 번호가 명시됩니다. DEV 환경 전체 구축에 약 2일이 걸렸다면, 이 Guardrail을 재사용하는 PROD 환경 구축은 약 1일로 단축됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이렇게 Guardrail이 축적되면 재사용할수록 구축 속도가 빨라집니다. 그리고 이 패턴은 쿠버네티스에만 적용되는 것이 아닙니다. Terraform, Ansible 등 어떤 IaC 도구를 사용하더라도 동일한 구조를 적용할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;4. 생산성 변화&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;직접 AI 기반 운영을 도입하니 아래와 같은 생산성 변화가 일어났습니다. &lt;strong&gt;AI가 사람을 대체한 게 아니라, 제한된 리소스의 커버리지를 몇 배로 확장했다는 점&lt;/strong&gt;을 가장 크게 느꼈습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3710/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2026-04-14_%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE_2_21_16.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;5. 조직에 적용할 점진적 도입 로드맵&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이러한 구조를 우리 조직에 한 번에 도입할 필요는 없습니다. 그보다는 단계적으로 조금씩 접근하는 것이 현실적입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Level 0 (1주):&lt;/strong&gt;기존 runbook을 구조화된 마크다운 형식의 문서로 정리합니다. 이것만으로도 문서 가독성이 크게 향상됩니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Level 1 (2~4주):&lt;/strong&gt;Claude Code로 DEV 환경에서 실험을 시작합니다. 이전 바이브옵스 글에서 다룬 것처럼, 먼저 DEV에서 충분히 테스트하는 것이 중요합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Level 2 (1~2개월):&lt;/strong&gt;Context + Guardrails 2계층 체계를 구축합니다. 실제 운영에서 발생하는 문제들을 반영하면서 점진적으로 완성합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Level 3 (지속):&lt;/strong&gt;DEV에서 PROD로의 패턴이 정착되고, helm-values(IaC)가 추가됩니다. 이 단계에서는 guardrail이 팀의 표준 운영 절차(SOP)가 됩니다.&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며: DevOps/SRE의 역할 변화&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이 글에서 다룬 4계층 문서 체계와 Command Guardrails 패턴을 보면, DevOps 엔지니어와 SRE의 역할이 바뀌고 있다는 것을 알 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;전통적인 DevOps/SRE가 kubectl을 직접 실행하는 사람이었다면, AI-Driven DevOps/SRE는 AI가 실행할 가이드를 설계하는 사람입니다. Runbook을 작성하던 역할은 Guardrails를 설계하는 역할로, 수동으로 감사하던 역할은 AI가 감사한 결과를 검증하는 역할로 바뀝니다. 반복 작업을 수행하는 대신 판단과 의사결정에 집중하게 되고, 혼자 환경 하나만 담당하던 것이 혼자 환경 N개를 커버할 수 있게 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AI가 잘하는 것은 최대한 활용하되, 실행에서 틀리지 않도록 구조로 잡아주는 것. 그것이 4계층 문서 체계와 Command Guardrails 패턴이 하는 일이며, 얻어가야 할 교훈입니다.&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;부록 1: AI의 기억 관리를 위한 Memory 시스템&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;4계층 문서 체계를 운영하다 보면 자연스럽게 마주치는 문제가 하나 더 있습니다. Claude Code와 긴 대화를 나누다 보면 컨텍스트 압축(compaction)이 발생한다는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;예를 들어 35개 알림 규칙을 전수 분석해서 P0/P1/P2로 분류했는데, compaction이 발생하면 원본이 사라지고 “P0/P1/P2 분류 완료”라는 요약만 남습니다. 이 상태에서 “P1 항목이 뭐였지?”라고 물으면 AI는 대답할 수 없게 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 문제를 해결하기 위해 4계층과 동일한 원리를 적용한 &lt;strong&gt;memory 시스템&lt;/strong&gt;을 도입했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-plaintext"&gt;memory/
├── MEMORY.md&amp;nbsp;             # 인덱스 (200줄, 자동 주입)
├── alert-gap-analysis.md&amp;nbsp; # 토픽 파일 (필요 시 로드)
├── osd-lessons.md         # 토픽 파일 (필요 시 로드)
└── argocd-lessons.md&amp;nbsp;     # 토픽 파일 (필요 시 로드)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;시스템이 하는 역할은 크게 4가지입니다. compaction에서 살아남는 &lt;strong&gt;맥락 보존&lt;/strong&gt;, “하지 마라”를 축적한 &lt;strong&gt;금지 사항 누적&lt;/strong&gt;&lt;span style="color:#757575;"&gt;(guardrail 보완)&lt;/span&gt;, 대화가 끊어져도 이어지는 &lt;strong&gt;작업 상태 추적&lt;/strong&gt;, 그리고 매 세션마다 재탐색 없이 시작하는 &lt;strong&gt;콜드 스타트 방지&lt;/strong&gt;입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서 중요한 것은 MEMORY.md의 크기 관리입니다. AI 코딩 에이전트에는 200줄을 초과하면 경고 없이 잘려나가는&lt;span style="color:#757575;"&gt;(hard truncation)&lt;/span&gt; 현상이 있고, 오래된 기억은 때로 AI가 잘못된 근거로 판단하는 원인이 됩니다. 실제로 지시 준수율이 200줄 이하에서는 92%인데, 400줄 이상이 되면 71%로 떨어지는 것을 확인했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;따라서 MEMORY.md는 인덱스만 유지하고, 상세 내용은 토픽 파일로 분리합니다. 결국 4계층과 같은 원리입니다. 증류하고, 분리해서, 필요할 때만 로드하기. 이 원칙은 문서 체계뿐 아니라 AI의 기억 관리에도 동일하게 적용됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;부록 2: 옵저버빌리티 감사 데모로 직접 해보기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이 글에서 설명한 구조를 축소해서 직접 체험해볼 수 있는 데모도 준비했습니다. 읽기 전용 감사&lt;span style="color:#757575;"&gt;(Observability Audit)&lt;/span&gt;를 수행하는 구성으로, 4계층 중 실행에 해당하는 부분만 뽑아낸 형태입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-plaintext"&gt;demo/
├── CLAUDE.md&amp;nbsp;                   # AI 행동 규칙
├── claude-context/
│   └── 00-cluster-summary.md&amp;nbsp;   # 클러스터 맥락
├── command-guardrails/
│   └── observability-audit.md   # 실행 가이드
└── memory/
    └── MEMORY.md&amp;nbsp;               # 누적 기억&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;데모를 실행하면 CLAUDE.md에서 READ-ONLY만 허용하고, command-guardrails의 9단계 감사 절차를 AI가 순서대로 실행한 다음, 결과를 Audit Report 형식으로 출력합니다. 실제 감사 리포트 결과와 전체 소스는 &lt;a href="https://github.com/sysnet4admin/talks/tree/main/Byline-Network/2026-ai-era-k8s-cloud-native/demo"&gt;GitHub&lt;/a&gt;에서 확인할 수 있습니다.&lt;/p&gt;&lt;hr&gt;&lt;h4 style="margin-left:0px;text-align:justify;"&gt;&lt;strong&gt;작가&lt;/strong&gt;&lt;/h4&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;&lt;strong&gt;조훈(CNCF 앰버서더)&lt;/strong&gt;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;메가존에서 쿠버네티스와 컨테이너 인프라 Tech Evangelist, CoE(Center of Excellence) 역할을 맡고 있다. 클라우드 네이티브 컴퓨팅 재단(CNCF)의 글로벌 앰버서더, ‘IT 인프라 엔지니어 그룹’의 운영진, 오픈소스 컨트리뷰터로도 활동하고 있다. 인프런/유데미에서 앤서블 및 쿠버네티스에 관한 강의를 하고, 『컨테이너 인프라 환경 구축을 위한 쿠버네티스/도커』, 『우아하게 앤서블』, 『시스템/네트워크 관리자를 위한 파이썬 실무 프로그래밍』을 집필하였으며, 요즘IT와 같은 온라인 플랫폼에 글을 기고한다.&lt;/p&gt;&lt;p style="margin-left:0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;&lt;strong&gt;심근우&lt;/strong&gt;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;LG유플러스 CTO부문에서 대고객 비즈니스 시스템의 DevOps를 담당하는 UcubeDAX팀의 팀장으로 일하고 있다. 퍼블릭 클라우드와 프라이빗 클라우드에 걸친 쿠버네티스 클러스터를 안정적으로 운영하기 위해 노력하고 있으며, 특히 주니어 DevOps 엔지니어들의 육성에 큰 관심을 가지고 있다.&lt;/p&gt;&lt;p style="margin-left:0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;&lt;strong&gt;문성주&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;글로벌 소셜 플랫폼 기업에서 Site Reliability Engineer로 재직하며, 쿠버네티스 멀티 클러스터 관리와 데이터베이스 플랫폼 운영을 주도하고 있다. 또한 ISMS-P, GDPR, CCPA 등 글로벌 보안 규제에 부합하는 데이터 라이프사이클 파이프라인을 설계·운영한 실무 경험을 가지고 있으며, 쿠버네티스 오픈소스 프로젝트에도 기여하고 있다. 더불어 국내 주요 기업과 국가 기관의 클라우드 전환, 데이터 거버넌스 컨설팅, 보안 컴플라이언스 대응을 지원하고 있다.&lt;/p&gt;&lt;p style="margin-left:0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;&lt;strong&gt;이성민&lt;/strong&gt;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;미국 넷플릭스(Netflix) 사의 Data Platform Infrastructure 팀에서 사내 플랫폼 팀들과 데이터 사용자들을 어우르기 위한 가상화 및 도구들을 개발하는 일들을 하고 있다. 과거 컨테이너와 쿠버네티스에 큰 관심을 두고 ingress-nginx를 비롯한 오픈 소스에 참여했으며, 현재는 데이터 분야에 일하게 되면서 stateful 한 서비스들이 컨테이너화에서 겪는 어려움을 보다 근본적으로 해결하기 위한 많은 노력을 하고 있다.&lt;/p&gt;&lt;p style="margin-left:0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>자바 vs. 파이썬: 더 나은 에이전트 개발 언어는?</title><link>https://yozm.wishket.com/magazine/detail/3708</link><description>많은 사람이 생성형 AI 애플리케이션을 구축할 때는 파이썬이 가장 자연스러운 언어라고 잘못 알고 있습니다. 데이터 과학도 아닌데요. 사실 이미 JVM을 사용하고 있다면, JVM에서 생성형 AI를 다루는 것이 당연합니다. 오늘은 LangGraph와 Java로 만든 프레임워크 Embabel을 비교해보려고 합니다. LangGraph는 첫 번째이자, 동시에 가장 인기 있는 파이썬 기반 생성형 AI 프레임워크인 LangChain에서 나온 확장 프레임워크입니다. 이 프레임워크는 정말 Java가 할 수 없는 것들을 할 수 있을까요?</description><guid>https://yozm.wishket.com/magazine/detail/3708</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;&lt;span style="color:#757575;"&gt;본문은 로드 존슨(&lt;/span&gt;&lt;a href="https://www.linkedin.com/in/johnsonroda/"&gt;Rod Johnson&lt;/a&gt;&lt;span style="color:#757575;"&gt;)의 글 &amp;lt;&lt;/span&gt;&lt;a href="https://medium.com/@springrod/build-better-agents-in-java-vs-python-embabel-vs-langgraph-f7951a0d855c"&gt;Build Better Agents in Java vs Python: Embabel vs LangGraph&lt;/a&gt;&lt;span style="color:#757575;"&gt;&amp;gt;를 번역한 글입니다. 로드 존슨은 스프링 프레임워크를 만든 것으로 유명한 개발자죠.﻿ 그는 최근 Embabel이란 프로젝트를 만들고, 에이전트 프레임워크를 개발하고 있습니다. 필자에게 허락받고 번역과 게재를 진행했습니다.&lt;/span&gt;&lt;/p&gt;&lt;hr&gt;&lt;p style="text-align:justify;"&gt;많은 사람이 생성형 AI 애플리케이션을 구축할 때는 파이썬이 가장 자연스러운 언어라고 잘못 알고 있습니다. 데이터 과학도 아닌데요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그러니 이미 JVM을 사용하고 있다면, 사실 JVM에서 생성형 AI를 다루는 것이 당연합니다. 반면 둘 중 어느 쪽도 아니라면, 이제부터 보여드릴 공정한 비교 결과에 어쩌면 놀라워 할 수도 있겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이전 블로그들에서 저는 &lt;a href="https://www.crewai.com/"&gt;CrewAI&lt;/a&gt;와 &lt;a href="https://ai.pydantic.dev/"&gt;Pydantic AI&lt;/a&gt;의 예시를 가져와 Java와 &lt;a href="https://github.com/embabel/embabel-agent"&gt;Embabel&lt;/a&gt;로 다시 구현하면서, 같은 기능을 두고 더 깔끔하고 확장 가능한 코드를 만들어 본 적 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;오늘은 &lt;a href="https://www.langchain.com/langgraph"&gt;LangGraph&lt;/a&gt;의 차례입니다. LangGraph는 첫 번째이자, 동시에 가장 인기 있는 파이썬 기반 생성형 AI 프레임워크인 &lt;a href="https://www.langchain.com/"&gt;LangChain&lt;/a&gt;에서 나온 확장 프레임워크입니다. LangChain의 인기와 LangGraph의 약속은 회사를 주목받는 대상으로 만들었으며, 덕분에 회사는 &lt;a href="https://sacra.com/c/langchain/"&gt;최근 11억 달러의 평가액으로 시리즈 B 투자를 유치&lt;/a&gt;했습니다. 그 프레임워크는 이런 평가대로 정말 Java가 할 수 없는 것들을 할 수 있을까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:50%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image1.png"&gt;&lt;/figure&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;LangGraph 아키텍처&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;LangGraph는 코드를 이용하여 다수 에이전트를 사용하는 업무 프로그램을 구현할 수 있게 합니다. 이 프레임워크는 유한 상태 기계(Finite State Machine)를 사용하여 작업 순서를 정렬합니다. 노드(상태)는 함수이고, 엣지(전이)는 자동으로 결정되거나 함수 호출 결과에 따라 동적으로 결정되기도 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이러한 노드와 엣지들은 긴 흐름을 여러 단계로 나누어 실행을 더 결정론적으로 만들고 작업 흐름을 이해하기 쉽게 만듭니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;무엇보다 상태 기계는 작업 흐름을 정의하는 가장 명확한 방법이므로 이 개념을 가장 먼저 적용한 LangChain이 현재의 시장 위치를 차지하는 것이 놀랄 일은 아닙니다. 빠른 시장 출시에 따른 것이지요. 하지만 이것이 최선의 모델일까요, 아니면 아직 명확히 드러나지 않은 더 나은 해결책이 있을까요? 최근 저희는 여러 번 상태 기계를 구축한 끝에&amp;nbsp; &lt;a href="https://medium.com/@springrod/ai-for-your-gen-ai-how-and-why-embabel-plans-3930244218f6"&gt;목표 지향 행동 계획(GOAP)&lt;/a&gt;을 기반으로 하는 새로운 접근법을 정착시켰습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;때때로 먼저 움직이지 않고 다른 사람들의 성공과 실패에서 배우는 것이 최선일 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;패턴 대결&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;저는 오랫동안 Embabel과 LangGraph 사이의 체계적인 비교를 하고 싶었습니다. 공정을 기하기 위해 제가 만든 예시를 선택하지 않았고, 대신 Hamza Boulahia의 ‘&lt;a href="https://pub.towardsai.net/agentic-design-patterns-with-langgraph-5fe7289187e6?gi=4b6d27acb0b5"&gt;LangGraph 에이전트 디자인 패턴&lt;/a&gt;’에 관한 최근 블로그의 내용을 다시 구현했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;지난 몇 년간 AI 시스템을 구축하면서 배운 것이 있다면 패턴이 중요하다는 사실입니다. 전통적인 소프트웨어를 설계하든 대형 언어 모델(LLM) 에이전트로 실험하든, 작업 흐름을 구성하는 방식이야말로 결과물이 얼마나 견고하고 유연하며 확장 가능한지를 결정합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Boulahia는 6가지 에이전트 디자인 패턴을 시연합니다:&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;프롬프트 사슬 구성&lt;/strong&gt;: 복잡한 일들을 관리할 수 있는 단계로 나누기&lt;/li&gt;&lt;li style="text-align:justify;"&gt;제어 흐름을 위한 &lt;strong&gt;경로 설정&lt;/strong&gt;(routing)과 &lt;strong&gt;병렬화&lt;/strong&gt;&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;리플렉션(Reflection)&lt;/strong&gt;: 에이전트가 결과를 비판적으로 살피고 개선&lt;/li&gt;&lt;li style="text-align:justify;"&gt;외부 시스템과 통합하기 위한 &lt;strong&gt;도구 사용&lt;/strong&gt;&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;계획 수립(Planning)&lt;/strong&gt;: 목적을 명확하게 실행 가능한 순서로 구조화&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;여러 에이전트의 협업&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;각 패턴을 하나씩 살펴보면서 자바 프로그램에서 Embabel을 사용해 표현력을 올리는 방식들을 보여드리겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;프롬프트 사슬 구성&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;프롬프트 사슬 구성은 필수적인 패턴으로 한 모델의 결과가 다른 모델의 입력이 되는 구조입니다. 이렇게 하면 일의 흐름을 예측하기 좋습니다. 이제 다룰 예제에서 에이전트는 사용자 입력을 기반으로 주제를 제안하고 각 주제에 대해 여러 개의 블로그 제목을 생성할 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;LangGraph 구현&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;예제는 LLM을 호출할 때 기본 LangChain API를 사용하며, 작업 흐름 관리를 위해서 LangGraph를 사용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여타 작업 흐름 엔진(workflow engine)처럼 LangGraph를 사용하면 LangChain 만 사용할 때와 달리 프로세스 상태를 유지하기만 해도 좋습니다. 이를 State 클래스로 표현합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;작업 흐름은 노드와 엣지를 통해 정의됩니다. LLM을 호출하는 Python 메서드가 노드가 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image3.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;작업 흐름은 코드로 구현합니다. 노드는 메서드에 매핑되고 엣지가 메서드를 연결합니다. 예제에서 엣지는 간단하게 다음 상태로 전환하게 만듭니다. 작업 흐름이 하드코딩된 문자열로 표현되기 때문에 컴파일 할 때 유효성 검사가 거의 이루어지지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image2.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;작업 흐름의 실행은 아래와 같은 코드로 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image5.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실행한 결과는 다음과 같습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image4.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;Embabel 구현&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;사소한 부분이긴 하지만, 사실 위의 예시 일부는 좋지 않은 설계이기 때문에 이를 그대로 구현하기는 어렵습니다. 특히, 지금의 예시는 도메인에 대한 모델링 부족하다 할 수 있습니다. 파이썬으로 생성형 AI를 다룰 때는 도메인 모델링을 과소평가하는 경향이 있는데, 이는 &lt;a href="https://medium.com/@springrod/context-engineering-needs-domain-understanding-b4387e8e4bf8"&gt;심각한 실수&lt;/a&gt;입니다. State 클래스의 모든 필드는 문자열로 모델링되어 있으므로 구조가 있어야 합니다. 특히 주제를 하나로 문자열로 표현하는 일은 오해를 낳기 쉽습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 문제를 해결하는 형태로 최소한의 변경을 했습니다. 도메인 모델과 행위 그리고 목적으로 표현된 Embabel 구현 방식을 택했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;도메인 객체는 Java 레코드이며, 요구사항에서 암시된 구조를 올바르게 나타냅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image7.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;코드를 좀 더 자세히 해설해 보겠습니다. 우선 @Agent 애노테이션은 클래스가 Spring에 의해 생성되고 주입되며, Embabel이 처리하게 합니다. @Action 메서드는 단계를 나타내고, 목적은 원하는 출력입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Actor 필드는 하이퍼파라미터를 주고 LLM 모델을 선택하는 일과 명령어를 결합합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;extractTopics와 generateBlogTitles 메서드는 LangGraph 노드 메서드에 해당합니다. 그러나 작업 흐름은 매우 다르게 구성되어 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이처럼 Embabel에서는 코드에서 작업 흐름을 지정할 필요가 없습니다. 프레임워크 스스로&amp;nbsp; 코드를 분석하여 실행 경로를 계획합니다.&amp;nbsp; 특히 실행 로직은 타입의 흐름에서 올바른 실행 계획을 추론할 수 있습니다. 예를 들어, 작업 흐름 범위에서 Topics와 BlogTitles 객체를 사용할 수 있어야만 마찬가지로 목적을 달성할 수 있다는 것을 알 수 있습니다. 그에 따라 메서드 호출 순서를 올바르게 결정할 수 있습니다. 이와 같은 계획 단계는 결정론적입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;마지막으로, generateBlogTitles 단계를 병렬 작업으로 모델링하여 요구사항을 더 자연스럽게 반영하고 LLM과의 상호 작용을 더 간결하고 집중력있게 만듭니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;출력 결과는 다음과 같습니다. LangGraph 예제 출력과 달리 요구사항을 정확하게 반영한 구조입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image6.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;비교&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;두 구현 모두 흐름을 작고 초점이 분명한 단계로 나누어 예측을 쉽게 합니다. 다만, Embabel 버전에는 코드가 조금 더 많습니다. 다중성cardinality을 올바르게 모델링하려는 코드가 추가됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그 대신 Embabel 구현은 여러 측면에서 우수하다고 느껴집니다. 먼저, 타입 안전성 측면이 그렇습니다. 오용 가능성이 있는 문자열과 대비되는 제대로 된 도메인 모델이 있어 테스트하기 쉬워집니다. 그리고 추가할 수 있는 구조 때문에 병렬 작업도 가능합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그 외에도 Embabel 구현에서는 사소하지만 LangGraph 보다 나은 몇 가지 개선 사항이 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;LLM 선택과 페르소나 외부화: Embabel과 Spring을 사용하면, Actor 정의를 application.yml 파일로 간단하게 외부화할 수 있습니다. 파이썬에 부족한 복잡한 옵션 구성이 가능합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;주제와 블로그 제목 유지: 적절히 구조화된 도메인 객체가 있기 때문에, 원할 때 쉽게 내용을 유지할 수 있습니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;경로 선택(Routing)&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;또 다른 기본 패턴은 작업 흐름 안에서의 경로 선택입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;LangGraph 구현&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;여기 LangGraph 구현이 있습니다. 먼저 감정 분석을 수행한 다음 응답을 생성하기 위해 적절한 함수를 선택합니다:&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image9.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;LangGraph에서 항상 그렇듯이 작업 흐름은 확인할 수 없는 문자열로 구축됩니다. 예제 코드에서 “classification”에 오타가 났는데, 전부 같이 틀렸기 때문에 다행히 문제는 없습니다. 그래도 이렇게 취약할 때는 타이핑이 매우 중요해집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다음 예시는 함수의 출력을 다음 상태 이름에 매핑하는 식의 더 정교한 LangGraph 상태 전환을 보여주는데, 여기서도 역시 오류가 발생하기 쉬운 마법 문자열이 보너스로 더해집니다:&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image8.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다음과 같은 코드로 이를 실행합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image12.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;Embabel 구현&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;노드와 엣지를 명시적으로 연결하는 일은 이렇게 간단한 일을 너무 복잡하게 만듭니다. 좀 더 자연스러운 방식으로 단계를 표현해 봅시다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이때는 단계가 다르기 때문에 LLM과 관련된 공통 시스템 메시지가 아니라 매번 초점이 맞춰진 프롬프트를 사용할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;먼저 Sentiment의 타입을 만들겠습니다. 이는 흐름을 데이터 타입으로 표현할 수 있게 도와줍니다:&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image10.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이제 우리는 classify 메소드가 Sentiment 객체를 반환 하도록 구현을 시작할 수 있습니다. Embabel은 스스로 Sentiment가 하위 타입을 갖는지 알아차리며,그에 맞춰 적절한 경로를 계획합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;한편 Encourage와&amp;nbsp; help 메소드는 각각 하나의 Sentiment 하위 유형을 취합니다. 파이썬 함수와 마찬지로 LLM을 호출하여 응답을 생성하는 구조입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image11.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;비교&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;Embabel을 이용해 데이터 타입을 통해 실행 경로를 정의하는 것이 LangChain 상태 머신보다&amp;nbsp; 자연스럽고 오류가 적다고 생각합니다. 다시 한번, Embabel 내부에서 스스로 계획하는 기능이 흐름을 파악하기 때문에 직접 흐름을 정의할 필요가 없습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;병렬화&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;LLM 상호 작용이 일어나면, 동작이 느려질 수 있습니다. 따라서 병렬화는 생성형 AI 애플리케이션에서 중요합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;LangGraph는 “평행 엣지(parallel edges)”를 통해 작업을 병렬화할 수 있게 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image13.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Embabel에서는 병렬화를 위해 두 가지 선택이 가능합니다:&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;블로그 제목 예시에서 본 parallelMap 메서드를 사용한 프로그래밍 방식.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;자동 구조도 있습니다. embabel.agent.platform.process-type=CONCURRENT를 설정하면, Embabel 스스로 계획하여 서로 의존하지 않는 작업을 대상으로 현재 목표를 달성하기 위해 필요한 경로를 병렬 실행합니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;리플렉션(Reflection)&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;리플렉션은 다양한 이름으로 불리는 중요한 보편적 패턴입니다. 앤트로픽은 “&lt;a href="https://www.anthropic.com/engineering/building-effective-agents"&gt;Building Effective Agents”&lt;/a&gt;에서 이 패턴을 Evaluator-optimizer라고 부릅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;패턴의 핵심 아이디어는 LLM 호출을 한 차례 사용하여 다른 LLM의 출력에 대한 피드백을 제공하고 결과가 만족스러울 때까지 반복하는 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기 LangGraph 구현이 있습니다. 사용자가 지정한 작업에 응답하여 텍스트를 초안하고 만족스러울 때까지 비판합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image14.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;패턴의 가치에 빗대어 볼 때 이상적인 구현과는 거리가 멉니다. 일단, 종료를 보장할 수 없습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;개발자 관점에서 이런 류의 상태 머신은 일반적인 작업흐름을 표현하는데 이상적이지 않습니다. 공정하게 따지면, Embabel의 GOAP 계획도 마찬가지입니다. FSM이나 GOAP을 쓴다면 조잡한 계획에 잘 맞지만, 세밀한 작업을 정의할 수 있다면 정교한 프레임워크 지원으로 더 쉽게 할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;따라서 Embabel은 일반적인 패턴에 대해 바로 직접 만들지 않고 가져다 쓸 수 있도록 구현하는 방식을 제공합니다. (물론 자신만의 것을 만들 수도 있습니다.) 구현을 원하는 경우 GOAP 계획을 내보내는 fluent API&lt;span style="color:#757575;"&gt;*&lt;/span&gt;를 제공하기 때문에 표준적인 방식으로 단계를 관리할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;span style="color:#757575;"&gt;*fluent API: 메서드 체이닝으로 코드를 자연어처럼 읽히게 만드는 API 설계 패턴&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;RepeatUntilAcceptableBuilder를 사용하여 프로그래밍 방식으로 Agent를 만들고 @Configuration 클래스에서 Spring bean으로 노출하면, Embabel이 자동으로 배포합니다:&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image15.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;자바로 작성한 Embabel 코드는 LangGraph를 사용한 파이썬 코드보다 훨씬 적은 코드를 가지고 있습니다. 그 덕분에 타입을 보장하고 많은 도구를 활용할 수 있어 흐름을 망칠 일이 없습니다. 만일 maxIterations를 초과하면 루프가 종료되고, 지금까지 본 최고 점수의 결과를 반환합니다. 또한, RepeatUntilAcceptableBuilder가 매개변수화되어 있고 타입을 보장하기 때문에 자신의 결과 타입과 피드백 타입을 사용할 수 있습니다. 이 시나리오에서 LangGraph는 매우 좋지 않은 성능을 보여준다고 할 수 있겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;도구 사용&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;도구 사용은 모든 생성형 AI 프레임워크의 필수 요소이며 쉬워야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;LangGraph를 사용하면 Python에서 도구를 정의하고 LLM에 바인딩할 수 있습니다:&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image16.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;간단한 예시입니다. 다만, 이 예시는 생성된 Python 코드를 샌드박스 없이 실행하기 때문에 위험할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Embabel로 같은 처리를 한다면 매 번 PromptRunner를 사용하여 간단하게 도구를 추가할 수 있습니다. MCP가 지원하는 잘 알려진 도구 그룹을 정의하거나 Java 객체로 지정할 수 있습니다:&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image17.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;a href="https://medium.com/@springrod/domain-tools-direct-access-zero-ceremony-9a3e8d4cf550"&gt;도구 객체를 사용하는 기능&lt;/a&gt;은 특히 중요합니다. 이들은 데이터베이스에서 검색한 도메인 객체 또는 스프링으로 에이전트에 주입한 서비스일 수 있습니다. 파이썬에서도 그렇게 할 수 있지만, 자바 객체의 경우가 유용한 비즈니스 기능을 가질 가능성이 더 높다는 점에서 중요한 차이가 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Embabel은 또한 LlmReference와 같은 개념으로 도구 그룹화를 제공하며, 이는 도구를 프롬프트 요소와 결합하여 런타임에 정교한 구성을 가능하게 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;계획 수립&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;계획을 수립하는 과정을 다룬 LangGraph 블로그 예시는 이전 두 단계의 실행에 따라 최종 단계가 달라지는 형태를 포함합니다. 이것은 작업흐름 구축 과정에서다음과 같이 표현됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image18.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Embabel에서는 두 데이터 타입을 모두 사용하는 메서드를 간단히 정의합니다:&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3708/image19.png"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 방식이 제가 느끼기에 더 명확하고 타입 활용에 안전하며 테스트하기 쉽습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;LangChain 예시는 또한 계획의 단계를 하드코딩하지만, 그 코드는 LLM이 만들 수 있다고 언급합니다. Embabel에서 역시 LLM이 명령 객체를 인스턴스화하도록 하여 이를 구현할 수 있습니다. 그러나 LLM에 의존하여 계획을 수행하면 흐름 예측이 훨씬 어려워지므로 주의깊게 수행해야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;다중 에이전트 협업&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;마지막 패턴은 감독자 노드에서 다른 에이전트로의 전달 예시입니다. 이것은 Google ADK와 같은 프레임워크에서 흔한 패턴입니다. 상태 머신이나 GOAP 액션을 통해 단계를 표현하는 것보다 덜 결정론적이므로, 우리가 권장하는 경향이 없는 패턴입니다. 이러한 동작을 달성하기 위해 Embabel은 에이전트를 도구로 사용할 수 있게 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;전체 코드&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;전체 코드는 &lt;a href="https://github.com/embabel/langgraph-patterns"&gt;Embabel langgraph-patterns 저장소&lt;/a&gt;에서 찾을 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;누군가는 &lt;a href="https://pub.towardsai.net/agentic-design-patterns-with-langgraph-5fe7289187e6"&gt;원본 블로그&lt;/a&gt;가 LangGraph 사용을 제대로 보여준 것이 아니라고 주장할 수 있습니다. 하지만 이 글은 제가 보기에 에이전트에 대한 건전한 이해를 바탕으로 한 잘 쓴 글이며, 미디엄Medium에서 수백 개의 박수를 받았습니다. 다른 LangGraph 애플리케이션에서 동일한 결함을 찾기는 어렵지 않으며, 문제가 저자가 아니라 프레임워크, 언어 및 생태계에 있음을 시사합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이제 자바 커뮤니티는 파이썬 기반 에이전트의 성장을 따라잡아야 한다는 강박을 멈추고, 생성형 AI 에이전트를 구축하기 위한 해결책뿐만 아니라 모든 플랫폼에서 최고의 해결책을 가지고 있음을 보여줄 때입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;파이썬 프레임워크가 보여주는 평범한 아이디어 아래 안주하는 것을 멈추고 우리가 써온 언어를 기반으로 생각할 때입니다. 파이썬은 황제들만 갖출 수 있는 옷을 입지 않았습니다. 여러분이 JVM 개발자이지만, 상사가 파이썬으로 에이전트를 작성하라고 말하면, 비즈니스 애플리케이션, 생성형 AI 또는 기타 분야의 플랫폼으로서 파이썬의 약점을 지적할 준비를 하세요. 그리고 일반적인 패턴을 그대로 쓰면서도 파이썬보다 자바가 나아 보일 수 있는 방법을 보여줄 준비를 하세요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;파이썬은 모든 개발자가 능숙하게 쓰면 좋은 중요한 언어입니다. 많은 작업에 훌륭한 성능을 보여줍니다. 다만, 이 언어는 꽤 중요한 비즈니스 애플리케이션을 구축할 때 인기 있는 언어가 아니었으며, 여기에는 그럴만한 이유가 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;JVM의 견고성은 잘 알려져 있습니다. 생태계 — 특히 파이썬에서는 대안이 없는 Spring이 — 이러한 견고함을 강력하게 뒷받침합니다. Embabel은 이를 바탕으로 하며, 모든 파이썬 프레임워크보다 우수한 개념을 제공한다고 저는 믿습니다. 나머지는 여러분에게 달려 있습니다. 오늘 자바 에이전트 템플릿에서 첫 번째 에이전트를 만들어 보세요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>AI, 개발 말고 요구사항부터 써야 하는 이유</title><link>https://yozm.wishket.com/magazine/detail/3707</link><description>AI 열풍이 조금씩 식어가고 있습니다. 대부분의 기업은 이미 개발자에게 코파일럿, 코드 어시스턴트 같은 AI 도구를 쥐여주며 개발 속도를 높였는데요. 그런데도 여전히 뭔가 빠진 느낌입니다. AI가 우리가 기대했던 만큼 일하고 있다는 확신이 들지 않죠. ROI 향상, 10배의 생산성 개선, 그 기대했던 순간이 아직도 오지 않은 것 같습니다. 그런데 사실, 그 순간은 이미 와 있습니다. 지금 당장 활용할 수 있죠. 먼저 짚고 싶은 건, AI를 개발에 활용하는 것만으로는 부족하다는 점입니다. 개발 전 단계부터 이후까지, 전체 흐름이 함께 빨라져야 하거든요. 10배의 생산성과 더 나은 AI 투자 수익은 결국 가장 느린 단계를 얼마나 빠르게 끌어올리느냐에 달려 있습니다. </description><guid>https://yozm.wishket.com/magazine/detail/3707</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;본문은 요즘 IT와 번역가 Yuna가 함께 &lt;a href="https://www.linkedin.com/in/jakubgiza/"&gt;야쿠브 기자(&lt;u&gt;Jakub Giza&lt;/u&gt;&lt;/a&gt;)의 글 &lt;a href="https://medium.com/@giza.jakub/how-to-leverage-ai-for-better-it-requirements-and-process-improvements-in-your-company-2695ecc2507f"&gt;&amp;lt;&lt;u&gt;How to leverage AI for better IT requirements and process improvements in your company&lt;/u&gt;&lt;/a&gt;&amp;gt;을 번역한 글입니다. 필자는 25년 이상의 기업 IT 경력을 보유한 전문가로, 통신, 디지털 플랫폼, 대규모 혁신 프로젝트 등 다양한 분야에서 글로벌 개발 프로그램을 이끌어왔습니다. 현재는 AI 실험 단계를 넘어 실제 조직 안에서 AI를 체계적으로 실행할 수 있도록 돕는 데 집중하고 있으며, 인간과 AI의 협업 프레임워크인 HyperVe의 창시자이기도 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 글은 AI 도입 후에도 기대했던 ROI가 나오지 않는 이유를 짚고 그 해결책을 제시합니다. 개발 속도만 높이는 것으로는 부족하며, 요구사항을 정의하는 방식 자체를 AI 시대에 맞게 바꿔야 한다고 설명합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;span style="color:#999999;"&gt;필자에게 허락을 받고 번역했으며, 글에 포함된 링크는 원문에 따라 표시했습니다.&lt;/span&gt;&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;p style="text-align:justify;"&gt;AI 열풍이 조금씩 식어가고 있습니다. 대부분의 기업은 이미 개발자에게 코파일럿, 코드 어시스턴트 같은 AI 도구를 쥐여주며 개발 속도를 높였는데요. 그런데도 여전히 뭔가 빠진 느낌입니다. AI가 우리가 기대했던 만큼 일하고 있다는 확신이 들지 않죠. &lt;strong&gt;ROI 향상, 10배의 생산성 개선&lt;/strong&gt;, 그 기대했던 순간이 아직도 오지 않은 것 같습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 사실, 그 순간은 이미 와 있습니다. 지금 당장 활용할 수 있죠. 먼저 짚고 싶은 건, AI를 개발에 활용하는 것만으로는 부족하다는 점입니다. 개발 전 단계부터 이후까지, 전체 흐름이 함께 빨라져야 하거든요. 10배의 생산성과 더 나은 AI 투자 수익은 결국 가장 느린 단계를 얼마나 빠르게 끌어올리느냐에 달려 있습니다. 그리고 지금 그 병목은 개발 이전으로 옮겨갔습니다. 무엇을 만들지 정의하고 검증하는 단계가 빨라진 개발 속도를 따라가지 못하고 있는 거죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;상황은 더 심각합니다. AI 시대에는 불명확한 의도, 부족한 맥락, 검증되지 않은 비즈니스 가정이 단순히 속도를 늦추는 문제가 아닙니다. 잘못된 것을 더 빠르게 만들게 되고, 그만큼 조직의 위험도 커지죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;해결책은 무엇일까요? &lt;strong&gt;비즈니스 요구사항을 정의하고 프로세스를 개선하는 속도와 정확도를 AI 개발 속도에 맞춰야 합니다. 코딩에만 AI를 쓸 게 아니라, 비즈니스 활동 전반에 AI를 녹여야 한다는 뜻입니다.&lt;/strong&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;AI 투자 수익이 낮은 건 개발 속도 문제가 아닙니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;개발이 빨라지면 그 이전 단계가 새로운 병목이 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;불명확한 의도: "포털이 필요합니다…" 같은 두루뭉술한 요청&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;부족한 맥락: 실제 업무가 어떻게 돌아가는지 모르는 상태&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;부실한 검증: 이게 정말 가치를 만들어낼지 확인하지 않는 상태&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;숨겨진 제약: 법무, 운영, 시스템 의존성, 데이터 품질 등 미처 파악 못 한 것들&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;느린 합의: 회의로만 요구사항을 정리하려는 관행&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;결국 무엇을 만들지 정의하고 검증하는 단계가 AI로 빨라진 개발 속도를 따라가지 못하는 겁니다&lt;/strong&gt;. AI가 기대만큼의 성과를 내지 못하는 이유가 바로 여기 있죠. 더 빠르게, 때로는 더 잘 만들지만 정작 필요하지 않은 것을 만드는 경우가 너무 많습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;잘못된 방향에 빠른 실행이 더해지면, 빠르게 망합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;"더 나은 프롬프트"는 답이 아닙니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;많은 분들이 이렇게 반응합니다. "더 좋은 프롬프트가 필요해." 그럴듯하게 들리지만 잘못된 처방입니다. 프롬프트가 근본 문제가 아니거든요. 프롬프트는 이미 더 앞 단계에서 망가진 흐름의 마지막 단계일 뿐이죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;진짜 문제는 대부분의 조직이 요구사항을 다루는 방식이 아직도 그대로라는 점입니다. 문서 하나, 티켓 하나, 인수인계 하나, 한 번 쓰고 끝나는 산출물로 취급하죠. 개발이 느렸을 때는 그래도 됐습니다. 하지만 지금처럼 개발이 빠른 시대엔 통하지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AI 시대에 요구사항은 이래야 합니다.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;협업: 이해관계자와 AI가 함께 만들어가야 합니다.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;실제 맥락: 회사와 시장에 대한 구체적인 지식에서 출발해야 합니다.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;지속적인 개선: 한 번 쓰고 끝나는 게 아니라 계속 다듬어져야 합니다.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;추적 가능성: 처음 의도부터 최종 결과까지 가치를 검증할 수 있어야 합니다.&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;새로운 요구사항 정의 시스템, VOS의 등장&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;그렇다면 실제로 무엇이 필요할까요? &lt;strong&gt;개발이 시작되기 전, 팀이 비즈니스 의도를 실행 가능한 형태로 바꿀 수 있도록 돕는 무언가가 필요합니다. 거버넌스, 맥락, 팀 간 합의를 잃지 않으면서요&lt;/strong&gt;. 다시 말해, 의도, 맥락, 가정, 아이디어, 논의, 결정을 하나로 엮어주는 시스템이 필요한 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 등장한 새로운 개념이 바로 &lt;a href="https://medium.com/@giza.jakub/the-end-of-project-management-tools-the-ai-era-runs-on-value-orchestration-systems-vos-1ff8f4434629"&gt;&lt;u&gt;VOS(Value Orchestration System, 요구사항 정의 시스템)&lt;/u&gt;&lt;/a&gt;이죠. VOS는 백로그 도구도, 챗봇도, 문서 저장소도, 티켓 시스템도 아닙니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3707/image1.png"&gt;&lt;figcaption&gt;HyperVe Loop — Value Orchestration System&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;VOS는 AI가 팀의 일을 늘리기 전에, 먼저 질을 높이도록 돕는 시스템입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;이제 업무 흐름은 요청에서 프롬프트, 개발 순입니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;기존 개발 방식에서는 "요구사항"에서 "구현"으로 넘어가는 흐름을 따랐는데요. 일반적인 소프트웨어 개발 생명주기, SDLC가 그것입니다. AI 네이티브 업무에서는 흐름이 다릅니다. 더 단순하고, 더 명확하고, 더 솔직하죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;a href="https://medium.com/@giza.jakub/the-end-of-typical-agile-frameworks-and-the-rise-of-the-request-prompt-delivery-rpd-framework-e4671b2e359d"&gt;&lt;u&gt;요청하고, 프롬프트를 만들고, 개발합니다.&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://medium.com/@giza.jakub/request-the-successor-to-user-stories-in-ai-native-work-3111bdddee3b"&gt;&lt;strong&gt;&lt;u&gt;요청&lt;/u&gt;&lt;/strong&gt;&lt;/a&gt;: 비즈니스 의도, 기대 결과, 제약 조건, 성공 기준을 명확히 정의합니다.&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/@giza.jakub/prompt-the-new-specification-layer-for-ai-native-teams-cc7047be0921"&gt;&lt;strong&gt;&lt;u&gt;프롬프트&lt;/u&gt;&lt;/strong&gt;&lt;/a&gt;: 추측이 아닌 회사의 실제 상황을 담아 구체적인 지침을 만듭니다.&lt;/li&gt;&lt;li&gt;&lt;a href="https://medium.com/@giza.jakub/delivery-has-changed-forever-ai-doesnt-wait-for-sprints-cb60daaf45b1"&gt;&lt;strong&gt;&lt;u&gt;개발&lt;/u&gt;&lt;/strong&gt;&lt;/a&gt;: 사람과 AI가 함께 실행하되, 처음 의도와 일치하는지 언제든 확인할 수 있습니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 흐름이 실제로 이루어지려면 그에 맞는 공간이 필요합니다. 협업, 검증, 거버넌스가 기본으로 갖춰진 작업 공간이죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;AI가 우리 회사를 알아야 제대로 작동합니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AI가 일관되게 도움이 되려면 회사의 실제 상황을 알아야 합니다. 우리 조직이 어떻게 돌아가는지 AI가 파악하고 있어야 한다는 뜻이죠. 이를 위해 조직의 실제 상황을 담은 회사 정보가 필요합니다. 여기엔 이런 것들이 포함돼야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;프로세스: 업무가 어떻게 흘러가는지, 어디서 시간이 낭비되는지&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;시스템과 연동: 어떤 시스템을 쓰는지, 어디서 인수인계가 끊기는지&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;제약 조건: 보안, 법무, 운영, 데이터 저장 위치 등 반드시 지켜야 할 것들&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;기존 문서와 결정 사항: 이미 알고 있는 것, 이미 결정된 것들&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;담당자와 이해관계자: 누가 무엇을 결정하는지&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;데이터 품질 기준: 자동화가 제대로 작동하려면 어떤 조건이 갖춰져야 하는지&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3707/image3.png"&gt;&lt;figcaption&gt;HyperVe Loop System&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이런 토대 없이 요구사항을 만들면 그건 그냥 의견입니다. 이런 토대를 갖추고 요구사항을 만들면 그건 근거가 됩니다. “회의에서 나온 아이디어”가 “시스템 안에서 관리”되기 시작하는 변화입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실무에 적용해보면 다음과 같습니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;"주문에서 개통까지 걸리는 시간을 14일에서 3일로 줄이자"는 목표가 있다고 해봅시다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;대부분의 팀은 바로 해결책으로 뛰어듭니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;단계를 자동화한다&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;새 도구를 도입한다&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;워크플로를 다시 만든다&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;다른 플랫폼을 구매한다&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 AI 기반 요구사항 워크스페이스는 그 전에 먼저 해야 할 일을 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;올바른 질문을 던지는 거죠. 핵심을 파고드는 탐색입니다.&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;정확히 어디서 지연이 발생하는가?&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;어떤 단계가 수동이고 어떤 단계가 자동화되어 있는가?&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;무엇이 재작업을 유발하는가?&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;어떤 제약이 자동화를 막고 있는가?&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;어떤 수준의 데이터 품질이 필요한가?&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;이 질문들은 조직의 실제 정보에 기반하기 때문에 추측이 아닌 사실에서 출발합니다.&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;프로세스 흐름과 이미 파악된 병목 지점&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;관련된 시스템들&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;시스템 간 연결과 인수인계 지점&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;반복적으로 발생하는 문제 패턴&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;이전에 내려진 결정과 제약 조건&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;그리고 각 선택지를 장단점과 함께 제시합니다. 어떤 결정을 내릴지 훨씬 명확해지는 순간이죠.&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;"옵션 A는 시간을 가장 빠르게 단축하지만, 먼저 데이터 정리가 필요합니다."&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;"옵션 B는 비용이 덜 들지만 개선 효과는 20%에 그칩니다."&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;"옵션 C는 고객 경험을 높이지만 운영 방식의 변화가 필요합니다."&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;결과물은 바로 검토하고 실행할 수 있는 형태로 나옵니다.&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;구조화된 요청서&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;프롬프트로 바로 활용할 수 있는 명세서&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;목표에서 가정, 결정, 산출물까지 연결되는 추적 가능한 흐름&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 과정을 거치면 "프로세스를 개선해야 한다"는 막연한 말이 측정 가능한 결과로 이어지는 실질적인 결정이 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;HyperVe Loop의 사례&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;&lt;a href="https://hyperve.com/"&gt;&lt;u&gt;HyperVe Loop&lt;/u&gt;&lt;/a&gt;는 요청, 프롬프트, 개발 흐름을 중심으로 만들어진 VOS의 실제 사례입니다. 주요 기능은 이렇습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;AI 기반 협업: AI가 이해관계자들과 함께 올바른 질문을 던지고, 결정 사항을 기록하고, 새로운 아이디어를 끌어냅니다.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;실제 맥락 기반 대화: 추측이 아닌 회사의 프로세스, 시스템, 제약 조건, 문서, 결정 사항을 토대로 논의가 이루어집니다.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;개발 전 검증: 본격적인 개발에 들어가기 전에 가치, 실현 가능성, 리스크, 장단점을 먼저 따져봅니다.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;근거 있는 선택지 비교: ROI를 기준으로 실행 가능한 옵션을 비교해 볼 수 있습니다.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;전 과정 추적: 요청에서 프롬프트, 개발까지 모든 과정이 끊기지 않고 연결됩니다.&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결과적으로 더 나은 결정, 더 빠른 합의, 그리고 불필요한 재작업이 줄어듭니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3707/image2.png"&gt;&lt;figcaption&gt;리더가 AI로 실질적인 성과를 내는 5가지 방법&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;다음 경쟁력은 더 명확한 의도에서 나옵니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AI 네이티브 개발은 이제 당연한 것이 되어가고 있습니다. 다음 경쟁력은 비즈니스 요구사항을 정의하는 방식도 함께 바꾸는 데 있습니다. 구조화되고, 실제 맥락에 기반하고, 협업적이고, 추적 가능한 방식으로요. 개발이 빨라진 지금, 결국 중요한 건 하나입니다. 올바른 것을 만들고 있느냐는 질문이죠.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&amp;lt;원문&amp;gt;&lt;/p&gt;&lt;p&gt;&lt;a href="https://medium.com/@giza.jakub/how-to-leverage-ai-for-better-it-requirements-and-process-improvements-in-your-company-2695ecc2507f"&gt;&lt;u&gt;How to leverage AI for better IT requirements and process improvements in your company&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>[요즘IT 콘텐츠 AX] 기업 블로그 에이전트의 가능성과 한계 웨비나 오픈!</title><link>https://yozm.wishket.com/magazine/detail/3706</link><description>“AI로 콘텐츠 자동화하기” 콘텐츠를 만들어 본 분들이라면 한 번쯤은 생각해 보셨을 텐데요. 막상 해보면 글 한 편은 어떻게 완성되는데, 기획부터 발행까지 전체를 자동으로 돌리는 작업은 생각보다 훨씬 복잡합니다. 원했던 퀄리티가 나오지 않을 때도 많고요. 그래서 요즘IT가 직접 부딪혀봤습니다. 위시켓 기업 블로그를 대상으로, 콘텐츠 마케터의 워크플로우를 6단계로 나누고 각 단계에 AI 에이전트를 붙였습니다. 비개발자가 클로드 코드로 월간 12건의 콘텐츠 기획부터 발행까지 자동화한 과정, 그 한계와 가능성을 솔직하게 공유합니다. 정답이 있는, 이론을 배우는 자리는 아닙니다. 대신 직접 만들면서 겪은 것들을 있는 그대로 나눠보려고 합니다.</description><guid>https://yozm.wishket.com/magazine/detail/3706</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;blockquote&gt;&lt;h4&gt;&lt;strong&gt;“콘텐츠 담당자를 위한 기업 블로그 에이전트 가능성과 한계” 웨비나 오픈&lt;/strong&gt;&lt;/h4&gt;&lt;/blockquote&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;“AI로 콘텐츠 자동화하기” 콘텐츠를 만들어 본 분들이라면 한 번쯤은 생각해 보셨을 텐데요. 막상 해보면 글 한 편은 어떻게 완성되는데, 기획부터 발행까지 전체를 자동으로 돌리는 작업은 생각보다 훨씬 복잡합니다. 원했던 퀄리티가 나오지 않을 때도 많고요.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 요즘IT가 직접 부딪혀봤습니다. 위시켓 기업 블로그를 대상으로, 콘텐츠 마케터의 워크플로우를 6단계로 나누고 각 단계에 AI 에이전트를 붙였습니다. 비개발자가 클로드 코드로 월간 12건의 콘텐츠 기획부터 발행까지 자동화한 과정, 그 한계와 가능성을 솔직하게 공유합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;br&gt;정답이 있는, 이론을 배우는 자리는 아닙니다. 대신 직접 만들면서 겪은 것들을 있는 그대로 나눠보려고 합니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;span style="color:#757575;"&gt;&lt;strong&gt;[요즘IT 콘텐츠 AX 실험기 미리보기]&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://yozm.wishket.com/magazine/detail/3647/"&gt;12분 49초 만에 한 달치 기획이 나왔다: 콘텐츠 AX 실험기&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://yozm.wishket.com/magazine/detail/3695/"&gt;콘텐츠 AX, '프롬프트' 말고 '파일'을 보세요: 콘텐츠 AX 실험기 ②&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;a href="https://litt.ly/yozm_it/sale/qdteYzP"&gt;&lt;img src="https://www.wishket.com/media/news/3706/1_RlVsdEv.png"&gt;&lt;/a&gt;&lt;/figure&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;웨비나 정보&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;일시&lt;/strong&gt;: 2026년 4월 17일(금) 저녁 7:00&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;형태&lt;/strong&gt;: 온라인 라이브 (Zoom)&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;구성&lt;/strong&gt;: 발표 30분 + Q&amp;amp;A 20분&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;참가 비용&lt;/strong&gt;: 얼리버드 &lt;s&gt;15,000&amp;nbsp;&lt;/s&gt; ▶&lt;strong&gt;11,900원 (4/16일까지)&lt;/strong&gt;&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;신청 링크:&lt;/strong&gt;&lt;a href="https://litt.ly/yozm_it/sale/qdteYzP"&gt;&lt;strong&gt;웨비나 신청하기&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;슬라이드&lt;/strong&gt;: 참여자에게 발표 슬라이드 PDF 제공 (웨비나 전날 이메일 발송)&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;녹화본&lt;/strong&gt;: 따로 제공되지 않습니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;웨비나에서 이런 이야기를 다룹니다&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;01. 파이프라인 전체 구조&lt;/strong&gt;&amp;nbsp;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;콘텐츠 마케터의 워크플로우를 세분화하고, 각 단계에 에이전트를 붙인 구조. 왜 이렇게 나눴고, 어디서 사람이 개입하는지 살펴봅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;02. 시행착오 기록&lt;/strong&gt;&amp;nbsp;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;키워드 수집에서 노이즈가 터진 일, 기존 글과 중복 판정이 안 맞았던 일, GEO 최적화와 브랜드 톤이 충돌한 일. 실제 겪은 문제들과 대응 과정을 살펴봅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;03. 도메인 지식의 벽&lt;/strong&gt;&amp;nbsp;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;기업 담당자만 아는 비즈니스 맥락을 AI에 주입하는 것이 왜 어렵고, 어디까지 가능했는지 알아봅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;04. 생성 품질의 현실&lt;/strong&gt;&amp;nbsp;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;AI가 쓴 글이 "사람이 읽을 만한 글"이 되려면 무엇이 필요한지. 현재 수준은 어디이고, 무엇이 부족한지 알아봅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;05. 직접 만들 때 알아야 할 것&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;에이전트가 정확히 뭔지, 어떻게 만드는지, 어디까지 자동화되고 어디서 사람이 판단해야 하는지 살펴봅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;발표자&lt;/strong&gt;&lt;/h3&gt;&lt;blockquote&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;장대청(요즘IT 그로스 파트 리드 · 위시켓)&lt;/strong&gt;&lt;/h4&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;비개발자. 코드를 직접 짜지 않고, 업무 매뉴얼을 자연어로 정의하면 클로드 코드가 코드를 짜는 방식으로 파이프라인을 구축했습니다. 위시켓 기업 블로그 자동화 프로젝트의 설계와 실행을 담당하고 있습니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;span style="background-color:rgb(255,255,255);color:rgb(49,49,49);"&gt;&lt;strong&gt;이런 분들께 추천해요&lt;/strong&gt;&lt;/span&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;기업 블로그나 콘텐츠 마케팅을 담당하면서 AI 자동화를 검토 중인 분&lt;/li&gt;&lt;li style="text-align:justify;"&gt;에이전트가 궁금한데, 실제 사례를 먼저 보고 싶은 분&lt;/li&gt;&lt;li style="text-align:justify;"&gt;직접 파이프라인을 만들어보고 싶은데, 전체 그림이 안 잡히는 분&lt;/li&gt;&lt;li style="text-align:justify;"&gt;코드는 나오지 않습니다. 구조와 판단 과정, 시행착오 중심으로 이야기합니다. 사전 등록자의 77%가 비개발자(PM, 기획자, 콘텐츠 마케터)였습니다.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;자주 묻는 질문&lt;/strong&gt;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Q. 비개발자인데 이해할 수 있나요?&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;네. 사전 등록자의 77%가 비개발자(PM, 기획자, 콘텐츠 마케터, 경영진)입니다. 코드는 나오지 않습니다. 구조와 판단 과정, 시행착오 중심으로 이야기합니다.&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;strong&gt;Q. 웨비나를 듣고 바로 자동화를 구축할 수 있나요?&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;이 웨비나는 정답이나 성공 공식을 알려주는 자리가 아닙니다. 에이전트로 블로그를 자동화한다는 것이 실제로 어떤 것인지, 클로드 코드로 그것을 어떻게 시작하는지, 그 과정에서 부딪히는 문제들은 무엇인지, 직접 해본 사람의 경험과 시행착오를 공유합니다. 되는 것과 안 되는 것의 경계를 이해하고, 스스로 판단 기준을 세울 수 있도록 돕는 자리입니다.&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;strong&gt;Q. 우리 회사에도 적용 가능한가요?&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;기업 블로그 콘텐츠를 정기 발행하는 팀이라면 파이프라인 구조 자체는 적용 가능합니다. 다만 도메인 지식을 AI에 주입하는 과정이 핵심 과제이며, 이 부분의 현실적인 난이도를 웨비나에서 다룹니다.&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;strong&gt;Q. 녹화본이 제공되나요?&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;녹화본은 제공되지 않습니다. 참여자에게 발표 슬라이드 PDF를 웨비나 전날 이메일로 발송해드립니다.&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;strong&gt;Q. 환불이 가능한가요?&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;웨비나 당일 전까지 환불 요청 시 전액 환불됩니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;강의가 아니라 경험담을 나누는 자리입니다. 잘 된 것도, 막혔던 것도, 아직 안 되는 것도, 모두 있는 그대로 공유합니다. "우리 팀도 해볼 수 있을까?"라고 고민하고 계신 분들께 도움이 되길 바랍니다. 그럼 4/17일 웨비나에서 만나요!&lt;/p&gt;&lt;hr&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;a href="https://litt.ly/yozm_it/sale/qdteYzP"&gt;&lt;img src="https://www.wishket.com/media/news/3706/3.png"&gt;&lt;/a&gt;&lt;/figure&gt;&lt;h4 style="text-align:center;"&gt;&lt;strong&gt;[→&lt;/strong&gt;&lt;a href="https://litt.ly/yozm_it/sale/qdteYzP"&gt;&lt;strong&gt;웨비나 신청하기&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;]&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>AI 에이전트가 슬랙을 떠난 이유: 웹으로 이사한 곰곰이</title><link>https://yozm.wishket.com/magazine/detail/3705</link><description>요즘 기업들의 AI 도입 사례를 부쩍 자주 보게 됩니다. 특히 자연어로 데이터를 분석하는 Text-to-SQL 에이전트 사례가 눈에 띄게 늘었는데요. 그런데 흥미로운 점이 있습니다. 많은 초기 도입 사례에서 AI 에이전트가 슬랙봇의 형태로 소개된다는 것입니다. 저도 그랬습니다. 곰곰이도 처음엔 슬랙 채널에서만 활동했고, 덕분에 빠르게 프로토타이핑하여 동료들에게 선보일 수 있었습니다. 하지만 얼마 전 곰곰이를 웹앱으로 이사시켰습니다. LLM과 AI의 잠재력을 슬랙이라는 작은 그릇에 계속 가둬둘 수 없다고 판단했기 때문입니다. 이 글에서는 제가 왜 그런 결정을 내렸는지, 그리고 웹으로 이사 이후 무엇이 달라졌는지 풀어보려 합니다.</description><guid>https://yozm.wishket.com/magazine/detail/3705</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;이번 글은 &lt;a href="https://yozm.wishket.com/magazine/detail/3697/"&gt;반복적인 SQL 업무를 자동화하는 AI 에이전트 '곰곰이'&lt;/a&gt;의 후속입니다. 아직 읽지 않으셨다면 먼저 읽고 오시는 걸 추천합니다.&amp;nbsp;&lt;br&gt;&lt;br&gt;요즘 기업들의 AI 도입 사례를 부쩍 자주 보게 됩니다. 특히 자연어로 데이터를 분석하는 Text-to-SQL 에이전트 사례가 눈에 띄게 늘었는데요. 그런데 흥미로운 점이 있습니다. 많은 초기 도입 사례에서 &lt;strong&gt;AI 에이전트가 슬랙봇의 형태로 소개된다&lt;/strong&gt;는 것입니다. 저도 그랬습니다. 곰곰이도 처음엔 슬랙 채널에서만 활동했고, 덕분에 빠르게 프로토타이핑하여 동료들에게 선보일 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 얼마 전 &lt;strong&gt;곰곰이를 웹앱으로 이사시켰습니다.&lt;/strong&gt; LLM과 AI의 잠재력을 슬랙이라는 작은 그릇에 계속 가둬둘 수 없다고 판단했기 때문입니다. 이 글에서는 제가 왜 그런 결정을 내렸는지, 그리고 웹으로 이사 이후 무엇이 달라졌는지 풀어보려 합니다. 슬랙봇으로 AI 에이전트를 운영하고 있거나 고민 중인 분이라면, 저의 사례가 작은 힌트가 됐으면 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;목차&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;슬랙은 AI의 잠재력을 담을 수 없다&lt;/li&gt;&lt;li style="text-align:justify;"&gt;웹 전환으로 달라진 것들&lt;/li&gt;&lt;li style="text-align:justify;"&gt;커맨드와 예약: 반복 분석을 자동화하다&lt;/li&gt;&lt;li style="text-align:justify;"&gt;곰곰이 제작자의 생각&lt;/li&gt;&lt;li style="text-align:justify;"&gt;앞으로 남은 여정&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;슬랙은 AI의 잠재력을 담을 수 없다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;곰곰이가 슬랙봇으로 시작한 건 당연한 선택이었습니다. 슬랙은 동료들이 하루 종일 켜놓는 업무용 메신저입니다. 새로운 환경을 따로 세팅하거나 배울 필요 없이 곰곰이를 바로 써볼 수 있었고, 데이터 분석 결과를 동료들에게 공유하는 것도 쉬웠습니다. 빠르게 프로토타이핑하고 동료들의 반응을 확인하기엔 슬랙만한 환경이 없었습니다. 그런데 &lt;strong&gt;쓰면 쓸수록 불편한 지점들이 생겼습니다.&lt;/strong&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;첫 번째는 &lt;strong&gt;보안&lt;/strong&gt;입니다. 슬랙에서 회사 정보를 공유하는 건 이미 익숙한 일입니다. 그런데 DB와 연결된 AI가 슬랙 위에서 데이터를 조회하고 분석한다는 건 왠지 찝찝합니다. 보안 통제가 높은 조직이라면 더욱 그렇습니다. 데이터 조회와 반출에 대한 사용자별 권한 체계가 있는 곳이라면, 곰곰이가 슬랙에서 자유롭게 데이터를 분석하는 것 자체가 허락되지 않을 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;두 번째는 &lt;strong&gt;가독성&lt;/strong&gt;입니다. 아래 사진은 슬랙에서 곰곰이의 데이터 분석 답변입니다. 표는 줄이 맞지 않아 읽기가 어렵습니다. 그래프를 그리는 것은 아예 불가능하고, 굵게나 밑줄 같은 마크다운 기본 포맷도 제대로 렌더링되지 않습니다. 곰곰이가 데이터 분석 과정에서 도구를 선택하고 생각하는 흐름인 ReAct 추론 과정을 보여주는 것도 마찬가지입니다. 슬랙으로는 데이터 분석 결과를 보여주기에 충분하지 않았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/1.webp" alt="슬랙 곰곰이"&gt;&lt;figcaption&gt;슬랙 곰곰이 답변의 시원치 않은 모습&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;세 번째는 &lt;strong&gt;확장성&lt;/strong&gt;입니다. 슬랙은 채팅 앱으로서 훌륭하고 SDK나 플러그인도 잘 갖춰져 있습니다. 하지만 직접 만든 웹앱과 비교하면 기능을 추가하고 커스텀 할 때 발목이 잡힙니다. 개인화된 대화, 보고서 이미지 다운로드, 로그인과 권한 관리, 어드민 기능 같은 것들은 슬랙에서 만들 수 없습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;슬랙이 나쁘다는 게 아닙니다. 다만 곰곰이의 잠재력을 전부 끌어내려면 제가 원하는 대로 만들 수 있는 환경이 필요했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;웹 전환으로 달라진 것들&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;저는 백엔드에 익숙한 개발자입니다. 데이터 설계, 인프라 구축, API 개발은 늘 하던 일이라 부담이 없습니다. 그런데 버그 없이 잘 동작하는 웹앱을 만드는 건 솔직히 자신이 없었습니다. 하지만 그것도 몇 달 전 이야기입니다. &lt;strong&gt;AI 코딩 에이전트 덕분에 이제 퀄리티 높은 웹앱도 직접 만들 수 있게 되었습니다.&lt;/strong&gt; 슬랙봇 개발도 쉬운 편이긴 한데 AI의 도움이 잘 닿지 않는 부분들이 있습니다. 반면 AI 코딩 에이전트로 직접 웹앱을 만들면 빠르게 원하는 데로 모두 만들 수 있어 슬랙봇 보다 웹앱 개발이 더 쉬워진 상황이 됐습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 AI 에이전트의 족쇄가 되는 슬랙을 벗어나 직접 웹앱을 만들어 곰곰이가 능력을 더 자유롭게 보여줄 수 있는 브라우저 환경으로 이사시켰습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/2.webp" alt="곰곰이 웹앱 브라우저"&gt;&lt;figcaption&gt;새 채팅 화면&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;가장 먼저 달라진 건 &lt;strong&gt;개인화&lt;/strong&gt;입니다. 회원가입과 로그인으로 접근하게 되면서 채팅을 공유 환경뿐만 아니라 나만의 공간으로도 쓸 수 있게 됐습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/3.webp" alt="곰곰이 웹앱 브라우저"&gt;&lt;figcaption&gt;곰곰이 웹을 보고 만약 무엇인가 떠올랐다면, 맞습니다. 저는 스탯을 개발에만 찍어서 디자인 능력이 없거든요.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;나의 데이터 분석 채팅을 나만 볼 수 있는 게 생각보다 꽤 중요합니다. 곰곰이의 고객인 사내 동료들은 아직 데이터를 직접 다루는 습관이 충분히 쌓이지 않은 분들이 많습니다. &lt;strong&gt;내가 한 질문이 누군가에게 바보 같아 보이지 않을까 하는 마음이 곰곰이 사용을 주저하게 만들 수 있거든요.&lt;/strong&gt; 나만 볼 수 있는 대화가 생기니까 자유롭게 질문하고 시도해 볼 수 있습니다. 아직 만들진 않았지만 유저나 그룹별로 접근 가능한 데이터 종류를 제어하는 권한 관리도 웹이기 때문에 가능한 것들입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/4.webp" alt="곰곰이 웹앱 브라우저"&gt;&lt;figcaption&gt;바보 같은 질문 하는 채팅&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;답변의 표현도 훨씬 풍부해졌습니다. 곰곰이가 마크다운으로 답변하도록 만들고 브라우저에서 렌더링하니까 표, 코드, 텍스트 포맷이 제대로 보입니다. 슬랙과 웹에서 곰곰이의 답변을 비교하면 답변의 가독성이 더 좋다는 것을 바로 알 수 있죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/5.webp" alt="곰곰이 웹앱 브라우저"&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여기서 한 발 더 나가면 마크다운과 잘 호환되는 Mermaid 문법으로 답변하게 할 수 있는데, &lt;strong&gt;그러면 순서도, 막대, 꺾은선, 파이 그래프 같은 시각화를 코딩 없이 프롬프트만으로 보고서에 바로 넣을 수 있습니다.&lt;/strong&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/6.webp" alt="곰곰이 차트"&gt;&lt;figcaption&gt;곰곰이가 그려준 차트들&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;곰곰이가 데이터를 분석하는 ReAct 추론 과정을 채팅에서 바로 볼 수 있다는 것도 생각보다 유용합니다. 보고서가 어떤 과정으로 만들어졌는지 빠르게 파악할 수 있거든요. 동료들이 질문한 결과가 예상과 다르다고 확인을 요청해 올 때 추론 과정을 같이 들여다보면 어디서 어떻게 틀렸는지 바로 찾을 수 있습니다. 덕분에 “이 부분에서 이렇게 접근하면 됩니다” 같은 구체적인 피드백을 주기가 훨씬 수월해졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/7.webp" alt="곰곰이의 사고과정"&gt;&lt;figcaption&gt;곰곰이의 사고 과정 엿보기&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;직접 만든 웹앱이니까 원하는 기능을 그냥 만들면 됩니다. 당연한 말 같지만 이게 생각보다 큰 차이입니다. 데이터 분석 보고서를 HTML 렌더링된 형태 그대로 이미지로 저장할 수 있고, 좋아요 버튼을 누르면 대화 내용을 요약해서 곰곰이의 장기 기억에 넣을 수 있습니다. 뒤에서 설명할 커맨드와 예약도 웹 인터페이스 안에서 생성, 수정, 삭제가 가능합니다. 슬랙에서는 시도조차 못 했던 것들입니다. 우리가 웹앱에서 당연하게 기대하는 경험들을 이제 곰곰이도 갖추게 됐습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/8.webp" alt="곰곰이 웹앱 브라우저"&gt;&lt;figcaption&gt;좋아요를 누르면 곰곰이가 대화를 기억해 준다.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;마지막으로 대시보드 이야기를 빼놓을 수 없습니다. 전통적으로 데이터를 받아보는 방식은 두 가지였습니다. 새로운 정보나 가끔 필요한 분석은 데이터 분석가에게 요청해서 보고서로 받고, 자주 봐야 하는 정해진 지표들은 대시보드로 봤습니다. 곰곰이 채팅이 전자를 담당해 주고 있다면, 후자는 여전히 대시보드가 필요합니다. 채팅 분석만으로는 그 경험을 대체하기 어렵습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;옵저버빌리티처럼 데이터도 한곳에 모여 있어야 시너지가 난다&lt;/strong&gt;고 생각해서 데이터 대시보드도 같은 웹에 직접 개발했습니다. (Chart JS 사용) 차트는 곰곰이가 만드는 게 아니라, 코딩 에이전트의 도움을 받아 사람이 직접 만들고 있습니다. 곰곰이를 웹으로 이사시켰기 때문에 채팅과 대시보드를 한곳에서 제공할 수 있게 됐고, 두 가지가 만들어낼 시너지를 기대하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/9.webp" alt="곰곰이 대시보드"&gt;&lt;figcaption&gt;대시보드를 보고 바로 채팅으로 물어 볼수 있다.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;커맨드와 예약: 반복 분석을 자동화하다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;곰곰이로 데이터 분석을 잘하려면 순차적으로 질문하는 게 좋습니다. 예를 들면 이런 식입니다. “지금 진행 중인 투표가 있어?” → “해당 투표 후보자의 득표 Top3를 알려줘.” → “Top3 후보가 붙었던 다른 투표 모두 알려줘.” → “회차별 투표수 그래프를 포함해서 보고해줘.” 물론 이걸 한 번에 요청해도 곰곰이는 높은 확률로 맞는 답변을 만들어냅니다. 하지만 LLM의 특성상 단계적으로 접근할수록 결과의 품질이 올라가는 건 사실입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/10.webp" alt="곰곰이 커맨드"&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;문제는 매주 같은 분석이 필요할 때입니다. &lt;strong&gt;이 과정을 매번 반복해야 한다면 귀찮습니다.&lt;/strong&gt; 동료들의 곰곰이 사용 빈도도 자연스럽게 떨어질 것이고요. 그래서 만든 게 커맨드 기능입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;만족스러운 대화가 있으면 곰곰이에게 &lt;strong&gt;“이거 커맨드로 만들어줘”&lt;/strong&gt;라고 하면 됩니다. 곰곰이가 대화를 분석해서 사용자에게 확인받아야 하는 입력 정보, 데이터 분석 SQL, 분석 방법, 보고서 작성 형식 등을 프롬프트로 정리하여 저장합니다. 다음부터는 &lt;code&gt;/vote-weekly-report&lt;/code&gt; 같은 커맨드 하나로 동일한 보고서를 받을 수 있습니다. 커맨드 검색, 수정, 삭제 같은 관리도 웹 인터페이스 안에서 바로 할 수 있습니다. 슬랙이었다면 불가능했던 것들입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/11.webp" alt="커맨드 저장 &amp;gt; 커맨드 수정 &amp;gt; 커맨드 실행"&gt;&lt;figcaption&gt;커맨드 저장 &amp;gt; 커맨드 수정 &amp;gt; 커맨드 실행&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;커맨드를 만들었다고 해도 사용자가 직접 실행하러 와야 한다면 여전히 귀찮은 일입니다. 그래서 &lt;strong&gt;예약 기능을 붙였습니다.&lt;/strong&gt; 원하는 주기와 시점에 커맨드를 예약해 두면 곰곰이가 알아서 분석을 실행하고, 핵심 내용 3줄 요약과 바로 가기 링크를 슬랙으로 보냅니다. 사용자는 알림을 받고 지표에 이상한 점이 있을 때만 웹에 들어와서 그 세션 그대로 곰곰이에게 이어서 물어보면 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/12.webp" alt="보고서 슬랙"&gt;&lt;figcaption&gt;3줄 요약된 보고서를 슬랙 알림으로 수신 &amp;gt; 추가 궁금점을 질문&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;슬랙의 접근성과 웹의 경험을 합친 것입니다.&lt;/strong&gt; 인터페이스를 직접 만들었기 때문에 가능한 조합입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;곰곰이 제작자의 생각&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;곰곰이가 생기고 나서 &lt;strong&gt;데이터 업무의 패러다임 자체가 바뀌었습니다.&lt;/strong&gt; SQL을 모르는 동료가 직접 데이터를 확인하는 게 자연스러워졌고, 데이터를 기반으로 의사결정 하는 횟수도 늘었습니다. 예약 기능 덕분에 지표의 이상을 예전보다 훨씬 빠르게 감지할 수 있게 됐고요. 기존에 없던 개념의 데이터 플랫폼을 갖게 된 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;근데 솔직히 말하면 저의 기대보다 많이 안 씁니다. 이렇게 좋은 도구인데 동료들이 각자의 이유로 자주 찾지 않습니다. 무슨 데이터가 있는지 모르겠다, 너무 바빠서 데이터까지 볼 여유가 없다, 데이터를 확인해야 한다는 생각을 못 했다, 습관이 없다. 들어보면 다 맞는 말입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 저는 이 이유들이 일단 &lt;strong&gt;곰곰이에게 물어보기 시작하면 해결된다&lt;/strong&gt;고 생각합니다. 궁금한 게 생겼을 때 ChatGPT를 켜는 것처럼요. 새로운 도구는 써보면서 익히는 수밖에 없습니다. 다만 ChatGPT랑 다른 점이 하나 있습니다. 데이터에 대해 궁금해하고 분석 결과를 이해할 수 있는 능력이 있어야 한다는 것입니다. 그게 어렵다는 건 공감합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 지금 제가 하고 있는 건 동료들에게 먼저 다가가는 것입니다. 불편한 점을 물어보고, 사용 방법을 알려주고, 기다리는 것. 시간이 해결해 주는 부분도 분명히 있을 겁니다. &lt;strong&gt;그리고 이런 부분이 AI가 아닌 사람이 필요한 지점이 아닐까요?&lt;/strong&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3705/13.webp" alt="곰곰이"&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;앞으로 남은 여정&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;곰곰이를 처음 기획하면서 생각했던 것들은 대부분 만들었습니다. 생각보다 빨리 도달해서 스스로도 좀 놀랐습니다. 지금은 소프트웨어 개발의 대격변기니까요. 다음에 뭘 만들지 아직 계획은 없습니다. 그냥 머릿속에 있는 아이디어들을 꺼내봅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;멀티 에이전트, 다른 기업들의 사례를 보면 분야별로 에이전트를 따로 만들어 협업하게 하는 경우를 종종 봤습니다. 질문 의도를 분석하는 에이전트, 작업을 계획하고 지휘하는 에이전트, SQL만 전담하는 에이전트, 답변만 만드는 에이전트, 이런 식으로요. 흥미롭긴 한데 곰곰이는 아직 도구 수가 많지 않아서인지 단일 에이전트로도 충분히 만족스럽습니다. 언젠가는 필요할 것 같기도 한데 지금은 모르겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;어드민 API를 도구로 제공해서 채팅으로 어드민을 관리하는 것도 생각해 봤습니다. 사실 AI 에이전트의 본질은 분야가 달라도 다 똑같습니다. 요청을 받고, 생각하고, 도구를 골라 실행하고, 결과를 관찰합니다. 기존 어드민 API들을 곰곰이가 쓸 수 있는 도구로 만들어준다면 &lt;strong&gt;“곰곰아 다음 주 투표 미리 만들어놔. 가이드 문서 보고 알아서 해!”&lt;/strong&gt; 같은 것도 가능해집니다. 도구와 가이드만 주면 곰곰이가 데이터 분석가 말고도 뭐든 될 수 있는 거죠. 안 해봐서 잘 될지는 모르겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;사내 모든 문서와 정보를 RAG로 넣어주는 것도 재밌는 상상입니다. 창사 이후 모든 지라 티켓, 슬랙 대화 내용들을 곰곰이에게 제공한다면 &lt;strong&gt;창업자보다 회사를 더 잘 아는 존재가 될 수도 있습니다.&lt;/strong&gt; 물론 LLM과 RAG의 한계가 있으니 기대만큼은 안 되겠죠. 역시 안 해봐서 모릅니다. &lt;span style="color:#999999;"&gt;(언젠가 곰곰이 3탄이 나올 수 있다면 좋겠네요.)&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:#999999;"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>타입스크립트 제네릭, 실무에서 제대로 활용하기</title><link>https://yozm.wishket.com/magazine/detail/3702</link><description>타입스크립트를 쓰다 보면 제네릭을 마주치는 일이 정말 많습니다. 라이브러리의 타입 정의를 읽을 때, API 응답 타입을 만들 때, 공통 함수를 작성할 때 등 어디에서든 &lt;T&gt; 같은 꺾쇠괄호가 등장하는데요, 그런데 다른 사람이 작성한 제네릭은 대충 읽을 수 있어도, 막상 직접 작성하려면 막막한 경우가 많습니다. 이번 글에서는 제네릭이 왜 필요한지부터 실무에서 자주 만나는 패턴까지 단계별로 살펴보겠습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3702</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;타입스크립트를 쓰다 보면 제네릭을 마주치는 일이 정말 많습니다. 라이브러리의 타입 정의를 읽을 때, API 응답 타입을 만들 때, 공통 함수를 작성할 때 등 어디에서든 &amp;lt;T&amp;gt; 같은 꺾쇠괄호가 등장하는데요, 그런데 다른 사람이 작성한 제네릭은 대충 읽을 수 있어도, 막상 직접 작성하려면 막막한 경우가 많습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 제네릭이 왜 필요한지부터 실무에서 자주 만나는 패턴까지 단계별로 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;미리 요점만 콕 집어보면?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;타입스크립트를 쓰다 보면 제네릭을 마주치는 일이 정말 많습니다, 제네릭이 왜 필요한지부터 실무에서 자주 만나는 패턴까지 단계별로 살펴보겠습니다.&lt;/li&gt;&lt;li&gt;any를 쓰면 반환 값의 타입 정보가 사라집니다, 타입의 중복도 없애고 타입 안전성도 유지할 수 있는 방법이기 때문입니다.&lt;/li&gt;&lt;li&gt;제네릭에 익숙해지면 타입스크립트가 기본으로 제공하는 유틸리티 타입(Pick, Omit, Partial 등)을 이해하는 것도 훨씬 수월해집니다.&lt;/li&gt;&lt;/ul&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;제네릭이 필요한 이유&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;제네릭이 왜 필요한지 이해하려면, 제네릭 없이 코드를 작성했을 때 어떤 불편함이 생기는지 먼저 살펴보는 것이 좋습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 타입을 하드코딩하면 생기는 문제&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;배열의 첫 번째 요소를 반환하는 간단한 함수를 만든다고 해봅시다. string 배열이라면 이렇게 작성할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function getFirstString(arr: string[]): string {
  return arr[0];
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 number 배열도 처리해야 한다면 어떻게 해야 할까요? 같은 로직의 함수를 하나 더 만들어야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function getFirstNumber(arr: number[]): number {
  return arr[0];
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;로직은 완전히 같은데 타입만 다르다는 이유로 함수가 계속 늘어납니다. boolean 배열, 객체 배열까지 대응하려면 끝이 없어지겠죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) any를 사용하면 되지 않을까?&lt;/strong&gt;&lt;/h4&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3702/%EA%B7%B8%EB%A6%BC1__2_.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, ChatGPT로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그렇다면 매개변수 타입을 any로 바꾸면 어떨까요? 중복 문제는 해결됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function getFirst(arr: any[]): any {
  return arr[0];
}

const result = getFirst([1, 2, 3]);
result.toUpperCase(); // 에러가 안 남&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;any를 쓰면 타입 정보가 사라질뿐 아니라, 타입스크립트의 검사 자체가 대부분 우회됩니다. result가 number인데도 toUpperCase()를 호출해도 타입스크립트가 경고해 주지 않습니다. 결국 런타임에서야 에러가 터지게 되는데, 이렇게 되면 타입스크립트를 쓰는 의미가 퇴색되겠죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;바로 이런 상황에서 필요한 것이 제네릭입니다. 타입의 중복도 없애고, 타입 안전성도 유지할 수 있는 방법이기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;제네릭 기본 문법&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;제네릭의 필요성을 확인했으니, 이제 실제 문법을 살펴보겠습니다. 함수, 인터페이스, 그리고 제약 조건까지 단계적으로 알아볼게요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3702/%EA%B7%B8%EB%A6%BC2__2_.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 함수에서의 제네릭&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;제네릭 함수는 꺾쇠괄호(&amp;lt;T&amp;gt;)로 타입 매개변수를 선언합니다. T는 호출 시점에 전달되는 값에 따라 타입이 결정됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function getFirst&amp;lt;T&amp;gt;(arr: T[]): T | undefined {
  return arr[0];
}

const num = getFirst([1, 2, 3]);       // T는 number로 추론
const str = getFirst(["a", "b", "c"]); // T는 string으로 추론&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;getFirst([1, 2, 3])을 호출하면 타입스크립트가 인자를 보고 T를 number로 추론합니다. 덕분에 반환값 num도 number 타입으로 정확하게 잡히죠. 아까 any를 썼을 때와 달리, num.toUpperCase()를 쓰면 컴파일 단계에서 에러가 발생합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;타입 추론이 원하는 대로 되지 않을 때는 직접 타입을 명시할 수도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;const value = getFirst&amp;lt;string&amp;gt;(["a", "b", "c"]);&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 대부분 타입스크립트가 알아서 추론해 주기 때문에 특별한 이유가 없다면 명시하지 않아도 괜찮습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 인터페이스와 타입에서의 제네릭&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;제네릭은 함수뿐 아니라 인터페이스와 타입 별칭에도 적용할 수 있습니다. 특히 구조는 같지만 내부 데이터 타입만 달라지는 경우에 유용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface KeyPair&amp;lt;K, V&amp;gt; {
  key: K;
  value: V;
}

const pair1: KeyPair&amp;lt;string, number&amp;gt; = {
  key: "age",
  value: 27,
};

const pair2: KeyPair&amp;lt;string, boolean&amp;gt; = {
  key: "isActive",
  value: true,
};&lt;/code&gt;&lt;/pre&gt;&lt;p style="margin-left:36pt;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 함수와 한 가지 다른 점이 있습니다. 제네릭 함수는 호출 시 인자를 보고 타입을 추론할 수 있지만, 제네릭 인터페이스나 타입 별칭은 함수처럼 호출 인자를 통해 즉시 추론되는 경우가 적기 때문에, 사용하는 위치에 따라 타입 인수를 직접 명시하는 경우가 많습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;타입 별칭에서도 동일하게 사용할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;type Pair&amp;lt;K, V&amp;gt; = {
  key: K;
  value: V;
};&lt;/code&gt;&lt;/pre&gt;&lt;p style="margin-left:36pt;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) 제네릭 제약 조건(extends)&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;제네릭은 기본적으로 어떤 타입이든 받을 수 있습니다. 하지만 실무에서는 아무 타입이나 받으면 안 되는 경우가 많은데요, 이때 extends 키워드로 타입의 범위를 제한할 수 있습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function getLength&amp;lt;T extends { length: number }&amp;gt;(data: T): number {
  return data.length;
}

getLength("hello");      // ✅ string은 length 속성이 있음
getLength([1, 2, 3]);    // ✅ 배열은 length 속성이 있음
getLength({ length: 5 }); // ✅ 직접 정의한 객체도 가능
getLength(123);           // ❌ number에는 length가 없어서 에러&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;T extends { length: number }는 “T는 반드시 number 타입의 length 속성을 가져야 한다”는 제약입니다. 이 조건을 만족하지 않는 타입이 들어오면 컴파일 단계에서 에러가 발생합니다. 이처럼 제약 조건을 활용하면 제네릭의 유연함은 유지하면서도, 필요한 속성이나 메서드가 있다는 것을 보장받을 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실무에서 자주 쓰는 제네릭 패턴&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;문법을 익혔으니, 이제 실무에서 제네릭이 어떻게 쓰이는지 살펴보겠습니다. 가장 흔하게 만나는 두 가지 패턴을 소개해 보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) API 응답 타입 래퍼&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;실무에서 백엔드 API를 호출하면, 응답 구조가 보통 일정한 형태를 따릅니다. 상태 코드와 메시지는 공통이고, 실제 데이터 부분만 엔드포인트 마다 달라지는 경우가 많죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface ApiResponse&amp;lt;T&amp;gt; {
  success: boolean;
  statusCode: number;
  data: T;
  message: string;
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이렇게 data 부분만 제네릭으로 열어두면, 하나의 인터페이스로 모든 API 응답을 커버할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;interface User {
  id: number;
  name: string;
}

interface Post {
  id: number;
  title: string;
  content: string;
}

type UserResponse = ApiResponse&amp;lt;User&amp;gt;;
type PostListResponse = ApiResponse&amp;lt;Post[]&amp;gt;;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3702/%EA%B7%B8%EB%A6%BC3__1_.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;ApiResponse&amp;lt;User&amp;gt;는 data가 User 타입이 되고, ApiResponse&amp;lt;Post[ ]&amp;gt;는 data가 Post[ ] 타입이 됩니다. 엔드포인트가 수십 개라도 API 응답 래퍼를 매번 새로 정의할 필요가 없습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 공통 유틸 함수에 제네릭 적용하기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;프로젝트를 진행하다 보면 배열이나 객체를 다루는 공통 유틸 함수를 만들게 됩니다. 이런 함수에 제네릭을 적용하면 반환 타입까지 정확하게 추론되는 것을 확인할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;// 배열에서 특정 조건을 만족하는 첫 번째 요소 반환
function findFirst&amp;lt;T&amp;gt;(arr: T[], predicate: (item: T) =&amp;gt; boolean): T | undefined {
  return arr.find(predicate);
}

const users = [
  { name: "홍길동", age: 27 },
  { name: "김철수", age: 30 },
];

const found = findFirst(users, (user) =&amp;gt; user.age &amp;gt; 25);
// found의 타입: { name: string; age: number } | undefined&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;findFirst에 users 배열을 넘기면, 타입스크립트가 T를 { name: string; age: number }로 추론합니다. 덕분에 predicate 콜백의 user 매개변수에서도 user.age에 자동완성이 동작하고, 반환값의 타입도 정확하게 잡힙니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;객체의 특정 필드를 추출하는 함수도 제네릭과 제약 조건을 조합하면 타입 안전하게 만들 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-typescript"&gt;function pluck&amp;lt;T, K extends keyof T&amp;gt;(arr: T[], key: K): T[K][] {
  return arr.map((item) =&amp;gt; item[key]);
}

const names = pluck(users, "name"); // string[]
const ages = pluck(users, "age");   // number[]&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;K extends keyof T는 “K는 T의 키 중 하나여야 한다”는 제약입니다. 덕분에 존재하지 않는 키를 넘기면 컴파일 에러가 발생하고, 반환 타입도 해당 키의 값 타입에 맞게 자동으로 추론됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 제네릭이 필요한 이유부터 기본 문법, 그리고 실무 패턴까지 살펴봤습니다. 처음에는 &amp;lt;T&amp;gt; 같은 꺾쇠괄호가 낯설게 느껴질 수 있지만, 결국 핵심은 하나입니다. 타입을 값처럼 매개변수로 전달해서 중복 없이 다양한 타입에 대응하는 것이죠. 실무에서 반복되는 타입 패턴이 보인다면, 그것이 바로 제네릭을 쓸 타이밍입니다. 특히 API응답 타입이나 공통 유틸 함수처럼 구조는 같고 데이터만 달라지는 상황에서 제네릭은 가장 큰 효과를 발휘합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;제네릭에 익숙해지면 타입스크립트가 기본으로 제공하는 유틸리티 타입(Pick, Omit, Partial 등)을 이해하는 것도 훨씬 수월해집니다. 이 유틸리티 타입들도 결국 제네릭으로 만들어진 것이기 때문입니다.&lt;/p&gt;&lt;hr&gt;&lt;p style="text-align:justify;"&gt;&amp;lt;참고&amp;gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://ts.winterlood.com/"&gt;&lt;u&gt;한 입 크기로 잘라먹는 타입스크립트&lt;/u&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://inpa.tistory.com/entry/TS-%F0%9F%93%98-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Generic-%ED%83%80%EC%9E%85-%EC%A0%95%EB%B3%B5%ED%95%98%EA%B8%B0"&gt;&lt;u&gt;타입스크립트 Generic 타입 정복하기&lt;/u&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;&lt;span style="color:#999999;"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>시니어를 넘어 ‘백수저’ 리드 개발자로</title><link>https://yozm.wishket.com/magazine/detail/3701</link><description>개발 현장에서 시간은 누구에게나 공평하게 흐릅니다. 그렇게 연차가 쌓이고 경험이 더해지면 우리는 자연스레 시니어(Senior)라는 타이틀을 달게 됩니다. 하지만, 코드를 오래 작성했다고 해서 누구나 팀과 프로덕트를 이끄는 리드(Lead) 개발자가 되는 것은 아닙니다. 리드를 목표로 하는 것은 어쩌면 매일 하는 일의 기준을 한 단계 높여놓겠다는 뜻일지도 모릅니다. 같은 업무를 처리하더라도 “리드라면 이 상황에서 어떤 판단을 했을까?”라는 시각으로 봐야 더 높은 학습 효율을 끌어낼 수 있습니다. 주니어 시절의 방향 설정이 중요한 이유가 여기 있습니다. 주니어 레벨부터 리드 개발자의 마인드셋을 지향해야 매일의 경험을 성장의 자양분으로 환산해낼 수 있습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3701</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;주니어 개발자라도, 리드 개발자를 지향해야 하는 이유&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;개발 현장에서 시간은 누구에게나 공평하게 흐릅니다. 그렇게 연차가 쌓이고 경험이 더해지면 우리는 자연스레 시니어(Senior)라는 타이틀을 달게 됩니다. 하지만, 코드를 오래 작성했다고 해서 누구나 팀과 프로덕트를 이끄는 리드(Lead) 개발자가 되는 것은 아닙니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;주니어 시절부터 리드의 시선을 가지라는 조언은 단순히 빠른 승진에 야망을 품으라는 말이 아닙니다. 커리어라는 긴 흐름 속에서 표류하지 않고 앞으로 나아갈 방향을 찾는 일에 가깝습니다. 목적지를 알고 움직이는 사람은 길을 쉽게 잃지 않기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;마찬가지로 지금 당장 리드 역할을 맡으라는 것도 아닙니다. 어쩌면 매일 하는 일의 기준을 한 단계 높여놓겠다는 뜻일지도 모릅니다. 같은 업무를 처리하더라도 “리드라면 이 상황에서 어떤 판단을 했을까?”라는 시각으로 봐야 더 높은 학습 효율을 끌어낼 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;주니어 시절의 방향 설정이 중요한 이유가 여기 있습니다. 주니어 레벨부터 리드 개발자의 마인드셋을 지향해야 매일의 경험을 성장의 자양분으로 환산해낼 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3701/image4.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Gemini로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;시니어는 ‘어떻게’를 풀고, 리드는 ‘왜’를 정의한다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;주니어 시절부터 리드의 시선을 가지는 것의 중요성을 이야기했습니다. 그렇다면 한 가지 의문이 생깁니다. &lt;i&gt;“시니어 개발자와 리드 개발자는 무엇이 다를까요?”&lt;/i&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;흔히들 코딩 실력이 극한에 달하면 리드 개발자가 된다고 생각합니다. 하지만 시니어에서 리드로 넘어가는 과정은 단순한 스킬의 향상보다는 &lt;strong&gt;패러다임의 전환(Paradigm Shift)&lt;/strong&gt;에 가깝습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이러한 관점은 실제로 실리콘밸리의 빅테크 기업이 정의하는 엔지니어링 레벨(Engineering Level) 가이드에서도 핵심 기준으로 다뤄집니다. 구글이나 메타의 업무 가이드에서는 리드로 성장하기 위해 이전과는 다른 차원의 비즈니스 관점과 주도성을 가질 것을 요구합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그들이 공통적으로 강조하고, 실제 실무에서도 체감할 수 있는 결정적인 차이를 3가지로 요약해 보았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1. 해결사(Problem Solver) vs 정의자(Problem Definer)&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;시니어 개발자의 핵심 역량은 뛰어난 ‘문제 해결 능력’이라고들 합니다. 복잡한 요구사항이 주어졌을 때도 엣지 케이스까지 고려해 버그 없는 좋은 코드를 짜는 거죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 리드 개발자는 JIRA 티켓이 만들어지기 전부터 움직입니다. 단순히 주어진 요청을 처리하는 데 그치지 않고, 데이터와 사용자 피드백을 기반으로 “지금 우리가 정말로 해결해야 할 문제는 무엇인가? 혹시 근본적인 원인은 다른 곳에 있지 않은가?”를 고민해야 합니다. 즉, 리드는 ‘무엇이 문제인지’를 새로 프레이밍(Framing)하는 사람입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3701/image6.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, ChatGPT로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2. 기술적 해법(How to build) vs 비즈니스 우선순위(What &amp;amp; Why now)&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;시니어 개발자는 “이 기능을 어떻게(How) 가장 효율적이고 안정적으로 구현할 수 있을까?”를 고민하며, 팀을 위한 표준 가이드와 문서를 정리합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반면 리드 개발자는 &lt;strong&gt;“우리는 무엇을(What), 왜 하필 지금(Why now) 만들어야 하는가?”&lt;/strong&gt;를 먼저 묻습니다. 아무리 기술적으로 우아한 아키텍처도 지금 제품의 비즈니스 단계와 맞지 않거나 사용자에게 제공하는 가치가 낮다면 과감하게 “지금 우리 우선순위가 아닙니다”라고 말하며 조직을 설득합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3. 기술의 언어(옳은 답) vs 비즈니스의 언어(가치와 비용)&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;시니어 개발자가 ‘기술적으로 100점에 가까운 정답’을 만들어내는 사람이라면, 리드 개발자는 그 정답을 다른 조직에 ‘설득하고 전달할 수 있는 사람’입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;새로운 기술 스택을 도입하거나 레거시 시스템을 개선해야 할 때, 리드는 단순히 “더 최신 기술이니까요”라고 하지 않습니다. 대신 비용 절감, 장애 리스크 감소, 그리고 비즈니스 가치 창출이라는 &lt;strong&gt;비즈니스의 언어&lt;/strong&gt;로, 타 부서와 경영진에게 선택의 근거를 명확하게 전달합니다.&lt;/p&gt;&lt;hr&gt;&lt;p style="text-align:justify;"&gt;실무자의 정점이자 전략가로 첫 걸음을 내딛은 리드 개발자는 팀의 방향을 결정하는 ‘아키텍트(Architect)’입니다. 코드가 어떻게 동작하는지를 넘어, 우리 팀과 제품이 어디를 향해 나아가고 있는지를 아는 리드 개발자는 조직에서 매우 귀한 인재입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실무에서 증명해야 할 리드의 역할&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;시니어와 리드 개발자의 시야 차이를 보고 나면, 이런 질문이 자연스럽게 떠오를 겁니다. &lt;i&gt;“아직 주니어인 내가, 실무에서 어떻게 리드의 역할을 보여줄 수 있을까?”&lt;/i&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실리콘밸리 빅테크를 비롯한 주요 테크 기업들의 평가 원칙 중 하나는 &lt;strong&gt;“그 다음 레벨로 승진하려면, 이미 그 레벨처럼 일하고 있다는 것을 증명해야 한다(Demonstrate next-level behavior)”&lt;/strong&gt;입니다. 단순히 연차가 쌓였다고 타이틀을 주는 대신, 주니어 시절부터 리드의 역할과 행동 방식을 실무에서 미리 보여주어야 다음 단계로 나아갈 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;‘리드 개발자’처럼 일한다는 것, 그 &lt;strong&gt;핵심은 선제성(Proactivity)과 영향력(Influence)&lt;/strong&gt;으로 요약됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1. 규칙을 따르는 사람에서 만드는 사람으로&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;주니어 시절에는 보통 팀에 이미 구축된 컨벤션과 아키텍처를 이해하고 따르는 데 집중합니다. 하지만 다음 레벨로 가려면 지금 시스템의 불편함을 당연하게 여기지 않는 태도가 필요합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;“우리 팀의 코드 리뷰가 주관적으로 이루어지고 있는데, 이런 체크리스트를 도입해 보면 어떨까요?”라고 제안해 보세요. 또는 반복되는 수동 배포 과정을 스크립트로 자동화하거나, 파편화된 에러 처리 방식을 하나로 정리하는 가이드를 만드는 것도 좋은 방법입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이처럼 &lt;strong&gt;팀의 생산성을 높이고 올바른 방향을 제시하는 규칙(Standard)을 설정&lt;/strong&gt;하는 것이 리드 역할의 출발점입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2. 코드 작성 전, 기획의 최전선에 서기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;코드를 다 짜고 나서 버그를 고치는 것보다, 기획 단계에서 구조적인 결함을 발견하는 편이 훨씬 저렴합니다. 리드 개발자는 이슈가 터지고서야 이를 수습하는 사람이 아니라, 이슈가 터질 만한 곳을 미리 막는 사람입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;JIRA 티켓의 작업을 수동적으로 기다리지 마세요. 기획 회의나 디자인 리뷰 단계에 적극적으로 참여해야 합니다. “이 기능은 사용자 트래픽이 몰릴 경우 DB에 병목이 생길 수 있으니, 캐싱 전략을 추가하는 것이 안전합니다” 같이 말하는 거죠. 이러한 행동이 바로 선제성(Proactivity)을 발휘하는 방식입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;3. 우리 팀을 넘어 전사적 임팩트 창출하기&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3701/image1.jpg"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Gemini로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 지점이 실무형 시니어와 리드 개발자를 가르는 가장 결정적인 차이입니다. 업계에서 리드 엔지니어를 평가할 때 가장 중요하게 보는 기준은 바로 &lt;strong&gt;영향력의 반경(Radius of Impact)&lt;/strong&gt;입니다. 자신의 코드가 팀 내부에만 영향을 미친다면 시니어에 머물겠지만, 전사에 영향을 준다면 리드로 평가받게 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;거창할 필요는 없습니다. 내가 해결한 어려운 트러블슈팅 과정을 사내 기술 블로그나 위키에 정리해 보세요. 또는 최근 주목받는 AI 코딩 도구(GitHub Copilot, ChatGPT 등)를 실무에 어떻게 적용해 생산성을 높였는지 베스트 프랙티스로 정리해 공유하는 것도 좋은 방법입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;나의 작은 시도가 다른 팀의 작업 시간을 단축시켰다면, 이미 리드 개발자의 영향력(Influence)을 조직 전반에 행사하고 있는 셈입니다.&lt;/p&gt;&lt;hr&gt;&lt;p style="text-align:justify;"&gt;결국, 직급은 남이 주지만, 역할은 내가 취하는 겁니다. “내가 아직 주니어인데 이런 제안을 해도 될까?”라는 걱정은 내려놓아도 좋습니다. 개발 표준을 제안하고, 기획에 의견을 더하며, 지식을 공유하는 일에는 연차의 제한이 없습니다. 오늘 당장 내가 속한 조직에서 작은 개선 포인트 하나라도 찾아보세요. 이러한 작은 주도성들이 쌓이면서, 자연스럽게 여러분을 다음 레벨로 이끌게 될 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;리드 개발자의 커뮤니케이션, 글쓰기, 그리고 학습법&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;리드 개발자가 갖춰야 할 강력한 무기가 있습니다. 커뮤니케이션, 글쓰기, 그리고 지속적인 학습 역량이죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실리콘밸리의 빅테크 기업들도 이 점을 명확히 인식하고 있습니다. 이를테면 구글의 엔지니어링 레벨 시스템을 보면, L5(시니어)까지는 코딩 능력과 시스템 설계 역량이 주요 평가 기준으로 작용합니다. 하지만 L6(스태프) 이상부터는 전혀 다른 기준이 적용됩니다. 실제로 구글에서 Principal Engineer로 일하는 Adam Bender는 이를 다음과 같이 설명합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;i&gt;L5까지의 성장은 가파르지만 선형적이다. 더 효율적으로, 더 빠르게, 더 많이. 하지만 L6는 사다리 자체가 바뀌는 것에 가깝다. &lt;strong&gt;코드를 작성하는 능력보다 명확한 커뮤니케이션과 전략적 사고 능력이 더 중요&lt;/strong&gt;해진다.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;최근 국내 주요 IT 기업들도 이러한 글로벌 기준에 맞춰 엔지니어링 레벨 체계를 재정비하고 있습니다. 그렇게 대부분 시니어 레벨에서는 테크 리드 역할을 기대하는 구조로 점차 전환되고 있죠. 그렇다면 다음 단계의 사다리를 오르기 위해, 우리는 구체적으로 어떤 역량을 길러야 할까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3701/image5.jpg"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Gemini로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1. 커뮤니케이션: 기술적 임팩트를 비즈니스 임팩트로&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;리드 개발자는 PM, 디자이너, 경영진과 소통할 때 개발자만 쓰는 언어에 머무르지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;같은 사실, 다른 파급력:&lt;/strong&gt; “이 API의 레이턴시가 200ms에서 50ms로 줄었습니다”라고 말과 “사용자가 검색 결과를 4배 빠르게 받으며 이탈률이 감소할 것으로 예상됩니다”라는 말은 같은 사실을 설명하고 있습니다. 하지만 이를 듣는 사람에게 전달되는 영향력은 완전히 다릅니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;평가를 가르는 커먼 센스(Common Sense):&lt;/strong&gt; 이러한 말하기 능력은 특히 성과 평가에서 결정적인 차이를 만듭니다. 같은 일을 수행했더라도 “캐싱 레이어를 리팩토링했습니다”라고 쓰는 대신 “캐싱 구조 개선으로 서버 비용을 월 200만 원 절감하고, 응답 속도 개선으로 전환율이 15% 상승했습니다”라고 표현하면 평가가 달라질 수밖에 없습니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이는 리드 레벨에서도 동일하게 적용됩니다. 기술적 성과를 비즈니스 언어로 번역해 상위 조직에 전달하는 리드가 있는 팀과 편한 방식 그대로 보고하는 리드가 있는 팀은 받는 평가 자체가 크게 달라집니다. 개발 성과를 몇 MD(Man-Day) 절감했는지, 비용을 얼마나 줄였는지처럼 &lt;strong&gt;누구나 이해할 수 있는 숫자로 설득하는 것&lt;/strong&gt;. 이것이 바로 리드 수준의 커뮤니케이션입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2. 글쓰기: 구글 독스를 내 IDE로&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;리드 개발자가 되면 코드보다 문서로 더 많은 의사결정에 영향을 미칩니다. Adam Bender는 “구글 독스(Google Docs)가 사실상 내 IDE다.”라고 표현하기까지 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;스케일링의 도구, 글쓰기:&lt;/strong&gt; 전략 문서를 쓰고, 가치 문서를 다루고, 시스템 설계 문서를 작성하며, 다른 사람의 문서를 리뷰하는 일까지, 업무 대부분은 코드가 아니라 글로 이루어집니다. Adam은 글쓰기 역량을 키우는 것이 자신의 영향력(Influence)을 스케일하는 가장 효과적인 방법이었다고 강조합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;회의 열 번보다 강력한 문서:&lt;/strong&gt; RFC(Request for Comments), 기술 제안서, 아키텍처 결정 기록(ADR), 장애 보고서(Post-mortem) 등 대부분 핵심은 글로 쓰입니다. 읽는 사람의 시간을 존중하면서도 핵심을 명확하게 전달하는 글쓰기 능력은 잘 쓴 코드만큼이나 리드 개발자의 핵심 역량입니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3. 학습 역량: 일상에서 배우는 평생 학습자&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;기술의 변화 속도는 무자비합니다. 그런만큼 리드 개발자는 학습에 높은 우선순위를 두어야 합니다. 다만, 가장 중요한 것은 거창한 계획이 아니라 ‘일관성’입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;업무와 학습의 일체화:&lt;/strong&gt; 그토록 바쁜 일상에서 일관성을 어떻게 유지할까요? 가장 효과적인 방법은 &lt;strong&gt;학습을 업무와 분리하지 않는 것&lt;/strong&gt;입니다. 코드 리뷰를 할 때마다 새로운 패턴을 메모하고, 장애를 대응한 다음에는 근본 원인을 파고들어 시스템의 새로운 영역을 학습해 나가야 합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;학습을 습관으로:&lt;/strong&gt; 학습을 주말에 몰아서 수행하는 숙제처럼 두기보다, 매일 숨쉬듯 반복하는 ‘루틴’으로 정착시키는 것도 중요합니다. 꾸준함은 의지보다는 환경에서 만들어집니다. 이렇게 쌓은 지식을 블로그나 오픈소스에 공유하며 나만의 성장 선순환 구조를 갖추는 것이야말로 리드 개발자의 학습 방식입니다.&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;p style="text-align:justify;"&gt;이렇게 리드로 도약하기 위해서는 기술 그 이상의 역량이 필요합니다. 전략적인 커뮤니케이션과 논리적인 글쓰기, 그리고 멈추지 않는 학습 습관을 내 것으로 만드세요. 이 무기들을 갈고닦아 &lt;strong&gt;성장의 방향을 조직의 가치와 일치&lt;/strong&gt;시킬 수 있다면, 어느덧 다음 레벨의 사다리 위에 서 있는 자신을 발견할 것입니다. 모두 성장의 사다리를 갈아탈 준비가 되었나요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며: 시간은 시니어를 만들지만, 방향은 리드를 만든다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;주니어라는 타이틀로 리드처럼 행동하다 보면, 문득 &lt;strong&gt;“내가 너무 앞서가는 건 아닐까?”&lt;/strong&gt; 하는 자기 의심(Imposter Syndrome)에 빠질 수도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3701/Gemini_Generated_Image_we6yrtwe6yrtwe6y.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 요즘IT, Gemini로 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;lt;흑백요리사2&amp;gt;에 출연한 손종원 셰프는 “내가 3스타에서 일했다고 해서 그곳이 나를 3스타로 만들어 주는 건 아니다. 나의 스타는 내가 만들어 가야 한다.” 라고 이야기 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;리드 개발자도 마찬가지입니다. 이는 직급의 문제가 아닌 문제를 대하는 태도, 비즈니스를 바라보는 시야, 그리고 일관된 학습 습관에 관한 이야기입니다. 당장의 위치는 주니어 개발자라 하더라도 리드의 렌즈를 끼고 치열하게 고민한 그 여정 자체가 여러분을 뛰어난 개발자로 성장시켜 줄 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;좋은 코드에 집중하는 시니어로 남을 것인지, 아니면 팀과 프로덕트의 방향을 결정하는 리더로 성장할 것인지. 그 갈림길은 10년 뒤 시니어가 되었을 때가 아닌 &lt;strong&gt;주니어인 바로 지금&lt;/strong&gt; 어떤 방향을 선택하느냐에 따라 결정됩니다. 그러니 지금부터 리드처럼 생각하고, 리드처럼 기록하며, 리드처럼 제안해 보세요. 남은 것은 묵묵히 그 길을 걸어가는 것뿐입니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>반복적인 SQL 업무를 자동화하는 AI 에이전트 '곰곰이'</title><link>https://yozm.wishket.com/magazine/detail/3697</link><description>2025년 10월에 태어난 곰곰이는 STAYGE Labs에서 사내 데이터 분석 AI Agent를 담당하며, 데이터를 잘 다룬다는 특징이 있습니다. 짧은 기간이지만, 구성원들이 곰곰이를 통해 데이터 속에 숨어 있는 높은 차원의 정보를 발견하고, 데이터 비전문가임에도 스스로 데이터를 분석할 수 있는 역량을 강화해 가는 모습을 보니 곰곰이를 만든 ‘곰빠’로서 뿌듯한 기분을 느끼고 있는데요. 이번 글에서는 곰곰이는 무엇이고 어떻게 생겼으며, 왜 만들게 되었는지까지 알아보도록 하겠습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3697</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;2025년 10월에 태어난 곰곰이는 STAYGE Labs에서 &lt;strong&gt;사내 데이터 분석 AI Agent&lt;/strong&gt;를 담당하며, 데이터를 잘 다룬다는 특징이 있습니다. 짧은 기간이지만, 구성원들이 곰곰이를 통해 &lt;strong&gt;데이터 속에 숨어 있는 높은 차원의 정보를 발견&lt;/strong&gt;하고, &lt;strong&gt;데이터 비전문가임에도 스스로 데이터를 분석할 수 있는 역량을 강화&lt;/strong&gt;해 가는 모습을 보니 곰곰이를 만든 ‘곰빠’로서 뿌듯한 기분을 느끼고 있는데요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 곰곰이는 무엇이고 어떻게 생겼으며, 왜 만들게 되었는지까지 알아보도록 하겠습니다.&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;왜 만들었을까?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;제가 STAYGE Labs에 처음 입사했을 때 맡은 프로젝트가 Redash를 사용해 데이터 추출 업무를 자동화하고 BI 대시보드를 구축하는 것이었습니다. BI 도구가 있으니까 데이터 업무에서 자유로울 수 있을 것으로 기대하지만 실상은 그렇지 않습니다. BI 대시보드와 데이터 추출 업무에 사용되는 SQL들은 정적이기 때문에, 새로운 기능이 오픈되어 새로운 데이터가 보고 싶거나, 데이터 추출 업무의 규칙이 바뀌어 살짝 다른 모양의 데이터를 보고 싶다면, &lt;strong&gt;매번 새로운 SQL을 추가하거나 수정해야 하는 불편함&lt;/strong&gt;이 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;SQL을 작성하는 것은 쉬운 일이 아닙니다. SQL 작성 시 &lt;strong&gt;데이터 간의 관계를 잘 파악&lt;/strong&gt;하고 있어야 하며, 각 테이블의 특징에 맞게 쿼리 엔진에 부담이 되지 않는 &lt;strong&gt;튜닝 작업&lt;/strong&gt;도 필요합니다. 그리고 가끔씩 사용하는 &lt;strong&gt;고급 SQL은 매번 잊어버려&lt;/strong&gt; 종종 검색을 하곤 합니다. AI가 대세인 지금 시대에 저는 생각했습니다. “귀찮다!”&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3697/1.webp"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;2024년 초부터 2025년에 이르기까지 기업들이 AI Agent를 사용한 자동화 사례를 앞다투어 기술 블로그와 각종 세미나에서 자랑하기 시작했습니다. &lt;a href="https://medium.com/musinsa-tech/langchain-%EA%B8%B0%EB%B0%98-%EC%A7%80%EB%8A%A5%ED%98%95-%EC%9E%90%EB%8F%99%ED%99%94-%EB%8F%84%EC%9E%85%EA%B8%B0-d83cb93291fa"&gt;&lt;u&gt;CS 자동화&lt;/u&gt;&lt;/a&gt;, &lt;a href="https://velog.io/@useradd_temp/%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81-%EC%9D%B4%EC%A0%9C-%EC%95%8C%EB%9E%8C-%EB%BF%90%EB%A7%8C-%EC%95%84%EB%8B%88%EB%9D%BC-%EB%B6%84%EC%84%9D%EB%8F%84-%EC%9E%90%EB%8F%99%ED%99%94-%EB%90%9C"&gt;&lt;u&gt;모니터링 자동화&lt;/u&gt;&lt;/a&gt;, &lt;a href="https://blog.banksalad.com/tech/how-banksalad-testdata/"&gt;&lt;u&gt;테스트 데이터 생성&lt;/u&gt;&lt;/a&gt;, &lt;a href="https://techblog.woowahan.com/18144/"&gt;&lt;u&gt;Text-to-SQL&lt;/u&gt;&lt;/a&gt;, &lt;a href="https://aws.amazon.com/ko/blogs/tech/building-ai-wine-label-image-search-with-bedrock/"&gt;&lt;u&gt;이미지 검색&lt;/u&gt;&lt;/a&gt; 등 정말 다양한 사례가 있었고, 특히 자연어를 통해 SQL을 생성하여 데이터 분석을 자동화하는 ‘Text-to-SQL’ 사례가 유독 많았습니다. 그리고 모든 사례가 &lt;strong&gt;기존에 없던 새로운 가치를 만들고 생산성을 높였다&lt;/strong&gt;는 이야기를 합니다. 저는 여기서 다시 생각했습니다. “왜 나에게는 저런 것이 없지? 부러워!”, “나도 만들어서 동료들에게 억지로라도 맛보게 해야겠다!!”&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;무엇을 만들까?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AI Agent를 향한 첫걸음으로 데이터 업무와 분석 작업으로부터 나를 해방해 줄 수 있는 사내 데이터 분석 AI Agent부터 시작하기로 했습니다. 우선 사내 데이터 분석 AI Agent를 동료들이 친근하고 쉽게 다가갈 수 있도록, &lt;strong&gt;궁금한 것은 곰곰이 생각하고 답변해준다는 의미인 “곰곰이”&lt;/strong&gt; 라는 이름과 귀여운 캐릭터를 만들어 주었습니다. (이하 사내 데이터 분석 AI Agent는 ‘곰곰이’라고 칭함.)&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;곰곰이로 달성하고자 하는 것을 네 가지로 정했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;개발자를 대신해서 &lt;strong&gt;데이터를 분석하거나 추출하는 업무를 수행한다.&lt;/strong&gt; 데이터 분석 업무는 복잡하여 자동화하기 어렵지만, LLM이 등장한 현시점에서 단순하고 반복적인 업무를 넘어 복잡하고 반복적인 업무도 엔지니어링을 통해 자동화할 수 있습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;비개발 직무인 각 &lt;strong&gt;도메인의 전문가들이 AI를 통해 데이터의 잠재력을 폭발시킨다.&lt;/strong&gt; 개발자는 SQL을 다룰 수 있을 뿐 기획, 마케팅, 판매와 같은 전문 분야에 대해서는 잘 모릅니다. 소통의 단계를 줄여 도메인 전문가가 직접 데이터를 다루면 데이터 안에서 기존에 없던 새로운 정보를 찾아낼 것입니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;조직의 &lt;strong&gt;데이터 활용 능력을 높여 데이터를 통해 미래를 예측하고 시장의 변화를 빠르게 감지한다.&lt;/strong&gt; 데이터 분석 능력이 높아지면 과거의 데이터를 통해 미래를 예측할 것이고, AI에게 자율성을 부여하여 인간보다 빠르게 이상 탐지를 할 것입니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;하나만 잘하는 싱글 에이전트를 넘어 &lt;strong&gt;많은 분야에 기여할 수 있는 멀티 에이전트로 진화한다.&lt;/strong&gt; 데이터 분석뿐만 아니라 개발, 기획, 운영 분야에 숨어 있는 비효율을 해결할 수 있는 기능을 추가하며 점진적으로 진화할 것입니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3697/2.webp"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;본격적인 설계와 개발에 앞서 제가 세운 가설에 의문점을 던졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;내가 만든 제품이 고객들에게 정말로 필요한 것일까?&lt;/li&gt;&lt;li style="text-align:justify;"&gt;실제 고객들은 어떤 불편함을 겪고 있지?&lt;/li&gt;&lt;li style="text-align:justify;"&gt;어떤 기능을 먼저 만들어 선보일 것인가?&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;제가 공들여 만든 제품이 실제 고객에게 필요하지 않아 외면받는 것이 싫었고, 제품 개발의 성공 가능성을 높이기 위해 고객인 동료들을 직접 찾아가 인터뷰하기로 했습니다. 인터뷰 대상은 평소 데이터를 자주 보거나 요청하는 분, 그리고 곰곰이의 능력이 필요하거나 잘 활용할 것 같은 분들을 위주로 선정하여 &lt;strong&gt;다양한 직무와 직급의 동료들을 인터뷰&lt;/strong&gt;했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;인터뷰를 통해 기존 시스템에서 동료들이 데이터를 접하는 데 어려워하는 공통적인 다섯 가지 불편함을 찾았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;보이지 않는 데이터&lt;/strong&gt;: 비개발 직군은 우리 데이터가 어디에, 어떻게 존재하는지 알 수 없음.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;기약 없는 대기 시간&lt;/strong&gt;: “데이터 좀 뽑아주세요”라고 요청한 후, 개발자의 일정을 기다려야만 함.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;보고 싶은 것만 못 봄&lt;/strong&gt;: 기존 대시보드는 정해진 틀만 제공하여 새로운 관점의 분석이 불가능함.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;흩어진 정보들&lt;/strong&gt;: BigQuery, Athena, PostgreSQL, 각종 SaaS에 데이터가 파편화되어 통합 확인이 어려움.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;소 잃고 외양간 고치기&lt;/strong&gt;: 이슈(구독 취소 등)를 미리 알지 못해 선제적 대응 타이밍을 놓침.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3697/3.webp"&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;인터뷰와 도출한 문제를 기반으로 곰곰이에게 필요한 기능과 유저 스토리, MVP 범위를 포함한 1차 기획서를 작성했습니다. 기획서는 긴 개발 과정에서 &lt;strong&gt;다른 길로 빠지지 않을 수 있는 이정표&lt;/strong&gt;가 되어 주며, 아직 &lt;strong&gt;실체가 없는 곰곰이가 무엇인지 동료들에게 이해시키는 효과&lt;/strong&gt;가 있습니다. 또한 곰곰이의 신규 기능을 스프린트 단위로 개발하고 배포하여 사용자의 이용 패턴을 관찰하면, 개발자의 입장이 아닌 사용자의 입장에서 우선순위가 높은 기능이 무엇인지 파악할 수 있어 빠르고 효율적인 개발이 가능합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3697/4.webp"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;어떻게 사용하나?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AI Agent를 많이 경험해 보지 않은 분이 여기까지 아티클을 읽으셨다면, 곰곰이가 도대체 어떻게 생겼는지, 그래서 무엇을 할 수 있는지 감이 잘 잡히지 않을 것입니다. 곰곰이의 사용 방법과 능력 및 사용 범위를 살펴보며 더 자세히 이해해 보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;사용하기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;곰곰이의 사용 방법은 매우 간단합니다. &lt;strong&gt;“질문한다 &amp;gt; 기다린다 &amp;gt; 답변받는다.”&lt;/strong&gt; ChatGPT를 사용해 보신 분이라면 익숙할 경험과 유사합니다. ChatGPT가 인터넷 검색을 통해 답변을 생성한다면, 곰곰이는 우리 서비스의 DB 검색을 통해 답변을 생성합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;원하는 데이터와 대상 기간을 자연어로 입력하면, 곰곰이가 분석 과정을 거쳐 원하는 답변을 주는 것을 확인하실 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3697/5.webp"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;잘 사용하기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;다음으로 곰곰이의 데이터 분석 수준은 어느 정도인지 궁금하실 겁니다. 저의 직관이 담긴 의견을 말씀드리자면, 질문하는 사람의 AI 활용 능력에 따라 중급 데이터 분석가 수준까지는 충분한 역량을 보여주는 것 같습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;i&gt;인간: “2025년 12월 LiNC 서비스의 재화 판매량과 매출액을 산출하고, 구매자 국적 및 재구매율 등 세부 지표를 통해 종합적인 판매 성과를 정량적으로 분석받고자 함”&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이것은 실제 동료가 원하던 데이터에서 얻고자 한 정보를 각색한 질문입니다. 단순히 기간 내 매출 합계를 구하는 것이 아니라, 구매자 국적 차원에서 재구매율까지 도출하고 종합적인 성과로 정리해야 합니다. 만약 제가 직접 분석했다면 몇 시간은 필요하고, 협업 상황에 따라 며칠이 소요됐을 정도로 까다로운 분석입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;i&gt;곰곰이: “2025년 12월 총 x원(x건)의 매출을 기록하며 저가형 패키지와 한국 시장이 판매량을 견인했으나, 인당 구매 빈도(충성도)는 해외 사용자가 더 높은 것으로 분석되었습니다.”&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결론적으로 곰곰이는 사용자와 여러 단계의 협업을 거쳐 몇 분 안에 만족스러운 답변을 주었습니다. 곰곰이가 훌륭하게 답변했지만, 질문자의 능력에 따라 답변의 수준이 달라질 수 있습니다. 곰곰이를 더 잘 사용하기 위한 방법은 다음과 같습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;의도를 알 수 있는 구체적인 질문&lt;/strong&gt;: “매출 알려줘”와 같은 질문으로는 대상 기간과 서비스를 알 수 없습니다. 원하는 분석 결과를 얻기 위해 필수적인 정보를 질문에 담아야 합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;단계적인 접근&lt;/strong&gt;: AI에게 너무 큰 단위의 요청을 하면 분석 과정에서 엉뚱한 방향으로 빠질 수 있습니다. [판매량 &amp;gt; 매출 &amp;gt; 국가 비율 &amp;gt; 재구매율 &amp;gt; 종합] 등 질문을 계층화하여 접근하면 성공적인 답변을 받을 확률이 높습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;칭찬&lt;/strong&gt;: 같은 질문인데 귀찮은 협업 과정을 매번 반복할 수는 없겠죠. 곰곰이에게 칭찬을 해준다면, 이를 잘된 분석으로 간주합니다. 그리고 대화 내용을 기반으로 질문과 분석 과정을 정리 및 저장하여 다음 유사 요청에 빠르고 정확하게 답변하게 됩니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3697/6.webp"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;도구들&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;문맥상 다음에 올 확률이 가장 높은 단어를 생성할 뿐인 거대 언어 모델(LLM)이 탑재된 곰곰이가 질문의 의도를 파악하고, SQL을 작성하며 데이터를 분석할 수 있는 이유는 무엇일까요? 바로 사전에 만들어 둔 도구들(Tools)을 사용하기 때문입니다. 도구에 대한 설명과 사용 방법을 곰곰이에게 학습시키면 사용자의 요청이 들어왔을 때 가장 적절한 답변을 만들기 위해 자율적으로 도구를 선택하고 사용하게 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;SQL 실행 도구&lt;/strong&gt;: 데이터베이스에서 정보를 조회하고 분석할 때 사용하며, 토큰 절약을 위해 100줄 이하의 결과만 조회 가능합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;CSV 변환 도구&lt;/strong&gt;: 100줄이 넘는 대용량 데이터 추출이 필요할 때 사용하며, CSV 파일로 변환하여 다운로드할 수 있는 링크를 제공합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;예시 SQL 저장소&lt;/strong&gt;: 질문을 해결하기 위한 SQL 작성 전 정보 수집을 위해 사용하며, 테이블 스키마나 문제를 해결한 예시 SQL을 저장하고 불러올 수 있습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;장기 기억 저장소&lt;/strong&gt;: 질문과 관련된 도메인 지식, 접근 방법, 풀이 과정 등 과거의 기억을 불러와 작업을 예열할 때 사용하며, 대화 맥락에서 필요한 정보를 자율적으로 요약하여 이후 유사한 요청에서 효율적으로 동작합니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3697/7.webp"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;곰곰이에게는 적은 수의 도구가 주어지고 구조도 단순하지만, 매우 높은 가치의 결과를 만들어 냅니다. 곰곰이가 &lt;strong&gt;높은 가치를 창출할 수 있는 비밀은 바로 ‘반복’과 ‘학습’에&lt;/strong&gt; 있습니다. 우선 반복의 원리를 알기 위해서는 ‘ReAct’ 프롬프트를 이해해야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;ReAct&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;여기서 ReAct는 프론트엔드에서 유명한 ‘React JS’가 아닙니다. Reasoning(추론)과 Acting(행동)을 결합한 단어로, LLM에게 “생각 — 행동 — 관찰”의 과정을 유도하는 프롬프트 기법입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;ReAct는 다음과 같은 반복적인 흐름으로 작동합니다. 프로그램을 통해 각 과정이 반복될 수 있는 구조를 구축하면, 곰곰이처럼 LLM이 생각과 도구 선택을 반복하며 자율적으로 문제를 해결할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Command (명령):&lt;/strong&gt; 지난주 투표당 투표 횟수에 대해 분석해 줘.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Thought (추론):&lt;/strong&gt; 질문과 유사한 기억이 있는지 저장소를 확인합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Action (행동):&lt;/strong&gt; “투표 및 투표 기록 테이블 검색.”&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Observation (관찰):&lt;/strong&gt; 이전에 동일한 질문을 한 적이 있으며, 진행 중인 투표와 투표 기록을 조인(Join)하는 예시 SQL을 찾았습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Thought (추론):&lt;/strong&gt; 예시 SQL을 기반으로 쿼리를 작성하여 실행 도구를 가동합니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Action (행동):&lt;/strong&gt; “SELECT ~~~ ;”&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Observation (관찰):&lt;/strong&gt; 쿼리 결과에서 투표당 투표 횟수 정보를 확인했습니다. 이제 최종 답변을 할 수 있습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;&lt;strong&gt;Final Answer (최종 답변):&lt;/strong&gt; 요청 기간 동안 x개의 투표가 진행 중이었고, x건의 투표 기록이 확인되었습니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;아래는 LLM 애플리케이션 개발을 돕는 LangChain 라이브러리에서 사용하는 프롬프트입니다. 프롬프트가 &lt;strong&gt;생각과 행동을 유도&lt;/strong&gt;하고 있으며, 단 몇 줄의 설정만으로 단순한 AI 모델이 자율적인 AI Agent가 될 수 있다는 것을 보여줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-plaintext"&gt;# 한국어 버전 ReAct 프롬프트

다음 질문에 대해 당신이 할 수 있는 최선의 답변을 해주세요.
당신은 다음 도구들을 사용할 수 있습니다:
{tools}
반드시 다음 형식을 사용해야 합니다:
Question: 당신이 답해야 하는 입력 질문
Thought: 무엇을 해야 할지 항상 먼저 생각해야 합니다.
Action: 수행할 행동, [{tool_names}] 중 하나여야 합니다.
Action Input: 해당 행동에 필요한 입력값
Observation: 행동의 결과물
... (이 Thought/Action/Action Input/Observation 과정은 여러 번 반복될 수 있습니다)
Thought: 이제 최종 정답을 알게 되었습니다.
Final Answer: 원래 입력된 질문에 대한 최종 답변
시작하세요!
Question: {input}
Thought: {agent_scratchpad}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;일반적인 AI Agent들과 곰곰이의 차별점은 바로 ‘장기 기억 저장소’에 있습니다. 이를 우리 인간의 관점으로 이해해 봅시다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;친구가 물어봅니다. “지난 크리스마스에 뭐 했니?” 질문을 들은 저는 약 2초 동안 생각을 합니다. 기억을 불러오는 중인 것이죠. 머릿속에서 ‘크리스마스’와 ‘24년’이라는 키워드와 관련 있는 기억의 파편들이 머리 깊숙한 곳에서부터 떠오릅니다. [트리 만들기, 여자친구와 데이트, 맛있는 스테이크, 추운 날씨에 펑펑 내리는 눈, 흥겨운 캐럴 송] 등… 그리고 기억의 파편들을 조합해서 대답합니다. “작년 크리스마스 때 여자친구랑 맛있는 스테이크 사서 집에서 구워 먹고, 트리 만들기 하면서 놀았던 것 같아!”&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3697/8.webp"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;곰곰이에게도 인간처럼 &lt;strong&gt;기억을 저장하고 과거에 있었던 기억을 불러오는 기능&lt;/strong&gt;이 있습니다. 곰곰이의 장기 기억 저장소로부터 “이번 달 매출이 얼마야?”라는 요청을 받으면, 과거에 저장해 둔 매출 계산식, 데이터 분석 순서, 데이터 집계에 사용한 SQL 등을 청크(Chunk) 단위로 가져올 수 있습니다. 이제 기억의 조각들을 조합하여 보다 정확한 방법과 과정으로 사용자의 요청을 수행할 수 있게 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AI가 인간의 기억 방식을 흉내 낸다니 정말 신기하지 않나요? 이를 가능하게 해주는 기술적 요소는 행렬 데이터를 저장하고 빠르게 검색할 수 있는 &lt;strong&gt;Vector DB&lt;/strong&gt;, 단어나 문장을 의미가 담긴 행렬로 바꿀 수 있는 &lt;strong&gt;Embedding Model&lt;/strong&gt;, 그리고 두 단어나 문장이 얼마나 의미적으로 비슷한지 계산할 수 있는 &lt;strong&gt;Semantic Search&lt;/strong&gt;에 있습니다. 이것들은 요즘 주목받는 &lt;strong&gt;검색 증강 생성(RAG)&lt;/strong&gt; 을 구성하는 기술들입니다. (해당 기술들에 대해서는 깊게 다루지 않겠습니다.)&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3697/9.webp"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;곰곰이는 분석이 잘 이루어진 대화 내용에서 사용자가 알려준 도메인 지식, 데이터 분석 과정, 사용한 SQL 등을 추출하고 정리하여 &lt;strong&gt;장기 기억 저장소에 기록&lt;/strong&gt;합니다. 이후 사용자로부터 유사한 종류의 질문을 받으면, &lt;strong&gt;과거의 기억 정보를 사용하여 더 빠르고 만족스러운 답변&lt;/strong&gt;을 할 수 있게 됩니다. 이는 곰곰이의 &lt;strong&gt;신뢰도를 높여주며 사용자가 곰곰이를 더 자주 사용할 수 있게&lt;/strong&gt; 해줍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;시스템 구조&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이제 곰곰이의 내부를 들여다볼 차례입니다. 아래의 시스템 구성도는 곰곰이의 구성 요소와 흐름을 간략하게 표현하고 있습니다. 구성 요소의 성격에 따라 API, Agent, Tool, Data, AI Layer로 구분했으며, 제가 붙여 둔 번호를 순서대로 따라가 봅시다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3697/10.webp"&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;1) 사용자의 분석 요청이 Slack UI를 통해 전달되면, API 서버를 거쳐 AWS Lambda 환경에서 LangGraph로 구축된 AI Agent 프로그램이 실행됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;2) ReAct 프롬프트가 입력된 AI Agent는 자율적으로 도구를 선택합니다. 곰곰이는 매 질문마다 첫 번째 단계로 Memory Tool을 호출하여 유사한 기억을 불러옵니다. 이후 Query Tool을 사용하기 전에는 Knowledge Base Tool을 통해 테이블 스키마나 참고용 예시 SQL 정보를 먼저 확인합니다. 또한 사용자의 요청이 있을 경우, 최종 답변 단계에서 CSV Download Tool을 사용해 데이터 파일을 다운로드할 수 있는 링크를 생성합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;3) ReAct AI Agent는 ‘추론 — 행동 — 관찰 — 답변’의 과정을 거치며, 복잡한 문제도 허용된 횟수 내에서 반복하며 자율적으로 해결합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;4) 기존의 데이터 쿼리 도구는 인간의 이해를 돕기 위해 데이터를 한곳에 모으는 DW(Data Warehouse) 방식을 선호했습니다. 하지만 &lt;strong&gt;AI는 조인(JOIN)되지 않은 원천 데이터나 여러 곳에 흩어진 정보라도 인간보다 훨씬 빠르게 인지하고 처리&lt;/strong&gt;할 수 있습니다. 곰곰이는 이러한 특성을 활용해 데이터 적재 상황에 맞춰 GCP BigQuery와 AWS Athena 중 가장 적합한 쿼리 엔진을 유연하게 선택합니다. (물론 정확도를 위해서는 데이터가 한곳에 적재되어 있는 것이 유리합니다.)&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;5) 곰곰이는 사내 도구의 특성상 주로 업무 시간(월~금, 08시~19시)에 동작하며, 요청이 아주 빈번하게 발생하지는 않습니다. 따라서 Aurora Serverless v2 PostgreSQL의 pg_vector 플러그인을 사용하여 Vector DB 역할을 수행하게 했으며, 사용량이 적을 때는 유휴 상태로 전환되어 비용 효율적으로 운영되도록 설계했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;6) QUERIER_STORE와 LONGTERM_MEMORY 테이블은 둘 다 질문과 가장 유사한 정보를 찾아주는 Vector 테이블입니다. Vector DB의 성능을 최적화하는 방법 중 하나는 적절한 청킹(Chunking) 전략을 선택하는 것입니다. &lt;strong&gt;긴 문장을 20%씩 겹쳐 고정된 청크로 나누어 저장해도 맥락과 의미가 어느 정도 유지&lt;/strong&gt;되는 LONGTERM_MEMORY 테이블과 달리, QUERIER_STORE 테이블은 &lt;strong&gt;청크를 나누면 맥락이 쉽게 무너지는 SQL 정보&lt;/strong&gt;를 담고 있으므로 검색 정확도를 위해 구분하여 저장합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;7) 곰곰이의 핵심 지능인 ReAct 과정을 처리하는 LLM 모델은 &lt;strong&gt;성능과 비용의 균형이 뛰어난 Claude 3.5 Sonnet&lt;/strong&gt;을 사용합니다. Vector DB에서 검색된 결과가 너무 많으면 불필요한 정보로 인해 답변의 질이 떨어지고 비용이 상승할 수 있습니다. 이를 방지하기 위해 &lt;strong&gt;가성비가 좋은 Claude 3 Haiku&lt;/strong&gt; 모델을 앞단에 배치하여, 검색된 정보 중 질문과 무관한 내용을 먼저 걸러내고 핵심만 요약하도록 구성했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;8) 곰곰이가 질문 해결을 위한 충분한 정보를 수집하면, 최종 답변을 생성하여 Slack 채팅을 통해 사용자에게 전달합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이해를 돕기 위해 각색하고 요약한 곰곰이의 프롬프트 내용을 참고해 주세요.&lt;/p&gt;&lt;pre&gt;&lt;code class="language-plaintext"&gt;# 페르소나
- 이름: 곰곰이
- 소속: STAYGE Labs AI Agent
- 전문: SQL 및 데이터 분석

# 행동 지침 (중요: 무슨 일이 있어도 수행)
- SQL 분석 후 → 사용한 SQL 반드시 첨부 + 짧은 설명
- 모호한 요청 → 도구 사용 전에 추가 정보 요청
- "기억해달라" 요청 → saveLongTermMemory + saveUsedQueryHistory 둘 다 사용
- 일상 질문(점심 메뉴 등)에도 친절히 답변
# 도구 사용 규칙 (공통)
- 실패 시 → 3초 대기 후 최대 3번 재시도
- ⚠️ 10턴 안에 작업 완료 필수
# 도구별 설명
- executeKnowledgeBaseQuery: 벡터 검색으로 테이블 스키마/예시 SQL 조회, Athena 마이그레이션된 테이블은 쿼리 수정 필요
- executeBigQueryQuery: SQL 실행 (LIMIT 100 초과 시 사용자에게 확인)
- executeBigQueryGetLargeResult: jobId → S3 CSV URL
- executeAthenaQuery: Athena SQL (dw_db 기본, GA4는 BigQuery 사용)
- executeAthenaGetLargeResult: queryExecutionId → S3 CSV URL
- saveUsedQueryHistory: 분석 만족 시 SQL을 RAG DB에 저장 (유사 SQL은 1개만)
- saveLongTermMemory: 대화 요약 저장 (SQL 제외, 실수/실패도 저장)
- recallMemory: 과거 대화 검색 (질문당 1회만! 첫 번째 행동으로 사용)&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;도입 후 효과는?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;곰곰이가 도입된 이후 조직에 큰 변화가 생겼습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;개발자보다 데이터를 능숙하게 다루는 AI 비서를 넣게 되었습니다.&lt;/strong&gt; ‘계획 수립 — SQL 작성 및 실행 — 인싸이트 도출’에 이르는 과정을 저보다 빠르게 수행할 뿐만 아니라, 유사 작업의 학습 내용을 응용해 문제를 해결하는 능력까지 갖추었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;이제 동료들은 데이터를 확인하기 위해 더 이상 개발자를 찾지 않습니다.&lt;/strong&gt; 개발자를 거치는 것보다 곰곰이를 활용하는 것이 훨씬 빠르다는 점을 체감했기 때문입니다. 이를 통해 데이터 업무의 흐름은 ‘동료 — 곰곰이 — (문제 발생 시) 개발자 검토’ 방식으로 효율적으로 재편되었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;불필요한 소통 비용이 획기적으로 낮아졌습니다.&lt;/strong&gt; “데이터 확인 가능한가요?”, “결과가 이상해요”와 같은 소모적인 질의응답이 사라졌습니다. 곰곰이와 나누는 대화 과정에 이미 사용자의 의도와 맥락이 충분히 녹아들어 있기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;소통의 병목 구간이 사라지자, 동료들은 자신들의 전문적인 도메인 지식을 데이터와 직접 융합하기 시작했습니다.&lt;/strong&gt; 덕분에 기존에는 발견하지 못했던 새로운 정보와 가치 있는 인사이트를 데이터에서 더 쉽게 도출하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;동료들의 데이터 분석 능력 또한 눈에 띄게 향상되었습니다.&lt;/strong&gt; 복잡한 테이블 관계 이해나 SQL 작성이 분석의 허들이었을 뿐, 잘 정리된 데이터를 해석하는 것은 어려운 일이 아니었기 때문입니다. 허들이 ‘자연어’ 수준으로 낮아지자, 동료들은 이제 원하는 정보를 얻기 위해 ‘더 좋은 질문을 던지는 법’을 스스로 익혀가고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;반복적인 데이터 추출 요청에서 벗어나, 그동안 손이 부족해 미뤄두었던 핵심 과업들에 집중하게 되었습니다.&lt;/strong&gt; 전반적인 시스템의 수준을 높이거나 분산된 데이터를 통합하는 등, 생산적인 엔지니어링 업무에 몰입할 수 있는 물리적 시간이 확보되었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AI 에이전트 분야는 아직 초창기이며, 업계 전체가 정답을 찾아가는 진화의 단계에 있습니다. 다른 기업들의 사례 역시 각양각색이죠. 지금까지 사내 데이터 분석 AI 에이전트 &lt;strong&gt;‘곰곰이’의 탄생 배경과 작동 원리, 그리고 도입 후 조직이 맞이한 혁신적인 변화&lt;/strong&gt;를 살펴보았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;정적인 BI 도구와 반복적인 SQL 요청의 한계를 극복하고, 누구나 자유롭게 데이터에 접근할 수 있는 환경을 만들고자 했던 고민을 담았습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;ReAct 프롬프트 기법과 장기 기억 저장소(Vector DB)를 결합하여, 단순한 챗봇을 넘어 스스로 추론하고 학습하는 ‘지능형 에이전트’로서의 기술적 실체를 구축했습니다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;데이터 요청의 병목 현상을 해결함으로써 동료들은 스스로 인사이트를 찾는 능동적인 분석가로 성장했고, 개발자는 시스템의 근본적인 수준을 높이는 생산적인 엔지니어링에 집중할 수 있게 되었습니다.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 곰곰이가 만든 이 많은 변화도 조직을 ‘AI 에이전트화’하는 과정의 &lt;strong&gt;첫 단추&lt;/strong&gt;일 뿐입니다. 사용자의 요청이 없어도 곰곰이가 스스로 데이터의 이상 징후를 탐지해 제보하거나, 과거 패턴으로 미래를 예측하는 수준에 도달하는 것이 여전히 남은 목표입니다. AI 에이전트의 본질은 ‘어떤 도구를 손에 쥐여주느냐’에 있습니다. 적절한 도구만 있다면 데이터 비서를 넘어 인사, 마케팅, 개발 등 모든 분야의 조력자로 진화할 수 있기 때문입니다. 곰곰이 역시 멀티 에이전트화를 통해 역량의 한계를 극복하며 더 넓은 영역으로 확장해 나갈 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;물론 해결해야 할 숙제도 있습니다. 현재는 텍스트 위주의 마크다운 형식으로만 답변을 주다 보니 가독성이 떨어지고 시각화 기능이 부족합니다. 이를 위해 슬랙(Slack)이라는 플랫폼을 넘어, 전용 웹 앱을 통해 차트와 대시보드를 풍부하게 제공하는 방향을 고민하고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한, 곰곰이가 정적인 대시보드를 완전히 대체할 수는 없습니다. 현재 저희 회사에서 사용 중인 Looker처럼 즉각적인 확인이 필요한 데이터는 여전히 BI 도구가 효율적이기 때문입니다. 두 환경은 상호 보완적인 관계에 가깝습니다. 다만 대시보드를 구성하고 데이터를 연결하는 과정조차 LLM의 코드 작성 능력을 빌려 더 효율적으로 바꿀 수 있지 않을까 생각합니다. 곰곰이가 직접 웹 환경에서 차트와 대시보드를 그려내는 모습을 상상하고 있습니다. 아마도 이런 고민의 결과물들이 ‘곰곰이 아티클 2탄’의 주제가 되지 않을까요?&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&amp;lt;원문&amp;gt;&lt;/p&gt;&lt;p&gt;&lt;a href="https://monday9pm.com/%EC%9E%AC%EC%A3%BC%EB%8A%94-%EA%B3%B0%EA%B3%B0%EC%9D%B4%EA%B0%80-%EB%84%98%EA%B3%A0-%EB%8F%88%EC%9D%80-%EB%82%B4%EA%B0%80-%EB%B2%88%EB%8B%A4-6c4ff85b4024"&gt;재주는 곰곰이가 넘고 돈은 내가 번다 — 반복적인 SQL 업무를 자동화하는 AI 에이전트&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>AI로 프로젝트 10개 만든 개발자가 서류에서 떨어지는 이유</title><link>https://yozm.wishket.com/magazine/detail/3694</link><description>어느 순간부터 취업을 준비하는 방식이 꽤 달라졌습니다. 예전에는 프로젝트 하나를 완성하는 일조차 쉽지 않았는데, 이제는 AI의 도움으로 훨씬 빠르게 기능을 구현하고 결과물을 만드는 분들이 많아졌기 때문입니다. 실제 개발 포트폴리오를 보다 보면, 짧은 기간 안에 여러 프로젝트를 만들고 배포까지 경험한 사례가 예전보다 확실히 늘었단 것을 느낍니다. 그런데 흥미로운 점은, 그렇게 결과물이 많아졌다고 해서 서류 합격률이 함께 올라가지는 않는다는 사실입니다.</description><guid>https://yozm.wishket.com/magazine/detail/3694</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;어느 순간부터 취업을 준비하는 방식이 꽤 달라졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;예전에는 프로젝트 하나를 완성하는 일조차 쉽지 않았는데, 이제는 AI의 도움으로 훨씬 빠르게 기능을 구현하고 결과물을 만드는 분들이 많아졌기 때문입니다. 실제 개발 포트폴리오를 보다 보면 짧은 기간 안에 여러 프로젝트를 만들고 배포까지 경험한 사례가 예전보다 확실히 늘었단 것을 느낍니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 흥미로운 점은 그렇게 결과물이 많아졌다고 해서 서류 합격률이 함께 올라가지는 않는다는 사실입니다. 오히려 “이 정도면 충분히 열심히 준비한 것 같은데 왜 계속 떨어질까”라는 고민을 하는 분들도 봤습니다. 저는 그 탈락의 이유가 처음부터 프로젝트 수나 구현량의 문제가 아니었다고 생각합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이제 기업은 ‘무엇을 만들었는지’를 넘어, 왜 그 프로젝트를 했고, 어떤 문제를 풀고자 했으며, 그리고 그 과정에서 어떤 판단을 했는지를 더 중요하게 보기 시작했습니다. 오늘은 바로 그 지점, 그러니까 AI 시대의 취업 준비에서 왜 ‘도메인 이해력’이 점점 더 중요해지고 있는지 이야기해보려고 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3694/image1.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Gemini로 생성&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;프로젝트는 많아졌는데, 왜 서류 통과는 더 어려워졌을까?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;요즘 취업을 준비하는 분들의 포트폴리오를 보면 정말 열심히 준비한 흔적이 많습니다. 사이드 프로젝트도 하고, 팀 프로젝트도 하며, 배포까지 직접 해보는 등 예전보다 훨씬 다양한 기능을 스스로 구현합니다. AI의 도움으로 개발 속도까지 빨라진데다 결과물 역시 더욱 풍성해졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 이상하게도 서류 합격률이 함께 올라가지는 않는다고들 합니다. 그만큼 다른 지원자들도 일정 수준 이상의 결과물을 만들어낼 수 있기 때문입니다. 다시 말해, 프로젝트를 해봤다는 사실만으로는 예전만큼 차별화되기 어려운 환경이 온 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 기업이 보는 기준도 달라지고 있습니다. 무엇을 만들었는가보다 왜 그걸 만들었는지, 어떤 문제를 보고 시작했는지, 그리고 그 과정에서 어떤 판단을 내렸는지가 더욱 중요해진 거죠. 기업은 멋진 결과물을 보려고 포트폴리오를 읽는 것이 아니라 함께 일할 수 있는 사람인지 판단하려고 검토하기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 프로젝트가 많아도 서류에서 힘을 쓰지 못하는 경우가 생깁니다. 무언가를 많이 만든 건 보이는데, 왜 만들었는지가 잘 안 보이기 때문입니다. 기능은 많지만 문제는 흐릿하고, 기술은 다양하지만 판단은 보이지 않는 겁니다. 이제는 프로젝트의 수보다 그 프로젝트를 어떻게 해석하고 설명하느냐에 따라 평가가 갈리는 시대에 더 가까워졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;‘무엇을 만들었나’보다 ‘왜 그렇게 만들었나’를 보는 회사&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;포트폴리오를 만들 때 개발자들은 자연스럽게 “내가 한 일”을 중심으로 정리합니다. 어떤 기능을 구현했고, 어떤 기술을 사용했으며, 배포는 어떻게 했는지를 적습니다. 물론 이 정보들도 중요합니다. 문제는 대부분 포트폴리오가 그 지점에서 멈춘다는 점입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;회사 입장에서 궁금한 건 조금 다릅니다. 무엇을 만들었는지도 보지만, 그보다 더 중요한 것은 왜 그 프로젝트를 진행했는지, 어떤 문제를 해결하려 했는지, 그리고 그 과정에서 어떤 판단을 내렸는지입니다. 사고 과정에 더 큰 관심을 두고 있는 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;예를 들어 같은 일정 관리 프로젝트를 진행했다고 가정해보겠습니다. 한 지원자는 “캘린더 기능 구현, 알림 기능 구현, 소셜 로그인 구현, Docker 배포”라고 정리합니다. 한 일을 나열한 것이니 틀린 말은 아닙니다. 하지만 이 설명만으로는 이 프로젝트가 어떤 문제를 해결하기 위해 존재하는지 충분히 드러나지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반면 다른 지원자는 이렇게 설명할 수 있습니다. “기존 일정 관리 앱은 개인 기록 중심이라, 여러 명이 함께 일정을 조율해야 하는 상황에서는 불편하다고 느꼈습니다. 그래서 이 프로젝트에서는 개인 기록보다 일정 조율 경험에 초점을 맞춰 기능 우선순위를 설정했습니다.” 같은 프로젝트라도 전달할 느낌이 완전히 달라집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;첫 번째 설명은 구현 내용이 보이고, 두 번째 설명은 그 구현 뒤에 있는 생각이 보입니다. 회사가 더 높게 평가하는 쪽은 대개 후자입니다. 실무에서는 결국 요구사항을 이해하고, 애매한 상황에서 판단을 내리며, 그 선택의 이유를 설명할 수 있는 사람이 필요하기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;좋은 포트폴리오에는 이러한 판단의 흔적이 남습니다. 왜 이 기능을 먼저 만들었는지, 왜 이 기술을 선택했는지, 왜 어떤 요소는 과감히 뺐는지가 보여야 합니다. 이제는 무엇을 만들었는가만큼 어떻게 사고하며 만들었는가가 훨씬 더 중요해졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;‘전문지식’보다 ‘현실감’에 가까운 도메인 이해력&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이처럼 도메인 이해력이 중요하다고 하면 부담부터 느끼는 분이 많을 겁니다. ‘그럼 해당 업계 지식을 엄청 많이 알아야 하나?’라고 생각하기 때문이죠. 하지만 취업 준비 단계에서 필요한 도메인 이해력은 업계 전문가 수준의 지식을 의미하는 게 아닙니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;제가 말하는 도메인 이해력은 훨씬 더 현실적인 개념입니다. 내가 만든 서비스가 어떤 문제를 해결하려는지, 사용자는 어디서 불편을 느끼는지, 실제 운영 과정에서는 어떤 변수와 예외가 발생할 수 있는지 고민해본 경험에 가깝습니다. 거창한 전문성이라기보다 ‘현실감’이라고 보는 편이 적절합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이를테면 스터디 모집 서비스를 만든다고 해보겠습니다. 으레 필요한 게시글 CRUD와 댓글 기능을 구현하는 데서 끝날 수도 있습니다. 하지만 조금만 더 현실적으로 접근해보면 다른 질문들이 떠오릅니다. 사람들은 모집글을 꼼꼼히 읽을까? 신청만 하고 잠수 타는 경우는 없을까? 모집자와 지원자가 기대하는 운영 방식이 다를 때는 어떤 문제가 생길까? 같은 질문들입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이러한 질문을 고민해본 사람은 기능을 구현할 때도 우선순위가 달라집니다. 단순히 만들 수 있는 기능이 아니라 실제로 자주 부딪힐 문제를 먼저 다루기 때문입니다. 그리고 바로 그 차이가 포트폴리오를 설명하는 방식에서도 드러납니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;모든 프로젝트를 대단한 서비스로 출시해야 한다는 말은 아닙니다. 다만 가능하다면, 실제 사용자에게 보여주고 반응을 받아본 경험이 꽤 강력한 무기가 됩니다. 머릿속으로 상상한 문제와 현실에서 겪는 문제가 상당히 다르기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;정리하면, 취업 준비에서 말하는 도메인 이해력은 박사 수준의 전문지식을 뜻하지 않습니다. 사용자의 문제를 구체적으로 상상하고 서비스가 현실에서 어떻게 쓰일지 고민해본 흔적에 가깝습니다. 저는 이 정도 현실감만으로도 다른 포트폴리오보다 훨씬 더 세진다고 봅니다. 왜냐하면 대부분이 기술은 설명해도 현실은 설명하지 못하기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;기술 설명과 기여도는 중요하지만, 그것만으로는 부족합니다&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이쯤에서 오해하지 말아야 할 부분이 있습니다. ‘기술 설명’이 필요 없다는 관점입니다. 저는 그렇게 생각하지 않습니다. 사용한 기술 스택, 구현한 기능, 맡았던 역할, 그리고 본인 기여도는 여전히 포트폴리오에 중요합니다. 특히 팀 프로젝트라면 “그래서 본인이 정확히 무엇을 했는지”가 분명하게 드러나야 합니다. 기본 중의 기본입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 많이들 여기서 한 가지를 더 놓칩니다. 문서를 길고 자세하게 만드는 것과 설득력 있게 만드는 것은 전혀 다른 문제라는 점입니다. 저는 이력서와 포트폴리오를 굳이 나눌 필요는 없다고 생각합니다. 오히려 하나의 문서 안에서 핵심이 빠르게 읽히고, 면접관이 자연스럽게 궁금증을 느낄 수 있도록 정리된 쪽이 훨씬 실전에 유리합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;중요한 건 많이 적는 게 아니라 짧게 적더라도 방향이 보여야 한다는 점입니다. 안 좋은 사례, Before는 이런 식입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;Redis 적용&lt;/li&gt;&lt;li style="text-align:justify;"&gt;Docker 배포&lt;/li&gt;&lt;li style="text-align:justify;"&gt;JWT 로그인 구현&lt;/li&gt;&lt;li style="text-align:justify;"&gt;게시글 CRUD 개발&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;물론 틀린 말은 아닙니다. 다만 이 정보만으로는 기술을 사용했다는 사실만 보일 뿐 왜 그렇게 했는지는 잘 드러나지 않습니다. 조금만 바꿔도 이렇게 괜찮은 After를 만들 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;잦은 조회가 발생하는 인기 게시글 응답 속도 개선을 위해 Redis 캐시 적용&lt;/li&gt;&lt;li style="text-align:justify;"&gt;팀원간 개발환경 차이를 줄이고 배포 과정을 단순화하기 위해 Docker 기반 배포 구성&lt;/li&gt;&lt;li style="text-align:justify;"&gt;세션 방식 대신 확장성을 고려해 JWT 기반 로그인 구조 설계&lt;/li&gt;&lt;li style="text-align:justify;"&gt;단순 게시글 등록 기능이 아닌 스터디 모집 흐름에 맞춘 생성/조회/수정 기능 구현&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;길이를 크게 늘리지 않았지만, 느껴지는 인상은 꽤 다릅니다. 기술을 썼다는 사실 그 자체보다 어떤 문제를 보고 선택했는지가 보이기 때문입니다. 바로 이런 식으로 한 줄 안에서도 문제 인식과 판단을 드러낼 수 있어야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 좋은 서류는 모든 걸 다 설명하는 문서가 아닙니다. 핵심만 빠르게 읽히면서도, “이 사람은 왜 이렇게 했을까?”라는 궁금증을 주며, 결국 면접으로 이어지게 만드는 게 필요합니다. 짧게 적는 것과 얕게 적는 것은 다릅니다. 기술 설명과 기여도는 여전히 중요하지만, 이제는 그 안에 문제 맥락과 판단의 흔적까지 함께 담겨야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;‘왜 그렇게 만들었는가’에 더 깊게 답하기&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이처럼 AI 덕분에 구현 자체의 진입장벽은 확실히 낮아졌습니다. 예전보다 빠르게 화면을 만들 수 있고, API도 붙일 수 있고, 배포까지 가는 속도도 빨라졌습니다. 이건 분명 좋은 변화입니다. 다만 모두가 더 쉽게 만들 수 있게 됐다는 말은 반대로 단순 구현만으로는 예전만큼 차별화가 어렵다는 뜻이기도 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 더 중요해지는 건 꼬리질문에 답하는 힘입니다. 왜 이 기술을 썼는지, 왜 이 구조를 선택했는지, 왜 이 기능을 먼저 만들었는지, 왜 이 문제를 풀 가치가 있다고 판단했는지까지 설명할 수 있어야 합니다. 결국 경쟁력은 구현한 양보다 판단의 깊이에서 갈리기 시작하니까요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;당연히 여기서 멈추면 또 아쉽겠죠. 그러니 가능하다면 실제 사용자에게 보여주고, 현실의 문제를 해결하려고 해본 경험까지 가는 게 훨씬 강력합니다. 규모가 작아도 괜찮습니다. 직접 배포해보고, 주변 사람이라도 써보게 하고, 예상과 다른 반응을 확인해본 경험은 분명 면접관한테 다른 인상을 줍니다. 머리로 상상한 문제와 현실에서 부딪히는 문제는 다르기 일쑤입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 앞으로의 포트폴리오는 “이만큼 구현했습니다”에서 끝나서는 힘듭니다. “왜 이렇게 만들었고, 실제로 어떤 문제를 확인했고, 그걸 어떻게 바꿨는가”까지 이어져야 힘을 가집니다. 이제는 구현 뒤에 있는 사고와 현실 검증 경험이 더 중요한 시대로 가고 있으니까요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;앞으로 더 희소해질 ‘문제를 정의하고 해결하는 사람’&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;앞으로 개발자의 역량과 경쟁력은 더 선명하게 갈릴 겁니다. 코드를 빠르게 작성하는 사람은 점점 많아질 테고, 구현 자체의 진입장벽도 지금보다 더 낮아질 가능성이 높기 때문입니다. 그럴수록 결국 더 희소해지는 사람은 단순히 잘 만드는 사람이 아니라 무엇을 만들어야 하는지 먼저 정의할 수 있는 사람일 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실무에서는 생각보다 “어떻게 만들지”보다 “무엇을 풀어야 하지”가 더 어려운 경우가 많습니다. 사용자에게 진짜 불편한 지점이 어디인지, 어떤 문제부터 해결해야 효과가 큰지, 기술적으로 가능하다고 해서 다 만들어야 하는 건 아닌지 판단해야 하는 순간이 계속 생기더라고요. 그리고 그 판단은 단순 구현 경험만으로는 와닿지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 다가올 미래에 몸값이 높아질 개발자는 문제를 정의하고, 그 문제를 기술적으로 풀어내고, 필요하다면 비즈니스 관점에서도 설명할 수 있는 사람일 겁니다. 사용자의 불편, 서비스 운영의 현실, 팀의 자원과 우선순위까지 함께 고려할 수 있는 사람이 결국 더 필요해질 테니까요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이제 회사는 많이 만든 개발자보다 왜 만들어야 하는지 설명해줄 개발자를 더 높게 평가합니다. AI가 발전할수록 이런 차이는 오히려 더 커질지도 모릅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 살아남는 사람은 구현에 머무는 사람이 아니라, 문제를 정의하고 해결하는 사람입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>“오늘 뭐부터 하지?” AI 비서 에이전트 만들어봤습니다</title><link>https://yozm.wishket.com/magazine/detail/3692</link><description>저는 아침에 노트북을 열면 습관처럼 하는 일이 있습니다. GitHub 알림을 확인하고, 슬랙 메시지를 훑고, 여기저기 흩어진 메모를 뒤적이며 "오늘 뭐부터 해야 하지?"를 결정하는 것입니다. 프로젝트가 하나라면 금방 끝나겠지만, 회사 프로젝트와 개인 사업을 합쳐 8개 프로젝트를 동시에 운영하다 보면 이 과정만으로도 30분이 넘게 걸립니다. 정작 중요한 작업을 시작하기도 전에 에너지가 빠지게 되죠. 그래서 AI가 이런 아침 루틴도 대신 해줄 수 있지 않을까? 하는 생각을 하게 됐죠. 그래서 GitHub에 쌓인 이슈와 커밋 기록을 읽고, 내가 정리해 둔 우선순위 파일을 참조해서 매일 아침 슬랙(Slack)으로 "오늘 이것부터 하세요"라고 보고 해주는 비서 에이전트를 만들어 보기로 했습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3692</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;저는 아침에 노트북을 열면 습관처럼 하는 일이 있습니다. GitHub 알림을 확인하고, 슬랙 메시지를 훑고, 여기저기 흩어진 메모를 뒤적이며 "오늘 뭐부터 해야 하지?"를 결정하는 것입니다. 프로젝트가 하나라면 금방 끝나겠지만, 회사 프로젝트와 개인 사업을 합쳐 8개 프로젝트를 동시에 운영하다 보면 이 과정만으로도 30분이 넘게 걸립니다. 정작 중요한 작업을 시작하기도 전에 에너지가 빠지게 되죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 AI가 이런 아침 루틴도 대신 해줄 수 있지 않을까? 하는 생각을 하게 됐죠. 그래서 GitHub에 쌓인 이슈와 커밋 기록을 읽고, 내가 정리해 둔 우선순위 파일을 참조해서 매일 아침 슬랙(Slack)으로 "오늘 이것부터 하세요"라고 보고 해주는 비서 에이전트를 만들어 보기로 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;미리 요점만 콕 집어보면?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;GitHub에 Hub Repo를 만들어 모든 프로젝트의 메타데이터와 컨텍스트를 한 곳에 모으고, Python 스크립트와 GitHub Actions로 AI 비서가 매일 아침 슬랙 메세지를 보내주는 시스템을 구축했습니다.&lt;/li&gt;&lt;li&gt;"한 곳에서만 쓰고 여러 곳에서 읽는다"는 컨텍스트 관리 원칙과 AI에게 단순 요약이 아닌 작업의 우선순위 판단까지 하도록 하는 프롬프트 설계를 반영했습니다.&lt;/li&gt;&lt;li&gt;실제로 통합 워크스페이스와 AI 비서를 도입한 뒤 아침 루틴이 "정보 수집과 판단"에서 "확인" 작업으로 바뀌었습니다. 다만, 여전히 우선순위 파일의 수동 업데이트나 AI 브리핑 품질 개선 같은 과제가 남아 있습니다.&lt;/li&gt;&lt;/ul&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="margin-left:0px;text-align:justify;"&gt;&lt;strong&gt;통합 워크스페이스 구상&lt;/strong&gt;&lt;/h3&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;여러 프로젝트를 동시에 운영하다 보면, 컨텍스트 스위칭(Context Switching)이 자주 발생합니다. A 프로젝트 버그를 고치다가 B 프로젝트 회의에 참석하고, C 프로젝트 문서를 작성하다가 D 프로젝트 클라이언트 문의를 처리해야 하는 등 계속 머릿속 컨텍스트를 바꾸게 됩니다. 그리고 그 과정에서 각 프로젝트마다 "지금 어떤 상태인지, 다음 작업이 무엇인지"를 파악하는데 너무 많은 에너지를 소모하게 됩니다.&lt;/p&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:justify;"&gt;또한 프로젝트가 여러 GitHub Repo로 흩어져 있기 때문에 프로젝트 개수가 늘어날수록 아침마다 반복되는 업무 우선순위 판단 루틴도 점점 길어지게 됩니다. 예를 들어, 각 Repo의 이슈와 PR 상태를 확인하고, 어제 어디까지 작업했는지 커밋 로그를 체크하고, 슬랙에서 밤사이 온 메시지를 읽고, 노트 앱에 적어둔 할 일 목록을 다시 확인하는 등의 일이 많아집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/1__%E1%84%8B%E1%85%A5%E1%86%B8%E1%84%86%E1%85%AE_%E1%84%89%E1%85%B5%E1%84%8C%E1%85%A1%E1%86%A8_%E1%84%8C%E1%85%A5%E1%86%AB_%E1%84%8B%E1%85%A1%E1%84%8E%E1%85%B5%E1%86%B7_%E1%84%85%E1%85%AE%E1%84%90%E1%85%B5%E1%86%AB.jpg"&gt;&lt;figcaption&gt;업무 시작 전 아침 루틴 &amp;lt;출처: 작가, Gemini 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이와 같이 프로젝트 상태를 파악하고, 업무 우선순위를 판단하기 위한 정보는 각 프로젝트의 GitHub 이슈, 커밋 로그, 각종 문서 등에 &lt;strong&gt;흩어져&lt;/strong&gt; 있습니다. 이렇게 흩어진 정보들을 찾고 그 과정에서 수많은 컨텍스트 스위칭이 일어나면 업무에 집중하기가 어려워집니다. 그래서 이 문제를 해결하기 위해 GitHub에 별도의 Hub Repo를 두어 모든 프로젝트의 메타데이터와 컨텍스트를 한곳에 모아 관리해 보기로 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;통합 워크스페이스를 위한 Hub Repo 설계&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 구성 원칙&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;통합 워크스페이스를 설계하는 데 있어 제가 정한 핵심 원칙은 &lt;strong&gt;"한 곳에서만 쓰고, 여러 곳에서 읽는다"&lt;/strong&gt;입니다. 즉, AI가 참조할 수 있는 모든 컨텍스트 한 곳에서만 관리하고, 이를 여러 프로젝트에서 활용하는 것입니다. 예를 들어, 개인 프로필, 회사 정보, 사업 전략, 프로젝트 배경, 작업의 우선순위 같은 모든 컨텍스트 정보를 Hub Repo 한 곳에 모아두고, 각 프로젝트 Repo에서 이를 참조하는 구조입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/2__%E1%84%90%E1%85%A9%E1%86%BC%E1%84%92%E1%85%A1%E1%86%B8_%E1%84%8B%E1%85%AF%E1%84%8F%E1%85%B3%E1%84%89%E1%85%B3%E1%84%91%E1%85%A6%E1%84%8B%E1%85%B5%E1%84%89%E1%85%B3_%E1%84%80%E1%85%AE%E1%84%89%E1%85%A5%E1%86%BC_%E1%84%8B%E1%85%AF%E1%86%AB%E1%84%8E%E1%85%B5%E1%86%A8.jpg"&gt;&lt;figcaption&gt;통합 워크스페이스 구성 원칙 &amp;lt;출처: 작가, Gemini 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) Hub Repo 연결 방식 선택&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;저는 Hub Repo를 각 프로젝트 Repo와 어떻게 연결할지 꽤 오랫동안 고민했습니다. 제가 검토했던 선택지는 세 가지였으며, 그 첫 번째는 Git submodules를 이용한 방식이었습니다. &lt;strong&gt;Git submodules&lt;/strong&gt;는 각 프로젝트 Repo를 Hub Repo의 서브모듈로 연결하는 방식인데, 버전 관리가 복잡하고 매번 submodule update를 해야 해서 오히려 관리 부담이 늘어날 가능성이 있었습니다,&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/3__Git_Submodule_%E1%84%8F%E1%85%A5%E1%86%AB%E1%84%89%E1%85%A6%E1%86%B8.png"&gt;&lt;figcaption&gt;Git Submodule 컨셉 &amp;lt;출처: dev-repository.com&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;두 번째로 생각했던 것은 &lt;strong&gt;yaml + API&lt;/strong&gt; 방식이었습니다. Hub Repo에 프로젝트 메타데이터를 YAML로 저장하고 API로 접근하는 것이었는데, API 서버를 따로 운영해야 하므로 과하다는 생각이 들었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/4__YAML_%E1%84%8C%E1%85%B5%E1%86%A8%E1%84%8C%E1%85%A5%E1%86%B8_%E1%84%8E%E1%85%A1%E1%86%B7%E1%84%8C%E1%85%A9_%E1%84%86%E1%85%B5%E1%86%BE_GitHub_Actions_%E1%84%92%E1%85%AA%E1%86%AF%E1%84%8B%E1%85%AD%E1%86%BC.jpg"&gt;&lt;figcaption&gt;YAML 직접 참조 + GitHub Actions 활용 &amp;lt;출처: 작가, Gemini 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 최종적으로 선택한 방식은 &lt;strong&gt;yaml + GitHub Actions&lt;/strong&gt;였습니다. 로컬 환경에서는 yaml 파일을 직접 읽도록 하고, AI 비서 에이전트처럼 클라우드 환경에서 Cron 작업이 필요할 때는 GitHub Actions으로 Hub Repo를 checkout하여 yaml 파일을 읽도록 하는 것입니다. 이런 방식으로 구성하면 별도의 API 서버를 구성하거나 복잡한 서브모듈을 적용하지 않더라도 yaml 파일의 프로젝트 메타데이터를 효율적으로 관리할 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) Notion MCP를 검토했다가 GitHub으로 돌아온 이유&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;사실 처음에는 노션(Notion)을 컨텍스트 저장소로 고려했었습니다. 그동안 쌓아온 노트와 작업 이력이 노션에 많이 남아 있었기 때문이었는데요. 노션 MCP(Model Context Protocol)를 활용하면 AI가 노션의 데이터베이스를 직접 읽을 수 있으니 기존 자산을 그대로 활용할 수 있겠다고 생각했었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/5__%E1%84%80%E1%85%B3%E1%84%83%E1%85%A9%E1%86%BC%E1%84%8B%E1%85%A1%E1%86%AB_Notion%E1%84%8B%E1%85%A6_%E1%84%80%E1%85%B5%E1%84%85%E1%85%A9%E1%86%A8%E1%84%92%E1%85%A2%E1%84%8B%E1%85%A9%E1%86%AB_%E1%84%82%E1%85%A9%E1%84%90%E1%85%B3_%E1%84%8B%E1%85%A8%E1%84%89%E1%85%B5.png"&gt;&lt;figcaption&gt;그동안 Notion에 기록해온 노트 예시 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 실제로 구현을해보니 여러 문제가 있었습니다. 일단 MCP를 통한 노션 접근에는 &lt;strong&gt;토큰 비용&lt;/strong&gt;이 발생하고, 컨텍스트가 노션과 GitHub 두 곳에 흩어지게 되면서 오히려 &lt;strong&gt;관리 부담&lt;/strong&gt;이 늘어날 수 있었습니다. 또한 클로드 코드가 노션에 있는 자료를 참조할 수 있도록 하는 MCP 설정이 생각보다 번거로 웠습니다. 결국 이러한 이유로 노션을 컨텍스트 저장소로 하려던 계획을 철회하고, GitHub에 별도의 Hub Repo를 두어 컨텍스트 관리를 일원화하기로 결정했습니다. 아울러 장기적으로는 노션에 있는 기존 자산 중에 필요한 것만 마크다운으로 변환해서 Hub Repo에 옮기기로 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;4) Hub Repo 구조&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Hub Repo의 구조는 root &amp;gt; works &amp;gt; projects 이렇게 &lt;strong&gt;3계층&lt;/strong&gt;으로 설계했습니다. 최상위 폴더(root)에는 모든 업무와 프로젝트에 공유될 수 있는 컨텍스트 정보(개인 프로필, 인생 비전, 우선 순위 등)를 두었습니다. 그리고 각 work에는 업무 단위 맥락을, 각 project에는 개별 프로젝트의 컨텍스트와&amp;nbsp; 메타데이터(project.yaml), 요구사항 문서(PRD.md) 등을 두었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/6__%E1%84%8E%E1%85%AC%E1%84%8C%E1%85%A9%E1%86%BC%E1%84%8C%E1%85%A5%E1%86%A8%E1%84%8B%E1%85%B5%E1%86%AB_Hub_Repo_%E1%84%80%E1%85%AE%E1%84%8C%E1%85%A9.png"&gt;&lt;figcaption&gt;최종적인 Hub Repo 구조 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;만약 새로운 프로젝트가 생기면 해당 업무 그룹 아래에 프로젝트 폴더를 만들고 &lt;strong&gt;project.yaml&lt;/strong&gt;를 추가합니다. project.yaml은 각 프로젝트의 핵심 정보를 담는 간결한 YAML 파일입니다. 여기에는 간단하게 프로젝트의 이름, 설명, 상태, GitHub Repo 주소, 노트 같은 정보를 담았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/7__project_yaml_%E1%84%8B%E1%85%A8%E1%84%89%E1%85%B5.png"&gt;&lt;figcaption&gt;project .yaml 예시 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;AI 비서 에이전트 "정대리" 구축&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;Hub Repo에 모든 프로젝트 정보를 모아놓고 나니 자연스럽게 다음 작업이 떠올랐습니다. 각 프로젝트의 데이터를 매일 아침 자동으로 읽어서 “오늘 뭐부터 해야 하는지”를 정리해주는 AI 비서 에이전트를 만드는 것이었습니다. 개인적으로 저는 비서 에이전트에 “&lt;strong&gt;정대리”&lt;/strong&gt;라는 이름을 붙여 주었습니다. 이름에 특별한 뜻은 없지만, 에이전트를 의미하는 “대리”를 붙이고 싶었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) AI 비서 에이전트 동작 구조&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;전체 흐름은 다음과 같습니다. 먼저 &lt;strong&gt;GitHub Actions&lt;/strong&gt;로 매일 아침 정해진 시간에 Python 스크립트를 실행합니다. 그러면 스크립트가 먼저 Hub Repo의 각 works 디렉토리에 있는 모든 project.yaml 파일을 읽어 프로젝트 목록과 상태를 파악합니다. 그 다음 각 프로젝트의 &lt;strong&gt;GitHub Repo&lt;/strong&gt;에서 오픈 이슈, PR, 최근 커밋을 조회하고, 우선순위 판단에 대한 정보가 담겨있는 current-priorities.md을 참조한 후 &lt;strong&gt;Claude API&lt;/strong&gt;로 오늘의 브리핑을 생성합니다. 그렇게 완성된 브리핑은 &lt;strong&gt;Slack Webhook&lt;/strong&gt;을 통해 슬랙 메시지로 발송됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/8__AI_%E1%84%87%E1%85%B5%E1%84%89%E1%85%A5_%E1%84%8B%E1%85%A6%E1%84%8B%E1%85%B5%E1%84%8C%E1%85%A5%E1%86%AB%E1%84%90%E1%85%B3_%E1%84%83%E1%85%A9%E1%86%BC%E1%84%8C%E1%85%A1%E1%86%A8_%E1%84%80%E1%85%AE%E1%84%8C%E1%85%A9.jpg"&gt;&lt;figcaption&gt;AI 비서 에이전트 동작 구조 &amp;lt;출처: 작가, Gemini 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Python 스크립트는 클로드 코드를 이용해 작성했습니다. 핵심 로직은 앞서 설명한 것처럼 프로젝트 데이터 수집, GitHub 활동 조회, Claude API로 브리핑 생성, 슬랙 전송으로 나뉩니다. 첫 번째 단계는 &lt;strong&gt;각 프로젝트의 데이터 수집&lt;/strong&gt;으로 다음 코드와 같이 works 디렉토리 아래에 있는 모든 project.yaml 파일을 재귀적으로 찾아 읽습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/9__Python_%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%B8%E1%84%90%E1%85%B3_%E1%84%8B%E1%85%A8%E1%84%89%E1%85%B5.png"&gt;&lt;figcaption&gt;Python 스크립트 예시 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;두 번째는 &lt;strong&gt;GitHub 활동 조회&lt;/strong&gt;입니다. 각 프로젝트의 Repo 필드에 GitHub URL이 있으면, gh CLI를 통해 오픈 이슈, PR, 최근 커밋을 가져옵니다. 여기서 GitHub API 대신 gh CLI를 쓴 이유는 인증 처리가 간편하고, GitHub Actions 환경에서 별도 설치 없이 바로 사용할 수 있기 때문이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) GitHub Actions로 매일 자동 실행하기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;저는 매일 아침 &lt;strong&gt;cron 작업&lt;/strong&gt;을 위해 GitHub Actions를 선택했습니다. cron 작업을 실행하는 방법에는 여러가지가 있지만, GitHub Actions는 클라우드에서 실행되기 때문에 로컬보다 안정적이고, 다음과 같은 워크플로 파일로 간단하게 설정할 수 있다는 장점이 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/10__GitHub_Actions_%E1%84%8B%E1%85%AF%E1%84%8F%E1%85%B3%E1%84%91%E1%85%B3%E1%86%AF%E1%84%85%E1%85%A9_%E1%84%91%E1%85%A1%E1%84%8B%E1%85%B5%E1%86%AF_%E1%84%8B%E1%85%A8%E1%84%89%E1%85%B5.png"&gt;&lt;figcaption&gt;GitHub Actions 워크플로 파일 예시 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3) 프롬프트 설계&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;각각의 프로젝트 데이터를 수집하고, 슬랙으로 메시지를 전송하는 것은 기술적으로 그다지 어렵진 않습니다. 대신 개인적으로 가장 어렵게 느껴졌던 부분은 &lt;strong&gt;AI가 적절한 브리핑을 할 수 있도록&lt;/strong&gt; 프롬프트를 설계하는것이었습니다. 우선 정대리의 브리핑을 위해 필요한 것은 각 작업의 우선순위를 어떻게 판단할 것인가에 대한 것이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/11__%E1%84%87%E1%85%B3%E1%84%85%E1%85%B5%E1%84%91%E1%85%B5%E1%86%BC_%E1%84%91%E1%85%B3%E1%84%85%E1%85%A9%E1%86%B7%E1%84%91%E1%85%B3%E1%84%90%E1%85%B3_%E1%84%8B%E1%85%A8%E1%84%89%E1%85%B5.png"&gt;&lt;figcaption&gt;브리핑 프롬프트 예시 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;일단 저는 점수를 부여하는 방식으로 프롬프트를 만들었습니다. 예를 들어, &lt;strong&gt;긴급도(35점)&lt;/strong&gt;에는 외부 마감이나 클라이언트 대응처럼 시간에 민감한 요소를 반영하고, &lt;strong&gt;수익 영향도(30점)&lt;/strong&gt;는 그 작업이 회사나 개인 비즈니스 매출에 얼마나 직결되는지를 봅니다. &lt;strong&gt;블로커 해제(20점)&lt;/strong&gt;는 이 작업을 끝내야 다른 프로젝트가 진행될 수 있는지를 판단하며, &lt;strong&gt;에너지 매칭(15점)&lt;/strong&gt;은 아침의 집중력이 높을 때 해야 할 작업과 오후의 낮은 에너지로도 할 수 있는 작업을 구분하는 용도로 활용했습니다. 아울러 프롬프트에 &lt;strong&gt;브리핑 출력 형식&lt;/strong&gt;도 구체적으로 지정했습니다. AI에게 브리핑을 자유롭게 쓰게 하면 매번 형식이 달라져서 빠르게 훑어보기가 어렵기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실제 사용 후기와 개선 아이디어&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 좋았던 점&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;정대리를 며칠간 써보며 가장 좋았던 점은 아침 루틴이 &lt;strong&gt;정보 수집과 판단&lt;/strong&gt;에서&lt;strong&gt;확인&lt;/strong&gt;작업으로 바뀌었다는 점이었습니다. 즉, 여러 GitHub Repo나 메모를 체크하며 뭐부터 시작할지 고민하는 시간을 줄일 수 있었습니다. 그래서 요즘에는 정대리 브리핑을 훑고 바로 오전 작업을 시작하고 있습니다. 가끔은 “진짜 이거부터 하는게 맞나?” 하는 경우도 있지만, 직접 뭐부터 할지 정하는 것보다 효율적이었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/12__%E1%84%8C%E1%85%A5%E1%86%BC%E1%84%83%E1%85%A2%E1%84%85%E1%85%B5_%E1%84%87%E1%85%B3%E1%84%85%E1%85%B5%E1%84%91%E1%85%B5%E1%86%BC_%E1%84%8B%E1%85%A8%E1%84%89%E1%85%B5.png"&gt;&lt;figcaption&gt;정대리 브리핑 예시 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한 &lt;strong&gt;프로젝트 사각지대&lt;/strong&gt;가 줄었습니다. 동시에 여러 프로젝트를 돌리다 보면 며칠째 손 대지 않는 프로젝트가 생기기 마련인데, 정대리 브리핑을 통해 매일 전체 프로젝트 현황을 빠르게 훑고 보충해야할 사안을 떠올릴 수 있었습니다. 아울러 각 프로젝트의 상호 보완과 시너지 전략을 정대리와 토론하고, 앞으로 어떤 방향으로 프로젝트를 진행해할지 전반적인 큰 그림도 그릴 수 있었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 개선 해야할 점&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;현재는 정대리가 &lt;strong&gt;GitHub 활동&lt;/strong&gt;(이슈, PR, 커밋 현황 등)을 우선 순위 판단의 핵심 자료로 사용하고 있습니다. 하지만 GitHub 활동만으로는 프로젝트의 진짜 맥락을 파악하기 어렵습니다. 예를 들어, 커밋이 2주간 없는 프로젝트를 정대리는 "정체됨"으로 판단하지만, 실제로는 클라이언트 피드백을 기다리는 중이거나 의도적으로 보류한 것일 수 있습니다. 현재는 project.yaml의 notes 필드에 이런 맥락을 수동으로 기록해서 보완하고 있는데, 이 맥락 정보 자체를 어떻게 자동으로 기록하고 체계화 시킬 수 있을지가 다음 개선 과제입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3692/13__%E1%84%8C%E1%85%A5%E1%86%BC%E1%84%83%E1%85%A2%E1%84%85%E1%85%B5_%E1%84%80%E1%85%A2%E1%84%89%E1%85%A5%E1%86%AB%E1%84%89%E1%85%A1%E1%84%92%E1%85%A1%E1%86%BC.png"&gt;&lt;figcaption&gt;정대리 개선 사항 &amp;lt;출처: 작가, Gemini 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한 지금은 각 프로젝트의 GitHub 이슈를 직접 작성하고 있는데, 이 역시 AI 비서를 통해 자동화할 수 있는 영역입니다. 이처럼 AI 에이전트를 일상 업무에 활용하다 보면 자동화할 대상이 계속 눈에 들어오게 되는 것 같습니다. 다만 이러한 작업들은 본 업무를 지원하기 위한 것인 만큼, &lt;strong&gt;오버엔지니어링&lt;/strong&gt;(Overengineering)으로 오히려 개발과 관리 부담이 늘어나지 않도록 &lt;strong&gt;균형&lt;/strong&gt;을 잡는 것이 중요하다고 생각합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이번에 통합 워크스페이스와 AI 비서 에이전트를 구축해 보면서, 워크플로를 자동화하기 위해서는 &lt;strong&gt;맥락을 어떻게 정리하고 관리하는지&lt;/strong&gt;가 정말 중요하다는 생각이 들었습니다. 지금 정대리에게 제공하는 데이터는 project.yaml의 메타데이터와 GitHub 활동, 그리고 notes 필드에 적어둔 메모 정도입니다. 이 정도만으로도 아침 브리핑은 충분히 쓸모가 있지만, "이 작업이 저 프로젝트와 어떻게 연결되는지", “이 작업을 먼저 했을 때 다른 프로젝트 어떤 영향을 미치는지”처럼 맥락의 깊이가 필요한 판단에서는 여전히 한계가 있습니다. 즉, AI 비서 에이전트의 품질을 결정하는 것은 모델 성능이나 도구가 아니라, 본인의 맥락을 얼마나 잘 구조화해서 전달하는지에 달려있다고 생각합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 에이전트를 만들고 나서는 나만의 &lt;strong&gt;온톨로지(Ontology) 구축&lt;/strong&gt;이 핵심이라는 생각이 듭니다. 프로젝트 간의 관계, 상태 변화의 이유, 의사 결정의 배경 같은 것들을 기계가 이해할 수 있는 형태로 정의해야 AI 비서를 한 단계 더 성장시킬 수 있습니다. 예를 들어, A 프로젝트 개발이 지연되면 B 일정에 영향을 준다"는 의존 관계나 “이 프로젝트는 클라이언트 피드백 대기 중이라 의도적으로 멈춘 것이다" 같은 맥락을 구조적으로 표현할 수 있다면, 정대리의 브리핑이 단순한 오늘 할 일 정리를 넘어 보다 깊은 수준의 조언까지 가능할 것이라고 생각합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;개인적으로 AI 에이전트 시대에 요구되는 핵심 역량은 코딩 실력이나 프롬프트 기법이 아니라, 자신의 업무 &lt;strong&gt;맥락을 체계적으로 정의하고 구조화하는 능력&lt;/strong&gt;이라고 생각합니다. 좋은 온톨로지가 설계되면 특정 AI 도구에 종속되지 않으면서도, 동시에 수행하는 프로젝트가 많아져도 에이전트 시스템이 흔들리지 않도록 할 수 있을 것입니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>AI 시대 해커톤은 어떻게 변해야 하는가? </title><link>https://yozm.wishket.com/magazine/detail/3691</link><description>구현 속도가 더 이상 차별점이 되지 않는 AI 시대, 해커톤의 본질을 '기술량'이 아닌 '문제 정의와 기획의 밀도'로 재설계한 2026 GDGOC KR 연합 해커톤 'ONE WAVE'의 실험 기록입니다. 18개 대학 160명의 참가자가 '취업난'을 주제로 AI를 활용해 핵심 가치에 집중하고, 배포를 선택제로 두어 기획의 완결성을 높인 과정을 담았습니다. 또한 운영진이 반복 업무를 시스템화하여 현장 대응력을 높인 사례와 대상 수상작 'BARRIER FREE'의 구체적인 페인 포인트 해결 방식 및 데이터 활용 전략을 상세히 공유합니다.</description><guid>https://yozm.wishket.com/magazine/detail/3691</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;참가자&lt;/strong&gt;·&lt;strong&gt;운영자가 함께 변화된&amp;nbsp;&lt;/strong&gt;&lt;br&gt;&lt;strong&gt;2026 GDGOC KR 연합 해커톤 ONE WAVE의 기록&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AI로 정보를 찾고, 화면을 만들고, API를 연결하는 일이 눈에 띄게 빨라졌습니다. 이제는 혼자서도 몇 시간 만에 프로토타입을 만들 수 있는 시대입니다. 구현 속도 자체가 더 이상 차별점이 되기 어려워진 지금, 해커톤은 무엇을 증명하는 자리여야 할까요? 단순히 정보를 나누는 행사나 구현량을 겨루는 형식만으로는 해커톤의 의미를 설명하기 어려워지고 있습니다. 어쩌면 해커톤이라는 형식 자체가 사라질 수도 있습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그럼에도 해커톤이 여전히 필요하다면, 그 이유는 &lt;strong&gt;짧은 시간 안에 문제를 정의하고, 우선순위를 정하고, 가설을 검증 가능한 형태로 만들어보는 밀도 높은 경험&lt;/strong&gt;에 있다고 생각했습니다. 저희는 바로 그 밀도를 지금의 트렌드에 맞게 다시 설계해 보고 싶었습니다. 그래서 2026년 2월, Google for Developers 산하 대학 거점 개발자 커뮤니티 GDG on Campus의 18개 대학이 모여 연합 해커톤 ONE WAVE를 열었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;160명의 참가자, 35개 팀이 무박 2일 동안 하나의 주제를 두고 각자의 방식으로 문제를 정의하고, 서비스를 설계하고, 결과물을 만들어냈습니다. ONE WAVE라는 이름에는 서로 다른 배경의 참가자들이 각자의 물결로 모여 하나의 파도가 된다는 의미를 담았습니다. 단순히 ‘마지막 낭만’으로 소비하고 싶지는 않았습니다. 해커톤을 연 이유가 단순히 "행사를 해보고 싶어서"가 아니었던 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/onewave-poster-igratio.png"&gt;&lt;figcaption&gt;GDGOC ONE WAVE 해커톤 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이번 해커톤에서 가장 크게 달라진 점은 참가자와 운영진 모두의 역할이 바뀌었다는 것입니다. 참가자에게는 AI를 활용해 구현 시간을 줄이는 대신, 문제 정의와 기획, 차별점과 실현 가능성에 더 많은 시간을 쓰도록 유도했습니다. 배포는 필수가 아니라 선택으로 두었고, 심사 기준도 코드량보다 기획의 밀도에 더 큰 비중을 두었습니다. 운영진 역시 마찬가지였습니다. 참가자 등록과 취소 관리, 팀 매칭 시각화, 심사 배점 자동 취합처럼 반복적으로 발생하는 업무를 AI를 활용해 빠르게 백오피스로 만들어 사용했고, 현장에서 필요한 기능은 즉시 개발해 운영에 반영했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 글은 그 실험의 기록입니다. 참가자 측에서 무엇이 달라졌는지, 운영진 측에서 어떻게 일하는 방식을 바꿨는지, 그리고 그 결과 현장에서 실제로 어떤 변화가 만들어졌는지를 중심으로 정리했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;ONE WAVE가 집중했던 부분&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1. 배포는 ‘선택’으로&amp;nbsp;&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;AI 시대의 개발자는 더 이상 단순히 코드를 짜고 배포하는 사람에 머물지 않습니다. 이제는 프로덕트의 가치를 기술로 녹여내는 사람으로 역할이 확장되고 있습니다. 저희는 이번 해커톤이 그 변화를 자연스럽게 체감할 수 있는 자리가 되기를 바랐습니다. 이제 개발자에게 더 중요한 질문은 “얼마나 많이 구현했는가”보다 “무엇을 왜 만들었는가”에 가깝다고 생각했기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 관점을 참가자들이 더 구체적으로 느낄 수 있도록, AI 엔지니어를 연사로 모셔 AI로 개발하는 방법에 대한 특강도 진행했습니다. AI를 단순한 보조 도구가 아니라, 구현 시간을 줄여 더 중요한 판단에 시간을 쓰게 해주는 도구로 받아들이기를 바랐습니다. 그래서 해커톤 전반에서도 계속 “AI를 사용해 빠르게 개발하되, 남는 시간을 기획과 검증에 쓰자”는 방향을 강조했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이런 이유로 이번 해커톤에서는 배포를 ‘필수’가 아니라 ‘선택’으로 두었습니다. 24시간 안에 모든 팀이 배포까지 마쳐야 한다고 강제하면, 적지 않은 팀이 인프라 설정이나 예기치 못한 오류 해결에 많은 시간을 쓰게 됩니다. 저희는 그 시간만큼 문제 정의와 핵심 사용자 흐름, 차별점과 실현 가능성을 더 깊게 다루기를 바랐습니다. 심사 기준 역시 기술의 복잡도나 코드량보다 서비스 자체의 기획, 문제 정의, 실현 가능성에 더 많은 비중을 두었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결과적으로 배포를 선택으로 둔 것이 참가자들의 완주를 막지는 않았습니다. 35개 팀 중 34개 팀이 최종 결과물을 제출해 97%의 완주율을 기록했고, 이 가운데 18개 팀은 배포가 필수가 아니었음에도 자발적으로 서비스 URL까지 배포하며 MVP를 완성했습니다. 배포를 강제하지 않았기에 포기한 것이 아니라, 기획에 충분한 시간을 쓴 뒤 남는 시간으로 배포까지 도달한 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 저희가 참가자들에게 전하고 싶었던 메시지는 분명했습니다. &lt;strong&gt;이제 개발자는 코드를 만들어내는 사람을 넘어, 그 코드가 의미를 갖게 만드는 사람이어야 한다는 점&lt;/strong&gt;입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2. 해커톤의 주제: ‘취업난’&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;좋은 서비스는 대개 내가 직접 느끼는 문제에서 출발합니다. 그래서 이번 해커톤의 주제를 정할 때도 참가자들이 가장 보편적으로, 그리고 가장 크게 공감할 수 있는 문제가 무엇일지를 오래 고민했습니다. 그 결과 선정한 주제가 바로 ‘취업난’이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/image1.jpg"&gt;&lt;figcaption&gt;GDGOC ONE WAVE 해커톤 OT - 주제 공개 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;대학생에게 취업은 너무 멀지도, 너무 추상적이지도 않은 문제입니다. 이미 현실로 닿아 있고, 주변의 많은 사람이 함께 고민하는 주제이기도 합니다. 실제로 주제가 공개되었을 때 행사장에서는 웃음과 탄식이 동시에 나왔습니다. 모두가 너무 잘 알고 있는 문제였기 때문입니다. 저희는 바로 그 공감대를 출발점으로 삼고 싶었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 큰 주제가 하나로 주어지면 비슷한 아이디어가 반복될 가능성도 큽니다. 이를 막기 위해 ‘검증’, ‘실전’, ‘전략’, ‘멘탈’이라는 네 개의 서브 키워드 중 하나를 선택해 조합하도록 했습니다. 같은 ‘취업난’을 다루더라도 어떤 팀은 정보의 신뢰성과 검증에, 어떤 팀은 실전 준비에, 또 어떤 팀은 전략 설계나 멘탈 관리에 더 집중할 수 있도록 한 것입니다. 이 장치 덕분에 참가자들은 하나의 공통 문제를 두고도 각기 다른 타깃 사용자와 해결 방식을 설계할 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실제로 이 장치는 참가자들의 문제 정의를 꽤 선명하게 갈라놓았습니다. 한 팀은 스펙 위주의 서류 전형이 실제 역량을 제대로 보여주지 못한다는 점에 주목해, 이력서를 없애고 실무 과제만으로 평가받는 채용 플랫폼을 제안했습니다. 반면 세 개의 팀은 취업난을 정보나 역량의 문제가 아니라 반복된 탈락 속에서 무너지는 심리의 문제로 해석하고, 짧은 챌린지와 감정 기반 피드백을 제공하는 멘탈 케어 서비스로 풀어냈습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 밖에도 기업 기술 블로그를 바탕으로 실무 시뮬레이션을 만든 팀, 합격자의 준비 과정을 타임라인으로 시각화한 팀 등 접근 방식은 다양했습니다. 결국 같은 '취업난'이라는 주제를 두고도, 어떤 팀은 역량의 검증을, 어떤 팀은 심리적 회복을, 또 어떤 팀은 실전 체감이나 전략 설계를 핵심 문제로 삼은 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/%E1%84%8C%E1%85%A6%E1%84%86%E1%85%A9%E1%86%A8_%E1%84%8B%E1%85%A5%E1%86%B9%E1%84%82%E1%85%B3%E1%86%AB_%E1%84%91%E1%85%B3%E1%84%85%E1%85%A6%E1%84%8C%E1%85%A6%E1%86%AB%E1%84%90%E1%85%A6%E1%84%8B%E1%85%B5%E1%84%89%E1%85%A7%E1%86%AB.jpg"&gt;&lt;figcaption&gt;GDGOC ONE WAVE 해커톤 참가 팀 기획 물 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반면 또 다른 한팀은 기업마다 다른 실무 환경과 의사결정 문화를 미리 체감하지 못하는 점을 문제로 보고, 기업 기술 블로그를 바탕으로 실제 상황을 롤플레잉하는 시뮬레이션 서비스를 기획했습니다. 결과론적인 합격 스펙보다 합격자가 어떤 순서로 무엇을 해왔는지가 더 중요하다고 판단해, 준비 과정을 타임라인 형태의 전략 로드맵으로 시각화한 두 팀도 있었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또 세 개의 팀은 취업난을 단지 정보나 역량의 문제가 아니라 반복된 탈락 속에서 무너지는 심리의 문제로 해석하고, 짧은 챌린지와 감정 기반 피드백을 제공하는 멘탈 케어 서비스로 풀어냈습니다. 결국 같은 ‘취업난’이라는 주제를 두고도, 어떤 팀은 역량의 검증을, 어떤 팀은 실전의 체감을, 어떤 팀은 준비 전략을, 또 어떤 팀은 심리적 회복을 핵심 문제로 삼았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;3. 미리 ‘기획’을 공개하다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;요즘은 좋은 서비스가 나오면 AI를 활용해 하루 만에 유사한 서비스가 만들어지는 시대입니다. 이런 환경에서는 아이디어를 끝까지 숨기는 것만으로 차별점을 만들기 어렵습니다. 오히려 중요한 것은 같은 문제를 보더라도 어떤 관점으로 정의하고, 어떤 근거와 논리로 풀어내는가에 있다고 생각했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 저희는 각 팀이 행사 첫날 저녁, 기획을 마무리하고 본격적인 개발에 착수하기 직전에 기획 내용을 공유하도록 했습니다. 아이디어가 아직 흐릿한 단계에서는 서로의 방향을 비교하기 어렵고, 반대로 개발이 너무 진행된 뒤에는 중복을 인지하더라도 기획을 수정하기 쉽지 않기 때문입니다. 다시 말해, 서비스의 뼈대는 세워졌지만 아직 방향 전환의 여지가 충분히 남아 있는 시점을 의도적으로 기획 교류 시간으로 잡았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;실제로 기획 교류 시간에 등록된 35개 팀의 아이디어를 살펴보면, AI를 활용해 취업 문제를 해결하겠다는 큰 방향은 비슷했지만 세부 주제는 생각보다 많이 겹쳤습니다. 면접 연습 및 피드백이 4팀, 취업 멘탈 케어가 4팀, 취업 로드맵 생성 및 매칭이 4팀, 적합성 검증 및 기업 매칭이 4팀이었고, 이력서·자기소개서 첨삭 및 생성도 3팀에 달했습니다. 마지막 발표 전까지 서로의 기획을 보지 못했다면, 적지 않은 팀이 발표장에서야 “우리와 비슷한 주제가 이렇게 많았구나”를 확인했을 것입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 구조가 실제로 의미 있었던 이유는, 참가자들이 단순히 기능을 더 붙이는 대신 문제를 다시 정의하게 만들었기 때문입니다. 대표적인 사례가 Team 36이었습니다. 이 팀은 초기에는 깃 로그 분석, 모션 인식 등 여러 기술 요소를 포함한 비교적 넓은 취업 지원 서비스를 구상했습니다. 하지만 기획 교류를 통해 범용 면접 앱이나 자기소개서 관련 서비스가 이미 여러 팀에서 나오고 있다는 점을 확인한 뒤, 방향을 과감하게 좁혔습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/image6.jpg"&gt;&lt;figcaption&gt;ONE WAVE 해커톤 밤샘 개발 현장 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AI가 자기소개서를 대신 써주거나 면접 답변을 만들어주는 쪽이 아니라, 지원자가 자기 경험을 스스로 복기하고 구조화하도록 돕는 ‘커리어 리플렉션’에 집중한 것입니다. 최종 결과물에서는 모션 인식 같은 부가 기능을 덜어내고, 경험 정리와 질문 유도에 초점을 맞춘 서비스로 정체성을 선명하게 만들었습니다. 같은 취업 준비라는 주제를 다루더라도, 어디를 문제의 핵심으로 보느냐에 따라 완전히 다른 서비스가 될 수 있다는 점을 보여준 사례였습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;기획 교류 이후 가장 인상적이었던 점은 ‘기능의 추가’보다 오히려 ‘&lt;strong&gt;기능의 삭제&lt;/strong&gt;’가 더 자주 일어났다는 사실입니다. 초기 기획안과 최종 결과물을 비교해 보면, 많은 팀이 이것저것 다 넣으려는 방향에서 벗어나 한 줄로 설명 가능한 핵심 가치에 집중했습니다. 저희는 이 과정을 통해, AI 시대의 해커톤에서는 구현 자체보다도 누구의 어떤 문제를, 왜 이 방식으로 해결하는가를 더 밀도 있게 설명하는 기획이 차별점이 된다는 사실을 다시 확인했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;4. 운영진 또한 AI로 일한다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;AI 시대의 해커톤을 이야기하면서 참가자만 바뀌어서는 충분하지 않습니다. 운영 방식 역시 함께 달라져야 합니다. 해커톤 현장에는 생각보다 많은 반복 업무가 있습니다. 참가자 등록과 취소 상태 관리, 운영진 및 참가자 권한 부여, 팀 매칭 현황 시각화, 참가자 연락, 팀별 현황 조사, 심사 배점 입력과 결과 취합처럼 하나하나 보면 단순하지만 실제로는 많은 시간을 잡아먹는 일들입니다. 이런 업무가 수작업에 의존할수록 운영진은 작은 변경에도 여러 문서를 오가며 확인해야 하고, 현장 대응 속도도 자연스럽게 느려질 수밖에 없습니다. 그래서 저희는 반복적이고 비효율적인 운영 업무를 가능한 한 시스템 안으로 끌어들였습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;대표적인 사례는 심사 결과 자동 산정 대시보드였습니다. 심사위원이 시스템에서 바로 점수를 입력하면 예선·본선 점수와 가중치가 즉시 반영되고, 동점 여부까지 포함한 최종 순위가 자동으로 계산되도록 구성했습니다. 운영진이 별도의 시트에서 점수를 다시 모으고 계산식을 확인하던 과정을 줄이면서, 시상 직전의 취합 부담도 크게 낮출 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/image9.png"&gt;&lt;figcaption&gt;심사 현황 관리 시스템 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/image10.png"&gt;&lt;figcaption&gt;심사 현황 관리 시스템 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;참가자 상태 관리 역시 자동화했습니다. 해커톤 운영에서는 참여 취소, 팀 변경, 명단 수정처럼 참가자 상태가 바뀌는 일이 생각보다 자주 생깁니다. 문제는 이런 변경이 오프라인 명단 수정에서 끝나지 않는다는 점입니다. 참가자들이 모여 있는 디스코드에서도 해당 인원의 접근 권한을 조정하고, 필요한 경우 닉네임 표시까지 함께 바꿔야 했기 때문입니다. 이를 수작업으로 처리하면 운영진이 디스코드 관리자 화면에서 한 명씩 사용자를 찾아 역할을 수정해야 해 시간이 많이 들고, 변경 사항이 누락될 가능성도 있었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 저희는 백오피스에서 상태가 변경된 참가자들을 선택하면 디스코드 권한과 닉네임이 자동으로 함께 반영되도록 만들었습니다. 덕분에 오프라인에서 변경된 내용이 온라인 운영 공간에도 바로 동기화됐고, 운영진은 반복적인 권한 관리보다 참가자 경험과 현장 흐름을 살피는 일에 더 집중할 수 있었습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/image3.png"&gt;&lt;figcaption&gt;참가자 관리 시스템 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/image2.png"&gt;&lt;figcaption&gt;참가자 관리 시스템 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한 현장에서는 계획한 기능만으로는 부족한 순간이 자주 생깁니다. 이번 해커톤에서는 그런 순간마다 필요한 기능을 즉시 만들어 실제 운영에 반영할 수 있었습니다. 행사 도중 구글 로그인 오류가 발생했을 때는 팀별 임시 비밀번호 로그인 기능을 곧바로 추가해 제출 병목을 해소하기도 했습니다. 저희에게 AI는 단순히 일을 빨리 하는 도구가 아니라, 운영 과정에서 드러나는 병목을 현장에서 바로 시스템으로 바꾸는 도구였습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 지점에서 운영진의 역할도 조금 달라졌다고 느꼈습니다. 예전처럼 많은 일을 손으로 빠르게 처리하는 사람이 되는 것보다, 반복 업무를 시스템화하고 현장의 흐름이 끊기지 않도록 구조를 설계하는 사람이 되는 것이 더 중요해졌기 때문입니다. ONE WAVE는 참가자들이 AI를 활용해 개발 방식의 변화를 경험한 자리였을 뿐 아니라, 운영진 역시 AI를 활용해 일하는 방식 자체를 바꿔본 자리이기도 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;대상 수상작 소개&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;기획 교류 시간에 팀별 아이디어를 등록하면 관리자였던 저 역시 내용을 함께 확인할 수 있었는데요. 그중에서 주제를 처음 봤을 때 “이 팀은 참신하다”는 인상을 준 팀이 있었습니다. 바로 8팀이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/image4.jpg"&gt;&lt;figcaption&gt;8팀 발표 모습 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;8팀은 장애인 구직자와 기업을 연결하고, 채용 정보의 디지털 접근성을 개선하는 매칭 플랫폼 ‘BARRIER FREE’를 제안했습니다. 이들이 높은 평가를 받은 이유는 ‘취업난’이라는 큰 주제 속에서 타깃 사용자가 명확했고, 그들이 겪는 현실적인 장벽을 구체적인 데이터와 UX로 풀어냈기 때문입니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;8팀이 제안한 서비스의 핵심 플로우는 이렇습니다. 시각장애인 구직자가 앱에 접속하면 화면을 읽기 힘든 점을 고려해 클라우드 기반 텍스트 음성화(TTS) 기능으로 사운드 안내를 제공합니다. 구직자가 안내에 따라 10~60초간 자신의 경력을 음성으로 녹음하면, 음성 텍스트화(STT) 기술과 OpenAI를 활용해 말하는 것만으로 이력서가 자동 생성됩니다. 기존 채용 플랫폼이 장애 정도를 단순히 ‘심하다/심하지 않다’로 뭉뚱그려 정보만 제공했던 것과 달리, 실제 사용자가 정보를 입력하고 탐색하는 과정 자체의 '디지털 접근성' 장벽을 허문 것입니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/image5.png"&gt;&lt;figcaption&gt;8팀 발표 슬라이드 - 핵심 기능 &amp;lt;출처: GDGOC ONE WAVE, 8팀(남경인, 강지윤, 안성현, 조정현)&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한, 이들은 문제 해결의 근거로 구체적이고 수치화된 데이터를 활용했습니다. 구직자의 직무 역량을 판단하기 위해 수작업, 근력, 시력 등 6개의 신체 역량을 4단계로 세분화하여 수치화했습니다. 이 데이터와 공공데이터포털의 정보를 결합하여, 신체 환경 적합도뿐만 아니라 고용 안정성과 급여 매력도 등을 100점 만점의 매칭 점수로 환산해 추천해 주는 전략적인 검색 엔진을 구축했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;심사위원분들의 평가 역시 비슷한 방향에 모였습니다. 발표가 깔끔하고 전달력이 좋았으며, 문제를 잘 정의한 뒤 그에 맞는 해결책을 제시하는 흐름이 좋았다는 평가가 있었습니다. 참신한 아이디어로 틈새시장을 날카롭게 공략했다는 의견도 있었고, 다수의 사람이 공감할 수 있는 약자와 소수자의 문제를 해결하려 했다는 점을 강점으로 보신 분들도 계셨습니다. 활용하는 데이터와 API가 비교적 구체적이었고, 시장을 설정하는 앞단의 논리 구조 역시 잘 짜여 있었다는 평가도 이어졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;저 역시 이 팀이 높은 평가를 받은 이유가 분명하다고 느꼈습니다. 먼저 서비스의 타깃이 입체적이었습니다. 장애인 구직자뿐만 아니라, 장애인을 고용하지 않을 경우 1인당 200만 원의 고용부담금을 내야 하는 기업의 HR 담당자까지 핵심 타깃으로 삼아 맞춤형 대시보드를 기획했습니다. 또 문제 해결에 사용할 데이터와 근거가 비교적 구체적이었으며, 그 사용자를 위한 UX 흐름도 자연스럽게 설계되어 있었습니다. 결국 이 수상작은 이번 해커톤이 무엇을 더 중요하게 보았는지를 잘 보여주는 사례였습니다. 코드의 양보다 누구를 위해, 어떤 문제를, 어떤 근거와 흐름으로 풀어냈는가가 더 중요하다는 점 말입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;ONEWAVE Team 인터뷰&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;ONE WAVE는 11월 초부터 약 두 달간, 전국 18개 챕터에서 모인 운영진이 8개 파트(Sales, DevRel, HR, Infra, Marketing, Branding, Finance, Operation)로 나뉘어 준비했습니다. 이 글에서 계속 이야기한 것처럼, 이번 해커톤은 참가자뿐 아니라 운영진의 일하는 방식도 함께 바뀌는 실험이었습니다. 그 변화를 가장 직접적으로 체감한 세 파트를 소개합니다. 백오피스를 직접 설계한 총괄, 체크인 시스템을 자체 개발한 Infra, 평가 환경의 설계를 바꾼 Sales의 이야기입니다. 이어서 나머지 파트의 운영진이 각자의 자리에서 어떤 역할을 맡았는지도 함께 전합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/%E1%84%8B%E1%85%AE%E1%86%AB%E1%84%8B%E1%85%A7%E1%86%BC%E1%84%8C%E1%85%B5%E1%86%AB_%E1%84%83%E1%85%A1%E1%86%AB%E1%84%8E%E1%85%A6%E1%84%89%E1%85%A1%E1%84%8C%E1%85%B5%E1%86%AB.jpg"&gt;&lt;figcaption&gt;GDGoC ONE WAVE 해커톤 운영진 단체사진 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;총괄: 강남대학교 정은혁&lt;/strong&gt;&lt;/h4&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;안녕하세요! 이번 ONE WAVE 해커톤에서 총괄을 맡은 정은혁입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이번 행사를 준비하며 가장 중요하게 생각한 방향은 ‘지속 가능한 모두를 위한 해커톤’을 만드는 것이었습니다. 참가자뿐 아니라 운영진 역시 운영 경험을 통해 배우고 성장하는 또 다른 참여자라고 생각했기 때문에, 팀 구성과 협업 방식, 문서화, 태스크 관리까지 최대한 체계적으로 설계해 더 건강한 운영 환경을 만들고자 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그 과정에서 가장 크게 고민한 것은 어디까지 직접 개입하고 어디까지 믿고 맡길지에 대한 균형이었습니다.이를 고민하는 과정에서 특히 총괄이 세부 실행까지 모두 붙잡기보다 초기에 방향과 기준을 명확히 잡고 필요한 순간에만 조율하는 방식이 더 중요하다는 점을 많이 배웠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한 참가자 관리와 심사 운영 과정에서 반복적으로 발생하는 불편을 줄이기 위해 백오피스를 직접 개발해 적용했는데, 이런 자동화가 큰 규모의 행사 운영을 훨씬 안정적으로 만든다는 것도 확인할 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이번 해커톤을 통해 잘 설계된 구조와 좋은 팀워크가 있다면, 연합 해커톤도 충분히 즐겁고 지속 가능하게 운영할 수 있다는 확신을 얻었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;Infra: 성공회대학교 윤준석&lt;/strong&gt;&lt;/h4&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;안녕하세요, GDGOC 성공회대학교 오거나이저 윤준석입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이번 ONE WAVE 해커톤에서는 Infra 팀을 맡아 해커톤이 원활하게 진행될 수 있도록 전반적인 인프라를 담당했습니다. Infra 팀이라는 이름은 단순한 기술 지원을 넘어 온라인과 오프라인을 아우르는 해커톤 운영 환경 전체를 책임지겠다는 의미를 담고 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;먼저 준비 단계에서는 운영진들의 빠른 의사결정과 업무 연속성을 위해 노션 회의록을 관리하고, 부서장 중심의 디스코드 커뮤니케이션 구조를 구축해 부서 간 소통이 원활하도록 지원했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여러 학교의 운영진이 함께 준비하는 행사였기에 이러한 협업 환경을 정리하는 것이 중요한 일 중 하나였다고 생각합니다. 현장에서는 “성공적인 마무리를 위한 인프라 지원”에 초점을 두었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;참가자들의 원활한 입장을 위해 체크인 시스템을 직접 개발해 키오스크 형태로 운영했고, 이를 통해 행사장 입장시 발생할 수 있는 병목과 대기 시간을 크게 줄일 수 있었습니다. 또한 메인 홀 행사 중 상단 TV가 출력되지 않는 예상치 못한 상황이 있었지만, 만일을 대비해 챙겨간 HDMI 분배기를 활용해 빠르게 문제를 해결할 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;아울러 호실 방송 시스템을 구축해 공지 전달을 지원하고, 참가자들이 개발에 몰입할 수 있도록 참여형 음악 플레이리스트를 제공했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Infra 팀은 무대 위가 아니라 무대 뒤에서 행사가 자연스럽게 흘러가도록 기반을 만드는 팀이라고 생각합니다. 이번 ONE WAVE 해커톤을 통해 보이지 않는 곳에서 행사를 완성도 있게 만들어 주는 지속적인 인프라 지원의 중요성을 다시 한번 느낄 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;Sales: 서울과학기술대학교 염정우&lt;/strong&gt;&lt;/h4&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;안녕하세요, GDGOC 서울과학기술대학교 오거나이저 염정우입니다. 이번 ONE WAVE 해커톤에서 영업팀장을 맡아 심사위원 및 멘토 섭외, 후원사 컨택을 담당했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;섭외 과정에서 제가 가장 깊이 고민한 부분은 'AI 시대 해커톤의 새로운 평가 기준'이었습니다. AI 도구의 발전으로 기술 구현의 장벽이 크게 낮아진 지금, 해커톤의 핵심은 단순한 기술력 평가를 넘어섰다고 생각합니다. 이제는 프로덕트가 어떤 문제를 어떻게 해결하는지, 그 기획과 비즈니스 역량을 평가하는 것이 훨씬 중요해진 시대입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;참가자들의 치열한 결과물이 제대로 인정받을 수 있도록, 이번 행사에서는 Tech와 Biz 전문가를 고루 모셔 심사위원단의 밸런스를 맞추는 데 가장 큰 공을 들였습니다. 다각도의 날카로운 피드백을 통해 1박 2일의 시간이 참가자들에게 단순한 대회를 넘어 '확실한 성장의 시간'이 되도록 경험의 밀도를 높이고 싶었습니다. 이러한 목표에 공감하고 한마음으로 움직여준 운영진분들 덕분에 참가자들의 기획과 기술을 입체적으로 평가할 수 있는 최적의 심사 환경을 만들 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이번 해커톤은 '어떤 시각으로 프로덕트를 바라보고 평가할 것인가'에 대한 해답을 찾아가는 과정이었습니다. 운영진으로서 평가 환경을 설계하며, 기술의 완성도만큼이나 비즈니스적 가치 창출이 중요하다는 점을 다시금 깨달을 수 있었던 값진 경험이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 외에도 ONE WAVE는 다양한 파트의 운영진이 함께 만들었습니다. 브랜딩을 맡은 계원예술대학교 노권후는 도쿄 여행 중 출력물 발주 위기를 원격으로 해결하며 현장 몰입을 설계했고, DevRel의 대진대학교 이우민은 본선 심사가 길어진 40분을 전날 못 쓴 콘텐츠로 즉석 커버했습니다. 마케팅의 삼육대학교 김성윤은 서로 다른 배경의 참가자들을 하나의 메시지로 모객하는 역할을, 회계의 전남대학교 황재현은 변동하는 예산을 실시간으로 반영해 안정적인 집행을 이끌었습니다. HR의 중앙대학교 최민준은 약 200명의 사전 설문 데이터를 AI 기반 매칭 프로세스로 분석해 35개 팀의 직군 밸런스를 맞추는 팀 빌딩을 이끌었고, A현장운영의 가천대학교 장영하는 멘토가 직접 팀을 찾아가는 동선을 설계해 참가자의 멘토링 접근성을 높였습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3691/image7.jpg"&gt;&lt;figcaption&gt;GDGoC ONE WAVE 해커톤 단체사진 &amp;lt;출처: GDGOC ONE WAVE&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이번 해커톤에서 확인한 것은 세 가지입니다. 첫째, 배포를 필수에서 선택으로 바꾸자 참가자들은 실제로 기획에 더 많은 시간을 썼고, 심사 상위 팀일수록 문제 정의의 밀도가 높았습니다. 둘째, 기획 교류를 프로세스 안에 넣자 비슷한 주제의 중복이 초기에 걸러졌고, 팀들은 기능을 더 붙이는 대신 차별점을 다듬는 쪽으로 움직였습니다. 셋째, 운영진이 반복 업무를 AI로 시스템화하자 현장 대응에 쓸 수 있는 시간이 늘어났고, 예상하지 못한 필요에도 즉시 대응할 수 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그리고 이 세 가지 변화가 실제로 작동하고 있다는 걸 가장 분명하게 보여준 건 현장의 분위기였습니다. 체력이 바닥난 새벽에도 팀들이 붙들고 있었던 건 코드의 양이 아니라 "우리의 로직이 진짜 이 문제를 풀 수 있는가"라는 본질적인 질문이었습니다. 단순히 해커톤을 후원하는 차원을 넘어, 이 실험의 방향성에 공감해 함께해 준 파트너들의 존재도 큰 힘이 되었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;동시에 다음에 바꿔야 할 것도 보였습니다. 기획 교류의 효과를 더 정밀하게 측정할 장치가 필요했고, 운영 백오피스도 사전에 더 체계적으로 설계했다면 현장에서 즉석으로 만드는 부담을 줄일 수 있었을 것입니다. 참가자에게 "기획이 중요하다"고 말하면서도, 그 기획의 질을 끌어올려 줄 수 있는 멘토링 구조는 아직 충분하지 않았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;해커톤을 준비하는 분들이 이 글에서 한 가지라도 가져갈 수 있다면, 이것을 말씀드리고 싶습니다. AI가 구현의 장벽을 낮추는 만큼, 해커톤의 무게중심은 자연스럽게 "무엇을 왜 만드는가"로 옮겨갑니다. 그리고 그 변화는 참가자에게만 해당하는 이야기가 아닙니다. 참가자가 기획에 집중하길 바란다면, 운영진도 반복 업무에 묶여 있는 방식에서 먼저 벗어나야 합니다. ONE WAVE는 그 실험의 첫 번째 기록이었고, 다음에는 더 나은 버전을 만들 수 있다고 생각합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;글:&lt;/strong&gt;&lt;span style="color:rgb(49,49,49);"&gt;GDGoC 정은혁&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;&lt;span style="color:#757575;"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>자바스크립트 AbortController로 비동기 작업 취소하기</title><link>https://yozm.wishket.com/magazine/detail/3686</link><description>우리가 검색창에 글자를 입력할 때마다 서버에 요청을 보내는 자동완성 기능을 떠올려봅시다. 사용자가 “자바스크립트”를 검색하려고 “자”, “자바”, “자바스”를 빠르게 입력하면, 이전에 보낸 요청들은 더 이상 필요 없어집니다. 이처럼 비동기 작업을 시작한 뒤 중간에 취소해야 하는 상황은 실무에서 꽤 자주 발생하는데요, 자바스크립트에서는 AbortController를 통해 이런 비동기 작업을 깔끔하게 취소할 수 있습니다. 이번 글에서는 AbortController의 기본 구조부터 실무에서 활용하는 패턴까지 함께 살펴보겠습니다.</description><guid>https://yozm.wishket.com/magazine/detail/3686</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;우리가 검색창에 글자를 입력할 때마다 서버에 요청을 보내는 자동완성 기능을 떠올려봅시다. 사용자가 “자바스크립트”를 검색하려고 “자”, “자바”, “자바스”를 빠르게 입력하면, 이전에 보낸 요청들은 더 이상 필요 없어집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3686/%EA%B7%B8%EB%A6%BC1.avif" alt="비동기작업"&gt;&lt;figcaption&gt;&amp;lt;출처: &lt;a href="https://smart-interface-design-patterns.com/articles/autocomplete-ux"&gt;smart-interface-design-patterns.com&lt;/a&gt;&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이처럼 비동기 작업을 시작한 뒤 중간에 취소해야 하는 상황은 실무에서 꽤 자주 발생하는데요, 자바스크립트에서는 AbortController를 통해 이런 비동기 작업을 깔끔하게 취소할 수 있습니다. 이번 글에서는 AbortController의 기본 구조부터 실무에서 활용하는 패턴까지 함께 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;미리 요점만 콕 집어보면?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;AbortController를 통해 비동기 작업을 시작한 뒤 중간에 취소해야 하는 상황을 깔끔하게 처리할 수 있습니다.&lt;/li&gt;&lt;li&gt;controller.abort()를 호출하면 signal의 aborted 속성이 true로 바뀌면서 연결된 비동기 작업이 중단됩니다.&lt;/li&gt;&lt;li&gt;fetch 요청 취소, 이벤트 리스너 관리, 여러 비동기 작업을 한 번에 취소하는 패턴까지 활용할 수 있습니다.&lt;/li&gt;&lt;/ul&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;AbortController의 기본 구조&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AbortController를 사용하려면 먼저 두 가지 개념을 알아야 합니다. 바로 AbortController 자체와, 여기서 파생되는 AbortSignal입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3686/%EA%B7%B8%EB%A6%BC2.webp" alt="AbortController"&gt;&lt;figcaption&gt;&amp;lt;출처: https://reliasoftware.com/blog/axios-in-react-js&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) AbortController와 AbortSignal&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;AbortController를 생성하면, signal이라는 속성을 통해 AbortSignal 객체가 함께 노출됩니다. AbortController가 취소 명령을 내리는 쪽이라면, AbortSignal은 그 취소 신호를 전달받는 쪽입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;비유하자면, AbortController는 리모컨이고, AbortSignal은 TV에 달린 수신기라고 생각할 수 있습니다. 리모컨의 버튼을 누르면 수신기가 신호를 받아서 TV가 꺼지는 것처럼, controller.abort()를 호출하면 signal이 신호를 받아서 연결된 작업이 취소됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const controller = new AbortController();
const signal = controller.signal;
console.log(signal.aborted); // false

controller.abort(); // 취소 명령 전달
console.log(signal.aborted); // true&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;AbortController()로 컨트롤러를 생성하면, 자동으로 signal 속성에 AbortSignal 객체가 만들어집니다. 이 상태에서 abort()를 호출하면 signal의 aborted 속성이 true로 바뀌면서, 이 signal을 전달받은 비동기 작업이 중단됩니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) abort 이벤트 감지하기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;그렇다면 취소 시점에 맞춰 정리 작업을 해야 할 때는 어떻게 할까요? signal의 abort 이벤트를 활용하면 됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const controller = new AbortController();
const signal = controller.signal;

signal.addEventListener("abort", () =&amp;gt; {
  console.log("작업이 취소되었습니다");
  console.log("취소 사유:", signal.reason);
});

controller.abort("사용자가 페이지를 떠남");
// "작업이 취소되었습니다"
// "취소 사유: 사용자가 페이지를 떠남"&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;abort() 메서드에 인자를 전달하면 signal.reason으로 취소 사유를 확인할 수 있습니다. 참고로 reason에는 문자열뿐만 아니라 어떤 값이든 넣을 수 있어서, 에러 객체나 코드 값을 전달하는 식으로 활용할 수도 있습니다. reason을 생략하면 기본적으로 “AbortError” DOMException이 들어갑니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;fetch 요청 취소하기&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AbortController의 기본 구조를 알았으니, 이제 실제로 가장 많이 쓰이는 fetch 요청 취소에 적용해 보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) 기본적인 fetch 취소&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;AbortController가 가장 많이 쓰이는 곳은 fetch 요청입니다. fetch의 두 번째 인자에 signal을 전달하면, 해당 요청을 원하는 시점에 취소할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const controller = new AbortController();

fetch("https://api.example.com/users", {
  signal: controller.signal, // signal 연결
})
  .then((res) =&amp;gt; res.json())
  .then((data) =&amp;gt; console.log(data))
  .catch((err) =&amp;gt; {
    if (err.name === "AbortError") {
      console.log("요청이 취소되었습니다");
    } else {
      console.error("요청 실패:", err);
    }
  });

// 필요한 시점에 취소
controller.abort();&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;abort()가 호출되면 fetch는 AbortError라는 특별한 에러를 발생시킵니다. catch 블록에서 err.name을 확인하면 사용자가 의도적으로 취소한 것인지, 네트워크 오류인지 구분할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 실무에서 자동완성처럼 연속으로 요청을 보내는 경우, 단순히 이전 요청을 abort하는 것만으로는 부족할 수 있습니다. 네트워크 환경이나 캐시 상태에 따라 늦게 도착한 이전 응답이 최신 결과를 덮어쓰는 경우가 생기기도 하는데요, 이런 상황을 방지하려면 abort와 함께 마지막 요청만 반영하는 로직을 같이 사용하는 편이 안전합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;let currentController = null;

async function search(query) {
  // 이전 요청이 있으면 취소
  if (currentController) currentController.abort();
  currentController = new AbortController();

  try {
    const res = await fetch(`/api/search?q=${query}`, {
      signal: currentController.signal,
    });
    const data = await res.json();
    renderResults(data); // 마지막 요청 결과만 반영
  } catch (err) {
    if (err.name !== "AbortError") {
      console.error("검색 실패:", err);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이렇게 하면 이전 요청을 가능한 빨리 취소할 수 있습니다. 위 코드에서 매번 new AbortController()로 새 컨트롤러를 만드는 이유는, 한 번 abort된 signal은 재사용할 수 없기 때문입니다. 이미 abort된 signal을 다시 fetch에 넘기면 요청이 즉시 reject되므로, 매 요청마다 새로운 AbortController를 생성해야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;다만 abort는 fetch 요청 자체를 중단시킬 뿐, UI 반영 로직까지 자동으로 막아주는 것은 아닙니다. 실무에서는 이미 처리 단계에 들어간 이전 응답이 뒤늦게 화면을 덮어쓰는 경우까지 방지하기 위해, abort와 함께 요청 ID를 비교하는 방식으로 마지막 요청만 반영하도록 만드는 것이 더 안전합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 타임아웃 설정하기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;서버 응답이 너무 오래 걸릴 때 자동으로 요청을 취소하고 싶다면, AbortSignal.timeout()을 활용할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;// 5초 안에 응답이 없으면 자동 취소
fetch("https://api.example.com/data", {
  signal: AbortSignal.timeout(5000),
})
  .then((res) =&amp;gt; res.json())
  .then((data) =&amp;gt; console.log(data))
  .catch((err) =&amp;gt; {
    if (err.name === "TimeoutError") {
      console.log("요청 시간이 초과되었습니다");
    }
  });&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AbortSignal.timeout(5000)은 5초 후에 자동으로 취소 신호를 보내는 signal을 생성합니다. 기존에는 setTimeout과 abort()를 조합해야 했지만, 이 정적 메서드를 사용하면 한 줄로 간결하게 타임아웃을 설정할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;스펙상 timeout으로 인한 취소는 TimeoutError로 구분할 수 있게 되어 있지만, fetch에서 최종적으로 어떤 에러 이름이 보이는지 런타임에 따라 차이가 있을 수 있습니다. 그래서 에러를 더 정확히 구분하고 싶다면 err.name과 함께 signal.reason까지 같이 확인하는 편이 안전합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;다양한 활용법&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AbortController는 fetch 외에도 다양한 Web API에서 활용할 수 있습니다. 이벤트 리스너 관리부터 여러 비동기 작업을 한꺼번에 제어하는 패턴까지 살펴보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;1) addEventListener에서의 활용&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;AbortController는 fetch뿐만 아니라 이벤트 리스너 관리에도 활용할 수 있습니다. addEventListener의 세 번째 인자에 signal을 전달하면, abort() 호출 시 이벤트 리스너가 자동으로 해제됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const controller = new AbortController();

document.addEventListener(
  "click",
  () =&amp;gt; {
    console.log("클릭!");
  },
  { signal: controller.signal } // signal 전달
);

// 이벤트 리스너 자동 해제
controller.abort();&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;기존에는 removeEventListener로 직접 이벤트를 해제해야 했고, 이때 동일한 함수 참조를 유지해야 하는 번거로움이 있었습니다. signal을 활용하면 이런 불편함 없이 깔끔하게 이벤트를 정리할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;특히 하나의 controller로 여러 이벤트 리스너를 한 번에 해제할 수도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const controller = new AbortController();
const { signal } = controller;

window.addEventListener("resize", handleResize, { signal });
window.addEventListener("scroll", handleScroll, { signal });
document.addEventListener("keydown", handleKeydown, { signal });

// 세 개의 이벤트 리스너를 한 번에 해제
controller.abort();&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;컴포넌트 언마운트나 페이지 전환 시점에 controller 하나만 abort하면 관련된 리스너를 한꺼번에 정리할 수 있어, 이벤트 해제 누락으로 인한 리소스 낭비를 줄이는 데 유리합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;2) 여러 비동기 작업 한 번에 취소하기&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;같은 원리로, 하나의 signal을 여러 fetch 요청에 전달하면 한 번의 abort()로 모든 요청을 동시에 취소할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3686/%EA%B7%B8%EB%A6%BC3.gif"&gt;&lt;figcaption&gt;&amp;lt;출처: &lt;a href="https://www.c-sharpcorner.com/article/easy-way-to-handle-cancellation-of-api-requests-in-react-with-abortsignal-types/"&gt;www.c-sharpcorner.com&lt;/a&gt;&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const controller = new AbortController();
const { signal } = controller;

// 여러 요청에 같은 signal 전달
const userReq = fetch("/api/user", { signal });
const postReq = fetch("/api/posts", { signal });
const commentReq = fetch("/api/comments", { signal });

// 페이지 이동 시 모든 요청을 한 번에 취소
controller.abort();&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;또한 여러 개의 취소 조건을 하나로 합쳐야 할 때는 AbortSignal.any()를 활용할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const userController = new AbortController();
const timeoutSignal = AbortSignal.timeout(5000);

// 사용자가 취소하거나, 5초가 지나면 취소
const signal = AbortSignal.any([
  userController.signal,
  timeoutSignal,
]);

fetch("/api/data", { signal })
  .then((res) =&amp;gt; res.json())
  .then((data) =&amp;gt; console.log(data))
  .catch((err) =&amp;gt; console.log("취소됨:", err.message));&lt;/code&gt;&lt;/pre&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AbortSignal.any()는 전달받은 signal 중 하나라도 abort되면 취소 신호를 보내며, 이때 가장 먼저 abort된 signal의 reason이 최종 reason으로 전달됩니다. 위 코드에서는 “사용자가 직접 취소”하거나 “5초 타임아웃”이 발생하면 요청이 취소됩니다. 다만, AbortSignal.any()는 비교적 최신 API라 일부 구형 환경에서는 호환성 확인이 필요할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이번 글에서는 AbortController의 기본 구조부터 fetch 취소, 이벤트 리스너 관리, 그리고 여러 작업을 한 번에 취소하는 패턴까지 살펴봤습니다.비동기 작업에서 “시작”하는 방법은 많이 다루지만, “취소”하는 방법은 상대적으로 덜 주목받는 경우가 많습니다. 하지만 불필요한 요청을 제때 취소하지 않으면 메모리 누수나 예상치 못한 상태 업데이트로 이어질 수 있기 때문에, 비동기 작업의 취소는 시작만큼이나 중요한 부분입니다. AbortController의 사용법이 그리 어렵지 않은 만큼, 다음 프로젝트에서 한번 적용해 보시면 좋겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>개발자, 이직이 완벽한 도피처가 될 수 있을까요?</title><link>https://yozm.wishket.com/magazine/detail/3683</link><description>여러분은 혹시 늦은 밤, 불 꺼진 방 안에서 모니터만 멍하니 바라보며 "나, 이대로 계속 개발을 해도 괜찮은 걸까?"라는 서늘한 불안감을 느껴본 적이 있으신가요? 아마 매일 똑같이 반복되는 업무에 지쳐서, 혹은 시간이 지나도 더 이상 실력이 발전하지 않는다는 생각에 이직 채용 사이트를 습관적으로 들여다보고 계실지도 모르겠습니다. 사실 저 또한 그런 시절이 있었습니다. 특히 일본에서의 첫 전직은 단순히 제 명함의 로고를 바꾸거나 출근하는 지하철 노선을 바꾸는 가벼운 일이 결코 아니었죠. 오늘은 일본에서 첫 전직을 결심하고 실행에 옮기며 부딪혔던 차가운 현실, 그리고 그 과정에서 철저하게 제 부족함을 돌아봤던 이야기를 나누어 보려고 합니다.</description><guid>https://yozm.wishket.com/magazine/detail/3683</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;blockquote&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;일본에서의 첫 이직: 개발자로서의 고뇌&lt;/strong&gt;&lt;/h4&gt;&lt;/blockquote&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여러분은 혹시 늦은 밤, 불 꺼진 방 안에서 모니터만 멍하니 바라보며 "나, 이대로 계속 개발을 해도 괜찮은 걸까?"라는 서늘한 불안감을 느껴본 적이 있으신가요? 아마 매일 똑같이 반복되는 업무에 지쳐서, 혹은 시간이 지나도 더 이상 실력이 발전하지 않는다는 생각에 이직 채용 사이트를 습관적으로 들여다보고 계실지도 모르겠습니다. 사실 저 또한 그런 시절이 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;타국에서 커리어를 쌓아간다는 것은 생각보다 훨씬 외롭고 막막한 순간들의 연속이었습니다. 특히 일본에서의 첫 전직(轉職, 직업이나 직무를 바꾸어 옮김)은 단순히 제 명함의 로고를 바꾸거나 출근하는 지하철 노선을 바꾸는 가벼운 일이 결코 아니었습니다. 당장 제 체류 자격을 증명하고 삶을 지탱해 주는 비자 문제가 걸려 있었고, 한 치 앞을 알 수 없는 복잡한 연봉 체계를 새롭게 계산해야 하는 치열한 생존의 문제였죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;무엇보다 일본 IT 특유의 파견 및 도급 중심 구조 속에서, 제가 개발자로서 올바른 방향으로 성장하고 있는지 스스로에게 냉정하게 물어야만 하는 고통스러운 과정이기도 했습니다. 처음 전직을 결심했던 순간만 해도, 제가 겪는 모든 성장의 정체와 불만족은 '내가 속한 환경' 탓이라고 굳게 믿었습니다. "회사가 나를 제대로 가르쳐 주지 않아서", "할당받은 프로젝트의 퀄리티가 너무 낮아서"라고 탓하곤 했죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;하지만 본격적으로 이력서를 쓰고 면접의 문을 두드리며 뼈저리게 깨닫게 된 사실이 하나 있습니다. 그 견고한 산업의 구조보다도 먼저 부족했던 건, 바로 준비되지 않은 저 자신이었다는 사실을요. 오늘은 일본에서 첫 전직을 결심하고 실행에 옮기며 부딪혔던 차가운 현실, 그리고 그 과정에서 철저하게 제 부족함을 돌아봤던 이야기를 여러분과 허심탄회하게 나누어 보려고 합니다.&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;성장의 시계가 멈추다: 전직을 고민하게 된 진짜 이유&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3683/image4.png"&gt;&lt;figcaption&gt;반복 업무, 1인 개발, 성장 정체의 악순환 &amp;lt;출처: 작가&amp;gt;&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;혼자라는 자유로움 뒤에 숨겨진 성장의 한계&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;제가 이전 회사에서 주로 담당했던 업무는 고객의 요구에 따라, 시스템을 만들어 납품하는 이른바 수탁 개발 형태였습니다. 다양한 산업군의 기능을 접해볼 수 있을 거라는 초기의 기대와는 달리, 현실은 늘 빠듯한 예산 속에서 쫓기듯 진행되는 소규모 프로젝트의 연속이었는데요. 회사의 이익 구조상 남는 것이 적다 보니 자연스럽게 저희의 급여도 제자리걸음을 면치 못하는 악순환이 계속되었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;게다가 규모가 작다 보니 개발의 기획 단계부터 납품까지 온전히 저 혼자 감당해야 하는 1인 개발 형태가 매우 잦았습니다. 물론 1인 개발을 통해 처음부터 끝까지 혼자 고민해 보며, IT 기술의 전반적인 파이프라인(Pipeline)을 넓고 유연하게 접할 수 있었다는 점은 큰 장점이었습니다. 하지만 체계적인 코드 리뷰(Code Review)나 뛰어난 시니어 개발자의 멘토링을 기대하는 것은 사치에 불과했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;당장 눈앞에 떨어진 버그를 고치고 납품 기한을 맞추는 데 급급하다 보니 설계의 본질에 대해 깊이 고민할 여유가 없었습니다. 막히는 에러가 발생해도 물어볼 곳 하나 없이 속 시원히 해결되지 않아, 퇴근 후에도 어김없이 집에서 노트북을 열고 끙끙 앓아야 했던 날들이 무수히 많았습니다. 이러한 환경에서 과연 5년 뒤, 10년 뒤의 제가 어떤 모습일지 상상하니 눈앞이 캄캄해졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;개발자 타이틀을 잃을지도 모른다는 깊은 위기감&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이러한 불만족이 쌓여가던 중, 저를 본격적인 전직 시장으로 강력하게 내몬 결정적인 위기가 찾아왔습니다. 다니던 회사가 다른 기업과 합병을 겪게 되면서 심각한 영업 부진에 빠진 것이었는데요. 합병 이후 영업이 급격히 위축되면서, 동료 개발자들은 하나둘 회사를 떠나기 시작했습니다. 결국 남은 건 저 혼자였습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;개발할 프로젝트도 사라진 상황에서, 매출이라도 만들어야 했던 회사는 저를 IT 시스템 운영팀으로 보낼 수밖에 없었습니다. 그렇게 5개월이라는 결코 짧지 않은 시간 동안, 본연의 코딩 업무가 아닌 무미건조한 운영 업무만을 전담하게 되었습니다. 운영팀에서의 하루하루는 제게 커다란 절망감을 안겨주었습니다. 당장 이곳에서 아무리 훌륭하게 성과를 낸다고 한들, 개발자로서 급여가 더 오를 희망은 보이지 않았기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;무엇보다 하루가 다르게 새로운 기술이 쏟아져 나오는 이 업계에서, 소중한 제 커리어에 회복하기 힘든 공백이 생길 것이라는 걱정이 매일 밤 저를 짓눌렀습니다. 더 늦기 전에 멈춰버린 성장의 톱니바퀴를 다시 굴려야 한다는 확신이 들었습니다. 그것이 제가 서둘러 정든 곳을 떠날 채비를 하게 만든 가장 절박한 이유였습니다. 결코 여유롭고 안정적인 상황에서 준비한 이직이 아니었기에 제 마음은 더욱 초조할 수밖에 없었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;피부로 느낀 일본 IT의 맨얼굴: 구조적 현실과 마주하다&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3683/image3.png"&gt;&lt;figcaption&gt;일본 IT 산업의 다단계 하청 구조 &amp;lt;출처: 작가&amp;gt;&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 style="text-align:justify;"&gt;&amp;nbsp;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;견고하게 자리 잡은 의존적 생태계&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;일본에서 개발자로 첫발을 내딛고 살아가다 보면, 피할 수 없이 마주치게 되는 단어가 있습니다. 바로 SES(System Engineering Service)라는 파견 위주의 기술 인력 제공 형태입니다. 한국의 시스템 통합(SI) 업무 환경과 비슷한 맥락이지만, 현장에 상주하는 방식과 다단계의 계약 구조에서 뚜렷한 차이를 보입니다. 실제로 수많은 일본의 IT 기업들이 자체적인 서비스를 기획하고 구축하는 사내 개발을 하기보다는, 이 SES나 수탁 개발 구조에 절대적으로 의존하고 있는 것이 엄연한 생태계의 현실입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;자체 플랫폼이나 서비스를 가진 사내 개발 환경에서는 하나의 프로덕트에 대해 깊이 있게 고민하고, 대규모 트래픽(Traffic)에 대비해 코드를 리팩터링(Refactoring)하며 성장해 나가는 경험을 차곡차곡 쌓을 수 있습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반면, 수탁 개발이나 많은 외국인 개발자들이 흔히 겪는 SES 환경에서는 어떨까요? 짧으면 몇 개월, 길어도 1년 남짓한 프로젝트가 끝나면 또다시 새로운 환경의 전혀 다른 시스템 코드를 뜯어봐야 합니다. 잦은 환경 변화 속에서 자신만의 기술적인 철학과 깊이를 뾰족하게 가다듬는 것은 정말이지 쉽지 않은 일이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;언어 장벽과 홀로서기라는 미션&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;게다가 외국인 개발자에게 이러한 폐쇄적인 구조 속에서의 생존과 전직은 결코 가벼운 마음으로 던질 수 있는 출사표가 아니었습니다. 제가 처음 다녔던 회사는 다행스럽게도 한국인 동료들이 꽤 포진해 있어 심리적인 안정감이 매우 높은 편이었습니다. 기술적인 소통의 어려움이나 미묘한 문화적 차이를 선배들이 훌륭하게 메워주고 배려해 주었죠. 하지만 제가 진정한 성장을 위해 온전히 홀로 일본의 IT 생태계 속으로 뛰어들어 '완전한 일본계 회사'로 발걸음을 옮기려다 보니 상황의 온도는 180도 달라졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;철저히 내국인 일본 개발자들과 똑같은 기준의 잣대 위에서 평가받아야 했기 때문입니다. 회의의 논리 전개 방식, 까다로운 내부 문서 작성 프로세스 등 모든 것이 생경했습니다. 따뜻한 온실 속에서만 자라다가, 처음으로 매서운 야생 한가운데 내던져진 기분이랄까요? 단순히 코드를 잘 짜는 것을 넘어, 일본어라는 언어의 장벽을 뚫고 내 실력을 증명해야 하는 이중고를 겪어야 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;보이지 않는 모래주머니: 비자와 급여 체계의 공포&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3683/image6.png"&gt;&lt;figcaption&gt;한국 여권과 급여 봉투 사이의 불안한 균형 &amp;lt;출처: 작가&amp;gt;&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h3 style="text-align:justify;"&gt;&amp;nbsp;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;카운트다운이 시작되는 비자 문제&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;외국인으로서 타국에서 다른 직장을 알아볼 때 가장 먼저 우리의 숨통을 조여 오는 부분은 무엇보다도 '비자'라는 무거운 이름표입니다. 현지인들에게 전직은 그저 연금 수첩을 갱신하고 보험증을 새로 발급받는 약간의 수고로움일지 모릅니다. 하지만 우리는 상황이 완전히 다릅니다. 이직하려는 새 회사의 직무가 현재 소지한 취업 비자의 명목과 조금의 오차 없이 맞닿아 있는지 확인해야 하며, 퇴사 후 14일 이내에 출입국재류관리청에 의무적으로 소속 기관 변경 신고를 해야만 하죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;만약 다음 행선지를 정하지 못한 채 무직으로 3개월이 넘어가 버린다면, 비자 갱신이 거절될 수도 있다는 보이지 않는 시한폭탄을 가슴에 안고 살아가야 합니다. 더 나은 내일을 위해 내린 결단이었음에도 불구하고, '공백기'라는 시간적 압박은 엄청난 족쇄이자 공포로 다가왔습니다. 당장 생활비도 문제지만, 일본이라는 나라에서 쫓겨날지도 모른다는 근원적인 불안감이 전직 활동 내내 저를 괴롭혔습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;연봉의 허수와 무퇴직금의 설움&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;급격히 달라지는 급여 구조의 맹점 또한 간과할 수 없는 심리적 짐이었습니다. 일본 회사들의 경우 기본 연봉을 단순히 12개월로 균일하게 나누어 지급하는 곳도 있지만, 상여금(Bonus)이 전체 실수령액에서 차지하는 비중이 비정상적으로 큰 구조가 빈번하게 존재합니다. 이 말은 곧, 이직 후 입사 첫해에는 자격 요건 미달로 이 상여금을 온전히 수령하지 못하는 경우가 허다하다는 뜻입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;결국 연봉 조건을 높여 이직했음에도 첫해에는 오히려 손에 쥐는 돈이 줄어드는 아찔한 기현상을 마주할 수도 있는 것이죠. 여기에 더해 한국인들에게는 너무나 당연하게 여겨지는 '퇴직금' 제도가 아예 존재하지 않는 일본 기업들이 부지기수입니다. 제가 몸담았던 첫 회사 역시 단 1엔의 퇴직금조차 위로금으로 나오지 않는 곳이었죠. 이직 사이에 잠깐의 빈 타이밍이 발생한다면, 매달 숨만 쉬어도 나가는 살인적인 월세와 각종 세금을 오로지 예금 잔고로 버텨내야 했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;알량한 자만심의 붕괴: 나를 무너뜨린 처절한 실패기&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3683/image5.png"&gt;&lt;figcaption&gt;면접장에서 말이 나오지 않는 순간 &amp;lt;출처: 작가&amp;gt;&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;과거의 애매한 스펙이 발목을 잡다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;솔직히 고백하자면, 처음 이력서 작성을 시작할 때까지만 해도 제 마음 한구석에는 은근한 자신감이 깔려 있었습니다. 나름 4년제 대학교에서 컴퓨터공학과를 전공했고, OCJP나 정보처리기사, SQLD 같은 자격증도 몇 개 따 두었으니까요. 대단한 것은 아니었지만, 적어도 서류에서 빈칸을 채울 정도는 된다고 생각했습니다. 실무 경험도 나쁘지 않다고 자부했죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;한국에서 꽤 비중 있는 SI 프로젝트와 대용량 빅데이터(Big Data) 처리, 전산실 실무까지 경험해 보았습니다. 일본으로 건너와서도 지난 3년 이상 묵묵히 버텨내며, 고객의 가혹한 수정 요청을 이겨내고 성공적으로 납품을 마친 소프트웨어 제품까지 포트폴리오(Portfolio)에 올릴 수 있었습니다. 제가 봐도 꽤 그럴듯한 이력서였습니다. 당연히 어디든 저를 원할 거라고 맹신하며 여러 회사에 과감하게 입사 지원서를 던졌습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;소통의 단절, 그리고 드러난 진짜 민낯&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;서류는 생각보다 쉽게 통과되었습니다. 하지만 실전의 공기는 제 예상과 너무나도 달랐습니다. 가장 뼈아팠고 치명적이었던 패인은 바로 언어, 즉 '일본어 구사력'이었습니다. 한국인 동료들의 친절한 통역 뒤에 숨어서 일하던 시절에는 미처 깨닫지 못했던 제 일본어의 얕은 밑천이 적나라하게 드러난 것이죠. 기술 면접 과정이나 왜 우리 회사여야만 하는지 꼬리를 무는 질문 앞에서 제 입은 무겁게 얼어붙고 말았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그뿐만 아니라 제 과거의 멋진 경험을 상대방의 관점에서, 매력적인 '이익'으로 포장해 내는 요령도 전무했습니다. "이것도 써봤고, 저것도 다뤄봤다"라는 식의 백화점식 나열형 대답은 면접관들의 흥미를 끌어내지 못했습니다. 기업이 진정으로 필요로 하는 핵심 역량이 무엇인지 꿰뚫어 보지 못한 채, 막연히 "열심히 하겠습니다" 식의 겉도는 파편만 나열했습니다. 철저한 자기 객관화 없이 과거의 타이틀에만 기대었던 안일함이 불러온 쓰라린 실패였습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실패 속에 피어난 자각: 진짜 부족했던 세 가지&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:80%;"&gt;&lt;img src="https://www.wishket.com/media/news/3683/image1.png"&gt;&lt;figcaption&gt;세 조각으로 갈라진 거울 속 나의 부족함 &amp;lt;출처: 작가&amp;gt;&amp;nbsp;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;얕은 기술력과 앵무새 같은 비즈니스 언어&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;수없는 불합격의 고배를 마시던 중, 정말 운 좋게도 제 가능성을 믿어준 지금의 회사를 만났습니다. 하지만 최종 합격 메일을 받은 그 밤, 제 마음속에 일렁이는 감정은 환희보다는 부끄러운 자기반성이었습니다. 제가 마주했던 결핍 중 첫 번째는 참담할 정도로 얕은 '기술의 깊이'였습니다. 외부 코드를 가져다 쓰는 임기응변은 능숙했을지 모르나, 정작 컴퓨터 공학의 본질적 코어 원리에 대해 집요하게 파고들어 본 경험이 부족했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;두 번째는 처참했던 '비즈니스 일본어'의 부재였습니다. 코드야말로 만국 공통어라고 자위하며 살았지만, 결국 그 코드를 팀원들과 함께 어떤 가치를 위해 짤 것인지 설득하는 과정은 인간의 언어로 이루어집니다. 상대방의 의도를 곡해 없이 파악하고 나의 논리를 부드럽고 묵직하게 설득해 낼 수 있는 수준의 경어와 뉘앙스 최적화가 안 된다면, 누군가가 시키는 잡무만 받아내는 부속품으로 전락할 수밖에 없음을 아프게 실감했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;모든 걸 밖에서 찾으려 했던 내면의 나태함&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;마지막으로 저를 가장 부끄럽게 만든 것은 모든 문제의 화살을 외부로 돌리기 바빴던 **'수동적인 태도'**였습니다. 멘토가 없었다면 외부 커뮤니티를 직접 찾아가 기꺼이 제 코드를 까발리며 리뷰를 간청했어야만 했습니다. 회사의 성장이 멈추는 것 같아 억울했다면, 주말을 반납해서라도 오픈 소스(Open Source)를 뜯어보며 스스로 생존의 길을 모색했어야 옳았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그러나 저는 그 귀중한 시간 동안 가혹한 현실을 불평하고 회사의 보수적인 시스템만 원망하며 한탄하는 구경꾼에 머물렀습니다. 스스로 배의 조타수를 쥐고 거친 파도 속으로 뛰어들 생각은 조금도 하지 못한 채, 언제나 잔잔한 우물 안에서 구조선만 기다리던 불쌍한 개구리였던 셈입니다. 이러한 자각은 저에게 큰 충격을 주었고, 비로소 제가 앞으로 가야 할 길이 보이기 시작했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;환경을 원망하기 전, 내 안의 거울을 먼저 닦아볼까요?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;참으로 다사다난했던 저의 첫 번째 전직 생활은 단순히 일하는 회사의 간판을 갈아 끼우는 과정이 아니었습니다. 제 자신을 냉혹한 시장의 저울대 위에 던져 넣음으로써, 그동안 외면하고 싶었던 실력의 비루한 민낯과 마주하는 시간이었습니다. 그리고 현재의 진짜 제 수준을 가감 없이 직시하고 바닥부터 인정하게 만들어 준 세상에서 가장 아프고도 찬란한 성장의 터닝 포인트였습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;여러분, 전직은 결코 지금 마주한 일상의 어려움에서 도망치기 위해 선택하는 달콤한 도피처가 되어서는 안 됩니다. 내가 향하고자 하는 뚜렷한 목표 깃발을 꽂고 정면 돌파하기 위한 철저하고 주도적인 '나침반'이 되어야만 하죠. 도전과 좌절이 공존하는 일본이라는 시장에서 우리는 어떻게 생존해야 할까요? 대체 불가능한 개발자로 뿌리내리기 위해서는 비즈니스 언어의 칼날, 시장을 꿰뚫는 통찰력, 그리고 기술적 소양이 완벽하게 맞물려 돌아가야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;지금 당장 이직 버튼을 눌러야 할지 고민하고 계신 여러분께 조심스럽게 여쭤보고 싶습니다. 지금 여러분이 떠나고 싶은 그곳은 숨 막히는 현실을 피해 도망갈 '안락한 퇴로'인가요? 아니면 나의 역량을 가슴 벅차게 증명해 낼 치열한 '새로운 전쟁터'인가요? 이력서를 쓰기 전에 부디 며칠 만이라도 시간을 내어 자신이 다져온 기술의 뿌리와 태도의 궤적을 서늘하게 되짚어보시기를 권해드립니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;가장 초라한 내 부족함을 인정하는 그 아픈 순간이 역설적이게도 앞으로 맞이할 수많은 면접관들 앞에서 여러분을 가슴 활짝 펴고 도약하게 만들어 줄 강력한 무기가 될 것입니다. 오늘 비록 에러를 다 잡지 못해 속상했더라도, 묵묵히 전진하는 여러분의 눈부신 내일을 저 역시 뜨겁게 응원하겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;&lt;span style="color:#999999;"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>소프트웨어의 유튜브 모멘트: 이제 누구나 제품을 만든다</title><link>https://yozm.wishket.com/magazine/detail/3681</link><description>"개발자가 없어서 못 하고 있어요." 아이디어가 반짝이지만 개발자가 없어서 시작도 못 한 이야기를 한 번쯤 들어봤거나, 직접 해봤을 말입니다. 그런데 2025년을 기점으로 이 말은 변명이 되어가고 있습니다. 그런데 2025년을 기점으로 이 말은 변명이 되어가고 있습니다. a16z의 파트너 Anish Acharya는 지난 1월 이렇게 말했습니다. "소프트웨어의 유튜브 모멘트가 지금 일어나고 있다. 소프트웨어에도 같은 일이 벌어지고 있습니다. Cursor, Claude Code, Replit, Wabi 같은 AI 코딩 도구들이 그 장벽을 허물고 있기 때문입니다.</description><guid>https://yozm.wishket.com/magazine/detail/3681</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;"개발자가 없어서 못 하고 있어요."&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;아이디어가 반짝이지만 개발자가 없어서 시작도 못 한 이야기를 한 번쯤 들어봤거나, 직접 해봤을 말입니다. 아이디어는 있는데 개발 리소스가 없고, 외주를 맡기자니 비용이 너무 비싸고, 그렇다고 개발자를 뽑자니 초기 팀에 그런 여유가 없는 상황 말이죠. PM이나 기획자들이 수도 없이 부딪혀온 벽일 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 2025년을 기점으로 이 말은 변명이 되어가고 있습니다. a16z의 파트너 &lt;a href="https://www.a16z.news/p/softwares-youtube-moment-is-happening"&gt;Anish Acharya&lt;/a&gt;는 지난 1월 이렇게 말했습니다. "소프트웨어의 유튜브 모멘트가 지금 일어나고 있다. "YouTube가 2005년에 나왔을 때, 영상은 방송국과 전문 PD의 영역이었습니다. 장비, 편집, 배급 전부 진입 장벽이었죠. 그게 스마트폰 카메라 하나로 무너졌습니다. 지금은 유튜버가 지상파보다 영향력이 큰 게 당연한 세상이고요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3681/8ad2567a-2994-423e-ab16-d2efd42a3ef3_1196x544.webp"&gt;&lt;figcaption&gt;"이제 만들 때입니다. 이제 누구나 만들 수 있습니다." &amp;lt;출처: &lt;a href="https://www.a16z.news/p/softwares-youtube-moment-is-happening"&gt;a16z.news&lt;/a&gt;&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;소프트웨어에도 같은 일이 벌어지고 있습니다. Cursor, Claude Code, Replit, Wabi 같은 AI 코딩 도구들이 그 장벽을 허물고 있기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="text-align:justify;"&gt;&lt;strong&gt;미리 요점만 콕 집어보면?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li style="text-align:justify;"&gt;YouTube가 영상 창작의 문턱을 낮췄듯, AI 코딩 도구는 소프트웨어 제작의 문턱을 낮추고 있다. 이제 개발자가 없어도 서비스를 만들 수 있는 시대가 열리고 있다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;기획자, PM, 창업자에게 이 변화는 단순한 도구 변화가 아니다. 아이디어 검증 속도가 달라지고, 경쟁 구도가 바뀌고, 누가 시장에 진입할 수 있는지가 달라지는 비즈니스 지형의 변화다.&lt;/li&gt;&lt;li style="text-align:justify;"&gt;이 기회를 잡으려면 '어떻게 만들지'보다 '무엇을 만들지'를 판단하는 능력이 훨씬 더 중요해진다.&lt;/li&gt;&lt;/ul&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;유튜브가 이미 보여준 것&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3681/2.jpg"&gt;&lt;figcaption&gt;&amp;lt;출처: 픽사베이&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Acharya는 영상 창작의 역사를 세 단계로 나눕니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;첫 번째는 &lt;strong&gt;“Hollywood” 시대&lt;/strong&gt;입니다. 영화 한 편을 만들려면 수백만 달러의 제작비와 전문 스튜디오가 필요했습니다. 창작은 소수의 전문가 집단 손에 있었죠.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;두 번째는 &lt;strong&gt;“인디 감독” 시대&lt;/strong&gt;입니다. 1990년대 쿠엔틴 타란티노, 폴 토마스 앤더슨 같은 감독들이 저예산으로 영화를 만들기 시작했습니다. 장벽이 낮아졌지만, 여전히 전문성과 비용이 필요했습니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;세 번째가 &lt;strong&gt;“YouTube” 시대&lt;/strong&gt;입니다. 스마트폰 하나면 누구나 촬영하고, 편집하고, 전 세계에 배포할 수 있게 됐습니다. Mr. Beast는 방송국 없이도 수억 명의 구독자를 가진 크리에이터가 됐습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;소프트웨어도 정확히 같은 경로를 걷고 있습니다. 할리우드 시대에는 소프트웨어 하나 만들려면 대기업이거나 수억 원을 쏟아야 했습니다. 인디 시대에 Y Combinator 같은 스타트업 액셀러레이터(초기 스타트업에 투자와 멘토링을 해주는 프로그램)가 생기면서 Airbnb, Coinbase 같은 아웃사이더들이 끼어들기 시작했고요. &lt;strong&gt;지금은 AI 코딩 도구가 유튜브 역할&lt;/strong&gt;을 하고 있습니다. 코딩을 모르는 사람도 제품을 만들 수 있는 시대가 된 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;a16z가 소개한 사례들을 보면 과장이 아니라는 걸 알 수 있습니다. 누군가는 MRI 이미지를 시각화하는 대시보드를 직접 만들었는데, 의료 전문가들 반응이 "원래 상용 소프트웨어가 필요한 작업"이었다고 합니다. 라이브 방송하면서 실시간으로 앱을 짜는 사람도 있고, CLI 하나로 광고 캠페인 전체를 뚝딱 만들어내는 사람도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;몇 년 전만 해도 개발팀 없이는 꿈도 못 꿨을 일들입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;실제로 일어나고 있는 일들&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;실제로 비개발자가 앱을 만들 수 있느냐고요? 제 지인은 개발자가 아닙니다. 그런데 최근 Cursor와를 이용해서 간단한 데이터 분석 대시보드를 만들었습니다. 특정 키워드가 포함된 기사들을 모아서 날짜별 트렌드를 시각화하는 도구였는데, 예전 같았으면 개발자 친구한테 부탁하거나 몇백만 원짜리 외주를 줬어야 할 작업이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;걸린 시간은 반나절이었습니다. 물론 한계는 있습니다. 복잡한 로직이나 고도화된 기능은 여전히 개발자 손이 필요합니다. 하지만 아이디어를 검증하는 수준의 프로토타입이라면, 이제 개발 전공이 필수가 아닙니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;Replit의 CEO Amjad Masad는 "앞으로 10억 명이 소프트웨어를 만들 것"이라고 했습니다. 과장 같죠. 그런데 YouTube가 처음 나왔을 때 "수억 명이 영상 크리에이터가 된다"는 말도 똑같이 허풍처럼 들렸습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;한국에서도 조짐이 보입니다. 국내 스타트업에서는 PM이 직접 프로토타입을 만들어 사용자 인터뷰를 돌리거나, 마케터가 데이터 분석 도구를 직접 만드는 사례가 늘고 있습니다. 개발자를 기다릴 필요 없이, 아이디어가 떠오른 그날 바로 테스트해 볼 수 있게 된 거죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;서비스를 만드는 사람들에게 생긴 실질적인 변화&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3681/3.jpg"&gt;&lt;figcaption&gt;&amp;lt;출처: 픽사베이&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 변화가 기획자, PM, 창업자에게 구체적으로 뭘 의미할까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;첫째, 아이디어 검증 주기의 변화&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;기존 개발 사이클을 떠올려보세요. 아이디어 → 기획 → 개발 의뢰 → 개발 완료 → 테스트 → 수정 요청 → 재개발까지, 짧으면 몇 주, 길면 몇 달. 그 사이에 시장이 바뀌기도 합니다. 막상 만들어놓고 보니, 사용자가 원하는 게 전혀 다른 거였다는 걸 뒤늦게 알게 되기도 했죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이제는 아이디어가 생기면 그날 바로 클릭 가능한 프로토타입을 만들 수 있습니다. 사용자한테 보여주고, 피드백 받고, 다음 날 고치면 됩니다. "최소한의 제품을 빠르게 만들고 사용자 반응을 보면서 방향을 잡자"는 린 스타트업 방법론, 그동안 이상에 가까웠던 "빠른 실험과 검증"이 이제야 현실이 된 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;둘째, 사라진 프로토타이핑 비용&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;예전에는 기능 하나 검증하려 해도 개발팀에 의뢰를 넣어야 했습니다. 개발팀 시간은 한정돼 있으니, "아직 검증 안 됐으니 보류"로 묻히는 아이디어가 수두룩했죠. 이제 프로토타입 만드는 비용이 거의 0입니다. 그만큼 더 많은 아이디어를 실험해 볼 수 있고, 많이 실험할수록 좋은 서비스가 나올 확률도 올라갑니다. 성공 방정식 자체가 달라진 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;셋째, 개발자와의 협업 방식이 바뀐다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;기획하는 사람과 개발하는 사람 사이에는 늘 번역의 문제가 있었습니다. 한쪽은 사용자 경험을 이야기하고, 한쪽은 기술적 제약을 이야기하고. 같은 서비스를 만들면서 서로 다른 언어로 대화하는 느낌이었죠. AI 코딩 도구가 이 간극을 줄여줄 수 있습니다. 기획자가 직접 프로토타입을 만들어서 "이런 느낌인데, 여기서 기술적으로 뭐가 어려워?"라고 물어볼 수 있게 되니까요. 말로 설명하던 걸 직접 보여주면서 대화하는 거라, 협업의 질이 확 달라집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;비즈니스 관점에서 보면 어떨까요?&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;기회: 새로운 시장이 열린다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Acharya 말대로, 소프트웨어에 관심도 없던 사람들이 직접 만들기 시작했습니다. 교사가 자기 수업에 딱 맞는 학습 도구를 만들고, 의사가 자기 진료 방식에 맞는 기록 시스템을 만들고, 요리사가 레시피 관리 앱을 만듭니다. 개발자들이 "이런 게 왜 필요해?"라고 넘겼던 문제들을 이제 비개발자들이 직접 코딩를 하기 시작한 것이죠. 여기서 기존에 없던 서비스들이 나올 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;기회: 소프트웨어는 콘텐츠와 다르다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;Acharya는 이렇게 말합니다. 콘텐츠는 올리는 순간부터 가치가 떨어집니다. 조회수 찍고 내려가죠. 반면 소프트웨어는 사용자가 쌓일수록 가치가 올라갑니다. 한번 잘 만들어놓으면 사용자가 늘고, 데이터가 쌓이고, 서비스가 좋아지는 선순환이 생깁니다. 개발 비용이 거의 0이 된 지금, 이 복리 효과를 누릴 수 있는 사람이 훨씬 많아진 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;위협: 나만 쉬운 게 아니다&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;기회가 있으면 위협도 있습니다. 나만 쉽게 만들 수 있는 게 아니라, 경쟁자도 쉽게 만들 수 있습니다. 내 제품과 비슷한 걸 누군가가 하루 만에 만들어서 무료로 뿌릴 수도 있는 거죠. 덕분에 비슷한 형식의 스마트폰 게임이 수백 개가 출시되고 있는 것처럼 말이죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;a16z 글의 댓글에는 더 날카로운 지적도 있었습니다. "이런 작은 도구들은 결국 Claude나 ChatGPT 같은 대형 모델이 기능을 흡수해버리면 살아남기 어렵다. 도구를 만들게 해준 플랫폼이 곧 경쟁자가 되는 셈이다." 그러니까 이제는 "만들 수 있다"는 것만으로는 부족합니다. 누구를 위해, 어떤 문제를 풀고 있는지가 진짜 경쟁력이 되는 시대입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;위협: '만들 수 있다'와 '잘 만들었다'의 차이&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;YouTube가 나온 후 수억 개의 영상이 올라왔지만, 그중에서 실제로 사람들에게 가치를 주는 콘텐츠는 소수였습니다. 소프트웨어도 마찬가지일 겁니다. 누구나 만들 수 있게 되면, 오히려 "잘 만든 것"의 기준이 높아집니다. 사용자 경험, 제품 감각, 문제에 대한 깊은 이해 등 이런 것들이 더 중요해집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;지금부터 준비해야 할 것은?&lt;/strong&gt;&lt;/h3&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3681/4.png"&gt;&lt;figcaption&gt;&amp;lt;출처: Claude Code, 터미널 화면 캡처&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그렇다면 이 변화 앞에서 우리는 뭘 해야 할까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;첫째, AI 코딩 도구를 직접 써보세요.&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이론으로 이해하는 것과 직접 써보는 것은 완전히 다릅니다. Cursor, Claude, v0(Vercel의 UI 생성 도구), Replit 중 하나를 골라서 본인이 평소에 "있으면 좋겠다"고 생각했던 간단한 도구를 직접 만들어보세요. 처음에는 느리고 답답하겠지만, 이 경험 자체가 엄청난 인사이트를 줍니다. 어디까지 가능한지, 어디서 막히는지, 어떤 도구가 어떤 작업에 맞는지가 보이기 시작합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;못 만든다고 생각했던 것들이 가능하다는 걸 느끼는 순간, 아이디어를 보는 눈이 달라집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;둘째, 빠른 검증을 팀의 문화로 만드세요.&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;AI 코딩 도구가 주는 가장 큰 선물은 속도입니다. 그런데 도구만 빨라져서는 소용이 없습니다. 팀이 그 속도에 맞춰 움직여야 합니다. 완벽한 기획서를 기다리는 대신, 대충이라도 만들어서 사용자한테 보여주고 반응을 보는 거죠. 회의실에서 "이거 될까요?" 논쟁하는 시간에 그냥 뚝딱 만들어서 돌려보는 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;셋째, '무엇을 만들 것인가'에 고민해 보세요.&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;아이러니하게도, 만드는 게 쉬워질수록 "뭘 만들지"가 더 중요해집니다. 누구나 만들 수 있으니까, 잘 만드는 건 더 이상 차별점이 아닙니다. 진짜 경쟁력은 풀어야 할 문제를 찾아내는 눈입니다. 사용자가 뭘 불편해하는지, 시장에 어떤 빈틈이 있는지, 이 문제가 정말 돈을 내고 해결할 만한 건지. 이건 아무리 AI가 좋아져도 대신 못 해주는 영역입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;유튜브도 마찬가지였습니다. 카메라를 잘 다루는 사람이 성공한 게 아니라, "이런 영상이 뜨겠지?"라고, 먼저 생각한 사람이 성공했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;넷째, AI 도구를 팀 전체가 쓸 수 있게 환경을 만드세요.&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;개발팀만 AI를 쓸 이유가 없습니다. PM, 디자이너, 마케터 모두 각자 맡은 영역에서 AI 도구를 쓸 수 있어야 합니다. 간단한 가이드라인을 만들어두고, 누가 어떻게 쓰고 있는지 공유하는 자리를 만들어보세요. 한 팀원이 AI로 분석 시간을 반으로 줄였다면, 그걸 혼자 알고 있을 이유가 없습니다. 이런 변화를 개인이 아닌 팀이 함께 움직여야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;변명이 사라진 시대의 ‘진짜 경쟁력’&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;소프트웨어의 유튜브 모멘트가 왔다는 말은, 단순히 "이제 코딩 안 해도 된다"는 뜻이 아닙니다. 더 많은 사람들이 더 빠르게 더 많은 것을 만들 수 있게 됐다는 뜻이고, 그 말은 경쟁의 기준선 자체가 올라간다는 의미입니다. 유튜브가 서비스를 시작했을 때, 결국 살아남은 건 "누구나 만들 수 있으니 끝났다"고 겁먹은 사람이 아니라, 자기만의 관점과 이야기를 가진 사람이었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;서비스를 만드는 사람들도 마찬가지입니다. "개발자가 없어서 못 만든다"는 말이 더 이상 안 통하는 시대에, 진짜 경쟁력은 뭘 만들지 아는 것, 누구를 위해 만드는지 아는 것, 그리고 빠르게 실험하고 배우는 것입니다.&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;도구의 문턱은 낮아졌습니다. 이제 남은 건 아이디어와 실행, 그리고 그걸 해볼 용기뿐입니다.&lt;/p&gt;&lt;hr&gt;&lt;p style="text-align:justify;"&gt;&amp;lt;참고&amp;gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;[a16z] &lt;a href="https://www.a16z.news/p/softwares-youtube-moment-is-happening"&gt;&lt;u&gt;Software's YouTube moment is happening now&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;[inference] &lt;a href="https://inferencebysequoia.substack.com/p/replit-ceo-amjad-masad-on-1-billion-173"&gt;&lt;u&gt;Replit CEO Amjad Masad on 1 Billion Developers: A Better End State than AGI&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:center;"&gt;&lt;span style="color:#999999;"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item><item><title>누구도 알려주지 않는 AWS 보안의 첫 번째 원칙</title><link>https://yozm.wishket.com/magazine/detail/3679</link><description>흠뻑 젖은 채로 리조트 방 앞에 서서야 깨달았습니다. “아, 방에서 키 안 가지고 나왔다….” 호텔이나 리조트에 놀러 다니다 보면 쉽게 이런 상황을 마주하기도 합니다. 만약 잃어버린 것이 호텔 키가 아니라 개인이나 회사의 클라우드 인프라 열쇠였다면 어떨까요? 누군가 내 클라우드 계정에 접근해 고객들의 개인정보를 탈취하고, 심지어 서비스까지 중단시킬 수도 있습니다. 위시켓 클라우드팀에서 업무상 수많은 AWS 계정을 관리하는 제게, 이러한 사건은 남의 이야기가 아닙니다. 그런 경험을 바탕으로 클라우드 보안에서 가장 흔하면서도 가장 위험한 실수 하나에 관해 설명해 보려고 합니다.</description><guid>https://yozm.wishket.com/magazine/detail/3679</guid><content:encoded>&lt;![CDATA[&lt;b&gt;&lt;p style="text-align:justify;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;&lt;i&gt;이 글은 위시켓과 함께 요즘IT 브랜디드 콘텐츠로 제작했습니다.&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;흠뻑 젖은 채로 리조트 방 앞에 서서야 깨달았습니다. “아, 방에서 키 안 가지고 나왔다….” 수영장에 다녀오며 카드키를 방에서 안 가지고 나왔던 겁니다. 결국 수영복 차림으로 떨며, 멀리 떨어진 프론트 데스크까지 걸어가서 새 키를 받으러 갔습니다. 지난 겨울 휴가 때 제 이야기입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;호텔이나 리조트에 놀러 다니다 보면 쉽게 이런 상황을 마주하기도 합니다. 평소 결제와 신분증 확인을 모두 휴대폰으로 해결하다 보니, 지갑 없이 폰 하나로 다니는 데 익숙하기 때문입니다. 호텔 카드키를 따로 챙기는 일은 꽤 번거롭게 느껴졌고, 때로는 방에 두고 나오거나 심지어 밖에서 잃어버리고 오는 일도 있었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;밖에서 놀다가 호텔 키를 잃어버리면 어떻게 될까요? 카드키를 받을 때는 호텔 측에서 작은 종이 케이스에 방 번호를 적어 주기도 하는데요, 이 경우 누구나 제 호텔 방에 들어올 수 있게 됩니다. 만약 그 열쇠를 잃어버린 사실조차 모른 채 방을 방치해 둔다면 어떨까요? 방에 있던 짐은 그대로 도난당하고, 파손된 가구나 전자제품에 대해 호텔 측에 변상해야 할 수도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3679/image8.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Gemini로 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그런데 만약 잃어버린 것이 호텔 키가 아니라 개인이나 회사의 클라우드 인프라 열쇠였다면 어떨까요? 마찬가지로 누군가 내 클라우드 계정에 접근해 고객들의 개인정보를 탈취하고, 심지어 서비스까지 중단시킬 수도 있습니다. 실제로 &lt;a href="https://www.theregister.com/2014/06/18/code_spaces_destroyed/"&gt;&lt;u&gt;2014년&lt;/u&gt;&lt;/a&gt;, 한 기업은 클라우드 열쇠를 탈취당해 모든 데이터와 백업이 삭제되었고, 회사는 영구 폐업했다고 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;위시켓 클라우드팀에서 업무상 수많은 AWS 계정을 관리하는 제게, 이러한 사건은 남의 이야기가 아닙니다. 그런 경험을 바탕으로 클라우드 보안에서 가장 흔하면서도 가장 위험한 실수 하나에 관해 설명해 보려고 합니다.&lt;/p&gt;&lt;div class="page-break" style="page-break-after:always;"&gt;&lt;span style="display:none;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;클라우드의 두 가지 자격 증명&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;요즘 메리어트나 IHG 같은 호텔 체인에서는 모바일 키를 지원합니다. 이런 모바일 키가 있었다면 카드키를 두고 나와도 당황하는 일은 없었을 것입니다. 또, 카드키를 잃어버리더라도 제 얼굴 인증 없이는 모바일 키를 사용할 수 없을 겁니다. &lt;span style="color:#757575;"&gt;(실제로 메리어트 본보이 앱은 모바일 카드키 사용 시 페이스 아이디를 요구합니다.)&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;클라우드에서도 이처럼 전통적인 키와 모바일 키처럼 두 가지 인증 방식이 존재합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;첫 번째 증명: 카드 키 방식&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;우리는 호텔에 도착하면 보통 프론트 데스크에서 카드키를 받습니다. 서울의 호텔, 도쿄의 호텔, 뉴욕의 호텔 모두 호텔마다 프론트에서 각각 다른 카드키를 받아야 합니다. 만약 잃어버린다면 어떨까요? 누군가 주워 제 방에 들어갈 수도 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AWS의 인증 열쇠를 잃어버리면, 호텔 열쇠와는 비교할 수 없을 만큼 심각한 문제가 발생할 수 있습니다. 특히, 호텔의 카드키는 최소한 체크아웃 날짜가 지나면 만료됩니다. &lt;span style="color:#757575;"&gt;(그래서 일부 호텔에서는 카드키를 기념으로 가져가게 해주기도 합니다.)&lt;/span&gt; 반면 AWS의 장기 자격 증명인 IAM 접근 키는 마치 쇠로 된 열쇠와 같습니다. 누군가 직접 문에 달린 자물쇠를 바꾸지 않는 한 꾸준히 작동합니다. 게다가 쇠 열쇠보다 복제하기도 쉽습니다. 두 줄의 문자열을 복사해 붙여넣기만 하면 되기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;두 번째 증명: 모바일 키 방식&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;반면 모바일 키는 조금 다릅니다. 예를 들어 메리어트 호텔의 모바일 키는 본사에서 중앙 관리됩니다. 하나의 메리어트 계정만 있으면 호텔 지점과 관계없이 어디서든 체크인하고 모바일 키로 객실 문을 열 수 있도록요. 심지어 동시에 예약한 호텔이 두 곳이라면, 하나의 휴대폰으로 두 객실을 모두 열 수도 있습니다. 또, 제 휴대폰이기 때문에 얼굴과 같은 생체 정보 없이는 사용할 수 없습니다. 여기에 체크아웃 이후에는 별도의 관리가 필요하지 않습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AWS에서도 마찬가지입니다. 저는 하루에도 여러 번 AWS 계정을 오가며 작업하는데, 로그인할 때마다 각 계정의 아이디와 비밀번호를 모두 알아야 한다면 매우 번거로운 일이 될 것입니다. 그래서 모바일 키 방식을 적극 사용합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;장기 기억 증명 vs. 단기 자격 증명&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AWS에서는 이 두 가지를 다음과 같이 구분합니다. 카드키, 마치 호텔의 쇠 열쇠 같은 방식은 &lt;strong&gt;장기 자격 증명&lt;/strong&gt;&lt;span style="color:#757575;"&gt;(long-term credential)&lt;/span&gt;이라고 부릅니다. 반면 모바일 키와 같은 방식은 &lt;strong&gt;단기 자격 증명&lt;/strong&gt;&lt;span style="color:#757575;"&gt;(short-term credential)&lt;/span&gt;이라고 합니다. 한 번 만들어지면 열쇠구멍이 바뀌지 않는 한 쓸 수 있는 쇠 열쇠와 달리, 모바일 키는 사용할 때마다 제 생체 인증이 필요하기 때문입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;장기 자격 증명의 대표적인 예는 AWS IAM&lt;span style="color:#757575;"&gt;(Identity and Access Management)&lt;/span&gt;의 &lt;strong&gt;접근 키&lt;/strong&gt;&lt;span style="color:#757575;"&gt;(Access Key)&lt;/span&gt;입니다. 이 접근 키는 두 줄의 문자열로 이루어져 있습니다. 한 번 생성되면 그 자체로는 만료되지 않는 특징도 가집니다. 또한 문자열 형태이기 때문에 누구에게나 복사해 전달할 수 있습니다. 카카오톡으로 주고받거나, 코드에 들어간 채 클라우드나 깃허브와 같은 원격 저장소에 업로드될 수도 있습니다. 이처럼 발급된 키를 삭제하려면 해당 계정에서 직접 삭제해야 합니다. 호텔마다 프론트 데스크에서 카드키를 따로 발급하듯, 각 AWS 계정에서 개별적으로 생성하고 관리합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반면 단기 자격 증명은 &lt;strong&gt;IAM 자격 증명 센터&lt;/strong&gt;&lt;span style="color:#757575;"&gt;(IAM Identity Center)&lt;/span&gt;&lt;strong&gt;를 통해 발급&lt;/strong&gt;됩니다. 호텔 체인 본사가 앱을 통해 키를 관리하듯, AWS 조직&lt;span style="color:#757575;"&gt;(AWS Organization, 여러 계정을 하나로 묶어 관리하는 단위)&lt;/span&gt;의 관리 계정에서 중앙으로 관리됩니다. 하나의 사용자로 여러 AWS 계정에 접근할 수 있다는 점도 특징입니다. 로그인할 때는 다단계 인증&lt;span style="color:#757575;"&gt;(Multi-Factor Authentication, MFA)&lt;/span&gt;을 거쳐야 하며, 인증이 완료되면 임시 토큰이 발급됩니다. 이 토큰은 사전에 설정된 일정 시간이 지나면 만료되고, 로그인할 때마다 새로 발급됩니다. 만료 이후에는 별도로 신경 쓸 필요가 없습니다. 알아서 사라지니까요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3679/image2.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude로 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3679/image1.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;AWS 접근 키를 잃어버리면, 어떤 사고가 날까요?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;AWS 접근 키를 잃어버리면 어떻게 될까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이 열쇠에는 만료일이 없고, 복제도 매우 쉽습니다. 사실 키 값이 그리 길지도 않아 마음만 먹으면 외울 수도 있는 수준입니다. 누가 복사했는지, 복사본이 몇 개나 존재하는지도 알 수 없습니다. 누군가 자물쇠를 바꾸기 전까지 그 열쇠의 복사본을 가진 누구든 언제든 문을 열 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;키 유출이 악용으로 이어진 시간&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;이에 대한 &lt;a href="https://www.comparitech.com/blog/information-security/github-honeypot/"&gt;&lt;u&gt;실험&lt;/u&gt;&lt;/a&gt;이 있습니다. 보안 연구팀 Comparitech는 AWS 자격 증명을 공개 깃허브 리포지토리에 일부러 올려두었습니다. 결과는 충격적이었습니다. 첫 번째 악용이 1분 이내에 발생했습니다. 1분입니다. 음료수 한 모금 마시기도 전에, 누군가 그 열쇠로 문을 열고 들어온 셈입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;이건 우연이 아닙니다. 팔로알토 네트워크의 Unit 42 팀이 추적한 &lt;a href="https://unit42.paloaltonetworks.com/malicious-operations-of-exposed-iam-keys-cryptojacking/"&gt;&lt;u&gt;EleKtra-Leak 캠페인&lt;/u&gt;&lt;/a&gt;에 따르면, 공격자들은 깃허브에 노출된 AWS 자격 증명을 자동으로 스캔하고 있었습니다. 키가 노출되면 평균 5분 이내에 악용이 시작됐고, 탈취한 키로 수백 대의 EC2 인스턴스를 생성해 암호화폐를 채굴했습니다. 이 캠페인은 2020년부터 최소 3년간 지속되었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;우버 역시 비슷한 &lt;a href="https://www.breaches.cloud/incidents/uber/"&gt;&lt;u&gt;사례&lt;/u&gt;&lt;/a&gt;를 겪었습니다. 2013년에 생성된 다음, 한 번도 교체되지 않은 접근 키가 깃허브 리포지토리에서 발견됐고, 곧바로 5,700만 건의 고객 데이터가 유출되었습니다. 이어 1억 4,800만 달러의 벌금이 부과되었고, 보안 책임자(CISO)는 형사 유죄 판결을 받았습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;키 유출을 알아챌 때까지 걸리는 시간&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;그렇다면 규모는 어느 정도일까요? &lt;a href="https://www.gitguardian.com/state-of-secrets-sprawl-report-2025"&gt;&lt;u&gt;깃가디언&lt;/u&gt;&lt;/a&gt;의 2025년 보고서에 따르면, 2024년 한 해 동안 공개 깃허브에서 유출된 암호 키는 2,380만 개에 달합니다. 이는 전년 대비 25% 증가한 수치입니다. 더 무서운 점은, &lt;strong&gt;2022년에 유출된 키의 70%가 2025년에도 여전히 유효하다는 사실&lt;/strong&gt;입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3679/image4.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude로 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그러니까 이들은 열쇠가 탈취되었는데도 자물쇠를 바꾸지 않은 것입니다. 무려 3년 동안이나요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;왜 바꾸지 않았을까요? 정확히는, 바꾸지 못했을 겁니다. 유출 사실을 몰라 바꾸지 않았을 수도 있고, 혹은 그 과정에서 기존에 정상적으로 작동하던 서비스에 영향을 줄까 걱정했을 수도 있습니다. 호텔에 비유하면, 객실 문고리를 전부 교체하는 바람에 기존 열쇠를 가진 직원들이 객실 청소를 못하게 되는 상황과 비슷합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그렇다면 모바일 키, 즉 단기 자격 증명이 유출된다면 어떨까요? 애초에 임시 토큰은 복사나 공유를 전제로 만들어진 값이 아닙니다. 또한 다단계 인증을 거쳐 발급되기 때문에 이를 굳이 복사해 전달할 상황 자체가 많지 않습니다. 즉, 유출 경로 자체가 상대적으로 적습니다. 설령 유출되더라도 이 키는 수 시간 내에 자동으로 만료됩니다. 체크아웃 이후의 키카드처럼, 만료된 토큰은 의미 없는 문자열에 불과합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;그래도 감시 카메라(CloudTrail)가 있지 않나요?&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;호텔에 CCTV가 있듯, AWS에는 클라우드트레일&lt;span style="color:#757575;"&gt;(CloudTrail)&lt;/span&gt;이라는 서비스가 있습니다. 누가 언제 어떤 작업을 했는지, 모든 API 호출을 기록하는 서비스입니다. 장기 자격 증명이든 단기 자격 증명이든, 예외 없이 모두 기록됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3679/image5_BD9XkHd.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;문제는 기록이 남는 것과 범인을 특정하는 것은 별개의 문제라는 점입니다. 모바일 키 방식, 즉 IAM 자격 증명 센터를 통한 접근은 기록이 비교적 명확합니다. “김승빈이 오후 2시 13분에 서울 호텔 503호에 들어갔다”처럼, 사용자 누구가 무슨 계정에서 어떤 작업을 했는지 신원을 특정할 수 있습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:50%;"&gt;&lt;img src="https://www.wishket.com/media/news/3679/image7.png"&gt;&lt;figcaption&gt;실제 위시켓에서 활용중인 추척 봇 &amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;반면 접근 키를 사용하면 기록에는 키 ID만 남습니다. 해당 키를 원래 주인이 사용한 것인지, 복사본을 가진 누군가가 사용한 것인지 구분할 수 없다는 뜻입니다. CCTV에 정문으로 자연스럽게 들어오는 사람이 찍혔지만, 그 사람이 실제 투숙객인지 열쇠를 주운 사람인지 알 수 없는 상황과 같습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;즉, 감시 카메라가 존재하더라도 범인이 정당한 열쇠를 들고 정문으로 들어온다면 이를 의심하기는 어렵습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;게다가 클라우드트레일에는 또 하나의 치명적인 한계가 있습니다. 기본 설정에서는 녹화 기록이 90일만 보관되며, 기간이 지나면 로그는 자동으로 삭제된다는 겁니다. 더 오래 보관하려면 별도의 저장소를 직접 설정해야 합니다. 클라우드트레일의 존재 자체를 모르는 경우도 적지 않고, 알고 있더라도 사건이 발생한 이후에야 CCTV를 돌려보듯 로그를 확인하는 경우가 비일비재합니다. 심지어 필요한 로그를 제대로 찾지 못하는 상황도 흔하죠.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;따라서 실시간으로 이상 징후를 탐지하는 체계가 무엇보다 중요합니다. AWS에는 이러한 감지기 역할을 하는 다양한 서비스가 있기 때문에, 상황에 맞게 활용하면 보다 선제적으로 계정을 보호할 수 있습니다. &lt;span style="color:#757575;"&gt;(더 자세한 내용은, 글이 호응을 얻는다면 후속 편에서 준비해 보겠습니다.)&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3679/image3.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가, Claude로 제작&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마스터 키인 루트 사용자(Root User) 관리하기&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;지금까지 이야기한 접근 키는 호텔 객실 하나를 열어주는 열쇠에 비유할 수 있습니다. 그런데 이 호텔에는 &lt;strong&gt;마스터 키&lt;/strong&gt;가 존재한다면 어떨까요?&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AWS 계정에는 루트 계정 사용자(Root Account User)라는 특별한 사용자가 있습니다. 계정을 처음 생성할 때 만들어지는 이 사용자는 해당 계정 내 모든 리소스에 접근할 수 있습니다. 서버를 생성하거나 삭제하는 것은 물론이고, 다른 IAM 사용자를 만들고 권한을 변경하거나, 심지어 계정 자체를 폐쇄하는 것까지 합니다. 호텔 체인 전체를 열 수 있는 마스터 키와 같은 존재입니다. 어떤 객실이든, 어떤 금고든 열 수 있는 열쇠입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;일반 사용자&lt;span style="color:#757575;"&gt;(IAM User)&lt;/span&gt;의 권한을 아무리 잘 설정해두더라도, 루트 계정 사용자가 탈취되면 모든 보안은 무력화됩니다. 공격자가 이 마스터 키를 손에 넣는 순간, 다른 열쇠로는 대응할 방법이 사실상 사라집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;Root User의 두 가지 자격 증명&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;이 루트 계정 사용자 역시 IAM 사용자와 마찬가지로 두 가지 자격 증명을 가집니다. 하나는 이메일 주소와 비밀번호로, AWS 콘솔(웹사이트)에 로그인할 때 사용합니다. 다른 하나는 접근 키로, 앞서 설명한 것과 동일한 두 줄의 문자열입니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;AWS 공식 문서는 이 두 가지 모두에 대해 강하게 &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/root-user-best-practices.html"&gt;&lt;u&gt;경고&lt;/u&gt;&lt;/a&gt;합니다. 콘솔 로그인에 대해서는 “루트 계정 사용자가 필요한 작업이 아니면 사용하지 마세요”라고 안내하며, 접근 키에 대해서는 아예 “생성하지 마세요”라고 명시합니다. 그러나 아이러니하게도 접근 키를 생성하는 버튼은 콘솔에 버젓이 존재합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;부주의하게 만약 이 마스터 키를 유출했다면 어떻게 될까요? 글의 서두에서 잠깐 언급했던 코드 스페이스 사건이 바로 그 사례입니다. 2014년, 공격자는 루트 계정을 얻어 코드 스페이스의 AWS 콘솔 접근 권한을 탈취했습니다. 회사가 대응을 시도하자 공격자는 서버와 저장소, 백업 등 복구 가능한 모든 리소스를 삭제해버렸습니다. 결국 코드 스페이스는 영구적으로 폐업했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;모바일 키로 바꿔라&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;지금까지의 이야기를 정리하면 이렇습니다. 쇠 열쇠(IAM 접근 키)는 만료되지 않고, 복제가 쉽고, 누가 사용하는지 구별하기 어렵습니다. 한 번 유출되면 회수도 거의 불가능합니다. 여기에 마스터 키(루트 계정 사용자)까지 유출된다면, 사실상 대응 자체가 불가능해집니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;물론 열쇠를 잃어버려 나오는 이 머리 아픈 상황에 대한 해법은 이미 정해져 있습니다. 모바일 키로 바꾸는 겁니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;AWS도 권장하는 해법&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;IAM 자격 증명 센터는 AWS가 제공하는 모바일 키 시스템입니다. 이 시스템은 AWS 조직 관리 계정에서 모든 멤버 계정의 사용자와 권한을 통합 관리합니다. 로그인할 때마다 MFA를 거쳐야 하고, 인증이 완료되면 임시 토큰이 발급됩니다. 이 토큰은 일정 시간이 지나면 자동으로 만료됩니다. 또, 그렇기에 누가 어떤 계정에서 어떤 작업을 했는지 기록도 명확하게 남습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3679/image6.png"&gt;&lt;figcaption&gt;&amp;lt;출처: 작가&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;사실 이 개념은 새로 등장한 규정은 아닙니다. AWS는 2017년 AWS SSO라는 이름으로 이 서비스를 처음 출시했고, 2022년 IAM 자격 증명 센터로 이름을 변경하며 공식 권장 방식으로 자리 잡았습니다. 이어 2025년에는 공식 블로그에서 “&lt;a href="https://aws.amazon.com/blogs/security/beyond-iam-access-keys-modern-authentication-approaches-for-aws/"&gt;&lt;u&gt;장기 IAM 접근 키를 넘어서라&lt;/u&gt;&lt;/a&gt;”는 제목의 글까지 발행했습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그럼에도 불구하고 많은 개발자가 여러 이유로 IAM 사용자와 접근 키를 씁니다. 아주 큰 글씨로 경고가 적힌 공식 문서를 충분히 읽지 못했을 수도 있고, 코딩 에이전트가 생성한 설정을 의심없이 신뢰했을 수도 있습니다. 또는 문제를 알면서도 관성적으로 기존 방식을 고수했을 지도 모릅니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서일까요? 접근 키를 코드에 포함한 채 깃허브에 올렸다는 이야기를 개발자라면 한 번쯤은 들어봤을 겁니다. 그렇게 여전히 2024년 한 해에만 2,380만 개의 암호 키가 유출되었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 style="text-align:justify;"&gt;&lt;strong&gt;보안 시스템을 직접 구축하기 어렵다면?&lt;/strong&gt;&lt;/h4&gt;&lt;p style="text-align:justify;"&gt;문제는 현실은 녹록지 않다는 겁니다. AWS 조직을 구성하고, IAM 자격 증명 센터를 설정하며, 사용자와 권한을 관리하고, 클라우드트레일 로그를 별도 저장소에 백업하는 일까지, 이 모든 과정을 직접 수행하려면 AWS 보안에 대한 전문 지식이 필요합니다. “개발자라면 이런 것쯤은 다 알지 않을까?”라고 생각할 수도 있습니다. 하지만 병원에서 수술을 받을 때도 외과 의사와 마취과 의사가 각자의 역할을 맡듯, DevSecOps나 클라우드 전문가 없이 이를 구축하는 일은 쉽지 않습니다. 중요한 보안 관련 일을 AI 모두에게 맡기는 것도 찝찝하고요.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;특히 직접 개발을 하지 않고 외주 개발사에 맡기는 경우도 마찬가지입니다. 개발 과정에서 외주 개발사가 접근 키를 실수로라도 유출하지 않았다고 확신할 수 있을까요? 임시 자격 증명 운용이 번거롭다는 이유로, 두 줄짜리 문자열을 복사해 여러 곳에서 사용하고 있을 가능성도 있습니다. 또한 AWS에 대한 기초 지식이 부족하다면, 외주 개발이 끝난 다음 불필요한 사용자나 접근 키가 모두 정리되었는지 확인하기도 어렵습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;사실 그래서 저는 위시켓에서 이런 일을 대신합니다. &lt;a href="https://www.wishket.com/vault/"&gt;&lt;u&gt;안심 호스팅 서비스&lt;/u&gt;&lt;/a&gt;라는 것을 운영하며 AWS 계정 생성부터 IAM 자격 증명 센터 사용자 생성, 권한 관리를 고객을 대신해 설정하고 운영합니다. 불필요한 리전에서의 서버 생성을 차단하고, 클라우드트레일 로그를 삭제하는 행위도 막습니다. 또한 보안에 취약한 IAM 사용자나 접근 키 생성 자체를 원천적으로 제한합니다. 정책은 누구든 예외 없이 적용됩니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class="image image_resized" style="width:100%;"&gt;&lt;img src="https://www.wishket.com/media/news/3679/wishket_vault.png"&gt;&lt;figcaption&gt;위시켓 안심 호스팅 서비스 &amp;lt;출처: 위시켓&amp;gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 style="text-align:justify;"&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h3&gt;&lt;p style="text-align:justify;"&gt;물론 서비스 홍보도 홍보지만, 저희한테 맡기지 않더라도 모바일 키로의 전환은 꼭 검토했으면 합니다. 위시켓 클라우드팀에서 근무하다 보니, 탈취된 자격 증명으로 뭄바이나 스톡홀름과 같은 예상치 못한 리전에 서버가 만들어지고, 암호화폐 채굴에 악용되는 사례를 직접 목격한 적도 있습니다. 보안 규칙을 매일 고민하고 다루는 입장에서 가장 쉬운 일을 두고 큰 피해를 입는 고객사를 보며, 그 지식을 전하고 싶었습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;그래서 다시 한 번 강조하려고 합니다. 애초에 열쇠를 만들지 않는다면 잃어버릴 열쇠도 존재하지 않습니다. AWS 스스로가 말하듯 쇠 열쇠를 내려놓고, 모바일 키로 바꿔야 합니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="text-align:justify;"&gt;기회가 된다면, IAM 자격 증명 센터의 기술적인 부분을 더 깊이 다뤄볼 예정입니다. 실제로 모바일 키를 어떻게 설정하고, 어떤 구조로 동작할지, 그 내부 구조를 열어보겠습니다.&lt;/p&gt;&lt;p style="text-align:justify;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin-left:0px;text-align:center;"&gt;&lt;span style="color:rgb(153,153,153);"&gt;©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.&lt;/span&gt;&lt;/p&gt;&lt;/b&gt;]]&gt;</content:encoded></item></channel></rss>