<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Fall in IT.</title>
    <link>https://ithub.tistory.com/</link>
    <description>먼저 되게 만들고, 잘되게 만들고, 빠르게 만들자</description>
    <language>ko</language>
    <pubDate>Sun, 26 Jul 2026 01:26:26 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>D.Y</managingEditor>
    <image>
      <title>Fall in IT.</title>
      <url>https://t1.daumcdn.net/cfile/tistory/2106814B58CFB49436</url>
      <link>https://ithub.tistory.com</link>
    </image>
    <item>
      <title>Hermes Agent 왜 핫하고, 뭐가 다른가</title>
      <link>https://ithub.tistory.com/453</link>
      <description>&lt;h1&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;사람들은 왜 Hermes와 OpenClaw를 쓰는 걸까. 직접 설치해보고 나서야, 이게 전혀 다른 문제를 푸는 도구라는 걸 알게 됐다.&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;아주 가볍게, Hermes에 대해서 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 왜 실습했는가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실습 동기는 세 가지였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, &lt;b&gt;&quot;왜 핫한가&quot;&lt;/b&gt;를 직접 확인하고 싶었다. 커뮤니티에서 OpenClaw와 Hermes가 계속 언급되는데, 실제로 써보지 않고 논평하는 건 의미가 없다고 판단했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, &lt;b&gt;&quot;Opus면 충분한데 왜 다들 이쪽으로 가는가&quot;&lt;/b&gt; 를 이해하고 싶었다. Claude Code + Opus 조합으로 코딩할 때 병목을 느껴본 적이 없었기 때문에, 이 도구들이 어떤 다른 문제를 푸는지가 궁금했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셋째, &lt;b&gt;파운데이션 모델과 에이전트 프레임워크를 직접 분리해서 조합해보고 싶었다&lt;/b&gt;. 완제품인 Claude Code를 쓰는 것과, 모델을 선택하고 에이전트를 선택하고 직접 연결하는 것 사이에 어떤 차이가 있는지 체감하고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 말하면, 실습을 마친 지금도 세 가지 질문에 대한 답이 완전히 정리되지는 않았다. 그 열린 상태 그대로 기록한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 같은 카테고리가 아니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실습 전에 갖고 있던 가장 큰 오해는, Claude Code와 OpenClaw/Hermes를 &lt;b&gt;경쟁 관계&lt;/b&gt;로 놓고 비교하려 했다는 점이다. 실제로는 그렇지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Claude Code는 코드베이스 전체를 이해하는 목적 특화 코딩 에이전트다.&lt;/b&gt;&lt;br /&gt;터미널 안에서 코드를 읽고, 수정하고, 테스트하고, PR을 올리는 일을 깊고 정확하게 한다. 좁고 깊은 문제에 최적화되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;OpenClaw/Hermes는 삶 전체에 걸친 작업 위임을 위한 범용 에이전트다.&lt;/b&gt;&lt;br /&gt;WhatsApp으로 명령하면 메일을 보내고, 일정을 잡고, 정보를 조회하고, 24시간 백그라운드에서 돌아간다. 코딩 품질을 비교하는 게 아니라, 애초에 풀려는 문제가 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 더해 Hermes가 핫해진 또 다른 이유가 있다. &lt;b&gt;&quot;사용할수록 더 똑똑해진다&quot;&lt;/b&gt;는 것이다. 단, 이 표현은 정확하게 이해할 필요가 있다. 모델 가중치가 학습되는 게 아니다. &lt;b&gt;Hermes Agent는 메모리를 세 레이어로 분리해서 관리&lt;/b&gt;한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;현재 세션의 컨텍스트 윈도우(in-context memory)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;과거 대화와 작업 결과를 벡터 DB에 저장하고 필요할 때 검색해서 꺼내오는 &lt;b&gt;외부 메모리(external memory via RAG)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;그리고 반복 작업의 패턴을 저장해두고 다음 실행 시 참조하는 &lt;b&gt;절차적 메모리(procedural memory)&lt;/b&gt;로 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 LLM이 매 세션마다 빈 상태로 시작하는 것과 달리, Hermes는 쌓인 이력을 retrieval해서 응답에 반영한다. &quot;똑똑해진다&quot;의 실체는 모델의 진화가 아니라, 개인화된 컨텍스트 데이터베이스가 두터워질수록 retrieval의 정밀도가 높아지는 구조다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;33:1-33:11;1498-1508&quot; data-ke-size=&quot;size16&quot;&gt;비유하자면 이렇다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-sourcepos=&quot;35:1-36:61;1510-1613&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-sourcepos=&quot;35:1-35:43;1510-1552&quot;&gt;Claude Code = 매번 새로 브리핑을 받아야 하는 전문 코딩 비서&lt;/li&gt;
&lt;li data-sourcepos=&quot;36:1-36:61;1553-1613&quot;&gt;OpenClaw/Hermes = 나의 업무 방식, 선호, 이력을 기억하며 점점 손발이 맞아가는 범용 비서&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. &quot;24시간 항시 동작&quot;의 실제 의미&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenClaw와 Hermes를 설명할 때 자주 나오는 문구가 있다. &quot;24시간 항시 동작한다.&quot; 이게 처음엔 직관적으로 이해가 안 됐다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 input도 없이 스스로 뭔가 하는 건가? 에이전트가 자율적으로 움직인다는 건가?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론부터 말하면, &lt;b&gt;입력 없이 도는 에이전트는 없다.&lt;/b&gt; &quot;24시간 동작&quot;의 핵심은 자율성의 정도 차이가 아니라, &lt;b&gt;input의 출처와 프로세스 생존 방식의 차이&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Claude Code의 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 모드에서 input 출처는 단 하나다. &lt;b&gt;&quot;사람이 터미널 앞에서 타이핑&quot;&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널(또는 SSH 세션)을 닫으면 프로세스 그룹에 SIGHUP 신호가 전달되고, Claude Code도 함께 종료된다. 살아있게 하려면 tmux 같은 멀티플렉서로 세션을 유지하거나, 상시 켜진 서버에 올려야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code가 CI 트리거나 cron job으로 헤드리스 모드(claude -p)로 실행될 수 있는 건 사실이다. 그러나 이 경우도 패턴은 동일하다: &lt;b&gt;&quot;한 번 호출 &amp;rarr; 한 번 실행 &amp;rarr; 종료&quot;.&lt;/b&gt; 세션이 계속 살아서 다음 이벤트를 기다리는 구조가 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &quot;24시간 항시 동작&quot;은 Claude Code의 기본 설계가 아니다. 사람이 인프라를 더 얹어서 흉내내는 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;OpenClaw/Hermes의 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조 자체가 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로세스 생존 방식&lt;/b&gt;: 처음부터 백그라운드 데몬(서버)으로 설계되어 있다. 앱을 닫아도 프로세스가 죽지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Input의 출처가 다양하다&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WhatsApp, Telegram, Slack, iMessage 등 8개 이상의 메시징 플랫폼 동시 연결&lt;/li&gt;
&lt;li&gt;30분마다 작동하는 내부 하트비트 스케줄러&lt;/li&gt;
&lt;li&gt;외부 시스템의 webhook/이벤트&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;30분마다 스스로 알아서 뭔가 한다&quot;는 것도 사실은 처음에 &lt;b&gt;&quot;30분마다 할 일 목록을 체크하라&quot;&lt;/b&gt;는 설정 input을 한 번 박아둔 것이다. 그 설정 자체가 input이다. 자율 동작처럼 보이지만, 트리거의 출처가 사람의 타이핑이 아니라 스케줄러일 뿐이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정리하면&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code (기본) OpenClaw / Hermes&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input 출처&lt;/td&gt;
&lt;td&gt;터미널 타이핑 (또는 CI 1회성)&lt;/td&gt;
&lt;td&gt;메신저 + 하트비트 + webhook&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;프로세스 형태&lt;/td&gt;
&lt;td&gt;터미널 종속 포그라운드&lt;/td&gt;
&lt;td&gt;독립적인 백그라운드 데몬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;상시 동작&lt;/td&gt;
&lt;td&gt;tmux + 상시-on 서버 필요&lt;/td&gt;
&lt;td&gt;기본 설계가 상시-on&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;24시간 항시 동작&quot;의 실제 의미는 이것이다. &lt;b&gt;input을 줄 수 있는 채널이 항상 열려 있고, 그걸 받아먹을 프로세스(데몬)가 항상 살아있다.&lt;/b&gt; 자율성의 차이가 아니라, 인프라 설계 철학의 차이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 파운데이션 모델과 에이전트를 직접 조합해보며 알게 된 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hermes Agent를 Qwen3.5와 직접 연결해보면서 얻은 가장 큰 수확은 도구 자체의 편의성이 아니었다. &lt;b&gt;모델과 에이전트 프레임워크 사이의 경계가 어디서 갈리는지를 직접 체감한 것&lt;/b&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code는 훌륭한 완제품이다. 그러나 완제품은 &quot;왜 이 모델이 도구 호출을 잘하고, 저 모델은 못하는지&quot;를 보여주지 않는다. 파운데이션 모델을 직접 선택하고, 에이전트 프레임워크를 따로 선택하고, 그 둘을 연결해보는 과정에서 &lt;b&gt;도구 호출 신뢰도(tool-calling reliability)&lt;/b&gt; 라는 변수가 실제로 존재한다는 걸 체감하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Qwen3.5가 왜 tool calling에 강하다고 평가받는지, 모델마다 function calling 포맷(ChatML, Hermes 포맷 등)이 왜 다른지, 에이전트 로직을 다시 쓰지 않고 모델만 교체할 수 있다는 것이 실제로 무슨 의미인지 이걸 사용 설명서가 아니라 직접 손으로 확인하며 느낀 것이 이번 실습의 핵심 가치였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 아직 답을 못 찾은 것들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하고 나니 오히려 질문이 선명해졌다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코딩엔 Claude Code + Opus, 그 외 범용 작업엔 Hermes/OpenClaw라는 이분법이 실제 워크플로우에서 지속 가능한가?&lt;/li&gt;
&lt;li&gt;아니면 이 조합은 아직 내 워크플로우에서는 불필요한 복잡성인가?&lt;/li&gt;
&lt;li&gt;모델 비종속 아키텍처가 주는 유연성이, 완제품의 통합된 품질을 실제로 넘어서는 시점은 언제인가?&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Artificial Intelligence</category>
      <category>agent</category>
      <category>AI</category>
      <category>ai agent</category>
      <category>claude code</category>
      <category>Foundation Model</category>
      <category>hermes</category>
      <category>hermes agent</category>
      <category>OpenClaw</category>
      <author>D.Y</author>
      <guid isPermaLink="true">https://ithub.tistory.com/453</guid>
      <comments>https://ithub.tistory.com/453#entry453comment</comments>
      <pubDate>Mon, 29 Jun 2026 09:52:12 +0900</pubDate>
    </item>
    <item>
      <title>요청을 받는 사람과 문제를 다시 쓰는 사람: BRM이 일하는 방식</title>
      <link>https://ithub.tistory.com/452</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;조직에서 &quot;이런 걸 만들어 달라&quot;는 요청은 끊이지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대시보드를 만들어 달라, 보고서를 자동화해 달라, 알림 기능을 넣어 달라. 이 요청들을 빠르게 접수하고 정확하게 전달하는 사람은 유능해 보인다. 그러나 BRM(Business Relationship Manager)이 하는 일은 그 지점에서 시작되는 것이 아니라, 오히려 그 지점을 의심하는 데서 시작된다.&lt;br /&gt;&lt;br /&gt;BRM 후보 과정에서 학습한 내용을 한 문장으로 요약하면 이렇다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;좋은 분석가는 요청을 그대로 전달하지 않고, 그 요청 뒤의 필요와 가치, 그리고 다음 행동을 분명하게 만든다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 그 한 문장이 실제 업무에서 어떻게 작동하는지를 단계별로 풀어낸 기록이다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 문제는 '요청'의 형태로 도착하지 않는다&lt;/b&gt;&lt;br /&gt;가장 흔한 실수는 현업의 요청을 곧바로 문제라고 부르는 것이다. &quot;회의실 예약 앱을 만들어 달라&quot;는 말은 문제가 아니라 해결책의 형태다. &quot;예약이 불편하다&quot;는 말 역시 문제가 아니라 증상이다. 진짜 문제는 그 뒤에 있다. 반복되는 예약 충돌로 참석자 조율 시간이 늘고, 중요한 회의의 시작이 지연된다.&lt;br /&gt;&lt;br /&gt;이 문장이 좋은 이유는 두 가지를 담고 있기 때문이다. 하나는 맥락(반복 충돌)이고, 다른 하나는 영향(조율 시간 증가, 회의 지연)이다. IIBA의 핵심개념 모형은 '필요(Need)'를 해결책이 아니라 다뤄야 할 문제나 기회로 정의한다. 그러나 필요만 적어서는 부족하다. 어떤 맥락에서, 어떤 이해관계자에게, 어떤 가치가 생기는지 연결되어야 비로소 &quot;기능 요청이 아니라 업무 문제로 다시 쓴 문장&quot;이 된다.&lt;br /&gt;&lt;br /&gt;여기서 한 가지를 의도적으로 보류한다는 점이 중요하다. 문제를 정의하는 단계에서는 원인과 해결책을 아직 확정하지 않는다. 왜 지금 필요한지, 어떤 가치와 닿아 있는지만 적는다. 원인으로 너무 빨리 점프하는 순간, 분석은 가설을 검증하는 일이 아니라 결론을 정당화하는 일로 변질되기 때문이다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 들은 것과 확인된 것은 다르다&lt;/b&gt;&lt;br /&gt;문제를 다시 썼다면, 이제 그것을 뒷받침할 사실이 필요하다. 요구 도출은 &quot;인터뷰를 했다&quot;는 사실만으로 끝나지 않는다. IREB는 &lt;b&gt;요구의 출처&lt;/b&gt;를 &lt;b&gt;이해관계자 &amp;middot; 문서 &amp;middot; 시스템&lt;/b&gt; 세 가지로 구분한다. 담당자에게 묻는 것은 이해관계자 출처이고, 업무 시스템과 처리 로그가 실제로 어떤 데이터를 갖고 어떻게 도는지 확인하는 것은 시스템 출처다. 좋은 도출은 이 세 출처를 교차시킨다. 상담원의 말, 응대 기준서, 티켓 처리 로그를 함께 봐야 한다.&lt;br /&gt;&lt;br /&gt;그리고 가장 본질적인 규율이 여기 있다. 양이 아니라 구분이다. 상담원이 &quot;월요일마다 문의가 폭증한다&quot;고 말했더라도, 티켓 로그로 확인하기 전까지 그것은 사실이 아니다. 엄밀히 말하면 사실인 것은 단 하나, &quot;상담원이 그렇게 말했다&quot;는 발언 자체다. &quot;실제로 폭증한다&quot;는 것은 추정이고, &quot;원인은 담당자 부족&quot;이라는 말은 결론이 아니라 원인 후보일 뿐이다.&lt;br /&gt;&lt;br /&gt;미확인 항목을 다루는 방식이 분석가의 수준을 가른다. 미확인 항목은 빼는 것이 아니라 '확인 대상'으로 남긴다. 모름을 감추면 다음 분석이 그 위에서 무너지고, 모름을 남기면 다음 분석이 안전해진다. 모름은 결함이 아니라 다음 행동의 좌표다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 불편을 길게 설명하는 능력 vs 현재를 구조화하는 능력&lt;/b&gt;&lt;br /&gt;현재상태 분석에서 요구되는 것은 불편을 길게 묘사하는 능력이 아니라, 업무와 시스템을 구조화하는 능력이다. 예컨대 고객 환불 처리는 &lt;b&gt;여섯 개의 요소&lt;/b&gt;로 분해된다. &lt;b&gt;흐름(접수&amp;rarr;승인&amp;rarr;환불), 시스템 연동(CRM&amp;middot;주문), 데이터(문의 유형&amp;middot;처리 상태), 정책과 제약(승인 기준), 예외(부분 환불), 병목(승인 대기)&lt;/b&gt;. 모르는 칸은 비워두지 않고 &quot;모름&quot;으로 명시한다.&lt;br /&gt;&lt;br /&gt;이 구조 위에서 핵심 질문이 던져진다. &quot;그래서 새로 만들 일인가, 아니면 기준과 책임을 먼저 정리할 일인가?&quot;, &quot;엑셀 때문에 느리니 시스템을 만들자&quot;는 방향이 완전히 틀린 것은 아니지만 분석으로는 약하다. 느림은 증상이고, 실제 원인 후보는 승인 기준이 문서와 메일에 흩어져 있거나, 처리 상태 데이터가 어긋나거나, 책임 주체가 불명확한 데 있을 수 있다.&lt;br /&gt;&lt;br /&gt;그래서 '간극(Gap)'의 정의가 중요해진다. 간극은 해결책의 이름이 아니라, 현재상태와 목표상태 사이의 차이다. &quot;새 환불 시스템 도입&quot;은 간극이 아니다. &quot;처리 흐름과 책임 기준이 서로 연결되어 있지 않다&quot;가 간극이다. 목표상태 역시 시스템의 이름이 아니라 *접수&amp;middot;승인&amp;middot;처리&amp;middot;상태 업데이트가 하나의 흐름으로 이어지는 업무 상태*로 기술된다. 분석가가 해결책의 언어가 아니라 차이의 언어로 말할 수 있을 때, 비로소 해결책의 선택지가 열린다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 기술 사실을 사업 언어로 번역한다&lt;/b&gt;&lt;br /&gt;여기까지가 비즈니스 분석(BA)의 영역이라면, BRM의 영역은 이 분석을 조직의 의사결정으로 옮기는 일이다.&lt;br /&gt;&lt;br /&gt;도메인&amp;middot;기술 이해는 기술을 많이 아는 능력이 아니라, 기술 사실을 현업이 선택할 수 있는 사업 언어로 바꾸는 능력이다. 주문 시스템에 이미 상태 알림 기능이 있다면, &quot;개발이 가능하다&quot;가 아니라 &quot;새 시스템 없이도 고객 대기 시간을 줄일 수 있다&quot;고 번역되어야 한다. 반대로 데이터가 여러 시스템에 흩어져 있다면 &quot;연동이 어렵다&quot;에서 멈추지 않고 비용&amp;middot;기간&amp;middot;운영 책임&amp;middot;오류 리스크를 함께 말해야 한다. ITIL 4의 네 가지 차원(조직, 정보와 기술, 파트너, 가치 흐름)은 이때 &quot;무엇을 함께 보아야 하는가&quot;를 점검하는 체크리스트로 쓰인다.&lt;br /&gt;&lt;br /&gt;그리고 아무리 좋은 개선안이라도 회사가 지금 중요하게 보는 목표와 따로 놀면 단발성 개선에 그친다. 전략 정렬은 분석한 문제를 응답 시간, 반복 문의 감소, 운영비 절감 같은 측정 가능한 목표에 연결하는 일이다. 회사의 방향이 문서로 명확하지 않을 때조차 그냥 넘기지 않는다. &quot;어떤 기준으로 우선순위를 정할 것인가&quot;라는 질문을 남긴다. 방향의 공백도 관리해야 할 이슈이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;5. 관계가 움직였는가 &amp;mdash; BRM의 진짜 영역&lt;/b&gt;&lt;br /&gt;이 모든 분석이 작동하려면 한 가지 전제가 필요하다. 상대가 자료를 내주고 함께 풀겠다고 말할 만큼의 신뢰다. 파트너십은 &quot;좋은 관계를 만들었다&quot;는 말로 증명되지 않는다. &lt;b&gt;관계가 실제로 움직였는가&lt;/b&gt;로 증명된다. 처음에 &quot;우리 업무를 모른다&quot;며 경계하던 고객센터가, 처리 로그를 공유하고 승인자를 소개하며 &quot;같이 기준을 정해보자&quot;고 말하기 시작했다면 그때 관계가 움직인 것이다. 요청 처리자와 전략 파트너의 차이는 바로 이 지점에서 드러난다.&lt;br /&gt;&lt;br /&gt;관계가 열리면 BRM은 수요를 형성한다. BRM Institute는 BRM을 사업 기능과 사업 파트너 사이의 전략적 연결자로 정의하며, 그 역할을 수요를 자극하고(stimulate), 드러내고(surface), 형성하는(shape) 일로 설명한다. &quot;대시보드를 만들어 달라&quot;는 요청 뒤에는 의사결정에 필요한 상태가 늦게 보인다는 문제가, &quot;알림을 넣어 달라&quot;는 요청 뒤에는 책임 기준이 흐리다는 문제가 숨어 있다. 수요 형성은 이 표면 요청을 업무 목표가 보이는 문장으로 다시 쓰는 일이다.&lt;br /&gt;&lt;br /&gt;그다음에야 가치 동인을 붙인다. &quot;대시보드를 만든다&quot;는 해결안이지 가치가 아니다. 가치는 일이 빨라진다, 실수가 줄어든다, 고객 불편이 줄어든다 처럼 변화의 방향으로 적는다. 그리고 거기에 추적 가능한 지표를 잇는다. 평균 처리 시간, 재작업 건수, 반복 문의율. 지표가 처음부터 확정값일 필요는 없다. 중요한 것은 &quot;좋아진다&quot;는 막연한 말을 측정 가능한 변화로 바꾸는 것이다.&lt;br /&gt;&lt;br /&gt;마지막은 조율이다. 여러 부서가 &quot;좋다&quot;고 말해도 누가 언제 무엇을 할지 정하지 않으면 일은 멈춘다. 조율은 합의에서 끝나지 않고 책임자, 다음 행동, 일정, 확인 기준까지 남길 때 비로소 실행이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;마치며 - 결국 하나의 습관&lt;/b&gt;&lt;br /&gt;열여섯&amp;nbsp;장에&amp;nbsp;걸친&amp;nbsp;개념을&amp;nbsp;다&amp;nbsp;익히고&amp;nbsp;나서&amp;nbsp;남은&amp;nbsp;것은&amp;nbsp;의외로&amp;nbsp;단순한&amp;nbsp;습관&amp;nbsp;하나였다.&lt;br /&gt;&lt;br /&gt;모든 판단에서 사실과 추정과 다음 확인을 분리하고, 어떤 권고를 하든 남는 리스크와 다음 검증 행동을 함께 적는다.&lt;br /&gt;&lt;br /&gt;문제정의에서 조율까지, 모든 단계가 이 습관의 변주였다. 요청을 필요로 다시 쓰는 것도, 발언을 사실과 추정으로 가르는 것도, 모름을 확인 대상으로 남기는 것도, 가치를 지표로 옮기는 것도 결국 불확실한 것을 불확실한 채로 정직하게 다루면서, 그럼에도 다음 행동을 분명히 만드는 일이다.&lt;br /&gt;&lt;br /&gt;요청을&amp;nbsp;받는&amp;nbsp;사람은&amp;nbsp;일을&amp;nbsp;처리하고,&amp;nbsp;문제를&amp;nbsp;다시&amp;nbsp;쓰는&amp;nbsp;사람은&amp;nbsp;방향을&amp;nbsp;만든다.&amp;nbsp;BRM은&amp;nbsp;후자가&amp;nbsp;되기로&amp;nbsp;선택한&amp;nbsp;사람의&amp;nbsp;이름이다.&lt;/p&gt;</description>
      <category>기타</category>
      <category>ade</category>
      <category>BA</category>
      <category>BRM</category>
      <category>FDE</category>
      <author>D.Y</author>
      <guid isPermaLink="true">https://ithub.tistory.com/452</guid>
      <comments>https://ithub.tistory.com/452#entry452comment</comments>
      <pubDate>Thu, 11 Jun 2026 13:40:17 +0900</pubDate>
    </item>
    <item>
      <title>MCP란 무엇인가 &amp;mdash; 개념부터 동작 흐름까지</title>
      <link>https://ithub.tistory.com/451</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;MCP가 왜 필요한가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM은 본질적으로 텍스트를 받아서 텍스트를 뱉는 기계다. 아무리 똑똑해도 스스로는 아무것도 할 수 없다. 파일을 읽거나, DB에 접속하거나, 외부 API를 호출하는 것 전부 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 등장한 것이 &lt;b&gt;도구(Tool)&lt;/b&gt; 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM이 &quot;나는 이 도구를 써야겠다&quot;는 신호를 보내면, 외부 시스템이 실제로 실행하고 결과를 돌려주는 구조다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 문제가 있었다. 도구마다 연결 방식이 제각각이었다. Slack API는 이렇게, GitHub API는 저렇게, PostgreSQL은 또 다르게 통합할 때마다 새로 만들어야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MCP(Model Context Protocol)&lt;/b&gt; 는 이 문제를 해결한다. Anthropic이 만든 &lt;b&gt;표준화된 도구 통신 프로토콜&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 외부 시스템이든 MCP 서버로 감싸면, Claude는 동일한 방식으로 연결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MCP의 핵심 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP는 세 가지 레이어로 이루어진다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; style=&quot;color: #eaecf0;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;┌─────────────────────────────────┐
│         Claude LLM              │  &amp;larr; 판단하는 두뇌
│    (tool_use 블록 생성)           │
└──────────────┬──────────────────┘
               │
┌──────────────▼──────────────────┐
│     Claude Code 런타임           │  &amp;larr; 연결하는 몸통
│  (tool_use 감지 + MCP 관리)       │
└──────────────┬──────────────────┘
               │  JSON-RPC
┌──────────────▼──────────────────┐
│         MCP 서버                 │  &amp;larr; 실제로 실행하는 손발
│  (외부 시스템과 실제 통신)           │
└─────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 레이어가 무엇을 하는지 명확히 구분하는 것이 MCP를 이해하는 출발점이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Claude LLM &amp;mdash; 판단하는 두뇌&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 도구를 써야 하는지 결정한다. 실제로 실행하지는 않는다. &quot;이 작업은 DB 조회가 필요하다, query 도구를 호출하겠다&quot;는 신호를 tool_use 블록으로 출력할 뿐이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Claude Code 런타임 &amp;mdash; 연결하는 몸통&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 claude 명령어를 실행했을 때 돌아가는 프로그램 전체다. 세 가지 역할을 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;중계자&lt;/b&gt;: 사용자 입력을 Anthropic API로 전달하고, 응답을 터미널에 출력&lt;/li&gt;
&lt;li&gt;&lt;b&gt;감지기&lt;/b&gt;: LLM 응답에서 tool_use 블록을 발견하면 도구 실행 신호로 인식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MCP 관리자&lt;/b&gt;: 설정된 MCP 서버들을 시작하고, 도구 호출 시 JSON-RPC 요청을 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM은 두 번 등장하지만, 런타임은 처음부터 끝까지 모든 단계에 관여한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MCP 서버 &amp;mdash; 실제로 실행하는 손발&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 외부 시스템과의 실제 통신을 담당하는 별도 프로세스다. PostgreSQL MCP 서버라면 SQL을 실행하고, Notion MCP 서버라면 페이지를 읽고 쓰고, GitHub MCP 서버라면 이슈를 조회한다. 모두 &lt;b&gt;동일한 MCP 프로토콜&lt;/b&gt;로 Claude와 통신한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;동작 흐름 &amp;mdash; 사용자 입력부터 결과까지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 PostgreSQL MCP가 연결된 환경에서 &quot;사용자 정보 조회해줘&quot;라고 입력한 상황을 따라가본다. 흐름은 어떤 MCP를 쓰든 동일하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-06-06 18.16.55.png&quot; data-origin-width=&quot;1496&quot; data-origin-height=&quot;1754&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sTknc/dJMcaaMjlb2/Jmf35tTLWZAJnxObIEzXBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sTknc/dJMcaaMjlb2/Jmf35tTLWZAJnxObIEzXBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sTknc/dJMcaaMjlb2/Jmf35tTLWZAJnxObIEzXBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsTknc%2FdJMcaaMjlb2%2FJmf35tTLWZAJnxObIEzXBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1496&quot; height=&quot;1754&quot; data-filename=&quot;스크린샷 2026-06-06 18.16.55.png&quot; data-origin-width=&quot;1496&quot; data-origin-height=&quot;1754&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1단계 &amp;mdash; 사용자 입력&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;1c&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;&quot;사용자 정보 조회해줘&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자연어다. 어떤 테이블인지, 어떤 조건인지 지정하지 않았다. Claude가 이 의도를 해석해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2단계 &amp;mdash; LLM 추론 (첫 번째 LLM 호출)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code 런타임이 사용자 입력을 Anthropic API로 전달한다. 이때 &lt;b&gt;시스템 프롬프트에 사용 가능한 MCP 도구 목록&lt;/b&gt;이 포함된다. Claude는 이 목록을 보고 판단한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; style=&quot;color: #eaecf0;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;사용 가능한 도구:
- postgresql_list_tables: 테이블 목록 조회
- postgresql_query: SQL 실행
- postgresql_describe_table: 테이블 구조 확인

판단: DB 조회가 필요 &amp;rarr; postgresql_query 도구를 쓰겠다&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3단계 &amp;mdash; tool_use 블록 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM의 응답이 일반 텍스트가 아닌 &lt;b&gt;tool_use 블록&lt;/b&gt;으로 나온다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;{
  &quot;type&quot;: &quot;tool_use&quot;,
  &quot;id&quot;: &quot;toolu_01abc...&quot;,
  &quot;name&quot;: &quot;postgresql_query&quot;,
  &quot;input&quot;: {
    &quot;query&quot;: &quot;SELECT * FROM users LIMIT 20&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude가 직접 SQL을 실행하는 게 아니다. &quot;이 도구를 이 파라미터로 실행하라&quot;는 &lt;b&gt;요청서&lt;/b&gt;를 작성한 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4단계 &amp;mdash; 런타임이 tool_use 감지 후 MCP 서버 호출&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code 런타임이 tool_use 블록을 감지한다. 그리고 해당 MCP 서버에 &lt;b&gt;JSON-RPC&lt;/b&gt; 프로토콜로 요청을 보낸다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;// 런타임 &amp;rarr; MCP 서버
{
  &quot;jsonrpc&quot;: &quot;2.0&quot;,
  &quot;id&quot;: 1,
  &quot;method&quot;: &quot;tools/call&quot;,
  &quot;params&quot;: {
    &quot;name&quot;: &quot;postgresql_query&quot;,
    &quot;arguments&quot;: {
      &quot;query&quot;: &quot;SELECT * FROM users LIMIT 20&quot;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP 서버는 로컬에서 돌고 있는 별도 프로세스다. stdio(표준 입출력) 또는 SSE(Server-Sent Events) 방식으로 런타임과 통신한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5단계 &amp;mdash; MCP 서버가 외부 시스템과 실제 통신&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP 서버가 요청을 받아 실제 작업을 수행한다. PostgreSQL 예시라면 pg 드라이버로 DB에 접속해 SQL을 실행한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;MCP 서버 &amp;rarr; PostgreSQL: SELECT * FROM users LIMIT 20
PostgreSQL &amp;rarr; MCP 서버: [{id:1, name:&quot;홍길동&quot;, ...}, ...]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;중요한 포인트&lt;/b&gt;: Claude는 외부 시스템에 직접 접근하지 않는다. MCP 서버가 항상 중간에서 통역사 역할을 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6단계 &amp;mdash; 결과를 tool_result로 포장해 LLM에 전달&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP 서버의 응답이 Claude Code 런타임으로 돌아온다. 런타임은 이것을 &lt;b&gt;tool_result 블록&lt;/b&gt;으로 포장해 LLM의 컨텍스트에 넣는다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;{
  &quot;type&quot;: &quot;tool_result&quot;,
  &quot;tool_use_id&quot;: &quot;toolu_01abc...&quot;,
  &quot;content&quot;: [
    {
      &quot;type&quot;: &quot;text&quot;,
      &quot;text&quot;: &quot;[{\&quot;id\&quot;:1,\&quot;name\&quot;:\&quot;홍길동\&quot;,...}, ...]&quot;
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 블록이 LLM의 두 번째 입력이 된다. Claude는 이제 실제 외부 시스템의 데이터를 컨텍스트에서 &quot;보게&quot; 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7단계 &amp;mdash; 최종 응답 생성 (두 번째 LLM 호출)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tool_result를 받은 Claude가 최종 응답을 생성한다. 원시 데이터를 그대로 뱉는 게 아니라 자연어로 해석해서 답한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;gherkin&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;조회 결과 20건입니다.

| id | name   | email            |
|----|--------|------------------|
|  1 | 홍길동 | hong@example.com |
|  2 | 김철수 | kim@example.com  |
...

추가 조건이 있으면 말씀해주세요.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;LLM 호출이 두 번 일어난다는 것의 의미&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 흐름에서 &lt;b&gt;LLM은 두 번 호출&lt;/b&gt;된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;1차 호출: 사용자 입력 &amp;rarr; tool_use 생성
2차 호출: tool_result 수신 &amp;rarr; 최종 응답 생성&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도구를 n번 쓰면 LLM 호출도 n+1번 일어난다. 비용과 지연시간이 선형으로 늘어나는 이유가 여기에 있다. 또한 이 루프 자체가 &lt;b&gt;에이전트의 가장 기본 단위&lt;/b&gt;다. 더 복잡한 멀티 에이전트 시스템도 결국 이 루프의 반복과 중첩으로 이루어진다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;계정정보는 어디에 저장되는가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP가 외부 시스템에 접속하려면 자격증명(API 키, DB 비밀번호 등)이 필요하다. 기본적으로 &lt;b&gt;설정 파일에 평문&lt;/b&gt;으로 저장된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)

{
  &quot;mcpServers&quot;: {
    &quot;postgresql&quot;: {
      &quot;command&quot;: &quot;npx&quot;,
      &quot;args&quot;: [&quot;-y&quot;, &quot;@modelcontextprotocol/server-postgres&quot;],
      &quot;env&quot;: {
        &quot;POSTGRES_HOST&quot;: &quot;localhost&quot;,
        &quot;POSTGRES_USER&quot;: &quot;myuser&quot;,
        &quot;POSTGRES_PASSWORD&quot;: &quot;mypassword123&quot;
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code 런타임이 이 파일을 읽어서 MCP 서버를 시작할 때 환경변수로 주입한다. &lt;b&gt;LLM은 이 자격증명을 볼 수 없다.&lt;/b&gt; 런타임과 MCP 서버 사이에서만 오가는 정보다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 평문 저장 대신 세 가지 방법을 쓴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;환경변수 참조&lt;/b&gt; &amp;mdash; 설정 파일에 값 대신 변수명을 쓴다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;accesslog&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;&quot;POSTGRES_PASSWORD&quot;: &quot;${POSTGRES_PASSWORD}&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;.env 파일 분리&lt;/b&gt; &amp;mdash; 자격증명을 별도 파일로 관리하고 git에서 제외한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Secret Manager&lt;/b&gt; &amp;mdash; AWS Secrets Manager나 HashiCorp Vault 같은 전용 비밀 관리 시스템에서 런타임에 값을 가져온다. 운영 환경의 표준 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP를 한 문장으로 정의하면 이렇다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM이 외부 세계와 표준화된 방식으로 통신하기 위한 프로토콜.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 동작 흐름의 핵심은 세 가지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, &lt;b&gt;LLM은 판단만 한다.&lt;/b&gt; 실제 실행은 MCP 서버가 담당한다. Claude가 직접 DB에 접속하거나 API를 호출하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, &lt;b&gt;LLM 호출은 두 번 일어난다.&lt;/b&gt; tool_use 생성과 최종 응답 생성, 이 두 번의 API 호출 사이에 MCP 서버 실행이 끼어드는 구조다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셋째, &lt;b&gt;MCP는 표준화가 핵심이다.&lt;/b&gt; PostgreSQL이든, Notion이든, GitHub이든 &amp;mdash; Claude 입장에서는 동일한 tool_use/tool_result 인터페이스로 모든 것을 다룬다. 외부 시스템이 바뀌어도 Claude 쪽 로직은 바뀌지 않는다.&lt;/p&gt;</description>
      <category>Artificial Intelligence</category>
      <category>AI</category>
      <category>LLM</category>
      <category>MCP</category>
      <author>D.Y</author>
      <guid isPermaLink="true">https://ithub.tistory.com/451</guid>
      <comments>https://ithub.tistory.com/451#entry451comment</comments>
      <pubDate>Sat, 6 Jun 2026 18:13:45 +0900</pubDate>
    </item>
    <item>
      <title>Claude Code 작업 완료 알림에 작업 내용 포함하기</title>
      <link>https://ithub.tistory.com/450</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code를 여러 세션으로 병렬 운영하다 보면 한 가지 불편함이 생긴다. 작업이 완료될때까지 모니터링해야한다는 점이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 필자는 hook과 terminal-notifier 스크립트를 사용해서 작업이 끝나면 알림이 오도록 구성해서 사용하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데.... 사용하다보니....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업이 완료됐다는 알림은 오는데, &quot;작업 완료&quot;라는 메시지만으로는 어떤 세션에서 무엇이 끝났는지 알 방법이 없다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 Stop 훅 설정은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;hooks&quot;: {
    &quot;Stop&quot;: [
      {
        &quot;hooks&quot;: [
          {
            &quot;type&quot;: &quot;command&quot;,
            &quot;command&quot;: &quot;terminal-notifier -message '작업 완료' -title 'Claude Code' -sound default&quot;
          }
        ]
      }
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알림에는 항상 동일한 &quot;작업 완료&quot; 문자열만 표시된다. 세션이 많아질수록 알림을 받아도 어떤 작업이 끝난 건지 알 수 없다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;원인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code의 Stop 훅은 실행 시 이벤트 데이터를 stdin으로 전달한다. 기본 설정에서는 이 데이터를 전혀 사용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 JSON 구조는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;{
  &quot;session_id&quot;: &quot;...&quot;,
  &quot;hook_event_name&quot;: &quot;Stop&quot;,
  &quot;last_assistant_message&quot;: &quot;V94 마이그레이션 파일을 생성하고 서버를 재시작했습니다...&quot;,
  &quot;transcript_path&quot;: &quot;...&quot;,
  ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;last_assistant_message 필드에 Claude의 마지막 응답 전문이 담겨 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결책&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;훅 스크립트에서 last_assistant_message의 첫 번째 줄을 추출해 알림 메시지로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 스크립트 작성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;~/.claude/hooks/terminal-notify.sh:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;#!/bin/bash
EVENT=$(cat)
SUMMARY=$(echo &quot;$EVENT&quot; | jq -r '
  .last_assistant_message // &quot;&quot; |
  split(&quot;\\n&quot;)[0] |
  .[0:100]
' 2&amp;gt;/dev/null)
if [ -z &quot;$SUMMARY&quot; ] || [ &quot;$SUMMARY&quot; = &quot;null&quot; ]; then
    SUMMARY=&quot;작업 완료&quot;
fi
terminal-notifier -message &quot;$SUMMARY&quot; -title &quot;Claude Code&quot; -sound default
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 권한을 부여한다.&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;chmod +x ~/.claude/hooks/terminal-notify.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. settings.json 등록&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;~/.claude/settings.json의 Stop 훅에 위 스크립트를 등록한다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;hooks&quot;: {
    &quot;Stop&quot;: [
      {
        &quot;matcher&quot;: &quot;&quot;,
        &quot;hooks&quot;: [
          {
            &quot;type&quot;: &quot;command&quot;,
            &quot;command&quot;: &quot;~/.claude/hooks/terminal-notify.sh&quot;
          }
        ]
      }
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 인라인 terminal-notifier 명령이 있다면 위 스크립트 경로로 교체한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결과&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알림 메시지 예시&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Before&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;작업 완료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;After&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;V94 마이그레이션 파일을 생성하고 서버를 재시작했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답의 첫 번째 줄은 대부분 작업 결과 요약 문장이다. 알림만으로 어떤 작업이 끝났는지 즉시 파악할 수 있다. 메시지를 추출할 수 없는 경우에는 &quot;작업 완료&quot;로 폴백된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jq가 사전 설치되어 있어야 한다(brew install jq). macOS 외 환경에서는 terminal-notifier 대신 해당 플랫폼의 알림 도구로 교체하면 동일하게 적용된다.&lt;/p&gt;</description>
      <category>Artificial Intelligence</category>
      <category>claudecode</category>
      <category>hooks</category>
      <category>Opus4.7</category>
      <category>클로드코드</category>
      <author>D.Y</author>
      <guid isPermaLink="true">https://ithub.tistory.com/450</guid>
      <comments>https://ithub.tistory.com/450#entry450comment</comments>
      <pubDate>Fri, 15 May 2026 13:58:21 +0900</pubDate>
    </item>
    <item>
      <title>AI 에이전트 시대, 개발자에게 필요한 것은 무엇인가</title>
      <link>https://ithub.tistory.com/449</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 잘 짜는 능력이 개발자의 핵심 역량이라는 공식이 흔들리고 있다. 실리콘밸리의 일부 팀은 이미 구현의 상당 부분을 AI에게 맡기고 있으며, 엔지니어는 코드를 작성하는 사람에서 AI가 잘 작동할 수 있는 환경을 설계하는 사람으로 역할이 이동하고 있다. 이 변화가 현장 개발자에게 무엇을 요구하는지, 그리고 어떤 개념들을 이해해야 하는지를 정리한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AI 엔지니어링을 구성하는 네 가지 축&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 AI를 활용한 개발 방법론은 크게 네 가지 영역으로 구분된다. 이 네 가지는 순서대로 적용하는 단계가 아니라, 상호 보완적으로 함께 작동하는 구성 요소이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Prompt Engineering&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM 모델에게 의도를 정확하게 전달하는 기술이다. 구체적인 지침을 작성하거나 페르소나를 설정하는 방식이 대표적이다. 가장 먼저 알려졌고 가장 익숙한 영역이지만, 단독으로는 한계가 명확하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Context Engineering&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI에게 프로젝트 구조, 기존 코드 예시, API 문서 등을 함께 전달하는 기술이다. 단순히 정보를 많이 주는 것이 아니라, 필요한 정보를 적절하게 선별해서 제공하는 것이 핵심이다. 정보를 과도하게 제공하면 오히려 역효과가 발생한다는 것이 실제 사용 사례들을 통해 확인되었으며, LLM 모델마다 컨텍스트를 유지하는 용량이 다르기 때문에 설계 기술이 필요해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트는 세 개의 레이어로 구성된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;System Context&lt;/b&gt;: 에이전트가 항상 참조하는 기본 설정 (CLAUDE.md, AGENTS.md 등)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Conversation Context&lt;/b&gt;: 대화 과정에서 누적되는 이전 맥락&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Tool &amp;amp; Environment Context&lt;/b&gt;: 도구 실행을 통해 얻은 실시간 정보 (MCP, 플러그인 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Harness Engineering&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하네스(Harness)는 원래 말을 통제하기 위해 씌우는 마구(馬具)를 뜻한다. Harness Engineering은 강력한 AI 에이전트를 안전하게 통제할 수 있는 환경을 만드는 기술이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 소프트웨어는 결정론적이다. 같은 입력에는 반드시 같은 결과가 나온다. 그러나 LLM은 비결정론적이다. 같은 입력이라도 상황에 따라 다른 결과가 나올 수 있다. 이 특성 때문에 단순히 프롬프트를 정교하게 작성하는 것만으로는 부족하며, 실패가 구조적으로 반복되지 않도록 환경 자체를 설계해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &quot;DB 테이블을 절대 삭제하지 마라&quot;고 프롬프트에 적는 것은 Prompt Engineering 방식이다. Harness Engineering 방식은 pre-commit hook을 사용해 변경된 코드에 DB 삭제 구문이 포함되어 있으면 커밋 자체가 실패하도록 강제하는 것이다. 규칙을 지키도록 요청하는 것이 아니라, 어기는 것이 불가능한 구조를 만드는 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Agentic Engineering&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트가 자율적으로 복잡한 작업을 수행할 수 있도록 설계하는 기술이다. 단일 LLM 호출이 아니라, 여러 에이전트가 역할을 나누어 협력하거나 작업을 반복&amp;middot;검증하는 파이프라인을 구성하는 것이 핵심이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vibe Coding과 Agentic Engineering의 가장 큰 차이는 테스트다. 견고한 테스트 스위트가 있으면 AI 에이전트는 테스트가 통과할 때까지 스스로 반복하며, 그 결과에 높은 확신을 가질 수 있다. &amp;mdash; Google Chrome Team&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Harness Engineering을 깊이 이해해야 하는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 가지 축 중에서 현재 가장 주목받고 있으며, 실무 적용에서 가장 큰 변화를 만드는 영역이 Harness Engineering이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구성 요소 네 가지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기계가 읽는 컨텍스트 파일&lt;/b&gt; 코드 저장소 안에 AI가 읽고 따르는 런타임 설정 파일을 배치한다. CLAUDE.md, AGENTS.md, .cursorrules 등이 해당한다. 다만, 컨텍스트에 제약을 제공해도 이를 어기는 경우가 발생한다는 점을 전제로 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결정론적 CI/CD 게이트&lt;/b&gt; AI 출력물이 반드시 통과해야 하는 자동화된 품질 관문이다. 린터, pre-commit hook, 구조 테스트 규칙으로 규칙 준수를 강제한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;명시적 도구 경계&lt;/b&gt; AI가 접근할 수 있는 파일, API, DB 시스템의 범위를 명확히 제한한다. 권한을 구조적으로 설정하면 모델이 아예 해당 영역에 접근하지 못하도록 차단할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지속적 피드백 루프&lt;/b&gt; 실패를 자동으로 감지하고, 규칙을 정제하며, 하네스 구조를 지속적으로 발전시킨다. Garbage Collection, 규칙 위반 감지, 자동 리팩토링, 아키텍처 체크를 주기적으로 실행하고 보완하는 구조가 필요하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;하네스 시스템의 작동 단계&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;분류기&lt;/b&gt;: 요청의 성격을 판별한다. 단순 질의인지, 실제 코드 작업인지.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컨텍스트 관리자&lt;/b&gt;: 필요한 파일과 규칙만 선별해서 제공한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행 루프&lt;/b&gt;: 테스트를 통과할 때까지 자동으로 반복 실행한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;워커 격리&lt;/b&gt;: 코드를 작성하는 AI와 코드를 검토하는 AI를 분리해 이중 검증한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Hook의 네 가지 유형&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hook은 하네스 시스템의 핵심 작동 기제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유형 동작 시점 실전 예시&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pre-action&lt;/td&gt;
&lt;td&gt;에이전트가 행동하기 전&lt;/td&gt;
&lt;td&gt;코드 저장 전 lint 자동 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Post-action&lt;/td&gt;
&lt;td&gt;에이전트가 행동한 후&lt;/td&gt;
&lt;td&gt;커밋 후 자동 테스트 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validation&lt;/td&gt;
&lt;td&gt;에이전트 출력의 품질 검증&lt;/td&gt;
&lt;td&gt;보안 취약점 스캔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notification&lt;/td&gt;
&lt;td&gt;특정 조건 충족 시&lt;/td&gt;
&lt;td&gt;비용 임계치 초과 경고&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code는 이미 이 구조 위에서 동작하고 있다. 파일 변경 시 관련 테스트가 자동 실행되고, package.json 수정 시 의존성 충돌을 검사하며, 보안 관련 파일 수정 시 보안 리뷰 에이전트가 자동으로 호출된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OpenAI의 실험이 보여준 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenAI는 &quot;수동으로 코드를 한 줄도 작성하지 않고 소프트웨어 제품을 만든다&quot;는 의도적 제약을 설정하고 실제 프로젝트를 개발하는 실험을 진행했다. 3~7명의 인원이 약 5개월간 100만 줄의 코드를 작성했고, 이는 기존 대비 약 10배에 달하는 생산성이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기 진행이 예상보다 더뎠던 이유는 에이전트의 역량이 부족해서가 아니었다. 환경이 제대로 갖춰지지 않았기 때문이었다. 에이전트가 상위 목표를 달성하기 위한 도구, 추상화, 내부 구조가 부족했고, 팀의 주요 업무는 에이전트가 유용한 작업을 수행할 수 있도록 그 환경을 만드는 것으로 전환되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 실험에서 도출된 핵심 통찰은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;역할의 분리가 명확해졌다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인간: 의도 정의, 시스템 설계, 제약 설정&lt;/li&gt;
&lt;li&gt;AI: 코드 생성, 테스트, 리뷰, 수정 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;중요한 것은 프롬프트가 아니라 구조다.&lt;/b&gt; 단순히 프롬프트를 잘 작성하는 것이 아니라, 저장소 구조, 문서 구조, 테스트 시스템, CI/CD, lint 규칙, Observability, 에이전트 워크플로우 전체를 설계하는 능력이 요구된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 가독성의 기준이 바뀌고 있다.&lt;/b&gt; 기존에는 옆에 있는 동료 개발자가 이해하기 쉬운 코드를 작성하는 것이 목표였다. 지금은 에이전트가 이해하고 자동으로 수정&amp;middot;검증할 수 있는 코드가 좋은 코드의 기준이 되고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 의사결정은 문서로 남아야 한다.&lt;/b&gt; 머릿속이나 구두로만 이루어지는 의사결정은 AI 시스템에서 의미가 없다. 규칙이 적용된 문서에 기록되어야 에이전트가 참조할 수 있다. 구조적이고 규칙적으로 정리하는 능력이 중요해졌다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;하네스 엔지니어링 설계 시 주의할 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현장에서 실제로 구현할 때 반드시 염두에 두어야 할 사항들이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;큰 instruction 하나는 실패한다.&lt;/b&gt; 작고 연결된 문서 구조를 만들어, 필요할 때 필요한 정보만 참조할 수 있도록 Knowledge Graph 형태로 구성해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Single Source of Truth 원칙을 지켜야 한다.&lt;/b&gt; 정보가 외부 문서, Slack, 담당자의 머릿속 등에 파편화되어 있으면 에이전트는 일관되게 작동할 수 없다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;강한 구조적 제약이 필요하다.&lt;/b&gt; 아키텍처, lint 규칙, 폴더 구조, 접근 권한 설정은 선택이 아닌 필수다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리뷰도 에이전트가 수행한다.&lt;/b&gt; 리뷰 루프 자체가 자동화되는 방향으로 설계해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AI에게 관찰 능력을 제공해야 한다.&lt;/b&gt; QA 병목을 해소하려면 Playwright, UI 스냅샷, 로그, 메트릭, trace 등 에이전트가 스스로 확인할 수 있는 도구를 갖춰야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;피드백 루프가 핵심이다.&lt;/b&gt; &quot;실행 &amp;rarr; 관찰 &amp;rarr; 평가 &amp;rarr; 수정 &amp;rarr; 반복&quot;이 자동으로 작동한다면, 인간의 개입 없이도 기능 개발이 가능해진다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발 속도와 안정성의 균형이 재조정되고 있다.&lt;/b&gt; 기존에는 안정성 우선으로 코드 리뷰가 길게 이루어졌다. 현재는 속도를 우선하고, 문제가 생기면 빠르게 수정하는 방향으로 바뀌고 있다. AI를 활용하면 수정 비용이 거의 0에 가까워지기 때문이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Garbage Collection 설계가 필요하다.&lt;/b&gt; AI는 기존 패턴에 잘못된 것이 하나 들어가면 지속적으로 코드를 오염시킨다. 이를 자동으로 감지하고 정리하는 메커니즘이 반드시 필요하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시니어 개발자에게 요구되는 변화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 흐름 속에서 시니어 개발자에게 요구되는 역량은 다음과 같이 정리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제를 구조화하는 능력과 시스템 설계 능력&lt;/b&gt; AI가 이해하고 수행할 수 있도록 문제를 작게 쪼개고, 명세를 정확하게 작성하는 능력이 핵심 역량이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;좋은 코드의 기준 재정의&lt;/b&gt; AI가 이해하기 쉽고, 자동 수정 및 검증이 가능한 코드가 좋은 코드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 스킬의 변화&lt;/b&gt; 아키텍처 강제력 설계, 규칙 설계, 피드백 루프 설계, Observability 구축, 명세 작성 능력이 중요해지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;마인드셋의 전환&lt;/b&gt; &quot;내가 직접 해결한다&quot;에서 &quot;시스템이 해결하게 만든다&quot;로의 전환이 필요하다. 이것이 이 시대 엔지니어에게 요구되는 가장 근본적인 변화다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 에이전트는 이미 현장에 들어와 있다. 이 변화에서 살아남는 개발자는 코딩을 가장 잘하는 사람이 아니라, AI가 가장 잘 일할 수 있는 환경을 설계하는 사람일 가능성이 높다.&lt;/p&gt;</description>
      <category>Artificial Intelligence</category>
      <category>Agentic Engineering</category>
      <category>Context Engineering</category>
      <category>Harness Engineering</category>
      <category>open ai</category>
      <category>Prompt Engineering</category>
      <category>SSOT</category>
      <category>하네스 엔지니어링</category>
      <author>D.Y</author>
      <guid isPermaLink="true">https://ithub.tistory.com/449</guid>
      <comments>https://ithub.tistory.com/449#entry449comment</comments>
      <pubDate>Mon, 13 Apr 2026 16:00:29 +0900</pubDate>
    </item>
    <item>
      <title>AI 에이전트 시대, 설계와 TDD의 종말인가 진화인가?</title>
      <link>https://ithub.tistory.com/448</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 개발 패러다임이 급격하게 변하고 있다. AI 에이전트의 발전은 '코드를 작성하는 비용'을 비약적으로 낮추었으며, 이는 기존의 개발 방법론에 대한 근본적인 의문을 제기한다. 특히 설계 중심의 개발이나 테스트 주도 개발(TDD)이 여전히 유효한가에 대한 논의는 현시점 모든 개발자가 마주한 화두다.&lt;br /&gt;&lt;br /&gt;결론부터 말하자면, &lt;b&gt;코드는 저렴해졌으나 설계의 가치는 오히려 상승했으며, TDD는 방법론적 '절차'에서 전략적 '선택'으로 진화하고 있다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. 코드 생산 비용의 급감과 가치의 이동&lt;/b&gt;&lt;br /&gt;과거의&amp;nbsp;개발&amp;nbsp;프로세스에서&amp;nbsp;구현,&amp;nbsp;리팩토링,&amp;nbsp;테스트&amp;nbsp;코드&amp;nbsp;작성은&amp;nbsp;상당한&amp;nbsp;시간과&amp;nbsp;비용이&amp;nbsp;투입되는&amp;nbsp;영역이었다.&amp;nbsp;그러나&amp;nbsp;AI&amp;nbsp;에이전트의&amp;nbsp;등장으로&amp;nbsp;구현&amp;nbsp;비용은&amp;nbsp;분&amp;nbsp;단위로&amp;nbsp;단축되었고,&amp;nbsp;리팩토링과&amp;nbsp;테스트&amp;nbsp;생성&amp;nbsp;역시&amp;nbsp;자동화의&amp;nbsp;영역으로&amp;nbsp;들어왔다.&lt;br /&gt;&lt;br /&gt;이제 '어떻게 구현할 것인가(How)'에 대한 기술적 숙련도의 중요도는 낮아지고 있다. 대신 &lt;b&gt;'무엇을 해결할 것인가(What)'&lt;/b&gt;에 대한 &lt;b&gt;문제 정의 역량&lt;/b&gt;이 개발자의 핵심 가치로 부상했다. &lt;b&gt;즉, 코드 그 자체보다 시스템의 목적과 방향성을 설정하는 능력이 더욱 중요해진 것이다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. 설계의 재정의: 구현 상세에서 경계 설계로&lt;/b&gt;&lt;br /&gt;AI가&amp;nbsp;코드를&amp;nbsp;빠르게&amp;nbsp;양산할수록&amp;nbsp;시스템의&amp;nbsp;복잡도는&amp;nbsp;기하급수적으로&amp;nbsp;증가한다.&amp;nbsp;일관성&amp;nbsp;없는&amp;nbsp;구조,&amp;nbsp;모듈&amp;nbsp;간&amp;nbsp;경계의&amp;nbsp;모호함,&amp;nbsp;중복&amp;nbsp;로직의&amp;nbsp;범람은&amp;nbsp;AI가&amp;nbsp;가진&amp;nbsp;'국소&amp;nbsp;최적화'의&amp;nbsp;한계에서&amp;nbsp;기인한다.&amp;nbsp;시스템&amp;nbsp;전체의&amp;nbsp;일관성을&amp;nbsp;유지하는&amp;nbsp;능력은&amp;nbsp;여전히&amp;nbsp;인간&amp;nbsp;개발자의&amp;nbsp;영역에&amp;nbsp;머물러&amp;nbsp;있다.&lt;br /&gt;&lt;br /&gt;현대적 설계의 핵심은 클래스 내부의 상세 구현을 고민하는 것이 아니다. &lt;b&gt;도메인 모델을 정립하고, 서비스 간의 책임과 경계(Boundary)를 명확히 획정하며, AI가 준수해야 할 제약 조건을 설계하는 것&lt;/b&gt;으로 그 역할이 전이되었다. 즉, 설계는 구현을 위한 밑그림이 아니라 AI라는 강력한 엔진을 제어하는 가이드라인이 되어야 한다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. TDD의 전략적 후퇴와 테스트의 질적 변화&lt;/b&gt;&lt;br /&gt;모든&amp;nbsp;기능에&amp;nbsp;대해&amp;nbsp;테스트를&amp;nbsp;먼저&amp;nbsp;작성하는&amp;nbsp;전통적인&amp;nbsp;TDD의&amp;nbsp;효율성은&amp;nbsp;확실히&amp;nbsp;감소했다.&amp;nbsp;AI를&amp;nbsp;통해&amp;nbsp;구현과&amp;nbsp;테스트를&amp;nbsp;동시에&amp;nbsp;생성할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;된&amp;nbsp;시점에서,&amp;nbsp;Red-Green-Refactor&amp;nbsp;사이클을&amp;nbsp;고집하는&amp;nbsp;것은&amp;nbsp;자원&amp;nbsp;낭비일&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;&lt;br /&gt;하지만&amp;nbsp;테스트&amp;nbsp;자체의&amp;nbsp;중요성은&amp;nbsp;그&amp;nbsp;어느&amp;nbsp;때보다&amp;nbsp;높다.&amp;nbsp;AI가&amp;nbsp;작성한&amp;nbsp;코드의&amp;nbsp;신뢰성을&amp;nbsp;검증하는&amp;nbsp;'가드레일'로서의&amp;nbsp;역할이&amp;nbsp;필수적이기&amp;nbsp;때문이다.&lt;br /&gt;&lt;br /&gt;- TDD의 선별적 도입: 모든 영역이 아닌, 금융/정산 등 정합성이 치명적인 핵심 도메인 로직이나 버그 발생 비용이 큰 영역으로 TDD의 적용 범위를 한정해야 한다.&lt;br /&gt;- 테스트 전략의 고도화: 단순히 Happy Path를 검증하는 것을 넘어, AI가 놓치기 쉬운 Edge Case를 식별하고 시스템의 행동 명세를 정의하는 '전략적 검증'에 집중해야 한다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. AI 시대, 개발자의 핵심 역량&lt;/b&gt;&lt;br /&gt;앞으로의&amp;nbsp;개발자에게&amp;nbsp;요구되는&amp;nbsp;전문성은&amp;nbsp;다음의&amp;nbsp;네&amp;nbsp;가지로&amp;nbsp;요약된다.&lt;br /&gt;&lt;br /&gt;1.&amp;nbsp; &lt;b&gt;문제 구조화 능력:&lt;/b&gt; 모호한 비즈니스 요구사항을 AI가 이해할 수 있는 명확한 구조로 치환하는 능력.&lt;br /&gt;2.&amp;nbsp; &lt;b&gt;경계 설계 역량:&lt;/b&gt; 시스템의 응집도를 높이고 결합도를 낮추는 아키텍처 설계 및 책임 분리 능력.&lt;br /&gt;3.&amp;nbsp; &lt;b&gt;검증 전략 수립:&lt;/b&gt; 투자 대비 효율(ROI)이 높은 지점을 포착하여 집중적으로 검증하는 판단력.&lt;br /&gt;4.&amp;nbsp; &lt;b&gt;코드 리뷰 및 감별:&lt;/b&gt; AI가 생성한 결과물에서 잠재적인 결함과 구조적 결을 읽어내는 안목.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;결론: 효율을 넘어 본질로&lt;/b&gt;&lt;br /&gt;&quot;설계와 TDD가 불필요해졌다&quot;는 진단은 오판이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;설계는 더 고도화되었고, TDD는 고정된 규범에서 상황에 따른 고급 전략으로 변화했다&quot;&lt;/b&gt;고 생각한다.&lt;br /&gt;&lt;br /&gt;코드&amp;nbsp;작성이&amp;nbsp;쉬워진&amp;nbsp;만큼&amp;nbsp;개발자는&amp;nbsp;더&amp;nbsp;높은&amp;nbsp;차원의&amp;nbsp;사고에&amp;nbsp;집중할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;여력을&amp;nbsp;얻었다.&amp;nbsp;구현의&amp;nbsp;늪에서&amp;nbsp;벗어나&amp;nbsp;시스템의&amp;nbsp;본질을&amp;nbsp;설계하고,&amp;nbsp;어디가&amp;nbsp;깨질&amp;nbsp;것인지를&amp;nbsp;예측하며,&amp;nbsp;전체적인&amp;nbsp;흐름을&amp;nbsp;제어하는&amp;nbsp;&lt;b&gt;'시스템&amp;nbsp;아키텍트'&lt;/b&gt;로서의&amp;nbsp;면모를&amp;nbsp;갖추는&amp;nbsp;것이&amp;nbsp;AI&amp;nbsp;시대&amp;nbsp;개발자가&amp;nbsp;생존하고&amp;nbsp;증명해야&amp;nbsp;할&amp;nbsp;전문성이다.&lt;/p&gt;</description>
      <category>Artificial Intelligence</category>
      <category>AI</category>
      <category>ai agent</category>
      <category>ai 에이전트</category>
      <category>Architecture</category>
      <category>Software Engineer</category>
      <category>TDD</category>
      <category>미래 개발자</category>
      <category>아키텍트</category>
      <category>테스트</category>
      <author>D.Y</author>
      <guid isPermaLink="true">https://ithub.tistory.com/448</guid>
      <comments>https://ithub.tistory.com/448#entry448comment</comments>
      <pubDate>Fri, 3 Apr 2026 10:11:20 +0900</pubDate>
    </item>
    <item>
      <title>Flyway - DB 마이그레이션 전략</title>
      <link>https://ithub.tistory.com/447</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 스키마 변경은 애플리케이션 개발에서 피할 수 없는 일이다. 문제는 이 변경을 어떻게 관리하느냐에 있다. Flyway는 데이터베이스 스키마 변경을 코드처럼 버전 관리할 수 있게 해주는 오픈소스 DB 마이그레이션 도구로, 개발팀이 DB 구조 변경 사항을 체계적으로 추적하고 모든 환경에 일관되게 적용할 수 있도록 설계되었다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 왜 Flyway가 필요한가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB를 수동으로 관리하는 조직에서는 다음과 같은 문제가 반복적으로 발생한다.&lt;/p&gt;
&lt;p&gt;문제 설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;스키마 불일치&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;팀원마다 로컬 DB가 달라 &quot;내 환경에서는 정상 동작한다&quot;는 상황이 발생한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;수동 실행 의존&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;SQL을 직접 공유하거나 문서화해야 하며, 누락 위험이 상존한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;이력 불투명&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;특정 테이블이 언제, 왜 변경되었는지 추적이 불가능하다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;환경 재현 불가&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;신규 팀원 온보딩이나 서버 셋업 시 스키마를 일치시키기 어렵다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flyway는 이 문제들에 대해 명쾌한 해법을 제시한다. &lt;b&gt;모든 DB 변경을 번호가 붙은 SQL 파일로 관리하고, 애플리케이션 실행 시 자동으로 순서대로 적용하는 것이다.&lt;/b&gt; 즉, DB 변경 사항이 곧 SQL 파일이고, 이 파일은 Git으로 관리된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 핵심 개념&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마이그레이션 파일 네이밍 규칙&lt;/h3&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;V{버전}__{설명}.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 프로젝트에서는 다음과 같은 구조가 된다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;db/migration/
├── V1__init_schema.sql
├── V2__add_user_table.sql
├── V3__add_email_column.sql
└── V4__add_index_on_email.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버전 번호는 반드시 유니크해야 하며, 접두사와 설명 사이의 언더스코어는 &lt;b&gt;두 개&lt;/b&gt;(__)라는 점에 유의해야 한다. 사소해 보이지만, 실무에서 한 개만 사용하여 마이그레이션이 인식되지 않는 실수가 의외로 빈번하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마이그레이션 파일 종류&lt;/h3&gt;
&lt;p&gt;접두사 이름 특징 예시&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;V&lt;/td&gt;
&lt;td&gt;Versioned&lt;/td&gt;
&lt;td&gt;한 번만 실행되며, 주력으로 사용한다&lt;/td&gt;
&lt;td&gt;V1__create_table.sql&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;U&lt;/td&gt;
&lt;td&gt;Undo&lt;/td&gt;
&lt;td&gt;롤백 용도 (유료 기능)&lt;/td&gt;
&lt;td&gt;U1__drop_table.sql&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;Repeatable&lt;/td&gt;
&lt;td&gt;내용이 변경되면 재실행된다&lt;/td&gt;
&lt;td&gt;R__create_view.sql&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 V 접두사 파일이 대부분을 차지한다. R 접두사는 뷰(View)나 저장 프로시저처럼 매번 재생성해도 무방한 객체에 적합하다. U 접두사의 Undo 기능은 유료 플랜에서만 제공되므로, 무료 버전을 사용하는 경우 롤백 전략을 별도로 수립해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;flyway_schema_history 테이블&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flyway는 자체적으로 이력 관리 테이블을 생성하여 어떤 마이그레이션이 언제, 어떤 순서로 적용되었는지를 기록한다.&lt;/p&gt;
&lt;p&gt;installed_rank version description script checksum success&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;init schema&lt;/td&gt;
&lt;td&gt;V1__init_schema.sql&lt;/td&gt;
&lt;td&gt;12345678&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;add user table&lt;/td&gt;
&lt;td&gt;V2__add_user_table.sql&lt;/td&gt;
&lt;td&gt;87654321&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;add email column&lt;/td&gt;
&lt;td&gt;V3__add_email_column.sql&lt;/td&gt;
&lt;td&gt;11223344&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 주목할 것은 &lt;b&gt;checksum&lt;/b&gt; 컬럼이다. Flyway는 각 파일의 체크섬을 저장해두고, 이미 적용된 파일이 사후에 변경되면 즉시 오류를 발생시킨다. 이 메커니즘이 마이그레이션 이력의 무결성을 보장하는 핵심 장치이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 동작 방식&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;최초 실행&lt;/h3&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;앱 시작
  -&amp;gt; Flyway가 flyway_schema_history 테이블 부재를 확인
  -&amp;gt; 테이블을 자동 생성
  -&amp;gt; db/migration 폴더에서 V*.sql 파일을 탐색
  -&amp;gt; 버전 순서대로 SQL을 실행
  -&amp;gt; 각 실행 결과를 history 테이블에 기록
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;두 번째 이후 실행&lt;/h3&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;앱 시작
  -&amp;gt; flyway_schema_history 테이블을 확인
  -&amp;gt; 이미 실행된 파일은 건너뜀
  -&amp;gt; 새로 추가된 파일만 실행
  -&amp;gt; 실행 완료 후 history에 기록
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 구조 덕분에 개발자는 새로운 마이그레이션 파일만 추가하면 된다. Flyway가 &quot;어디까지 실행했는지&quot;를 알고 있으므로, 나머지는 자동으로 처리된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;파일 변조 감지&lt;/h3&gt;
&lt;pre class=&quot;erlang-repl&quot;&gt;&lt;code&gt;기존 V2__add_user_table.sql의 내용을 수정
  -&amp;gt; Flyway가 체크섬 불일치를 감지
  -&amp;gt; ERROR: Migration checksum mismatch!
  -&amp;gt; 앱 실행을 중단
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 동작은 의도된 설계이다. 한번 적용된 마이그레이션을 사후에 수정하는 것은 환경 간 스키마 불일치를 초래하므로, Flyway는 이를 원천적으로 차단한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Spring Boot 연동&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot 프로젝트에서 Flyway를 도입하는 과정은 놀라울 정도로 간결하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;의존성 추가 (build.gradle)&lt;/h3&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;implementation 'org.flywaydb:flyway-core'
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마이그레이션 파일 배치&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;src/main/resources/db/migration/
├── V1__init_schema.sql
├── V2__add_user_table.sql
└── V3__add_email_column.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;application.yml 설정&lt;/h3&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;spring:
  flyway:
    enabled: true
    locations: classpath:db/migration
    baseline-on-migrate: true    # 기존 DB에 처음 Flyway를 적용할 때
    out-of-order: false           # 버전 순서를 강제한다
    validate-on-migrate: true     # 체크섬 검증을 활성화한다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;baseline-on-migrate 옵션은 이미 운영 중인 DB에 Flyway를 사후 도입할 때 필수적인 설정이다. 이 옵션이 true이면 Flyway는 현재 DB 상태를 기준선(baseline)으로 설정하고, 이후 추가되는 마이그레이션만 실행한다. 신규 프로젝트라면 이 옵션 없이 시작해도 무방하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot에서는 애플리케이션 시작 시 마이그레이션이 자동으로 실행되므로, 별도의 수동 개입이 필요하지 않다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 주요 CLI 명령어&lt;/h2&gt;
&lt;p&gt;명령어 설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;flyway migrate&lt;/td&gt;
&lt;td&gt;미실행 마이그레이션을 순서대로 실행한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flyway info&lt;/td&gt;
&lt;td&gt;현재 마이그레이션 상태를 조회한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flyway validate&lt;/td&gt;
&lt;td&gt;파일 변조 여부 및 체크섬을 검증한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flyway repair&lt;/td&gt;
&lt;td&gt;실패한 마이그레이션 이력을 수정한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flyway baseline&lt;/td&gt;
&lt;td&gt;기존 DB를 특정 버전 기준으로 초기화한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flyway clean&lt;/td&gt;
&lt;td&gt;모든 테이블을 삭제한다 (운영 환경에서는 절대 사용 금지)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;repair 명령어는 마이그레이션 실행 중 오류가 발생하여 history 테이블에 실패 기록이 남았을 때 유용하다. 원인을 해결한 후 repair로 실패 이력을 정리하고, migrate를 다시 실행하는 것이 일반적인 복구 절차이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 실무 주의사항&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flyway를 운영하면서 체감한 규칙들을 정리한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;기존 파일은 절대 수정하지 않는다.&lt;/b&gt; 체크섬 불일치로 애플리케이션 기동이 실패한다. 수정이 필요하면 반드시 새 버전 파일을 추가한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;버전 번호는 유니크하게 유지한다.&lt;/b&gt; 동일한 버전 번호를 가진 파일이 두 개 이상 존재하면 오류가 발생한다. 여러 개발자가 동시에 작업할 경우, 타임스탬프 기반 버전 번호(예: V20260326_1430__description.sql)를 사용하면 충돌을 줄일 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;flyway clean은 운영 환경에서 절대 사용하지 않는다.&lt;/b&gt; 이 명령은 모든 테이블을 삭제한다. Spring Boot 설정에서 spring.flyway.clean-disabled=true를 운영 프로파일에 명시해 두는 것이 안전하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DB 접속 정보를 마이그레이션 파일이나 설정 파일에 직접 노출하지 않는다.&lt;/b&gt; 환경 변수나 Vault를 통해 주입하는 방식을 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;마이그레이션 파일에는 DDL만 포함하는 것을 원칙으로 한다.&lt;/b&gt; DML(데이터 조작)이 필요한 경우, 해당 파일의 설명에 데이터 변경임을 명시하고 트랜잭션 안전성을 반드시 확인한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. Flyway vs Liquibase&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB 마이그레이션 도구를 선정할 때 Flyway와 함께 거론되는 것이 Liquibase이다.&lt;/p&gt;
&lt;p&gt;항목 Flyway Liquibase&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;문법&lt;/td&gt;
&lt;td&gt;SQL 위주로 직관적이다&lt;/td&gt;
&lt;td&gt;XML, YAML, JSON, SQL을 모두 지원한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;학습 곡선&lt;/td&gt;
&lt;td&gt;낮다&lt;/td&gt;
&lt;td&gt;상대적으로 높다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;롤백&lt;/td&gt;
&lt;td&gt;유료 플랜에서 제공한다&lt;/td&gt;
&lt;td&gt;무료로 지원한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;커뮤니티&lt;/td&gt;
&lt;td&gt;활발하다&lt;/td&gt;
&lt;td&gt;활발하다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;적합한 상황&lt;/td&gt;
&lt;td&gt;소~중규모 프로젝트에서 빠르게 도입할 때&lt;/td&gt;
&lt;td&gt;복잡한 엔터프라이즈 환경에서&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flyway의 장점은 SQL을 그대로 사용한다는 점이다. 별도의 DSL을 학습할 필요 없이, DBA가 작성한 SQL을 그대로 마이그레이션 파일로 사용할 수 있다. 반면 Liquibase는 DB 벤더에 독립적인 추상화 레이어를 제공하므로, 다중 DB를 지원해야 하는 환경에서는 Liquibase가 더 적합할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flyway의 본질은 단순하다. &quot;DB 변경을 파일로 만들고, 순서대로 실행하고, 한번 실행한 것은 건드리지 않는다.&quot; 이 세 가지 원칙만 지키면 환경 간 스키마 불일치, 변경 이력 추적 불가, 수동 배포 의존이라는 고질적인 문제에서 벗어날 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 자료&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://documentation.red-gate.com/flyway&quot;&gt;Flyway 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-initialization.migration-tool.flyway&quot;&gt;Spring Boot + Flyway 가이드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>데이터베이스</category>
      <category>DB</category>
      <category>DB Migration</category>
      <category>flyway</category>
      <category>liquibase</category>
      <category>Schema</category>
      <category>sql</category>
      <category>스키마</category>
      <author>D.Y</author>
      <guid isPermaLink="true">https://ithub.tistory.com/447</guid>
      <comments>https://ithub.tistory.com/447#entry447comment</comments>
      <pubDate>Thu, 26 Mar 2026 13:55:48 +0900</pubDate>
    </item>
    <item>
      <title>DB에 JSON 데이터를 저장하는 두 가지 방법: JSON 타입 vs TEXT 타입</title>
      <link>https://ithub.tistory.com/446</link>
      <description>&lt;h1&gt;문제의 출발점&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션에서 구조화된 데이터를 하나의 컬럼에 통째로 저장해야 하는 경우가 있다. 설정값, 메타데이터, 가변적인 속성 목록 등이 대표적이다. 이때 선택지는 크게 두 가지로 나뉜다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스가 제공하는 &lt;b&gt;JSON/JSONB 타입&lt;/b&gt;을 사용하는 방법&lt;/li&gt;
&lt;li&gt;일반 &lt;b&gt;TEXT 타입&lt;/b&gt;에 JSON 문자열을 그대로 저장하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 방식 모두 현업에서 널리 쓰이며, 어느 쪽이 절대적으로 우월하다고 말하기는 어렵다. 상황에 따라 적합한 선택이 달라지기 때문이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;JSON/JSONB 타입으로 저장하는 경우&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL의 jsonb, MySQL 8.0+의 JSON 등 주요 RDBMS는 JSON 전용 컬럼 타입을 지원한다. 단순히 문자열로 저장하는 것이 아니라, DB 엔진이 JSON 구조를 인식하고 파싱한 상태로 보관한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;장점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 데이터 무결성 보장&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;INSERT/UPDATE 시점에 DB가 JSON 유효성을 자동으로 검증한다. 잘못된 형식의 데이터가 저장되는 것 자체를 원천 차단할 수 있다. TEXT 타입에서는 애플리케이션 레이어에서만 이를 검증할 수 있으므로, 버그나 직접 SQL 실행 등으로 잘못된 데이터가 유입될 가능성이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. JSON 내부 필드 쿼리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON 내부의 특정 키에 대해 직접 조건절을 작성할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;oxygene&quot;&gt;&lt;code&gt;-- PostgreSQL 예시: 변수 목록에서 type이 'FORMULA'인 step 조회
SELECT * FROM recipe_steps
WHERE variable_metadata::jsonb @&amp;gt; '[{&quot;type&quot;: &quot;FORMULA&quot;}]';
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TEXT 타입에서는 LIKE '%FORMULA%'와 같은 문자열 패턴 매칭에 의존해야 하며, 이는 정확도와 성능 양면에서 불리하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 인덱싱 지원&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL의 jsonb는 GIN 인덱스를 생성할 수 있어, JSON 내부 필드에 대한 검색 성능을 크게 향상시킬 수 있다.&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;CREATE INDEX idx_variable_metadata ON recipe_steps
USING GIN (variable_metadata jsonb_path_ops);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 저장 공간 효율 (JSONB 한정)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PostgreSQL jsonb는 바이너리 형태로 저장하므로, 키 중복 제거와 압축이 적용되어 TEXT 대비 저장 공간이 절약된다. 또한 읽기 시 파싱 비용이 들지 않는다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. DB 간 호환성 부족&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON 타입의 문법과 기능은 DB 벤더마다 상이하다. PostgreSQL의 jsonb 연산자(-&amp;gt;, -&amp;gt;&amp;gt;, @&amp;gt;)는 MySQL이나 H2에서 동작하지 않는다. 테스트 환경에서 H2를 사용하고 운영에서 PostgreSQL을 사용하는 경우, JSON 타입 컬럼은 호환성 문제를 일으킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. ORM 매핑의 복잡성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA/Hibernate에서 jsonb 컬럼을 매핑하려면 별도의 설정이 필요하다. @JdbcTypeCode(SqlTypes.JSON) 어노테이션을 사용하거나, hypersistence-utils 같은 서드파티 라이브러리를 추가해야 한다. 단순한 String 필드에 columnDefinition = &quot;TEXT&quot;를 지정하는 것에 비하면 진입 장벽이 높다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 쓰기 성능 오버헤드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jsonb는 저장 시 파싱과 바이너리 변환 과정을 거치므로, 단순 TEXT 저장보다 쓰기 비용이 높다. 빈번한 갱신이 발생하는 컬럼에서는 이 차이가 누적될 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;TEXT 타입으로 저장하는 경우&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON 문자열을 있는 그대로 TEXT 컬럼에 저장하는 방식이다. DB 입장에서는 일반 문자열과 다를 바 없으며, JSON 파싱과 검증은 전적으로 애플리케이션의 책임이 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;장점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. DB 독립성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TEXT는 모든 RDBMS에서 동일하게 지원된다. 운영 DB와 테스트 DB가 다른 벤더를 사용하더라도 문제가 없다. 예를 들어, 운영에서 PostgreSQL을 쓰고 테스트에서 H2 인메모리 DB를 쓰는 구조에서 TEXT 컬럼은 아무런 호환성 이슈 없이 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. ORM 매핑의 단순함&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 String 필드에 @Column(columnDefinition = &quot;TEXT&quot;)만 선언하면 끝이다. 별도의 타입 변환기, 서드파티 라이브러리, DB별 방언 설정이 전혀 필요 없다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@Column(name = &quot;variable_metadata&quot;, columnDefinition = &quot;TEXT&quot;)
private String variableMetadata;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 쓰기 성능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파싱이나 바이너리 변환 없이 문자열을 그대로 저장하므로 쓰기 속도가 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 유연성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB가 JSON 구조를 강제하지 않으므로, 스키마 변경 없이 JSON 구조를 자유롭게 변경할 수 있다. 과도기적 데이터 마이그레이션 시에도 유연하게 대처할 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 무결성 미보장&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB는 컬럼에 어떤 문자열이 들어오든 허용한다. 잘못된 JSON, 빈 문자열, HTML 등이 저장되어도 DB 레벨에서 막을 수 없다. 데이터 품질은 전적으로 애플리케이션 코드에 의존하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 내부 필드 검색 불가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON 내부의 특정 키를 조건으로 검색하려면 LIKE 또는 정규식을 사용해야 하며, 이는 정확성도 낮고 인덱스를 활용하지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 읽기 시 파싱 비용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 조회할 때마다 애플리케이션에서 JSON 파싱을 수행해야 한다. jsonb는 이미 파싱된 상태로 저장되므로 읽기 시 추가 비용이 없지만, TEXT는 매번 ObjectMapper.readValue() 등을 호출해야 한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;비교 요약&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기준 JSON/JSONB 타입 TEXT 타입&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DB 레벨 유효성 검증&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;내부 필드 쿼리&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GIN 인덱스&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB 간 호환성&lt;/td&gt;
&lt;td&gt;제한적&lt;/td&gt;
&lt;td&gt;완전 호환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ORM 매핑 복잡도&lt;/td&gt;
&lt;td&gt;높음&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;쓰기 성능&lt;/td&gt;
&lt;td&gt;상대적으로 느림&lt;/td&gt;
&lt;td&gt;빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;읽기 시 파싱 비용&lt;/td&gt;
&lt;td&gt;없음 (이미 파싱)&lt;/td&gt;
&lt;td&gt;매번 파싱 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;저장 공간 효율&lt;/td&gt;
&lt;td&gt;좋음 (JSONB)&lt;/td&gt;
&lt;td&gt;보통&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;어떤 경우에 무엇을 선택할 것인가&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TEXT가 적합한 경우&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 통째로 읽고 쓰기만 하고, DB에서 JSON 내부를 쿼리할 일이 없는 경우&lt;/li&gt;
&lt;li&gt;운영 DB와 테스트 DB가 다른 벤더를 사용하며, 호환성이 중요한 경우&lt;/li&gt;
&lt;li&gt;ORM 설정을 단순하게 유지하고 싶은 경우&lt;/li&gt;
&lt;li&gt;JSON 스키마가 자주 변경되는 초기 개발 단계&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;JSON/JSONB가 적합한 경우&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB 레벨에서 JSON 내부 필드를 조건으로 검색해야 하는 경우&lt;/li&gt;
&lt;li&gt;데이터 무결성이 비즈니스 요구사항 수준에서 중요한 경우 (예: 규제 환경)&lt;/li&gt;
&lt;li&gt;동일 DB 벤더를 운영/테스트 모두에서 사용하는 경우&lt;/li&gt;
&lt;li&gt;저장된 JSON이 크고, 부분 읽기/업데이트가 필요한 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;실무 적용 사례&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EBR(Electronic Batch Record) 시스템에서는 레시피 단계(Step)별 변수 목록을 variable_metadata 컬럼에 JSON 배열로 저장하고 있다. 이 필드는 다음과 같은 특성을 가진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Step 단위로 통째로 읽고 쓴다&lt;/li&gt;
&lt;li&gt;DB에서 JSON 내부를 쿼리하지 않는다&lt;/li&gt;
&lt;li&gt;운영은 PostgreSQL, 테스트는 H2를 사용한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 조건에서 TEXT 타입은 합리적인 선택이다. H2 호환성을 유지하면서 ORM 매핑을 단순하게 가져갈 수 있기 때문이다. 만약 향후 &quot;특정 타입의 변수를 포함하는 Step을 검색&quot;하는 요구사항이 발생한다면, 그때 jsonb로 전환하는 것이 YAGNI 원칙에도 부합하는 접근이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;결론&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON 데이터의 저장 방식은 &quot;정답&quot;이 아니라 &quot;맥락에 따른 선택&quot;의 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB가 JSON을 이해할 필요가 있는가, 여러 DB 벤더를 지원해야 하는가, ORM 복잡도를 얼마나 감수할 수 있는가 이 세 가지 질문에 대한 답이 선택의 기준이 된다. 현재 필요하지 않은 기능을 위해 복잡성을 도입하기보다는, 실제 요구사항이 발생했을 때 전환하는 편이 대부분의 경우 더 나은 전략이다.&lt;/p&gt;</description>
      <category>데이터베이스</category>
      <category>DB</category>
      <category>JSON</category>
      <category>JSONB</category>
      <category>rdbms</category>
      <category>Text</category>
      <category>데이터베이스</category>
      <author>D.Y</author>
      <guid isPermaLink="true">https://ithub.tistory.com/446</guid>
      <comments>https://ithub.tistory.com/446#entry446comment</comments>
      <pubDate>Thu, 26 Mar 2026 13:31:49 +0900</pubDate>
    </item>
    <item>
      <title>[주간 IT 동향] 2026-03-16 ~ 03-19: NVIDIA GTC 2026 총정리, Groq 3 LPU 공개, 에이전트 보안의 &amp;quot;Sudo 레이어&amp;quot;</title>
      <link>https://ithub.tistory.com/445</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;TL;DR&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NVIDIA GTC 2026 키노트에서 Jensen Huang이 Blackwell+Vera Rubin 주문량이 2027년까지 1조 달러에 달할 것으로 전망했다. 지난해 5,000억 달러 전망의 2배다&lt;/li&gt;
&lt;li&gt;Groq 3 LPU가 NVIDIA 최초의 추론 전용 칩으로 공개되었다. 200억 달러에 인수한 Groq 기술을 기반으로, Vera Rubin GPU 옆에 256개 LPU를 탑재하는 LPX 랙이 Q3에 출하된다&lt;/li&gt;
&lt;li&gt;NemoClaw가 OpenClaw의 엔터프라이즈 레퍼런스 스택으로 발표되면서, NVIDIA가 에이전트 경제의 인프라 레이어를 장악하려는 전략이 명확해졌다&lt;/li&gt;
&lt;li&gt;AI 에이전트에 &quot;Sudo 레이어&quot;를 구축해야 한다는 주장이 등장했다. Regex 기반 필터링의 한계를 넘어, 결정론적(deterministic) 권한 통제가 에이전트 보안의 핵심 패턴으로 부상하고 있다&lt;/li&gt;
&lt;li&gt;OpenSearch 3.5가 agentic conversation memory를 지원하면서, 에이전트 워크로드를 위한 데이터 인프라가 빠르게 진화하고 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. NVIDIA GTC 2026: 에이전트 경제의 인프라를 선점하다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주 IT 업계의 모든 시선이 산호세에 쏠렸다. Jensen Huang의 2시간 키노트는 단순한 제품 발표를 넘어, NVIDIA가 AI 경제의 &quot;운영 레이어&quot;가 되겠다는 전략을 명확히 한 자리였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 큰 숫자부터 보자. Jensen은 Blackwell과 Vera Rubin 시스템의 주문량이 2027년까지 1조 달러에 달할 것으로 전망했다. 지난해 가을 GTC에서 제시한 5,000억 달러의 정확히 2배다. AI 인프라 투자가 둔화될 것이라는 우려에 대한 NVIDIA의 대답은 &quot;오히려 가속&quot;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어 측면에서 가장 주목할 발표는 Groq 3 LPU다. 이것은 NVIDIA가 작년 200억 달러에 인수한 Groq 기술을 기반으로 한 최초의 추론 전용 칩이다. Q3에 출하 예정이며, 256개 LPU를 탑재하는 Groq 3 LPX 랙은 Vera Rubin 랙 옆에 배치되도록 설계되었다. 학습은 GPU, 추론은 LPU라는 이분화된 AI 컴퓨팅 아키텍처가 NVIDIA 내부에서 공식화된 것이다. Google TPU, AMD, 그리고 자체 추론 칩을 개발하는 클라우드 업체들에 대한 NVIDIA의 직접적인 견제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vera Rubin NVLink 72도 무대에 올랐다. Jensen은 &quot;10년간 4,000만 배의 컴퓨팅 증가&quot;라고 표현했고, &quot;초고성능 싱글스레드 AI 성능을 위해 완전히 새로운 CPU를 설계했다&quot;고 밝혔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 측면에서는 NemoClaw가 핵심이다. 이것은 OpenClaw를 &quot;엔터프라이즈 레디&quot;로 만들기 위한 레퍼런스 스택이다. Jensen은 &quot;OpenClaw를 찾아서 다운로드하고, AI 에이전트를 빌드해준다&quot;고 설명했다. Nemotron Coalition이라는 오픈 프론티어 모델 연합도 발표되었는데, Perplexity, Reflection, Black Forest Labs 등이 참여한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jensen은 엔지니어에게 연봉과 함께 연간 AI 토큰 예산을 지급하자고 제안했다. 토큰이 전기나 컴퓨팅 자원처럼 핵심 업무 인프라가 되었다는 인식의 전환이다. 실리콘밸리에서 면접 시 &quot;추론 용량을 얼마나 배정받느냐&quot;를 묻는 후보가 늘고 있다는 관측도 나왔다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 에이전트 보안의 새로운 패러다임: &quot;Sudo 레이어&quot;와 OpenShell&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주 에이전트 보안 영역에서 두 가지 중요한 논의가 등장했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, &quot;Why Regex is Not Enough: Building a Deterministic 'Sudo' Layer for AI Agents&quot;라는 기사다. Claude Code로 오래된 프로젝트를 정리하다가 &quot;디스크가 꽉 찼는데 정리 좀 해줘&quot;라고 프롬프트했더니, 에이전트가 docker system prune을 포함한 공격적인 정리 명령을 제안한 경험에서 출발한다. 핵심 주장은 regex 기반 명령어 필터링으로는 에이전트의 위험한 행동을 막을 수 없다는 것이다. 대신, 리눅스의 sudo처럼 결정론적(deterministic)인 권한 통제 레이어가 필요하다. 에이전트가 특정 임계치를 넘는 행위를 하려면 명시적 승인을 받아야 하는 구조다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, &quot;NVIDIA OpenShell and the Rise of Agent Sandboxes in Agentic DevOps&quot;라는 기사다. GTC 2026에서 발표된 OpenShell을 에이전트 샌드박스의 맥락에서 분석한다. 에이전트를 베어메탈에서 실행하는 것이 왜 위험한지, 그리고 3계층 방어 아키텍처(instructions, hooks, gates)가 247개 커밋, 100% 테스트 커버리지, 제로 롤백을 달성한 경험을 공유한다. 지난주 Docker NanoClaw + Sandboxes, AWS Nitro Enclaves 레퍼런스와 함께, 에이전트 격리 실행이 &quot;선택&quot;이 아닌 &quot;기본값&quot;이 되어야 한다는 합의가 형성되고 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. AWS 보안 에이전트와 에이전틱 인프라의 확장&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS에서 이번 주 주목할 두 가지 업데이트가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, AWS Security Agent가 침투 테스트 보고서 다운로드를 지원하기 시작했다. 보고서에는 경영진 요약, 테스트 범위, 방법론, 태스크 상세, 취약점 분석이 포함되며 필터 기반 커스터마이징이 가능하다. 에이전트가 보안 테스트를 자동 수행하고, 그 결과를 사람이 검토 가능한 형태로 산출하는 패턴이 정착되고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, Amazon Inspector가 에이전트 없는 EC2 스캐닝을 확장하면서 Windows OS 취약점 스캐닝도 지원하게 되었다. WordPress, Apache HTTP Server, Python 패키지, Ruby gems까지 커버리지가 넓어졌다. 에이전트리스(agentless) 보안 스캐닝이 멀티 OS, 멀티 런타임으로 확장되는 추세다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenSearch 3.5도 에이전틱 AI 기능을 대폭 강화했다. Agentic conversation memory가 대화 컨텍스트와 도구 호출 결과를 캡처하면서, 에이전트 워크로드를 위한 검색 엔진으로의 진화를 보여준다. 에이전트가 과거 대화를 기억하고 맥락에 맞는 검색을 수행하는 것이 인프라 레벨에서 지원되기 시작한 것이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Kubernetes Image Promoter 재작성과 인프라 신뢰성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;registry.k8s.io에서 풀하는 모든 컨테이너 이미지는 kpromo(Kubernetes Image Promoter)를 통해 배포된다. 이 도구가 이번 주 대대적으로 재작성되었다. 스테이징에서 프로덕션으로 이미지를 복사하고, cosign으로 서명하고, 20개 이상 리전 미러에 시그니처를 복제하고, SLSA provenance attestation을 생성하는 전 과정이 대상이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;눈에 보이지 않는 인프라이지만, Kubernetes 생태계 전체의 공급망 보안에 직접 영향을 미치는 핵심 컴포넌트다. 소프트웨어 공급망 보안이 더 이상 선택이 아닌 기본 요구사항이 된 시대에, 이런 &quot;보이지 않는 재작성&quot;이 실제로 가장 중요한 작업인 경우가 많다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이번 주 주목할 기술 동향&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Lambda AZ 메타데이터 지원&lt;/b&gt;: Lambda 함수가 실행 중인 Availability Zone ID를 알 수 있게 되면서, same-AZ 라우팅으로 cross-AZ 레이턴시를 줄이는 것이 가능해졌다. 에이전트 워크로드의 지연 최적화에 직접 활용 가능하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;멀티클라우드 에이전트 배포&lt;/b&gt;: VPN 없이 AWS, GCP, Azure에 걸쳐 에이전트를 배포하는 방법이 2줄 명령어로 단순화되는 도구가 등장했다. 크로스클라우드 에이전트 오케스트레이션의 진입장벽이 낮아지고 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Amazon ECR Chainguard Pull Through Cache&lt;/b&gt;: 보안 강화된 컨테이너 이미지 공급원으로 Chainguard가 ECR pull through cache에 추가되었다. 컨테이너 공급망 보안의 선택지가 확대된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Redshift 신규 쿼리 성능 최대 7배 향상&lt;/b&gt;: BI 대시보드, ETL, 그리고 &quot;자율적 목표 추구형 AI 에이전트&quot;의 SQL 쿼리 성능이 크게 개선되었다. AWS가 에이전트 워크로드를 데이터 인프라 최적화의 기준으로 삼고 있다는 신호다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모바일 DevOps 대시보드&lt;/b&gt;: Docker 컨테이너를 폰에서 SSH 없이 관리하는 모바일 대시보드가 등장했다. 저녁 식사 중 Telegram 알림 받고 6인치 화면에서 docker ps 치는 고통에서 해방.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cnbc.com/2026/03/16/nvidia-gtc-2026-ceo-jensen-huang-keynote-blackwell-vera-rubin.html&quot;&gt;Nvidia GTC 2026 CEO Jensen Huang keynote &amp;mdash; CNBC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tomshardware.com/news/live/nvidia-gtc-2026-keynote-live-blog-jensen-huang&quot;&gt;Nvidia GTC 2026 keynote live blog &amp;mdash; Tom's Hardware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.eweek.com/news/nvidia-gtc-2026-keynote-jensen-huang/&quot;&gt;At GTC 2026, Jensen Huang Shows How Nvidia Plans to Run the 'Full AI Stack' &amp;mdash; eWeek&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.techradar.com/pro/live/nvidia-gtc-2026-live-coverage-all-the-news-and-updates-as-it-happens&quot;&gt;GTC 2026 live coverage &amp;mdash; TechRadar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/htekdev/nvidia-openshell-and-the-rise-of-agent-sandboxes-in-agentic-devops-1a6o&quot;&gt;NVIDIA OpenShell and the Rise of Agent Sandboxes &amp;mdash;&lt;/a&gt; &lt;a href=&quot;http://dev.to&quot;&gt;dev.to&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/node9_ai/why-regex-is-not-enough-building-a-deterministic-sudo-layer-for-ai-agents-2fjm&quot;&gt;Why Regex is Not Enough: Building a Deterministic &quot;Sudo&quot; Layer &amp;mdash;&lt;/a&gt; &lt;a href=&quot;http://dev.to&quot;&gt;dev.to&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2026/03/aws-security-agent-generates-customizable/&quot;&gt;AWS Security Agent penetration testing reports &amp;mdash; AWS Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2026/03/amazon-inspector-agentless-ec2-scanning-windows/&quot;&gt;Amazon Inspector agentless EC2 scanning &amp;mdash; AWS Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/blog/2026/03/17/image-promoter-rewrite/&quot;&gt;The Invisible Rewrite: Modernizing the Kubernetes Image Promoter &amp;mdash; Kubernetes Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2026/03/amazon-opensearch-service-version-3-5/&quot;&gt;OpenSearch 3.5 agentic AI capabilities &amp;mdash; AWS Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/teoslayer/deploy-agents-across-aws-gcp-and-azure-no-vpn-4n0k&quot;&gt;Deploy Agents Across AWS, GCP, and Azure &amp;mdash;&lt;/a&gt; &lt;a href=&quot;http://dev.to&quot;&gt;dev.to&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2026/03/amazon-ecr-pull-through-cache-chainguard/&quot;&gt;Amazon ECR pull through cache for Chainguard &amp;mdash; AWS Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2026/03/lambda-availability-zone-metadata/&quot;&gt;Lambda Availability Zone metadata &amp;mdash; AWS Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2026/03/amazon-redshift-increases-performance-for-new-queries/&quot;&gt;Amazon Redshift performance 7x improvement &amp;mdash; AWS Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/bigabou007dev/i-built-a-mobile-devops-dashboard-because-managing-docker-from-my-phone-shouldnt-require-ssh-4j6n&quot;&gt;Mobile DevOps Dashboard &amp;mdash;&lt;/a&gt; &lt;a href=&quot;http://dev.to&quot;&gt;dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Artificial Intelligence</category>
      <category>Groq 3</category>
      <category>GTC</category>
      <category>NemoClaw</category>
      <category>Nvidia</category>
      <author>D.Y</author>
      <guid isPermaLink="true">https://ithub.tistory.com/445</guid>
      <comments>https://ithub.tistory.com/445#entry445comment</comments>
      <pubDate>Fri, 20 Mar 2026 09:18:33 +0900</pubDate>
    </item>
    <item>
      <title>tmux를 사용해서 Claude Code 사용성을 높여보자</title>
      <link>https://ithub.tistory.com/444</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code를 로컬 맥 환경에서 처음 쓰는 개발자 대부분은 iTerm2를 열고, 그 안에서 claude 명령어를 실행한다. 작동은 한다. 그러나 iTerm2 창을 닫거나 맥을 재시작하는 순간 진행 중이던 작업 세션과 작업환경은 사라진다. (세션이야 resume 명령어로 다시 불러올 수 있다. 하지만, 작업환경은 사라진다.) 백엔드 엔지니어들이 tmux를 사용하는 본질적인 이유가 바로 여기에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 두 개념을 명확히 구분하고, tmux가 왜 생산성을 높이는지, 현업에서 어떻게 쓰이는지를 실제 사례와 함께 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 개념 구분: 터미널 클라이언트 vs tmux&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;터미널 클라이언트란 무엇인가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iTerm2, Terminal.app, Warp 같은 도구는 &lt;b&gt;터미널 클라이언트&lt;/b&gt;다. 이 도구들의 역할은 단 하나다 &amp;mdash; 사용자가 입력한 키스트로크를 셸로 전달하고, 셸의 출력을 화면에 렌더링한다. 마치 텍스트 전용 브라우저와 같다. 브라우저가 HTML을 시각적으로 표현하듯, 터미널 클라이언트는 문자 스트림을 시각적으로 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 이것이다. &lt;b&gt;터미널 클라이언트는 프로세스를 소유하지 않는다.&lt;/b&gt; 창을 닫으면 그 안에서 실행 중이던 프로세스는 종료된다. 창이 곧 세션이고, 세션이 곧 프로세스의 생애 주기다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;tmux란 무엇인가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tmux는 **터미널 멀티플렉서(Terminal Multiplexer)**다. 터미널 클라이언트와 전혀 다른 계층에 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tmux는 OS 위에서 독립적인 서버 프로세스로 동작한다. 이 서버가 **세션(session)**을 관리한다. 세션 안에는 여러 **윈도우(window)**가 있고, 하나의 윈도우는 여러 **팬(pane)**으로 분할될 수 있다. 중요한 것은 이 세션이 터미널 클라이언트와 완전히 독립되어 있다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iTerm2로 tmux 세션에 접속(attach)하면, iTerm2는 단순히 그 세션의 출력을 보여주는 뷰어에 불과해진다. iTerm2를 닫아도 tmux 세션은 OS 백그라운드에서 살아 있다. 언제든 다시 접속(re-attach)하면 작업은 그대로다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비유하자면&lt;/b&gt;: iTerm2는 TV이고, tmux는 방송국이다. TV를 꺼도 방송은 계속된다. TV를 다시 켜면 방송을 이어서 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 왜 tmux가 생산성을 높이는가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드 엔지니어들이 tmux를 사용하는 이유는 단순히 &quot;여러 창을 열 수 있어서&quot;가 아니다. 본질적인 이유는 세 가지다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;세션의 영속성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 작업을 하는 백엔드 개발자는 배포, 빌드, 테스트를 원격 서버에서 장시간 실행한다. SSH 연결이 끊기거나 노트북 덮개를 닫아도 작업은 계속 실행되어야 한다. tmux가 없으면 프로세스가 즉시 종료된다. tmux가 있으면 세션이 서버에 살아 있고, 나중에 다시 접속해 결과를 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code 관점에서 이것은 결정적이다. 대규모 코드베이스 분석이나 멀티 스텝 작업을 Claude Code에게 맡겨 놓고 자리를 비울 수 있다. 맥 화면이 꺼지거나 iTerm2가 강제 종료되어도 작업은 계속 진행된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨텍스트 전환 비용 제거&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 개발 흐름을 생각해보자. Claude Code로 코드를 생성하면서, 동시에 Git 로그를 확인하고, 서버 로그를 모니터링하고, 테스트를 실행해야 한다. iTerm2만 사용하면 각 작업마다 탭을 전환하거나 창을 새로 열어야 한다. 멘탈 컨텍스트가 분산된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tmux에서는 단일 화면을 여러 팬으로 분할한다. 왼쪽에 Claude Code, 오른쪽 위에 파일 트리, 오른쪽 아래에 테스트 결과가 동시에 보인다. 물리적으로 같은 화면에 모든 컨텍스트가 존재한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;작업 단위의 격리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트별로 tmux 세션을 분리하면 작업 단위가 명확해진다. ebs-backend 세션에서는 EBR 시스템 개발만, devops 세션에서는 인프라 작업만 진행한다. 세션을 전환하는 것은 프로젝트를 전환하는 것이다. 각 세션의 상태는 완전히 독립적으로 보존된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 현업 개발자들은 tmux를 어떻게 사용하는가&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 구조 설계&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현업에서 사용하는 tmux 구조는 대체로 다음 패턴을 따른다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; style=&quot;color: #eaecf0;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;세션: project-name
  ├── window 0: main     &amp;mdash; Claude Code 실행
  ├── window 1: git      &amp;mdash; git 작업, 브랜치 관리
  ├── window 2: server   &amp;mdash; 개발 서버 실행
  └── window 3: logs     &amp;mdash; 서버 로그 모니터링&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 프로젝트가 하나의 세션이다. 세션 안의 윈도우는 역할로 구분한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;필수 단축키 (실전 기준)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tmux의 모든 명령은 &lt;b&gt;프리픽스 키&lt;/b&gt; 이후에 입력한다. 기본값은 Ctrl + b다.&lt;/p&gt;
&lt;div&gt;작업단축키
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;새 세션 생성&lt;/td&gt;
&lt;td&gt;tmux new -s project-name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;세션 목록 확인&lt;/td&gt;
&lt;td&gt;tmux ls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;세션 재접속&lt;/td&gt;
&lt;td&gt;tmux attach -t project-name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;새 윈도우&lt;/td&gt;
&lt;td&gt;Ctrl+b c&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;다음 윈도우&lt;/td&gt;
&lt;td&gt;Ctrl+b n&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;화면 수직 분할&lt;/td&gt;
&lt;td&gt;Ctrl+b %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;화면 수평 분할&lt;/td&gt;
&lt;td&gt;Ctrl+b &quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;팬 간 이동&lt;/td&gt;
&lt;td&gt;Ctrl+b 방향키&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;세션 분리 (detach)&lt;/td&gt;
&lt;td&gt;Ctrl+b d&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현업 개발자 대부분은 Ctrl+b 대신 Ctrl+a로 프리픽스를 재설정한다. ~/.tmux.conf에 한 줄 추가로 변경 가능하다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;dsconfig&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;# ~/.tmux.conf
set-option -g prefix C-a
unbind-key C-b
bind-key C-a send-prefix&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Claude Code와 함께하는 실전 워크플로우&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아침에 맥을 켰을 때 tmux를 사용하는 개발자의 루틴은 다음과 같다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;vala&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;# 어제 작업하던 세션으로 복귀
tmux attach -t ebs-backend

# &amp;rarr; 어제 실행 중이던 Claude Code가 그대로 실행 중
# &amp;rarr; git 윈도우에는 어제 마지막 커밋 상태가 그대로
# &amp;rarr; 서버 로그 윈도우에는 밤새 발생한 로그가 쌓여 있음&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션을 새로 만드는 것이 아니라, 어제 작업 상태로 그대로 복귀한다. 이것이 tmux 사용자와 비사용자의 첫 번째 차이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 대표 사례: Claude Code 멀티 에이전트 작업&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Claude Code를 tmux와 함께 사용할 때 나타나는 대표적인 패턴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시나리오&lt;/b&gt;: EBR 시스템의 API 레이어와 DB 스키마를 동시에 작업한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;vala&quot; style=&quot;color: #eaecf0;&quot;&gt;&lt;code&gt;# 세션 생성
tmux new -s ebr-dev

# window 0: orchestrator Claude Code
claude --model claude-opus-4-6

# Ctrl+b c &amp;rarr; window 1 생성: subagent Claude Code
claude --model claude-sonnet-4-6

# Ctrl+b c &amp;rarr; window 2 생성: 파일 변경 감시
watch -n 2 'git diff --stat'

# Ctrl+b c &amp;rarr; window 3 생성: 테스트 자동 실행
pytest --watch&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Opus가 전체 아키텍처를 설계하는 동안, Sonnet이 개별 컴포넌트를 구현한다. watch가 파일 변경을 실시간으로 보여주고, pytest가 변경 즉시 테스트를 돌린다. 이 모든 것이 단일 터미널 화면에서, 세션이 끊기지 않고, 동시에 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iTerm2만 사용했다면 이 중 어느 하나에 집중할 때 나머지 세 개의 컨텍스트를 탭 전환으로 잃어가며 작업해야 했을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;터미널 클라이언트는 화면을 렌더링하는 도구다. tmux는 세션을 관리하는 OS 레벨 서버&lt;/b&gt;다. 이 둘은 같은 계층에 있지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tmux가 백엔드 엔지니어 사이에서 표준으로 자리 잡은 이유는 화려한 기능 때문이 아니다. &lt;b&gt;세션의 영속성, 컨텍스트의 동시 가시성, 작업 단위의 격리&lt;/b&gt; &amp;mdash; 이 세 가지가 장시간 복잡한 작업을 수행하는 개발자의 흐름을 유지시키기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code를 진지하게 사용한다면, tmux는 선택이 아니라 인프라다.&lt;/p&gt;</description>
      <category>Artificial Intelligence</category>
      <category>claude code</category>
      <category>CLI</category>
      <category>iTerm2</category>
      <category>session</category>
      <category>tmux</category>
      <category>WARP</category>
      <author>D.Y</author>
      <guid isPermaLink="true">https://ithub.tistory.com/444</guid>
      <comments>https://ithub.tistory.com/444#entry444comment</comments>
      <pubDate>Fri, 20 Mar 2026 08:56:48 +0900</pubDate>
    </item>
  </channel>
</rss>