<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>MangKyu's Diary</title>
    <link>https://mangkyu.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 01:28:32 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>망나니개발자</managingEditor>
    <image>
      <title>MangKyu's Diary</title>
      <url>https://t1.daumcdn.net/cfile/tistory/99AA043359FC5BAF0B</url>
      <link>https://mangkyu.tistory.com</link>
    </image>
    <item>
      <title>[Image] 소벨 필터(Sobel Filter)란?</title>
      <link>https://mangkyu.tistory.com/465</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt;1. 소벨&amp;nbsp;필터(Sobel&amp;nbsp;Filter)란?&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 소벨 필터란? ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소벨 필터란 이미지에서 경계(edge)를 검출하기 위한 필터이다. 여기서 경계(edge)란 이미지에서 픽셀 값이 급격하게 변하는 구간을 말한다. 예를 들어 왼쪽은 어둡고 오른쪽은 밝은 이미지가 있다고 하자. 그러면 급변하는 그 지점을 우리는 edge라고 한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt; 10  10  10 | 200  200
 10  10  10 | 200  200
 10  10  10 | 200  200
            &amp;uarr;
    여기서 값이 10&amp;rarr;200으로 급변 = edge!&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본의 이미지에서 edge를 추출한 예시 그림을 보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;653&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lzAEo/dJMcaaEAgd4/D6QhDdbJszHCGdGdzcgRkk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lzAEo/dJMcaaEAgd4/D6QhDdbJszHCGdGdzcgRkk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lzAEo/dJMcaaEAgd4/D6QhDdbJszHCGdGdzcgRkk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlzAEo%2FdJMcaaEAgd4%2FD6QhDdbJszHCGdGdzcgRkk%2Fimg.webp&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;653&quot; height=&quot;321&quot; data-origin-width=&quot;653&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 소벨 필터의 동작 방식 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;미분(변화량 측정하기)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소벨 필터는 두 가지 연산을 한 번에 하는 커널인데, 첫 번째는 미분이다. 미분은 특별한 개념이 아니라, 그저 &quot;얼마나 변했는가&quot;를 표현하는 수단이다. 예를 들어 이미지의 가로로 보았을 때, [50, 50, 200] 픽셀이 존재한다고 하자. 중간을 기준으로 왼쪽과 오른쪽은 150 픽셀 정도의 차이를 보인다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;픽셀 값:  50  50  200

변화량 = 오른쪽 - 왼쪽 = 200 - 50 = 150
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 바로 미분(변화량)이며, 이것을 가운데 픽셀 기준으로 수식으로 쓰면 다음과 같다. 즉, [-1, 0, 1]과 같이 계산이 되도록 배열을 만드는 것이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;(-1 &amp;times; 왼쪽) + (0 &amp;times; 가운데) + (1 &amp;times; 오른쪽)
= (-1 &amp;times; 50) + (0 &amp;times; 50) + (1 &amp;times; 200) = 150
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 안에 그림은 연속성이 있으니, 이제 3x3으로 만들어서 확장할 필요가 있다. 그러면 이제 왼쪽과 오른쪽의 차이를 비교할 수 있게 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;왼쪽 열 (-1, -1, -1): 왼쪽 픽셀들을 빼고&lt;/li&gt;
&lt;li&gt;가운데 열 (0, 0, 0): 가운데는 무시하고&lt;/li&gt;
&lt;li&gt;오른쪽 열 (1, 1, 1): 오른쪽 픽셀들을 더한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 가로 방향으로의 픽셀 변화량과 세로 방향으로의 픽셀 변화량을 감지하기 위해 2가지 필터를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;455&quot; data-origin-height=&quot;213&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UGHDl/dJMcabKgB0b/IkQkLUoZASHGP9Kg2LKxw0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UGHDl/dJMcabKgB0b/IkQkLUoZASHGP9Kg2LKxw0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UGHDl/dJMcabKgB0b/IkQkLUoZASHGP9Kg2LKxw0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/UGHDl/dJMcabKgB0b/IkQkLUoZASHGP9Kg2LKxw0/img.gif&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;455&quot; height=&quot;213&quot; data-origin-width=&quot;455&quot; data-origin-height=&quot;213&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가로 방향의 필터를 활용하면 다음과 같이 변화의 차이를 알 수 있게 된다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;몇 가지 경우:
50  50  50   &amp;rarr;  (-1&amp;times;50) + (0&amp;times;50) + (1&amp;times;50)  =  0     변화 없음
50  50  200  &amp;rarr;  (-1&amp;times;50) + (0&amp;times;50) + (1&amp;times;200) =  150   오른쪽이 밝아짐
200 50  50   &amp;rarr;  (-1&amp;times;200)+ (0&amp;times;50) + (1&amp;times;50)  = -150   왼쪽이 밝았음
&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;스무딩(부드럽게 평균내기)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;노이즈(noise)란&lt;span&gt;&amp;nbsp;&lt;/span&gt;카메라로 사진을 찍을 때 원래 없어야 하는 엉뚱한 값이 생기는 현상이다. 어두운 곳에서 핸드폰으로 사진 찍으면 거칠거칠한 점들이 보이는데, 그게 노이즈다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HWkcp/dJMcaaEAf5y/mxee24F6Rey0qi8H3IkIkK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HWkcp/dJMcaaEAf5y/mxee24F6Rey0qi8H3IkIkK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HWkcp/dJMcaaEAf5y/mxee24F6Rey0qi8H3IkIkK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHWkcp%2FdJMcaaEAf5y%2Fmxee24F6Rey0qi8H3IkIkK%2Fimg.jpg&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;300&quot; height=&quot;224&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;깨끗한 이미지:       노이즈가 낀 이미지:
50  50  50          50   50   50
50  50  50          50  250   50    &amp;larr; 250은 노이즈!
50  50  50          50   50   50
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;문제는 소벨 필터가 &quot;값이 급변하는 곳 = edge&quot;로 판단하기 때문에,&lt;span&gt;&amp;nbsp;&lt;/span&gt;노이즈도 edge로 오인할 수 있다는 것이다. 따라서 스무딩 기법을 적용하여 주변 값들을 평균내서 이런 튀는 값을 깎아낸다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;노이즈 값 250 주변의 평균:
(50 + 250 + 50) / 3 = 116  &amp;larr; 부드러워짐
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;소벨은 단순 평균 [1 1 1] 대신 [1 2 1]을 사용한다. 가운데에 가중치 2를 줘서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가까운 값을 더 신뢰&lt;/b&gt;하는 것이다.&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;비유: 내 바로 옆자리 친구가 &quot;저기 edge 있어&quot;라고 하는 것과, 멀리 있는 사람이 &quot;저기 edge 있어&quot;라고 하는 것 중&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;옆자리 친구 말을 더 믿는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만약 가중치 유무에 따라 노이즈의 영향도를 비교해보면 그 차이를 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;값: 250  50  50
        &amp;uarr; 가운데(정상)

단순 평균 [1 1 1]:  (250 + 50 + 50) / 3 = 116  &amp;larr; 노이즈에 많이 끌려감
가우시안  [1 2 1]:  (250 + 100 + 50) / 4 = 100  &amp;larr; 가운데를 더 믿어서 덜 끌려감
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;소벨 커널(미분과 스무딩)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 둘을 합하면 소벨 커널이 나오게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPIyyH/dJMcadgYZ36/csDszhhBkPyHGOi0IjzFfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPIyyH/dJMcadgYZ36/csDszhhBkPyHGOi0IjzFfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPIyyH/dJMcadgYZ36/csDszhhBkPyHGOi0IjzFfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPIyyH%2FdJMcadgYZ36%2FcsDszhhBkPyHGOi0IjzFfk%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;420&quot; height=&quot;219&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이 커널을 이미지 위에서 &lt;/span&gt;&lt;b&gt;한 칸씩&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;이동시키며 계산한다.&amp;nbsp;&lt;/span&gt;각 위치에서 커널과 픽셀 값을 곱해서 합산(컨볼루션)하고, 그 결과값이 크면 edge, 작으면 edge가 아니라고 판단한다.&lt;/p&gt;
&lt;pre class=&quot;prolog&quot;&gt;&lt;code&gt;1단계: 왼쪽 위부터 시작       2단계: 한 칸 오른쪽으로 이동
[■ ■ ■] . . .               . [■ ■ ■] . .
[■ ■ ■] . . .               . [■ ■ ■] . .
[■ ■ ■] . . .               . [■ ■ ■] . .
 .  .  .  . . .               .  .  .  . .

... 한 줄이 끝나면 아래로 이동하여 반복
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 이번에 필터를 적용하는 3x3 영역이 다음과 같이 존재한다고 할 때, 필터를 적용해서 합계를 구하면 특정한 값이 나온다. 그러면 중간의 값이 왼쪽과 오른쪽 좌표의 값과 비교했을 때의 변화량이 나오게 된 것인데, 이때 그 값이 크면 edge라고 볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;이미지에서 3x3 영역을 꺼냄:
 50   50  200
 50   50  200
 50   50  200

커널과 곱해서 합산:
(-1&amp;times;50) + (0&amp;times;50) + (1&amp;times;200)  = 150
(-2&amp;times;50) + (0&amp;times;50) + (2&amp;times;200)  = 300
(-1&amp;times;50) + (0&amp;times;50) + (1&amp;times;200)  = 150

합계: 150 + 300 + 150 = 600  &amp;larr; 값이 크다 = edge!
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 변화가 없는 영역이라면, 0이 나오면서 edge가 아님을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt; 50   50   50

(-1&amp;times;50) + (0&amp;times;50) + (1&amp;times;50) = 0  &amp;larr; edge 아님
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 노이즈와 Edge의 구분 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 3개 픽셀을 연속으로 보기 때문이다. 1개 픽셀만 보면 그게 edge인지 노이즈인지 알 수 없지만, 3개를 연속으로 보면 패턴이 보인다.&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;edge: 여러 줄이 같은 패턴으로 이어진다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt; 50 | 200
 50 | 200     &amp;larr; 세로로 값이 전부 같음
 50 | 200

세로로 평균내도: (200 + 200 + 200) / 3 = 200  &amp;rarr; 안 변함!
&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;&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;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;  50
 250    &amp;larr; 혼자만 튀어있음
  50

세로로 평균내면: (50 + 250 + 50) / 3 = 116  &amp;rarr; 깎여나감!
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소벨의 [1 2 1] 스무딩은 이 원리를 이용해 edge는 보존하면서 노이즈만 줄이는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>나의 공부방</category>
      <author>망나니개발자</author>
      <guid isPermaLink="true">https://mangkyu.tistory.com/465</guid>
      <comments>https://mangkyu.tistory.com/465#entry465comment</comments>
      <pubDate>Tue, 17 Mar 2026 10:00:57 +0900</pubDate>
    </item>
    <item>
      <title>[AI] 앤트로픽(Anthropic)이 알려주는 좋은 클로드 코드 스킬(Claude Code Skill)</title>
      <link>https://mangkyu.tistory.com/464</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;앤트로픽은 좋은 스킬을 작성하는 방법에 대한 내용을 33쪽의 분량에 걸친 &lt;a href=&quot;https://resources.anthropic.com/hubfs/The-Complete-Guide-to-Building-Skill-for-Claude.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PDF 자료&lt;/a&gt;로 제공하고 있다. 보다 상세하고 구체적인 내용을 원한다면, 해당 PDF 파일을 참고하기를 권장한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt;1. 앤트로픽(Anthropic)이 알려주는 좋은 클로드 코드 스킬(Claude Code Skill)&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Skill의 개념과 작성 예시 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; Skill의 개념과 범주&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skill은 Claude의 기능을 확장하는 기술로, 일회성 프롬프트가 아닌, 반복 사용 가능한 워크플로 자산이자 지식의 저장소이다. 따라서 반복 가능하고 구조화된 작업에서 가장 유용하다. Skill은 하나의 폴더 단위로 존재하며, 다음과 같이 구성된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필수 구성:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SKILL.md: YAML frontmatter와 Markdown 지침을 포함한 핵심 파일&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;선택 구성:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;scripts/: Python, Bash 등 실행 코드&lt;/li&gt;
&lt;li&gt;references/: 필요 시 참조되는 문서와 가이드&lt;/li&gt;
&lt;li&gt;assets/: 출력물에 사용되는 템플릿, 리소스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SKILL.md 파일에 지침을 작성하면, Claude가 이를 도구 모음에 추가한다. 그러면&amp;nbsp;Claude는 관련 상황에서 스킬을 자동으로 사용하며, 설정에 따라 사용자가 /skill-name으로 직접 호출할 수도 있다. Claude Code가 제공하는 Skill은 여러 AI 도구에서 통용되는 &lt;a href=&quot;https://agentskills.io/&quot;&gt;Agent Skills&lt;/a&gt; 오픈 표준을 따르며, 호출 제어와 서브에이전트 실행, 동적 컨텍스트 주입 등과 같은 추가 기능을 제공한다.&amp;nbsp;참고로 커스텀 커맨드는 Claude의 초기 기술로, 프론트매터 자동 로딩 등이 추가되며 스킬로 통합되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skill에는 크게 4가지 범주가 존재하며, 다음과 같이 구분할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;위치&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;경로&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;적용 범위&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise&lt;/td&gt;
&lt;td&gt;See&amp;nbsp;managed settings&lt;/td&gt;
&lt;td&gt;Organization에 속한 모든 사용자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Personal&lt;/td&gt;
&lt;td&gt;~/.claude/skills/&amp;lt;skill-name&amp;gt;/SKILL.md&lt;/td&gt;
&lt;td&gt;모든 프로젝트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Project&lt;/td&gt;
&lt;td&gt;.claude/skills/&amp;lt;skill-name&amp;gt;/SKILL.md&lt;/td&gt;
&lt;td&gt;현재의 프로젝트만&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plugin&lt;/td&gt;
&lt;td&gt;&amp;lt;plugin&amp;gt;/skills/&amp;lt;skill-name&amp;gt;/SKILL.md&lt;/td&gt;
&lt;td&gt;플러그인이 활성화되었을 경우에만&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일한 이름의 Skill 이 존재할 경우에는 높은 우선순위(enterprise &amp;gt; personal &amp;gt; project)의 구역이 우선 채택되며,&amp;nbsp;plugin의 Skill 은 plugin-name:skill-name에 해당하는 namespace를 갖기 때문에, 충돌이 나지 않는다. Personal 또는 Project Skill은 자동 로드되며, 라이브 변경 감지도 되므로 세션을 재시작하지 않고도 수정할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; Skill의 Frontmatters 항목들과 작성 예시&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skill 내용이 작성되는&amp;nbsp;SKILL.md는 &amp;ldquo;YAML Frontmatter + Markdown 본문&amp;rdquo; 구조를 따른다.&amp;nbsp;Frontmatter에는 메타데이터를, 본문에는 실제 작업 절차와 기준을 적는다. Frontmatter에는 다음의 항목들이 존재한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;필드명&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;필수 여부&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;스킬 이름, 없으면 디렉터리명을 사용함. 소문자/숫자/하이픈만 허용(최대 64자)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;description&lt;/td&gt;
&lt;td&gt;Recommended&lt;/td&gt;
&lt;td&gt;스킬이 무엇을 하고 언제 쓰는지에 대한 설명. &lt;br /&gt;Claude가 자동 적용 여부를 판단할 때 사용하며, 없으면 마크다운 첫 문단을 사용함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;argument-hint&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;자동완성 시 기대 인자를 힌트로 표시. 예: [issue-number] 또는 [filename] [format]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;disable-model-invocation&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;true면 Claude가 자동으로 로드/호출하지 않음. /name으로 수동 실행만. 기본값 false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;user-invocable&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;false면 / 메뉴에서 숨김(사용자 직접 호출 불가). 백그라운드 지식용. 기본값 true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;allowed-tools&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;스킬 활성 시 Claude가 추가 승인 없이 사용할 수 있는 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;model&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;스킬 활성 시 사용할 모델&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;context&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;fork면 분리된 서브에이전트 컨텍스트에서 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;agent&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;context: fork일 때 사용할 서브에이전트 타입&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hooks&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;스킬 라이프사이클에 스코프된 훅. 형식은 &lt;a href=&quot;https://www.notion.so/en/hooks#hooks-in-skills-and-agents&quot;&gt;Hooks in skills and agents&lt;/a&gt; 참고.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 코드를 설명하는 explain-code Skill을 작성한다고 하면, ~/.claude/skills/explain-code/SKILL.md를 다음과 같이 작성해줄 수 있다. 스킬은 디렉토리 이름이 스킬 이름에 해당하며, SKILL.md가 그 내용을 채워준다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;---
name: explain-code
description: Explains code with visual diagrams and analogies. Use when explaining how code works, teaching about a codebase, or when the user asks &quot;how does this work?&quot;
---

When explaining code, always include:

1. **Start with an analogy**: Compare the code to something from everyday life
2. **Draw a diagram**: Use ASCII art to show the flow, structure, or relationships
3. **Walk through the code**: Explain step-by-step what happens
4. **Highlight a gotcha**: What's a common mistake or misconception?

Keep explanations conversational. For complex concepts, use multiple analogies.
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만약 스킬에 파라미터가 필요하다면 다음과 같은 방식으로 전달할 수 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;변수명&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$ARGUMENTS&lt;/td&gt;
&lt;td&gt;스킬 호출 시 전달된 모든 인자. &lt;br /&gt;본문에 $ARGUMENTS가 없으면 ARGUMENTS: &amp;lt;value&amp;gt; 형태로 자동 추가됨.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$ARGUMENTS[N]&lt;/td&gt;
&lt;td&gt;0부터 시작하는 인덱스로 특정 인자 접근. 예: 첫 인자는 $ARGUMENTS[0].&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$N&lt;/td&gt;
&lt;td&gt;$ARGUMENTS[N]의 축약형. 예: $0, $1.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;${CLAUDE_SESSION_ID}&lt;/td&gt;
&lt;td&gt;현재 세션 ID. 로그 파일 생성 등 세션 단위 작업에 유용.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Skill 작성 관련 고급 팁 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SKILL.md 안에서 Bash 명령어 사용하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로드에서 !를 가장 앞에 입력하면 Bash 모드로 전환이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Flrmb/dJMcabQO6ap/BJZ5Se0X1dVkdy6vnicjGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Flrmb/dJMcabQO6ap/BJZ5Se0X1dVkdy6vnicjGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Flrmb/dJMcabQO6ap/BJZ5Se0X1dVkdy6vnicjGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFlrmb%2FdJMcabQO6ap%2FBJZ5Se0X1dVkdy6vnicjGk%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;1068&quot; height=&quot;274&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;274&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스킬에도 Bash 모드를 활용할 수 있는데, 스킬에서는 각 !command는 전처리(preprocessing) 단계로, Claude가 어떤 내용도 보기 전에 즉시 실행된다. 따라서 ! 명령의 출력이 스킬 콘텐츠 안의 플레이스 홀더를 대체하며,&amp;nbsp;Claude는 실제 Bash 실행 결과가 포함된, 완전히 렌더링된 프롬프트를 최종 결과물로 받는다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;---
name: pr-summary
description: Summarize changes in a pull request
context: fork
agent: Explore
allowed-tools: Bash(gh *)
---

## Pull request context
- PR diff: !`gh pr diff`
- PR comments: !`gh pr view --comments`
- Changed files: !`gh pr diff --name-only`

## Your task
Summarize this pull request...
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 위와같이 PR에 대한 요약본을 설명해주는 스킬이 있다고 하면, 위의 !로 시작되는 명령어는, 스킬이 실행되기 전에 실제 gh pr diff 등의 실행 결과로 치환되며 클로드에게 전달이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;서브에이전트에서 Skill 실행하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Frontmatter에 context: fork를 추가하면, 격리된 상태에서 스킬이 실행된다. 또한 이때 해당 스킬을 수행할 Agent 타입도 agent로 지정해줄 수 있다. context: fork가 설정되면 스킬의 내용 전체가 서브에이전트를 구동하는 프롬프트가 되며, 이 서브에이전트는 현재 대화 기록에 접근할 수 없이 분리된 상태에서 실행된다.&amp;nbsp;즉, 서브에이전트는 스킬을 실행하고 결과만 주고 끝나므로, 해당 기능은 명시적인 지시(작업)이 존재하는 스킬에서만 의미가 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;접근&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;시스템 프롬프트&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;작업&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;함께 불러와지는 내용들&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.6977%;&quot;&gt;context: fork가 있는 스킬&lt;/td&gt;
&lt;td style=&quot;width: 34.186%;&quot;&gt;에이전트 타입(Explore, Plan 등)에서 옴&lt;/td&gt;
&lt;td style=&quot;width: 17.7907%;&quot;&gt;&lt;a href=&quot;http://SKILL.md&quot;&gt;SKILL.md&lt;/a&gt; 내용&lt;/td&gt;
&lt;td style=&quot;width: 27.2093%;&quot;&gt;&lt;a href=&quot;http://CLAUDE.md&quot;&gt;CLAUDE.md&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.6977%;&quot;&gt;skills 필드가 있는 서브에이전트&lt;/td&gt;
&lt;td style=&quot;width: 34.186%;&quot;&gt;서브에이전트의 마크다운 본문&lt;/td&gt;
&lt;td style=&quot;width: 17.7907%;&quot;&gt;Claude의 위임 메시지&lt;/td&gt;
&lt;td style=&quot;width: 27.2093%;&quot;&gt;사전 로드된 스킬들 + &lt;a href=&quot;http://CLAUDE.md&quot;&gt;CLAUDE.md&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Skill&lt;/b&gt;&lt;b&gt;의 트리거 조건 설정하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤에서 설명하겠지만 스킬은 적당량이 유지되는 것이 중요하다. 따라서 어떠한 스킬을 클로드에게 항상 선택지 중 하나로 전달하는 것은 컨텍스트를 낭비하게 되므로, 사용자가 직접 트리거 하기만을 원하는 경우에는 disable-model-invocation와 user-invocable를 조정해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 좋은 Skill에 대하여 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;좋은 Skill을 작성하는 과정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skills 구축의 성패는 작성 단계 이전의 설계 품질에서 거의 결정된다고 한다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;잘 설계된 Skill은 구현이 단순해지고, 테스트와 유지보수 비용도 크게 줄게 되는데, 앤트로픽은 &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;좋은 Skill을 작성하기 전에&lt;/span&gt;, 반드시 2~3개의 구체적인 사용 사례(use case) 를 정의할 것을 권장한다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;사용 사례는 추상적인 목적이 아니라, 실제 사용자가 말할 문장과 결과까지 포함해야 하며, &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;좋은 사용 사례는 다음의 요소들이 포함되어야 한다.&lt;/span&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;li&gt;사용되는 도구(Claude 기본 기능 또는 MCP)&lt;/li&gt;
&lt;li&gt;최종 결과 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 앤트로픽은 테스트의 중요성 역시 강조하는데, 크게 3가지 핵심 테스트 영역을 구성하여 활용할 것을 권장한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트리거 테스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목적: 스킬이&amp;nbsp;적절한 상황에서만 자동 로드되는지&amp;nbsp;검증&lt;/li&gt;
&lt;li&gt;ex) 표현이 바뀐 요청에서도 스킬이 트리거 되는지 검증함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;기능 테스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목적: 스킬이&amp;nbsp;의도한 결과를 정확히 생성하는지&amp;nbsp;확인&lt;/li&gt;
&lt;li&gt;ex) 출력 결과의 정확성, 엣지 케이스 대응 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;성능 비교 테스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목적: 스킬 사용 전후의&amp;nbsp;실질적 개선 효과&amp;nbsp;확인&lt;/li&gt;
&lt;li&gt;ex) 메시지 왕복 횟수, 총 토큰 사용량 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;skill-creator를 활용한 Skill의 생성과 품질 평가 및 개선&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mangkyu.tistory.com/463&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스팅&lt;/a&gt;에서 설명하였듯,&amp;nbsp;&lt;a href=&quot;https://skills.sh/anthropics/skills/skill-creator&quot;&gt;Skill Creator&lt;/a&gt;는 Anthropic(앤트로픽)이 기본으로 제공하는 도구 중 하나로, 다음의 주요 기능들을 제공한다.&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;SKILL.md 형식과 frontmatter 자동 생성&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skill Creator는&amp;nbsp;스킬을 잘 만드는 방법에 대한 가이드와 템플릿을 제공한다. &lt;span&gt;에이전트에게 특정 도메인 지식 + 워크플로 + 도구 사용법을 넣어서 &amp;ldquo;일반 에이전트 &amp;rarr; 전문 에이전트&amp;rdquo;로 바꿔주며, 생성한 스킬들을 평가할 수 있는 항목들도 포함하여 그 성능을 극대화시킨다. &lt;/span&gt;&lt;span&gt;스킬을 새롭게 생성하고, 기존에 존재하는 스킬들을 평가 및 개선하고자 할 때면 반드시 Skill Creator를 활용할 것을 권장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;적정량의 Skill의 수 유지하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로드는 &amp;ldquo;사용 가능한 스킬 목록&amp;rdquo;을 관리하기 위해 문자 예산(character budget)이라는 개념을 활용한다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;클로드는 각 스킬의 설명(description)들을 대화 컨텍스트에 같이 로드하는데, &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;문자 예산은 컨텍스트 윈도우의 2% 차지하며, 컨텍스트 윈도우가 너무 작을 경우를 대비해 최소 하한선으로 16000자가 지정되어 있다. &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;스킬이 많으면 문자 예산(character budget)을 초과하며 일부 스킬이 제외될 수 있기에, 적절한 양의 스킬과 스킬의 설명들로 관리가 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Skill의 실행 순서와 description&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 설명하였듯 Skill은 프롬프트처럼 대화에 바로 주입되지 않고, name과 description 만이 시스템 프롬프트에 올라간다. 그리고 '단계별 공개'(progressive disclosure) 방식을 따라 처리된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;메타데이터(name + description)를 시스템 프롬프트에 상시 로딩함(Skill 하나당 약 100토큰)&lt;/li&gt;
&lt;li&gt;사용자 명령이 SKILL의 description에 부합하는 경우, Bash 도구로 &lt;a href=&quot;http://SKILL.md&quot;&gt;SKILL.md&lt;/a&gt; 전문을 읽어들임&lt;/li&gt;
&lt;li&gt;처리를 하다가 scripts 와 references 폴더 파일이 필요해지면, 실제 참조 시점에 로딩함&lt;/li&gt;
&lt;li&gt;스크립트 실행 시 코드 자체는 맥락에 올라가지 않고 출력값만 소비함&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 본문 내용(&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Body)에 자주 들어가는 &amp;ldquo;When to Use This Skill&amp;rdquo;은 이미 Skill 이 발동되고 읽히므로 낭비일 뿐이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;컨텍스트 윈도우는 공공재이기 때문에, Skill은 대화 기록이나 시스템 프롬프트와 SKILL의 body가 함께 공존한다. 따라서 가급적 500줄 이하로 작성하고, 클로드가 이미 아는 내용은 작성할 필요가 없다. 또한 &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;500줄보다 길어질 경우 상세 파일로 분리해야 하며, 2단계 이상의 중첩 참조는 지양해야 한다. &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;참조 파일이 길어질 경우, Claude가 head -100으로 일부만 읽을 수 있으므로 목차를 맨 위에 넣어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;검증 루프 작성하기&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그 다음은 Skill의 성능과 정확도를 가장 끌어올릴 수 있는 기술로, 검증 루프를 작성하는 것이다. 실행 &amp;rarr; 검증 &amp;rarr; 수정 후에는 재검증 루프를 추가해주어 Claude가 문제를 재발하지 않도록 해야 한다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이를 위해 체크리스트를 body 에 넣고 Claude에게 검증하라고 하면, Skill의 질을 극대화할 수 있다. 실제로 검증 루프에 대한 체감은 상당히 크기 때문에, 반드시 작성할 것이 권장된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Skill의 트리거에 대하여 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Skill 발동을 위한 훅&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스킬이 잘 발동되지 않는 이유는, 클로드에 스킬 정보가 없는 것이 아니라, 그 지시를 제대로 읽지 못하기 때문이다. 이를 위해 스킬 트리거를 위한 Hook을 사용하면, 스킬의 호출률을 높일 수 있다. 이 동작은 Claude가 프롬프트를 보기 직전에 사용자의 입력을 가로채서, 스킬 추천을 메시지에 직접 덧붙이는 방식이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ASIS:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능 구현 좀 도와줘&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TOBE:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능 구현 좀 도와줘&lt;b&gt;CRITICAL SKILLS (REQUIRED): &lt;/b&gt;session-management&lt;b&gt;ACTION: Use Skill tool BEFORE responding&lt;/b&gt;&lt;/li&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RECOMMENDED SKILLS: &lt;/b&gt;git-commits&lt;/li&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;--- SKILL ACTIVATION CHECK ---&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;앤트로픽은 좋은 스킬을 작성하는 방법에 대한 내용을 33쪽의 분량에 걸친&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #0070d1; text-align: start;&quot; href=&quot;https://resources.anthropic.com/hubfs/The-Complete-Guide-to-Building-Skill-for-Claude.pdf&quot;&gt;PDF 자료&lt;/a&gt;로 제공하고 있다. 보다 상세하고 구체적인 내용을 원한다면, 해당 PDF 파일을 참고하기를 권장한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://code.claude.com/docs/en/skills&quot;&gt;https://code.claude.com/docs/en/skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/posts/jyoung105_anthropic-이-공개한-skillmd-body-작성-규칙-5가지-activity-7428729561946722304-O3kE&quot;&gt;https://www.linkedin.com/posts/jyoung105_anthropic-이-공개한-skillmd-body-작성-규칙-5가지-activity-7428729561946722304-O3kE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/coding-nexus/claude-code-skill-activation-hook-force-skills-to-load-every-time-no-memory-required-e2bdfba37656#id_token=eyJhbGciOiJSUzI1NiIsImtpZCI6ImQyNzU0MDdjMzllODAzNmFhNzM1ZWIyYzE3YzU0ODc2MWNlZDZhNjQiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMTYyOTYwMzU4MzQtazFrNnFlMDYwczJ0cDJhMmphbTRsamRjbXMwMHN0dGcuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMTYyOTYwMzU4MzQtazFrNnFlMDYwczJ0cDJhMmphbTRsamRjbXMwMHN0dGcuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDY2NDQwMTE1NTY1MDA2Njg3MTIiLCJoZCI6InRvc3MuaW0iLCJlbWFpbCI6Im1hbmdreXVAdG9zcy5pbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJub25jZSI6Im5vdF9wcm92aWRlZCIsIm5iZiI6MTc3MjAwOTE3NCwibmFtZSI6IuyhsOuvvOq3nEIgKE1hbmdLeXUpIiwicGljdHVyZSI6Imh0dHBzOi8vbGgzLmdvb2dsZXVzZXJjb250ZW50LmNvbS9hL0FDZzhvY0s1NTlSUU4tLTN2WTU3c1VrRnZ4UmJqOUI1cTVHbHJkREFkaWNBVEdNVDlkZHdSZz1zOTYtYyIsImdpdmVuX25hbWUiOiLrr7zqt5xCIiwiZmFtaWx5X25hbWUiOiLsobAiLCJpYXQiOjE3NzIwMDk0NzQsImV4cCI6MTc3MjAxMzA3NCwianRpIjoiMTFmNWZmNzViOWEyN2YxZGQzNGM2ZThkMzVhYzY2MjBlY2E1NjcyNSJ9.p6Z8USH98ODbqBT1351qUN6sonKdrXiEJnyeYQ9DvaY9z87cupxg2tZYLJHp-JscfBbHUULQp3DSIuaYZZNvyJJyZsZj_HZzGJODZsC4kWZ3H1y_5_dI9PrSI8xwrGQcoBXv-GlD_7TTrCG8PT-4XS5cm_47j5iYKSQ1jComXTsXX2NogxMWElpybabb79AXOonrEn7L30oewaGqe_BLqlhON9XxuIbmalNVqPQ6tTEfHHoFVW4kQyuLiVJJPwC2pAGxnhhL_8r1l2_khWENjzG9-Jg_mM-iFjKIPfSDchu0YsG7naOdzxyX3699Bq9gtKZQDb5DQOQg3qEP-pe83g&quot;&gt;https://medium.com/coding-nexus/claude-code-skill-activation-hook-force-skills-to-load-every-time-no-memory-required-e2bdfba37656&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.hada.io/topic?id=26328&quot;&gt;https://news.hada.io/topic?id=26328&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AI</category>
      <author>망나니개발자</author>
      <guid isPermaLink="true">https://mangkyu.tistory.com/464</guid>
      <comments>https://mangkyu.tistory.com/464#entry464comment</comments>
      <pubDate>Tue, 10 Mar 2026 10:00:32 +0900</pubDate>
    </item>
    <item>
      <title>[AI] Claude Code(클로드 코드)의 활용을 극대화해주는 설정과 도구들의 모음(Claude Code Skills, Plugins, ETC)</title>
      <link>https://mangkyu.tistory.com/463</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt;1. Claude Code(클로드 코드)의 활용을 극대화해주는 설정과 도구들의 모음&lt;br /&gt;(Claude Code Skills, Plugins, ETC)&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Claude Code의 실행 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; &lt;span data-token-index=&quot;0&quot;&gt;Claude Code 실행 Alias&lt;/span&gt; &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로드 코드를 실행시키려면, 기존에는 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;프로젝트 디렉토리로 이동한 후에 claude 명령어로 클로드를 실행시켜야 했다. 하지만 이러한 과정 역시 번거로운데, c mem과 같은 명령어만 입력해도, 유사한 이름의 프로젝트 디렉토리로 이동한 후에 자동으로 클로드를 실행해주면 매우 용이할 것이다. 다음의 파일을 실행하여 클로드 실행에서 편리함을 가져가주도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/ueYms/dJMcahcrbDK/RS4T4JIUUKhZzeAgqFJ1Yk/c-alias-install.sh?attach=1&amp;amp;knm=tfile.sh&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;c-alias-install.sh&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.01MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Haiku 모델 비활성화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Haiku 모델은 일관성 없는 결과를 내놓으며 결과의 품질을 떨어뜨린다. 또한 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;세션이 길어지거나 복잡해지면 앞에서 합의한 조건을 잊거나 앞 문맥과 충돌하기도 도 한다. 따라서 Haiku &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;사용 시에 적용되는 모델을 Sonnet 1M으로 변경하여, Haiku가 사용되지 않는 환경의 이점을 누리도록 하자. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;~/.claude/settings.json에서 다음의 설정을 추가해주면 된다. 만약 Sonnet 1M을 사용할 수 없는 구독제라면, 일반 sonnet 모델을 사용해주도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1772280878997&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;env&quot;: {
    &quot;ANTHROPIC_DEFAULT_HAIKU_MODEL&quot;: &quot;claude-sonnet-4-5-20250929[1m]&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Claude Status Line&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Status Line은 Claude Code CLI의 상태 표시줄에 원하는 정보를 자유롭게 추가할 수 있게 한다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;현재 작업 중인 Git 브랜치, 최근 커밋 메시지, CPU/GPU 사용량, 남은 토큰 수 등을 표시할 수 있다. &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;대표적인 플러그인으로 &lt;a href=&quot;https://github.com/jarrodwatts/claude-hud&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;jarrodwatts/claude-hud&lt;/a&gt; 등이 존재하며, 본인의 입맛에 맞게 커스터마이징하면 됨&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ITerm2 키 바인딩 문제 수정하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Iterm2에서 한글일 때, 단축키가 제대로 동작이 안될 것이다. 예를 들어 Ctrl + V는 이미지 붙여넣기가 되겟지만, V가 한글 상태일 때인 Ctrl + ㅍ는 이미지 붙여넣기가 안된다. 그 이유는 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;한글 입력기(IME)가 키보드 입력을 &quot;단축키&quot;로 인식하지 못하고 &quot;끌자 입력&quot;으로 처리하기 때문인데, &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;ITerm2의 설정 조합으로 단축키 Hex를 앱에 직접 보내게 설정하면 해결 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;ITerm2 완전 종료(⌘Q) 후에 터미널에서 다음의 스크립트 실행해주면 자동으로 설치가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/oxqZb/dJMcadA2TDY/XZrvdiUgdrUY5HcHcsk6B0/iterm2-key-binding.sh?attach=1&amp;amp;knm=tfile.sh&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;iterm2-key-binding.sh&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.00MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Line Height Settings&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널 기본 환경은 터미널 줄 간격(line height)이 너무 짧아서, 가독성이 떨어지고 제대로 읽기가 힘들다. 따라서 클로드에게 다음의 명령어를 전달하여 터미널의 줄 간격을 1.3으로 넓혀주도록 하자. 그러면 클로드 이용이 훨씬 수월해질 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1772281222581&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;please set my terminal line height to 1.3&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;유용한 단축키들&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;!: bash 실행 모드&lt;/li&gt;
&lt;li&gt;Ctrl + S: 작성중인 명령어 스태시(stash, 임시 저장)&lt;/li&gt;
&lt;li&gt;Ctrl + Z: 절전 모드, fg 누르면 복귀&lt;/li&gt;
&lt;li&gt;Ctrl + U: 커서 앞 다 지우기&lt;/li&gt;
&lt;li&gt;Ctrl + K: 커서 뒤 다 지우기&lt;/li&gt;
&lt;li&gt;Ctrl + A / E: 줄 단위 이동&lt;/li&gt;
&lt;li&gt;Ctrl + W: 한단어 지우기&lt;/li&gt;
&lt;li&gt;Ctrl + G: VIM 모드에서 명령어 편집&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 플러그인(&lt;span data-token-index=&quot;0&quot;&gt;Plugins) &lt;/span&gt;]&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Oh-my-claudecode: Claude Code CLI의 멀티 에이전트 도구&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Yeachan-Heo/oh-my-claudecode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oh-my-claudecode&lt;/a&gt;는 Claude Code CLI에 자동으로 &quot;멀티 에이전트 오케스트레이션(작업 분업/병렬화)&amp;rdquo;을 얹어주는 플러그인이다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;사용자가 명령을 외우지 않아도, 입력한 요청을 보고 자동으로 멀티 에이전트 작업으로 분해해서 처리해준다. &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;플러그인 설치만 하면, 알아서 병렬 처리가 적용되기 때문에 사용이 용이하다. 자신만의 에이전트 환경이 아직 없다면 사용해주고, 그 외에 개인만의 최적화된 에이전트 구성이 필요하다면 직접 구성하고 활용해도 괜찮을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;code-simplifier: Anthropic의 코드 품질 플러그인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/anthropics/claude-plugins-official/blob/main/plugins/code-simplifier/agents/code-simplifier.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;code-simplifier&lt;/a&gt;은 클로드를 만든 Anthropic(앤트로픽)에서 내부적으로 사용하다가 오픈소스로 공개한 코드 품질 플러그인이다. 코드의 가독성, 일관성, 유지보수성을 높이면서 기능은 그대로 유지하도록 단순화하고 정제해준다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;복잡한 코드를 명확하고 유지보수 가능한 형태로 단순화시키고, 모든 기존 기능을 그대로 유지하면서 코드 품질 개선시켜준다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Ralph Wiggum: 작업의 반복적 개선을 도와주는 랄프 루프&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/anthropics/claude-code/blob/main/plugins/ralph-wiggum/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ralpha Wiggum&lt;/a&gt;은 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Anthropic(앤트로픽)에서&lt;span&gt; 만든 플러그인 중 하나로, 클로드가 자체 작업을 반복해서 수행하게 하게 도와준다. 이를 통해 AI가 같은 작업을 여러 번 반복하여 점진적으로 완성시키게 된다. &lt;/span&gt;&lt;/span&gt;Claude는 이제 한 번에 작업을 딱 끝내는 것이 아니라, 다음의 과정을 계속 반복하면서 목표에 가까운 결과를 만들게 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;652&quot; data-start=&quot;588&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;599&quot; data-start=&quot;588&quot;&gt;작업을 실행하고,&lt;/li&gt;
&lt;li data-end=&quot;611&quot; data-start=&quot;600&quot;&gt;결과를 확인하고,&lt;/li&gt;
&lt;li data-end=&quot;637&quot; data-start=&quot;612&quot;&gt;실패나 부족한 점이 있으면 다시 실행하고,&lt;/li&gt;
&lt;li data-end=&quot;652&quot; data-start=&quot;638&quot;&gt;그 결과를 다시 보고&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 외부에 공개된 스킬들(External Skills) ]&lt;br /&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Superpowers&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/obra/superpowers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Superpowers&lt;/a&gt;는 코딩 에이전트를 위한 완성형 소프트웨어 개발 워크플로우로, 에이전트가 코드를 짜기 전에 리드 개발자처럼 생각하게 된다. 실제 워크 플로우는 다음의 과정을 따라 처리되며, 클로드의 능력을 극대화해주는 하나의 도구라고 보면 된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Brainstorming: 기획을 구체화하고 설계를 검증받는 단계예요.&lt;/li&gt;
&lt;li&gt;Writing Plans: 작업을 잘게 쪼개고 검증 계획을 세워요.&lt;/li&gt;
&lt;li&gt;Subagent Dev: 각 태스크마다 서브 에이전트가 작업을 수행해요.&lt;/li&gt;
&lt;li&gt;TDD Cycle: 실패하는 테스트 작성 &amp;rarr; 코드 구현 &amp;rarr; 성공 확인 과정을 거쳐요.&lt;/li&gt;
&lt;li&gt;Finishing: 모든 테스트가 통과되면 브랜치를 정리하고 마무리!&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Skill Creator&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://skills.sh/anthropics/skills/skill-creator&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Skill Creator&lt;/a&gt;는 Anthropic(앤트로픽)이 기본으로 제공하는 도구 중 하나로, 다음의&lt;span&gt;&amp;nbsp;&lt;/span&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;SKILL.md&lt;span&gt;&amp;nbsp;&lt;/span&gt;형식과 frontmatter 자동 생성&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Skill Creator는&amp;nbsp;스킬을 잘 만드는 방법에 대한 가이드와 템플릿을 제공한다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;에이전트에게 특정 도메인 지식 + 워크플로 + 도구 사용법을 넣어서 &amp;ldquo;일반 에이전트 &amp;rarr; 전문 에이전트&amp;rdquo;로 바꿔주며, 생성한 스킬들을 평가할 수 있는 항목들도 포함하여 그 성능을 극대화시킨다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;스킬을 새롭게 생성하고, 기존에 존재하는 스킬들을 평가 및 개선하고자 할 때면 반드시 Skill Creator를 활용할 것을 권장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Find Skills&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://skills.sh/vercel-labs/skills/find-skills&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Find Skills&lt;/a&gt;는 스킬 생태계에서 필요한 스킬을 찾고(검색) 설치까지 안내해주는 스킬이다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;사용자가 &quot;X 어떻게 해?&quot;, &quot;X용 스킬 있어?&quot; 처럼 특정 작업/역량을 확장하고 싶을 때 트리거된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 직접 만들어 사용하는 스킬들(Custom Skills) ]&lt;br /&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Git 관련 Skill&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;git/pr: 커밋 없이 Pull Request 생성&lt;/li&gt;
&lt;li&gt;git/rebase:&amp;nbsp;현재 브랜치를 develop에 rebase함&lt;/li&gt;
&lt;li&gt;git/rebase-and-pr: develop 브랜치로 Rebase 후 PR을 생성함&lt;/li&gt;
&lt;li&gt;git/commit-rebase-and-pr:&amp;nbsp;커밋 + Rebase + PR 생성을 한 번에 수행함&lt;/li&gt;
&lt;li&gt;git/merge-pr:&amp;nbsp;PR을 머지함&lt;/li&gt;
&lt;li&gt;git/release:&amp;nbsp;master &amp;lt;- develop 릴리즈 PR을 생성하고 머지함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DB&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;db/ddl: JPA Entity를 분석하여 MySQL CREATE TABLE DDL을 생성함&lt;/li&gt;
&lt;li&gt;db/dml: JPA Repository를 분석하여 사용되는 DML을 생성함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Server&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;server/intellij-http:&amp;nbsp;Controller에서 IntelliJ HTTP 테스트 파일을 생성함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Task&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;task/parallel-subtree:&amp;nbsp;Git WorkTree 기반으로 작업을 병렬 처리함&lt;/li&gt;
&lt;li&gt;task/create-hooks: Claude Code Hooks 가이드 기반으로 만들어진 훅 생성 도구&lt;/li&gt;
&lt;li&gt;task/create-plugin: Claude Code 플러그인 생성 도구&lt;/li&gt;
&lt;li&gt;task/create-agents: Claude Code Agent(서브에이전트) 생성 도구&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;task&lt;/span&gt;&amp;nbsp;/retrospect: 현재 대화 세션을 회고하여 개선점 도출&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Settings&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;settings/publish-skill: 개인 스킬을 관리하는 레포에 변경 사항을 자동 배포하는 스킬&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Notion&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;notion/append: Notion 페이지에 콘텐츠 추가하는 스킬&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Workflow&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;workflow/init: 워크플로우 초기 설정&lt;/li&gt;
&lt;li&gt;workflow/backlog: 백로그 등록 (Jira + Notion)&lt;/li&gt;
&lt;li&gt;workflow/quick-start: 빠른 작업 시작&lt;/li&gt;
&lt;li&gt;workflow/start: 백로그 티켓으로 작업 시작&lt;/li&gt;
&lt;li&gt;workflow/quick-auto: Slack 기반 자동 작업&lt;/li&gt;
&lt;li&gt;workflow/inprogress: 진행 중인 Jira 티켓 조회&lt;/li&gt;
&lt;li&gt;workflow/complete: 작업 완료 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 AI의 시대가 도래하면서, 이제 못할 것은 없다고 생각이 든다.&amp;nbsp;위에 적지는 못했더라도 이미 많은 사람들이 훨씬 많은 시도들로 도구들을 만들고 있고, 많은 업무들의 자동화가 더욱 가속화되리라는 생각이 든다. 만약 본인이 특정한 업무 작업을 반복하고 있다면, 어떻게든 자동화하고 개선할 여지를 찾으면서 AI의 활용을 극대화하도록 하자.&lt;/p&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AI</category>
      <author>망나니개발자</author>
      <guid isPermaLink="true">https://mangkyu.tistory.com/463</guid>
      <comments>https://mangkyu.tistory.com/463#entry463comment</comments>
      <pubDate>Tue, 3 Mar 2026 10:00:00 +0900</pubDate>
    </item>
    <item>
      <title>[AI] AI 시대를 맞이하는 개발자의 역할과 작업 방식의 변화</title>
      <link>https://mangkyu.tistory.com/462</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt; 1. AI 시대를 맞이하는 개발자의 역할과 작업 방식의 변화&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘날 다양한 AI 코딩 도구들이 나오면서, 개발자들은 많은 작업 방식의 변화를 맞이하고 있다. 이러한 변화는 실제하며, 나 역시도 이러한 과도기를 적극적으로 맞이하고 있다. 개인적으로 맞이한 변화가 무엇이고, 어떠한 생각을 가지고 있는지 정리해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ IDE(IntelliJ)의 활용 시간 감소 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 IDE(IntelliJ)의 활용 시간 감소이 대폭 줄어들었다. IDE의 활용도가 많은 생산성 향상과 효율성 증대를 일으킨다는 것을 체감하기에, 신입 사원을 교육할 때면 마우스 없이 개발하며, 키보드와 IDE 단축키의 활용을 극대화하는 의도적 연습을 시키곤 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 오늘날 이러한 가치는 이전 대비 대폭 감소했고, 켄트 백(Kent Beck)이 &lt;a href=&quot;https://newsletter.pragmaticengineer.com/p/tdd-ai-agents-and-coding-with-kent&quot;&gt;팟 캐스트&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;1187&quot; data-origin-height=&quot;220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QZBaa/dJMcab4eDuG/0nZfDkGU3aFOu8vHbKawn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QZBaa/dJMcab4eDuG/0nZfDkGU3aFOu8vHbKawn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QZBaa/dJMcab4eDuG/0nZfDkGU3aFOu8vHbKawn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQZBaa%2FdJMcab4eDuG%2F0nZfDkGU3aFOu8vHbKawn1%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;1187&quot; height=&quot;220&quot; data-origin-width=&quot;1187&quot; data-origin-height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 IDE에서 단축키를 이용해 코드를 생성하고, 변경하는 등의 작업이 주였다면, 이제는 Iterm2와 같은 터미널에서 프롬프트를 입력시키는 것이 주된 업무가 되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BOrir/dJMcab4eDuP/lEHDpAlu5IiDnUPhEWr6w0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BOrir/dJMcab4eDuP/lEHDpAlu5IiDnUPhEWr6w0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BOrir/dJMcab4eDuP/lEHDpAlu5IiDnUPhEWr6w0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBOrir%2FdJMcab4eDuP%2FlEHDpAlu5IiDnUPhEWr6w0%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;2048&quot; height=&quot;902&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;902&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 IDE를 전혀 활용하지 않는 것은 아니다. 상세한 구현을 보거나, Code 변경 사항을 보거나, 간단한 rename 등의 작업을 할 때 활용하기도 한다. 하지만 이전에 중요하다고 여겼던 IDE의 활용 능력은 이제 그 가치가 바래졌음을 느낀다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 여러 작업을 동시에 처리하기 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 내가 하는 작업의 대부분은 프롬프트 입력이 되었기에, 개발 자체에 쏟는 시간이 많이 줄어들었다. 따라서 그 시간이 여러 다른 곳들로 분배되며 더 많은 업무 상황을 다루게 되었다. 그리고 이는 자연스레 여러 컨텍스트를 다룰 수 있는 능력과 여러 작업을 동시에 AI에게 위임할 수 있는 능력을 요구하게 되었다. 아래의 그림처럼 서로 다른 여러 컨텍스트의 작업을 병렬적으로 돌릴 수 있어야 하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o0ttK/dJMcag5zbYU/BfOaXOQpIzaJxGgik8pWzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o0ttK/dJMcag5zbYU/BfOaXOQpIzaJxGgik8pWzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o0ttK/dJMcag5zbYU/BfOaXOQpIzaJxGgik8pWzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo0ttK%2FdJMcag5zbYU%2FBfOaXOQpIzaJxGgik8pWzK%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;2048&quot; height=&quot;802&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 개발자는 완성도 있는 1개의 작업에 집중했고, 이를 위해 컨텍스트의 방해를 유발하지 않는 &lt;a href=&quot;https://news.hada.io/topic?id=25575&quot;&gt;집중하는 시간이 필요하다는 주장&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;1320&quot; data-origin-height=&quot;710&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3HzSR/dJMcahwDUf5/EwtbuXnLVv6PWj1znm5P8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3HzSR/dJMcahwDUf5/EwtbuXnLVv6PWj1znm5P8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3HzSR/dJMcahwDUf5/EwtbuXnLVv6PWj1znm5P8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3HzSR%2FdJMcahwDUf5%2FEwtbuXnLVv6PWj1znm5P8k%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;1320&quot; height=&quot;710&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;710&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이제는 더 이상 이러한 부분이 유효하지 않다고 생각했다. 더 많은 컨텍스트를 동시에 다루어야 하며, 빠르게 문맥을 파악하고 AI에게 위임할 수 있어야 한다. 즉, 1개에 포커스해서 집중하던 업무 방식에서, 동시에 여러 개의 문맥과 프로젝트를 다루며 빠르게 컨텍스트 스위칭하는 방식으로 전환된 것이다. (ADHD를 유발할 수 있는&amp;hellip;) 복잡하고 정신없이 업무를 다루는 방식이 되었고, 이러한 변화는 이제 불가피한 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 불편함을 직접 개선할 수 있는 시대 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 업무를 하며 여러 가지 도구를 활용하게 된다. 그리고 심지어 그 도구의 활용도를 더욱 높이기 위해 플러그인까지 활용한다. 간단하게 크롬을 이용할 때에는 크롬 확장 프로그램(크롬 익스텐션, Chrome Extension)도 활용하고, IntelliJ와 같은 IDE를 이용할 때에도 서드파티 플러그인을 많이 활용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 동안은 크롬이나 IDE를 이용하면서 겪는 불편함이 있을 때, 이를 개선하기 위한 도구들을 직접 만드는 것은 러닝 커브도 높고 허들도 있기에, 약간의 불편함을 감수하고 살아왔다. 하지만 이제 우리에게는 AI가 있기에, 불편한 부분이 있고 그것이 나의 업무 생산성에 영향을 준다면 직접 만들어 해결해버리면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 AI를 활용해 &lt;a href=&quot;https://toss.tech/article/internal-mcp-server&quot;&gt;사내 MCP 서버&lt;/a&gt;를 만들고, &lt;a href=&quot;https://toss.tech/article/flowise-llm-error-analysis-automation&quot;&gt;에러 분석 자동화&lt;/a&gt; 등의 흐름을 개선했었다. 하지만 최근에는 AI가 더욱 발전하면서, 키바나(Kibana)의 JSON 필드를 시각화해주는 크롬 확장 플러그인과 IntelliJ에서 yaml 파일의 전체 key를 힌트로 노출해주는 플러그인을 개발했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;966&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GRm4I/dJMcabQHhZe/LYLYUY3IYECyx75OUORhOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GRm4I/dJMcabQHhZe/LYLYUY3IYECyx75OUORhOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GRm4I/dJMcabQHhZe/LYLYUY3IYECyx75OUORhOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGRm4I%2FdJMcabQHhZe%2FLYLYUY3IYECyx75OUORhOK%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;2048&quot; height=&quot;966&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;966&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1072&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUuBAu/dJMcac9RNYw/8z1afDPE7cTxwBtd7soY0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUuBAu/dJMcac9RNYw/8z1afDPE7cTxwBtd7soY0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUuBAu/dJMcac9RNYw/8z1afDPE7cTxwBtd7soY0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUuBAu%2FdJMcac9RNYw%2F8z1afDPE7cTxwBtd7soY0K%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;1072&quot; height=&quot;424&quot; data-origin-width=&quot;1072&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 내가 직접 코드에 관여한 것은 하나도 없었고, 프롬프트와 개선점에 대한 피드백을 지속적으로 주었을 뿐이다. 이제 이러한 역량의 경계가 없어졌으니, 스스로 보다 많은 불편함을 탐지하고 직접 개선해서 작업을 지연시키는 블로커를 제거할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 위의 소스 코드 참고 링크와 이용은 아래를 통해 할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;beautify-kibana 설치하기: &lt;a href=&quot;https://chromewebstore.google.com/detail/kibana-beautify/eljnhhjaplhcfmegclljpdohiadagclo?authuser=0&amp;amp;hl=ko&quot;&gt;https://chromewebstore.google.com/detail/kibana-beautify/eljnhhjaplhcfmegclljpdohiadagclo?authuser=0&amp;amp;hl=ko&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;beautify-kibana 소스 코드: &lt;a href=&quot;https://github.com/MangKyu/beautify-kibana&quot;&gt;https://github.com/MangKyu/beautify-kibana&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;yaml-properties-hinter 설치하기: &lt;a href=&quot;https://plugins.jetbrains.com/plugin/30256-yaml-properties-hinter/edit&quot;&gt;https://plugins.jetbrains.com/plugin/30256-yaml-properties-hinter/edit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;yaml-properties-hinter 소스코드: &lt;a href=&quot;https://github.com/MangKyu/yaml-properties-hinter-intellij-plugin&quot;&gt;https://github.com/MangKyu/yaml-properties-hinter-intellij-plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI는 계속해서 발전하고 있고, 이러한 변화가 쌓여 화이트 컬러 직종이 모두 AI에게 대체된다는 이야기까지 나오고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;1324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wtomz/dJMcahDna96/RfBGscScQ2JJXyQxAXBs90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wtomz/dJMcahDna96/RfBGscScQ2JJXyQxAXBs90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wtomz/dJMcahDna96/RfBGscScQ2JJXyQxAXBs90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwtomz%2FdJMcahDna96%2FRfBGscScQ2JJXyQxAXBs90%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;2002&quot; height=&quot;1324&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;1324&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 미래의 상황에 따라 그렇게 변할 수도 있다. 하지만 중요한 것은 현실이고, 그 시점이 당장은 아니라는 점이다. 우리가 당장 집중해야 할 것은, AI에게 대체 당할 걱정을 하며 소흘히 하루를 보내는 것이 아니라, AI의 활용도를 높이고 극대화하여 10x 엔지니어가 되기 위한 &amp;lsquo;의도적 수련(Deliberate Practice)&amp;rsquo; 일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 지금 우리가 수행하는 것 그리고 우리에게 중요한 것은 유연하게 상황에 적응하는 &amp;lsquo;태도와 자세&amp;rsquo;라고 본다. 현실이 빠르게 변한다고 하더라도, 상황을 빠르게 파악하고 능력을 기르는 연습을 나는 하고 있고, 해야 한다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AI</category>
      <author>망나니개발자</author>
      <guid isPermaLink="true">https://mangkyu.tistory.com/462</guid>
      <comments>https://mangkyu.tistory.com/462#entry462comment</comments>
      <pubDate>Tue, 24 Feb 2026 10:00:14 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] MySQL의 wait_timeout 설정과 HikariCP 6.1.0에 추가된 maxLifeTime 분산 기능</title>
      <link>https://mangkyu.tistory.com/461</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt;1. MySQL의 wait_timeout 설정과 HikariCP 6.1.0에 추가된 maxLifeTime 분산 기능&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ MySQL의 wait_timeout 설정과 커넥션 풀의 maxLifeTime 설정이란? ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 리소스와의 연결을 위해, 반드시 추가해야 하는 설정 중 하나가 타임아웃이다. 타임아웃을 제대로 설정하지 않으면, 다른 컴포넌트의 응답이 느려질 때 애플리케이션 전체가 영향을 받을 수 있다. 대표적으로 MSA 환경에서 외부 API와 통신을 할 때 타임아웃 설정이 중요하다. 타임아웃 설정이 존재하지 않으면, 외부 API의 응답이 지연될 때 애플리케이션의 스레드가 대기 상태에 빠져 전체 서비스의 응답 속도가 느려지며 장애를 전파받을 수 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 관점에서도 타임아웃 설정은 매우 중요하다. 데이터베이스는 특정 커넥션이 idle(유휴) 상태로 오래 유지되는 것을 허용하지 않는 경우가 많다. 왜냐하면 죽은 커넥션이 데이터베이스 서버의 자원을 낭비하는 등의 문제를 일으킬 수 있기 때문이다. 따라서 데이터베이스 서버는 일정 시간 이상 유휴 상태인 커넥션을 자동으로 종료하는 타임아웃 설정을 제공한다. 대표적으로 MySQL은 wait_timeout 시간 동안 유휴 상태인 커넥션을 자동으로 종료한다. 이를 통해 서버 자원을 효율적으로 관리하고, 불필요한 커넥션이 서버에 부담을 주지 않도록 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bssUSt/dJMcaac5Moq/aIKIlsI0xPw3ZkhxRDKlWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bssUSt/dJMcaac5Moq/aIKIlsI0xPw3ZkhxRDKlWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bssUSt/dJMcaac5Moq/aIKIlsI0xPw3ZkhxRDKlWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbssUSt%2FdJMcaac5Moq%2FaIKIlsI0xPw3ZkhxRDKlWK%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;600&quot; height=&quot;400&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;533&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 애플리케이션 입장에서는 정상 상태의 커넥션인데, 갑자기 데이터베이스 커넥션의 연결이 끊어지면 곤란하다. 따라서 애플리케이션에서는 데이터베이스 커넥션 풀을 사용할 때, 커넥션이 일정 시간 이상 유지되지 않도록 즉, 데이터베이스가 연결을 끊어버리기 전에 애플리케이션이 먼저 끊도록 설정하는 것이 중요하다. 대표적으로 HikariCP는 maxLifetime 설정을 통해 커넥션이 일정 시간 이상 유지되지 않도록 관리할 수 있다. 이 설정을 통해 커넥션이 일정 시간 이상 유지되면, 해당 커넥션을 종료하고 새로운 커넥션을 생성하도록 한다. 이를 통해 데이터베이스 서버와 애플리케이션 간의 커넥션 상태를 일치시키고, 예기치 않은 오류를 방지할 수 있다. 참고로 maxLifeTime에 따라 주기적으로 커넥션이 재생성되는 모습을 확인하고 싶다면, TCP 덤프에서 mysql.protocol == 10 으로 필터링하면 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ HikariCP 6.1.0에 추가된 maxLifeTime 분산 기능 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HikariCP 6.1.0에는 추가된 maxLifeTime 분산 기능이 추가되었다. 해당 설정이 존재하기 이전에는 maxLifetime 설정이 모든 커넥션에 동일하게 적용되었다. 예를 들어, maxLifetime을 30분으로 설정하면, 모든 커넥션이 생성된 시점부터 30분 후에 종료되었다. 이로 인해 커넥션 풀 내의 모든 커넥션이 동시에 종료되는 현상이 발생할 수 있었다. 이러한 현상은 커넥션 풀이 갑자기 비어버리는 상황을 초래할 수 있으며, 이는 애플리케이션의 성능 저하나 장애로 이어질 수 있다. 이러한 문제를 해결하기 위해 HikariCP 6.1.0 버전부터는 기본적으로 maxLifeTime의 25% 를 분산시키는 기능이 추가되었다. 이를 통해 maxLifetime이 동일하게 설정되어 있더라도, 각 커넥션의 실제 수명은 다르게 된다. 예를 들어, maxLifetime이 30분으로 설정된 경우, 각 커넥션의 실제 수명은 22.5분에서 37.5분 사이로 분산된다. 이를 통해 커넥션 풀이 갑자기 비어버리는 현상을 방지할 수 있으며, 애플리케이션의 안정성과 성능을 향상시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 HikariCP의 maxLifeTime 분산 기능에 대한 자세한 내용은 아래 커밋을 참고하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/brettwooldridge/HikariCP/commit/28f81da4400c4ee7899d1f901c663b8697843b85&quot;&gt;https://github.com/brettwooldridge/HikariCP/commit/28f81da4400c4ee7899d1f901c663b8697843b85&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java &amp;amp; Kotlin</category>
      <author>망나니개발자</author>
      <guid isPermaLink="true">https://mangkyu.tistory.com/461</guid>
      <comments>https://mangkyu.tistory.com/461#entry461comment</comments>
      <pubDate>Tue, 3 Feb 2026 10:00:25 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Validation 애노테이션 사용 시에 발생하는 ConstraintDeclarationException 에러</title>
      <link>https://mangkyu.tistory.com/460</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt;1. Validation&amp;nbsp;애노테이션&amp;nbsp;사용&amp;nbsp;시에&amp;nbsp;발생하는&amp;nbsp;ConstraintDeclarationException&amp;nbsp;에러&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Validation 애노테이션 사용 시에 발생하는 ConstraintDeclarationException 에러 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에를 들어 다음과 같은 컨트롤러가 존재한다고 하자. 파라미터로 받는 name은 최소 길이가 10이여야 한다는 유효성 검사를 도와주는 @Length 애노테이션이 붙어 있다. 그리고 이를 추싱화한 TestControllerInterface에는 관련 애노테이션 정보가 존재하지 않는 상황이다. 이러한 상황에서 컨트롤러를 호출하게 되면 어떤 결과가 나올까?&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import org.hibernate.validator.constraints.Length;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
class TestController implements TestControllerInterface {

    @GetMapping(&quot;/test&quot;)
    public Integer test(@RequestParam @Length(min = 10) String name) {
        return name.length();
    }
}

interface TestControllerInterface {
    Integer test(String name);
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 애플리케이션은 다음과 같은 에러를 내며 요청을 처리하지 못한다. 에러 메시지가 워낙 친절하기 때문에 해당 내용만 읽어도 어떻게 문제를 해결할 수 있을지 감을 잡을 수 있다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;2026-01-18T12:18:59.423+09:00 ERROR 47216 --- [mangkyu-spring] [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [
Request processing failed: jakarta.validation.ConstraintDeclarationException: 
HV000151: A method overriding another method must not redefine the parameter constraint configuration, 
but method TestController#test(String) redefines the configuration of TestControllerInterface#test(String).] with root cause

jakarta.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration, but method TestController#test(String) redefines the configuration of TestControllerInterface#test(String).
	at org.hibernate.validator.internal.metadata.aggregated.rule.OverridingMethodMustNotAlterParameterConstraints.apply(OverridingMethodMustNotAlterParameterConstraints.java:24) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData$Builder.assertCorrectnessOfConfiguration(ExecutableMetaData.java:462) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData$Builder.build(ExecutableMetaData.java:380) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataBuilder$BuilderDelegate.build(BeanMetaDataBuilder.java:260) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataBuilder.build(BeanMetaDataBuilder.java:133) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl.createBeanMetaData(BeanMetaDataManagerImpl.java:206) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl.getBeanMetaData(BeanMetaDataManagerImpl.java:165) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:267) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:235) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.springframework.validation.beanvalidation.MethodValidationAdapter.invokeValidatorForArguments(MethodValidationAdapter.java:261) ~[spring-context-6.2.6.jar:6.2.6]
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 메시지는 오버라이딩하는 메서드에서 제약 사항을 재정의하면 안된다고(must not redefine the parameter constraint configuration) 설명하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 부모이자 인터페이스인 TestControllerInterface#test 에는 Bean Validation(@NotNull, @Size, @Valid 같은 것) 이 존재하지 않는데, 이를 구현하는 구체 클래스 TestController#test 에서는 이것이 재정의되어 에러가 발생한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 유효성 검사의 구현체를 제공하는 하이버네이트(Hibernate)는 왜 이러한 제약을 걸어둔 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Jakarta Validation Specification &amp;ndash; Method constraints in inheritance hierarchies ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 내용은 하이버네이트만의 단독적인 특성은 아니고, Jakarta Validation(Bean Validation) 스펙에 맞게 구현했을 뿐이다. &lt;a href=&quot;https://jakarta.ee/specifications/bean-validation/3.1/jakarta-validation-spec-3.1.html#constraintdeclarationvalidationprocess-methodlevelconstraints-inheritance&quot;&gt;Jakrata Bean Validation 5.6.5의 Method constraints in inheritance hierarchies&lt;/a&gt;을 보면, 다음과 같은 내용이 존재한다. 해당 내용은 리스코프 치환 원칙에 따라, 하위 타입에서 파라미터 제약을 선언(추가/강화)하면 안 된다는 규칙과, 위반 시 ConstraintDeclarationException 에러를 던져야 한다는 내용을 담고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1982&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lyMal/dJMcagjXGnz/64hZvWAJoaIVdIpLlXlUI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lyMal/dJMcagjXGnz/64hZvWAJoaIVdIpLlXlUI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lyMal/dJMcagjXGnz/64hZvWAJoaIVdIpLlXlUI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlyMal%2FdJMcagjXGnz%2F64hZvWAJoaIVdIpLlXlUI1%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;1982&quot; height=&quot;466&quot; data-origin-width=&quot;1982&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스코프 치환 원칙(Liskov substitution principle)은 객체지향 프로그래밍(OOP)의 기본 원칙 중 하나로, 하위 타입은 상위 타입을 대체할 수 있어야 한다는 것이다. 즉, 부모 타입이 쓰이는 자리에 자식 타입을 넣어도 프로그램이 깨지지 않아야 한다. 하지만 만약 상위 타입에서 정의된 내용을 초과해서 하위 타입이 제공한다면, 프로그램이 실패할 수 있다. 따라서 Jakarta Validation(Bean Validation) 스펙은 리스코프 치환 원칙을 준수하도록 해당 제약을 정의해두었고, 하이버네이트 역시 이를 정확히 구현하여 &lt;a href=&quot;https://docs.hibernate.org/stable/validator/reference/en-US/html_single/#section-method-constraints-inheritance-hierarchies&quot;&gt;Hibernate Validator Reference Guide 9.1의 3.1.4 Method constraints in inheritance hierarchies&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;1928&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nhQkx/dJMcaaD24YI/TH4hEY64kR8KgNMvFOGl00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nhQkx/dJMcaaD24YI/TH4hEY64kR8KgNMvFOGl00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nhQkx/dJMcaaD24YI/TH4hEY64kR8KgNMvFOGl00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnhQkx%2FdJMcaaD24YI%2FTH4hEY64kR8KgNMvFOGl00%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;1928&quot; height=&quot;470&quot; data-origin-width=&quot;1928&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 위의 문제는 부모 인터페이스에 정의되어 있지 않은 제약 사항을 하위 구현체에서 추가하였고, 이로 인해 리스코프 치환 원칙을 위반하게 되어 Jakarta Validation 스펙에 따라 ConstraintDeclarationException 에러가 던져진 것으로 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스코프 치환 원칙은 사실 그렇게 낯선 개념이 아니다. &lt;a href=&quot;https://mangkyu.tistory.com/228&quot;&gt;이전 포스팅&lt;/a&gt;에서 살펴보았듯 자바도 리스코프 치환 원칙에 따라 메소드 오버라이딩을 할 때, 더 좁은 범위의 접근제어자로 변경할 수 없도록 제약하고 있다. 즉, 인터페이스에 정의된 메서드가 public이라고 하면, 이를 구현하는 자식 클래스에서도 protected나 private으로 가시성을 좁힐 수 없는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 에러가 발생했을 떄, 에러 메시지가 워낙 친절하기 때문에 이를 수정하는 것은 그리 큰 문제가 아니다. 하지만 왜 이러한 설계 제약이 생겼고, 그 근거가 무엇인지 파악하는 것은 또 다른 문제이다. 이러한 문제가 생겼을 때, 단순한 해결보다는 깊이있는 생각을 통해 접근하는 자세가 더욱 중요할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <author>망나니개발자</author>
      <guid isPermaLink="true">https://mangkyu.tistory.com/460</guid>
      <comments>https://mangkyu.tistory.com/460#entry460comment</comments>
      <pubDate>Tue, 20 Jan 2026 10:00:53 +0900</pubDate>
    </item>
    <item>
      <title>[Java] synchronized의 한계를 극복하기 위한 Lock 인터페이스와 ReentrantLock 클래스</title>
      <link>https://mangkyu.tistory.com/459</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt;1. synchronized의 한계를 극복하기 위한 Lock 인터페이스와 ReentrantLock 클래스&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mangkyu.tistory.com/458&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스팅&lt;/a&gt;에서 설명하였듯, synchronized 키워드를 활용한 동시성 제어는 다음의 2가지 치명적인 문제가 있었다.&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이런 문제를 해결하기 위해 자바 1.5부터 java.util.concurrent 라는 동시성 문제 해결을 위한 라이브러리 패키지가 추가되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 무한 대기 문제를 해결하기 위한 LockSupport 클래스 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 무한 대기 문제를 해결하기 위해 LockSupport 클래스가 추가되었다. LockSupport는 스레드를 블로킹/언블로킹하기 위한 가장 기본적인 도구로, 먼저 스레드를 대기 상태로 변경시킬 수 있다. 이때 스레드는 WAITING 또는 TIMED_WAITING상태가 되며, 누가 깨워주기 전까지는 계속 대기하며 CPU 실행 스케줄링에 들어가지 않는다. 스레드를 깨울 수도 있는데, 그러면 대기중인 스레드가 RUNNABLE로 바뀌며 다시 작업을 수행하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 LockSupport 클래스가 제공하는 대표적인 기능은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;park() : 스레드를 대기 상태로 두며, 이때 스레드 상태는 WAITING 상태가 된다.&lt;/li&gt;
&lt;li&gt;parkNanos(nanos) : 스레드를 특정 나노초 동안만 대기 상태로 두며, 이때 스레드 상태는 TIMED_WAITING 상태가 된다. 지정한 시간이 지나면 TIMED_WAITING 상태에서 빠져나오고 RUNNABLE 상태로 변경된다.&lt;/li&gt;
&lt;li&gt;unpark(thread) : WAITING 상태의 대상 스레드를 RUNNABLE 상태로 변경한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LockSupport를 활용하는 예제 코드는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class LockSupportMainV1 {
     public static void main(String[] args) {
          Thread thread1 = new Thread(new ParkTask(), &quot;Thread-1&quot;);
          thread1.start();

          // 잠시 대기하여 Thread-1이 park 상태에 빠질 시간을 준다. 
          sleep(100);
          log(&quot;Thread-1 state: &quot; + thread1.getState());
          log(&quot;main -&amp;gt; unpark(Thread-1)&quot;); 
          LockSupport.unpark(thread1); // 1. unpark 사용 
          //thread1.interrupt(); // 2. interrupt() 사용
     }

     static class ParkTask implements Runnable {
          @Override
          public void run() { 
               log(&quot;park 시작&quot;);
               LockSupport.park();
               log(&quot;park 종료, state: &quot; + Thread.currentThread().getState()); 
               log(&quot;인터럽트 상태: &quot; + Thread.currentThread().isInterrupted());
          } 
     }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드를 실행하면 다음과 같은 흐름을 확인할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;main 스레드가 Thread-1 을 start() 하면 Thread-1 은 RUNNABLE 상태가 됨&lt;/li&gt;
&lt;li&gt;Thread-1 은 Thread.park() 를 호출하고, RUNNABLE 상태에서 WAITING 상태가 되면서 대기함&lt;/li&gt;
&lt;li&gt;main 스레드가 Thread-1 을 unpark() 로 깨우고, `Thread-1 은 RUNNABLE 상태로 변함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 LockSupport 는 특정 스레드를 WAITING 또는 TIMED_WAITING 상태와 RUNNABLE 상태로 변경시킬 수 있다. 참고로 여기서 대기중인 스레드에 인터럽트가 발생하면 WAITING 또는 TIMED_WAITING 상태에서 RUNNABLE 상태로 변하면서 깨어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Lock 인터페이스와 ReentrantLock 클래스의 사용법 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Lock 인터페이스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lock 인터페이스와 ReentrantLock 클래스는 더 강력하고 유연한 동시성 제어를 위해 등장한 도구들이다. Lock 인터페이스는 synchronized 키워드를 통한 암묵적인 락과 다르게 명시적인 락 획득과 해제를 지원한다. 조건 없는 락, 폴링 락, 타임아웃이 있는 락, 락 확보 대기 상태에 인터럽트를 걸 수 있는 방법 등이 포함돼 있으며, 락을 확보하고 해제하는 모든 작업이 명시적이다. 즉, Lock 인터페이스는 동시성 프로그래밍에서 쓰이는 안전한 임계 영역을 위해 락을 추상화한 인터페이스이다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;package java.util.concurrent.locks;

 public interface Lock {
     void lock();
     void lockInterruptibly() throws InterruptedException;
     boolean tryLock();
     boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
     void unlock();
     Condition newCondition();
}
&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ReentrantLock 클래스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lock 인터페이스는 대표적으로 다음의 2가지 구현을 제공한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ReentrantLock: 이는 기존 자바 동기화 블록에서 사용되는 잠금과 거의 동일하지만 더 유연하다.&lt;/li&gt;
&lt;li&gt;ReentrantReadWriteLock: 많은 Reader와 적은 Writer가 있는 경우 성능을 개선할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReentrantLock은 읽기와 쓰기 작업의 구분이 없기 때문에, 여러 동시 읽기 요청이 와도 하나의 작업만 처리 가능하다. 이러한 문제를 극복하기 위해 읽기 작업은 여러 요청을 허용하지만 쓰기 작업은 하나만 허용하도록 고도화하여 성능 향상을 꾀한 것이 바로 ReentrantReadWriteLock 이다. 참고로 ReentrantLock은 재진입 락이라는 의미인데, 이는 synchronized 키워드와 마찬가지로 동일한 스레드가 이미 획득한 락을 다시 획득할 수 있음을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReentrantLock는 구현을 통해 다음과 같은 기능을 제공하며, 내부적으로 스레드의 대기와 깨우기를 위해 LockSupport가 사용된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;void lock()
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;락을 획득한다. 만약 다른 스레드가 이미 락을 획득했다면, 락이 풀릴 때까지 현재 스레드는 대기(WAITING)한다. 이 메서드는 인터럽트에 응답하지 않는다.&lt;/li&gt;
&lt;li&gt;여기서 사용하는 락은 객체 내부의 모니터 락이 아니고, Lock 인터페이스와 ReentrantLock 이 제공하는 기능이다. 모니터 락과 BLOCKED 상태는 synchronized 에서만 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;void lockInterruptibly()
&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;만약 다른 스레드가 이미 락을 획득했다면 현재 스레드는 락을 획득할 때까지 대기하고, 대기 중에 인터럽트가 발생하면 InterruptedException이 발생하며 락 획득을 포기한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;boolean tryLock()
&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;락 획득에 성공하면 true를 반환하고, 다른 스레드에 의해 락을 선점당해 락 획득에 실패했다면 false를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;boolean tryLock(long time, TimeUnit unit)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주어진 시간 동안 락 획득을 시도하는데, 락을 획득하면 true를 반환하고 실패하면 false 를 반환한다.&lt;/li&gt;
&lt;li&gt;이 메서드는 대기 중 인터럽트가 발생하면 InterruptedException 이 발생하며 락 획득을 포기한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;void unlock()
&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;락을 획득한 스레드가 호출해야 하며, 그렇지 않으면 IllegalMonitorStateException 이 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Condition newCondition()
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Condition 객체를 생성하여 반환한다.&lt;/li&gt;
&lt;li&gt;Condition 객체는 락과 결합되어 사용되며, 스레드가 특정 조건을 기다리거나 신호를 받을 수 있도록 한다. 이는 Object 클래스의 wait , notify , notifyAll 메서드와 유사한 역할을 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 대기(WAITING) 상태의 스레드에 인터럽트가 발생하면 대기 상태를 빠져 나오는 것이 맞다. lock() 메서드를 사용하면, WAITING 상태가 되므로 인터럽트에 반응하여 아주 짧은 순간 대기 상태를 빠져 나와 RUNNABLE 이 된다. 그런데 lock() 메서드 안에서 해당 스레드를 다시 WAITING 상태로 강제로 변경하여 인터럽트를 무시한다. 대신 인터럽트가 필요하면 사용할 수 있는 lockInterruptibly() 를 제공하여, 개발자에게 보다 유연하고 다양한 선택권을 주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명시적인 락을 사용할 때 주의할 점은 반드시 finally 블록에서 락을 해제해야 한다는 것이다. 락을 finally 블록에서 해제하지 않으면 try 구문 내부에서 예외가 발생했을 때 락이 해제되지 않는 경우가 발생한다. 따라서 이러한 부분을 놓치게 되면 시스템에 심각한 문제를 초래할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class BankAccount {
    private int balance = 0;
    private final Lock lock = new ReentrantLock();

    public void deposit(int amount) {
        lock.lock(); // 락 획득
        try {
            balance += amount;
        } finally {
            lock.unlock(); // 반드시 finally 블록에서 락 해제
        }
    }

    public void withdraw(int amount) {
        lock.lock(); // 락 획득
        try {
            if (balance &amp;gt;= amount) {
                balance -= amount;
            }
        } finally {
            lock.unlock(); // 반드시 finally 블록에서 락 해제
        }
    }
}

&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 무한 대기 문제가 해결되었으므로, 다음 문제인 공정성 문제를 해결할 차례이다. ReentrantLock 클래스는 스레드가 공정하게 락을 얻을 수 있는 모드를 제공한다. 기본적으로 ReentrantLock은 비공정 모드이며, 해당 값은 생성자를 통해 설정할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class ReentrantLockFairMode {

    private final Lock nonFairLock = new ReentrantLock();  // 비공정 모드 락
    private final Lock fairLock = new ReentrantLock(true); //공정 모드 락

    public void nonFairLockTest() {
        nonFairLock.lock();
        try {
            // 임계 영역 
        } finally {
            nonFairLock.unlock();
        }
    }
     
    public void fairLockTest() {
        fairLock.lock();
        try {
            // 임계 영역
        } finally {
            fairLock.unlock();
        }
    }
}
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 불공정한 ReentrantLock이라고 하더라도 일부러 순서를 뛰어넘는 것은 아니다. 락이 해제되는 정확한 타이밍에 락 획득을 시도하는 스레드가 있다면 락 획득을 허용할 뿐이다. 반대로 공정한 락을 사용하면 항상 락을 획득하려는 스레드가 항상 큐의 대기자 목록 맨 뒤에 쌓일 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 불공정 락도 대부분의 경우에는 공정성이 지켜지지만, 간혹 예외 케이스가 있을 뿐이다. 공정 모드를 사용하면 불필요하게 성능이 저하될 수 있어서, 순서가 매우 크리티컬한 케이스가 아니라면 가급적 비공정 모드의 사용을 권장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇듯 Lock 인터페이스와 ReentrantLock 구현체를 사용하면 synchronized 단점인 무한 대기 문제와 공정성 문제를 모두 해결할 수 있다. 또한 훨씬 유연한 기능을 제공하여 오늘날 많이 사용되고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Condition 인터페이스 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시성 프로그래밍을 개발하다 보면 특정 조건이 만족할 때까지 작업을 멈추고 대기시키고(await), 조건이 충족되면 해당 스레드들을 깨우고(signal) 작업을 진행시킬 필요가 있다. Condition 인터페이스는 Lock과 함께 스레드들을 대기시키고 깨워주는 메커니즘으로, synchronized의 wait(), notify(), notifyAll()에 상응하는 기능이라고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 기능은 특정 조건에 따라 스레드를 먼저 대기시켜야 하므로, 반드시 특정한 Lock에 종속되어 Condition 객체가 만들어져야 한다. 다음의 코드는 Condition 객체를 활용하여 계좌에서 출금을 시도할 때 잔액이 부족하면 스레드를 대기시키고, 잔액이 충전되면 모든 스레드를 깨워 처리를 진행하게 한다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class BankAccount {
    private long balance = 0;

    private final Lock lock = new ReentrantLock();
    private final Condition sufficientFunds = lock.newCondition();

    public BankAccount() {}

    public void deposit(long amount) {
        lock.lock();

        try {
            balance += amount;
            // 잔액이 늘었으니, 기다리던 출금 스레드들을 모두 깨워 진행시킴
            sufficientFunds.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void withdraw(long amount) throws InterruptedException {
        lock.lockInterruptibly();

        try {
            while (balance &amp;lt; amount) {
                // 출금할 때 잔액이 부족하면, 잔액이 충분해질 때까지 대기시킴
                sufficientFunds.await();
            }
            balance -= amount;
        } finally {
            lock.unlock();
        }
    }
}

&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Condition 객체는 Lock 하나를 대상으로 필요한 만큼 몇 개라도 만들 수 있다. Condition 객체는 자신을 생성해준 Lock 객체의 공정성을 그대로 물려받는데, 공정한 Lock에서 생성된 Condition 객체의 경우에는 Condition.await 메소드에서 리턴될 때 정확하게 FIFO 순서를 따른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Lock와 ReentrantLock의 특징 요약 및 정리 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇듯 Lock 인터페이스와 ReentrantLock 클래스는 synchronized 키워드와 코드는 조금 다르지만 기본적인 사용법은 매우 비슷하다. 하지만 대기 중 인터럽트, 페어 락(fair lock), 둘 이상의 조건 지정 등 보다 유연한 기능을 제공한다.&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;둘 이상의 조건 지정: ReentrantLock은 동시에 여러 개의 Condition 객체와 연결 지을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 성능 상의 문제로 synchronized 키워드 대신 ReentrantLock을 선택해야 한다는 얘기도 많이 있다. 하지만 JDK 6 이후 버전을 이용중이라면, synchronized도 최적화 기법들이 많이 도입되어, synchronized냐 ReentrantLock이냐를 선택할 때 성능은 더 이상 고려 대상이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 포스팅&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/458&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;동시성 제어를 위한 synchronized 키워드의 의미와 한계점&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;synchronized의 한계를 극복하기 위한 Lock 인터페이스와 ReentrantLock 클래스&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java &amp;amp; Kotlin</category>
      <author>망나니개발자</author>
      <guid isPermaLink="true">https://mangkyu.tistory.com/459</guid>
      <comments>https://mangkyu.tistory.com/459#entry459comment</comments>
      <pubDate>Tue, 13 Jan 2026 10:00:11 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 동시성 제어를 위한 synchronized 키워드의 의미와 한계점</title>
      <link>https://mangkyu.tistory.com/458</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt;1. 동시성 제어를 위한 synchronized 키워드의 의미와 한계점&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ synchronized 키워드란? ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 언어는 설계 초기부터 대량의 요청을 처리할 수 있도록 멀티 스레드를 염두하여 설계되었다. 이를 위해 자바는 1.0부터 손쉽게 동시성을 제어할 수 있는 synchronized 키워드를 제공하였다. synchronized 키워드를 사용하면 임계 영역의 동기화를 쉽게 구현할 수 있다. synchronized 키워드는 메서드 선언부에 붙여 사용하거나 특정 객체를 대상으로 동기화 블록을 만들어 사용할 수도 있다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class BankAccount {
    private int balance = 0;

    // synchronized 메서드
    public synchronized void deposit(int amount) {
        balance += amount;
    }

    // synchronized 블록
    public void withdraw(int amount) {
        synchronized (this) {
            if (balance &amp;gt;= amount) {
                balance -= amount;
            }
        }
    }
}

&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ synchronized의 동작 방식과 모니터 락 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 컴파일러(javac)가 synchronized 키워드를 컴파일하면 monitorenter와 monitorexit 라는 두 가지 바이트코드 명령어가 각각 동기화 블록 전후에 생성된다. 이때 두 명령어 모두 락으로 사용할 객체를 참조 타입 매개 변수로 받는데, 이것이 가능한 이유는 모든 객체가 내부에 자신의 락을 가지고 있기 때문이다. 이를 모니터 락(monitor lock)이라고 부르며, 객체 내부에 존재하기 때문에 우리가 확인하기는 불가능하다. 따라서 암묵적인 락(intrinsic lock)이라고도 부르며, 내부적으로는 뮤텍스로 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드가 synchronized 블록에 진입하면 해당 객체의 모니터 락을 획득하고, 블록을 벗어날 때 락을 해제하게 된다. 스레드가 객체의 모니터 락을 획득하려고 시도할 때, 이미 다른 스레드가 해당 락을 보유하고 있다면, 현재 스레드는 락이 해제될 때까지 대기 상태에 들어간다. 이때 해당 스레드의 상태는 RUNNABLE 상태에서 BLOCKED 상태로 전환되고, 락을 획득할 때까지 무한정 대기하는 것이다. 참고로 BLOCKED 상태가 되면 락을 다시 획득하기 전까지는 계속 대기하고, CPU 실행 스케줄링에 들어가지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 위의 BankAccount 객체에 대해 2개의 스레드가 동시에 withdraw를 시도하는 상황이 생겼다고 하자. 이러한 상황에서 내부적인 동작 방식을 정리하면 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;스레드 t1 은 해당 객체의 모니터 락을 획득했기 때문에 withdraw() 메서드에 진입할 수 있다.&lt;/li&gt;
&lt;li&gt;스레드 t2 도 withdraw() 메서드 호출을 시도하는데, 이를 위해 해당 객체의 락이 필요하다.&lt;/li&gt;
&lt;li&gt;스레드 t2 는 객체의 모니터 락 획득을 시도하지만 락이 없다. 따라서 t2 스레드는 락을 획득할 때 까지 BLOCKED 상태로 대기한다.&lt;/li&gt;
&lt;li&gt;t2 스레드의 상태는 RUNNABLE에서 BLOCKED 상태로 변하고,락을 획득할 때까지 무한정 대기한다.&lt;/li&gt;
&lt;li&gt;참고로 BLOCKED 상태가 되면 락을 다시 획득하기 전까지는 계속 대기하고, CPU 실행 스케줄링에 들어가지 않는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFHyOS/dJMcab3VW47/htZjMmlRUKNalp2UW1vs2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFHyOS/dJMcab3VW47/htZjMmlRUKNalp2UW1vs2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFHyOS/dJMcab3VW47/htZjMmlRUKNalp2UW1vs2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFHyOS%2FdJMcab3VW47%2FhtZjMmlRUKNalp2UW1vs2K%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;800&quot; height=&quot;437&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;559&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ synchronized의 재진입성 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;synchronized 키워드는 재진입성(reentrancy)을 지원한다. 즉, 한 스레드가 동일한 락을 다시 획득할 수 있다. 예를 들어, synchronized 메서드 내부에서 또 다른 synchronized 메서드를 호출하는 경우, 동일한 스레드가 이미 락을 보유하고 있기 때문에 추가적인 락 획득이 허용된다. 이로 인해 데드락(deadlock) 상황을 방지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바는 재진입성을 지원하기 위해 내부적으로 락 획득 횟수를 카운트하는 메커니즘을 사용한다. 스레드가 synchronized 블록에 진입할 때(monitorenter 명령어를 실행할 때) 마다 카운터가 증가하고, 블록을 벗어날 때(monitorexit 명령어를 실행할 때) 마다 카운터가 감소한다. 카운터가 0이 되면 락이 해제된다. 같은 스레드가 락을 다시 얻으면 횟수를 증가시키고, 소유한 스레드가 synchronized 블록 밖으로 나가면 횟수를 감소시킨다. 이렇게 횟수가 0이 되면 해당 락은 해제되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 다양한 synchronized의 최적화 기법들 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 스레드(플랫폼 스레드)는 기본적으로 커널 스레드로 구현되어 있다. 따라서 synchronized 키워드를 사용하여 락을 획득하거나 해제할 때마다 운영체제의 커널 모드로 전환되는 오버헤드가 발생한다. 따라서 자바는 이러한 오버헤드를 줄이기 위해 다양한 최적화 기법을 synchronized 동작 방식에 도입하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 언어 개발자들은 실제 동시성의 활용 행태를 분석한 결과, 대부분의 synchronized 블록이 짧은 시간 동안만 락을 보유하고 곧 바로 해제하여 경쟁이 심하지 않다는 것을 발견했다. 이 짧은 시간 동안 운영 체제 모드 전환이 발생하면 오버헤드가 커지므로, 자바는 멀티코어 시스템을 활용한 최적화 기법을 도입하였다. 멀티코어 시스템에서는 여러 스레드가 동시에 실행될 수 있으므로, 한 스레드가 락을 획득한 상태에서도 다른 스레드가 실행될 수 있다. 자바는 이러한 특성을 활용하여, 하나의 스레드가 대기 상태로 들어가지 않고도 락이 해제되는지 옆 코어에서 지켜보고 있도록 하였다. 이러한 방식을 스핀 락(spin lock)이라고 부른다. 스핀락은 스레드 전환 부하는 없애지만 프로세서 시간을 소비하는 부작용이 따르기 때문에 락이 잠시만 잠겨 있을 때만 효과가 좋다. 따라서 초기에는 스핀 락이 활용되다가, 다른 스레드가 오래 기다리게 될 것 같으면 그제서야 블로킹 모드로 전환된다. 즉, 다른 스레드가 진입하면 블로킹 방식으로 확장시킨다는 것이다. 이를 통해 많은 리소스를 최적화할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 JDK 6에서는 스핀 락을 최적화한 적응형 스핀(adaptive spin)이 도입되었다. &amp;lsquo;적응형&amp;rsquo;이란 말은 스핀 시간이 고정되지 않고, 그 대신 같은 락의 이전 스핀 시간과 락 소유자의 상태에 따라 결정된다는 뜻이다. 하나의 락 객체에서 스핀 락이 성공했다면 가상 머신은 다음번 스핀도 성공할 가능성이 높다고 판단한다. 그래서 기존 스핀 횟수 한계까지 락을 얻지 못하더라도 &amp;lsquo;믿고 조금 더&amp;rsquo; 시도해 본다. 반대로 스핀 락 획득에 거의 실패한다면 다음번에도 가능성이 낮을 걸로 판단하여 스핀 로직을 완전히 생략할 수 있다. 이를 통해 프로세서 자원 낭비를 방지할 수 있었다. 보다 자세한 내용은 &lt;a href=&quot;https://mangkyu.tistory.com/448&quot;&gt;해당 포스팅&lt;/a&gt;을 참고하도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외에도 스레드를 블록하라고 운영 체제에 알리기 전에 바쁜 대기(busy waiting 또는 spining) 코드를 추가하여 모드 전환이 자주 일어나지 않게끔 하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스핀 락과 적응형 스핀 그리고 JIT 컴파일을 통한 락 제거 그리고 락 범위의 확장과 경량 락까지, 이렇듯 synchronized 키워드는 다양한 최적화 기법을 통해 성능을 향상시켰고, JDK 6 이후 버전에서는 사실상 ReentrantLock과 성능 차이가 거의 없다고 알려져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ synchronized의 한계 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;synchronized 키워드는 자바에서 동기화를 구현하는 가장 기본적인 방법으로, 프로그래밍 언어에서 문법으로 제공하여 사용이 편리하다. 또한 synchronized 키워드로 인해 블록이 자동으로 지정되므로, 개발자가 명시적으로 락을 획득하고 해제하는 코드를 작성할 필요가 없어서 용이하다. 하지만 뚜렷한 몇 가지 한계점도 존재한다.&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 락의 획득 순서가 보장되지 않는다는 점이다. 만약 BankAccount 객체의 withdraw 메서드를 여러 스레드가 동시에 호출한다면, 어떤 스레드가 먼저 락을 획득할지는 예측할 수 없다. 최악의 경우 가장 먼저 도착한 스레드는 영원히 락을 획득하지 못하고 무한정 대기 상태에 빠질 수 있다. 관련 부분은 '자바 가상 머신 명세'에 정의되어 있지 않으며, 이는 공정성(fairness)이 보장되지 않는다는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더욱 치명적인 문제로는 BLOCKED 상태로 대기하는 스레드를 제어할 수 없다는 점이다. synchronized 키워드를 사용하면, 락을 획득하지 못한 스레드는 BLOCKED 상태로 대기하게 된다. 이러한 상황에서 개발자는 해당 스레드에 인터럽트를 걸어 깨우거나, 특정 시간까지만 대기하는 타임아웃을 설정하는 등의 세밀한 제어가 불가능하다. 즉, 한 번 대기 상태에 들어가면, 락을 획득할 때까지 무한정 기다릴 수밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, synchronized는 매우 편리하지만 제공하는 기능이 너무 단순한 것이다. 오늘날에는 멀티 스레드가 더 중요해지고, 점점 더 고도화된 동시성 제어가 필요해지면서 synchronized의 한계점이 부각되고 있다. 이에 따라 자바 5부터는 java.util.concurrent 패키지를 통해 Lock 인터페이스와 ReentrantLock 클래스 등 더 강력하고 유연한 동시성 제어 도구들이 제공되고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 포스팅&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;동시성 제어를 위한 synchronized 키워드의 의미와 한계점&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://mangkyu.tistory.com/459&quot;&gt;synchronized의 한계를 극복하기 위한 Lock 인터페이스와 ReentrantLock 클래스&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java &amp;amp; Kotlin</category>
      <author>망나니개발자</author>
      <guid isPermaLink="true">https://mangkyu.tistory.com/458</guid>
      <comments>https://mangkyu.tistory.com/458#entry458comment</comments>
      <pubDate>Tue, 6 Jan 2026 10:00:46 +0900</pubDate>
    </item>
    <item>
      <title>[회고] 2025 회고 및 2026년 목표 설정</title>
      <link>https://mangkyu.tistory.com/457</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2025년에는 어떤 때보다 많은 일들이 있었고, 그에 따라 인상깊었던 한 해였습니다. 어느덧 2026년을 목전에 두고 있기에, 이제 한 해를 보낼 준비를 할 때가 된 것 같습니다. 2025년을 돌이켜보며 개인적으로 느꼈던 감정들과 생각들을 정리해보고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt; 1. 2025년 회고&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 2025년의 학습과 자기개발 ]&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1월: 기본기가 탄탄한 자바 개발자 (제2판)&lt;/li&gt;
&lt;li&gt;2월: 함께자라기&lt;/li&gt;
&lt;li&gt;3월: 자바 병렬 프로그래밍&lt;/li&gt;
&lt;li&gt;4월: 모던 자바 인 액션&lt;/li&gt;
&lt;li&gt;5월: 그로쓰 해킹 &amp;amp; 개발자를 위한 레디스&lt;/li&gt;
&lt;li&gt;6월: 컴퓨터 밑바닥의 비밀 &amp;amp; 직업으로서의 소설가&lt;/li&gt;
&lt;li&gt;7월: 린 스타트업 &amp;amp; 타입으로 견고하게, 다형성으로 유연하게&lt;/li&gt;
&lt;li&gt;8월: 가상면접 1권 &amp;amp; 기획은 2형식이다&lt;/li&gt;
&lt;li&gt;9월: 최고의 프롬프트 엔지니어링 강의&lt;/li&gt;
&lt;li&gt;10월: 아이디어 불패의 법칙 &amp;amp; 객체지향 시스템 디자인 원칙&lt;/li&gt;
&lt;li&gt;11월: 랭체인과 랭그래프로 구현하는 RAG, AI 에이전트 실전 입문 &amp;amp; 일하면서 성장하고 있습니다&lt;/li&gt;
&lt;li&gt;12월: 애플은 단순하게 일합니다 &amp;amp; 팩트풀니스&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2025년은 &lt;a href=&quot;https://mangkyu.tistory.com/408&quot;&gt;작년 회고&lt;/a&gt;에서 목표했던대로 기초를 탄탄히 하기 위한 학습들을 많이 진행했다. 자바 관련 서적 뿐만 아니라 컴퓨터의 기반 그리고 JVM 까지, 점점 더 낮은 수준의 책들을 보았던 것 같다. 그 외에도 인공지능이 제한적이지만 가시적으로 좋은 성과를 보여줄 수 있는 수준까지 올라왔기에, 관련 서적과 강의 역시 열심히 수강하였다. 그리고 다음의 2가지 포스팅을 토스 테크 블로그에 기고하기도 했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://toss.tech/article/36777&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Flowise와&amp;nbsp;LLM을&amp;nbsp;활용한&amp;nbsp;에러&amp;nbsp;분석&amp;nbsp;자동화&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://toss.tech/article/internal-mcp-server&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;API&amp;nbsp;연동&amp;nbsp;자동화를&amp;nbsp;위한&amp;nbsp;여정:&amp;nbsp;토스는&amp;nbsp;왜&amp;nbsp;사내&amp;nbsp;MCP&amp;nbsp;서버를&amp;nbsp;개발하였는가?&amp;nbsp;with&amp;nbsp;Spring-AI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CNbUL/dJMcagKU9dQ/rfchDnBfI2mkYED5tkfbP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CNbUL/dJMcagKU9dQ/rfchDnBfI2mkYED5tkfbP1/img.png&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;555&quot; data-is-animation=&quot;false&quot; width=&quot;400&quot; height=&quot;306&quot; style=&quot;width: 52.4089%; margin-right: 10px;&quot; data-widthpercent=&quot;53.03&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CNbUL/dJMcagKU9dQ/rfchDnBfI2mkYED5tkfbP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCNbUL%2FdJMcagKU9dQ%2FrfchDnBfI2mkYED5tkfbP1%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;726&quot; height=&quot;555&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1X2rz/dJMcaiu9jG3/vRiaWU8eZfLxl4WGyf0wZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1X2rz/dJMcaiu9jG3/vRiaWU8eZfLxl4WGyf0wZ0/img.png&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;617&quot; data-is-animation=&quot;false&quot; width=&quot;400&quot; style=&quot;width: 46.4283%;&quot; data-widthpercent=&quot;46.97&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1X2rz/dJMcaiu9jG3/vRiaWU8eZfLxl4WGyf0wZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1X2rz%2FdJMcaiu9jG3%2FvRiaWU8eZfLxl4WGyf0wZ0%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;715&quot; height=&quot;617&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외에도 비개발 역시 틈틈히 읽었고, 그 중에서도 제품 기획 관련된 부분을 많이 보았다. 학습한 내용을 바탕으로 &lt;a href=&quot;https://mangkyu.tistory.com/440&quot;&gt;개발자를 위한 제품 그로스 및 프로덕트 데이터 관련 지식 총정리&lt;/a&gt; 라는 글로 정리하기도 했다. 그 이유로는 겪었던 문제를 극복하기 위함이였는데, 자세한 이야기는 아래에서 살펴보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 템플릿 프로젝트 및 샘플 코드 작성하기 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 사람들이 초기에 프로젝트를 세팅하는 과정에서 필요한 핵심 설정들을 모르거나 놓치곤 한다. 이를 위해 작년에 템플릿 프로젝트를 만들어 제공하는 것을 목표로 했고, 그 결과로 다음의 2가지 프로젝트를 만들어두었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/MangKyu/java-spring-boot-template&quot;&gt;https://github.com/MangKyu/java-spring-boot-template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/MangKyu/kotlin-spring-boot-template&quot;&gt;https://github.com/MangKyu/kotlin-spring-boot-template&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열심히 만들어 보다보니, &amp;ldquo;왜 이 설정값은 이렇게 되었는가?&amp;rdquo; 하는 의문점을 보는 사람이 갖게 될 것 같았고, 그것을 아는 것이 중요하다고 생각했다. 그래서 이를 위한 여러 포스팅들을 작성하게 되었고, 이러한 글들이 사각지대에 놓인 개발자들에게 하나의 좋은 레퍼런스가 되었으면 좋겠다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/453&quot;&gt;운영 환경을 위한 실용적인 로그 레벨(Practical Log Level)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/426&quot;&gt;하이버네이트 ddl-auto 옵션과 ddl-auto=validate 옵션의 동작 과정 분석하기(Hibernate ddl-auto=validate option)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/432&quot;&gt;올바른 카프카 컨슈머(KafkaConsumer) 설정 가이드와 내부 동작 분석&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/429&quot;&gt;Logback AsyncAppender의 동작 방식과 neverBlock 설정의 필요성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/425&quot;&gt;@Async를 활용한 비동기 처리를 위한 올바른 설정 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/424&quot;&gt;스프링 부트 톰캣 애플리케이션의 Graceful Shutdown 동작 방식(Spring Boot Tomcat Graceful Shutdown)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/423&quot;&gt;올바른 스프링 부트 톰캣 애플리케이션 설정 가이드(SpringBoot Tomcat Configuration)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/422&quot;&gt;멀티 스레드 기반으로 다중 요청을 처리하는 톰캣(Tomcat)의 구조와 동작 방식&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/413&quot;&gt;데이터베이스 커넥션 풀 및 JPA, 하이버네이트 설정 최적화(Database Connection Pool and JPA, Hibernate properties optimization)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/412&quot;&gt;올바른 자바/코틀린(Java/Kotlin) 애플리케이션 JVM 메모리 설정 가이드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 유산소 운동하기 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작년에 대상포진에 걸리면서 기초 체력 향상을 위해 유산소 운동의 필요성에 대해 재고했고, 진행하겠다는 다짐을 했었다. 그 결과로 현재는 화목토 헬스장에 가는 날이면 20분 정도는 유산소에 시간을 쏟고 있다. 하지만 보다 많은 시간을 확보할 필요가 있다고 느껴서 그 시간을 점점 더 늘려가야 할 것 같다. 그래도 일단은 시작했고, 지속하고 있음에 충분히 원하는 바를 이루는 중이라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같이 입사했던 동기도 2025년에 대상포진에 걸렸다고 한다. 둘 다 나름대로 헬스장을 꾸준히 가는 사람들인데, 나 말고 저 친구도 걸렸다니 신기했다. 자기개발도 열심히 하는 친구인데, 같이 건강도 잘 챙겨서 꾸준한 발전을 같이 이뤘으면 좋겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 실패한 어학 공부의 루틴 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 초까지는 미성년자들이 토스를 적극적으로 활용할 수 있도록 하는 팀에 속해 있었고, 지금은 한국에 머무르는 외국인들을 대상으로 하는 팀에 속해 있다. 아무래도 언어 관련 능력이 요구될 것으로 생각되어, 이를 위해 어학 공부(링글)를 큰 마음 먹고 시작하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;튜터의 성향이나 전공 등을 바탕으로 한 선생님을 선점했고, 처음 수업 이후에 만족도가 높아 지속적으로 진행할 계획을 세웠다. 매 주 일요일 저녁에 정기적으로 4~5회 쯤 진행하던 찰나에 해당 선생님의 수업 시간이 추가로 열리지 않았다. 이후에 다른 선생님을 찾아서 진행하게 되었는데, 이 역시도 고정된 시간을 잡기가 쉽지 않았다. 타지에 있는 고정된 사람과 고정된 시간을 맞춘다는 게 쉽지 않은 일이였다.&lt;/p&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Life is Beautiful ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/J3lyOFVnRm8?si=tZwglSF8uD2UQZNX&amp;amp;t=404&quot;&gt;유퀴즈&lt;/a&gt;에서 우연히 프랑스에서 한국으로 놀러온 학생을 붙잡고, 인터뷰를 진행한다. &quot;고민이 있다면...??&quot; 그러나 그는 고개를 절레절레 흔들며 대답한다, &quot;Life is Beautiful.&quot; 그리고 대답하기를, 삶은 아름답기에 본인은 행복하다고. 왜냐하면 자기도, 자기 가족도, 친구들도 잘 지내고, 좋은 사람을 만나고, 여행을 다니고, 공부하고, 졸업하고, 일하고... 스트레스가 전혀 없다는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2012&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bitrvM/dJMcaihE6Oy/VUccdZZvP7YnSoQxGarJ61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bitrvM/dJMcaihE6Oy/VUccdZZvP7YnSoQxGarJ61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bitrvM/dJMcaihE6Oy/VUccdZZvP7YnSoQxGarJ61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbitrvM%2FdJMcaihE6Oy%2FVUccdZZvP7YnSoQxGarJ61%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;860&quot; height=&quot;438&quot; data-origin-width=&quot;2012&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이 사람이 겪는 갈등과 고민 등이 전혀 없지는 않을 것이다. 하지만 이 사람은 분명 건강한 정신 모델을 바탕으로 본인의 상황을 긍정적으로 해석할 것이라고, 나는 생각한다. 결정이 느릴 때 우리는 &amp;ldquo;답답하다&amp;rdquo;고 얘기할 수도 있지만, &amp;ldquo;신중하다&amp;rdquo;라고도 표현할 수 있다. 마찬가지로 즉흥적이라는 것은 계획이 없는 것으로도 볼 수 있지만, 그 찰나의 순간에서 최선의 선택을 내리는 것으로도 이해할 수 있다.&lt;/p&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 솔직한 순간에 대한 이야기 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자기객관화가 잘 되는 내가, 스스로를 평가해보자면 나는 꽤나 급한 편이다. 답답한 것을 좋아하지 않고, 빠르게 해결하는 것을 좋아한다. 그러다보니 무언가 미완료된 상태로 남는 것이 있다면, 머리속에서 계속 맴돌고 생각이 난다. 이러한 내가 더 좋은 사람이 되는 데 중요한 것이 무엇일까? 하면 인내심이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느날 접한 &lt;a href=&quot;https://www.youtube.com/shorts/azSe5qaEA-E&quot;&gt;유튜브 영상&lt;/a&gt; 중 하나는 다음의 부분을 시사한다, &amp;ldquo;그 순간에 솔직해질 필요는 없다&amp;rdquo;라고.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;751&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bel6fT/dJMcaihE6O4/3tJ5fWPtN09M6q4oOfaZS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bel6fT/dJMcaihE6O4/3tJ5fWPtN09M6q4oOfaZS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bel6fT/dJMcaihE6O4/3tJ5fWPtN09M6q4oOfaZS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbel6fT%2FdJMcaihE6O4%2F3tJ5fWPtN09M6q4oOfaZS1%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;1264&quot; height=&quot;751&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;751&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;친구가 무대에 서서 공연을 했는데, 관람객의 입장에서 공연이 성공적이지는 못했고 개선할 여지가 많았다고 하자. 이러한 상황에서 공연을 막 끝내고 아드레날린과 벅찬 가슴으로 공연이 어땠냐고 물어보는 친구에게, 공연에 대한 피드백을 조목조목 남긴다면 그 친구가 피드백을 받아들일 수 있을까? 이 영상은 그렇지 못하다고 얘기한다. 지금은 감정으로 벅찬 친구에게 고생했다는 격려와 칭찬의 박수를 주어야 하는 순간이고, 피드백은 이성이 돌아온 후에 전해야 한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 진정성 있는 이야기는 그 사람이 소중하고, 그 사람이 잘 되었으면 하는 마음에서 나와야 한다. 그렇기에 그 사람을 위한 이야기를 할 때에도, 그 사람이 받아들일 수 있는 상황일 때 이야기 하는 것이 합리적이다. 아무리 좋은 조언이라도 타이밍이 적절하지 못하다면 잔소리 내지는 기분 나쁜 말 밖에 되지 못할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 이 역시 결국 타이밍 그리고 인내심이라고 해석하며 영상의 이야기에 공감을 했고, 하고 싶은 얘기를 미루어보면서 많은 이점을 누렸음을 느꼈&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;다. 상대방의 기분 나쁜 언행에 대해 먼저 사과를 받았다던가, 원하지 않는 무언가가 취소되었다던가 직설적으로 혹은 감정적으로 무언가를 대할 때보다 훨씬 건강했다. 누구나 감정적으로 대하고 싶은 순간이 올테지만, 현명한 대처법을 기억하면서 최적의 타이밍을 조절해보면 어떨까 싶다. 그리고 나 역시도 지금처럼 감정을 조절할 수 있는 능력을 지속적으로 길러야 할 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 후쿠오카 카루비테이 ]&lt;/b&gt;&lt;/h3&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;최상급 일본식 야키니쿠 역시 한 몫을 했지만 함께 했던 친구들 그리고 국경을 넘어선 가게 어르신들과의 추억까지 더할나위 없었다. 나오는 음식들에 대한 친절한 설명부터 서로에 대한 관심과 존중이 있는 대화 그리고 국경을 넘어선 소통과 이를 위한 노력까지 모든 것들이 아름다웠다. 함께 구글 번역기를 돌려가며 대화하고, 잘못된 번역으로 웃고, 서로에 대해 알아가며, 사진으로 추억을 남겼던 순간을 잊지 못할 것 같다.&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 href=&quot;https://mangkyu.tistory.com/408&quot;&gt;작년 회고&lt;/a&gt;에서 &amp;ldquo;도움을 주는 것은 밑지는 일이 없다&amp;rdquo; 는 얘기를 했는데, 다른 사람에게 친절한 것 역시 비슷하지 않나 생각해본다. 나의 친절함이 누군가에게는 큰 도움이, 그리고 한 해의 가장 행복한 순간이 될 수 있음을 생각하며, 이러한 태도를 잃지 말아야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 객관성의 주관성 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;흑백요리사 1&amp;rdquo; 프로그램에서 개인적으로 가장 흥미로웠던 포인트 중 하나는, 나폴리맛피아라는 참가자가 음식에 식용꽃을 활용하여 안성재 심사위원으로부터 보류를 받은 부분이었다. 안성재 셰프가 자기 두부요리에는 금박을 올려서 약간의 얘기도 나왔었는데, 이후에 둘은 &lt;a href=&quot;https://youtu.be/w4A3BqBTO9A?feature=shared&amp;amp;t=933&quot;&gt;유튜브&lt;/a&gt;에서 만나 이에 대한 얘기를 나누었다. 식용꽃에 대해 애기했던 것은 &amp;ldquo;그 때, 그 디시에, 그 순간에 느낀 감정&amp;rdquo;이라고 말이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvDRfd/dJMcaiIGSiO/HCQ3rL2ftNu06TsWLQKrH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvDRfd/dJMcaiIGSiO/HCQ3rL2ftNu06TsWLQKrH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvDRfd/dJMcaiIGSiO/HCQ3rL2ftNu06TsWLQKrH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdvDRfd%2FdJMcaiIGSiO%2FHCQ3rL2ftNu06TsWLQKrH1%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;2048&quot; height=&quot;1179&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1179&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 영상을 보면서 함께 자라기라는 책에 있던 &amp;ldquo;객관성의 주관성&amp;rdquo;이라는 챕터가 생각났다. 무언가를 결정하는 것은 결국 사람이기 때문에, 그 사람이 마음에 드냐 안 드냐가 중요하다는 것이다. 그러다 보니 객관성의 개념 자체가 사실은 매우 주관적이며, &amp;ldquo;누구&amp;rdquo;의 객관인가가 중요하다는 것이다. 결국 인간은 감정의 동물이기 때문에 의사결정을 하는 과정에 감정적이고 직관적인 부분이 큰 역할을 하고 있으며, 그런 감정적 부분이 배제된다면 의사결정을 제대로 할 수 없다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요리라는 분야에서 세계 최고 중 한 명 역시 이러한데, 하물며 나 스스로야 오죽하겠냐는 생각이 들었다. 오늘은 &amp;ldquo;느리다&amp;rdquo;라고 느껴졌던 부분이 내일은 &amp;ldquo;신중하다&amp;rdquo;라고 느껴질 수 있는 것처럼, 무언가를 평가함에 있어 순간의 감정보다는 텀을 두고 약간의 신중함을 더하는 것이 필요함을 다시금 상기했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 성공한 경험 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 초에 팀에서 &amp;ldquo;꽃돼지 키우기&amp;rdquo;라는 바이럴 이벤트를 진행했다. 이벤트 시작일에만 500만 이상의 참여자를 기록했고, 토스 이벤트 중에서 SOTA(States Of The Arts)로 꼽힐 만큼 모든 비즈니스 지표가 최고 수준을 보였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I5bbS/dJMcaaYeMyv/22KNQbk1LMSSCXFmezHxz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I5bbS/dJMcaaYeMyv/22KNQbk1LMSSCXFmezHxz1/img.png&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;1523&quot; data-is-animation=&quot;false&quot; width=&quot;400&quot; height=&quot;806&quot; style=&quot;width: 51.231%; margin-right: 10px;&quot; data-widthpercent=&quot;51.83&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I5bbS/dJMcaaYeMyv/22KNQbk1LMSSCXFmezHxz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI5bbS%2FdJMcaaYeMyv%2F22KNQbk1LMSSCXFmezHxz1%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;756&quot; height=&quot;1523&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R8K2K/dJMcaaYeMyD/AhpGILVUKjGmlvpLyh66e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R8K2K/dJMcaaYeMyD/AhpGILVUKjGmlvpLyh66e0/img.png&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2556&quot; data-is-animation=&quot;false&quot; width=&quot;400&quot; height=&quot;867&quot; style=&quot;width: 47.6062%;&quot; data-widthpercent=&quot;48.17&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R8K2K/dJMcaaYeMyD/AhpGILVUKjGmlvpLyh66e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR8K2K%2FdJMcaaYeMyD%2FAhpGILVUKjGmlvpLyh66e0%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;1179&quot; height=&quot;2556&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 해당 이벤트는 &amp;ldquo;세배하고 세뱃돈 받기&amp;rdquo;라는 이벤트의 후속작이였는데, 해당 이벤트는 많은 참여자로 인한 부하로 유발된 버그와 함께 2시간 만에 종료됐었다. 하지만 비즈니스 지표가 워낙 좋았기에 비슷하게 재시도를 했고, 그렇게 진행된 것이 &amp;ldquo;꽃돼지 키우기&amp;rdquo; 였다. 서버 문제로 인해 서비스가 실패했던 부분에 대해 큰 책임감을 느끼며 대대적인 보완 공사를 진행했고, 그 덕택에 &amp;ldquo;꽃돼지 키우기&amp;rdquo; 서비스를 성공적으로 마무리할 수 있었다. 비록 꽃돼지 유입으로 인해 타 서비스로의 진입이 많아지면서, 다른 서비스에 문제들이 생겼지만 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 이벤트의 실패를 복기했을 때 가장 큰 문제점으로 &amp;ldquo;비즈니스에 친화적이지 못함&amp;rdquo;을 뽑았다. 비즈니스에 친화적이었다면 이벤트의 사전 신청 참여자 수를 알았을 것이고, 부하가 예상되니 그에 맞는 대비를 했을 테니 말이다. 이러한 부분은 스스로도 문제라고 인지하고 있기에, 현재 팀에서 하는 &amp;ldquo;그로스&amp;rdquo; 관련 학습을 하며 비즈니스에 친숙해지려고 노력했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI는 계속해서 빠르게 발전하고 있고, 앞으로는 더 많은 AI의 도움으로 빠르게 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;개발을&lt;span&gt; &lt;/span&gt;&lt;/span&gt;완료하는 작업 형태가 될 것이다. 따라서 점점 더 비즈니스에 친화적이게 되어야만 요구 사항을 정확하게 이해하고, 이를 AI에게 명확하게 전달하여 빠르게 구현의 도움을 받을 수 있을 것이다. 하여 아이디어 불패의 법칙, 애플은 단순하게 일합니다, 린 스타트업 등의 책들도 보고, 승건님의 프로덕트 관련 강의도 보고, 학습한 내용을 바탕으로 &amp;ldquo;개발자를 위한 제품 그로스 및 프로덕트 데이터 관련 지식 총정리 &lt;a href=&quot;https://mangkyu.tistory.com/440&quot;&gt;포스팅&lt;/a&gt;까지 작성하게 되었다. 이를 통해 모르는 부분을 보완했고, 나의 또 다른 밑거름이 되리라 기대한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 이벤트의 성공을 복기했을 때는, 토스의 대표 승건님이 &amp;ldquo;절대 피해야 할 것은 실패&amp;rdquo;라고 &lt;a href=&quot;https://youtu.be/q-QYmM4e-9E?feature=shared&quot;&gt;이야기했던 부분&lt;/a&gt;이 떠오르며 많이 공감했다. 사실 작년에 내가 참여했던 팀의 작업들은 (개인적으로 보기에) 모두 실패했고, 이러한 부분은 과업들을 단순 기계적 반복처럼 취급하게 만드는 데 일조하였다. 하지만 이번의 성공 경험을 통해 성공하는 제품을 만들기 위해 보다 비즈니스에 가까워지는 계기가 되었다고 생각한다. 덕분에 제품 측면에서 가슴 설레이는 순간을 경험했고, 이러한 경험은 나를 한층 더 성숙한 개발자가 되도록 일조할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt;2. 2026년 목표&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; [ 리더십 학습하기 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2026년에는 기술적으로 어떠한 것들을 위주로 학습하면 좋을까 고민해보면, 꾸준히 공부는 하겠지만 무엇이 될지는 솔직히 모르겠다. 점점 하나의 책이나 영상 등으로 얻어가는 부분은 희소해질 뿐만 아니라,&amp;nbsp;기술적 학습의 가치는 떨어지고 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 리더십과 관련된 부분을 중점적으로 학습할 계획이다. 이제는 슬슬 다른 동료들에게 길을 제시해주고, 그들의 잠재력을 끌어 올리는 역량을 키워야 할 때가 다가오는 것 같다. 그 상황이 닥치고 준비하면 늦기에, 2026년에는 올바른 리더십이 무엇인지 고민해보고, 인간의 관계에 대해 고민해볼 것이다. 학습할 대상들로는 극한의 오너십, 실리콘밸리의 팀장들 등과 관련된 부분이 되지 않을까 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; [ AI 에반젤리스트 ]&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 토스에서 CTO 이형석님의 주도 하에 AI 에반젤리스트라는 모임이 신설되었다. 에반젤리스트는 &amp;ldquo;전도사&amp;rdquo;를 의미하는데, 토스는 이전에 &amp;ldquo;컬쳐 에반젤리스트&amp;rdquo;라는 직군을 만들고 채용했었다. 토스의 코어 밸류 그리고 기업 문화는 성공방정식이기에 토스의 문화를 전파시킬 사람이 필요했던 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cucDo3/dJMcaa4ZDAL/42pzEVaFNmM2EecZCyKW11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cucDo3/dJMcaa4ZDAL/42pzEVaFNmM2EecZCyKW11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cucDo3/dJMcaa4ZDAL/42pzEVaFNmM2EecZCyKW11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcucDo3%2FdJMcaa4ZDAL%2F42pzEVaFNmM2EecZCyKW11%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;650&quot; height=&quot;338&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 만들어진 AI 에반젤리스트 역시 AI가 매우 중요하기에, 기술적 관점에서 AI 활용을 리서치하고 PoC하고 사내 개발자들이 AI의 활용을 극대화할 수 있도록 돕는 역할을 기대하고 있다. 이를 위해 나는 사내의 MCP 서버를 구축하여 다양한 직군의 개발자들이 AI를 극대화할 수 있게 하고, AI 관련 소식을 전달하는 등의 역할을 했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 이 역할을 맡게 되었을 때, 크게 2가지 생각이 떠올랐다. 먼저 나는 이러한 부분을 사내의 개인 프로젝트로 진행하고 있었고, 전사의 모든 개발자들이 쓸 수 있는 AI 도구로 발전시킬 계획이 있었는데, 타이밍 좋게 회사의 공식적인 활동으로 이어지게 된 것이다. 그래서 스스로 강점을 많이 발휘할 수 있다고 생각이 들었고, 의지력이 충만해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음으로는 아무런 대가나 보상 없이 진행해오던 활동들이 알게 모르게 쌓여 가며 하나의 결실이 되었다는 것이다. AI 에반젤리스트는 각 챕터(직군)의 헤드(대표)가 임의로 선정을 하는 식으로 진행되었는데, 감사하게도 나를 바로 떠올리시고 적임자로 뽑으셨다고 한다. 나는 그 동안 서버 개발자 외에도 다른 직군의 개발자나 디자이너, 기획자 등 직군을 가리지 않고 그들이 느끼는 수작업이나 반복 작업을 AI를 활용해 자동화해왔다. 뿐만 아니라, 매일 새로운 기술 관련 내용을 특정 채널에 공유하거나 발표하는 등의 활동을 이어왔다. 아무런 보상 없이 해왔던 활동이지만, 이 둘이 결국 나의 AI 에반젤리스트 활동을 만들어주었다고 생각한다. 솔직히 이러한 활동을 헤드가 알기 어려울 것이라고 생각했는데, 선정된 것을 보면 미세하게나마 전달이 되지 않았나 싶다. 앞으로도 이러한 상황이 많겠지만, 내가 생각하기에 중요한 일 그리고 해야하는 일을 꾸준히 해야 할 필요가 있다고 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스스로의 강점 중 하나로 메타인지가 높은 부분을 꼽는다. 다른 직군의 사람들이 스스로도 느낄 수 없는, 익숙해져버린 불편함을 많이 발견하고 개선하며 AI 에반질리스트로서 나만의 역량을 증명해보이고 싶다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 인연 그리고 기부 멘토링 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 신재동님께서 운영하시는 &lt;a href=&quot;https://www.notion.so/124b88836faf80ee9760e29058b759ab?pvs=21&quot;&gt;기부멘토링&lt;/a&gt; 활동에 멘토로 합류하게 되었다. 그리고 놀랍게도 가장 빠르게 멘토링을 신청했던 사람들은 모두 올해 맺었던 인연들이었다. (당장은 쉬고있지만 내년 중에 다시 재개할 예정인데, 멘토링 참여를 원하시면 &lt;a href=&quot;https://mangkyu.tistory.com/436&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;여기&lt;/span&gt;&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;728&quot; data-origin-height=&quot;507&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6saLU/dJMcadtPTuk/WVAKZOzqHPE9YZ3zRjx9y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6saLU/dJMcadtPTuk/WVAKZOzqHPE9YZ3zRjx9y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6saLU/dJMcadtPTuk/WVAKZOzqHPE9YZ3zRjx9y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6saLU%2FdJMcadtPTuk%2FWVAKZOzqHPE9YZ3zRjx9y0%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;728&quot; height=&quot;507&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;507&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 분은 토스 코어의 면접 준비를 앞두고 계셨을 때, 내가 준비했던 자료 정리와 준비에 대한 피드백을 드렸던 분이였고, 또 다른 한 분은 어떤 모임에서 얘기를 나누면서 알게되었던 분이다. 감사하게도 내가 선의의 활동에 참여한다는 소식을 접하시고, &amp;lsquo;Pay It Forward &amp;ndash; 받은 만큼 남에게 돌려주기&amp;rsquo; 형태로 선한 영향력을 행사해주셨다. 매번 느꼈지만, 도움을 먼저 건넨 것은 나일 수 있어도, 결국 나 역시도 이를 분명히 돌려받고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 초에 가장 흥미로웠던 서적 중 하나는 &amp;lsquo;&lt;a href=&quot;https://mangkyu.tistory.com/447&quot;&gt;게임 이론&lt;/a&gt;&amp;rsquo; 관련 부분이었다. 끝이 없는 협력과 배반의 현실에서, 협력을 지속적으로 이어온다면 그 가치를 극대화할 수 있다는 것이다. 내가 이어온 멘토링은 이러한 부분을 충분히 증명했던 것 같고, 삶의 태도를 건강하게 유지시켜 주는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, 자바 언어의 창시자이자 천재 개발자인 제임스 고슬링(James Gosling)은 올해 &lt;a href=&quot;https://news.hada.io/topic?id=20964&quot;&gt;자바 30주년 인터뷰&lt;/a&gt;에서 함께 식사하고 싶은 사람과 일하고 싶다고 말해왔다. 사람 중심의 협업 기준을 중시하며 일해온 것이다. 나 역시도 그러한 사람들 중 한 명이 되고, 앞으로도 그러한 사람들과 일할 수 있는 기회를 계속해서 누리고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; [ 영어 리스닝 루틴화하기 ] &lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2025의 목표였던 어학 능력 기르기는 실패했고, 개인적으로 느끼기에 듣고 말하는 부분을 한 번에 학습한다는 것이 꽤나 난이도가 있었다. 단어를 모르니 듣기도 어려운데, 귀도 좋지 못한 편이라 그 어려움이 가중되고, 그 와중에 말까지 하려니 많이 버벅이곤 했었다.&lt;/p&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmFsp4/dJMcadUT5MF/FgUnPVWBnrtHY7yc3mzxtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmFsp4/dJMcadUT5MF/FgUnPVWBnrtHY7yc3mzxtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmFsp4/dJMcadUT5MF/FgUnPVWBnrtHY7yc3mzxtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmFsp4%2FdJMcadUT5MF%2FFgUnPVWBnrtHY7yc3mzxtK%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;400&quot; height=&quot;489&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무언가에 실패한 후에 복기를 했을 때면, 보완점이 상당히 많아 나왔고 이는 성공 혹은 성장의 밑거름이 되었다. 하지만 흥미로운 점은 성공 후에 복기를 했을 때에도 마찬가지로 보완점이 상당히 많이 나왔다는 것이다. 단기적으로는 성공이 목표가 될 수 있겠지만, 장기적으로 우리는 더 나은 개발자 혹은 사람이 되는 것이 목표일 것이다. 따라서 성공/실패와 무관하게 복기(회고)를 진행하고, 부족한 부분에 대한 피드백을 반드시 얻어갈 수 있도록 하면 좋을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 맥락에서 회고 역시 마찬가지다. 그 상황에 대한 생각과 감정이 뚜렷한 그 시간에 진행할 때 스스로의 문제점 진단과 개선점을 보다 선명히 떠올릴 수 있다. 그런 의미에서 나도 스스로 회고하는 시간을 수시로 가져가고 있고, 이 글 역시도 1년에 걸쳐 지속적으로 작성되고 다듬어지며 완성되었다. 연간 회고도 좋지만, 회고의 목적을 상기해보며, 지속적인 일상의 루틴 속 회고를 자리잡아 보면 어떨까 싶다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>끄적끄적</category>
      <author>망나니개발자</author>
      <guid isPermaLink="true">https://mangkyu.tistory.com/457</guid>
      <comments>https://mangkyu.tistory.com/457#entry457comment</comments>
      <pubDate>Tue, 30 Dec 2025 10:00:19 +0900</pubDate>
    </item>
    <item>
      <title>[AI] Claude Code(클로드 코드) 활용을 극대화하기 위한 최신 기술들(Skills, Slack, GitHub Actions, Chrome ETC)</title>
      <link>https://mangkyu.tistory.com/456</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f15f5f;&quot;&gt;1. Claude Code(클로드 코드) 활용을 극대화하기 위한 최신 기술들&lt;br /&gt;(Skills, Slack, GitHub Actions, Chrome ETC)&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Claude Code and Slack ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘날 슬랙과 같은 협업 메신저는 업무의 중심에 존재하는 경우가 많다. 기능 요청, 엔지니어링 논의 뿐만 아니라 버그 리포트, 장애 회고 등 엔지니어링 작업과 관련된 중요한 문맥은 Slack에 담겨 있는 경우가 다반사다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7yFRq/dJMcajgrAcM/JQKQspXDTYmldn7Q1yuMeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7yFRq/dJMcajgrAcM/JQKQspXDTYmldn7Q1yuMeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7yFRq/dJMcajgrAcM/JQKQspXDTYmldn7Q1yuMeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7yFRq%2FdJMcajgrAcM%2FJQKQspXDTYmldn7Q1yuMeK%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;400&quot; height=&quot;400&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앤트로픽은 이러한 상황에 대해 인지하고, 버그 리포트가 올라오거나 팀원이 코드 수정을 요청할 때, Slack에서 Claude를 태그하여 주변 문맥을 활용해 자동으로 Claude Code 세션을 생성할 수 있는 기능을 추가하였다. 예를 들어 슬랙에서 Claude를 멘션하여 버그 조사와 수정을 요청하고, 코드 작성과 리팩터링 및 리뷰를 맞기게 되는 것이다. 이를 위해 &lt;a href=&quot;https://claude.com/blog/claude-code-and-slack&quot;&gt;Claude Code and Slack&lt;/a&gt;이라는 글을 통해 Slack에서 @Claude를 언급하여 일을 처리할 수 있게 하는 기능을 소개하였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXDLpg/dJMcabJxMoK/khkXy8GvDqOMmu2RKzRMz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXDLpg/dJMcabJxMoK/khkXy8GvDqOMmu2RKzRMz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXDLpg/dJMcabJxMoK/khkXy8GvDqOMmu2RKzRMz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXDLpg%2FdJMcabJxMoK%2FkhkXy8GvDqOMmu2RKzRMz0%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;600&quot; height=&quot;338&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Claude를 언급하면, Claude는 메시지를 검토해 그것이 코딩 작업인지 판단하고, 코딩 작업이라면 새로운 Claude Code 세션을 자동으로 생성한다. 그러면 해당 요청을 코딩 작업으로 처리하도록 지시할 수 있다. Claude는 Slack의 최근 채널 및 스레드 메시지에서 문맥을 수집해 Claude Code 세션에 전달하고, 이를 기반으로 웹에서 사용자가 인증한 저장소 중 어떤 곳에서 작업할지 자동으로 선택하게 되는 것이다. Claude Code 세션이 진행되는 동안 Claude는 Slack 스레드에 상태 업데이트를 게시하고, 작업이 완료되면 변경 사항을 검토할 수 있는 전체 세션 링크와 PR을 바로 열 수 있는 링크가 제공된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Claude Code GitHub Actions ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 GitHub를 통해 코드 리뷰와 빌드 등을 담당하게 된다. 따라서 앤트로픽은 AI 기반 자동화를 GitHub 워크플로우에 통합하기 위해 Claude Code GitHub Actions 기능을 출시하였다. 이는 GitHub 레포지토리에서 PR이나 이슈에 @claude를 멘션하면 Claude가 작업을 수행할 수 있도록 하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;469&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QLn11/dJMcaa4VeQA/wYvs1Cu8tbMXQWUQcgYwY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QLn11/dJMcaa4VeQA/wYvs1Cu8tbMXQWUQcgYwY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QLn11/dJMcaa4VeQA/wYvs1Cu8tbMXQWUQcgYwY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQLn11%2FdJMcaa4VeQA%2FwYvs1Cu8tbMXQWUQcgYwY1%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;839&quot; height=&quot;469&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;469&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적으로 코드베이스를 읽고 분석, PR 생성, 기능 구현, 버그 수정 등이 가능하며, 이 기능은 Claude Code SDK 위에 구축되어 있어, 단순 자동화뿐 아니라 프로그래밍 방식 커스터마이즈도 가능하다. 간단한 변경 등은 이제 다시 IDE로 돌아가서 작업할 필요 없이 간단히 Claude에게 맡기면 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code에서 /install-github-app 명령어를 이용하면, 해당 GitHub에 Claude Code 앱이 설치되고 이후에 API 키를 추가하면 자동으로 워크플로우 파일이 포함된 Pull Request가 생성된다. 해당 작업으로 .github/workflows 디렉터리에 워크플로우 파일들이 추가될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Claude in Chrome ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앤트로픽은 Claude in Chrome 브라우저 확장 프로그램을 베타 버전으로 공개하면서, Chrome 웹 브라우저에서 모든 유료 플랜(Pro, Max, Team, Enterprise) 사용자들이 Claude를 사용할 수 있게 제공하였다.&amp;nbsp;Claude는 이제 사용자들과 함께 웹사이트를 읽고, 클릭하고, 탐색할 수 있으며, 우리가 브라우징하는 동안 사이드 패널에서 직접 작동하며, 우리가 보고 있는 내용을 함께 확인하고 요청 시 행동을 수행해준다. 이를 통해 브라우저에 AI가 통합되는 경험을 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;699&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLIIDK/dJMcafFbBua/JorRjfBRkQsdppORv4RmHk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLIIDK/dJMcafFbBua/JorRjfBRkQsdppORv4RmHk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLIIDK/dJMcafFbBua/JorRjfBRkQsdppORv4RmHk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLIIDK%2FdJMcafFbBua%2FJorRjfBRkQsdppORv4RmHk%2Fimg.jpg&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;1242&quot; height=&quot;699&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;699&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code도 브라우저와 통합되는데, Chrome 확장 프로그램이 함께 작동하기 때문에, 빌드&amp;ndash;테스트&amp;ndash;검증 워크플로우를 지원한다. 이는 특히 디자인 검증(Figma 시안과 빌드 결과 비교), 실시간 디버깅, 자동화 테스트에 유용할 것이라고 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;터미널에서 Claude Code로 빌드&lt;/li&gt;
&lt;li&gt;Chrome 확장 프로그램으로 브라우저에서 테스트 및 검증&lt;/li&gt;
&lt;li&gt;콘솔 로그를 사용해 문제 디버깅(Claude가 오류, 네트워크 요청, DOM 상태를 직접 읽을 수 있음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Claude Desktop에서 역시 브라우저 작업 제어가 가능해진다. Claude Desktop에서 작업을 시작한 뒤, 창을 전환하지 않고 브라우저 작업을 Claude가 처리하도록 할 수 있다. 데스크톱 앱에서 Claude in Chrome 커넥터를 활성화하려면 다음 단계가 필요하다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;왼쪽 하단의 이니셜을 클릭한 후 &amp;ldquo;Settings&amp;rdquo; 선택&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Connectors&amp;rdquo;**로 이동&lt;/li&gt;
&lt;li&gt;목록에서 Claude in Chrome을 찾아 &amp;ldquo;Configure&amp;rdquo; 클릭&lt;/li&gt;
&lt;li&gt;커넥터를 켠 뒤, 아직 설치하지 않았다면 확장 프로그램을 다운로드 및 설치&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계를 완료하면 Claude와의 채팅 화면에 있는&amp;nbsp;Connectors&amp;nbsp;드롭다운에&amp;nbsp;Claude in Chrome이 추가된다. 이 기능은 기본적으로 비활성화되어 있어서&amp;nbsp;각 대화마다 수동으로 활성화해야 한다. 또한&amp;nbsp;Haiku 4.5, Sonnet 4.5, Opus 4.5&amp;nbsp;모델에서만 작동하며, 채팅 창에서 다른 모델을 선택하면 커넥터가 비활성화된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 통합을 위해 직접 단계를 기록해 Claude에게 워크플로우를 가르치고 Claude가 이를 학습해 반복 실행할 수 있는 워크플로우 기록(Record a workflow) 기능과 오류, 네트워크 요청, DOM 상태를 포함한 브라우저 콘솔 출력을 읽는 콘솔 로그(Console Log) 기능, 정해진 일정에 따라 자동으로 브라우저 반복 작업을 설정할 수 있는 예약 작업(Scheduled tasks) 기능,&amp;nbsp;Claude가 먼저 실행 계획을 작성해 승인을 받은 뒤, 승인된 범위 내에서 전체 워크플로우를 독립적으로 실행하는 실행 전 묻기(Ask before acting)&amp;nbsp;기능 등이 추가되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 앤트로픽은 해당 브라우저 사용 기능이 사용자를 대신해 Claude가 웹사이트와 직접 상호작용할 수 있게 하는 베타 기능이므로, 위험 요소가 존재하여 사용 전에&amp;nbsp;&lt;a href=&quot;https://support.claude.com/en/articles/12902428-using-claude-in-chrome-safely&quot;&gt;Chrome에서 Claude를 안전하게 사용하기&lt;/a&gt;&amp;nbsp;문서를 반드시 검토할 것을 권장하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Claude Skills ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Skills란 연관된 작업을 수행할 때 처리하기 위한 지침, 스크립트, 리소스가 담긴 폴더로, 이를 특정 도메인에 대한 전문 지식을 Claude에게 부여하는 전문화된 훈련 매뉴얼이다. Claude가 어떤 작업을 접하면, 사용 가능한 Skills를 스캔해 관련된 항목을 찾고, Skills 내용을 참고해서 작업을 수행하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skills는 점진적 공개(progressive disclosure) 방식을 사용한다. 이를 통해 Skills는 토큰의 사용량을 획기적으로 낮출 수 있었다고 한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;먼저 Skill이 연관된 작업이 있는지를 판단하기 위한 메타데이터가 로드됨(~100 토큰)&lt;/li&gt;
&lt;li&gt;Claude가 특정한 Skill을 적용할지 여부를 판단함&lt;/li&gt;
&lt;li&gt;Skill을 적용하고자 한다면 그때서야 전체 지침이 로드됨(&amp;lt;5,000 토큰)&lt;/li&gt;
&lt;li&gt;이후 작업을 수행하면서 번들된 파일이나 스크립트가 필요해진다면, 그때 로드됨&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skills는 Claude가 특정한 작업을 일관되고 효율적으로 수행해야 할 때 적합하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 조직 워크플로: 브랜드 가이드라인, 컴플라이언스 절차, 문서 템플릿&lt;/li&gt;
&lt;li&gt;ex) 도메인 전문성: Excel 수식, PDF 조작, 데이터 분석&lt;/li&gt;
&lt;li&gt;ex) 개인 선호 반영: 노트 정리 방식, 코딩 패턴, 연구 방법론&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프롬프트는 대화 중에 Claude에게 자연어로 제공하는 지침인데 해당 지침이 반복될 수 있다. 따라서 이러한 순간에 그리고 전문 적인 지식이 필요하다면, 프롬프트 내용을 Skills로 만들어 활용하는 것도 고려해볼법하다. 만약 Subagents를 활용하고 있다면, 각각의 Subagents들은 Skills를 활용하게 될 것이므로, 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일부 사람들이 MCP와 Skills의 차이를 헷갈려 하곤 한다. &lt;a href=&quot;https://mangkyu.tistory.com/421&quot;&gt;이전 포스팅&lt;/a&gt;에서 살펴보았듯 MCP는 LLM을 외부 시스템(IDE, GitHub, Slack 등) 에 연결하기 위한 오픈 표준으로, 데이터가 존재하는 곳에 Claude가 직접 접근할 수 있게 해준다. 그리고 MCP를 기반으로 구현한 MCP 서버는 데이터와 기능을 외부로 노출하고, MCP 클라이언트는 이 서버에 연결하여 데이터를 활용하게 된다. 즉, MCP는 데이터 접근을 가능하게 하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 Skills는 그 데이터를 어떻게 활용할지 가르친다. 따라서 MCP가 접근한 데이터들을 기반으로 작업을 수행하려고 할 때, Claude는 적용 가능한 Skills를 확인하고, 이를 기반으로 처리하여 일관된 결과를 제공할 수 있는 것이다. 따라서 MCP와 Skills는 상호보완적인 존재이므로 함께 사용해줄 필요가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) &amp;ldquo;데이터베이스에 접근해야 한다&amp;rdquo; &amp;rarr; MCP&lt;/li&gt;
&lt;li&gt;ex) &amp;ldquo;데이터베이스를 사용할 때 항상 날짜 범위로 먼저 필터링하라&amp;rdquo; &amp;rarr; Skill&lt;/li&gt;
&lt;li&gt;ex) &amp;ldquo;Excel 보고서는 이 특정 수식으로 포맷해라&amp;rdquo; &amp;rarr; Skill&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 다른 사람들이 만들어 둔 Skills를 활용할 수 있는 &lt;a href=&quot;https://skills.intellectronica.net/&quot;&gt;Skills Supermarket&lt;/a&gt;도 존재하므로 이미 작성된 Skills를 활용하는 것도 바람직하다. 또한 최근 Notion에서 사용중인 &lt;a href=&quot;https://github.com/team-attention/notion-skills-for-claude/&quot;&gt;Claude Skills 예시&lt;/a&gt;를 공개한 바가 있다. 따라서 이를 활용해서 우리가 사용할 Skills 역시 만들어보면 좋을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;582&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNBCKO/dJMcadHjjxW/iSJ94xT7KOvmuZmLZi1s2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNBCKO/dJMcadHjjxW/iSJ94xT7KOvmuZmLZi1s2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNBCKO/dJMcadHjjxW/iSJ94xT7KOvmuZmLZi1s2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNBCKO%2FdJMcadHjjxW%2FiSJ94xT7KOvmuZmLZi1s2k%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;400&quot; height=&quot;379&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;582&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;notion-meeting-intelligence: Notion에서 관련 컨텍스트를 모아 회의 자료를 준비하고, 사전 읽기 자료와 아젠다를 생성합니다.&lt;/li&gt;
&lt;li&gt;notion-research-documentation: 여러 페이지에서 얻은 결과를 종합해 구조화된 리서치 보고서로 만들어 줍니다.&lt;/li&gt;
&lt;li&gt;notion-knowledge-capture: 대화 내용을 Notion의 구조화된 문서로 변환합니다.&lt;/li&gt;
&lt;li&gt;notion-spec-to-implementation: 제품/기술 스펙을 실제 실행 가능한 Notion 작업(Task)으로 전환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ &lt;span data-token-index=&quot;0&quot;&gt;Hooks&lt;/span&gt;&amp;nbsp;]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hooks는 Claude가 tool을 실행하려고 하기 전이나 후에 명령을 실행할 수 있게 해주는 기술이다. 예를 들어 파일 수정 후 코드 포매터를 실행하거나, 파일 변경 시 테스트를 돌리거나, 특정 파일에 대한 접근을 차단하는 등 자동화된 워크플로우를 구현하는 데 매우 유용하다.&amp;nbsp;Hooks에는 두 가지 타입이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PreToolUse hooks: 도구가 호출되기 이전에 실행&lt;/li&gt;
&lt;li&gt;PostToolUse hooks: 도구가 호출된 이후에 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;702&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kAQll/dJMcajgxEk5/d00YRunIadbyfGjchVKei1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kAQll/dJMcajgxEk5/d00YRunIadbyfGjchVKei1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kAQll/dJMcajgxEk5/d00YRunIadbyfGjchVKei1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkAQll%2FdJMcajgxEk5%2Fd00YRunIadbyfGjchVKei1%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;600&quot; height=&quot;331&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;702&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 다른 것들과 마찬가지로 Hooks는 Claude 설정 파일에 정의되며, 다음 위치 중 하나에 추가할 수 있다. Hooks는 설정 파일에 직접 작성할 수도 있지만, Claude Code 내부에서 /hooks 명령을 사용해 설정할 수도 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Global: ~/.claude/settings.json (모든 프로젝트에 적용)&lt;/li&gt;
&lt;li&gt;Project: .claude/settings.json (팀과 공유)&lt;/li&gt;
&lt;li&gt;Project (커밋되지 않음): .claude/settings.local.json (개인 설정)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hooks가 활용되는 가장 대표적인 사례는 Claude가 .env 같은 민감한 파일을 읽지 못하도록 막는 것이라고 한다.&amp;nbsp;Read 도구뿐 아니라 Grep 도구도 파일 내용을 접근할 수 있으므로,&amp;nbsp;두 도구 모두를 감시하고 제한된 경로에 접근하는지 확인해야 한다.&amp;nbsp;이 방식은 Claude의 파일 시스템 접근을 완전히 통제하면서도,&amp;nbsp;특정 작업이 왜 제한되었는지에 대해 명확한 피드백을 제공할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 Hooks는 크게 다음과 같은 경우에 많이 사용된다고 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드 포매팅: Claude가 파일을 수정한 뒤 자동으로 포매터 실행&lt;/li&gt;
&lt;li&gt;테스트: 파일 변경 시 테스트 자동 실행&lt;/li&gt;
&lt;li&gt;접근 제어: 특정 파일에 대한 읽기/수정 차단&lt;/li&gt;
&lt;li&gt;코드 품질 관리: 린터나 타입 체커 실행 후 결과를 Claude에게 전달&lt;/li&gt;
&lt;li&gt;로깅: Claude가 접근하거나 수정한 파일 추적&lt;/li&gt;
&lt;li&gt;검증: 네이밍 규칙이나 코딩 컨벤션 검사&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Tool Search Tool 기능 준비중 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앤트로픽에서&amp;nbsp;&lt;a href=&quot;https://github.com/anthropics/claude-code/issues/12836#issuecomment-3629052941&quot;&gt;MCP-CLI&lt;/a&gt;라는 실험 기능을 통해 Tool Search Tool 기능을 테스트 중인데, 토큰 소비를 대폭 줄여주는 새로운 방식이다. 기존에는 MCP 서버가 모든 tool definition을 system prompt에 다 올려서 토큰을 매우 많이 사용했었고, 이로 인해 컨텍스트가 줄어들고 compaction이 자주 일어나는 등의 문제가 생겼다. 하지만 MCP-CLI를 활용하면 필요한 툴 정보만 그때그때 요청하는 on-demand 방식이 가능해진다. 대용량 JSON 같은 건 파일로 빼거나 jq로 처리 가능한 구조를 실험중이다. 이를 사용하기 위해서는 Claude Code&amp;nbsp;2.0.56&amp;nbsp;이상에서&amp;nbsp;ENABLE_EXPERIMENTAL_MCP_CLI=true&amp;nbsp;를 설정하면 사용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Anthropic, MCP를 Linux Foundation에 기증하다 ]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Linux Foundation은 Agentic AI Foundation (AAIF)를 설립했고, 에이전트형(autonomous) AI 개발을 위한 개방형, 중립적 오픈소스 거버넌스를 구축하고 산업 전체의 협력과 혁신을 촉진하고자 하였다. 그리고 재단 설립 초기에 다음의 핵심 기술/프로젝트가 기여되었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Model Context Protocol (MCP): Anthropic이 기여한 AI 모델이 외부 도구, 데이터 및 애플리케이션과 연결되는 표준 프로토콜&lt;/li&gt;
&lt;li&gt;goose: Block이 기여한 오픈소스 AI 에이전트 프레임워크로, MCP 기반 구조와 로컬 중심 실행 환경을 제공함&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://agents.md/&quot;&gt;AGENTS.md&lt;/a&gt;: OpenAI가 기여한 에이전트 코드 및 동작 지침 형식의 표준으로, 다양한 리포지토리와 도구에서 일관된 에이전트 행동을 정의할 수 있게 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 AWS, Anthropic, Block, Bloomberg, Cloudflare, Google, Microsoft, OpenAI 등 주요 AI&amp;middot;클라우드&amp;middot;인터넷 기업들이 Platinum 멤버로 참여했다고 한다. 이전에는 Open AI에서도 MCP가 아닌 자체적인 프로토콜을 구축하려고 했지만, 앤트로픽이 MCP를 Linux Foundation에 기증하면서 이러한 반복 작업을 하지 않게 되었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;관련 포스팅&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://mangkyu.tistory.com/444&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;Claude&amp;nbsp;Code(클로드&amp;nbsp;코드)&amp;nbsp;사용법과&amp;nbsp;고급&amp;nbsp;사용팁&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;https://mangkyu.tistory.com/451&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Claude Code(클로드 코드) Custom Command 활용 사례 및 예시&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;Claude&amp;nbsp;Code(클로드&amp;nbsp;코드)&amp;nbsp;활용을&amp;nbsp;극대화하기&amp;nbsp;위한&amp;nbsp;최신&amp;nbsp;기술들(Skills,&amp;nbsp;Slack,&amp;nbsp;GitHub&amp;nbsp;Actions,&amp;nbsp;Chrome&amp;nbsp;ETC)&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://claude.com/blog/claude-code-and-slack&quot;&gt;https://claude.com/blog/claude-code-and-slack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.claude.com/docs/ko/github-actions&quot;&gt;https://code.claude.com/docs/ko/github-actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://claude.com/blog/skills-explained&quot;&gt;https://claude.com/blog/skills-explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/team-attention/notion-skills-for-claude/&quot;&gt;https://github.com/team-attention/notion-skills-for-claude/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/anthropics/claude-code/issues/12836#issuecomment-3629052941&quot;&gt;https://github.com/anthropics/claude-code/issues/12836#issuecomment-3629052941&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aaif.io/press/linux-foundation-announces-the-formation-of-the-agentic-ai-foundation-aaif-anchored-by-new-project-contributions-including-model-context-protocol-mcp-goose-and-agents-md/&quot;&gt;https://aaif.io/press/linux-foundation-announces-the-formation-of-the-agentic-ai-foundation-aaif-anchored-by-new-project-contributions-including-model-context-protocol-mcp-goose-and-agents-md/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://skills.intellectronica.net/&quot;&gt;https://skills.intellectronica.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.claude.com/en/articles/12012173-getting-started-with-claude-in-chrome&quot;&gt;https://support.claude.com/en/articles/12012173-getting-started-with-claude-in-chrome&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AI</category>
      <author>망나니개발자</author>
      <guid isPermaLink="true">https://mangkyu.tistory.com/456</guid>
      <comments>https://mangkyu.tistory.com/456#entry456comment</comments>
      <pubDate>Tue, 23 Dec 2025 10:00:00 +0900</pubDate>
    </item>
  </channel>
</rss>