<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>코딩하는 겸</title>
    <link>https://mingyum119.tistory.com/</link>
    <description>  Github : https://github.com/Mingyum-Kim</description>
    <language>ko</language>
    <pubDate>Thu, 27 Aug 2026 01:57:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>MINGYUM</managingEditor>
    <image>
      <title>코딩하는 겸</title>
      <url>https://tistory1.daumcdn.net/tistory/4482312/attach/96fcc08891e14a0c8bfac71680ab2c4a</url>
      <link>https://mingyum119.tistory.com</link>
    </image>
    <item>
      <title>[2026 Q2 회고] 경험을 전문성으로 바꾸는 방법 (의식적 훈련, 첫 RFC, 그리고 첫 이직 면접)</title>
      <link>https://mingyum119.tistory.com/386</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Q3 중반에 하는 Q2 회고!&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;입사한 지 일년 차가 지나고 이제 일년 반을 앞두고 있다.&lt;br&gt;작년 3월에 독일로 이민 와 일을 시작하게 되면서 새로운 나라에서의 삶에 대한 적응과 더불어, 규칙적인 시간에 맞춰 일을 하는 근로자로서의 삶에 적응하는 일년을 보냈다. 처음에는 그저 이 환경에 무사히 적응하는 것만으로도 충분히 난이도가 높은 하루하루였다. 영어로 일하는 것도, 낯선 도메인을 이해하는 것도, 처음 보는 사람들과 협업하는 것도 하나하나가 새로운 일이었다. 더군다나 주 5일, 같은 시간에 일을 시작하고 일을 끝내는 것을 반복하는 것 자체에서 오는 매너리즘을 극복하는 것도 쉬운 일은 아니었다.&lt;br&gt;&amp;nbsp;&lt;br&gt;그렇게 &lt;i&gt;오늘 하루만 열심히 하자!&lt;/i&gt; 라고 다짐한 날들이 쌓이고 쌓여 일 년이 흘렀다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Q2의 새로운 변화와 새로운 불편함&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;Q2를 시작하게 되며 팀에 변화가 생겼다. 새로운 매니저가 생기고, 기존 매니저는 시니어 개발자의 역할로 돌아갔다. 그리고 무엇보다 큰 변화는 우리가 담당하는 프로덕트가 바뀌었다는 것이다.&lt;br&gt;&amp;nbsp;&lt;br&gt;기존 프로덕트는 다른 팀으로 이전되고, 새로운 프로덕트를 처음부터 만들어가게 되었다.&amp;nbsp;&lt;br&gt;새로운 프로덕트는 실시간으로 요청을 처리해야 하는 서비스였기 때문에 단순히 기능을 구현하는 것 외에도 신경 써야 할 부분이 많았다. 캐시와 메시지 브로커를 활용한 데이터 처리부터 모니터링, 로드 테스트, 알림과 같이 심화된 부분까지 고려해야했다.&lt;br&gt;&amp;nbsp;&lt;br&gt;자연스럽게 새롭게 공부해야하는 것들도 많아졌다. 버그 픽스 위주로 작은 티켓을 처리하던 나에게, 시스템 안정성을 고려한 설계부터 접근해야하는 큰 규모의 티켓은 도전적이고 새롭고 즐거웠다. 업무를 하면서 새로운 기술을 공부하게 되면서 성장하는 감각도 좋았다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;그러나 어느 순간, 여러 업무를 처리하면서 축적된 경험이 나의 지식 전문성으로 이어지고 있지 않다는 생각을 했다.&lt;br&gt;당장 업무를 해결하기 위해 공부했던 지식은 티켓이 끝나고 다른 업무로 넘어가면 생각보다 빠르게 휘발됐다. 당시에는 분명 이해했다고 생각했는데 몇 주 뒤 다시 마주치면 흐릿하게 기억나는 경우도 있었다.&amp;nbsp;&lt;br&gt;요구사항을 충족시키기 위한 업무가 끝나면 바로 다음 티켓으로 넘어가느라, 이전 업무에서 부족한 점은 없었는 지, 그 기술을 내가 충분히 이해했는 지 돌이켜보는 시간이 없었다.&lt;br&gt;&amp;nbsp;&lt;br&gt;그런 불편함을 느끼고 나서 일을 한다는 것과는 별개로, 그 업무 경험을 내 지식으로 만들며 성장하는 것은 별도의 과정이 필요하다는 생각이 들었다.&amp;nbsp;&lt;br&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;nbsp;&lt;br&gt;어떻게 업무를 다시 되돌아보고 지식을 내 것으로 만들 수 있을까 고민하다가 떠오른 것이&amp;nbsp;&lt;b&gt;의식적 훈련&amp;nbsp;&lt;/b&gt;이었다.&amp;nbsp;&lt;br&gt;우아한테크코스에서 왼손 코치님이 강의해주셨던 개념인데, 나의 현재 불편함을 해결하기 위한 좋은 방법인 느낌을 받았다.&amp;nbsp;&lt;br&gt;의식적 훈련은 단순히 같은 행동을 반복하는 것이 아니라, 명확한 목표를 세우고 현재 자신의 능력보다 조금 더 어려운 영역에 도전한 뒤 피드백을 통해 부족한 부분을 수정하며 실력을 향상시키는 방법이다.&lt;br&gt;&amp;nbsp;&lt;br&gt;우테코에서 개발 공부를 할 때에는 비교적 자연스럽게 이런 과정을 거쳤다. 모르는 개념을 공부하고, 코드를 작성해보고, 피드백을 받고, 부족한 부분을 다시 공부한다. 그런데 정작 회사에서 일을 시작한 뒤에는 이런 학습 과정이 많이 사라졌다는 생각이 들었다. 시간에 쫓겨, 혹은 동기부여의 부족으로 퇴근하면 일에 대한 관심을 끄기 마련이다. 더군다나 실제 업무에서는 요구사항을 구현하고, PR을 머지하고, 기능을 배포하면 일이 끝나기 때문에 ’이 업무를 통해 나는 무엇을 배웠는가?’에 대한 완료 조건은 나만의 몫이었다.&lt;br&gt;&amp;nbsp;&lt;br&gt;그래서 의식적 훈련의 구조를 업무 학습에도 적용해보기로 했다.&lt;br&gt;이를 위해 작은 &lt;b&gt;개인 프로젝트&lt;/b&gt;를 만들었다.&amp;nbsp;&lt;br&gt;&lt;a href=&quot;https://github.com/Mingyum-Kim/deliberate-practice&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://github.com/Mingyum-Kim/deliberate-practice&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;GitHub - Mingyum-Kim/deliberate-practice&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;Contribute to Mingyum-Kim/deliberate-practice development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Mingyum-Kim/deliberate-practice&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/NfH9p/dJMb8RR9jeK/EhXvKaAFnAuooXtsl1bpM1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bwhdIk/dJMb8YqcKav/Je6CBb2AiN9K58gnNIJI80/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot; data-og-url=&quot;https://github.com/Mingyum-Kim/deliberate-practice&quot;&gt;&lt;a href=&quot;https://github.com/Mingyum-Kim/deliberate-practice&quot; target=&quot;_blank&quot; data-source-url=&quot;https://github.com/Mingyum-Kim/deliberate-practice&quot;&gt;&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/NfH9p/dJMb8RR9jeK/EhXvKaAFnAuooXtsl1bpM1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bwhdIk/dJMb8YqcKav/Je6CBb2AiN9K58gnNIJI80/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600')&quot;&gt; &lt;/div&gt;&lt;div class=&quot;og-text&quot;&gt;&lt;p class=&quot;og-title&quot;&gt;GitHub - Mingyum-Kim/deliberate-practice&lt;/p&gt;&lt;p class=&quot;og-desc&quot;&gt;Contribute to Mingyum-Kim/deliberate-practice development by creating an account on GitHub.&lt;/p&gt;&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;&lt;/div&gt;&lt;/a&gt;&lt;/figure&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;업무를 하면서 얻은 배움을 기록하고, 내가 얼마나 깊게 학습했는지 일정한 기준에 따라 평가받은 뒤, 다음에는 무엇을 더 공부하면 좋을지 피드백을 받는 것이다. &amp;nbsp;혼자&amp;nbsp;회고를&amp;nbsp;작성하면&amp;nbsp;내가&amp;nbsp;이미&amp;nbsp;알고&amp;nbsp;있는&amp;nbsp;범위&amp;nbsp;안에서만&amp;nbsp;생각하게&amp;nbsp;되는데,&amp;nbsp;AI를&amp;nbsp;활용해서&amp;nbsp;옵시디언에&amp;nbsp;업무&amp;nbsp;회고를&amp;nbsp;작성하면&amp;nbsp;클로드가&amp;nbsp;그&amp;nbsp;회고를&amp;nbsp;읽은&amp;nbsp;뒤&amp;nbsp;내가&amp;nbsp;정의한&amp;nbsp;학습&amp;nbsp;기준에&amp;nbsp;따라&amp;nbsp;피드백을&amp;nbsp;제공하도록&amp;nbsp;만들었다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;내가 업무 회고에 왜 이런 접근 방식을 선택했는지, 무엇을 새롭게 알게 되었는지를 회고에 남기면 AI가 기록을 기반으로 내가 놓친 부분을 다시 질문하거나 기술적으로 더 깊게 파고들 수 있는 지점을 제안해주었다. &amp;nbsp;또한 다른 방법은 없었는지, 현재 구현의 트레이드 오프는 무엇인지, 내부적으로는 어떻게 동작하는지처럼 한 단계 더 깊은 질문을 던져주기도 했다. 그래서 내가 너무 당연하게 가정하고 넘어간 부분에서 다른 관점을 제시하기도 했다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;이 프로젝트에서 내가 배웠던 것들을 기록하면서 AI를 활용한 학습의 루프를 만들 수 있었다. 업무를&amp;nbsp;끝내는&amp;nbsp;지점을&amp;nbsp;곧&amp;nbsp;학습이&amp;nbsp;끝나는&amp;nbsp;지점으로&amp;nbsp;만들지&amp;nbsp;않고,&amp;nbsp;AI의&amp;nbsp;평가로&amp;nbsp;수치화된&amp;nbsp;점수를&amp;nbsp;기준으로&amp;nbsp;하여&amp;nbsp;스스로&amp;nbsp;학습의&amp;nbsp;깊이를&amp;nbsp;점검하게&amp;nbsp;될&amp;nbsp;수&amp;nbsp;있다는&amp;nbsp;것이&amp;nbsp;뜻깊었다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;6월 한 달 동안 이 학습 방법을 업무에 적용해 봤을 때 솔직히 매일 완벽하게 지키지는 못했다. 일이 바쁜 날에는 회고를 건너뛰기도 했고, 퇴근하고 나면 귀찮다는 이유로 미룬 날도 있었다. 하지만 꾸준히 했던 기간만큼은 분명 이전과는 다른 점이 있었다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;가장 크게 느낀 변화는 업무에서 마주친 기술을 한 번 더 깊게 들여다보게 되었다는 것이다. 예전에는 문제를 해결하면 자연스럽게 다음 문제로 넘어갔다면 회고를 작성하면서부터는 &quot;왜 이렇게 동작하지?&quot; 혹은 &quot;다른 접근 방법이 없었을까?&quot;, &quot;이런 방식에는 어떤 문제점이 있을까?&quot; 하는 질문을 한 번 더 하게 되었다. &lt;br&gt;또한 AI의 피드백을 통해서 기술적으로 더 공부할 만한 지점을 알게 되기도 했고, 내가 선택한 해결 방법과 다른 관점을 알게 되기도 했다. AI의 피드백 없이도 매일의 업무 경험을 그냥 흘려보내지 않고 조금이라도 다시 되돌아본다는 것이 큰 의미가 있는 것 같다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;이 방법을 잘 실천해서 나의 업무 습관 중 하나로 자리 잡아, 더 깊은 학습을 꾸준히 할 수 있는 사람이 되었으면 좋겠다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;주니어도 RFC부터 시작하면 안될까요?&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;Q2에 있었던 또 하나의 중요한 변화는 처음으로 RFC 단계부터 업무를 시작해 본 것이었다.&lt;br&gt;&amp;nbsp;&lt;br&gt;우리 팀에서는 새로운 프로젝트 문제를 정의하고 초기 해결 방향을 잡는 RFC를 주로 시니어 엔지니어가 담당했다. 주니어 엔지니어는 어느 정도 방향이 정해진 이후 구현에 참여하는 경우가 많았다. 구현 과정에서도 많은 것을 배울 수 있었지만, 새로운 프로덕트를 만들어 가면서 다른 욕심이 생겼다. &lt;br&gt;&lt;br&gt;이미 정의된 문제를 잘 해결하는 것뿐만 아니라 초기 단계부터 주어진&amp;nbsp;문제를&amp;nbsp;어떻게&amp;nbsp;해결해&amp;nbsp;나갈지를&amp;nbsp;구상하는&amp;nbsp;경험을&amp;nbsp;해보고&amp;nbsp;싶었다.&amp;nbsp;그래서&amp;nbsp;5월&amp;nbsp;팀&amp;nbsp;회고에서&amp;nbsp;이런&amp;nbsp;부분에&amp;nbsp;대한&amp;nbsp;아쉬움을&amp;nbsp;얘기했고,&amp;nbsp;주니어&amp;nbsp;개발자에게도&amp;nbsp;RFC&amp;nbsp;작성과&amp;nbsp;초기&amp;nbsp;설계부터&amp;nbsp;참여할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;기회가&amp;nbsp;더&amp;nbsp;많았으면&amp;nbsp;좋겠다고&amp;nbsp;의견을&amp;nbsp;냈다.&amp;nbsp;다행히&amp;nbsp;다른&amp;nbsp;팀원들도&amp;nbsp;공감해&amp;nbsp;주었고&amp;nbsp;이후부터&amp;nbsp;나도&amp;nbsp;새로운&amp;nbsp;업무를&amp;nbsp;RFC부터&amp;nbsp;시작할&amp;nbsp;기회를&amp;nbsp;얻었다.&lt;br&gt;&amp;nbsp;&lt;br&gt;아주 큰 업무는 아니었지만, 막상 직접 참여한 RFC 업무는 쉽지 않았다. 대규모 트래픽이 예상되는 서비스인 만큼 고려해야 할 점이 정말 많았고, 내가 알고 있는 지식의 범위보다 더 넓은 범위의 지식이 필요한 경우가 많았다.&lt;br&gt;&lt;br&gt;그래서 이미 정의된 요구사항을 구현할 때와 달리 기존 시스템을 훨씬 넓게 이해해야 했고, 현재 구조가 왜 이렇게 되어 있는지를 조사하고 가능한 해결 방법들을 제시한 다음에 비교해야 했다. &amp;nbsp;또한 다른&amp;nbsp;사람들과&amp;nbsp;소통하며&amp;nbsp;의견을&amp;nbsp;조율하는&amp;nbsp;것에&amp;nbsp;또&amp;nbsp;많은&amp;nbsp;시간과&amp;nbsp;노력이&amp;nbsp;필요했다.&lt;br&gt;&amp;nbsp;&lt;br&gt;이런 과정에서 훨씬 더 많은 코드를 읽었고, 프로덕트와 관련된 문서를 찾아봤고, 사람들에게 질문을 했다. 맡은 업무의 특성상 프로덕트 전체를 이해해야 하는 부분이 있었기 때문에, 다른 사람이 맡고 있는 업무에 대한 백그라운드도 더 많이 이해해야 했다. 주어진 문제를 해결하기 위한 여러 가지 방법을 제시하고, 선택된 방법에 대해 비용성, 안정성 측면에서 최적의 선택이라는 것을 사람들에게 설득하기 위한 문서를 작성했다. 이전에는 고민해보지 못했던 트래픽 수, 메시지 처리 비용, 레이턴시, 폴백, 확장성을 고민해 시스템을 설계했다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;첫 RFC를 맡아 주도적으로 진행함으로써 업무에 대한 책임감, 자신감이 훨씬 늘었고, 팀 백그라운드 자체에 대한 지식이 쌓여 복리 효과로 다음 업무도 더 잘할 수 있게 되었다. RFC 작성으로 시작하는 업무 방식에 대한 기대 효과가 내가 생각했던 것보다 훨씬 더 컸다.&lt;br&gt;&amp;nbsp;&lt;br&gt;그래서 Q2에 내가 가장 잘했다고 생각하는 일 중 하나는 내게 필요한 성장 기회를 기다리지 않고 직접 이야기하여 좀 더 주도적인 방식으로 업무를 진행했다는 것이다. 기회가&amp;nbsp;주어지기를&amp;nbsp;기다리는&amp;nbsp;대신&amp;nbsp;어떤&amp;nbsp;경험이&amp;nbsp;필요한지&amp;nbsp;이야기했고,&amp;nbsp;실제로&amp;nbsp;업무&amp;nbsp;방식의&amp;nbsp;작은&amp;nbsp;변화를&amp;nbsp;만들었다는&amp;nbsp;점에서&amp;nbsp;의미가&amp;nbsp;있었다.&amp;nbsp;&lt;br&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;nbsp;&lt;br&gt;한국에 돌아간다면 1, 2년 일하고 말 회사가 아닌 10년 이상 꾸준히 다니면서 해당 분야에서 도메인 지식을 넓혀 나가고, 업무적으로도 성장하고, 사람들과 교류를 통해 인맥을 넓히고, 연봉과 복지도 충분히 받을 수 있는 회사를 가고 싶었다.&amp;nbsp;&lt;br&gt;나름의 엄격한 기준에서 꼭 한번 도전해 보고 싶었던 회사였기 때문에 제안을 받았을 때 정말 기뻤다. 만약 합격한다면 한국으로 돌아가는 것도 진지하게 고려할 정도였다.&lt;br&gt;&amp;nbsp;&lt;br&gt;서류 전형에 합격하고 코딩 테스트를 진행했다. 하지만 결과는 좋지 않았다. 당시에 긴장을 너무 많이 했고, 무엇보다 문제를 처음에 제대로 정의하지 못한 상태에서 여러 접근 방법을 오가며 시간을 많이 사용했다. 테스트가 끝난 직후에는 문제를 끝까지 풀지 못했다는 사실이 너무 부끄러웠고, 어렵게 받은 기회를 놓쳤다는 생각에 정말 아쉬웠다.&lt;br&gt;&amp;nbsp;&lt;br&gt;그래도 결과를 인정할 수 있었던 것은 내가 업무를 진행하는 동안 코딩 테스트를 꾸준히 훈련하고 있지 않았다는 점 때문이다.&amp;nbsp; &lt;br&gt;실무에서 매일 코드를 작성하고 있으니 자연스럽게 개발 실력도 계속 늘고 있다고 생각했다. 하지만 실무에서 필요한 능력과 제한 시간 안에 처음 보는 문제를 구조화하고 해결하는 능력은 완전히 같지 않다는 것을 알게 됐다. 그래서 이번 탈락은 꽤 아쉬웠지만 동시에 내가 무엇을 공부해야 하는지 명확하게 보여주는 경험이기도 했다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;아이러니하게도, 실제로 ’정말 합격해서 한국으로 돌아간다면?’이라고 생각하니 아쉬운 것들이 떠올랐다. 다양한 국적의 사람들과 더 많이 어울려보고 싶고, 영어로 일하고 생활하는 환경에서도 조금 더 자연스러운 사람이 되어보고 싶다. 무엇보다 지금의 다국적 회사에서 단순히 주어진 업무를 처리하는 구성원을 넘어, 내 의견을 가지고 사람들에게 영향을 줄 수 있는 개발자가 되어보고 싶다.&lt;br&gt;&amp;nbsp;&lt;br&gt;지난 1년은 이 환경에 적응하는 데 사용했다면, 이제는 이 환경을 &lt;b&gt;제대로 활용해보고 싶다&lt;/b&gt;는 생각이 들었다.&lt;br&gt;그래서 다음 기회를 준비하면서, 적어도 지금 독일에 있는 동안 내가 여기에서만 얻을 수 있는 경험을 충분히 얻어보고 싶다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;업무적으로 많은 변화가 있었던 Q2 였다. &lt;br&gt;업무에 적응하는 시기를 지나, 업무 방식의 불편함을 느끼고 조금 더 주도적으로 업무할 수 있도록 환경을 개선하는 데 집중했다. &lt;br&gt;다행히도 주니어인 내가 기술 설계부터 시작할 수 있는 티켓이 주어졌다. 주도성과 오너십을 조금 더 가지는 것이 본래 목적이었지만 실제 업무를 진행할 수록 프로덕트 백그라운드에 대한 이해, 다양한 기술 적용, 안정적인 설계에 대한 고민, 트래픽을 고려한 비용 측정, 이해관계 조율, 로드 테스트와 성능 최적화 등 짧은 시간에 많은 기술/소통 면에서 성장할 수 있었다. &lt;br&gt;&lt;br&gt;한편으로는 빠르게 요구사항을 구현하는 과정에서 새롭게 배우는 기술이 정말 많았는데, 이 배움을 일회성으로 넘기지 않고 의식적 훈련을 통해 나의 지식으로 승화시키는 과정을 실천했다. &lt;br&gt;&lt;br&gt;Q3 에는 혼자만의 배움으로 끝내지 않고, 배운 내용을 밖으로 표현하는 연습도 더 많이 해보고 싶다. 영어 역시 아직 많이 부족하다고 생각하는데, 배운 내용을 영어로 발표하는 세션을 가지는 것도 좋은 생각인 것 같다. &lt;br&gt;&lt;br&gt;꼭 이직 대비를 하기 위함이 아니더라도, 알고리즘 문제를 주기적으로 풀며 제한된 시간에 문제를 푸는 능력을 기르려 한다. &lt;br&gt;&lt;br&gt;Q3 가 끝났을 때는, 빠르게 업무를 완료하는 나의 장점을 유지하되, 업무 회고를 통해 기술적으로 돌아보면서 ‘이 접근 방식의 취약점은 뭘까?’ ‘이 컴포넌트에서 오류가 발생하면 어떤 방식으로 복구가 가능할까?‘ 등의 단점을 보완하는 방식으로 일할 수 있는 사람이 되면 좋겠다. &lt;/p&gt;</description>
      <category>Other/기록</category>
      <author>MINGYUM</author>
      <guid isPermaLink="true">https://mingyum119.tistory.com/386</guid>
      <comments>https://mingyum119.tistory.com/386#entry386comment</comments>
      <pubDate>Sun, 23 Aug 2026 05:04:33 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] Maximal Square C++ 풀이</title>
      <link>https://mingyum119.tistory.com/385</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/maximal-square/description/?envType=problem-list-v2&amp;amp;envId=array&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/maximal-square/description/?envType=problem-list-v2&amp;amp;envId=array&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1787392674262&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Maximal Square - LeetCode&quot; data-og-description=&quot;Can you solve this real interview question? Maximal Square - Given an m x n binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area. &amp;nbsp; Example 1: [https://assets.leetcode.com/uploads/2020/11/26/max1grid.jpg] &quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/maximal-square/description/?envType=problem-list-v2&amp;amp;envId=array&quot; data-og-url=&quot;https://leetcode.com/problems/maximal-square/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gvQcs/dJMb8YqcJfY/WTLgkyYIL20nckL9B59rU0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/CMxiK/dJMb9ia8dbG/kkpbvAVGwYZd5ZwkqL33T0/img.jpg?width=404&amp;amp;height=322&amp;amp;face=0_0_404_322&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/maximal-square/description/?envType=problem-list-v2&amp;amp;envId=array&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/maximal-square/description/?envType=problem-list-v2&amp;amp;envId=array&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gvQcs/dJMb8YqcJfY/WTLgkyYIL20nckL9B59rU0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/CMxiK/dJMb9ia8dbG/kkpbvAVGwYZd5ZwkqL33T0/img.jpg?width=404&amp;amp;height=322&amp;amp;face=0_0_404_322');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Maximal Square - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Can you solve this real interview question? Maximal Square - Given an m x n binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area. &amp;nbsp; Example 1: [https://assets.leetcode.com/uploads/2020/11/26/max1grid.jpg]&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Description:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Given an&lt;span&gt;&amp;nbsp;&lt;/span&gt;m x n&lt;span&gt;&amp;nbsp;&lt;/span&gt;binary&lt;span&gt;&amp;nbsp;&lt;/span&gt;matrix&lt;span&gt;&amp;nbsp;&lt;/span&gt;filled with&lt;span&gt;&amp;nbsp;&lt;/span&gt;0's and&lt;span&gt;&amp;nbsp;&lt;/span&gt;1's,&lt;span&gt;&amp;nbsp;&lt;/span&gt;find the largest square containing only&lt;span&gt;&amp;nbsp;&lt;/span&gt;1's&lt;span&gt;&amp;nbsp;&lt;/span&gt;and return its area.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccjxY4/dJMcag0S2aR/tqVuDtVUckv03dC1hIjm2k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccjxY4/dJMcag0S2aR/tqVuDtVUckv03dC1hIjm2k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccjxY4/dJMcag0S2aR/tqVuDtVUckv03dC1hIjm2k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccjxY4%2FdJMcag0S2aR%2FtqVuDtVUckv03dC1hIjm2k%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;404&quot; height=&quot;322&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;prolog&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: matrix = [[&quot;1&quot;,&quot;0&quot;,&quot;1&quot;,&quot;0&quot;,&quot;0&quot;],[&quot;1&quot;,&quot;0&quot;,&quot;1&quot;,&quot;1&quot;,&quot;1&quot;],[&quot;1&quot;,&quot;1&quot;,&quot;1&quot;,&quot;1&quot;,&quot;1&quot;],[&quot;1&quot;,&quot;0&quot;,&quot;0&quot;,&quot;1&quot;,&quot;0&quot;]]
Output: 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;165&quot; data-origin-height=&quot;165&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cebvNm/dJMcag0S2aQ/QcEqaR9IXUfKscUKXy9vWK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cebvNm/dJMcag0S2aQ/QcEqaR9IXUfKscUKXy9vWK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cebvNm/dJMcag0S2aQ/QcEqaR9IXUfKscUKXy9vWK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcebvNm%2FdJMcag0S2aQ%2FQcEqaR9IXUfKscUKXy9vWK%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;165&quot; height=&quot;165&quot; data-origin-width=&quot;165&quot; data-origin-height=&quot;165&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;prolog&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: matrix = [[&quot;0&quot;,&quot;1&quot;],[&quot;1&quot;,&quot;0&quot;]]
Output: 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;lua&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: matrix = [[&quot;0&quot;]]
Output: 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Constraints:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;m == matrix.length&lt;/li&gt;
&lt;li&gt;n == matrix[i].length&lt;/li&gt;
&lt;li&gt;1 &amp;lt;= m, n &amp;lt;= 300&lt;/li&gt;
&lt;li&gt;matrix[i][j]&lt;span&gt;&amp;nbsp;&lt;/span&gt;is&lt;span&gt;&amp;nbsp;&lt;/span&gt;'0'&lt;span&gt;&amp;nbsp;&lt;/span&gt;or&lt;span&gt;&amp;nbsp;&lt;/span&gt;'1'.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 브루트 포스 풀이 방식을 떠올렸다.&lt;/p&gt;
&lt;pre id=&quot;code_1787392935890&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int answer = 0; 
for(int i = 0; i &amp;lt; n; i++) 
	for(int j = 0; j &amp;lt; m; j++) {
    	// matrix[i][j]에서 넓힐 수 있는 최대 정사각형의 크기
        for(int size = 1;; size++) {
        	// size * size 개수만큼 순회
        }
    }&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;MN = 90,000이기 때문에 전체 셀에서 최대 정사각형의 크기를 계산하는 풀이 방법은 (MN)^2 = 8,100,000,000으로 너무 큰 시간 복잡도를 보인다.&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;최적화하기 위해서는 (i, j)를 왼쪽 상단으로 하는 최대 정사각형 넓이를 찾기 위해 (i + 1, j), (i, j +1), (i + 1, j + 1) 를 순회하는 것이 그 이전에 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(i + 1, j), (i, j +1), (i + 1, j + 1)&lt;span&gt; 각각을 왼쪽 상단으로 하는 최대 정사각형 넓이를 찾기 위해 순회하는 것과 중복된다.&amp;nbsp;&lt;/span&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;따라서 이는 다이나믹 프로그래밍 문제로, 규칙을 통해 dp[i][j] 배열의 정의를 찾으면 해결되는 문제이다.&lt;/span&gt;&lt;/span&gt;&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;dp[i][j] = (i, j) 를 왼쪽 상단으로 하는 정사각형 중에 가장 최대 길이 라고 가정해보자.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 11.8605%; height: 111px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;0&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;이 matrix가 주어졌을 때, 바로 알 수 있는 dp[i][j] 를 정의하면 아래와 같다. 더 확장할 곳이 없는 위치의 셀들은 자기 자신이 1이라면 1 크기의 정사각형을, 0이라면 정사각형을 만들 수 없다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 11.9767%; height: 61px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;0&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;dp[1][1]을 채워보자. dp[2][1], dp[1][2]는 1 이지만&amp;nbsp; dp[2][2]가 0인 바람에 dp[1][1] = 1이 될 수밖에 없다. 만약 dp[2][2] = 1 이었다면 dp[1][1] = 2였을 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, dp[i][j] 는 dp[i+ 1][j], dp[i][j + 1], dp[i + 1][j + 1]의 최솟값에 1을 더한 것과 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 예제를 통해서 더 설명해보겠다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 11.9767%; height: 61px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;0&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;dp[0][1] 지점에서는 2 크기의 정사각형을 만들 수 있다. A 지점이 3이 되기 위해서는 matrix 내에서 9가지 셀이 모두 1이여서 dp 배열의 A 주변의 세 지점이 모두 2여야 가능하다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 11.9767%; height: 61px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&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;하지만 불행하게도, A의 아래 두개 지점의 dp 배열이 1이기 때문에 3을 완성하지 못한다. 대신에 2 크기의 정사각형 배열을 만들 수 있다.&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;pre id=&quot;code_1787394010306&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
public:
    int dp[301][301];
    
    int maximalSquare(vector&amp;lt;vector&amp;lt;char&amp;gt;&amp;gt;&amp;amp; matrix) {
        int n = matrix.size(); 
        int m = matrix[0].size();

        int answer = 0; 

        for(int i = 0; i &amp;lt; n; i++) {
            dp[i][m - 1] = matrix[i][m - 1] - '0';
            if(dp[i][m-1] == 1) {
                answer = 1;
            }
        }

        for(int j = 0; j &amp;lt; m; j++) {
            dp[n - 1][j] = matrix[n - 1][j] - '0';
            if(dp[n-1][j] == 1) {
                answer = 1;
            }
        }

        for(int i = n - 2; i &amp;gt;= 0; i--) {
            for(int j = m - 2; j &amp;gt;= 0; j--) {
                if(matrix[i][j] == '1') {
                    dp[i][j] = min(dp[i+1][j], min(dp[i][j+1], dp[i+1][j+1])) + 1; 
                    if(dp[i][j] &amp;gt; answer) {
                        answer = dp[i][j]; 
                    }
                } else {
                    dp[i][j] = 0;
                }
            }
        }
        return answer * answer; 
    }
};&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;matrix[i][j] == 0 인 경우에는 계산할 필요없이 무조건 dp[i][j] = 0 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미리 정의해둔 dp 배열에서 나온 하나의 크기의 정사각형이 최대 크기일 수도 있음을 고려해, 하나라도 1이 나오는 경우 answer = 1로 미리 고정해둔다.&lt;/p&gt;</description>
      <category>Algorithm</category>
      <author>MINGYUM</author>
      <guid isPermaLink="true">https://mingyum119.tistory.com/385</guid>
      <comments>https://mingyum119.tistory.com/385#entry385comment</comments>
      <pubDate>Sat, 22 Aug 2026 19:22:04 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] Gas Station C++ 풀이</title>
      <link>https://mingyum119.tistory.com/384</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/gas-station/?envType=problem-list-v2&amp;amp;envId=dglcn6pr&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/gas-station/?envType=problem-list-v2&amp;amp;envId=dglcn6pr&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786787151728&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Gas Station - LeetCode&quot; data-og-description=&quot;Can you solve this real interview question? Gas Station - There are n gas stations along a circular route, where the amount of gas at the ith station is gas[i]. You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from the ith st&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/gas-station/?envType=problem-list-v2&amp;amp;envId=dglcn6pr&quot; data-og-url=&quot;https://leetcode.com/problems/gas-station/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/wqAcU/dJMb82e3nzg/bW1hr7KK6CkbDP81takmv0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/gas-station/?envType=problem-list-v2&amp;amp;envId=dglcn6pr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/gas-station/?envType=problem-list-v2&amp;amp;envId=dglcn6pr&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/wqAcU/dJMb82e3nzg/bW1hr7KK6CkbDP81takmv0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Gas Station - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Can you solve this real interview question? Gas Station - There are n gas stations along a circular route, where the amount of gas at the ith station is gas[i]. You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from the ith st&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Description:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;There are&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;gas stations along a circular route, where the amount of gas at the&lt;span&gt;&amp;nbsp;&lt;/span&gt;ith&lt;span&gt;&amp;nbsp;&lt;/span&gt;station is&lt;span&gt;&amp;nbsp;&lt;/span&gt;gas[i].&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;You have a car with an unlimited gas tank and it costs&lt;span&gt;&amp;nbsp;&lt;/span&gt;cost[i]&lt;span&gt;&amp;nbsp;&lt;/span&gt;of gas to travel from the&lt;span&gt;&amp;nbsp;&lt;/span&gt;ith&lt;span&gt;&amp;nbsp;&lt;/span&gt;station to its next&lt;span&gt;&amp;nbsp;&lt;/span&gt;(i + 1)th&lt;span&gt;&amp;nbsp;&lt;/span&gt;station. You begin the journey with an empty tank at one of the gas stations.&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Given two integer arrays&amp;nbsp;gas&amp;nbsp;and&amp;nbsp;cost, return&amp;nbsp;the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return&amp;nbsp;-1. If there exists a solution, it is&amp;nbsp;&lt;b&gt;guaranteed&lt;/b&gt;&amp;nbsp;to be&amp;nbsp;&lt;b&gt;unique&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
Output: 3
Explanation:
Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 4. Your tank = 4 - 1 + 5 = 8
Travel to station 0. Your tank = 8 - 2 + 1 = 7
Travel to station 1. Your tank = 7 - 3 + 2 = 6
Travel to station 2. Your tank = 6 - 4 + 3 = 5
Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3.
Therefore, return 3 as the starting index.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: gas = [2,3,4], cost = [3,4,3]
Output: -1
Explanation:
You can't start at station 0 or 1, as there is not enough gas to travel to the next station.
Let's start at station 2 and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 0. Your tank = 4 - 3 + 2 = 3
Travel to station 1. Your tank = 3 - 3 + 3 = 3
You cannot travel back to station 2, as it requires 4 unit of gas but you only have 3.
Therefore, you can't travel around the circuit once no matter where you start.
&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;b&gt;Constraints:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;n == gas.length == cost.length&lt;/li&gt;
&lt;li&gt;1 &amp;lt;= n &amp;lt;= 105&lt;/li&gt;
&lt;li&gt;0 &amp;lt;= gas[i], cost[i] &amp;lt;= 104&lt;/li&gt;
&lt;li&gt;The input is generated such that the answer is unique.&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;브루트 포스로 풀면 O(N^2)의 시간복잡도가 나오는 문제이다. 입력 제한이 커서 Optimization이 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지 최적화 방법은 문제의 특징을 사용해서 O(N^2)의 순회를 하되, 중간에 Skipping을 할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;i에서 출발해서 j 에서 연료가 모자라 실패했다면, 다음 순회는 i + 1가 아니라 j + 1에서 시작하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면, i와 j 사이에 어디에서 출발하든 연료는 똑같이 모자랄 수 밖에 없기 때문이다.&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;index = 0 1 2 3 4&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gas&amp;nbsp; &amp;nbsp; = 1 2 3 4 5&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cost&amp;nbsp; &amp;nbsp;= 3 4 5 1 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;4번째 인덱스에서 출발한다고 하자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;current = 4: totalGas = 0 + 5 - 2 = 3&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;current = 0: totalGas = 3 + 1 - 3 = 1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;current = 1: totalGas = 1 + 2 - 4 = -1&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4번째 인덱스에서 시작해서 그나마 1번째까지 온것이지만, 0번째에서 시작했으면 더 일찍 실패했지 더 나아가지는 못하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 다음과 같은 개념을 적용해, 모든 시작 인덱스를 다 테스트해보는 것이 아닌 실패한 지점보다 1만큼 더 나아간 지점에서 테스트하면 훨씬 시간 복잡도를 아낄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Solution:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1786787724634&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
public:
    int canCompleteCircuit(vector&amp;lt;int&amp;gt;&amp;amp; gas, vector&amp;lt;int&amp;gt;&amp;amp; cost) {
        int size = gas.size();
        for(int i = 0; i &amp;lt; size;) {
            int current = i; 
            int totalGas = 0;
            for (int step = 0; step &amp;lt; size; step++) {
                current = (step + i) % size; // 출발 점에서 step만큼 이동한 위치
                totalGas = totalGas + gas[current] - cost[current];
                
                if(totalGas &amp;lt; 0) { // i 시작점일 때 current 에서 막힌다.
                    break;
                }
            }

            if(totalGas &amp;gt;= 0) {
                return i;
            }

            if(current &amp;lt; i) {
                break;
            }

            i = current + 1; // 막힌 구간 바로 뒤에서 다시 시작한다.
        }
        return -1;
    }&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;if (current &amp;lt; i)&amp;nbsp; break; 의 코드를 이해하기 어려웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 코드에서 시작점을 0부터 테스트하고 있다. 그래서 current, 즉 마지막 실패 지점은 항상 i 보다 크기 마련이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 totalGas 가 0보다 작아 실패한 지점인 게 확실한 상황에서,&amp;nbsp;current 가 i 보다 작기까지 한다면 이미 배열 끝을 지나 0을 거쳐 한바퀴 돌아 이전에 검사한 영역까지 들어왔음을 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 i = 3일때, current = 0인 지점에서 실패했다고 하자. 어짜피 다음 순회를 시작해봤자 current + 1 인 1을 시작점으로 둘 터인데, 그러면 이미 이전에 i = 1일때 검사했던 것과 중복된다. 그래서 더 이상 새롭게 검사할 시작점 후보가 없다는 것을 의미해 break;를 통해 -1을 반환하도록 하는 것이다.&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;이는 이론적으로 O(N^2)의 시간복잡도를 가진다. O(N)의 시간복잡도 풀이는 아래 링크에서 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Reference:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/deluxify/leetcode-134-gas-station-11295b36f0cf&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/deluxify/leetcode-134-gas-station-11295b36f0cf&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786787156569&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Leetcode# 134. Gas Station&quot; data-og-description=&quot;There are n gas stations along a circular route, where the amount of gas at the ith station is gas[i].&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/deluxify/leetcode-134-gas-station-11295b36f0cf&quot; data-og-url=&quot;https://medium.com/deluxify/leetcode-134-gas-station-11295b36f0cf&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ciMVxM/dJMb8UH5KBS/C5BmRrHkROIQKLkGIx9cNk/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://medium.com/deluxify/leetcode-134-gas-station-11295b36f0cf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/deluxify/leetcode-134-gas-station-11295b36f0cf&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ciMVxM/dJMb8UH5KBS/C5BmRrHkROIQKLkGIx9cNk/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Leetcode# 134. Gas Station&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;There are n gas stations along a circular route, where the amount of gas at the ith station is gas[i].&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <author>MINGYUM</author>
      <guid isPermaLink="true">https://mingyum119.tistory.com/384</guid>
      <comments>https://mingyum119.tistory.com/384#entry384comment</comments>
      <pubDate>Sat, 15 Aug 2026 19:01:09 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] WordBreak C++ 풀이</title>
      <link>https://mingyum119.tistory.com/383</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/word-break/description/?envType=problem-list-v2&amp;amp;envId=array&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/word-break/description/?envType=problem-list-v2&amp;amp;envId=array&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786095584295&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Word Break - LeetCode&quot; data-og-description=&quot;Can you solve this real interview question? Word Break - Given a string s and a dictionary of strings wordDict, return true if s can be segmented into a space-separated sequence of one or more dictionary words. Note that the same word in the dictionary may&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/word-break/description/?envType=problem-list-v2&amp;amp;envId=array&quot; data-og-url=&quot;https://leetcode.com/problems/word-break/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Tdhkt/dJMb81HcWx7/eMYLhMYqnafNXaIs5uPLdK/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/word-break/description/?envType=problem-list-v2&amp;amp;envId=array&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/word-break/description/?envType=problem-list-v2&amp;amp;envId=array&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Tdhkt/dJMb81HcWx7/eMYLhMYqnafNXaIs5uPLdK/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Word Break - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Can you solve this real interview question? Word Break - Given a string s and a dictionary of strings wordDict, return true if s can be segmented into a space-separated sequence of one or more dictionary words. Note that the same word in the dictionary may&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Source Code&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1786095605461&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
public:
    set&amp;lt;string&amp;gt; words;
    int dp[301];

    bool recursive(string s, int start) {
        if (dp[start] != -1) return dp[start];

        if (start &amp;gt;= s.length()) {
            return true;
        }

        bool breakable = false;
        for(int j = start; j &amp;lt; s.length(); j++) {
            string sub = s.substr(start, j - start + 1);
            if(words.find(sub) != words.end()) {
                if(recursive(s, j + 1)) {
                    breakable = true;
                }
            }
        }
        return dp[start] = breakable;
    }

    bool wordBreak(string s, vector&amp;lt;string&amp;gt;&amp;amp; wordDict) {
        for(int i = 0; i&amp;lt; 300; i++) {
            dp[i] = -1;
        }
        for(string word: wordDict) {
            words.insert(word);
        }
        return recursive(s, 0);
    }
};&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;Recursive + Dynamic Programming 기법으로 풀었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;s.substr(start, j) 가 wordDict에 존재하는 지 확인하고, 존재한다면 다음 스택에 start = j + 1를 파라미터로 하여 다음 substring을 검증하는 방식이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wordDict에 존재하는 즉시 순회를 멈추고 다음 스택으로 넘어가는 것이 아니라, 순회를 계속 이어가면서 다른 wordDict에 포함된 단어가 있는 지 확인하였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이유는, catsandog 에서 start = 0일때 cat과 cats 두가지 경우의 수가 발견될 수 있기 때문이다. 하지만 가장 짧은 단어를 찾은 이후 멈춘다면 cats를 발견할 수 없고, wordDict에 sand가 없다고 가정했을 때 cats/and 조합을 발견할수 없기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시간복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;recursive(start) 는 DP 에 의해서 start위치마다 한번씩 계산된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. recursive(start)의 호출 횟수 = O(N)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. for(int j = start; j &amp;lt; n; j++) = O(N)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. substr()에 의해 문자열 복사 = O(N)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 O(N^3)의 시간복잡도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공간복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. dp 배열 = O(N)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 재귀호출에 의한 스택 사용 = O(N)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. set&amp;lt;string&amp;gt; words = O(M) 여기서 M&amp;nbsp; 은 wordDict에 있는 총 문자의 개수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 O(N + M) 의 공간복잡도&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://www.geeksforgeeks.org/dsa/word-break-problem-dp-32/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.geeksforgeeks.org/dsa/word-break-problem-dp-32/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786096372712&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Word Break - GeeksforGeeks&quot; data-og-description=&quot;Your All-in-One Learning Portal: GeeksforGeeks is a comprehensive educational platform that empowers learners across domains-spanning computer science and programming, school education, upskilling, commerce, software tools, competitive exams, and more.&quot; data-og-host=&quot;www.geeksforgeeks.org&quot; data-og-source-url=&quot;https://www.geeksforgeeks.org/dsa/word-break-problem-dp-32/&quot; data-og-url=&quot;https://www.geeksforgeeks.org/dsa/word-break-problem-dp-32/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bfOETg/dJMb8PGLEx7/LNYB6luJqkgysQyx9BWkn0/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/UUM13/dJMb8ZvQRzs/Yo5K7QZnMLEcxCVYRqJg71/img.png?width=1003&amp;amp;height=470&amp;amp;face=0_0_1003_470,https://scrap.kakaocdn.net/dn/bfE3QR/dJMb8XkuZug/LQeyF6smkQTIxWC0vAR1Ek/img.png?width=1003&amp;amp;height=470&amp;amp;face=0_0_1003_470&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/dsa/word-break-problem-dp-32/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.geeksforgeeks.org/dsa/word-break-problem-dp-32/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bfOETg/dJMb8PGLEx7/LNYB6luJqkgysQyx9BWkn0/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/UUM13/dJMb8ZvQRzs/Yo5K7QZnMLEcxCVYRqJg71/img.png?width=1003&amp;amp;height=470&amp;amp;face=0_0_1003_470,https://scrap.kakaocdn.net/dn/bfE3QR/dJMb8XkuZug/LQeyF6smkQTIxWC0vAR1Ek/img.png?width=1003&amp;amp;height=470&amp;amp;face=0_0_1003_470');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Word Break - GeeksforGeeks&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Your All-in-One Learning Portal: GeeksforGeeks is a comprehensive educational platform that empowers learners across domains-spanning computer science and programming, school education, upskilling, commerce, software tools, competitive exams, and more.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.geeksforgeeks.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;</description>
      <category>Algorithm</category>
      <author>MINGYUM</author>
      <guid isPermaLink="true">https://mingyum119.tistory.com/383</guid>
      <comments>https://mingyum119.tistory.com/383#entry383comment</comments>
      <pubDate>Fri, 7 Aug 2026 18:54:07 +0900</pubDate>
    </item>
    <item>
      <title>[2026 Q1 회고] 시니어 처럼 일하고 싶은 주니어 개발자의 회고</title>
      <link>https://mingyum119.tistory.com/382</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;춥고 추웠던 베를린의 겨울이 지나고, 4월이 되었다!&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;처음 경험하는 독일 겨울은 무자비했다. 겨울에도 해가 드는 한국의 날씨가 얼마나 소중한 것인지 몸소 깨달았다. 온도만 봤을 때 영하 3도 안팎의 상대적으로 따듯한 온도임에도 불구하고, 해가 들지 않아 서늘하고 눈이 녹지 않아 길이 몇 주 내내 미끄러웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 한국인 친구들은 겨울에 한국으로 떠났고 나는 9월, 10월에 한국을 다녀온 탓에 독일에서 겨울을 보내며 날씨 공격을 정통으로 맞았다. 몸이 날씨에 적응을 하지 못해서 한달에 한 번은 꼭 아프고, 기본적으로 감기에 걸린 상태에서 지냈다. 한국처럼 병원을 쉽게 갈 수 있는 구조가 아니다 보니 병원을 딱히 가지는 않았지만, 가더라도 약 처방 대신 약국에서 처방전 없이 살 수 있는 일반의약품을 사거나 감기차를 마시는 것을 권한였다. 어릴 때부터 이런 환경에서 자란 독일 사람들의 면역력은 세계 최강일 것 같다.&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;그래도 비가 오나 눈이 오나 일을 하는 것이 어른. 그럼에도 Q1에도 열심히 일했다! (뿌듯)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;189b5e1ed5a522198.jpg&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sIVDI/dJMcahRDEDQ/mm1E2fQuHCzCimFSB1HgQK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sIVDI/dJMcahRDEDQ/mm1E2fQuHCzCimFSB1HgQK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sIVDI/dJMcahRDEDQ/mm1E2fQuHCzCimFSB1HgQK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsIVDI%2FdJMcahRDEDQ%2Fmm1E2fQuHCzCimFSB1HgQK%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;640&quot; height=&quot;480&quot; data-filename=&quot;189b5e1ed5a522198.jpg&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;480&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;h3 data-ke-size=&quot;size23&quot;&gt;Q1 에서 가장 많이 고민했던 것.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q1에서는 내가 어떻게 하면 더 완성도 높은 결과물을 낼 수 있을지에 대해서 가장 많이 고민했다.&lt;br /&gt;예전에는 일단 만들고 빠르게 전달하는 데에 더 집중했다면, 이번에는 그냥 구현하고 끝내는 게 아니라 이 프로덕트가 실제로 배포되었을 때 어떤 영향을 미칠지, 어떻게 동작할지, 실패 케이스는 무엇일지를 같이 생각하는 게 중요하다고 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번 &lt;a href=&quot;https://mingyum119.tistory.com/381&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;1년 회고&lt;/a&gt;에서도 썼듯이, &lt;b&gt;오너십&lt;/b&gt;이라는 게 단순히 맡은 기능을 만드는 것에서 끝나는 게 아니라고 생각했다. 내가 만든 기능이 실제 서비스 안에서 어떻게 작동할지, 문제가 생기면 어디서 어떻게 터질 수 있을지까지 같이 보는 게 더 중요하다고 느꼈다.&lt;br /&gt;그래서 수동적으로 일하기보다는, 내가 할 수 있는 범위 안에서 더 능동적으로 일하고 싶다는 생각을 많이 했다. 사실 다짐했다고 해서 한번에 되기는 쉽지 않아서 의식적으로 노력을 한 시기였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Q1에 실제로 시도했던 변화.&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 실제로 어떻게 구현할 수 있을까 생각했을 때, 우리 팀이 새로운 프로젝트를 빌딩하고 있는 상황이 오히려 좋은 기회라고 느꼈다.&lt;br /&gt;그래서 기능을 다 만든 뒤에 테스트하는 데 더 많은 시간을 쓰려고 했다. 예전에는 개발이 끝나면 해피 케이스 위주로만 확인하고 넘어가는 경우가 있었는데, 이번에는 의식적으로 &lt;b&gt;예외 케이스&lt;/b&gt;나 &lt;b&gt;실패 시나리오&lt;/b&gt;를 더 많이 보려고 했다.&lt;br /&gt;아직 문제가 발생하지 않았더라도, 내가 만들고 있는 Feature가 어떤 영향을 줄 수 있는지, 실패한다면 어떻게 해결해야 하는지, 그리고 그 해결 방법이 지금 구현 안에 포함되어 있는지를 생각해보려고 했다. 그 과정에서 고민이 있거나 의문이 드는 점이 있을 때 사소하더라도 팀에 질문을 하거나 같이 이야기해보려고 했다.&lt;br /&gt;기술적으로 엄청 많은 것을 배웠다기보다는, 프로덕트를 만들 때 무엇을 중요하게 봐야 하는지, 그리고 꼼꼼하게 개발한다는 게 어떤 의미인지에 대해서 더 생각해보게 된 Q1이었다.&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;span&gt;Q1에서 느낀 아쉬움.&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아쉬운 점은, 내가 &lt;b&gt;충분한 피드백&lt;/b&gt;을 받고 있지 않다는 것이었다.&lt;br /&gt;사실 나는 내가 지금 잘하고 있는지, 느린지 빠른지, 방향이 맞는지에 대한 감각이 아직 부족한데, 그걸 확인할 수 있는 피드백이 별로 없다고 느꼈다. 왜 그런지를 생각해봤을 때, 피드백을 따로 요청하지 않은 나의 안일함 혹은 자신감 부족도 있었고, 팀 분위기 자체가 자주 모여서 많이 이야기하는 분위기는 아니라는 점도 영향을 줬던 것 같다. 그래서 더더욱 내가 먼저 피드백을 요청하지 않으면 아무것도 얻지 못하는 상태였던 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q1에는 소소하게 몸도 좋지 않아서 재택하는 날이 많아 심리적으로도, 환경적으로도 팀원들과 가까워지는 것이 쉽지 않았다. 자신감이 부족하다 보니 방어적으로 되는 순간도 많았고, 그러다 보니 더 캐주얼하게 접근하기가 어렵게 느껴졌다. 그래서 피드백이 필요하다는 건 알았지만, 실제로 그걸 얻기 위한 행동까지는 충분히 못 갔던 것 같다.&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;span&gt;최근에 바뀌고 있는 부분.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h3&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;&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;그래서 최근에는 마음을 좀 고쳐 먹고 팀원들과 더 시간을 보내려고 하고 있다. 팀 이벤트도 기획해보고, 내 현재 상태를 더 자주, 자세히 공유하려고 하고 있다. 아직 당장 팀원들과 많이 가까워졌다고 말할 수는 없지만, 적어도 예전보다는 더 나은 상태로 가고 있다는 것이 느껴진다. 내가 팀원들을 어려워하면 팀원들도 나를 더 어려워할 것이라고 생각한다. 완벽주의를 버리고 조금 더 편하게 다가가고 싶다.&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;업무에 AI를 쓰는 방법.&amp;nbsp;&lt;/h3&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;br /&gt;내가 생각했을 때 AI 시대에 더 중요해지는 건 실행 자체보다도 판단에 가까운 능력들이다.&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;li&gt;질문을 잘 던지는 능력&lt;/li&gt;
&lt;li&gt;AI의 결과를 해석하고 자기 것으로 만드는 능력&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;나는 아직 주니어라서 이런 판단이나 책임을 크게 가지는 역할을 맡기 어려운 순간도 많다고 생각한다. 그렇지만 AI 시대일수록 더 &lt;b&gt;주도권을 가지고 일하려는 태도&lt;/b&gt;가 중요하다고 느꼈고, 그래서 나도 AI에 대체되는 사람이 아니라 &lt;b&gt;AI를 활용해서 더 좋은 판단&lt;/b&gt;을 할 수 있는 사람이 되어야겠다고 생각했다. 주니어지만 충분히 시니어처럼 일할 수 있다고 생각한다. 물론 시니어의 경험에서 우러나오는 판단력을 다 대체할 수는 없겠지만 적어도 AI 등장으로 인해 시니어만큼의 지식을 가지고 있다고 말해도 과언이 아니라는 뜻이다. 그래서 판단력을 더 기르는 방향으로 일을 해야한다는 것이다.&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;span&gt;Q2에 가져가고 싶은 방향&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 분기에는 AI를 더 많이 학습하고, 실제 업무에도 더 적극적으로 적용해보고 싶다.&lt;br /&gt;반복적인 일은 최대한 자동화하는 연습을 하고, 그렇게 아낀 시간을 AI가 대신할 수 없는 능력을 기르는 데 쓰고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그와 동시에, 단순히 컴포넌트 하나를 구현하는 역할이 아니라 내가 &lt;b&gt;하나의 토픽을 주도적으로 가져가보고 싶다.&amp;nbsp; &lt;/b&gt;회사의 동의가 필요한 부분이기에 어떻게 될지는 모르겠지만 나는 그런 기회를 통해 소통해서 결과를 만들어내는 능력을 더 키우고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금의 나는 스스로를 아직 부족하다고 느끼고, 조금 수동적이라고 느낄 때도 있다. 그러나 이렇게 하나의 토픽을 내가 온전히 맡고 여러 이해관계자와 소통하는 과정에서 질문하는 능력이나 판단하는 능력 등을 더 키울 수 있을 것이라 믿는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 외치는 좌우명이 있다. &lt;b&gt;&quot;인생은 기세다!&quot;   &lt;/b&gt;업무이든 인간관계이든 잘 되는 게 별로 없다고 생각이 들어 자신감도 많이 떨어지고 주눅이 들고 무기력한 시기도 있었는데 이제는 조금 더 정신 차리고 제대로 해보려고 한다. 생각없이 살게 되면 사는 대로 생각하게 된다. 내가 나를 끌어올려주지 못하고 주어진 대로 살면 정체, 사실상 내려가는 것과 다름 없다. 생각대로 살고 싶으면 내가 더 잘할 수 있다고 믿고 스스로를 상황 속으로 던져주어야 한다. 더 자신감있게, AI를 잘 활용하도록 노력하면서 똑똑하게 일하는 Q2가 되었으면 좋겠다.&lt;/p&gt;</description>
      <category>Other/기록</category>
      <author>MINGYUM</author>
      <guid isPermaLink="true">https://mingyum119.tistory.com/382</guid>
      <comments>https://mingyum119.tistory.com/382#entry382comment</comments>
      <pubDate>Mon, 20 Apr 2026 03:35:20 +0900</pubDate>
    </item>
    <item>
      <title>토종 한국인  개발자의 외국 회사에서의 우당탕탕 1년 회고  </title>
      <link>https://mingyum119.tistory.com/381</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;입사를 한 지 어느덧 일년 차가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일년 단위가 아니면 어느 단위로 회고를 하겠는가  &amp;nbsp;&lt;br /&gt;취업을 했던 1년 전부터 지금까지를 돌이켜보며 개발자로서 어떤 고민과 성장이 있었는지를 정리해보았다.&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;첫 취업과 코흘리개 신입 개발자의 고군분투&amp;nbsp;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 점을 우선 이야기하자면, 한 회사에서 개발자로 일하면서 어느 순간 개발이라는 일이 정말 &lt;b&gt;재미있다&lt;/b&gt;는 것을 깨달았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 치는 게 재미있었다기보다는, 티켓을 받고, 문제의 원인을 찾고, 어떤 액션을 통해 문제를 해결할 수 있을 지 파악하고, 실제로 해결하여 나의 온전한 노력으로 끝까지 결과를 이끌어내는 과정이 재미있었다. 한국인의 긍지를 보여주마! 이런 느낌 .. 그 과정에서 우리 팀의 백그라운드를 이해하고 도메인 지식을 넓혀가는 감각도 좋았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발이 재미있다는 깨달음은 상당히 큰 소득이다. 개발자라는 나의 첫 직업에 대한 자신이 생기고 앞으로도 이 직업으로 먹고 살기 위해 투자해도 되는 근거가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 회사 일은 당연하게도 재미있는 일만 있지는 않았다. 내가 이걸 해결할 수 있을까 의문이 들 정도로의 어려움을 경험하기도 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 크게 느낀 어려움은 &lt;b&gt;커뮤니케이션&lt;/b&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀원들과의 디스커션에 적극적으로 참여하지 못하는 상황이 특히 힘들었다. 나에게 이게 유독 힘들었던 건 물론 언어 차이의 문제도 있다. 초반에는 아예 언어적인 장벽 때문에 알아듣지 못하는 대화가 있었고, 무언가 말하고 싶은게 있더라도 한 문장을 제대로 완성하지 못해 자신감이 많이 떨어졌다. 한 마디도 꺼내지 못하고 디스커션이 종료되는 상황이 적지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 팀과의 대화에서 위축되었던 이유는 비단 언어 문제 때문만은 아니었다. 이는 무엇보다 &lt;b&gt;타인의 시선에서 나를 평가하는 습관&lt;/b&gt;에서 비롯되었다고 생각한다. 질문을 하기 전에 많이 고민하고, 혹시 틀린 질문일까 고민한다. 일을 하는 과정에서 무언가 잘 안되는 모습을 보여주기보다는 혼자 잘 해결해서 완성된 결과를 보여주고 싶어한다. 즉, 의견을 내거나 상황을 공유하여 평가받는 것보다는 맡은 일을 성실히 수행하는 편을 선택했다.&amp;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;하지만 최근의 나의 모습을 보면 꽤 자신감이 붙었고 회의에서의 참여도 주저하지 않는 나의 모습을 볼 수 있었다.&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;커뮤니케이션을 잘하는 방법에 대해&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋다! 언어의 차이를 극복하고 습관을 극복해서 무언가 말을 하기 위한 마음의 벽을 허물었다고 하자.&lt;/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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;질문을 하는 것도 결국에는 상황을 입체적으로 보며 창의적인 사고를 할 때 자연스럽게 떠오르는 것이다.&lt;/li&gt;
&lt;li&gt;그리고 상대방이 이해하기 쉽게 설명하고 매끄럽게 대화가 이어지도록 하는 것도 아직 어렵다.&lt;/li&gt;
&lt;li&gt;도메인 지식이 충분하고 서비스가 어떻게 돌아가는 지 잘 알고 있어야 풍부한 대화가 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국에 커뮤니케이션은 '창의성'과 '도메인 지식'과 '대화 능력'이 어우러진 아름다운 결과물이라고 정의 내렸다.&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;li&gt;도메인 지식을 키우기 위해서는 우선 주어진 티켓에 열심히 임한다.&lt;/li&gt;
&lt;li&gt;대화 능력을 키우기 위해서는 내가 하고자 하는 말을 들을 상대방 입장을 생각하고 이해 가능하게 말하도록 노력한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은 창의성이 가장 중요한 부분이라 생각하면서도 가장 어렵다.&lt;/p&gt;
&lt;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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;오너십이란? 개발자가 프로덕트에 오너십을 갖는 방법에 대해&lt;/h3&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;기획 / 디자인에 관여할 수 있는 범위가 줄어들고, 프로덕트가 크고 여기저기 연결되어있는 곳이 많고, 매니저와 PM 레벨에서 주로 필요한 내용이 정해져서 내려오니 개발자는 개발만 하면 되는 일이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사 일 적응하고 받은 티켓을 처리하는 데만 시간을 쏟다보니 처음 6개월 정도는 오너십이라는 건 생각도 못했다. 그러다 어느 순간 가벼운 매너리즘에 빠진 적이 있다. 뭔가 능동적으로 일한다는 느낌보다는 기계적으로 주어진 솔루션을 개발만 하고 있다는 생각이 들어서이다.&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;처음에는 회사의 구조, 일하는 방식이 문제라고 생각했다. 스타트업이 일하는 방식처럼 기획 단계에도 참여하고, 정해진 문제를 푸는 게 아니라 유저와 가까운 거리에서 직접 문제를 찾을 수 있다면 능동적으로 일할 수 있을 거라고 생각했다. 하지만 매니저나 PM 급이 아닌 이상 기획에 참여하기는 제한적이었고 이러한 환경에서도 주도성을 발휘할 수 있는 방법을 찾지 못해 헤맸다.&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;그 분을 관찰하며 이렇게 자신의 영역을 벗어나 다른 부분에도 호기심을 가지고 찾아보고 개선점을 찾는 등 주도적으로 일할 때 &lt;b&gt;기술적인 도전&lt;/b&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;&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;/li&gt;
&lt;li&gt;아웃풋 내기 : 조사한 것을 팀이 이해하기 쉽게 정리하여 공유하면서 디스커션이 필요한 부분을 제기한다. 디스커션에 참여하며 질문을 던지고 의견을 요청하고 나의 생각을 제안한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;잘 마무리하기 : 디스커션의 결론을 실행하고 스테이징에서 테스트한다. 팀에 공유하여 피드백을 받는다. 배포 후 프로덕션에서 테스트한다. 배포가 마무리되었다고 공유한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 이상적인 방식의 일하는 방법을 정리해보았다.&lt;/p&gt;
&lt;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 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;AI 시대에서 살아남는 개발자란!&lt;/h3&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;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;/li&gt;
&lt;li&gt;다양한 해결책을 비교하고 토론하는 능력&lt;/li&gt;
&lt;li&gt;테스트하고 검증하는 능력&lt;/li&gt;
&lt;li&gt;의문을 가지고 깊이 파고드는 능력&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;프로덕트와 사용자의 커넥션은 앞으로도 계속, 혹은 더 많아질 것이다. AI 가 생기면서 풀 수 있는 문제가 많아지기 때문에, 사람들은 더 편리함을 원할 것이라 생각한다.&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;b&gt;팀 내에서 능동적으로 일하는 태도&lt;/b&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;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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Other/기록</category>
      <author>MINGYUM</author>
      <guid isPermaLink="true">https://mingyum119.tistory.com/381</guid>
      <comments>https://mingyum119.tistory.com/381#entry381comment</comments>
      <pubDate>Mon, 9 Mar 2026 05:07:42 +0900</pubDate>
    </item>
    <item>
      <title>SQS 메시지 유실이 발생하는 원인을 CloudWatch 지표로 분석하기</title>
      <link>https://mingyum119.tistory.com/380</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SQS &amp;rarr; Consumer 파이프라인에서 메시지 수신이 실패한 상황에서 그 원인과 대응 전략을 회고하기 위한 글이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;무슨 일이 있었나?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SNS &amp;rarr; SQS &amp;rarr; Consumer 구조는 AWS에서 흔하게 쓰이는 패턴이다. 우리도 이 시스템을 채택하고 있었고 한 서비스가 하나의 큐를 리스닝하고 있는 구조이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그러나 운영 중에 서비스가 동작하지 않는다는 제보가 생겼고 큐를 확인했더니 메인 큐에 여러 메시지가 쌓여있는 것을 보았다.  &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;하지만 DLQ에는 쌓여있는 메시지가 0개였다.&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;실패된 메시지에 대해서는 3번 재시도 후 DLQ로 빠지고 DLQ의 메시지 수가 증가하면 알림이 트리거 되어야 한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;하지만 메시지가 DLQ에도 없고 메인 큐에서도 지속적으로 증가하지 않고 메시지가 증가했다가 사라지는 패턴을 반복하고 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 실패된 메시지가 재시도 되어 DLQ로 빠지지 못하고 메인 큐에 계속 쌓여있었을까?&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;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;큐가 소비되지 못하고 메시지에 쌓인 이유&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;우선 가장 근본적인 원인은 설정 오류로 인해 Consumer가 큐를 찾지 못하고 메시지를 소비하지 못한 것이 원인이었다.&amp;nbsp; 그래서 일정 기간 메시지가 큐에 쌓여있었고, Retention Period (1일) 이후에 자동으로 큐에서 삭제된 것이다.&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;1354&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4W2is/dJMcafL7zBs/iiMlMKwzzrG400IlDNQ560/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4W2is/dJMcafL7zBs/iiMlMKwzzrG400IlDNQ560/img.png&quot; data-alt=&quot;정상적으로 소비하는 플로우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4W2is/dJMcafL7zBs/iiMlMKwzzrG400IlDNQ560/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4W2is%2FdJMcafL7zBs%2FiiMlMKwzzrG400IlDNQ560%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;721&quot; height=&quot;197&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;정상적으로 소비하는 플로우&lt;/figcaption&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;SQS 메인 큐에 있는 메시지는 Consumer가 Polling 방식으로 ReceiveMessage API를 전송해 가져간다. Consumer가 메시지를 잘 받았다고 DeleteMessage API를 보내야 SQS는 '아 적어도 하나의 Consumer가 메세지를 잘 받았구나' 하고 안전하게 삭제할 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;DLQ로 메시지가 전달되지 않은 이유?&amp;nbsp;&lt;/b&gt;&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;1530&quot; data-origin-height=&quot;1430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ou7PF/dJMcabiEHgn/Hj9vmiep3xegy9SFhO8j51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ou7PF/dJMcabiEHgn/Hj9vmiep3xegy9SFhO8j51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ou7PF/dJMcabiEHgn/Hj9vmiep3xegy9SFhO8j51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fou7PF%2FdJMcabiEHgn%2FHj9vmiep3xegy9SFhO8j51%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;642&quot; height=&quot;600&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;1430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;DLQ는 메인 큐에서 일정 횟수 이상 리트라이된 메시지가 이동하는 곳이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;메시지가 Consumer로 전달될 때마다 메시지의 &lt;b&gt;RecieveCount가 1 씩 증가&lt;/b&gt;한다. Consumer에서 메시지를 처리하지 못하면 다시 재시도하는데, 이때 &lt;b&gt;MaxRecieveCount에 도달&lt;/b&gt;하게 되면 해당 메시지는 DLQ로 빠진다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;메시지가 리트라이가 되기 위해서는 Consumer가 메시지를 소비해야만 가능하다. 하지만 SQS와 Consumer의 파이프라인이 고장나있었기 때문에 리트라이가 되지 않았고, DLQ로 이동하지 못한 채 메인 큐에 쌓여있었던 것이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;대응을 위한 CloudWatch 지표 알아보기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;1.&amp;nbsp; NumberOfMessagesReceived / MessagesDeleted&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;비정상 구간에서 MessagesReceived가 0에 수렴하고, MessagesDeleted도 0에 가까웠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이건 Consumer가 처리를 시도했는데 실패했다는 뜻이 아니라,&amp;nbsp;아예 가져가질(Receive) 않았고, 따라서 지울(Delete) 수도 없었다는 의미다. 즉 Consumer가 정상적으로 큐를 읽고 있지 않았다.&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;2. &lt;b&gt;NumberOfEmptyReceives&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;정상적으로 polling하는 Consumer는 메시지가 없을 때도 ReceiveMessage를 날리고, 그 결과가 empty일 수밖에 없다. &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그래서 평소에는 이 지표가 어느 정도 나온다. &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;근데 비정상 구간에서는 EmptyReceives가 0이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이건 메시지가 없어서 empty가 아니라, 폴링 자체가 멈췄다는 뜻이었다. SQS-Consumer 파이프라인이 고장났음을 알아챌 수 있었던 중요한 지표임을 알게 되었다.&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;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;3. ApproximateAgeOfOldestMessage ⭐️&lt;b&gt;⭐️&lt;/b&gt;&lt;b&gt;⭐️&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;메인 큐 내에서 &lt;b&gt;가장 오래된 메시지&lt;/b&gt;의 나이 (큐에 들어온 이후로 유지된 기간) 에 대한 지표이다. 비정상 구간에서&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ApproximateAgeOfOldestMessage가 86,400초(즉, 1일) 근처에서 평평하게 유지되는 구간이 있었다.&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;958&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/etEaod/dJMcac9DZxz/pRdEeswK8BEJnerzXkpcgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/etEaod/dJMcac9DZxz/pRdEeswK8BEJnerzXkpcgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/etEaod/dJMcac9DZxz/pRdEeswK8BEJnerzXkpcgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FetEaod%2FdJMcac9DZxz%2FpRdEeswK8BEJnerzXkpcgK%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;414&quot; height=&quot;260&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;현재 큐 세팅에서 Retention Period가 1일이기 때문에, &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;가장 오래된 메시지는 24시간이 되는 순간 &lt;b&gt;만료로 삭제&lt;/b&gt;된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그래서 oldest age가 계속 올라가서 며칠이 되는 게 아니라, &lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1일 근처에서 더 이상 못 올라가고 유지되는 모양이 나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그렇기 때문에 이 지표는 Retention Period 보다 높아질 수 없고 이미 이 지표가 Retention Period와 같게 표시된다? 그러면 이미 여러 개의 메시지가 삭제된 상태일 것이다.   이렇게 삭제된 메시지는 DLQ에도 남지 않기 때문에, 조기에 발견하기 위해서 Retention Period보다 낮은 Threshold로 알림을 걸어놓고 모니터링하는 것이 중요하다.&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;알게된 점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ApproximateAgeOfOldestMessage라는 지표에 대해 잘 몰랐으며 메인 큐의 Retention Period가 존재함도 모르고 있었다. 하지만 이번 기회에 SQS에 대해서 이해할 수 있었고, 이 지표를 잘 모니터링하는 게 중요하다고 느꼈다.&lt;/li&gt;
&lt;li&gt;DLQ의 동작 원리에 대해 이해할 수 있었다. Spring Boot에서는 &lt;i&gt;SQSTextMessage.acknowledge()&lt;/i&gt;를 사용하여 '메시지를 잘 받았고 재시도 처리를 하지 않아도 된다'라는 신호를 보낸다. &amp;nbsp;만약 어느 Consumer에서도 이 신호를 받지 못하면 그 메세지는 DLQ로 넘어가지도 않고 메인 큐에 저장되어있다가 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Retention Period가 지나면 삭제된다.&amp;nbsp;&lt;/span&gt;&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;1148&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m2U2f/dJMcaaxhliY/ZDaIGbYITzJcnifiQdUCKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m2U2f/dJMcaaxhliY/ZDaIGbYITzJcnifiQdUCKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m2U2f/dJMcaaxhliY/ZDaIGbYITzJcnifiQdUCKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm2U2f%2FdJMcaaxhliY%2FZDaIGbYITzJcnifiQdUCKK%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;517&quot; height=&quot;137&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;즉, DLQ로 넘어가기 위해서는 적어도 Consumer가 Receive할 수 있어야 가능한 것이다. Consumer가 Receive 해서 여러 번 재시도 했을 때 실패하면 그제서야 DLQ 로 넘어갈 수 있는 것이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Server/MQ</category>
      <author>MINGYUM</author>
      <guid isPermaLink="true">https://mingyum119.tistory.com/380</guid>
      <comments>https://mingyum119.tistory.com/380#entry380comment</comments>
      <pubDate>Sat, 17 Jan 2026 04:31:43 +0900</pubDate>
    </item>
    <item>
      <title>일로, 여행으로 가득 채운 2025 하반기  &amp;zwj; </title>
      <link>https://mingyum119.tistory.com/379</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;2025가 끝나고 하반기를 돌아보았다.&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;b&gt;엄마와 함께 유럽 여행&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;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;그렇게 3개월 정도가 지나 엄마가 시간 여유가 생겨 유럽에 놀러오게 되었고, 내친김에 2개월 넘게 독일 살이를 결정하셨다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엄마와 시간을 보내면서 가장 놀라웠던 것은 엄마의 강인함이다. 워낙 안정성을 추구하시고 소녀같은 분이라 유럽 살이가 괜찮으실 지 걱정했는데, 필요한 것만 몇 개 알려드리니 혼자서 너무 잘다니셔서 놀랐다. 연고도 없는 곳에서 독일 근교로 혼자 1박 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;엄마 덕분에 한식도 엄청 먹었다. 재택할 때마다 오셔서 좋아하는 반찬으로 점심을 차려주시고, 내 친구들을 불러 서너번 저녁을 차려주시기도 했다. 아플때는 삼계탕도 해주셨다. 언어가 잘 통하지 않아 힘드셨을텐데 직접 약국에서 내 증상에 맞는 약을 사와주신 것도 무지 감동이었다. 항상 김치를 사먹어야해서 돈이 많이 들었는데, 내 친구들과 함께 대규모 김장을 해주고 가셔서 4개월 넘게 엄마가 만든 김치로 먹고 살았다. ㅎㅎ 이사도 도와주시고 의자나 자전거와 같이 부피가 있는 중고거래 할때도 같이 가주셨다.&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&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/FkbkB/dJMcahb3cbL/NCkJcBLzK2CpG1Q9x5pklk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FkbkB/dJMcahb3cbL/NCkJcBLzK2CpG1Q9x5pklk/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;1712&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-10-23-50-55 001.jpeg&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FkbkB/dJMcahb3cbL/NCkJcBLzK2CpG1Q9x5pklk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFkbkB%2FdJMcahb3cbL%2FNCkJcBLzK2CpG1Q9x5pklk%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;1284&quot; height=&quot;1712&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg6l75/dJMb99LQOk1/WxrrGVSPmoLhu3kj1Jt4s0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg6l75/dJMb99LQOk1/WxrrGVSPmoLhu3kj1Jt4s0/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;1712&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-10-23-50-55 002.jpeg&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg6l75/dJMb99LQOk1/WxrrGVSPmoLhu3kj1Jt4s0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg6l75%2FdJMb99LQOk1%2FWxrrGVSPmoLhu3kj1Jt4s0%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;1284&quot; height=&quot;1712&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;다시 한국으로 보내드릴 때는 조그만 선물과 함께 편지를 써드렸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;747&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPPm2V/dJMcaiouzPw/ZqHEej1TAkFtYwBccErd6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPPm2V/dJMcaiouzPw/ZqHEej1TAkFtYwBccErd6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPPm2V/dJMcaiouzPw/ZqHEej1TAkFtYwBccErd6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPPm2V%2FdJMcaiouzPw%2FZqHEej1TAkFtYwBccErd6K%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;1600&quot; height=&quot;747&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;747&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;자존심 강한 경상도 여자 둘은 공항에서 절대 서로 우는 모습을 보여주지 않았지만, 나는 편지쓰면서도 울었고 엄마 보내고 나서도 울었다 (ㅋㅋ) 엄마도 아마 편지 읽으면서 우시지 않았을까 싶다. 돈 많이 벌어서 더 많은 곳을 여행하게 해드려야겠다고 생각한 시간이었다.&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;b&gt;두번의 이사&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해에만 &lt;b&gt;네 번&lt;/b&gt;의 이사를 했다. 와우!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상반기에는 한국 서울 자취방을 정리하고 본가로 내려가는 이사, 그리고 베를린 첫 집에서의 이사.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하반기에는 베를린에서 주거지가 두 번 바뀌어서 두 번의 이사를 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;룸메이트의 아는 언니가 사는 집의 세입자로 들어가 Zelendorf라는 지역에서 5개월 정도를 살았다. 앰뷸런스와 자동차 소리, 술집의 시끄러운 소리가 밤마다 들리던 도시에서 살다가 한적하고 아파트 없이 단독 주택만 있는 남서 지역에 오니 좋았다. 중고 자전거를 사서 타고 다녔고, 여름이면 집 근처 호수에 가서 수영했다. 재택하는 날에는 햇살을 쬐며 마당에서 점심을 먹었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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/JoMK0/dJMcagc9ESe/G6thTVAIKD2W1G07LeGH91/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JoMK0/dJMcagc9ESe/G6thTVAIKD2W1G07LeGH91/img.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-11-00-09-45 004.jpeg&quot; style=&quot;width: 25.855%; margin-right: 10px;&quot; data-widthpercent=&quot;26.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JoMK0/dJMcagc9ESe/G6thTVAIKD2W1G07LeGH91/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJoMK0%2FdJMcagc9ESe%2FG6thTVAIKD2W1G07LeGH91%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rH6L0/dJMcafL4YFE/CqRXaVAYvfPUIW4fHlxk41/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rH6L0/dJMcafL4YFE/CqRXaVAYvfPUIW4fHlxk41/img.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-11-00-09-35 003.jpeg&quot; style=&quot;width: 45.9644%; margin-right: 10px;&quot; data-widthpercent=&quot;47.06&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rH6L0/dJMcafL4YFE/CqRXaVAYvfPUIW4fHlxk41/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrH6L0%2FdJMcafL4YFE%2FCqRXaVAYvfPUIW4fHlxk41%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;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byJFSm/dJMcafL4YFM/GGTCijKVp2TYF2nXExnKg0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byJFSm/dJMcafL4YFM/GGTCijKVp2TYF2nXExnKg0/img.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-11-00-09-45 005.jpeg&quot; style=&quot;width: 25.855%;&quot; data-widthpercent=&quot;26.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byJFSm/dJMcafL4YFM/GGTCijKVp2TYF2nXExnKg0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyJFSm%2FdJMcafL4YFM%2FGGTCijKVp2TYF2nXExnKg0%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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/bIzsTJ/dJMcafL4YFH/ZWYRIzkSkgKLZb3ZZoDNPK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIzsTJ/dJMcafL4YFH/ZWYRIzkSkgKLZb3ZZoDNPK/img.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-is-animation=&quot;false&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-11-00-09-21 001.jpeg&quot; style=&quot;width: 63.2558%; margin-right: 10px;&quot; data-widthpercent=&quot;64&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIzsTJ/dJMcafL4YFH/ZWYRIzkSkgKLZb3ZZoDNPK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIzsTJ%2FdJMcafL4YFH%2FZWYRIzkSkgKLZb3ZZoDNPK%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;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cn9BZM/dJMcacaKz6i/0rIbERab07yP7tobfpOPb1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cn9BZM/dJMcacaKz6i/0rIbERab07yP7tobfpOPb1/img.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-11-00-09-25 002.jpeg&quot; data-widthpercent=&quot;36&quot; style=&quot;width: 35.5814%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cn9BZM/dJMcacaKz6i/0rIbERab07yP7tobfpOPb1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcn9BZM%2FdJMcacaKz6i%2F0rIbERab07yP7tobfpOPb1%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;3024&quot; height=&quot;4032&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; &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;그러나 모종의 이유로 이사를 해야했기 때문에 한국에 다녀오는 2개월 동안에는 새 집을 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;친구들과 함께 네명이서 살 집을 찾다보니 Lichtenrade라는 지역의 비슷한 결의 2층짜리의 단독 주택으로 집을 구하게되었다. 아직 공사도 끝나지 않은 집이었으나 가격, 회사와의 거리, 집 근처의 분위기를 고려해서 좋은 집이라고 생각해 계약하였다. 공사가 끝난 상태에서 이사하고 나니 정말 집을 잘 구했다고 느꼈다. 바로 옆집에 사는 친절한 집주인분, 예쁜 인테리어, 넓은 거실과 부엌, 마당, 예쁜 뷰 .. 그리고 무엇보다 가구가 다 준비된 상태인게 대박이었다. 저렴한 가격에 너무 좋은 집을 저점매수했다는 것이 뿌듯했다. 그리고 내 방은 2층이고 테라스도 있다 !!!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에는 눈이 많이 왔는데 창밖의 눈 쌓인 풍경이 그렇게 예쁠 수가 없었다. 마음 같아서는 이 집에 오래오래 살고 싶었다. 별 보는 것에 취미 없었는데, 여기 이사와서 별이 너무너무 잘 보여서 별자리를 외우고 다닌다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-11-00-16-12 004.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pSPMG/dJMcafL4YFK/hIb8CKiP5laO30kquB1hek/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pSPMG/dJMcafL4YFK/hIb8CKiP5laO30kquB1hek/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pSPMG/dJMcafL4YFK/hIb8CKiP5laO30kquB1hek/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpSPMG%2FdJMcafL4YFK%2FhIb8CKiP5laO30kquB1hek%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;4032&quot; height=&quot;3024&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-11-00-16-12 004.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/figure&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/ctINzK/dJMcafL4YFI/6c3jK6uaep0RwtN5GXfrK1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctINzK/dJMcafL4YFI/6c3jK6uaep0RwtN5GXfrK1/img.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-11-00-16-12 003.jpeg&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctINzK/dJMcafL4YFI/6c3jK6uaep0RwtN5GXfrK1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctINzK%2FdJMcafL4YFI%2F6c3jK6uaep0RwtN5GXfrK1%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bER9Yh/dJMcafL4YFL/xaaRFwvdtW5ohpZcpegWNK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bER9Yh/dJMcafL4YFL/xaaRFwvdtW5ohpZcpegWNK/img.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-11-00-16-08 002.jpeg&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bER9Yh/dJMcafL4YFL/xaaRFwvdtW5ohpZcpegWNK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbER9Yh%2FdJMcafL4YFL%2FxaaRFwvdtW5ohpZcpegWNK%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1pltB/dJMcagc9ESd/M6Ik2QkIpPcIT3tGbHU3d1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1pltB/dJMcagc9ESd/M6Ik2QkIpPcIT3tGbHU3d1/img.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;KakaoTalk_Photo_2026-01-11-00-16-03 001.jpeg&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1pltB/dJMcagc9ESd/M6Ik2QkIpPcIT3tGbHU3d1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1pltB%2FdJMcagc9ESd%2FM6Ik2QkIpPcIT3tGbHU3d1%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;3024&quot; height=&quot;4032&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;아무튼 지금은 좋은 집에 만족하는 가격으로 살고 있어서 다행이다. 역마살 레전드인 한 해를 보냈다. 이제 이사는 그만하고 싶다.&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;b&gt;1인분 하는 개발자 되기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상반기에 어영부영 1인분도 못하던 시절을 생각해보면 그래도 꽤나 성장했던 하반기가 아닐까 싶다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일의 난이도가 쉬워지고 1인분을 할 수 있게 된 건 영어 실력이 늘은 덕분도 있다. 영어권 국가에서 살고 있고 글로벌 회사에서 일하고 있지만 실질적으로 영어를 할 수 있는 기회는 많지 않다. 환경에 던져지는 것은 운이지만 환경에서 원하는 성장을 하는 것은 본인 의지인 것 같다. 그래도 나름 영어로 회의하고 영어 공부를 따로 한 덕에 실력이 많이 늘었다. 원어민과 캐주얼 챗을 하는 것에는 무리가 없다.&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;b&gt;독일어 학원 다니기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로 시작한 공부가 있다면 독일어 공부이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11월부터 2개월 간 꽤나 빡센 독일어 학원을 다녔다. 왜 독일어를 배우는가, 라고 물어보면 딱히 할 말은 없다. 일상에서도 독일어 쓸 일이 많이 없고 회사에서도 영어를 쓰기 때문이다. 하지만 독일에서 독일어 배우는 건 의미있는 일이라고 생각한다. 수업 듣는게 좀 힘들긴 했지만 독일어 자체는 재미있는 것 같다. 식당에서 주문할 때 아주 간단한 독일어로 주문할 수 있는 것도 성과라면 성과다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2026 Q1에 독일어 A1 자격증을 따는 것이 목표이다.&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/bLL81O/dJMcagc9Fcz/ctqqbodByFXBkNIgcPBzm0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLL81O/dJMcagc9Fcz/ctqqbodByFXBkNIgcPBzm0/img.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;IMG_1037.JPG&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLL81O/dJMcagc9Fcz/ctqqbodByFXBkNIgcPBzm0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLL81O%2FdJMcagc9Fcz%2FctqqbodByFXBkNIgcPBzm0%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/booBbm/dJMcafefFl2/HkV1c5IHUbnXqoN3X7WCEk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/booBbm/dJMcafefFl2/HkV1c5IHUbnXqoN3X7WCEk/img.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;IMG_1109.JPG&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/booBbm/dJMcafefFl2/HkV1c5IHUbnXqoN3X7WCEk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbooBbm%2FdJMcafefFl2%2FHkV1c5IHUbnXqoN3X7WCEk%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBLiAg/dJMcagc9FcA/ldKDE5FtDqvXztUqgPU3WK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBLiAg/dJMcagc9FcA/ldKDE5FtDqvXztUqgPU3WK/img.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;IMG_1124.JPG&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBLiAg/dJMcagc9FcA/ldKDE5FtDqvXztUqgPU3WK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBLiAg%2FdJMcagc9FcA%2FldKDE5FtDqvXztUqgPU3WK%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;3024&quot; height=&quot;4032&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;&lt;b&gt;취미 굳히기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상반기에는 사람들과 이것저것 새로운 취미를 많이 시도해봤다면, 하반기에는 내 취미는 이거다! 할 수 있을 정도로 특정 활동에 시간을 많이 들였다.&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;두 번째는 운동이다. 요즘은 매주 수영, 배드민턴을 간다. 수영은 새로 시작했다. 호흡하는 거부터 시작했는데 2개월 정도 지나 이제 자유형을 어설프게 할 수 있다. 매주 수영 갈 때마다 실력이 느는게 느껴져서 재미있다.&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;&lt;b&gt;한국 다녀오기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3월 베를린에서 일을 시작한 이후 한국이 너무 그리웠다. 4월 즈음에 8월 말에 한국으로 가는 비행기 티켓을 예약했다.&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;&lt;b&gt;다음 해에는,&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업무 외에도 개인적인 개발 공부에 시간을 많이 투자하고 싶다. 스터디를 하는 것도 좋고, 마감기한을 정해두고 책을 읽는 것도 좋다.&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;</description>
      <category>Other/기록</category>
      <author>MINGYUM</author>
      <guid isPermaLink="true">https://mingyum119.tistory.com/379</guid>
      <comments>https://mingyum119.tistory.com/379#entry379comment</comments>
      <pubDate>Mon, 12 Jan 2026 05:09:38 +0900</pubDate>
    </item>
    <item>
      <title>  왜 OpenFeign과 Circuit Breaker를 함께 사용할까?</title>
      <link>https://mingyum119.tistory.com/378</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mingyum119.tistory.com/376&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.09.12 - [Server/Architecture] -   Resilience4J 라이브러리의 개념과 Circuit Breaker의 동작 과정&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757676675927&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;  Resilience4J 라이브러리의 개념과 Circuit Breaker의 동작 과정&quot; data-og-description=&quot;Resilience4j 란?fault tolerance (결함 허용) 라이브러리이다. 즉 오류나 장애가 발생해도 서비스가 중단되지 않게 안정적으로 도와주는 서비스이다. 이 기능을 구현하기 위한 여러 Resilience4j 모듈이 있&quot; data-og-host=&quot;mingyum119.tistory.com&quot; data-og-source-url=&quot;https://mingyum119.tistory.com/376&quot; data-og-url=&quot;https://mingyum119.tistory.com/376&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dHlCr1/hyZJp5wbR1/ZOOYhBlwUHdjzmQOC5Qhk1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cS1OaZ/hyZJdEFyCL/E9AVlMx8XvXBM5Pq72r1U1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/dtB1jc/hyZIYVYNkY/fOVcWGUEqseSdbwkCl6CjK/img.png?width=616&amp;amp;height=842&amp;amp;face=0_0_616_842&quot;&gt;&lt;a href=&quot;https://mingyum119.tistory.com/376&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mingyum119.tistory.com/376&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dHlCr1/hyZJp5wbR1/ZOOYhBlwUHdjzmQOC5Qhk1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cS1OaZ/hyZJdEFyCL/E9AVlMx8XvXBM5Pq72r1U1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/dtB1jc/hyZIYVYNkY/fOVcWGUEqseSdbwkCl6CjK/img.png?width=616&amp;amp;height=842&amp;amp;face=0_0_616_842');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;  Resilience4J 라이브러리의 개념과 Circuit Breaker의 동작 과정&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Resilience4j 란?fault tolerance (결함 허용) 라이브러리이다. 즉 오류나 장애가 발생해도 서비스가 중단되지 않게 안정적으로 도와주는 서비스이다. 이 기능을 구현하기 위한 여러 Resilience4j 모듈이 있&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mingyum119.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 어떻게 라이브러리의 목적이 무엇인지 알아보고, 이 목적을 구현하기 위한 여러 모듈 중 Circuit Breaker에 대해 알아보았다.&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://mingyum119.tistory.com/377&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.09.12 - [Framework/Spring] - Spring Cloud OpenFeign의 개념과 사용 방법 알아보기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757685170273&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Spring Cloud OpenFeign의 개념과 사용 방법 알아보기&quot; data-og-description=&quot;팀 코드를 살펴보다가 외부 서비스와 연동하여 API를 호출하기 위해 @FeignClient 라는 어노테이션을 사용하는 것을 보았다.어떤 원리로 REST API로 서비스와 연동을 하고 있는 지 파악하기 위해 글을 &quot; data-og-host=&quot;mingyum119.tistory.com&quot; data-og-source-url=&quot;https://mingyum119.tistory.com/377&quot; data-og-url=&quot;https://mingyum119.tistory.com/377&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cMlQDr/hyZJddBuh7/TbK663DrwUyhmNylzVenJK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/EDYAa/hyZJdxU8WK/kimTNyR20kz2w8sCF1MWq0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://mingyum119.tistory.com/377&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mingyum119.tistory.com/377&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cMlQDr/hyZJddBuh7/TbK663DrwUyhmNylzVenJK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/EDYAa/hyZJdxU8WK/kimTNyR20kz2w8sCF1MWq0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spring Cloud OpenFeign의 개념과 사용 방법 알아보기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;팀 코드를 살펴보다가 외부 서비스와 연동하여 API를 호출하기 위해 @FeignClient 라는 어노테이션을 사용하는 것을 보았다.어떤 원리로 REST API로 서비스와 연동을 하고 있는 지 파악하기 위해 글을&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mingyum119.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이어서 Spring Cloud OpenFeign은 외부 서비스와 연동해서 HTTP API 호출을 간단하게 하기 위한 툴이라고 설명하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두가지 라이브러리를 함께 사용하면 외부 서비스에게 HTTP API 호출을 보내는 상황에서 Circuit Breaker를 통해 장애를 탐지하고 자동으로 대응할 수 있다.&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;아래는 Configuration Properties 방식으로 OpenFeign과 Circuit Breaker를 설정한 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1757686016261&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  cloud:
    openfeign:
      circuitbreaker:
        enabled: true
        alphanumeric-ids: # 이름에 영문자와 숫자만 사용 가능하도록 하는 옵션
          enabled: true
resilience4j:
  circuitbreaker:
    instances:
      DemoClientgetDemo: # circuit breaker 이름
        minimumNumberOfCalls: 69&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;DemoClientgetDemo라는 이름의 Circuit Breaker에 대한 설정 정보를 입력하였다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757686673258&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@FeignClient(name = &quot;FeignClientName&quot;)
@CircuitBreaker(name = &quot;DemoClientgetDemo&quot;)
interface HelloClient {
    @RequestMapping(method = RequestMethod.GET, value = &quot;/hello&quot;)
    Hello getHello();
}&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;@CircuitBreaker 어노테이션을 클래스 레벨에 붙이면 모든 메서드에 해당 어노테이션을 적용한 것과 같은 효과를 준다.&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;메서드에 어노테이션을 붙이면 이전 게시글에서 말한 것처럼 모든 함수가 Circuit Breaker에 의해서 Protected function이 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 호출의 결과가 Circuit Breaker에 수집되고 일정한 개수 이상의 실패율이나 일정한 시간 이상 지연 시 CallNotPermittedException이 발생한다.&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;왜 OpenFeign과 Circuit Breaker를 자주 함께 사용할까?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 서비스로의 HTTP 요청에 의해서 네트워크 환경이 불안정해지는 사례가 많다.&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;그래서 실패를 감지해 장애 확산을 막아주는 장치가 필요하다. 즉 외부 API 호출로 인한 장애를 미리 감지하고 대응하기 위함이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-clou-feign-circuitbreaker-configurationproperties&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-clou-feign-circuitbreaker-configurationproperties&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757677057156&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Spring Cloud OpenFeign&quot; data-og-description=&quot;Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable &quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-clou-feign-circuitbreaker-configurationproperties&quot; data-og-url=&quot;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-clou-feign-circuitbreaker-configurationproperties&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-clou-feign-circuitbreaker-configurationproperties&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-clou-feign-circuitbreaker-configurationproperties&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spring Cloud OpenFeign&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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>Server/Architecture</category>
      <author>MINGYUM</author>
      <guid isPermaLink="true">https://mingyum119.tistory.com/378</guid>
      <comments>https://mingyum119.tistory.com/378#entry378comment</comments>
      <pubDate>Fri, 12 Sep 2025 23:29:29 +0900</pubDate>
    </item>
    <item>
      <title>  Spring Cloud OpenFeign의 개념과 사용 방법 알아보기</title>
      <link>https://mingyum119.tistory.com/377</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;팀 코드를 살펴보다가 외부 서비스와 연동하여 API를 호출하기 위해 @FeignClient 라는 어노테이션을 사용하는 것을 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 원리로 REST API로 서비스와 연동을 하고 있는 지 파악하기 위해 글을 작성한다.&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://github.com/OpenFeign/feign&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Feign&lt;/a&gt; 은 HTTP API 호출을 쉽게 해주는 자바 라이브러리이다.&amp;nbsp; Feign 에서 구현된 인터페이스와 어노테이션으로 HTTP API를 호출할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순수한 Feign을 사용해도 좋지만, Spring와 함께 사용해서 DI와 JSON 직렬화/역직렬화 기능을 사용한다면 더욱 확장성 있게 사용할 수 있다. Spring Cloud에서는 Feign을 Spring Boot 환경에서 쓸 수 있게 통합한 모듈로, &lt;b&gt;Spring Cloud OpenFeign&lt;/b&gt; 라이브러리를 도입했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  Spring Cloud란?&lt;br /&gt;Spring Cloud는 마이크로서비스를 지원하는 여러 모듈의 통합된 프로젝트이다.&amp;nbsp; Spring Boot가 개발 애플리케이션을 만드는 역할을 수행한다면, Spring Cloud는 서비스를 운영하기위해 필요한 기능 (로드밸런싱, 게이트웨이 등)을 개발한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Spring Cloud OpenFeign 사용하기&lt;/h3&gt;
&lt;pre id=&quot;code_1757678856086&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootApplication
@EnableFeignClients
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}&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;Spring Boot 애플리케이션에서 @EnableFeignClients 를 사용해 기능을 활성화한다.&lt;/p&gt;
&lt;pre id=&quot;code_1757679125834&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@FeignClient(&quot;stores&quot;)
public interface StoreClient {
    @RequestMapping(method = RequestMethod.GET, value = &quot;/stores&quot;)
    List&amp;lt;Store&amp;gt; getStores();

    @RequestMapping(method = RequestMethod.GET, value = &quot;/stores&quot;)
    Page&amp;lt;Store&amp;gt; getStores(Pageable pageable);

    @RequestMapping(method = RequestMethod.POST, value = &quot;/stores/{storeId}&quot;, consumes = &quot;application/json&quot;)
    Store update(@PathVariable(&quot;storeId&quot;) Long storeId, Store store);

    @RequestMapping(method = RequestMethod.DELETE, value = &quot;/stores/{storeId:\\d+}&quot;)
    void delete(@PathVariable Long storeId);
}&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;인터페이스에 @FeignClient를 통해 'stores' 라는 이름을 가진 Feign 클라이언트를 만들 수 있다. 이 이름을 활용해 Spring Cloud의 인스턴스와 연동해 사용할 수 있게 된다. 인터페이스의 메서드에 의해 실제로 HTTP 요청을 보내는 코드가 런타임에 자동으로 구현된다.&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;혹은 URL을 직접 지정해서 Spring Cloud의 디스커버리를 거치지 않고 바로 해당 주소로 요청을 보낼 수도 있다. 이 경우 Eureka와 같은 서비스 레지스트리가 필요 없고 고정 주소로 바로 거칠 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1757679510029&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@FeignClient(name=&quot;stores&quot;, url=&quot;http://localhost:8080&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;@FeignClient에서 지정하는 이름은 중요하다. 마이크로 서비스에서는 여러 서비스가 동작하는데, 각각 이름으로 인식되기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757679829275&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
    cloud:
        openfeign:
            client:
                config:
                    feignName:
                        url: http://remote-service.com
                        connectTimeout: 5000
                        readTimeout: 5000
                        loggerLevel: full
                        errorDecoder: com.example.SimpleErrorDecoder
                        retryer: com.example.SimpleRetryer
                        defaultQueryParameters:
                            query: queryValue
                        defaultRequestHeaders:
                            header: headerValue
                        requestInterceptors:
                            - com.example.FooRequestInterceptor
                            - com.example.BarRequestInterceptor
                        responseInterceptor: com.example.BazResponseInterceptor
                        dismiss404: false
                        encoder: com.example.SimpleEncoder
                        decoder: com.example.SimpleDecoder
                        contract: com.example.SimpleContract
                        capabilities:
                            - com.example.FooCapability
                            - com.example.BarCapability
                        queryMapEncoder: com.example.SimpleQueryMapEncoder
                        micrometer.enabled: false&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;configuration properties를 사용해서 설정하는 방식도 있다. 여기서 feignName은 @FeignClient에 지정된 이름과 일치해야한다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 포스팅에서는 OpenFeign으로 등록한 클라이언트 서비스를 Circuit Breaker에 활용하는 방법을 알아보겠다.&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;a href=&quot;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-cloud-feign&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-cloud-feign&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757677121051&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Spring Cloud OpenFeign&quot; data-og-description=&quot;Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable &quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-cloud-feign&quot; data-og-url=&quot;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-cloud-feign&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-cloud-feign&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-cloud-feign&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spring Cloud OpenFeign&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <author>MINGYUM</author>
      <guid isPermaLink="true">https://mingyum119.tistory.com/377</guid>
      <comments>https://mingyum119.tistory.com/377#entry377comment</comments>
      <pubDate>Fri, 12 Sep 2025 22:36:40 +0900</pubDate>
    </item>
  </channel>
</rss>