<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>미니베리</title>
    <link>https://miniberry-coding.tistory.com/</link>
    <description>Github: https://github.com/ljh8450</description>
    <language>ko</language>
    <pubDate>Mon, 13 Jul 2026 22:40:12 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>miniberry</managingEditor>
    <image>
      <title>미니베리</title>
      <url>https://tistory1.daumcdn.net/tistory/8585280/attach/39c312c6974e48a7b80fe047779dc82f</url>
      <link>https://miniberry-coding.tistory.com</link>
    </image>
    <item>
      <title>[Java] 코딩 자율학습 나도코딩의 자바 입문 리뷰</title>
      <link>https://miniberry-coding.tistory.com/33</link>
      <description>&lt;h1&gt;코딩 자율학습 나도코딩의 자바 입문 리뷰&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입문자가 따라가기 좋은 자바 학습서&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 리뷰는 출판사로부터 도서를 제공받아 작성한 후기이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 책을 읽게 된 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바는 백엔드 개발을 준비하는 사람이라면 꼭 한 번은 제대로 공부해야 하는 언어라고 생각한다.&lt;br /&gt;최근 Spring Boot를 공부하거나 객체지향 개념을 이해하려면 자바 문법에 대한 기본기에 대한 보충이 필요했다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FRKyB/dJMcaffH5RK/KzSVaE80XfCtsCpN1Yd2h0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FRKyB/dJMcaffH5RK/KzSVaE80XfCtsCpN1Yd2h0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FRKyB/dJMcaffH5RK/KzSVaE80XfCtsCpN1Yd2h0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFRKyB%2FdJMcaffH5RK%2FKzSVaE80XfCtsCpN1Yd2h0%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;594&quot; height=&quot;766&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;평소 나도코딩 강의처럼 친절하고 실습 중심의 설명을 기대하며 읽어보게 되었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 책의 구성과 특징&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;br /&gt;이후 배열, 메서드, 클래스, 상속, 인터페이스 등 자바에서 중요한 개념으로 자연스럽게 확장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 좋았던 점은 단순히 개념을 설명하는 데서 끝나지 않고, 직접 코드를 작성하면서 이해할 수 있도록 예제가 많이 제공된다는 점이다.&lt;br /&gt;입문자는 문법 설명만 읽으면 쉽게 지루해질 수 있는데, 이 책은 실습 흐름이 잘 잡혀 있어 따라가기 편하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 좋았던 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, 설명이 어렵지 않다.&lt;br /&gt;자바를 처음 배우는 사람도 이해할 수 있도록 용어를 풀어서 설명하고, 코드 예제도 복잡하지 않게 제시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, 실습 중심이라 학습 흐름이 좋다.&lt;br /&gt;개념을 읽고 바로 코드를 작성해볼 수 있어 &amp;ldquo;이 문법이 실제로 어떻게 쓰이는지&amp;rdquo; 확인하기 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셋째, 객체지향 개념을 입문자 눈높이에 맞게 다룬다.&lt;br /&gt;자바에서 클래스, 객체, 상속, 인터페이스는 중요한 개념이지만 처음에는 어렵게 느껴질 수 있다.&lt;br /&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;자바 코딩 무료 강의 (기본편) - 9시간 뒤면 여러분도 개발자가 될 수 있어요&quot; href=&quot;https://www.youtube.com/watch?v=NQq0dOoEPUM&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.youtube.com/watch?v=NQq0dOoEPUM&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=NQq0dOoEPUM&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/gIR1F/dJMb8WMv0Hz/HGjWkLgEkRCsZE1EEKTrW0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/dWnWwZ/dJMb8Yp1LwU/fJhukmIeEtEtUGKxJGp8R1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;자바 코딩 무료 강의 (기본편) - 9시간 뒤면 여러분도 개발자가 될 수 있어요&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/NQq0dOoEPUM&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&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. 아쉬웠던 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완전 입문자를 대상으로 한 책이다 보니, 이미 자바 문법을 어느 정도 알고 있는 사람에게는 앞부분이 다소 쉽게 느껴질 수 있다.&lt;br /&gt;또한 심화 문법이나 실무적인 Spring Boot 연계 내용까지 기대한다면 범위가 조금 제한적으로 느껴질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 책의 목적이 &amp;ldquo;자바 입문&amp;rdquo;이라는 점을 생각하면, 처음 배우는 독자에게는 적절한 난이도라고 판단된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 도서를 읽은 목적이 Java 복습이었기 때문에 충분히 만족스러웠다.&lt;/p&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;자바를 처음 공부하는 사람&lt;/li&gt;
&lt;li&gt;프로그래밍 입문서를 찾는 사람&lt;/li&gt;
&lt;li&gt;Spring Boot 공부 전에 자바 기본기를 다지고 싶은 사람&lt;/li&gt;
&lt;li&gt;문법 설명보다 실습을 통해 배우는 방식을 선호하는 사람&lt;/li&gt;
&lt;li&gt;나도코딩 스타일의 친절한 설명을 좋아하는 사람&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 전체 후기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;『코딩 자율학습 나도코딩의 자바 입문』은 자바를 처음 시작하는 사람이 기초 문법과 객체지향 개념을 차근차근 익히기에 좋은 책이다.&lt;br /&gt;설명이 친절하고 예제가 많아 혼자 공부하기에도 부담이 적다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 자바를 단순히 암기하는 것이 아니라, 직접 코드를 작성하면서 익히고 싶은 사람에게 잘 맞는 입문서라고 느껴졌다.&lt;br /&gt;백엔드 개발을 준비하는 입장에서 자바 기본기를 다시 정리하는 데에도 도움이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바를 처음 시작하는 사람이라면 이 책을 통해 기본 문법부터 객체지향 개념까지 자연스럽게 익혀볼 수 있을 것이다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>독서</category>
      <category>나도코딩의자바입문</category>
      <category>자바공부</category>
      <category>자바입문</category>
      <category>코딩자율학습</category>
      <category>프로그래밍입문</category>
      <author>miniberry</author>
      <guid isPermaLink="true">https://miniberry-coding.tistory.com/33</guid>
      <comments>https://miniberry-coding.tistory.com/33#entry33comment</comments>
      <pubDate>Tue, 26 May 2026 15:06:02 +0900</pubDate>
    </item>
    <item>
      <title>[Codex] 하네스 엔지니어링으로 풀스택 개발 시작하기</title>
      <link>https://miniberry-coding.tistory.com/32</link>
      <description>&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;0. 배경&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 &lt;b&gt;React + Spring 기반 풀스택 프로젝트(ChaekList)&lt;/b&gt;를 시작하면서 &amp;ldquo;Codex를 활용한 하네스 엔지니어링 방식으로 개발&amp;rdquo;을 적용해봤다.&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;a href=&quot;https://miniberry-coding.tistory.com/31&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://miniberry-coding.tistory.com/31&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;259&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnzaqK/dJMcabjG3b6/iYaGmyRqVaqurXVNPvnoH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnzaqK/dJMcabjG3b6/iYaGmyRqVaqurXVNPvnoH0/img.png&quot; data-alt=&quot;계획부터 구현까지 Codex를 통해서 작업이 가능하다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnzaqK/dJMcabjG3b6/iYaGmyRqVaqurXVNPvnoH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnzaqK%2FdJMcabjG3b6%2FiYaGmyRqVaqurXVNPvnoH0%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;1078&quot; height=&quot;259&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;259&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;계획부터 구현까지 Codex를 통해서 작업이 가능하다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론부터 말하면,&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: center;&quot;&gt;AI를 팀원처럼 만들어&lt;/span&gt; &amp;ldquo;명확한 제한과 방향성을 명시하는 과정&amp;rdquo;이었다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;1. Codex 처음 사용하면서 느낀 점&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;&amp;ldquo;Chat GPT보다 코드 조금 더 잘 짜주는 모델인가?&amp;rdquo;&lt;/li&gt;
&lt;/ul&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;/li&gt;
&lt;li&gt;실행 방법을 분석&lt;/li&gt;
&lt;li&gt;작업을 계획&lt;/li&gt;
&lt;/ul&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;frontend / backend 구조 분석&lt;/li&gt;
&lt;li&gt;실행 명령 자동 정리&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;Codex는 실제로 프로젝트를 이해하고 상황에 맞는 코드를 제시한다&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2. 첫 기능: Health Check API 구현&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Codex가 추천한 첫 작업은 &lt;b&gt;GET /api/health &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;frontend + backend 연결 확인 가능&lt;/li&gt;
&lt;li&gt;복잡한 도메인 없이 구조 검증 가능&lt;/li&gt;
&lt;li&gt;개발 환경 정상 여부 체크 가능&lt;/li&gt;
&lt;/ul&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;/api/health &amp;rarr; {&quot;status&quot;:&quot;ok&quot;}&lt;/li&gt;
&lt;li&gt;실제 서버 실행 후 정상 응답 확인&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;3. 예상 못한 문제: 테스트 깨짐&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 여기서 발생했다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;GradleWorkerMain ClassNotFoundException
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 넘어갈 수도 있었지만, 하네스 관점에서는 중요했다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;코드 &amp;rarr; 테스트 &amp;rarr; 검증
&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4. 문제 해결 과정&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Codex에게 문제 해결을 맡겼다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원인: Windows 사용자 경로의 &lt;b&gt;비ASCII 문자 문제&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;해결: GRADLE_USER_HOME을 프로젝트 내부 경로로 변경&lt;/li&gt;
&lt;/ul&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;gradlew.bat&lt;/li&gt;
&lt;li&gt;gradlew&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과:&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;BUILD SUCCESSFUL
&lt;/code&gt;&lt;/pre&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;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;나는 지시한 뒤, 확인하고 승인만 하면 된다&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;5. 프론트엔드 연결까지 완료&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js에서 /api/health 호출&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;http://localhost:3000/api/health &amp;rarr; 정상 응답&lt;/li&gt;
&lt;li&gt;rewrite 설정 통해 backend 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;6. 리뷰에서 발견된 문제&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Codex 리뷰 결과는 localhost &lt;b&gt;하드코딩 문제&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;http://localhost:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;포트 바뀌면 깨짐&lt;/li&gt;
&lt;li&gt;환경별 설정 불가능&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;AI는 코드만 만드는 게 아니라, 리스크도 찾아준다&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;7. 하네스 엔지니어링의 핵심: AGENTS.md&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 가장 중요한 작업을 했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;673&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEmBdd/dJMcafl4tfP/ImxcmmDmerSyvi7qWIUCn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEmBdd/dJMcafl4tfP/ImxcmmDmerSyvi7qWIUCn0/img.png&quot; data-alt=&quot;AGENTS.md 중 일부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEmBdd/dJMcafl4tfP/ImxcmmDmerSyvi7qWIUCn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEmBdd%2FdJMcafl4tfP%2FImxcmmDmerSyvi7qWIUCn0%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;672&quot; height=&quot;673&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;673&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AGENTS.md 중 일부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AGENTS.md 작성&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;Codex 행동 규칙 정의&lt;/li&gt;
&lt;li&gt;작업 범위 제한&lt;/li&gt;
&lt;li&gt;검증 방식 지정&lt;/li&gt;
&lt;li&gt;언어 설정 (한국어)&lt;/li&gt;
&lt;/ul&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;frontend / backend 분리&lt;/li&gt;
&lt;li&gt;테스트 필수&lt;/li&gt;
&lt;li&gt;PR 기반 작업&lt;/li&gt;
&lt;li&gt;하드코딩 금지&lt;/li&gt;
&lt;/ul&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;AI가 이상한 방향으로 안 감&lt;/li&gt;
&lt;li&gt;매번 같은 설명 안 해도 됨&lt;/li&gt;
&lt;li&gt;작업 품질 상승&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;8. Codex 사용 방식 변화&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;codex &quot;Read AGENTS.md first. Act as a backend specialist...&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;codex &quot;AGENTS.md를 먼저 읽고 backend 개발자 역할로 동작해...&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 Codex를 사용했기 때문에 영어로 명령하는 것이 편하지만, AGENTS.md에 한글로 명시가 가능하고 CLI에서도 한글로 명령하는것이 가능했다.&lt;/p&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;9. 가장 큰 깨달음&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 경험에서 가장 크게 느낀 점:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전트는 도구가 아니다&lt;br /&gt;하네스 엔지니어링을 통해 &amp;ldquo;환경을 어떻게 설계하느냐에 따라 성능이 결정된다&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;10. 앞으로 방향&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;CI/CD 자동화&lt;/li&gt;
&lt;li&gt;Codex PR 리뷰 자동화&lt;/li&gt;
&lt;li&gt;배포까지 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;완전한 AI 기반 개발 파이프라인 구축&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&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;이번 경험을 통해 느낀 건 하나다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;이제 개발자는 코드를 짜는 사람이 아니라&lt;br /&gt;시스템을 설계하는 사람이 되어야 한다&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로는 단순한 코딩보다&lt;br /&gt;&lt;b&gt;하네스 엔지니어링 능력&lt;/b&gt;이 더 중요해질 것 같다.&lt;/p&gt;</description>
      <category>인사이트</category>
      <category>Codex</category>
      <category>에이전틱 엔지니어링</category>
      <category>웹개발</category>
      <category>하네스 엔지니어링</category>
      <author>miniberry</author>
      <guid isPermaLink="true">https://miniberry-coding.tistory.com/32</guid>
      <comments>https://miniberry-coding.tistory.com/32#entry32comment</comments>
      <pubDate>Fri, 24 Apr 2026 13:05:37 +0900</pubDate>
    </item>
    <item>
      <title>[에이전틱 엔지니어링] 하네스 엔지니어링(Harness Engineering) 이란?</title>
      <link>https://miniberry-coding.tistory.com/31</link>
      <description>&lt;h2 data-end=&quot;215&quot; data-start=&quot;193&quot; data-section-id=&quot;12hux04&quot; data-ke-size=&quot;size26&quot;&gt;1. 하네스 엔지니어링이란 무엇인가&lt;/h2&gt;
&lt;p data-end=&quot;292&quot; data-start=&quot;217&quot; data-ke-size=&quot;size16&quot;&gt;최근 LLM 기반 서비스가 발전하면서, 단순히 모델을 잘 사용하는 것만으로는 실제 제품을 만들 수 없다는 한계가 드러나기 시작했다.&lt;/p&gt;
&lt;p data-end=&quot;349&quot; data-start=&quot;294&quot; data-ke-size=&quot;size16&quot;&gt;이 과정에서 등장한 개념이 바로 &lt;b&gt;하네스 엔지니어링(Harness Engineering)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;378&quot; data-start=&quot;351&quot; data-ke-size=&quot;size16&quot;&gt;하네스 엔지니어링은 다음과 같이 정의할 수 있다.&lt;/p&gt;
&lt;blockquote data-end=&quot;435&quot; data-start=&quot;380&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;435&quot; data-start=&quot;382&quot; data-ke-size=&quot;size16&quot;&gt;LLM을 중심으로, 모델을 제외한 나머지 모든 실행&amp;middot;제어&amp;middot;검증&amp;middot;관리 시스템을 설계하는 엔지니어링&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;452&quot; data-start=&quot;437&quot; data-ke-size=&quot;size16&quot;&gt;조금 더 직관적으로 말하면,&lt;/p&gt;
&lt;blockquote data-end=&quot;493&quot; data-start=&quot;454&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;493&quot; data-start=&quot;456&quot; data-ke-size=&quot;size16&quot;&gt;프롬프트 엔지니어링을 넘어, LLM에게 방향성을 제시하는 엔지니어링 기법&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;498&quot; data-start=&quot;495&quot; data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;hr data-end=&quot;503&quot; data-start=&quot;500&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;529&quot; data-start=&quot;505&quot; data-section-id=&quot;1ibsdu0&quot; data-ke-size=&quot;size26&quot;&gt;2. 왜 하네스 엔지니어링이 등장했는가&lt;/h2&gt;
&lt;h3 data-end=&quot;556&quot; data-start=&quot;531&quot; data-section-id=&quot;1jfavy7&quot; data-ke-size=&quot;size23&quot;&gt;(1) LLM은 완전한 시스템이 아니다&lt;/h3&gt;
&lt;p data-end=&quot;578&quot; data-start=&quot;558&quot; data-ke-size=&quot;size16&quot;&gt;LLM은 다음과 같은 한계를 가진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;668&quot; data-start=&quot;580&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;606&quot; data-start=&quot;580&quot; data-section-id=&quot;1w0pi4o&quot;&gt;상태를 기억하지 못한다 (stateless)&lt;/li&gt;
&lt;li data-end=&quot;630&quot; data-start=&quot;607&quot; data-section-id=&quot;1x9s21u&quot;&gt;외부 시스템과 직접 상호작용하지 못한다&lt;/li&gt;
&lt;li data-end=&quot;648&quot; data-start=&quot;631&quot; data-section-id=&quot;137lg5j&quot;&gt;실행 흐름을 제어할 수 없다&lt;/li&gt;
&lt;li data-end=&quot;668&quot; data-start=&quot;649&quot; data-section-id=&quot;109e0dv&quot;&gt;결과의 신뢰성을 보장하지 못한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;711&quot; data-start=&quot;670&quot; data-ke-size=&quot;size16&quot;&gt;즉, LLM은 &lt;b&gt;CPU에 가까운 존재&lt;/b&gt;이지, 완성된 프로그램이 아니다.&lt;/p&gt;
&lt;hr data-end=&quot;716&quot; data-start=&quot;713&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;748&quot; data-start=&quot;718&quot; data-section-id=&quot;w8rai0&quot; data-ke-size=&quot;size23&quot;&gt;(2) Prompt Engineering의 한계&lt;/h3&gt;
&lt;p data-end=&quot;781&quot; data-start=&quot;750&quot; data-ke-size=&quot;size16&quot;&gt;초기에는 &amp;ldquo;프롬프트를 잘 짜면 된다&amp;rdquo;는 접근이 주류였다.&lt;/p&gt;
&lt;p data-end=&quot;809&quot; data-start=&quot;783&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실제 서비스에서는 다음 문제가 발생한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;886&quot; data-start=&quot;811&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;835&quot; data-start=&quot;811&quot; data-section-id=&quot;oocosl&quot;&gt;동일 입력에도 출력이 달라짐 (비결정성)&lt;/li&gt;
&lt;li data-end=&quot;853&quot; data-start=&quot;836&quot; data-section-id=&quot;15h7xzw&quot;&gt;복잡한 작업 흐름 처리 불가&lt;/li&gt;
&lt;li data-end=&quot;871&quot; data-start=&quot;854&quot; data-section-id=&quot;1reeofa&quot;&gt;외부 데이터/툴 연동 어려움&lt;/li&gt;
&lt;li data-end=&quot;886&quot; data-start=&quot;872&quot; data-section-id=&quot;eco2oo&quot;&gt;실패 원인 분석 불가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;937&quot; data-start=&quot;888&quot; data-ke-size=&quot;size16&quot;&gt;결국 프롬프트만으로는 &lt;b&gt;제품 수준의 시스템을 만들 수 없다&lt;/b&gt;는 결론에 도달하게 된다.&lt;/p&gt;
&lt;hr data-end=&quot;942&quot; data-start=&quot;939&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;965&quot; data-start=&quot;944&quot; data-section-id=&quot;x2oksl&quot; data-ke-size=&quot;size23&quot;&gt;(3) Agent 시스템의 등장&lt;/h3&gt;
&lt;p data-end=&quot;995&quot; data-start=&quot;967&quot; data-ke-size=&quot;size16&quot;&gt;Agent 구조가 도입되면서 상황은 더 복잡해졌다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;User &amp;rarr; Planner &amp;rarr; Tool &amp;rarr; Memory &amp;rarr; LLM &amp;rarr; Action&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1073&quot; data-start=&quot;1052&quot; data-ke-size=&quot;size16&quot;&gt;이 구조에서는 단순 응답 생성이 아니라&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1136&quot; data-start=&quot;1075&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1089&quot; data-start=&quot;1075&quot; data-section-id=&quot;8xnkv1&quot;&gt;계획(Planning)&lt;/li&gt;
&lt;li data-end=&quot;1102&quot; data-start=&quot;1090&quot; data-section-id=&quot;1p4tiuf&quot;&gt;행동(Action)&lt;/li&gt;
&lt;li data-end=&quot;1121&quot; data-start=&quot;1103&quot; data-section-id=&quot;1uts8jv&quot;&gt;재계획(Re-planning)&lt;/li&gt;
&lt;li data-end=&quot;1136&quot; data-start=&quot;1122&quot; data-section-id=&quot;u2mecj&quot;&gt;상태 유지(State)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1147&quot; data-start=&quot;1138&quot; data-ke-size=&quot;size16&quot;&gt;까지 필요해진다.&lt;/p&gt;
&lt;p data-end=&quot;1200&quot; data-start=&quot;1149&quot; data-ke-size=&quot;size16&quot;&gt;이때 이를 통제하는 시스템이 필요해지고, 그 역할을 하는 것이 바로 &lt;b&gt;Harness&lt;/b&gt;다.&lt;/p&gt;
&lt;hr data-end=&quot;1205&quot; data-start=&quot;1202&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1229&quot; data-start=&quot;1207&quot; data-section-id=&quot;yub5vo&quot; data-ke-size=&quot;size26&quot;&gt;3. 하네스 엔지니어링의 핵심 개념&lt;/h2&gt;
&lt;p data-end=&quot;1254&quot; data-start=&quot;1231&quot; data-ke-size=&quot;size16&quot;&gt;하네스는 단순한 &amp;ldquo;테스트 도구&amp;rdquo;가 아니다.&lt;/p&gt;
&lt;p data-end=&quot;1280&quot; data-start=&quot;1256&quot; data-ke-size=&quot;size16&quot;&gt;최신 관점에서는 다음과 같이 이해해야 한다.&lt;/p&gt;
&lt;blockquote data-end=&quot;1356&quot; data-start=&quot;1282&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1356&quot; data-start=&quot;1284&quot; data-ke-size=&quot;size16&quot;&gt;Harness = Execution + Control + Memory + Tools + Evaluation + Governance&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;1384&quot; data-start=&quot;1358&quot; data-ke-size=&quot;size16&quot;&gt;즉, 모델을 둘러싼 &lt;b&gt;전체 운영 환경&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr data-end=&quot;1389&quot; data-start=&quot;1386&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1410&quot; data-start=&quot;1391&quot; data-section-id=&quot;5bt4s2&quot; data-ke-size=&quot;size26&quot;&gt;4. 하네스의 주요 구성 요소&lt;/h2&gt;
&lt;h3 data-end=&quot;1445&quot; data-start=&quot;1412&quot; data-section-id=&quot;1ftaqqq&quot; data-ke-size=&quot;size23&quot;&gt;4.1 Execution &amp;amp; Orchestration&lt;/h3&gt;
&lt;p data-end=&quot;1470&quot; data-start=&quot;1447&quot; data-ke-size=&quot;size16&quot;&gt;에이전트의 전체 흐름을 실행하고 제어한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;Plan &amp;rarr; Act &amp;rarr; Observe &amp;rarr; Re-plan&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1552&quot; data-start=&quot;1512&quot; data-ke-size=&quot;size16&quot;&gt;단일 요청이 아니라 &lt;b&gt;멀티 스텝 프로세스&lt;/b&gt;를 관리하는 것이 핵심이다.&lt;/p&gt;
&lt;hr data-end=&quot;1557&quot; data-start=&quot;1554&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1595&quot; data-start=&quot;1559&quot; data-section-id=&quot;e2imsp&quot; data-ke-size=&quot;size23&quot;&gt;4.2 Tool / Environment Interface&lt;/h3&gt;
&lt;p data-end=&quot;1624&quot; data-start=&quot;1597&quot; data-ke-size=&quot;size16&quot;&gt;LLM이 외부 세계와 상호작용할 수 있도록 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1664&quot; data-start=&quot;1626&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1634&quot; data-start=&quot;1626&quot; data-section-id=&quot;1vve378&quot;&gt;API 호출&lt;/li&gt;
&lt;li data-end=&quot;1646&quot; data-start=&quot;1635&quot; data-section-id=&quot;1r5v669&quot;&gt;데이터베이스 접근&lt;/li&gt;
&lt;li data-end=&quot;1655&quot; data-start=&quot;1647&quot; data-section-id=&quot;6wb5jw&quot;&gt;파일 시스템&lt;/li&gt;
&lt;li data-end=&quot;1664&quot; data-start=&quot;1656&quot; data-section-id=&quot;1q1wfwk&quot;&gt;웹 브라우징&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1711&quot; data-start=&quot;1666&quot; data-ke-size=&quot;size16&quot;&gt;LLM은 혼자 아무것도 할 수 없고, 실제 &amp;ldquo;행동&amp;rdquo;은 이 레이어에서 발생한다.&lt;/p&gt;
&lt;hr data-end=&quot;1716&quot; data-start=&quot;1713&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1751&quot; data-start=&quot;1718&quot; data-section-id=&quot;1a2ijvw&quot; data-ke-size=&quot;size23&quot;&gt;4.3 Memory &amp;amp; State Management&lt;/h3&gt;
&lt;p data-end=&quot;1788&quot; data-start=&quot;1753&quot; data-ke-size=&quot;size16&quot;&gt;LLM은 상태를 유지하지 못하기 때문에, 이를 보완하는 구조다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1825&quot; data-start=&quot;1790&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1797&quot; data-start=&quot;1790&quot; data-section-id=&quot;1ooakhd&quot;&gt;대화 기록&lt;/li&gt;
&lt;li data-end=&quot;1806&quot; data-start=&quot;1798&quot; data-section-id=&quot;zjyj8g&quot;&gt;사용자 상태&lt;/li&gt;
&lt;li data-end=&quot;1817&quot; data-start=&quot;1807&quot; data-section-id=&quot;9hircp&quot;&gt;작업 진행 상황&lt;/li&gt;
&lt;li data-end=&quot;1825&quot; data-start=&quot;1818&quot; data-section-id=&quot;1p44glt&quot;&gt;중간 결과&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1849&quot; data-start=&quot;1827&quot; data-ke-size=&quot;size16&quot;&gt;특히 멀티턴 에이전트에서는 필수 요소다.&lt;/p&gt;
&lt;hr data-end=&quot;1854&quot; data-start=&quot;1851&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1882&quot; data-start=&quot;1856&quot; data-section-id=&quot;c8pvdw&quot; data-ke-size=&quot;size23&quot;&gt;4.4 Context Management&lt;/h3&gt;
&lt;p data-end=&quot;1906&quot; data-start=&quot;1884&quot; data-ke-size=&quot;size16&quot;&gt;LLM에 어떤 정보를 입력할지 결정한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1949&quot; data-start=&quot;1908&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1922&quot; data-start=&quot;1908&quot; data-section-id=&quot;16l6ehg&quot;&gt;어떤 데이터를 포함할지&lt;/li&gt;
&lt;li data-end=&quot;1936&quot; data-start=&quot;1923&quot; data-section-id=&quot;1ukisz5&quot;&gt;어떤 부분을 요약할지&lt;/li&gt;
&lt;li data-end=&quot;1949&quot; data-start=&quot;1937&quot; data-section-id=&quot;yq0whv&quot;&gt;어떤 순서로 넣을지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2012&quot; data-start=&quot;1951&quot; data-ke-size=&quot;size16&quot;&gt;이 영역은 기존의 &lt;b&gt;Context Engineering / Prompt Engineering&lt;/b&gt;과 연결된다.&lt;/p&gt;
&lt;hr data-end=&quot;2017&quot; data-start=&quot;2014&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2053&quot; data-start=&quot;2019&quot; data-section-id=&quot;d76teu&quot; data-ke-size=&quot;size23&quot;&gt;4.5 Control &amp;amp; Constraints (핵심)&lt;/h3&gt;
&lt;p data-end=&quot;2077&quot; data-start=&quot;2055&quot; data-ke-size=&quot;size16&quot;&gt;하네스에서 가장 중요한 요소 중 하나다.&lt;/p&gt;
&lt;p data-end=&quot;2099&quot; data-start=&quot;2079&quot; data-ke-size=&quot;size16&quot;&gt;에이전트의 행동을 제한하고 통제한다.&lt;/p&gt;
&lt;p data-end=&quot;2103&quot; data-start=&quot;2101&quot; data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2161&quot; data-start=&quot;2105&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2119&quot; data-start=&quot;2105&quot; data-section-id=&quot;115yigo&quot;&gt;특정 API 호출 제한&lt;/li&gt;
&lt;li data-end=&quot;2130&quot; data-start=&quot;2120&quot; data-section-id=&quot;7od4ck&quot;&gt;위험 행동 차단&lt;/li&gt;
&lt;li data-end=&quot;2150&quot; data-start=&quot;2131&quot; data-section-id=&quot;15dcxgo&quot;&gt;human approval 요구&lt;/li&gt;
&lt;li data-end=&quot;2161&quot; data-start=&quot;2151&quot; data-section-id=&quot;1atnvh4&quot;&gt;정책 기반 제어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2206&quot; data-start=&quot;2163&quot; data-ke-size=&quot;size16&quot;&gt;즉, 하네스는 단순 실행기가 아니라&lt;br /&gt;**&amp;ldquo;브레이크가 달린 시스템&amp;rdquo;**이다.&lt;/p&gt;
&lt;hr data-end=&quot;2211&quot; data-start=&quot;2208&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2246&quot; data-start=&quot;2213&quot; data-section-id=&quot;j3u3nn&quot; data-ke-size=&quot;size23&quot;&gt;4.6 Verification &amp;amp; Evaluation&lt;/h3&gt;
&lt;p data-end=&quot;2261&quot; data-start=&quot;2248&quot; data-ke-size=&quot;size16&quot;&gt;결과의 품질을 검증한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2325&quot; data-start=&quot;2263&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2291&quot; data-start=&quot;2263&quot; data-section-id=&quot;1f5x2n&quot;&gt;규칙 기반 검증 (keyword, format)&lt;/li&gt;
&lt;li data-end=&quot;2317&quot; data-start=&quot;2292&quot; data-section-id=&quot;mws0n2&quot;&gt;모델 기반 평가 (LLM-as-judge)&lt;/li&gt;
&lt;li data-end=&quot;2325&quot; data-start=&quot;2318&quot; data-section-id=&quot;52i1ex&quot;&gt;혼합 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2383&quot; data-start=&quot;2327&quot; data-ke-size=&quot;size16&quot;&gt;이 부분이 흔히 말하는 &amp;ldquo;evaluation harness&amp;rdquo;이며, 전체 하네스의 일부에 해당한다.&lt;/p&gt;
&lt;hr data-end=&quot;2388&quot; data-start=&quot;2385&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2418&quot; data-start=&quot;2390&quot; data-section-id=&quot;ol0u7i&quot; data-ke-size=&quot;size23&quot;&gt;4.7 Lifecycle Management&lt;/h3&gt;
&lt;p data-end=&quot;2438&quot; data-start=&quot;2420&quot; data-ke-size=&quot;size16&quot;&gt;작업의 전체 생명주기를 관리한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2488&quot; data-start=&quot;2440&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2449&quot; data-start=&quot;2440&quot; data-section-id=&quot;17qa7hf&quot;&gt;시작 / 종료&lt;/li&gt;
&lt;li data-end=&quot;2457&quot; data-start=&quot;2450&quot; data-section-id=&quot;uuo38w&quot;&gt;실패 처리&lt;/li&gt;
&lt;li data-end=&quot;2465&quot; data-start=&quot;2458&quot; data-section-id=&quot;16o79ls&quot;&gt;retry&lt;/li&gt;
&lt;li data-end=&quot;2488&quot; data-start=&quot;2466&quot; data-section-id=&quot;g1ygg9&quot;&gt;long-running task 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2513&quot; data-start=&quot;2490&quot; data-ke-size=&quot;size16&quot;&gt;특히 실제 서비스 환경에서 매우 중요하다.&lt;/p&gt;
&lt;hr data-end=&quot;2518&quot; data-start=&quot;2515&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2539&quot; data-start=&quot;2520&quot; data-section-id=&quot;1se2n03&quot; data-ke-size=&quot;size23&quot;&gt;4.8 Persistence&lt;/h3&gt;
&lt;p data-end=&quot;2562&quot; data-start=&quot;2541&quot; data-ke-size=&quot;size16&quot;&gt;상태를 저장하고 복구할 수 있게 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2594&quot; data-start=&quot;2564&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2571&quot; data-start=&quot;2564&quot; data-section-id=&quot;focm6l&quot;&gt;세션 저장&lt;/li&gt;
&lt;li data-end=&quot;2582&quot; data-start=&quot;2572&quot; data-section-id=&quot;qtbnok&quot;&gt;작업 상태 저장&lt;/li&gt;
&lt;li data-end=&quot;2594&quot; data-start=&quot;2583&quot; data-section-id=&quot;2tngts&quot;&gt;재실행 가능 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2599&quot; data-start=&quot;2596&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2622&quot; data-start=&quot;2601&quot; data-section-id=&quot;p890c8&quot; data-ke-size=&quot;size23&quot;&gt;4.9 Observability&lt;/h3&gt;
&lt;p data-end=&quot;2641&quot; data-start=&quot;2624&quot; data-ke-size=&quot;size16&quot;&gt;시스템을 관찰 가능하게 만든다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2667&quot; data-start=&quot;2643&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2647&quot; data-start=&quot;2643&quot; data-section-id=&quot;yi0tjg&quot;&gt;로그&lt;/li&gt;
&lt;li data-end=&quot;2658&quot; data-start=&quot;2648&quot; data-section-id=&quot;142l3ok&quot;&gt;실행 trace&lt;/li&gt;
&lt;li data-end=&quot;2667&quot; data-start=&quot;2659&quot; data-section-id=&quot;16wusos&quot;&gt;디버깅 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2701&quot; data-start=&quot;2669&quot; data-ke-size=&quot;size16&quot;&gt;이게 없으면 Agent 시스템은 사실상 운영이 불가능하다.&lt;/p&gt;
&lt;hr data-end=&quot;2706&quot; data-start=&quot;2703&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2730&quot; data-start=&quot;2708&quot; data-section-id=&quot;17wq5k&quot; data-ke-size=&quot;size23&quot;&gt;4.10 Feedback Loop&lt;/h3&gt;
&lt;p data-end=&quot;2751&quot; data-start=&quot;2732&quot; data-ke-size=&quot;size16&quot;&gt;실패를 기반으로 시스템을 개선한다.&lt;/p&gt;
&lt;p data-end=&quot;2760&quot; data-start=&quot;2753&quot; data-ke-size=&quot;size16&quot;&gt;중요한 점은,&lt;/p&gt;
&lt;blockquote data-end=&quot;2793&quot; data-start=&quot;2762&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2793&quot; data-start=&quot;2764&quot; data-ke-size=&quot;size16&quot;&gt;프롬프트를 수정하는 것이 아니라 시스템을 개선한다&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;2801&quot; data-start=&quot;2795&quot; data-ke-size=&quot;size16&quot;&gt;는 것이다.&lt;/p&gt;
&lt;hr data-end=&quot;2806&quot; data-start=&quot;2803&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2827&quot; data-start=&quot;2808&quot; data-section-id=&quot;ji124r&quot; data-ke-size=&quot;size26&quot;&gt;5. 하네스 엔지니어링의 구조&lt;/h2&gt;
&lt;p data-end=&quot;2848&quot; data-start=&quot;2829&quot; data-ke-size=&quot;size16&quot;&gt;정리하면 다음과 같은 구조가 된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div id=&quot;code_1776093018897&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;div style=&amp;quot;max-width: 760px; margin: 24px auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif; line-height: 1.8; color: #222;&amp;quot;&amp;gt;

  &amp;lt;div style=&amp;quot;border-left: 6px solid #4f46e5; background: #f8faff; padding: 18px 20px; border-radius: 12px; margin-bottom: 20px;&amp;quot;&amp;gt;
    &amp;lt;div style=&amp;quot;font-size: 22px; font-weight: 700; margin-bottom: 6px;&amp;quot;&amp;gt;  하네스 구조&amp;lt;/div&amp;gt;
    &amp;lt;div style=&amp;quot;font-size: 15px; color: #555;&amp;quot;&amp;gt;
      LLM 위에서 동작하는 것이 아니라, 실제로는 Harness가 LLM을 감싸며 실행 환경을 구성한다.
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div style=&amp;quot;border: 1px solid #e5e7eb; border-radius: 16px; overflow: hidden; box-shadow: 0 8px 24px rgba(0,0,0,0.06); margin-bottom: 28px;&amp;quot;&amp;gt;

    &amp;lt;div style=&amp;quot;background: linear-gradient(135deg, #6366f1, #4338ca); color: white; text-align: center; padding: 20px;&amp;quot;&amp;gt;
      &amp;lt;div style=&amp;quot;font-size: 24px; font-weight: 700;&amp;quot;&amp;gt;  LLM&amp;lt;/div&amp;gt;
      &amp;lt;div style=&amp;quot;font-size: 14px; opacity: 0.9;&amp;quot;&amp;gt;Core Engine&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div style=&amp;quot;text-align: center; font-size: 28px; padding: 10px 0; color: #6366f1; font-weight: 700;&amp;quot;&amp;gt;&amp;uarr;&amp;lt;/div&amp;gt;

    &amp;lt;div style=&amp;quot;background: #f9fafb; padding: 22px 20px 10px 20px; border-top: 1px solid #e5e7eb;&amp;quot;&amp;gt;
      &amp;lt;div style=&amp;quot;font-size: 22px; font-weight: 700; color: #111827; margin-bottom: 16px;&amp;quot;&amp;gt;  Harness &amp;lt;span style=&amp;quot;font-size: 15px; font-weight: 500; color: #6b7280;&amp;quot;&amp;gt;(Execution System)&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;

      &amp;lt;ul style=&amp;quot;list-style: none; padding: 0; margin: 0;&amp;quot;&amp;gt;
        &amp;lt;li style=&amp;quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&amp;quot;&amp;gt;
          &amp;lt;strong&amp;gt;⚙️ Execution&amp;lt;/strong&amp;gt; &amp;lt;span style=&amp;quot;color: #6b7280;&amp;quot;&amp;gt;(흐름 제어)&amp;lt;/span&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li style=&amp;quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&amp;quot;&amp;gt;
          &amp;lt;strong&amp;gt;  Tools&amp;lt;/strong&amp;gt; &amp;lt;span style=&amp;quot;color: #6b7280;&amp;quot;&amp;gt;(외부 연결)&amp;lt;/span&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li style=&amp;quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&amp;quot;&amp;gt;
          &amp;lt;strong&amp;gt;  Memory&amp;lt;/strong&amp;gt; &amp;lt;span style=&amp;quot;color: #6b7280;&amp;quot;&amp;gt;(상태 관리)&amp;lt;/span&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li style=&amp;quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&amp;quot;&amp;gt;
          &amp;lt;strong&amp;gt;  Context&amp;lt;/strong&amp;gt; &amp;lt;span style=&amp;quot;color: #6b7280;&amp;quot;&amp;gt;(입력 구성)&amp;lt;/span&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li style=&amp;quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&amp;quot;&amp;gt;
          &amp;lt;strong&amp;gt;  Control&amp;lt;/strong&amp;gt; &amp;lt;span style=&amp;quot;color: #6b7280;&amp;quot;&amp;gt;(제약 / 안전)&amp;lt;/span&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li style=&amp;quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&amp;quot;&amp;gt;
          &amp;lt;strong&amp;gt;✅ Verification&amp;lt;/strong&amp;gt; &amp;lt;span style=&amp;quot;color: #6b7280;&amp;quot;&amp;gt;(검증)&amp;lt;/span&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li style=&amp;quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&amp;quot;&amp;gt;
          &amp;lt;strong&amp;gt;  Lifecycle&amp;lt;/strong&amp;gt; &amp;lt;span style=&amp;quot;color: #6b7280;&amp;quot;&amp;gt;(작업 관리)&amp;lt;/span&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li style=&amp;quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&amp;quot;&amp;gt;
          &amp;lt;strong&amp;gt;  Persistence&amp;lt;/strong&amp;gt; &amp;lt;span style=&amp;quot;color: #6b7280;&amp;quot;&amp;gt;(저장)&amp;lt;/span&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li style=&amp;quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&amp;quot;&amp;gt;
          &amp;lt;strong&amp;gt;  Observability&amp;lt;/strong&amp;gt; &amp;lt;span style=&amp;quot;color: #6b7280;&amp;quot;&amp;gt;(로그)&amp;lt;/span&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li style=&amp;quot;padding: 12px 14px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&amp;quot;&amp;gt;
          &amp;lt;strong&amp;gt;  Feedback&amp;lt;/strong&amp;gt; &amp;lt;span style=&amp;quot;color: #6b7280;&amp;quot;&amp;gt;(개선)&amp;lt;/span&amp;gt;
        &amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div style=&amp;quot;border-left: 6px solid #10b981; background: #f0fdf4; padding: 18px 20px; border-radius: 12px;&amp;quot;&amp;gt;
    &amp;lt;div style=&amp;quot;font-size: 20px; font-weight: 700; margin-bottom: 10px;&amp;quot;&amp;gt;  이해를 위한 비유&amp;lt;/div&amp;gt;
    &amp;lt;div style=&amp;quot;font-size: 16px; margin-bottom: 8px;&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;LLM = CPU&amp;lt;/strong&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div style=&amp;quot;font-size: 16px; margin-bottom: 12px;&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Harness = 운영체제(OS)&amp;lt;/strong&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div style=&amp;quot;font-size: 15px; color: #374151;&amp;quot;&amp;gt;
      즉, Harness가 없으면 LLM은 실제 시스템으로 안정적으로 동작할 수 없다.
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

&amp;lt;/div&amp;gt;&quot;&gt;
&lt;div style=&quot;max-width: 760px; margin: 24px auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif; line-height: 1.8; color: #222;&quot;&gt;
&lt;div style=&quot;border-left: 6px solid #4f46e5; background: #f8faff; padding: 18px 20px; border-radius: 12px; margin-bottom: 20px;&quot;&gt;
&lt;div style=&quot;font-size: 22px; font-weight: bold; margin-bottom: 6px;&quot;&gt;  하네스 구조&lt;/div&gt;
&lt;div style=&quot;font-size: 15px; color: #555;&quot;&gt;LLM 위에서 동작하는 것이 아니라, 실제로는 Harness가 LLM을 감싸며 실행 환경을 구성한다.&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;border: 1px solid #e5e7eb; border-radius: 16px; overflow: hidden; box-shadow: 0 8px 24px rgba(0,0,0,0.06); margin-bottom: 28px;&quot;&gt;
&lt;div style=&quot;background: linear-gradient(135deg, #6366f1, #4338ca); color: white; text-align: center; padding: 20px;&quot;&gt;
&lt;div style=&quot;font-size: 24px; font-weight: bold;&quot;&gt;  LLM&lt;/div&gt;
&lt;div style=&quot;font-size: 14px; opacity: 0.9;&quot;&gt;Core Engine&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: center; font-size: 28px; padding: 10px 0; color: #6366f1; font-weight: bold;&quot;&gt;&amp;uarr;&lt;/div&gt;
&lt;div style=&quot;background: #f9fafb; padding: 22px 20px 10px 20px; border-top: 1px solid #e5e7eb;&quot;&gt;
&lt;div style=&quot;font-size: 22px; font-weight: bold; color: #111827; margin-bottom: 16px;&quot;&gt;  Harness &lt;span style=&quot;font-size: 15px; font-weight: 500; color: #6b7280;&quot;&gt;(Execution System)&lt;/span&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style: none; padding: 0; margin: 0;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&quot;&gt;&lt;b&gt;⚙️ Execution&lt;/b&gt; &lt;span style=&quot;color: #6b7280;&quot;&gt;(흐름 제어)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&quot;&gt;&lt;b&gt;  Tools&lt;/b&gt; &lt;span style=&quot;color: #6b7280;&quot;&gt;(외부 연결)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&quot;&gt;&lt;b&gt;  Memory&lt;/b&gt; &lt;span style=&quot;color: #6b7280;&quot;&gt;(상태 관리)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&quot;&gt;&lt;b&gt;  Context&lt;/b&gt; &lt;span style=&quot;color: #6b7280;&quot;&gt;(입력 구성)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&quot;&gt;&lt;b&gt;  Control&lt;/b&gt; &lt;span style=&quot;color: #6b7280;&quot;&gt;(제약 / 안전)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&quot;&gt;&lt;b&gt;✅ Verification&lt;/b&gt; &lt;span style=&quot;color: #6b7280;&quot;&gt;(검증)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&quot;&gt;&lt;b&gt;  Lifecycle&lt;/b&gt; &lt;span style=&quot;color: #6b7280;&quot;&gt;(작업 관리)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&quot;&gt;&lt;b&gt;  Persistence&lt;/b&gt; &lt;span style=&quot;color: #6b7280;&quot;&gt;(저장)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;padding: 12px 14px; margin-bottom: 10px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&quot;&gt;&lt;b&gt;  Observability&lt;/b&gt; &lt;span style=&quot;color: #6b7280;&quot;&gt;(로그)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;padding: 12px 14px; background: white; border: 1px solid #eef2f7; border-radius: 12px;&quot;&gt;&lt;b&gt;  Feedback&lt;/b&gt; &lt;span style=&quot;color: #6b7280;&quot;&gt;(개선)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;border-left: 6px solid #10b981; background: #f0fdf4; padding: 18px 20px; border-radius: 12px;&quot;&gt;
&lt;div style=&quot;font-size: 20px; font-weight: bold; margin-bottom: 10px;&quot;&gt;  이해를 위한 비유&lt;/div&gt;
&lt;div style=&quot;font-size: 16px; margin-bottom: 8px;&quot;&gt;&lt;b&gt;LLM = CPU&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 16px; margin-bottom: 12px;&quot;&gt;&lt;b&gt;Harness = 운영체제(OS)&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;font-size: 15px; color: #374151;&quot;&gt;즉, Harness가 없으면 LLM은 실제 시스템으로 안정적으로 동작할 수 없다.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;3014&quot; data-start=&quot;3011&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3032&quot; data-start=&quot;3016&quot; data-section-id=&quot;1553wc4&quot; data-ke-size=&quot;size26&quot;&gt;6. 핵심 패러다임 변화&lt;/h2&gt;
&lt;h3 data-end=&quot;3040&quot; data-start=&quot;3034&quot; data-section-id=&quot;1hrkbt6&quot; data-ke-size=&quot;size23&quot;&gt;과거&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3071&quot; data-start=&quot;3042&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3071&quot; data-start=&quot;3042&quot; data-section-id=&quot;14bx6r4&quot;&gt;LLM 활용 = Prompt Engineering&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;3076&quot; data-start=&quot;3073&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3084&quot; data-start=&quot;3078&quot; data-section-id=&quot;1hrnpta&quot; data-ke-size=&quot;size23&quot;&gt;현재&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3116&quot; data-start=&quot;3086&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3116&quot; data-start=&quot;3086&quot; data-section-id=&quot;1iqyvpg&quot;&gt;LLM 활용 = Harness Engineering&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;3121&quot; data-start=&quot;3118&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;3140&quot; data-start=&quot;3123&quot; data-ke-size=&quot;size16&quot;&gt;이 변화의 본질은 다음과 같다.&lt;/p&gt;
&lt;blockquote data-end=&quot;3171&quot; data-start=&quot;3142&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;3171&quot; data-start=&quot;3144&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;성능은 모델이 아니라 시스템 설계에서 결정된다&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;3176&quot; data-start=&quot;3173&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3192&quot; data-start=&quot;3178&quot; data-section-id=&quot;nqodj1&quot; data-ke-size=&quot;size26&quot;&gt;7. 중요한 인사이트&lt;/h2&gt;
&lt;p data-end=&quot;3227&quot; data-start=&quot;3194&quot; data-ke-size=&quot;size16&quot;&gt;하네스 엔지니어링을 이해할 때 가장 중요한 관점은 이것이다.&lt;/p&gt;
&lt;blockquote data-end=&quot;3254&quot; data-start=&quot;3229&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;3254&quot; data-start=&quot;3231&quot; data-ke-size=&quot;size16&quot;&gt;Agent = Model + Harness&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3289&quot; data-start=&quot;3256&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3271&quot; data-start=&quot;3256&quot; data-section-id=&quot;18ymsxt&quot;&gt;Model &amp;rarr; 추론 능력&lt;/li&gt;
&lt;li data-end=&quot;3289&quot; data-start=&quot;3272&quot; data-section-id=&quot;1r2wep3&quot;&gt;Harness &amp;rarr; 실행 능력&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3335&quot; data-start=&quot;3291&quot; data-ke-size=&quot;size16&quot;&gt;즉, 실제 서비스 품질은 &lt;b&gt;Harness의 설계 수준&lt;/b&gt;에 의해 결정된다.&lt;/p&gt;
&lt;hr data-end=&quot;3340&quot; data-start=&quot;3337&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3350&quot; data-start=&quot;3342&quot; data-section-id=&quot;zq6bc3&quot; data-ke-size=&quot;size26&quot;&gt;8. 결론&lt;/h2&gt;
&lt;p data-end=&quot;3430&quot; data-start=&quot;3352&quot; data-ke-size=&quot;size16&quot;&gt;하네스 엔지니어링은 단순한 도구나 프레임워크가 아니라, LLM 기반 시스템을 제품으로 만들기 위한 &lt;b&gt;핵심 아키텍처 설계 방법론&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;3455&quot; data-start=&quot;3432&quot; data-ke-size=&quot;size16&quot;&gt;앞으로의 AI 개발은 다음과 같이 바뀐다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3498&quot; data-start=&quot;3457&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3476&quot; data-start=&quot;3457&quot; data-section-id=&quot;zffygq&quot;&gt;모델을 잘 쓰는 개발자 &amp;rarr; 한계&lt;/li&gt;
&lt;li data-end=&quot;3498&quot; data-start=&quot;3477&quot; data-section-id=&quot;1r2qknz&quot;&gt;시스템을 설계하는 개발자 &amp;rarr; 경쟁력&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;3503&quot; data-start=&quot;3500&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3517&quot; data-start=&quot;3505&quot; data-section-id=&quot;1b765c3&quot; data-ke-size=&quot;size26&quot;&gt;9. 한 줄 요약&lt;/h2&gt;
&lt;blockquote data-end=&quot;3561&quot; data-start=&quot;3519&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;3561&quot; data-start=&quot;3521&quot; data-ke-size=&quot;size16&quot;&gt;하네스 엔지니어링은 LLM을 &amp;ldquo;실험&amp;rdquo;이 아닌 &amp;ldquo;제품&amp;rdquo;으로 만드는 기술이다&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-section-id=&quot;1b765c3&quot; data-start=&quot;3505&quot; data-end=&quot;3517&quot; data-ke-size=&quot;size26&quot;&gt;10. 마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 최근 굉장히 인기있는 키워드인 하네스 엔지니어링에 대해서 정리해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국내외에서 프롬프트 엔지니어링에 대한 다양한 자료가 쏟아지고 있는 상황에 가장 많이 등장하는 키워드 중에 하나인 하네스 엔지니어링에는 LLM의 현재 위치와 우리의 역할을 살펴볼 수 있는 개념이다.&lt;/p&gt;</description>
      <category>인사이트</category>
      <category>LLM</category>
      <category>인공지능</category>
      <category>프롬프트 엔지니어링</category>
      <category>하네스</category>
      <category>하네스 엔지니어링</category>
      <author>miniberry</author>
      <guid isPermaLink="true">https://miniberry-coding.tistory.com/31</guid>
      <comments>https://miniberry-coding.tistory.com/31#entry31comment</comments>
      <pubDate>Tue, 14 Apr 2026 00:58:12 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 1781번 - 컵라면</title>
      <link>https://miniberry-coding.tistory.com/30</link>
      <description>&lt;h2 data-end=&quot;130&quot; data-start=&quot;119&quot; data-section-id=&quot;g9z66v&quot; data-ke-size=&quot;size26&quot;&gt;1. 문제 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1781&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/1781&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;138&quot; data-start=&quot;132&quot; data-ke-size=&quot;size16&quot;&gt;각 문제마다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;162&quot; data-start=&quot;140&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;150&quot; data-start=&quot;140&quot; data-section-id=&quot;1ymk6dh&quot;&gt;데드라인 (d)&lt;/li&gt;
&lt;li data-end=&quot;162&quot; data-start=&quot;151&quot; data-section-id=&quot;10stuz3&quot;&gt;컵라면 수 (c)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;171&quot; data-start=&quot;164&quot; data-ke-size=&quot;size16&quot;&gt;가 주어진다.&lt;/p&gt;
&lt;p data-end=&quot;223&quot; data-start=&quot;173&quot; data-ke-size=&quot;size16&quot;&gt;모든 문제는 &lt;b&gt;1시간씩&lt;/b&gt; 걸리고,&lt;br /&gt;각 문제는 &lt;b&gt;데드라인 이전에만&lt;/b&gt; 풀 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;256&quot; data-start=&quot;225&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 목표:&lt;br /&gt;&lt;b&gt;얻을 수 있는 컵라면의 최대 개수&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;261&quot; data-start=&quot;258&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;282&quot; data-start=&quot;263&quot; data-section-id=&quot;1694pi1&quot; data-ke-size=&quot;size26&quot;&gt;2. 처음 접근 (틀린 코드)&lt;/h2&gt;
&lt;p data-end=&quot;301&quot; data-start=&quot;284&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 이런 식으로 접근했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775917816330&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;heapq.heappush(heap, (dead_line, -cup))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;402&quot; data-start=&quot;358&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;375&quot; data-start=&quot;358&quot; data-section-id=&quot;1bmalp5&quot;&gt;데드라인 기준으로 정렬하면서&lt;/li&gt;
&lt;li data-end=&quot;402&quot; data-start=&quot;376&quot; data-section-id=&quot;4glj2c&quot;&gt;같은 데드라인이면 컵라면 많은 것 우선 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;417&quot; data-start=&quot;404&quot; data-ke-size=&quot;size16&quot;&gt;그리고 하나 선택한 뒤&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775917825667&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while heap and curr &amp;gt;= heap[0][0]:
	heapq.heappop(heap)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;498&quot; data-start=&quot;493&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;533&quot; data-start=&quot;499&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;507&quot; data-start=&quot;499&quot; data-section-id=&quot;1ovezvs&quot;&gt;하나 고르면&lt;/li&gt;
&lt;li data-end=&quot;533&quot; data-start=&quot;508&quot; data-section-id=&quot;19e6weh&quot;&gt;같은 데드라인 이하 문제는 다 버리는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;538&quot; data-start=&quot;535&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;553&quot; data-start=&quot;540&quot; data-section-id=&quot;xx3hqv&quot; data-ke-size=&quot;size26&quot;&gt;3. 왜 틀렸는가?&lt;/h2&gt;
&lt;p data-end=&quot;561&quot; data-start=&quot;555&quot; data-ke-size=&quot;size16&quot;&gt;핵심 문제&lt;/p&gt;
&lt;blockquote data-end=&quot;593&quot; data-start=&quot;563&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;593&quot; data-start=&quot;565&quot; data-ke-size=&quot;size16&quot;&gt;같은 데드라인에서도 여러 개 선택할 수 있다&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;598&quot; data-start=&quot;595&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;609&quot; data-start=&quot;600&quot; data-section-id=&quot;elw006&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;반례&lt;/h3&gt;
&lt;pre id=&quot;code_1775917834569&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;3
2 10
2 9
2 8&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;670&quot; data-start=&quot;644&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;670&quot; data-start=&quot;644&quot; data-section-id=&quot;1o9lc8e&quot;&gt;데드라인이 2 &amp;rarr; 문제 2개까지 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;675&quot; data-start=&quot;672&quot; data-ke-size=&quot;size16&quot;&gt;정답은 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;10 + 9 = 19인 반면,&lt;/span&gt;&amp;nbsp;내 코드는 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;10을 출력한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &amp;rarr; 이유:&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;778&quot; data-start=&quot;747&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;758&quot; data-start=&quot;747&quot; data-section-id=&quot;1m5uxct&quot;&gt;10 하나 고르고&lt;/li&gt;
&lt;li data-end=&quot;778&quot; data-start=&quot;759&quot; data-section-id=&quot;1qidbnd&quot;&gt;나머지 (9, 8) 전부 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;783&quot; data-start=&quot;780&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;800&quot; data-start=&quot;785&quot; data-section-id=&quot;cab4oy&quot; data-ke-size=&quot;size26&quot;&gt;4. 핵심 개념 깨달음&lt;/h2&gt;
&lt;p data-end=&quot;820&quot; data-start=&quot;802&quot; data-ke-size=&quot;size16&quot;&gt;이 문제의 해결 전략:&lt;/p&gt;
&lt;blockquote data-end=&quot;852&quot; data-start=&quot;822&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;852&quot; data-start=&quot;824&quot; data-ke-size=&quot;size16&quot;&gt;데드라인 d까지는 최대 d개 문제를 풀 수 있다&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;856&quot; data-start=&quot;854&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;데드라인최대 선택 가능 개수&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;964&quot; data-start=&quot;858&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;964&quot; data-start=&quot;911&quot;&gt;
&lt;tr data-end=&quot;928&quot; data-start=&quot;911&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;922&quot; data-start=&quot;911&quot;&gt;1&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;928&quot; data-start=&quot;922&quot;&gt;1개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;946&quot; data-start=&quot;929&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;940&quot; data-start=&quot;929&quot;&gt;2&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;946&quot; data-start=&quot;940&quot;&gt;2개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;964&quot; data-start=&quot;947&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;958&quot; data-start=&quot;947&quot;&gt;3&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;964&quot; data-start=&quot;958&quot;&gt;3개&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;969&quot; data-start=&quot;966&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;988&quot; data-start=&quot;971&quot; data-section-id=&quot;xpfvzu&quot; data-ke-size=&quot;size26&quot;&gt;5. 올바른 접근&lt;/h2&gt;
&lt;h3 data-end=&quot;1004&quot; data-start=&quot;990&quot; data-section-id=&quot;1isumir&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;핵심 아이디어&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1124&quot; data-start=&quot;1006&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1029&quot; data-start=&quot;1006&quot; data-section-id=&quot;2h8wav&quot;&gt;문제를 &lt;b&gt;데드라인 오름차순 정렬&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1059&quot; data-start=&quot;1030&quot; data-section-id=&quot;fkbtv5&quot;&gt;현재까지 선택한 문제들을 &lt;b&gt;heap에 저장&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1124&quot; data-start=&quot;1060&quot; data-section-id=&quot;18m6h77&quot;&gt;만약 선택한 문제 개수 &amp;gt; 현재 데드라인:&amp;nbsp; 가장 컵라면 적은 문제 제거&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;1129&quot; data-start=&quot;1126&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1142&quot; data-start=&quot;1131&quot; data-section-id=&quot;1veya0l&quot; data-ke-size=&quot;size26&quot;&gt;6. 정답 코드&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775917778542&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import heapq
import sys
input = sys.stdin.readline

n = int(input())
problems = []

for _ in range(n):
    d, c = map(int, input().split())
    problems.append((d, c))

problems.sort()

heap = []

for d, c in problems:
    heapq.heappush(heap, c)
    
    if len(heap) &amp;gt; d:
        heapq.heappop(heap)

print(sum(heap))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>코딩테스트</category>
      <category>1781</category>
      <category>Python</category>
      <category>백준</category>
      <category>우선순위 큐</category>
      <category>컵라면</category>
      <category>코딩테스트</category>
      <author>miniberry</author>
      <guid isPermaLink="true">https://miniberry-coding.tistory.com/30</guid>
      <comments>https://miniberry-coding.tistory.com/30#entry30comment</comments>
      <pubDate>Sat, 11 Apr 2026 23:31:12 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 1655번 - 가운데를 말해요</title>
      <link>https://miniberry-coding.tistory.com/29</link>
      <description>&lt;h2 data-end=&quot;137&quot; data-start=&quot;126&quot; data-section-id=&quot;adyiqr&quot; data-ke-size=&quot;size26&quot;&gt;1. 문제 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1655&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/1655&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;188&quot; data-start=&quot;139&quot; data-ke-size=&quot;size16&quot;&gt;정수를 하나씩 입력받을 때마다&lt;br /&gt;지금까지 들어온 값들의 &lt;b&gt;중간값&lt;/b&gt;을 출력하는 문제&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;233&quot; data-start=&quot;190&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;206&quot; data-start=&quot;190&quot; data-section-id=&quot;u44c6w&quot;&gt;홀수 개 &amp;rarr; 정확한 중앙값&lt;/li&gt;
&lt;li data-end=&quot;233&quot; data-start=&quot;207&quot; data-section-id=&quot;1p76cfv&quot;&gt;짝수 개 &amp;rarr; 중앙 두 값 중 &lt;b&gt;작은 값&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;238&quot; data-start=&quot;235&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;256&quot; data-start=&quot;240&quot; data-section-id=&quot;avozgv&quot; data-ke-size=&quot;size26&quot;&gt;2. 처음 접근 (실패)&lt;/h2&gt;
&lt;p data-end=&quot;272&quot; data-start=&quot;258&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 생각했다.&lt;/p&gt;
&lt;blockquote data-end=&quot;294&quot; data-start=&quot;274&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;294&quot; data-start=&quot;276&quot; data-ke-size=&quot;size16&quot;&gt;힙 두 개 쓰면 되지 않을까?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;352&quot; data-start=&quot;301&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;320&quot; data-start=&quot;301&quot; data-section-id=&quot;13fqld5&quot;&gt;min_heap (최소 힙)&lt;/li&gt;
&lt;li data-end=&quot;352&quot; data-start=&quot;321&quot; data-section-id=&quot;shtxl3&quot;&gt;max_heap (최대 힙처럼 사용, 음수 저장)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;389&quot; data-start=&quot;354&quot; data-ke-size=&quot;size16&quot;&gt;두 개를 만들고 입력값을 각각 넣어서 길이를 맞추려고 했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775698863678&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if len(min_heap) &amp;gt; (i+1)//2:
	heapq.heapreplace(min_heap, x)
else:
	heapq.heappush(min_heap, x)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;547&quot; data-start=&quot;508&quot; data-ke-size=&quot;size16&quot;&gt;max_heap도 처리하고, 중간값은 출력&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775698897505&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if i % 2 == 0:
	print(min(min_heap))
else:
	print(-max(max_heap))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;639&quot; data-start=&quot;636&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;649&quot; data-start=&quot;641&quot; data-section-id=&quot;g359b1&quot; data-ke-size=&quot;size26&quot;&gt;2. 문제점&lt;/h2&gt;
&lt;h3 data-end=&quot;674&quot; data-start=&quot;651&quot; data-section-id=&quot;2kaksh&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;1) 두 힙이 &amp;ldquo;분할 구조&amp;rdquo;가 아님&lt;/h3&gt;
&lt;p data-end=&quot;685&quot; data-start=&quot;676&quot; data-ke-size=&quot;size16&quot;&gt;이 방식은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;726&quot; data-start=&quot;687&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;708&quot; data-start=&quot;687&quot; data-section-id=&quot;xpgunf&quot;&gt;같은 값이 두 힙에 동시에 들어가고&lt;/li&gt;
&lt;li data-end=&quot;726&quot; data-start=&quot;709&quot; data-section-id=&quot;126p8ke&quot;&gt;어떤 값은 교체되면서 사라짐&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;730&quot; data-start=&quot;728&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;blockquote data-end=&quot;760&quot; data-start=&quot;732&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;760&quot; data-start=&quot;734&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;작은 값 / 큰 값&amp;rdquo;으로 나뉜 구조가 아님&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;765&quot; data-start=&quot;762&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;794&quot; data-start=&quot;767&quot; data-section-id=&quot;q3pevk&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&amp;nbsp;2) heapreplace를 잘못 사용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;838&quot; data-start=&quot;796&quot; data-ke-size=&quot;size16&quot;&gt;heapreplace는 &amp;ldquo;루트와 비교해서 교체&amp;rdquo;할 때 의미가 있는데, 나는 단순히 &lt;b&gt;길이 기준으로 교체&lt;/b&gt;했다.&lt;/p&gt;
&lt;p data-end=&quot;885&quot; data-start=&quot;866&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;/span&gt;&amp;nbsp;결과: 값의 정렬 정보가 깨짐&lt;/p&gt;
&lt;hr data-end=&quot;890&quot; data-start=&quot;887&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;916&quot; data-start=&quot;892&quot; data-section-id=&quot;2q5e93&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;3) 힙의 루트를 안 쓰고 전체 탐색&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775700298837&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;min(min_heap)
max(max_heap)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;984&quot; data-start=&quot;961&quot; data-ke-size=&quot;size16&quot;&gt;힙의 장점을 완전히 무시한 코드였다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1012&quot; data-start=&quot;986&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1001&quot; data-start=&quot;986&quot; data-section-id=&quot;g5qsos&quot;&gt;힙은 &lt;b&gt;루트만 보장&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1012&quot; data-start=&quot;1002&quot; data-section-id=&quot;ux67el&quot;&gt;전체 정렬 아님&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1035&quot; data-start=&quot;1014&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 무조건 heap[0] 써야 함&lt;/p&gt;
&lt;hr data-end=&quot;1040&quot; data-start=&quot;1037&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1054&quot; data-start=&quot;1042&quot; data-section-id=&quot;2z7ngs&quot; data-ke-size=&quot;size26&quot;&gt;4. 핵심 깨달음&lt;/h2&gt;
&lt;p data-end=&quot;1079&quot; data-start=&quot;1056&quot; data-ke-size=&quot;size16&quot;&gt;이 문제의 핵심은 단순히 힙 2개가 아니라&lt;/p&gt;
&lt;blockquote data-end=&quot;1114&quot; data-start=&quot;1081&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1114&quot; data-start=&quot;1083&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;두 힙이 &amp;ldquo;값의 범위 기준으로 나뉘어야 한다&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;1119&quot; data-start=&quot;1116&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1133&quot; data-start=&quot;1121&quot; data-section-id=&quot;12pgh4a&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;올바른 구조&lt;/h2&gt;
&lt;p data-end=&quot;1152&quot; data-start=&quot;1135&quot; data-ke-size=&quot;size16&quot;&gt;두 힙의 역할은 이렇게 나뉜다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1211&quot; data-start=&quot;1154&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1187&quot; data-start=&quot;1154&quot; data-section-id=&quot;1r3sjfs&quot;&gt;max_heap &amp;rarr; &lt;b&gt;작은 값들 (중간값 포함)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1211&quot; data-start=&quot;1188&quot; data-section-id=&quot;5clq45&quot;&gt;min_heap &amp;rarr; &lt;b&gt;큰 값들&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1229&quot; data-start=&quot;1213&quot; data-ke-size=&quot;size16&quot;&gt;그리고 항상 다음 조건 유지:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;max_heap의 모든 값 &amp;le; min_heap의 모든 값&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1286&quot; data-start=&quot;1276&quot; data-ke-size=&quot;size16&quot;&gt;그리고 크기 조건:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775700315499&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;len(max_heap) == len(min_heap) 또는
len(max_heap) == len(min_heap) + 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1373&quot; data-start=&quot;1370&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1398&quot; data-start=&quot;1375&quot; data-section-id=&quot;1gfwypl&quot; data-ke-size=&quot;size26&quot;&gt;5. 중요했던 포인트: swap&lt;/h2&gt;
&lt;p data-end=&quot;1416&quot; data-start=&quot;1400&quot; data-ke-size=&quot;size16&quot;&gt;가장 헷갈렸던 부분&lt;/p&gt;
&lt;blockquote data-end=&quot;1446&quot; data-start=&quot;1418&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1446&quot; data-start=&quot;1420&quot; data-ke-size=&quot;size16&quot;&gt;왜 하나만 옮기지 않고, 두 개를 교환하지?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-end=&quot;1457&quot; data-start=&quot;1448&quot; data-section-id=&quot;5n51m4&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;1) 의문&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;max_heap&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;rarr;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;min_heap으로&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;하나만&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;보내면&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;안&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;되나&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1512&quot; data-start=&quot;1509&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1535&quot; data-start=&quot;1514&quot; data-section-id=&quot;o95epd&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;2) 안 되는 경우&lt;/h3&gt;
&lt;p data-end=&quot;1552&quot; data-start=&quot;1537&quot; data-ke-size=&quot;size16&quot;&gt;문제되는 상황:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;max_heap: [큰 값이 들어가 있음]&lt;/span&gt;&lt;br /&gt;&lt;span&gt;min_heap: [작은 값이 들어가 있음]&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1618&quot; data-start=&quot;1616&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;p data-end=&quot;1636&quot; data-start=&quot;1620&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;rarr; 경계가 꼬인 상태&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1641&quot; data-start=&quot;1638&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1657&quot; data-start=&quot;1643&quot; data-section-id=&quot;1ow6vdy&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp; 한쪽만 이동하면&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1685&quot; data-start=&quot;1659&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1673&quot; data-start=&quot;1659&quot; data-section-id=&quot;7rqtfs&quot;&gt;순서가 여전히 깨지거나&lt;/li&gt;
&lt;li data-end=&quot;1685&quot; data-start=&quot;1674&quot; data-section-id=&quot;18ljh3h&quot;&gt;크기 균형이 깨짐&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1708&quot; data-start=&quot;1692&quot; data-section-id=&quot;1y2o9q6&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp; 3) swap 하여 해결&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775700341197&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;max_value = -heapq.heappop(max_heap)
min_value = heapq.heappop(min_heap)

heapq.heappush(max_heap, -min_value)
heapq.heappush(min_heap, max_value)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1878&quot; data-start=&quot;1872&quot; data-ke-size=&quot;size16&quot;&gt;효과:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1914&quot; data-start=&quot;1880&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1897&quot; data-start=&quot;1880&quot; data-section-id=&quot;6g33v1&quot;&gt;잘못된 값 위치를 서로 교환&lt;/li&gt;
&lt;li data-end=&quot;1914&quot; data-start=&quot;1898&quot; data-section-id=&quot;1saosb7&quot;&gt;순서 + 크기 동시에 복구&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1919&quot; data-start=&quot;1916&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1929&quot; data-start=&quot;1921&quot; data-section-id=&quot;13he9q0&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;4) 직관&lt;/h2&gt;
&lt;p data-end=&quot;1948&quot; data-start=&quot;1931&quot; data-ke-size=&quot;size16&quot;&gt;두 힙은 다음과 같이 나뉘어야 한다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775700419997&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[작은 값들 -&amp;gt; max_heap
[큰 값들] -&amp;gt; min_heap&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2028&quot; data-start=&quot;2020&quot; data-ke-size=&quot;size16&quot;&gt;잘못되면 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;[작은 값 + 큰 값] | [작은 값 + 큰 값]과 같이 섞인다&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;해결 방법:&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;2105&quot; data-start=&quot;2082&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2105&quot; data-start=&quot;2084&quot; data-ke-size=&quot;size16&quot;&gt;잘못 들어간 두 값을 서로 교환&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;2110&quot; data-start=&quot;2107&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2122&quot; data-start=&quot;2112&quot; data-section-id=&quot;10ahu0h&quot; data-ke-size=&quot;size26&quot;&gt;6. 최종 코드&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775700589444&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import heapq
import sys
input = sys.stdin.readline

min_heap = []
max_heap = []
n = int(input())

for _ in range(n):
    x = int(input())
    if len(max_heap) == len(min_heap):
        heapq.heappush(max_heap, -x)
    else:
        heapq.heappush(min_heap, x)

    if min_heap and -min_heap[0] &amp;gt; max_heap[0]:
        max_value = -heapq.heappop(max_heap)
        min_value = heapq.heappop(min_heap)

        heapq.heappush(max_heap, -min_value)
        heapq.heappush(min_heap, max_value)

    print(-max_heap[0])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;2656&quot; data-start=&quot;2653&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2670&quot; data-start=&quot;2658&quot; data-section-id=&quot;1xj5ocw&quot; data-ke-size=&quot;size26&quot;&gt;7. 시간 복잡도&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2706&quot; data-start=&quot;2672&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2688&quot; data-start=&quot;2672&quot; data-section-id=&quot;1raogvi&quot;&gt;삽입: O(log N)&lt;/li&gt;
&lt;li data-end=&quot;2706&quot; data-start=&quot;2689&quot; data-section-id=&quot;11f4ikl&quot;&gt;총: O(N log N)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2733&quot; data-start=&quot;2708&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; N = 100,000까지 안정적으로 통과&lt;/p&gt;</description>
      <category>코딩테스트</category>
      <author>miniberry</author>
      <guid isPermaLink="true">https://miniberry-coding.tistory.com/29</guid>
      <comments>https://miniberry-coding.tistory.com/29#entry29comment</comments>
      <pubDate>Thu, 9 Apr 2026 11:22:07 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 1202번 - 보석 도둑</title>
      <link>https://miniberry-coding.tistory.com/28</link>
      <description>&lt;h2 data-end=&quot;123&quot; data-start=&quot;112&quot; data-section-id=&quot;g9z66v&quot; data-ke-size=&quot;size26&quot;&gt;1. 문제 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1202&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/1202&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;196&quot; data-start=&quot;125&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;145&quot; data-start=&quot;125&quot; data-section-id=&quot;6jsefo&quot;&gt;보석 N개 (무게 M, 가격 V)&lt;/li&gt;
&lt;li data-end=&quot;177&quot; data-start=&quot;146&quot; data-section-id=&quot;eaop3i&quot;&gt;가방 K개 (각 가방은 하나의 보석만 담을 수 있음)&lt;/li&gt;
&lt;li data-end=&quot;196&quot; data-start=&quot;178&quot; data-section-id=&quot;xahn2p&quot;&gt;가방마다 최대 무게 제한 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;229&quot; data-start=&quot;198&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 목표: &lt;b&gt;담을 수 있는 보석 가격 합의 최대값&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;234&quot; data-start=&quot;231&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;252&quot; data-start=&quot;236&quot; data-section-id=&quot;1r8zrm5&quot; data-ke-size=&quot;size26&quot;&gt;2. 처음 접근 (실패)&lt;/h2&gt;
&lt;p data-end=&quot;268&quot; data-start=&quot;254&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 이렇게 생각했다.&lt;/p&gt;
&lt;blockquote data-end=&quot;296&quot; data-start=&quot;270&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;296&quot; data-start=&quot;272&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;가장 비싼 보석부터 넣으면 되지 않을까?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;305&quot; data-start=&quot;298&quot; data-ke-size=&quot;size16&quot;&gt;그래서 구현:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775634261355&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;heapq.heappush(jewels, (-v, m)) # 가치 기준 최대힙&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;371&quot; data-start=&quot;367&quot; data-ke-size=&quot;size16&quot;&gt;그리고:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775634268161&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if bags[0] &amp;gt;= m:
	heapq.heappop(bags)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;432&quot; data-start=&quot;429&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;443&quot; data-start=&quot;434&quot; data-section-id=&quot;1odeq8u&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;문제점&lt;/h3&gt;
&lt;p data-end=&quot;466&quot; data-start=&quot;445&quot; 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-end=&quot;508&quot; data-start=&quot;468&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;483&quot; data-start=&quot;468&quot; data-section-id=&quot;155lbr7&quot;&gt;가치 높은 보석부터 꺼냄&lt;/li&gt;
&lt;li data-end=&quot;508&quot; data-start=&quot;484&quot; data-section-id=&quot;17kjky7&quot;&gt;가장 작은 가방 하나만 보고 넣을지 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;516&quot; data-start=&quot;510&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;문제:&lt;/p&gt;
&lt;blockquote data-end=&quot;557&quot; data-start=&quot;518&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;557&quot; data-start=&quot;520&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;뒤에 있는 더 큰 가방에 들어갈 수 있는 보석도 그냥 버려짐&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;562&quot; data-start=&quot;559&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;576&quot; data-start=&quot;564&quot; data-section-id=&quot;50can&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;핵심 반례&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;2 2&lt;/span&gt;&lt;br /&gt;&lt;span&gt;10 100&lt;/span&gt;&lt;br /&gt;&lt;span&gt;2 99&lt;/span&gt;&lt;br /&gt;&lt;span&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span&gt;10&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;620&quot; data-start=&quot;612&quot; data-ke-size=&quot;size16&quot;&gt;내 코드 결과:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;661&quot; data-start=&quot;622&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;645&quot; data-start=&quot;622&quot; data-section-id=&quot;1wnss81&quot;&gt;100 &amp;rarr; 가방 2 못 들어감 &amp;rarr; 버림&lt;/li&gt;
&lt;li data-end=&quot;661&quot; data-start=&quot;646&quot; data-section-id=&quot;15t74gu&quot;&gt;99 &amp;rarr; 가방 2에 넣음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;676&quot; data-start=&quot;663&quot; data-ke-size=&quot;size16&quot;&gt;결과: &lt;b&gt;99&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;676&quot; data-start=&quot;663&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;681&quot; data-start=&quot;678&quot; data-ke-size=&quot;size16&quot;&gt;정답:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;708&quot; data-start=&quot;683&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;694&quot; data-start=&quot;683&quot; data-section-id=&quot;wbtdk1&quot;&gt;99 &amp;rarr; 가방 2&lt;/li&gt;
&lt;li data-end=&quot;708&quot; data-start=&quot;695&quot; data-section-id=&quot;e348hv&quot;&gt;100 &amp;rarr; 가방 10&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;724&quot; data-start=&quot;710&quot; data-ke-size=&quot;size16&quot;&gt;결과: &lt;b&gt;199&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;729&quot; data-start=&quot;726&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;751&quot; data-start=&quot;731&quot; data-section-id=&quot;5pxpgo&quot; data-ke-size=&quot;size26&quot;&gt;3. 두 번째 접근 (또 실패)&lt;/h2&gt;
&lt;p data-end=&quot;766&quot; data-start=&quot;753&quot; data-ke-size=&quot;size16&quot;&gt;이번엔 반대로 생각했다.&lt;/p&gt;
&lt;blockquote data-end=&quot;791&quot; data-start=&quot;768&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;791&quot; data-start=&quot;770&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;작은 보석부터 넣으면 되지 않을까?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775634278224&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;heapq.heappush(jewels, (m, -v)) # 무게 기준&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;852&quot; data-start=&quot;849&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;863&quot; data-start=&quot;854&quot; data-section-id=&quot;1odeq8u&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;문제점&lt;/h3&gt;
&lt;p data-end=&quot;892&quot; data-start=&quot;865&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 &lt;b&gt;작은 보석을 너무 빨리 사용&lt;/b&gt;해버림&lt;/p&gt;
&lt;hr data-end=&quot;897&quot; data-start=&quot;894&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;908&quot; data-start=&quot;899&quot; data-section-id=&quot;elw006&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;반례&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;3 2&lt;/span&gt;&lt;br /&gt;&lt;span&gt;1 1&lt;/span&gt;&lt;br /&gt;&lt;span&gt;2 100&lt;/span&gt;&lt;br /&gt;&lt;span&gt;3 99&lt;/span&gt;&lt;br /&gt;&lt;span&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span&gt;3&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;951&quot; data-start=&quot;946&quot; data-ke-size=&quot;size16&quot;&gt;내 코드:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;990&quot; data-start=&quot;953&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;970&quot; data-start=&quot;953&quot; data-section-id=&quot;1fnbi09&quot;&gt;(1,1) &amp;rarr; 가방 2 사용&lt;/li&gt;
&lt;li data-end=&quot;990&quot; data-start=&quot;971&quot; data-section-id=&quot;pwo1rf&quot;&gt;(2,100) &amp;rarr; 가방 3 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1006&quot; data-start=&quot;992&quot; data-ke-size=&quot;size16&quot;&gt;결과: &lt;b&gt;101&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1006&quot; data-start=&quot;992&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1011&quot; data-start=&quot;1008&quot; data-ke-size=&quot;size16&quot;&gt;정답:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1045&quot; data-start=&quot;1013&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1029&quot; data-start=&quot;1013&quot; data-section-id=&quot;1l47cwf&quot;&gt;(2,100) &amp;rarr; 가방 2&lt;/li&gt;
&lt;li data-end=&quot;1045&quot; data-start=&quot;1030&quot; data-section-id=&quot;9lusvy&quot;&gt;(3,99) &amp;rarr; 가방 3&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1061&quot; data-start=&quot;1047&quot; data-ke-size=&quot;size16&quot;&gt;결과: &lt;b&gt;199&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1066&quot; data-start=&quot;1063&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1086&quot; data-start=&quot;1068&quot; data-section-id=&quot;1pexz7&quot; data-ke-size=&quot;size26&quot;&gt;4. 깨달음&lt;/h2&gt;
&lt;p data-end=&quot;1110&quot; data-start=&quot;1088&quot; data-ke-size=&quot;size16&quot;&gt;이 문제는 보석을 고르는 문제가 아니라,&lt;/p&gt;
&lt;blockquote data-end=&quot;1143&quot; data-start=&quot;1112&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1143&quot; data-start=&quot;1114&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;각 가방에 어떤 보석을 넣을지를 결정하는 문제&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;1148&quot; data-start=&quot;1145&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1162&quot; data-start=&quot;1150&quot; data-section-id=&quot;1g5z2o3&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;잘못된 접근&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;보석 &amp;rarr; 가방 찾기&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1191&quot; data-start=&quot;1188&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1205&quot; data-start=&quot;1193&quot; data-section-id=&quot;cwx8dq&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;올바른 접근&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;가방 &amp;rarr; 넣을 보석 선택&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1237&quot; data-start=&quot;1234&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1253&quot; data-start=&quot;1239&quot; data-section-id=&quot;tio9g2&quot; data-ke-size=&quot;size26&quot;&gt;5. 최종 해결 전략&lt;/h2&gt;
&lt;h3 data-end=&quot;1266&quot; data-start=&quot;1255&quot; data-section-id=&quot;1qb7f3j&quot; data-ke-size=&quot;size23&quot;&gt;핵심 아이디어&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1341&quot; data-start=&quot;1268&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1289&quot; data-start=&quot;1268&quot; data-section-id=&quot;3wd9e6&quot;&gt;가방을 &lt;b&gt;작은 순서대로 처리&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1316&quot; data-start=&quot;1290&quot; data-section-id=&quot;16spj21&quot;&gt;현재 가방에 들어갈 수 있는 보석들을 모음&lt;/li&gt;
&lt;li data-end=&quot;1341&quot; data-start=&quot;1317&quot; data-section-id=&quot;i9orwo&quot;&gt;그중 &lt;b&gt;가장 가치가 큰 보석 선택&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;1346&quot; data-start=&quot;1343&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1359&quot; data-start=&quot;1348&quot; data-section-id=&quot;1pcwpp9&quot; data-ke-size=&quot;size26&quot;&gt;6. 구현 코드&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775634296325&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import heapq
import sys
input = sys.stdin.readline

n, k = map(int, input().split())
jewels = list(sorted(tuple(map(int, input().split())) for _ in range(n)))
bags = list(sorted(int(input()) for _ in range(k)))
candidate = []
cost = 0
index = 0

for bag in bags:
    while index &amp;lt; n and jewels[index][0] &amp;lt;= bag:
        heapq.heappush(candidate, -jewels[index][1])
        index += 1
    
    if candidate:
        cost -= heapq.heappop(candidate)

print(cost)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1866&quot; data-start=&quot;1863&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1879&quot; data-start=&quot;1868&quot; data-section-id=&quot;vvlxp0&quot; data-ke-size=&quot;size26&quot;&gt;7. 시간복잡도&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1934&quot; data-start=&quot;1881&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1909&quot; data-start=&quot;1881&quot; data-section-id=&quot;16y2lny&quot;&gt;정렬: O(N log N + K log K)&lt;/li&gt;
&lt;li data-end=&quot;1934&quot; data-start=&quot;1910&quot; data-section-id=&quot;pgnce8&quot;&gt;힙 연산: O((N+K) log N)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1960&quot; data-start=&quot;1936&quot; data-ke-size=&quot;size16&quot;&gt;총: &lt;b&gt;O((N+K) log N)&lt;/b&gt;&lt;/p&gt;</description>
      <category>코딩테스트</category>
      <category>1202</category>
      <category>Python</category>
      <category>백준</category>
      <category>보석 도둑</category>
      <category>우선순위 큐</category>
      <category>코딩테스트</category>
      <author>miniberry</author>
      <guid isPermaLink="true">https://miniberry-coding.tistory.com/28</guid>
      <comments>https://miniberry-coding.tistory.com/28#entry28comment</comments>
      <pubDate>Wed, 8 Apr 2026 17:06:13 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 1715번 - 카드 정렬하기</title>
      <link>https://miniberry-coding.tistory.com/27</link>
      <description>&lt;h2 data-end=&quot;129&quot; data-start=&quot;112&quot; data-section-id=&quot;1n7zq4a&quot; data-ke-size=&quot;size26&quot;&gt;1. 문제를 처음 봤을 때&lt;/h2&gt;
&lt;p data-end=&quot;190&quot; data-start=&quot;131&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 단순히&lt;br /&gt;&amp;ldquo;카드를 합치면 비용이 든다 &amp;rarr; 그냥 순서대로 더하면 되지 않나?&amp;rdquo;&lt;br /&gt;라고 생각했다.&lt;/p&gt;
&lt;p data-end=&quot;202&quot; data-start=&quot;192&quot; data-ke-size=&quot;size16&quot;&gt;하지만 예시를 보면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;267&quot; data-start=&quot;204&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;235&quot; data-start=&quot;204&quot; data-section-id=&quot;16gck5n&quot;&gt;(10 + 20) + (30 + 40) = 100&lt;/li&gt;
&lt;li data-end=&quot;267&quot; data-start=&quot;236&quot; data-section-id=&quot;1eitonj&quot;&gt;(10 + 40) + (50 + 20) = 120&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;295&quot; data-start=&quot;269&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;합치는 순서에 따라 비용이 달라진다&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;304&quot; data-start=&quot;297&quot; data-ke-size=&quot;size16&quot;&gt;여기서 핵심은&lt;/p&gt;
&lt;blockquote data-end=&quot;329&quot; data-start=&quot;306&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;329&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;어떤 순서로 합쳐야 최소가 되는가?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;334&quot; data-start=&quot;331&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;356&quot; data-start=&quot;336&quot; data-section-id=&quot;10s38yy&quot; data-ke-size=&quot;size26&quot;&gt;2. 처음 접근 (잘못된 방식)&lt;/h2&gt;
&lt;p data-end=&quot;375&quot; data-start=&quot;358&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 이런 식으로 구현했다.&lt;/p&gt;
&lt;pre id=&quot;code_1775543373205&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;answer += answer + heapq.heappop(heap)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;433&quot; data-start=&quot;431&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;469&quot; data-start=&quot;434&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;469&quot; data-start=&quot;434&quot; data-section-id=&quot;83s09l&quot;&gt;이전 결과(answer)를 계속 재활용하면서 더하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;497&quot; data-start=&quot;471&quot; data-ke-size=&quot;size16&quot;&gt;하지만 이건 문제의 구조를 잘못 이해한 것이다.&lt;/p&gt;
&lt;h3 data-end=&quot;512&quot; data-start=&quot;499&quot; data-section-id=&quot;17coc79&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;왜 틀렸는가?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;549&quot; data-start=&quot;514&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;534&quot; data-start=&quot;514&quot; data-section-id=&quot;17ffw6d&quot;&gt;answer는 &amp;ldquo;총 비용&amp;rdquo;이지&lt;/li&gt;
&lt;li data-end=&quot;549&quot; data-start=&quot;535&quot; data-section-id=&quot;21x553&quot;&gt;&amp;ldquo;카드 묶음&amp;rdquo;이 아니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;584&quot; data-start=&quot;551&quot; data-ke-size=&quot;size16&quot;&gt;나는 answer를 카드 묶음처럼 사용해버림&lt;/p&gt;
&lt;hr data-end=&quot;589&quot; data-start=&quot;586&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;603&quot; data-start=&quot;591&quot; data-section-id=&quot;19bq7zd&quot; data-ke-size=&quot;size26&quot;&gt;3. 핵심 깨달음&lt;/h2&gt;
&lt;p data-end=&quot;625&quot; data-start=&quot;605&quot; data-ke-size=&quot;size16&quot;&gt;이 문제에서 중요한 건 딱 하나였다.&lt;/p&gt;
&lt;blockquote data-end=&quot;664&quot; data-start=&quot;627&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;664&quot; data-start=&quot;629&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;ldquo;합친 카드 묶음도 다시 하나의 묶음으로 취급해야 한다&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;668&quot; data-start=&quot;666&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;724&quot; data-start=&quot;670&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;682&quot; data-start=&quot;670&quot; data-section-id=&quot;1geok11&quot;&gt;두 묶음을 합친다&lt;/li&gt;
&lt;li data-end=&quot;702&quot; data-start=&quot;683&quot; data-section-id=&quot;1rnx7kq&quot;&gt;그 결과를 다시 후보에 넣는다&lt;/li&gt;
&lt;li data-end=&quot;724&quot; data-start=&quot;703&quot; data-section-id=&quot;9h1h4x&quot;&gt;다시 가장 작은 두 개를 선택한다&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;741&quot; data-start=&quot;726&quot; data-ke-size=&quot;size16&quot;&gt;이 흐름이 반복되어야 한다.&lt;/p&gt;
&lt;hr data-end=&quot;746&quot; data-start=&quot;743&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;783&quot; data-start=&quot;748&quot; data-section-id=&quot;26uxk3&quot; data-ke-size=&quot;size26&quot;&gt;4. 올바른 접근: 최소 힙 (Priority Queue)&lt;/h2&gt;
&lt;p data-end=&quot;809&quot; data-start=&quot;785&quot; data-ke-size=&quot;size16&quot;&gt;그래서 필요한 게 바로 &lt;b&gt;최소 힙&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;820&quot; data-start=&quot;811&quot; data-ke-size=&quot;size16&quot;&gt;이유는 간단하다.&lt;/p&gt;
&lt;blockquote data-end=&quot;854&quot; data-start=&quot;822&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;854&quot; data-start=&quot;824&quot; data-ke-size=&quot;size16&quot;&gt;매번 &amp;ldquo;가장 작은 두 묶음&amp;rdquo;을 빠르게 꺼내야 하기 때문&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;859&quot; data-start=&quot;856&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;872&quot; data-start=&quot;861&quot; data-section-id=&quot;3r7sj3&quot; data-ke-size=&quot;size26&quot;&gt;5. 최종 코드&lt;/h2&gt;
&lt;pre id=&quot;code_1775543413951&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import heapq
import sys
input = sys.stdin.readline

n = int(input())
heap = []
answer = 0

for _ in range(n):
    heapq.heappush(heap, int(input()))

while len(heap) &amp;gt; 1:
    card_sum = heapq.heappop(heap) + heapq.heappop(heap)
    answer += card_sum
    heapq.heappush(heap, card_sum)

print(answer)&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1193&quot; data-start=&quot;1190&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1211&quot; data-start=&quot;1195&quot; data-section-id=&quot;lvo8yr&quot; data-ke-size=&quot;size26&quot;&gt;6. 왜 최적인가?&lt;/h2&gt;
&lt;p data-end=&quot;1227&quot; data-start=&quot;1213&quot; data-ke-size=&quot;size16&quot;&gt;이 문제는 사실 구조적으로&lt;/p&gt;
&lt;blockquote data-end=&quot;1266&quot; data-start=&quot;1229&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1266&quot; data-start=&quot;1231&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;ldquo;항상 작은 것부터 합치는 것이 전체 비용을 최소화한다&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;1278&quot; data-start=&quot;1268&quot; data-ke-size=&quot;size16&quot;&gt;는 성질을 가진다.&lt;/p&gt;
&lt;p data-end=&quot;1288&quot; data-start=&quot;1280&quot; data-ke-size=&quot;size16&quot;&gt;직관적으로 보면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1354&quot; data-start=&quot;1290&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1322&quot; data-start=&quot;1290&quot; data-section-id=&quot;aumv1o&quot;&gt;큰 값끼리 먼저 합치면 &amp;rarr; 이후 계속 큰 비용이 누적됨&lt;/li&gt;
&lt;li data-end=&quot;1354&quot; data-start=&quot;1323&quot; data-section-id=&quot;17la7jx&quot;&gt;작은 값끼리 먼저 합치면 &amp;rarr; 비용 증가를 최소화 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1383&quot; data-start=&quot;1356&quot; data-ke-size=&quot;size16&quot;&gt;이게 바로 &lt;b&gt;그리디 전략&lt;/b&gt;이 성립하는 이유다.&lt;/p&gt;
&lt;hr data-end=&quot;1388&quot; data-start=&quot;1385&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1401&quot; data-start=&quot;1390&quot; data-section-id=&quot;vvlxp0&quot; data-ke-size=&quot;size26&quot;&gt;7. 시간복잡도&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1430&quot; data-start=&quot;1403&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1419&quot; data-start=&quot;1403&quot; data-section-id=&quot;sqebqn&quot;&gt;힙 연산: O(log N)&lt;/li&gt;
&lt;li data-end=&quot;1430&quot; data-start=&quot;1420&quot; data-section-id=&quot;1gdu3k4&quot;&gt;총 반복: N번&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1453&quot; data-start=&quot;1432&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;/span&gt;&amp;nbsp;전체: &lt;b&gt;O(N log N)&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1478&quot; data-start=&quot;1455&quot; data-ke-size=&quot;size16&quot;&gt;N = 100,000까지 충분히 통과 가능&lt;/p&gt;</description>
      <category>코딩테스트</category>
      <category>1715</category>
      <category>Python</category>
      <category>그리디</category>
      <category>백준</category>
      <category>우선순위 큐</category>
      <category>카드정렬하기</category>
      <category>코딩테스트</category>
      <category>힙</category>
      <author>miniberry</author>
      <guid isPermaLink="true">https://miniberry-coding.tistory.com/27</guid>
      <comments>https://miniberry-coding.tistory.com/27#entry27comment</comments>
      <pubDate>Tue, 7 Apr 2026 15:33:32 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 2075번 - N번째 큰 수</title>
      <link>https://miniberry-coding.tistory.com/26</link>
      <description>&lt;h2 data-end=&quot;134&quot; data-start=&quot;123&quot; data-ke-size=&quot;size26&quot;&gt;1. 문제 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2075&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/2075&lt;/a&gt;&lt;/p&gt;
&lt;p data-end=&quot;194&quot; data-start=&quot;136&quot; data-ke-size=&quot;size16&quot;&gt;N &amp;times; N 크기의 표가 주어지고,&lt;br /&gt;각 열은 &lt;b&gt;위에서 아래로 갈수록 값이 증가하는 특징&lt;/b&gt;을 가진다.&lt;/p&gt;
&lt;p data-end=&quot;225&quot; data-start=&quot;196&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 목표: &lt;b&gt;전체 수 중 N번째로 큰 값 찾기&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;230&quot; data-start=&quot;227&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;247&quot; data-start=&quot;232&quot; data-ke-size=&quot;size26&quot;&gt;2. 처음 접근 (실패)&lt;/h2&gt;
&lt;p data-end=&quot;264&quot; data-start=&quot;249&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 단순하게 생각했다.&lt;/p&gt;
&lt;blockquote data-end=&quot;300&quot; data-start=&quot;266&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;300&quot; data-start=&quot;268&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;전체에서 N번째 큰 수니까 다 넣고 뽑으면 되지 않나?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;316&quot; data-start=&quot;302&quot; data-ke-size=&quot;size16&quot;&gt;그래서 아래처럼 구현했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775469623351&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import heapq
import sys
input = sys.stdin.readline

heap = []
n = int(input())

for i in range(n):
    row = list(map(int, input().split()))
    for x in row:
        heapq.heappush(heap, -x)

for _ in range(n):
    k = -heapq.heappop(heap)

print(k)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;607&quot; data-start=&quot;584&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 최대 힙처럼 쓰기 위해 -x 사용&lt;/p&gt;
&lt;hr data-end=&quot;612&quot; data-start=&quot;609&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;630&quot; data-start=&quot;614&quot; data-ke-size=&quot;size26&quot;&gt;3. 결과: 메모리 초과&lt;/h2&gt;
&lt;h3 data-end=&quot;643&quot; data-start=&quot;632&quot; data-ke-size=&quot;size23&quot;&gt;왜 터졌을까?&lt;/h3&gt;
&lt;p data-end=&quot;651&quot; data-start=&quot;645&quot; data-ke-size=&quot;size16&quot;&gt;핵심 원인:&lt;/p&gt;
&lt;blockquote data-end=&quot;679&quot; data-start=&quot;653&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;679&quot; data-start=&quot;655&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 데이터를 힙에 저장했기 때문&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;684&quot; data-start=&quot;681&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;698&quot; data-start=&quot;686&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;메모리 분석&lt;/h2&gt;
&lt;p data-end=&quot;706&quot; data-start=&quot;700&quot; data-ke-size=&quot;size16&quot;&gt;최대 입력:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;758&quot; data-start=&quot;708&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;724&quot; data-start=&quot;708&quot;&gt;&lt;span&gt;&lt;span&gt;N=1500N = 1500&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;758&quot; data-start=&quot;725&quot;&gt;총 데이터 수 = &lt;span&gt;&lt;span&gt;N&lt;b&gt;&amp;sup2; &lt;/b&gt;= 2,250,000&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;775&quot; data-start=&quot;760&quot; data-ke-size=&quot;size16&quot;&gt;즉, 힙에 들어가는 데이터:&lt;/p&gt;
&lt;p data-end=&quot;792&quot; data-start=&quot;777&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;rarr; 약 225만 개&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;797&quot; data-start=&quot;794&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;821&quot; data-start=&quot;799&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;파이썬에서 더 치명적인 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;871&quot; data-start=&quot;823&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;851&quot; data-start=&quot;823&quot;&gt;파이썬 int는 객체라서 메모리를 많이 먹음&lt;/li&gt;
&lt;li data-end=&quot;871&quot; data-start=&quot;852&quot;&gt;리스트 + 힙 구조까지 고려하면&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;895&quot; data-start=&quot;873&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;rarr; 12MB 제한 절대 못 버팀&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;900&quot; data-start=&quot;897&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;918&quot; data-start=&quot;902&quot; data-ke-size=&quot;size26&quot;&gt;4. 문제의 핵심 깨달음&lt;/h2&gt;
&lt;p data-end=&quot;931&quot; data-start=&quot;920&quot; data-ke-size=&quot;size16&quot;&gt;중요한 질문:&lt;/p&gt;
&lt;blockquote data-end=&quot;959&quot; data-start=&quot;933&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;959&quot; data-start=&quot;935&quot; data-ke-size=&quot;size16&quot;&gt;우리가 진짜 필요한 건 모든 값인가?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;973&quot; data-start=&quot;961&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 답: &lt;b&gt;아님&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-end=&quot;1007&quot; data-start=&quot;984&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1007&quot; data-start=&quot;986&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;N번째 큰 수 하나만 필요&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;1012&quot; data-start=&quot;1009&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1027&quot; data-start=&quot;1014&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;해결 아이디어&lt;/h2&gt;
&lt;p data-end=&quot;1058&quot; data-start=&quot;1029&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;전체를 저장하지 말고, 필요한 것만 유지하자&amp;rdquo;&lt;/p&gt;
&lt;h3 data-end=&quot;1067&quot; data-start=&quot;1060&quot; data-ke-size=&quot;size23&quot;&gt;전략:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1108&quot; data-start=&quot;1069&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1089&quot; data-start=&quot;1069&quot;&gt;&lt;b&gt;크기가 N인 최소 힙 유지&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1108&quot; data-start=&quot;1090&quot;&gt;항상 &amp;ldquo;큰 값 N개만&amp;rdquo; 남기기&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1113&quot; data-start=&quot;1110&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1125&quot; data-start=&quot;1115&quot; data-ke-size=&quot;size26&quot;&gt;5. 알고리즘&lt;/h2&gt;
&lt;p data-end=&quot;1138&quot; data-start=&quot;1127&quot; data-ke-size=&quot;size16&quot;&gt;각 숫자 x에 대해&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775469681369&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. 힙 크기 &amp;lt; N &amp;rarr; 그냥 넣기
2. 힙 크기 == N
    &amp;rarr; x &amp;gt; heap[0] (현재 N번째 큰 값)
        &amp;rarr; heap[0] 제거 후 x 삽입
    &amp;rarr; 아니면 버림&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1257&quot; data-start=&quot;1254&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1269&quot; data-start=&quot;1259&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;개선 코드&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775469664144&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import heapq
import sys
input = sys.stdin.readline

n = int(input())
heap = []

for _ in range(n):
    row = map(int, input().split())
    for x in row:
        if len(heap) &amp;lt; n:
            heapq.heappush(heap, x)
        else:
            if x &amp;gt; heap[0]:
                heapq.heapreplace(heap, x)

print(heap[0])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1605&quot; data-start=&quot;1602&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1621&quot; data-start=&quot;1607&quot; data-ke-size=&quot;size26&quot;&gt;6. 핵심 차이 비교&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;구분기존 코드개선 코드
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1765&quot; data-start=&quot;1623&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1765&quot; data-start=&quot;1677&quot;&gt;
&lt;tr data-end=&quot;1714&quot; data-start=&quot;1677&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1684&quot; data-start=&quot;1677&quot;&gt;힙 크기&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1699&quot; data-start=&quot;1684&quot;&gt;N&amp;sup2; (최대 225만)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1714&quot; data-start=&quot;1699&quot;&gt;N (최대 1500)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1736&quot; data-start=&quot;1715&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1721&quot; data-start=&quot;1715&quot;&gt;메모리&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1728&quot; data-start=&quot;1721&quot;&gt;초과&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1736&quot; data-start=&quot;1728&quot;&gt;통과&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1765&quot; data-start=&quot;1737&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1745&quot; data-start=&quot;1737&quot;&gt;접근 방식&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1753&quot; data-start=&quot;1745&quot;&gt;전체 저장&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1765&quot; data-start=&quot;1753&quot;&gt;Top-N 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1770&quot; data-start=&quot;1767&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1783&quot; data-start=&quot;1772&quot; data-ke-size=&quot;size26&quot;&gt;7. 시간 복잡도&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1824&quot; data-start=&quot;1785&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1802&quot; data-start=&quot;1785&quot;&gt;전체 데이터: &lt;span&gt;N&amp;sup2; &lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1824&quot; data-start=&quot;1803&quot;&gt;힙 연산: &lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1848&quot; data-start=&quot;1826&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 전체: &lt;b&gt;O(N&amp;sup2; log N)&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1872&quot; data-start=&quot;1850&quot; data-ke-size=&quot;size16&quot;&gt;(시간은 비슷하지만 메모리가 핵심 차이)&lt;/p&gt;
&lt;hr data-end=&quot;1877&quot; data-start=&quot;1874&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1895&quot; data-start=&quot;1879&quot; data-ke-size=&quot;size26&quot;&gt;8. 중요한 포인트 정리&lt;/h2&gt;
&lt;h3 data-end=&quot;1918&quot; data-start=&quot;1897&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;1) 힙은 정렬 구조가 아니다&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1969&quot; data-start=&quot;1920&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1952&quot; data-start=&quot;1920&quot;&gt;heapq는 &lt;b&gt;최소값만 빠르게 찾기 위한 구조&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1969&quot; data-start=&quot;1953&quot;&gt;전체 정렬을 보장하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1974&quot; data-start=&quot;1971&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2001&quot; data-start=&quot;1976&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;2) &quot;전체가 필요하지 않다&quot;는 사고&lt;/h3&gt;
&lt;p data-end=&quot;2012&quot; data-start=&quot;2003&quot; data-ke-size=&quot;size16&quot;&gt;이 문제의 핵심:&lt;/p&gt;
&lt;blockquote data-end=&quot;2037&quot; data-start=&quot;2014&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2037&quot; data-start=&quot;2016&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;필요한 정보만 유지하는 것&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;2042&quot; data-start=&quot;2039&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2063&quot; data-start=&quot;2044&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;3) Top-K 문제 패턴&lt;/h3&gt;
&lt;p data-end=&quot;2075&quot; data-start=&quot;2065&quot; data-ke-size=&quot;size16&quot;&gt;이 문제는:&lt;/p&gt;
&lt;blockquote data-end=&quot;2100&quot; data-start=&quot;2077&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2100&quot; data-start=&quot;2079&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Top-K (K=N) 문제&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2139&quot; data-start=&quot;2119&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2128&quot; data-start=&quot;2119&quot;&gt;전체 저장 X&lt;/li&gt;
&lt;li data-end=&quot;2139&quot; data-start=&quot;2129&quot;&gt;K개만 유지 O&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>코딩테스트</category>
      <category>2075</category>
      <category>n번째 큰 수</category>
      <category>백준</category>
      <category>우선 순위 큐</category>
      <category>코딩테스트</category>
      <category>힙</category>
      <author>miniberry</author>
      <guid isPermaLink="true">https://miniberry-coding.tistory.com/26</guid>
      <comments>https://miniberry-coding.tistory.com/26#entry26comment</comments>
      <pubDate>Mon, 6 Apr 2026 19:16:51 +0900</pubDate>
    </item>
    <item>
      <title>[React] 라이프 사이클 - 단방향 데이터 흐름, 컴포넌트 마운트와 클린업</title>
      <link>https://miniberry-coding.tistory.com/25</link>
      <description>&lt;p data-end=&quot;162&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;이번에 React 공부하면서 가장 크게 이해가 정리된 부분이 두 가지였다.&lt;br /&gt;하나는 &lt;b&gt;단방향 데이터 흐름&lt;/b&gt;, 다른 하나는 컴포넌트의 &lt;b&gt;마운트&lt;/b&gt;와 &lt;b&gt;클린업(useEffect)&lt;/b&gt;이다.&lt;br /&gt;겉으로 보면 단순한 개념인데, 직접 코드로 부딪혀보니까 생각보다 중요한 포인트들이 많이 숨어 있었다.&lt;/p&gt;
&lt;hr data-end=&quot;167&quot; data-start=&quot;164&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;201&quot; data-start=&quot;169&quot; data-ke-size=&quot;size23&quot;&gt;1. 단방향 데이터 흐름 &amp;ndash; React의 기본 철학&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;데이터전달방향.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rHeOQ/dJMcadaqS3Q/4OeRcTPoTLc5RzBP2bxeu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rHeOQ/dJMcadaqS3Q/4OeRcTPoTLc5RzBP2bxeu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rHeOQ/dJMcadaqS3Q/4OeRcTPoTLc5RzBP2bxeu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrHeOQ%2FdJMcadaqS3Q%2F4OeRcTPoTLc5RzBP2bxeu0%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;755&quot; height=&quot;331&quot; data-filename=&quot;데이터전달방향.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;331&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;292&quot; data-start=&quot;203&quot; data-ke-size=&quot;size16&quot;&gt;React는 기본적으로 &lt;b&gt;데이터가 위에서 아래로 흐르는 구조&lt;/b&gt;를 가진다.&lt;br /&gt;부모 컴포넌트가 state를 가지고 있고, 그걸 자식에게 props로 내려준다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775468847727&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Parent() {
	const [count, setCount] = useState(0);

	return &amp;lt;Child count={count} onClick={() =&amp;gt; setCount(count + 1)} /&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;454&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;여기서 중요한 점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;504&quot; data-start=&quot;456&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;474&quot; data-start=&quot;456&quot;&gt;데이터는 &lt;b&gt;부모 &amp;rarr; 자식&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;504&quot; data-start=&quot;475&quot;&gt;이벤트는 &lt;b&gt;자식 &amp;rarr; 부모 (콜백 함수 호출)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;614&quot; data-start=&quot;506&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 &amp;ldquo;왜 이렇게 번거롭게 하지?&amp;rdquo; 싶었는데, 이 구조 덕분에 &lt;b&gt;데이터 흐름이 항상 예측 가능해진다&lt;/b&gt;는 걸 느꼈다.&lt;br /&gt;특히 디버깅할 때 &amp;ldquo;이 값 어디서 바뀌었지?&amp;rdquo;를 추적하기 쉬워진다.&lt;/p&gt;
&lt;hr data-end=&quot;619&quot; data-start=&quot;616&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;647&quot; data-start=&quot;621&quot; data-ke-size=&quot;size23&quot;&gt;2. 조건부 렌더링 = 컴포넌트 생명주기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라이프사이클은 다음과 같다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;라이프사이클.png&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6JTJx/dJMcabKyapg/7KYZ9EOveORCWFFiOVDK2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6JTJx/dJMcabKyapg/7KYZ9EOveORCWFFiOVDK2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6JTJx/dJMcabKyapg/7KYZ9EOveORCWFFiOVDK2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6JTJx%2FdJMcabKyapg%2F7KYZ9EOveORCWFFiOVDK2k%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;637&quot; height=&quot;215&quot; data-filename=&quot;라이프사이클.png&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;215&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;669&quot; data-start=&quot;649&quot;&gt;마운트 (Mount, 탄생): 컴포넌트가 페이지에 처음 렌더링될 때&lt;/li&gt;
&lt;li data-end=&quot;669&quot; data-start=&quot;649&quot;&gt;업데이트 (Update, 갱신): State나 Props의 값이 바뀌거나 부모 컴포넌트가 리렌더해 자신도 리렌더될 때&lt;/li&gt;
&lt;li data-end=&quot;669&quot; data-start=&quot;649&quot;&gt;언마운트&amp;nbsp;(Unmount,&amp;nbsp;사망):&amp;nbsp;더&amp;nbsp;이상&amp;nbsp;페이지에&amp;nbsp;컴포넌트가&amp;nbsp;렌더링되지&amp;nbsp;않을&amp;nbsp;때&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;669&quot; data-start=&quot;649&quot; data-ke-size=&quot;size16&quot;&gt;이번에 가장 크게 깨달은 점&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775468893937&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{count % 2 === 0 &amp;amp;&amp;amp; &amp;lt;Even /&amp;gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;733&quot; data-start=&quot;713&quot; data-ke-size=&quot;size16&quot;&gt;이 한 줄이 단순한 조건문이 아니라,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;785&quot; data-start=&quot;735&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;759&quot; data-start=&quot;735&quot;&gt;짝수 &amp;rarr; 컴포넌트 생성 (&lt;b&gt;마운트&lt;/b&gt;)&lt;/li&gt;
&lt;li data-end=&quot;785&quot; data-start=&quot;760&quot;&gt;홀수 &amp;rarr; 컴포넌트 제거 (&lt;b&gt;언마운트&lt;/b&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;818&quot; data-start=&quot;787&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 즉, &lt;b&gt;렌더링 조건 자체가 생명주기를 결정한다&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;865&quot; data-start=&quot;820&quot; data-ke-size=&quot;size16&quot;&gt;이걸 이해하고 나니까 React가 &amp;ldquo;컴포넌트 기반 UI&amp;rdquo;라는 말이 훨씬 와닿았다.&lt;/p&gt;
&lt;hr data-end=&quot;870&quot; data-start=&quot;867&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;903&quot; data-start=&quot;872&quot; data-ke-size=&quot;size23&quot;&gt;3. useEffect와 클린업 함수의 진짜 의미&lt;/h3&gt;
&lt;p data-end=&quot;921&quot; data-start=&quot;905&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 이 코드가 헷갈렸다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775468947058&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
	return () =&amp;gt; {
		console.log(&quot;Even 컴포넌트 언마운트&quot;);
	};
}, []);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1054&quot; data-start=&quot;1014&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;이게 왜 마운트냐 언마운트냐&amp;rdquo; 혼란이 왔는데, 핵심은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1125&quot; data-start=&quot;1056&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1086&quot; data-start=&quot;1056&quot;&gt;useEffect 자체는 &lt;b&gt;마운트 시 실행&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1125&quot; data-start=&quot;1087&quot;&gt;return 함수는 &lt;b&gt;언마운트 시 실행 (cleanup)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1129&quot; data-start=&quot;1127&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;p data-end=&quot;1167&quot; data-start=&quot;1131&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 마운트할 때 &lt;b&gt;&amp;ldquo;나중에 정리할 함수&amp;rdquo;를 등록해두는 구조&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1194&quot; data-start=&quot;1169&quot; data-ke-size=&quot;size16&quot;&gt;이걸 이해하고 나니까 흐름이 완전히 정리됐다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;마운트 &amp;rarr; effect 실행 &amp;rarr; cleanup 등록 &lt;/span&gt;&lt;br /&gt;&lt;span&gt;언마운트 &amp;rarr; cleanup 실행&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1260&quot; data-start=&quot;1257&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1283&quot; data-start=&quot;1262&quot; data-ke-size=&quot;size23&quot;&gt;4. 클린업 함수는 왜 존재할까&lt;/h3&gt;
&lt;p data-end=&quot;1337&quot; data-start=&quot;1285&quot; data-ke-size=&quot;size16&quot;&gt;클린업 함수는 단순히 로그 찍는 용도가 아니라,&lt;br /&gt;&lt;b&gt;남아있는 작업을 정리하는 역할&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;1345&quot; data-start=&quot;1339&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1388&quot; data-start=&quot;1347&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1359&quot; data-start=&quot;1347&quot;&gt;이벤트 리스너 제거&lt;/li&gt;
&lt;li data-end=&quot;1376&quot; data-start=&quot;1360&quot;&gt;setInterval 정리&lt;/li&gt;
&lt;li data-end=&quot;1388&quot; data-start=&quot;1377&quot;&gt;API 요청 취소&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1423&quot; data-start=&quot;1390&quot; data-ke-size=&quot;size16&quot;&gt;이걸 안 하면 실제로 &lt;b&gt;메모리 누수나 버그로 이어진다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1503&quot; data-start=&quot;1425&quot; data-ke-size=&quot;size16&quot;&gt;그래서 React는 아예 구조적으로&lt;/p&gt;
&lt;blockquote data-end=&quot;1503&quot; data-start=&quot;1425&quot; data-ke-style=&quot;style2&quot;&gt;effect를 만들면 반드시 정리도 같이 생각해라&lt;/blockquote&gt;
&lt;p data-end=&quot;1503&quot; data-start=&quot;1425&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1503&quot; data-start=&quot;1425&quot; data-ke-size=&quot;size16&quot;&gt;라는 패턴을 강제하고 있는 느낌이었다.&lt;/p&gt;
&lt;hr data-end=&quot;1508&quot; data-start=&quot;1505&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1529&quot; data-start=&quot;1510&quot; data-ke-size=&quot;size23&quot;&gt;5. 이번에 느낀 핵심 요소&lt;/h3&gt;
&lt;p data-end=&quot;1590&quot; data-start=&quot;1531&quot; data-ke-size=&quot;size16&quot;&gt;이번 학습에서 가장 좋았던 건&lt;br /&gt;이 세 개가 따로 노는 개념이 아니라 &lt;b&gt;하나로 연결된다는 것&lt;/b&gt;이었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1642&quot; data-start=&quot;1592&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1606&quot; data-start=&quot;1592&quot;&gt;단방향 데이터 흐름&lt;/li&gt;
&lt;li data-end=&quot;1618&quot; data-start=&quot;1607&quot;&gt;조건부 렌더링&lt;/li&gt;
&lt;li data-end=&quot;1642&quot; data-start=&quot;1619&quot;&gt;useEffect + cleanup&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1661&quot; data-start=&quot;1644&quot; data-ke-size=&quot;size16&quot;&gt;상태(state)가 바뀌면&lt;/p&gt;
&lt;p data-end=&quot;1661&quot; data-start=&quot;1644&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 렌더링 구조 변경&lt;br /&gt;&amp;rarr; 컴포넌트 마운트/언마운트&lt;br /&gt;&amp;rarr; 그에 따라 effect와 cleanup이 실행&lt;/p&gt;
&lt;hr data-end=&quot;1754&quot; data-start=&quot;1751&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1769&quot; data-start=&quot;1756&quot; data-ke-size=&quot;size23&quot;&gt;6. 한 줄 정리&lt;/h3&gt;
&lt;p data-end=&quot;1847&quot; data-start=&quot;1771&quot; data-ke-size=&quot;size16&quot;&gt;React는 단순히 UI를 그리는 라이브러리가 아니라,&lt;br /&gt;&lt;b&gt;상태 변화 &amp;rarr; 컴포넌트 생명주기 &amp;rarr; 부수 효과 관리까지 연결된 구조&lt;/b&gt;이다.&lt;/p&gt;</description>
      <category>프론트엔드/리액트</category>
      <category>react</category>
      <category>단방향 데이터 흐름</category>
      <category>라이프사이클</category>
      <category>리액트</category>
      <category>마운트</category>
      <category>컴포넌트</category>
      <category>클린업</category>
      <author>miniberry</author>
      <guid isPermaLink="true">https://miniberry-coding.tistory.com/25</guid>
      <comments>https://miniberry-coding.tistory.com/25#entry25comment</comments>
      <pubDate>Mon, 6 Apr 2026 18:55:21 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] JWT 로그아웃 기본 코드 분석</title>
      <link>https://miniberry-coding.tistory.com/24</link>
      <description>&lt;h2 data-end=&quot;138&quot; data-start=&quot;128&quot; data-section-id=&quot;1o1fj1w&quot; data-ke-size=&quot;size26&quot;&gt;1. 들어가며&lt;/h2&gt;
&lt;p data-end=&quot;216&quot; data-start=&quot;140&quot; data-ke-size=&quot;size16&quot;&gt;BenePicker 프로젝트를 진행하면서 인증을 JWT 기반으로 설계했다.&lt;br /&gt;로그인, 토큰&lt;/p&gt;
&lt;p data-end=&quot;216&quot; data-start=&quot;140&quot; data-ke-size=&quot;size16&quot;&gt;발급까지는 비교적 자연스럽게 구현됐지만, &lt;b&gt;로그아웃 구현에서 예상 밖의 혼란&lt;/b&gt;을 겪었다.&lt;/p&gt;
&lt;blockquote data-end=&quot;280&quot; data-start=&quot;251&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;280&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;&quot;로그아웃인데&amp;hellip; 왜 서버에서 아무것도 안 하지?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;로그아웃.png&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8w4Do/dJMcaiW5R7S/LZkBjh1FaCuIC5KnoDkzXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8w4Do/dJMcaiW5R7S/LZkBjh1FaCuIC5KnoDkzXk/img.png&quot; data-alt=&quot;로그아웃인데 서버에서 계속 요청해도 정상 응답 처리..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8w4Do/dJMcaiW5R7S/LZkBjh1FaCuIC5KnoDkzXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8w4Do%2FdJMcaiW5R7S%2FLZkBjh1FaCuIC5KnoDkzXk%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;634&quot; height=&quot;210&quot; data-filename=&quot;로그아웃.png&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;로그아웃인데 서버에서 계속 요청해도 정상 응답 처리..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;349&quot; data-start=&quot;282&quot; data-ke-size=&quot;size16&quot;&gt;이번 글에서는 단순 구현이 아니라, &lt;b&gt;JWT 로그아웃의 본질과 설계 관점에서의 깨달음&lt;/b&gt;을 정리해보려고 한다.&lt;/p&gt;
&lt;hr data-end=&quot;354&quot; data-start=&quot;351&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;373&quot; data-start=&quot;356&quot; data-section-id=&quot;1ba8wz1&quot; data-ke-size=&quot;size26&quot;&gt;2. 구현한 로그아웃 코드&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1775188228378&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PostMapping(&quot;/logout&quot;)
public ResponseEntity&amp;lt;Void&amp;gt; logout() {
    return ResponseEntity.ok().build();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;523&quot; data-start=&quot;493&quot; data-ke-size=&quot;size16&quot;&gt;처음 이 코드를 작성하면서 이런 생각이 들었다.&lt;/p&gt;
&lt;blockquote data-end=&quot;543&quot; data-start=&quot;525&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;543&quot; data-start=&quot;527&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;이게&amp;hellip; 로그아웃 맞나?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;578&quot; data-start=&quot;545&quot; data-ke-size=&quot;size16&quot;&gt;로직이 없다.&lt;br /&gt;DB 접근도 없다.&lt;br /&gt;토큰 처리도 없다.&lt;/p&gt;
&lt;p data-end=&quot;599&quot; data-start=&quot;580&quot; data-ke-size=&quot;size16&quot;&gt;그냥 200 OK 반환 끝이다.&lt;/p&gt;
&lt;hr data-end=&quot;604&quot; data-start=&quot;601&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;624&quot; data-start=&quot;606&quot; data-section-id=&quot;1cs82g0&quot; data-ke-size=&quot;size26&quot;&gt;3. 왜 이렇게 구현했을까?&lt;/h2&gt;
&lt;p data-end=&quot;661&quot; data-start=&quot;626&quot; data-ke-size=&quot;size16&quot;&gt;이걸 이해하려면 먼저 &lt;b&gt;JWT의 핵심 개념&lt;/b&gt;을 알아야 한다.&lt;/p&gt;
&lt;hr data-end=&quot;666&quot; data-start=&quot;663&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;692&quot; data-start=&quot;668&quot; data-section-id=&quot;11ijbug&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;1) JWT의 본질: Stateless&lt;/h2&gt;
&lt;p data-end=&quot;725&quot; data-start=&quot;694&quot; data-ke-size=&quot;size16&quot;&gt;JWT 인증은 &lt;b&gt;Stateless(무상태)&lt;/b&gt; 구조다.&lt;/p&gt;
&lt;p data-end=&quot;729&quot; data-start=&quot;727&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;blockquote data-end=&quot;757&quot; data-start=&quot;731&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;757&quot; data-start=&quot;733&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;서버는 로그인 상태를 저장하지 않는다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;762&quot; data-start=&quot;759&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;786&quot; data-start=&quot;764&quot; data-section-id=&quot;o74h2n&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;2) 우리가 익숙한 방식 (세션)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;825&quot; data-start=&quot;788&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;805&quot; data-start=&quot;788&quot; data-section-id=&quot;h2kzxn&quot;&gt;로그인 &amp;rarr; 서버에 세션 저장&lt;/li&gt;
&lt;li data-end=&quot;825&quot; data-start=&quot;806&quot; data-section-id=&quot;16w6uxo&quot;&gt;로그아웃 &amp;rarr; 서버에서 세션 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;842&quot; data-start=&quot;827&quot; data-ke-size=&quot;size16&quot;&gt;서버가 상태를 관리한다&lt;/p&gt;
&lt;hr data-end=&quot;847&quot; data-start=&quot;844&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;862&quot; data-start=&quot;849&quot; data-section-id=&quot;60exfv&quot; data-ke-size=&quot;size23&quot;&gt;3) JWT 방식&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;894&quot; data-start=&quot;864&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;877&quot; data-start=&quot;864&quot; data-section-id=&quot;17e6mwz&quot;&gt;로그인 &amp;rarr; 토큰 발급&lt;/li&gt;
&lt;li data-end=&quot;894&quot; data-start=&quot;878&quot; data-section-id=&quot;qrjz0y&quot;&gt;이후 요청 &amp;rarr; 토큰만 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;915&quot; data-start=&quot;896&quot; data-ke-size=&quot;size16&quot;&gt;서버는 상태를 저장하지 않는다&lt;/p&gt;
&lt;hr data-end=&quot;920&quot; data-start=&quot;917&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;934&quot; data-start=&quot;922&quot; data-section-id=&quot;qwv3t4&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;4) 핵심 깨달음&lt;/h2&gt;
&lt;p data-end=&quot;948&quot; data-start=&quot;936&quot; data-ke-size=&quot;size16&quot;&gt;그래서 결론은&lt;/p&gt;
&lt;blockquote data-end=&quot;977&quot; data-start=&quot;950&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;977&quot; data-start=&quot;952&quot; data-ke-size=&quot;size16&quot;&gt;JWT에서 로그아웃 = 서버 작업이 아니다&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;로그아웃 = 클라이언트에서 토큰 삭제&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1016&quot; data-start=&quot;1013&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1034&quot; data-start=&quot;1018&quot; data-section-id=&quot;76drn7&quot; data-ke-size=&quot;size26&quot;&gt;4. 실제 로그아웃 흐름&lt;/h2&gt;
&lt;p data-end=&quot;1058&quot; data-start=&quot;1036&quot; data-ke-size=&quot;size16&quot;&gt;JWT 기반 로그아웃은 이렇게 동작한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;1. 클라이언트 &amp;rarr; /logout 요청&lt;/span&gt;&lt;br /&gt;&lt;span&gt;2. 서버 &amp;rarr; 200 OK 응답&lt;/span&gt;&lt;br /&gt;&lt;span&gt;3. 클라이언트 &amp;rarr; 토큰 삭제&lt;/span&gt;&lt;br /&gt;&lt;span&gt;4. 이후 요청 &amp;rarr; 인증 실패 (401)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1178&quot; data-start=&quot;1153&quot; data-ke-size=&quot;size16&quot;&gt;즉, 서버는 그냥 &amp;ldquo;응답만 해주는 역할&amp;rdquo;&lt;/p&gt;
&lt;hr data-end=&quot;1183&quot; data-start=&quot;1180&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1209&quot; data-start=&quot;1185&quot; data-section-id=&quot;1bkj7bp&quot; data-ke-size=&quot;size26&quot;&gt;5. 진짜 로그아웃은 어디서 일어날까?&lt;/h2&gt;
&lt;p data-end=&quot;1227&quot; data-start=&quot;1211&quot; data-ke-size=&quot;size16&quot;&gt;정답: &lt;b&gt;클라이언트&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LocalStorage / AsyncStorage에서 토큰 삭제&lt;/li&gt;
&lt;li&gt;사용자 상태 초기화&lt;/li&gt;
&lt;li&gt;로그인 페이지로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1315&quot; data-start=&quot;1307&quot; data-ke-size=&quot;size16&quot;&gt;이걸 안 하면?&lt;/p&gt;
&lt;p data-end=&quot;1350&quot; data-start=&quot;1317&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&amp;rarr;&lt;/b&gt;&lt;/b&gt; 로그아웃 API를 호출해도 계속 로그인 상태처럼 보인다&lt;/p&gt;
&lt;hr data-end=&quot;1355&quot; data-start=&quot;1352&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1376&quot; data-start=&quot;1357&quot; data-section-id=&quot;1jd9bvr&quot; data-ke-size=&quot;size26&quot;&gt;6. 설계 관점에서의 인사이트&lt;/h2&gt;
&lt;p data-end=&quot;1403&quot; data-start=&quot;1378&quot; data-ke-size=&quot;size16&quot;&gt;이번 경험에서 가장 크게 느낀 점&lt;/p&gt;
&lt;blockquote data-end=&quot;1449&quot; data-start=&quot;1405&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1449&quot; data-start=&quot;1407&quot; data-ke-size=&quot;size16&quot;&gt;&quot;JWT는 서버를 단순하게 만드는 대신, 클라이언트 책임을 증가시킨다&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;1454&quot; data-start=&quot;1451&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1471&quot; data-start=&quot;1456&quot; data-section-id=&quot;1uzzm5a&quot; data-ke-size=&quot;size26&quot;&gt;7. 현재 구조의 한계&lt;/h2&gt;
&lt;p data-end=&quot;1516&quot; data-start=&quot;1473&quot; data-ke-size=&quot;size16&quot;&gt;지금 구현은 간단하고 효율적이지만,&lt;br /&gt;실제 서비스에서는 문제가 될 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;1528&quot; data-start=&quot;1518&quot; data-section-id=&quot;1qsyyw4&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;문제점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1574&quot; data-start=&quot;1530&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1555&quot; data-start=&quot;1530&quot; data-section-id=&quot;3r3hz9&quot;&gt;탈취된 토큰은 만료 전까지 계속 사용 가능&lt;/li&gt;
&lt;li data-end=&quot;1574&quot; data-start=&quot;1556&quot; data-section-id=&quot;1n3zpcr&quot;&gt;서버에서 강제 로그아웃 불가능&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1579&quot; data-start=&quot;1576&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1602&quot; data-start=&quot;1581&quot; data-section-id=&quot;1q39x44&quot; data-ke-size=&quot;size26&quot;&gt;8. 실무에서는 어떻게 해결할까?&lt;/h2&gt;
&lt;p data-end=&quot;1634&quot; data-start=&quot;1604&quot; data-ke-size=&quot;size16&quot;&gt;실제 서비스에서는 보통 아래 방식들을 추가로 사용한다.&lt;/p&gt;
&lt;hr data-end=&quot;1639&quot; data-start=&quot;1636&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1666&quot; data-start=&quot;1641&quot; data-section-id=&quot;82crcm&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;1) Refresh Token 관리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1692&quot; data-start=&quot;1668&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1680&quot; data-start=&quot;1668&quot; data-section-id=&quot;8hlrmq&quot;&gt;서버(DB)에 저장&lt;/li&gt;
&lt;li data-end=&quot;1692&quot; data-start=&quot;1681&quot; data-section-id=&quot;ua0kh2&quot;&gt;로그아웃 시 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1697&quot; data-start=&quot;1694&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1719&quot; data-start=&quot;1699&quot; data-section-id=&quot;104ro7f&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;2) Redis 블랙리스트&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;로그아웃된 AccessToken &amp;rarr; Redis에 저장&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1775&quot; data-start=&quot;1764&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&amp;rarr;&lt;/b&gt;&lt;/b&gt; 이후 요청 차단&lt;/p&gt;
&lt;hr data-end=&quot;1780&quot; data-start=&quot;1777&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1802&quot; data-start=&quot;1782&quot; data-section-id=&quot;enuo07&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;3) 토큰 만료 시간 전략&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1840&quot; data-start=&quot;1804&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1821&quot; data-start=&quot;1804&quot; data-section-id=&quot;1imkrfq&quot;&gt;AccessToken: 짧게&lt;/li&gt;
&lt;li data-end=&quot;1840&quot; data-start=&quot;1822&quot; data-section-id=&quot;cw225c&quot;&gt;RefreshToken: 길게&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1845&quot; data-start=&quot;1842&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1855&quot; data-start=&quot;1847&quot; data-section-id=&quot;1uxv63v&quot; data-ke-size=&quot;size26&quot;&gt;9. 회고&lt;/h2&gt;
&lt;p data-end=&quot;1920&quot; data-start=&quot;1857&quot; data-ke-size=&quot;size16&quot;&gt;이번 로그아웃 구현은 단순한 기능 하나를 넘어서, &lt;b&gt;인증 구조 자체를 다시 이해하게 되는 계기&lt;/b&gt;였다.&lt;/p&gt;
&lt;p data-end=&quot;1926&quot; data-start=&quot;1922&quot; data-ke-size=&quot;size16&quot;&gt;처음에는&lt;/p&gt;
&lt;blockquote data-end=&quot;1943&quot; data-start=&quot;1928&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1943&quot; data-start=&quot;1930&quot; data-ke-size=&quot;size16&quot;&gt;&quot;왜 동작을 안하지?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;1954&quot; data-start=&quot;1945&quot; data-ke-size=&quot;size16&quot;&gt;라고 생각했지만, 지금은 오히려 이렇게 느낀다.&lt;/p&gt;
&lt;blockquote data-end=&quot;2009&quot; data-start=&quot;1974&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2009&quot; data-start=&quot;1976&quot; data-ke-size=&quot;size16&quot;&gt;&quot;JWT는 설계를 이해하지 않으면 절대 제대로 쓸 수 없다&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;2014&quot; data-start=&quot;2011&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2028&quot; data-start=&quot;2016&quot; data-section-id=&quot;sum2vr&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;한 줄 정리&lt;/h2&gt;
&lt;blockquote data-end=&quot;2069&quot; data-start=&quot;2030&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2069&quot; data-start=&quot;2032&quot; data-ke-size=&quot;size16&quot;&gt;JWT에서 로그아웃은 서버가 아니라 &lt;b&gt;클라이언트가 수행한다&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;2074&quot; data-start=&quot;2071&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2087&quot; data-start=&quot;2076&quot; data-section-id=&quot;q2zis9&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;다음 목표&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2152&quot; data-start=&quot;2089&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2116&quot; data-start=&quot;2089&quot; data-section-id=&quot;1jtein7&quot;&gt;Refresh Token 기반 인증 구조 개선&lt;/li&gt;
&lt;li data-end=&quot;2133&quot; data-start=&quot;2117&quot; data-section-id=&quot;1gvsta5&quot;&gt;Redis 블랙리스트 도입&lt;/li&gt;
&lt;li data-end=&quot;2152&quot; data-start=&quot;2134&quot; data-section-id=&quot;1v22kjf&quot;&gt;로그아웃 시 토큰 무효화 처리&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>백엔드/회고</category>
      <category>jwt</category>
      <category>spring</category>
      <category>로그아웃</category>
      <category>백엔드</category>
      <category>세션</category>
      <author>miniberry</author>
      <guid isPermaLink="true">https://miniberry-coding.tistory.com/24</guid>
      <comments>https://miniberry-coding.tistory.com/24#entry24comment</comments>
      <pubDate>Fri, 3 Apr 2026 13:24:07 +0900</pubDate>
    </item>
  </channel>
</rss>