<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>우아한형제들 기술 블로그</title>
    <description>이 블로그는 배달의민족, 배민라이더스, 배민상회 등 Food Tech를 선도하는 우아한형제들 기술조직의 성장 일기를 다루는 블로그입니다.</description>
    <link>https://woowabros.github.io/</link>
    <atom:link href="https://woowabros.github.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 29 Jun 2021 13:05:41 +0900</pubDate>
    <lastBuildDate>Tue, 29 Jun 2021 13:05:41 +0900</lastBuildDate>
    <generator>Jekyll v3.9.0</generator>
    
      <item>
        <title>우테코에서 찾은 나만의 효과적인 공부법</title>
        <description>&lt;p&gt;안녕하세요. 테크코스교육개발팀 이원미입니다.
3기 크루들의 두 번째 방학 (부럽습니다..) 을 앞두고 레벨 2를 마무리하며 작성한 글을 공유합니다 : )&lt;/p&gt;

&lt;p&gt;이번 글쓰기의 주제는 “우테코에서 찾은 나만의 효과적인 공부법” 입니다. 우아한테크코스에서는 정해진 답이 없는 학습 방법을 정답이라며 알려주거나, 그를 통해 크루들을 일반화 시키지 않습니다.
학습의 방향성을 간단히 제시해 줄 뿐, 어떤 학습 방법을 선택하고 자신의 것으로 만들어 나아갈 것인지는 온전히 크루들의 몫으로 남겨두었어요.&lt;/p&gt;

&lt;p&gt;그 또한 배움의 과정이라고 생각하거든요 : )&lt;/p&gt;

&lt;p&gt;매번 같은 주제로 글을 쓰지만, 각 기수마다 그리고 크루들마다 깨달은 학습법이 다르다는 점과 글 속에서 특별한 인사이트를 얻을 수 있다는 점이 늘 흥미로운 것 같습니다.
크루들이 우테코 속에서 어떻게 학습하고 있는지 글을 통해 확인해 주세요.&lt;/p&gt;

&lt;p&gt;언제나 모든 미션에 최선을 다하는 크루들에게 감사의 말을 전합니다. ☺️&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-11/wooteco-3.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 style=&quot;font-size:40px; border-bottom: 1px solid gainsboro;&quot;&gt;소롱(최솔지)의 글&lt;/h1&gt;

&lt;h2 id=&quot;허영덩어리가-사는-법&quot;&gt;허영덩어리가 사는 법&lt;/h2&gt;

&lt;h3 id=&quot;궁금해하기&quot;&gt;궁금해하기&lt;/h3&gt;

&lt;p&gt;고등학생 때 수학 과외 선생님은 나를 귀찮아하셨다. 당장 수능을 앞두고도 진도를 빨리 나갈 생각이 없었으니까. 왜 이런 공식이 나왔죠? 이 문제는 왜 이렇게 풀어야 하나요? 이걸 풀면 뭐가 좋나요? &lt;strong&gt;저는 왜 공부해야 하죠?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;강산은 변해도 사람은 잘 바뀌지 않는다. 아직도 똑같은 고민을 하고 똑같이 일기에 쓴다. 그나마 내게 의욕을 불러일으키는 방법 하나를 소개할까 한다. 이 글은 &lt;strong&gt;공부를 지탱하는 법&lt;/strong&gt;에 가까울 수 있겠다.&lt;/p&gt;

&lt;p&gt;아직도 모르겠는 배움의 소용돌이 속, 허영으로 똘똘 뭉친 사람이 자존심 하나만으로 살아내는 법에 대하여.&lt;/p&gt;

&lt;h3 id=&quot;욕심내기&quot;&gt;욕심내기&lt;/h3&gt;

&lt;p&gt;인간은 사회적 동물이다. 누구나 사회적으로 인정받고픈 욕구가 있다. 이런 맥락에서, 재밌는 일을 직업으로 삼는가, 잘 하는 일을 하는가 질문을 던져보겠다. 내 의견은 분명하다. 잘 하는 일을 해야 한다. 일에는 성과가 있다. 좋은 성과를 내야 인정받을 수 있다. 일이 재밌기는 참 힘들다. 대신에 부수적인 부분에서 즐거움을 느끼면 어떨까?&lt;/p&gt;

&lt;p&gt;살면서 공부가 재밌다고 착각하게 되는 순간이 있다. 잘 살펴보면 공부 자체가 재밌다기보다, 공부 잘하는 나에 취해 살 때가 좋다. 내가 공부함으로써 성취하고픈 목표는 뚜렷하다. 남들이 나를 좀 추켜세워주면 좋겠다. 처음 우테코에 왔을 때 이런 부분이 충족되지 않으니 힘들었다. 공부를 더 하면 된다고? 나보다 이미 잘 하는 사람들이 같이 열심히 해서 간극이 좁혀지지 않는데 공허해하지 않을 사람은 없을 것이다.&lt;/p&gt;

&lt;p&gt;최근에 적극적 혹은 능동적이라는 피드백을 받았다. 세상에 마상에 수료할 때까지 이런 말을 들을 거라곤 상상도 못했다. 요즘 들어 내가 질문하는 빈도가 늘기는 했다. 그냥 나이 먹어서 뻔뻔해졌기 때문이라고 생각했다. 질문하기 창피해서 못하던 시절도 있었는데 이제는 아무려면 어떤가 싶다. 인생에 더 수치스러운 일도 많았는데 어찌저찌 철면피 깔고 살면 되더라. 헌데 이런 뻔뻔함이 남들이 보기에 좋아 보일 수도 있다고 생각하니 꽤 설레는 기분이랄까. 덕분에 요즘 &lt;strong&gt;사소한 일에 신경 안 쓰고 필요할 때는 적극적이 되는 당당한 사람&lt;/strong&gt; 컨셉으로 살기 위해 노력하고 있다. 스스로 보기에 제법 괜찮아서 만족스러웠다는 걸 여러분은 모르셨겠죠.&lt;/p&gt;

&lt;h3 id=&quot;티내기&quot;&gt;티내기&lt;/h3&gt;

&lt;p&gt;인간은 감각의 동물이다. 눈에 보이는 결과물이 있을 때 자신감도 상승한다. 레벨 2를 시작하면서 예쁜 노트를 샀다. 나는 아날로그를 사랑하는 사람이라 아직도 컴퓨터 데이터는 허구의 존재 같다. 언제 휘발될지 모르고 너무 가볍다. 그에 반해 필기는 얼마나 좋은지. 잉크가 닳고, 종이가 구겨지고, 손도 한 번씩 베이고.&lt;/p&gt;

&lt;p&gt;필기는 내 삶의 유구한 역사다. 초등학교 6년 내내 바른 글씨 쓰기 대회에서 상을 받았다. 중학생 때는 습작 노트가 열 몇권은 되었다. 고등학교 공부는 깜지만 썼다. 그리고 대학생이 되었을 때, 철학과는 시험을 어떻게 보냐고요? 먼저 팔 떨어지는 사람이 집니다. 결론은 뭔가 쓰지 않으면 공부한 느낌이 안 난다는 말이다. 패드를 사고 한동안 타자로 공부했던 적이 있는데 효과가 썩 좋지 않았다. 그 경험을 망각하고 &lt;strong&gt;개발자를 꿈꾸며 컴퓨터와 친한 나&lt;/strong&gt; 컨셉으로 공부했으니 지금까지 배운 내용들이 제대로 남았을 리 만무하다.&lt;/p&gt;

&lt;p&gt;오랜만에 수업을 노트에 필기하면서 정말 재밌었다. 앞에서 말한 바와 마찬가지로 공부가 재밌어지지는 않는다. 단지 그 필기감, ‘지금 이 단어 좀 예쁘게 잘 썼는데’ 할 때 소소한 즐거움이 좋다. 나는 손을 굉장히 잘 베는 편인데, 덕지덕지 붙은 반창고조차 뿌듯하다. 그렇다고 &lt;strong&gt;개발자를 꿈꾸며 컴퓨터와 친한 나&lt;/strong&gt; 컨셉을 관둔 것은 아닌지라 마지막 정리할 때는 디지털 감성을 확보한다. 결과적으로 복습도 한다는 뜻이고, 능률도 늘었다. 노란 뽀로로 반창고를 둘둘 감은 손가락이 마치 훈장 같아 코드를 칠 때도 괜히 어깨가 으쓱하고. 나는 참 재미있게 산다.&lt;/p&gt;

&lt;h3 id=&quot;아무튼-공부하기&quot;&gt;아무튼 공부하기&lt;/h3&gt;

&lt;p&gt;종합해보면 &lt;strong&gt;사소한 일에 신경 안 쓰고 필요할 때는 적극적이 되는데 아날로그 감성이 있어서 공부는 쓰면서 하지만 꿈은 개발자라 컴퓨터에 능통한 사람으로 살기&lt;/strong&gt;가 우테코에서 나의 공부법이다. 지금은 효과가 좋아서 계속해나가려고 하는데, 나중에 컨셉에 질리면 또 어떻게 바뀔지는 잘 모르겠다. 여기에 식욕까지 없어 보여야 완성인데 다소 힘든 감이 있다. 레벨 3 가면 프론트 분들과도 한잔해야 하고 그러니까, 유지만 열심히 해보는 걸로.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-11/wooteco-4.jpeg&quot; width=&quot;50%&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 style=&quot;font-size:40px; border-bottom: 1px solid gainsboro;&quot;&gt;웨지(성시형)의 글&lt;/h1&gt;

&lt;h2 id=&quot;웨지의-우아한-테크코스에서-찾은-나만의-학습법&quot;&gt;웨지의 우아한 테크코스에서 찾은 나만의 학습법&lt;/h2&gt;
&lt;p&gt;안녕하세요!! 웨지입니다.&lt;/p&gt;

&lt;p&gt;우테코에서 생활한 지 100일 정도 흘렀네요. 성격도 바뀌고, 삶의 목표도 바뀌고, 공부법도 바뀌고. 인생의 터닝포인트라고 부를만한 100일이었습니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;바뀐 나&lt;/code&gt;라는 주제로 6시간 정도 떠들고 싶지만, 여러분 고막도 보호해야하고  주제도 정해져 있으니 자제하겠습니다. 😉&lt;/p&gt;

&lt;p&gt;글쓰기 주제와 제목은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;우아한 테크코스에서 찾은 나만의 학습법&lt;/code&gt; 입니다.&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;난 이렇게 학습한다&lt;/code&gt;뿐만 아니라 나만의 학습법을 찾은 전체 이야기를 들려드릴 텐데요.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;내게 맞는 학습법을 찾아야 한다&lt;/code&gt; 라는 깨달음을 전달해드리고자 함입니다.&lt;/p&gt;

&lt;p&gt;우테코에 들어오기 전에는 하기 싫어도 꾸역꾸역 공부하던 나!&lt;/p&gt;

&lt;p&gt;이제는 시키지 않아도 척척 알아서 하는 착한 어른이가 되는데!&lt;/p&gt;

&lt;p&gt;시작합니당당당~~&lt;/p&gt;

&lt;h2 id=&quot;재미없어도-할-일은-해야지&quot;&gt;재미없어도 할 일은 해야지&lt;/h2&gt;
&lt;p&gt;우아한 테크코스에 들어오기 전에는 사실 공부가 재미없었어요.&lt;/p&gt;

&lt;p&gt;하지만 휴먼, 누가 공부에서 재미를 찾습니까? 재미는 취미에서 찾는 겁니다. 취미생활을 즐기려면 돈이 있어야 하지요. 그렇기 때문에 무적의 3단논법 등장.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;돈이 있으면 취미 생활을 누리며 즐겁게 살 수 있다.
공부를 하면 해당 지식을 이용해 돈을 벌 수 있다.
그러므로 공부를 하면 즐거울 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;무적의 3단 논법을 들이밀어도 공부를 시작하면 제 뇌는 강력하게 저항합니다.&lt;/p&gt;

&lt;p&gt;🧠 : 현재를 팔아서 미래를 살 셈이야…??&lt;/p&gt;

&lt;p&gt;🙄 : 30년 후에도 놀고 싶으면 지금 좀 해놓자…&lt;/p&gt;

&lt;p&gt;자기 설득과 인내의 과정이었답니다.&lt;br /&gt;
그러나 우아한 테크코스에서 공부가 재밌을 수 있다는 걸 깨닫고 맙니다! 어떻게?&lt;/p&gt;

&lt;h2 id=&quot;어떻게-공부가-재밌을-수-있어요&quot;&gt;어떻게 공부가 재밌을 수 있어요?&lt;/h2&gt;
&lt;p&gt;시간을 조금만 뒤로 돌려서, 우테코에 들어오기 전 개발 공부를 하며 TIL과 1일 1커밋 운동, 블로깅에 관심이 많았습니다. 롤모델인 조졸두님께서 앞서 해나가고 있었던 것이기 때문이었죠.
하지만 3번 시도해서 3번 실패하는데요.
조졸두님보다 의지력도, 열정도 약하기 때문이라 결론 내렸습니다. 어쩌겠어요? 전 그 정도밖에 안 되는 인간인걸요…… 흑흑&lt;/p&gt;

&lt;p&gt;시간이 흘러 우테코 레벨2를 시작하고 얼마 지나지 않은 어느 날, 이런 이력서를 가진 신입 개발자면 바로 채용한다는 내용의 &lt;a href=&quot;https://www.youtube.com/watch?v=Yc56NpYW1DM&amp;amp;t=784s&quot;&gt;유투브 영상&lt;/a&gt;을 보게 되었습니다.&lt;/p&gt;

&lt;p&gt;그분은 매일 양질의 커밋을 하며, 훌륭한 내용으로 가득 채운 블로그를 운영하고 계셨습니다. 그 영상을 보고 이번에야말로 1일 1커밋, 블로깅을 해보자 다짐합니다…..라고 할 뻔했으나!&lt;/p&gt;

&lt;p&gt;불현듯 깨달음이 옵니다! 전 이미 몹시 &lt;strong&gt;즐겁고 행복하게&lt;/strong&gt; 학습을 하고 있다는 걸요. 그러므로 굳이 남의 방법을 따라 할 필요가 없고, 저만의 길을 가면 됩니다.&lt;/p&gt;

&lt;p&gt;가슴이 웅장해진다…… 넷플릭스 켤지 인텔리제이 켤지 30분 고민하던 그 웨지가 맞나? 내 입에서 한 문장 안에 행복 + 학습 + 즐겁다는 단어가 동시에 나오는 날이 오다니. 무슨 일이 있었던 걸까요?&lt;/p&gt;

&lt;h2 id=&quot;나만의-학습법&quot;&gt;나만의 학습법&lt;/h2&gt;
&lt;p&gt;우테코 레벨1을 거치면서 빠르게 지식을 습득하기 위해 다양한 학습법을 테스트해 봤어요. 스터디, 독서, 인강, 노션 정리, 토론, 클론 코딩 등.&lt;/p&gt;

&lt;p&gt;그중 가장 효과를 본 것은 스터디와 남에게 설명해주기였습니다.&lt;/p&gt;

&lt;h3 id=&quot;스터디&quot;&gt;스터디&lt;/h3&gt;

&lt;p&gt;레벨1을 거치면서, 저는 사람에게서 에너지를 얻는다는 사실을 깨달았습니다. 제게 에너지와 영감을 준 레벨1 CU조, 우테코 여러분 다 사…사…사리 추가!!
사랑은 낯 간지러워서 도저히 못 하겠네요…… 어쨌든&lt;/p&gt;

&lt;p&gt;그 점을 학습에 이용하기 위해서 크루들과 함께 여러 스터디를 시도해 보았습니다. 그 중 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;모던자바인액션&lt;/code&gt; 스터디가 저에게 신선한 충격으로 다가오게 됩니다.&lt;/p&gt;

&lt;p&gt;단순히 서로에게 동기부여가 되는 수준을 넘어서 본인이 궁금했던 부분을 추가로 학습하여 공유하고, 주기적으로 모여 특정 주제에 관해 토론을 나누는 시간이 이어졌어요. 제가 잘 알지 못하는 분야에 대해 전문성을 가지고 있는 크루들이 자기만의 관점에서 토론과 학습을 풍성하게 해주었습니다. 또한, 의견이 다른 크루는 이야기를 나누면서 어떤 사고 흐름을 통해 결론에 도달했는지 이해하게 되었습니다. 맞는 것 같은 말 vs 맞는 것 같은 말을 비교하며 진실을 파악하는 비판적 사고력 또한 크게 늘었답니다.&lt;/p&gt;

&lt;p&gt;그런데 이 모든 과정이 ‘유익하다’를 넘어 &lt;strong&gt;즐겁다고&lt;/strong&gt; 느껴졌어요.
그래서 그 이후로 조금이라도 시간적 여유가 생기면 일단 슬랙에 스터디 공지부터 날립니다. 지금도 JPA, 도커, 배포, 스프링 시큐리티 스터디 열고 싶은데 몸이 하나라 꾹 참고 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;설명해보기&quot;&gt;설명해보기&lt;/h3&gt;

&lt;p&gt;또 다른 학습법으로는, 남에게 설명해보기가 있습니다. 추상적으로 알고 있던 지식을 말로 풀어 설명할 때, 구체적으로 아는 부분과 잘 모르는 부분을 깨달을 수 있습니다. 또 언어로 표현하는 과정 자체가 지식을 구체화하는 효과가 있습니다. 그래서 저는 누가 학습법을 물어보면 말로 풀어 설명해보는 것을 꼭 권해요.&lt;/p&gt;

&lt;p&gt;그리고 저는 남에게 뭔가 설명하는 것이 &lt;strong&gt;재밌습니다&lt;/strong&gt;. 아마 저한테 뭔가 물어보신 분들은 제가 흥분해서 설명하는 바람에 도망도 못 가고 ‘아 괜히 물어봤다……‘라고 생각해보신 경험이 있을 거예요.&lt;/p&gt;

&lt;p&gt;혹여나 제게 뭔가 물어볼 게 있으시다면 아무때나 말 걸어주시거나 DM 주세요. 제겐 포상입니다.&lt;/p&gt;

&lt;h2 id=&quot;혹시-눈치채셨나요&quot;&gt;혹시 눈치채셨나요?&lt;/h2&gt;
&lt;p&gt;제가 위의 단락에서 두 단어를 두껍게 처리했는데요, 바로 &lt;strong&gt;즐겁다고&lt;/strong&gt; 와 &lt;strong&gt;재밌습니다&lt;/strong&gt; 입니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;스터디&lt;/code&gt; 와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;말로 풀어 설명하기&lt;/code&gt;는 모두 좋은 학습법입니다. 그러나 그것보다 더 중요한 것은 다음 문장입니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;나와 맞는 방법인가?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TIL과 블로깅 또한 좋은 학습법입니다. 그리고 2단계 글쓰기로 올라오는 수많은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;좋은 학습법&lt;/code&gt;이 있겠죠. 다만 내게 맞는 방법은 내가 찾아야합니다.&lt;/p&gt;

&lt;p&gt;나만의 학습법을 찾은 이후로 나이 30 인생 처음으로 공부가 재미있습니다. 공부가 싫어 대학을 중퇴하고, 이런 일 저런 일 해봐도 재미가 없어 ‘인생은 취미생활을 즐기기 위해 존재한다.’ 는 가치관을 만든 저였습니다.&lt;/p&gt;

&lt;p&gt;지금은 “루터 올래?” 라는 말이 “피시방 갈래?” 보다 설렙니다. 제가 루터회관 지박령인 이유는 남들보다 열심히 하는 사람이라서가 아니라, 루터에 가는 게 재밌기 때문이에요.&lt;/p&gt;

&lt;p&gt;이 글을 보시는 분들도 자기만의 방식을 찾아, &lt;strong&gt;즐겁게&lt;/strong&gt; 학습했으면 좋겠습니다!!&lt;/p&gt;

&lt;h2 id=&quot;나만의-학습법을-찾는-방법&quot;&gt;나만의 학습법을 찾는 방법&lt;/h2&gt;
&lt;p&gt;자기만의 학습법을 찾기 위한 팁을 드리자면, 두려워 말고 시도해보세요. 해보기 전까지는 알 수 없습니다.&lt;/p&gt;

&lt;p&gt;우테코에서 처음 스터디를 모집할 땐 운영을 잘 못 하면 어쩌지, 크루들이 불편해하면 어쩌지, 실패하면 어쩌지 정말 고민이 많았습니다.&lt;/p&gt;

&lt;p&gt;하지만 누구나 처음은 있고 처음엔 미숙할 수밖에 없습니다. 그 사실을 되새기니 눈 딱 감고 시작할 수 있었습니다.&lt;/p&gt;

&lt;p&gt;그리고 실패에는 내성이 생겨요. 공부할 때만큼은 맘껏 실패해봐도 됩니다. 용기를 내서 시도해보고, 실패하고, 때로는 성공하고, 나만의 학습법을 만들어 가세요.&lt;/p&gt;

&lt;h2 id=&quot;마무리&quot;&gt;마무리&lt;/h2&gt;

&lt;p&gt;전에는 남들이 좋다고 하는 방식이 저한테 안 맞기 때문에 좌절하고 고민했었으나, 이제는 각자에게 맞는 방법이 따로 있음을 압니다. 그리고 나만의 방법을 찾은 지금은 자기 확신이 있습니다.
예전엔 스펙과 실력이 모자란 것이 고민이었지만, 지금은 시간이 모자란 것이 고민입니다. 시간만 주면 실력은 채울 자신이 있답니다. 호호&lt;/p&gt;

&lt;p&gt;이 자신감이야말로 가장 큰 자산이라고 생각해요. 정말 별것 아니었던 제가 나만의 학습법을 찾고 변화했듯이, 여러분 모두 나만의 학습법으로 각자의 자리에서 빛나시길 기원합니다.&lt;/p&gt;

&lt;p&gt;아, 그런데 제 학습법은 열정 있는 동료들이 필수조건이라서요…… ㅎㅎ 앞으로도 여러분의 도움이 필수입니다. 잘 부탁드리겠습니다. 😉&lt;/p&gt;

&lt;p&gt;-여러분에게 왕 빨대를 꽂은 웨지 올림&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-11/wooteco.001.jpeg&quot; width=&quot;50%&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 style=&quot;font-size:40px; border-bottom: 1px solid gainsboro;&quot;&gt;파노(전환오)의 글 &lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;학습에 고민을 가진 개발자들과 우테코 4기, 5기 차후 기수생들에게 도움이 되고자 글을 작성했습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;intro&quot;&gt;INTRO&lt;/h2&gt;

&lt;p&gt;끊임없이 소화해야 하는 지식들이 많습니다.
그래서 우아한테크코스 레벨2는 지치는 과정인 것 같아요.&lt;/p&gt;

&lt;p&gt;주변을 보면 배워야 할 것들에 압도되어 부담을 느끼는 사람이 많습니다. &lt;br /&gt;
저도 그중 한 명이고 여전히 극복 중에 있습니다.&lt;/p&gt;

&lt;p&gt;생각해보면 레벨2는 의도적으로 학습량에 부하를 주어서, 이를 극복하도록 해 자신만의 학습 방법을 만드는 시간이었던 것 같아요.&lt;/p&gt;

&lt;p&gt;레벨2로 올라와 언어 하나만이 아닌 다양한 기술을 배우고 사용하면서, 정립해본 제 학습 방법을 이야기해보려고 합니다.&lt;/p&gt;

&lt;h2 id=&quot;기술-배움-새로운-기술-도입하기&quot;&gt;기술 배움, 새로운 기술 도입하기&lt;/h2&gt;

&lt;h3 id=&quot;기술-선택하기&quot;&gt;기술 선택하기&lt;/h3&gt;

&lt;p&gt;우테코는 미션에서 사용할 기술을 강제하지 않습니다. 사용할 기술의 선택지는 넓습니다.&lt;/p&gt;

&lt;p&gt;기술을 배우기 이전에,  어떤 문제를 해결하고 싶은지 명확하게 정하고, 시중에 어떤 기술들이 존재하는지 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;메타정보&lt;/code&gt;를 파악하는 일이 가장 핵심이라고 생각해요.&lt;/p&gt;

&lt;p&gt;어떤 기술들이 존재하는지, 현재 트렌드는 어떤지, 각 기술의 장단점은 어떤지가 주요 키워드인 것 같네요. 기술은 계속 발전하고, 개발자들은 하나의 기술에 안주하지 않기에 이를 파악하는 일은 중요하다고 생각합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/fan/post/e929d797-72d4-400e-a735-7df1b7e15e3e/image.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;저는 개발자 서베이를 먼저 봅니다. 연 단위로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stack overflow survey&lt;/code&gt;나 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State of JS&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State of FE&lt;/code&gt;등 전 세계 개발자들을 대상으로 한 서베이들이 많습니다.&lt;/p&gt;

&lt;p&gt;이곳에서 동향 파악을 합니다. 어떤 기술들이 우세한지, 신진 기술들은 어떤 것이 있는지 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;기술 이름&lt;/code&gt;과 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;트렌드&lt;/code&gt;를 빠르게 파악할 수 있어요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/fan/post/b89a5789-156d-410e-bc1f-237a8443490e/image.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;다음은 기술에 대해 알기 위해 공식문서나 기술을 비교하는 블로그 아티클을 찾아봅니다.   &lt;br /&gt;
기술들은 사용자를 확보하기 위해 자신들의 정체성과 강점에 대해 PR합니다.  &lt;br /&gt;
다른 기술들과 비교를 하는 아티클도 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;블로그 아티클에서는 해당 기술을 먼저 사용한 사용자들의 경험을 쉽게 얻을 수 있어요.  &lt;br /&gt;
공식문서는 자신들의 장점만을 어필하기에 때로는 블로그 아티클에서 선택에 필요한 내용을 얻을 수도 있었습니다.&lt;/p&gt;

&lt;h3 id=&quot;기술-적용하기&quot;&gt;기술 적용하기&lt;/h3&gt;

&lt;p&gt;기술을 적용하기 위해 해당 기술의 전부를 파악할 필요는 없다고 생각해요. 물론 종국에는 전부 알아야 합니다.   &lt;br /&gt;
하지만 미션의 제한된 기간에 기술의 모든 것을 파악하는 일은 물리적 시간이 허락하지 않았습니다.&lt;/p&gt;

&lt;p&gt;저는 공식문서를 봅니다. 의문을 가질 수도 있을 것 같아요. 시간 없다면서 공식문서를 본다고?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/44419181/120099771-4dc62680-c178-11eb-8d6b-2f7dd31368be.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;대부분의 공식문서에는 크게 두 가지 섹션이 존재하는 듯합니다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;빠르게 주요 개념과 유즈케이스를 파악할 수 있는 Basic (Quick Start, Get Started, tutorial 등등)&lt;/li&gt;
  &lt;li&gt;디테일한 스펙이 기재되어 있는 Reference (API 등등)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;저는 먼저 Basic을 봅니다. 미션 진행에서 7~80%의 상황은 Basic에서 해결할 수 있었습니다.   &lt;br /&gt;
버전 업데이트가 빠른 기술영역에서, 공식문서는 가장 정확하고 최신의 내용을 담고 있습니다.&lt;/p&gt;

&lt;p&gt;실제로 React Testing Library를 배울 때, 업계에서 유명한 Velopert님이 작성한 튜토리얼을 학습하고 적용했었는데요. 이후에 공식문서를 보니 사용하는 방식이 바뀌어 적잖이 당황했던 적이 있습니다.&lt;/p&gt;

&lt;p&gt;기술을 적용하면서 의문이 드는 부분, 애매한 부분, 세세한 사용법을 Reference를 보면서 충당합니다.    &lt;br /&gt;
필요에 의해 학습하기에 기억에도 오래가고 보다 더 효율적이었습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/fan/post/4d30c36f-4e2d-4ab9-a973-0741becdc6e8/image.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이런 방식으로 레벨2 1~2달의 기간 동안 여러 기술들을 학습하고 적용을 해볼 수 있었습니다.&lt;/p&gt;

&lt;h2 id=&quot;구현-멈춤-모르는-개념이-나오면-잠시-멈추기&quot;&gt;구현 멈춤, 모르는 개념이 나오면 잠시 멈추기&lt;/h2&gt;

&lt;p&gt;미션들의 권장 수행 기간은 1~2주입니다. 시간이 지나면 바로 다음 미션으로 넘어갑니다.    &lt;br /&gt;
레벨2 과정 피드백 시간에 미션수행 기간이 타이트하다고 많은 크루들이 어려움을 표현했으니 넉넉하다고 생각할 수는 없는 기간입니다.&lt;/p&gt;

&lt;p&gt;그 기간 동안 기술을 배우고 미션을 수행하는데 마감일의 압박을 느끼게 되는데요.   &lt;br /&gt;
구현을 하다 모르거나 애매하게 알고 있는 부분이 나오면 ‘적당히 넘어갈까’ 혹은 ‘지금 구현하는 것만 마치고 찾아볼까’라는 유혹이 생기기도 합니다.&lt;/p&gt;

&lt;p&gt;하지만 여기서 생각해볼 점은 우리는 학습 중에 있다는 것입니다.&lt;/p&gt;

&lt;p&gt;해결법, 사용법만 알고 넘어가면 나중에 다시 같은 문제를 만났을 때, 또 검색을 하고 있는 자신을 발견할 수 있었어요.&lt;/p&gt;

&lt;p&gt;몇 번의 경험 이후로 모르는 것을 만나면 확실하게 알고 넘어갑니다.  &lt;br /&gt;
다만 여기서 주의해야 할 점은 찾는 정보의 중요성을 생각해보고, 검색 시간의 상한선을 정해야 한다는 점입니다.&lt;/p&gt;

&lt;p&gt;마냥 검색하는데 정보가 쉬이 나오지 않으면 나뿐이 아닌 페어의 정신력도 소모되고, 그래서 눈치도 보이고 힘들어져요.   &lt;br /&gt;
이때는 질문방에 질문을 올리거나, 코치들께 질문하는 것이 빠른 방법이 될 수 있을 것입니다.&lt;/p&gt;

&lt;p&gt;이렇게 얻은 정보들은 경험과 필요에 의해서 얻은 정보들이기에 기억 속에서 쉽게 사라지지 않았습니다.&lt;/p&gt;

&lt;h2 id=&quot;직접-찾는--이것도-적용해볼-수-있을까&quot;&gt;직접 찾는 +@, 이것도 적용해볼 수 있을까?&lt;/h2&gt;

&lt;p&gt;학습 내지는 메타데이터를 모으고 다니다 보면, 관련 기술에 대한 곁가지 키워드들을 알게 됩니다.   &lt;br /&gt;
또는 리뷰어분들이 추가 학습을 위한 키워드들을 던져주는 경우도 있는데요.  &lt;br /&gt;
이런 키워드들에서 미션에 적용할 수 있는 것들을 발견하는 경우가 있었고 그 내용을 적용해보는 지점에서 학습이 일어났습니다.&lt;/p&gt;

&lt;p&gt;최근 저의 경우는 에러 처리에 대한 고민에서 나온 것이었어요.    &lt;br /&gt;
API를 요청할 때 발생하는 비동기 에러를 어떻게 처리할 수 있을까에 대한 내용을 생각하던 차에&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/fan/post/bdc229b3-efc1-4f2e-a850-cc81ba98c6fc/image.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;토스에서 주최한 컨퍼런스 슬래쉬21에서 리액트 에러바운더리와 서스펜스 컴포넌트에 대한 키워드를 알게 되었습니다.    &lt;br /&gt;
이를 미션에 적용해보고, 리뷰어분의 피드백을 받으면서 해당 부분에 대한 학습을 할 수 있게 되었습니다.&lt;/p&gt;

&lt;h2 id=&quot;마무리-1&quot;&gt;마무리&lt;/h2&gt;

&lt;p&gt;레벨2 마무리가 일주일 남았지만, 아직 학습을 하는 방법이 완벽하지는 않은 것 같아요.      &lt;br /&gt;
하지만 이렇게 계속 시도해보고, 경험하면서 점진적으로 개선하는 과정이 긍정적이라 느낍니다.&lt;/p&gt;

&lt;p&gt;여러 방법을 나열했지만 이들을 관통하는 하나의 키워드를 꼽자면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;필요&lt;/code&gt;입니다.  &lt;br /&gt;
필요하다 느끼지 않은 학습은 효율적이지 않았습니다. &lt;br /&gt;
학습이 효율적이지 않았던 분들은 지금부터 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;필요한 학습&lt;/code&gt;을 해보면 어떨까요?&lt;/p&gt;

&lt;p&gt;이 글을 읽는 분들도 제 경험을 발판 삼아 또 다른 여러 방법들을 시도하고 공유를 하면 어떨까 생각해요.  &lt;br /&gt;
여기서 글을 마치도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-11/wooteco-2.jpeg&quot; width=&quot;50%&quot; /&gt;
&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 style=&quot;font-size:40px; border-bottom: 1px solid gainsboro;&quot;&gt;손너잘(손민성)의 글 &lt;/h1&gt;

&lt;h2 id=&quot;익사&quot;&gt;익사&lt;/h2&gt;
&lt;p&gt;모든 학문은 계층적인 구조를 띠고 있다고 생각한다. 따라서, 추상화된 상위계층을 제대로 이해하기 위해서는 조금 더 구현에 가까운 그 아래 계층에 대한 이해가 필요하다고 생각한다.&lt;/p&gt;

&lt;p&gt;이런 논리를 기반으로, 새로운 기술을 익히는데 항상 그 아래 단계를 이해하기 위해 노력했다.
곱셈을 할 줄 알더라도, 덧셈을 모르면 곱셈을 하는 행위에 의미를 부여하지 않았다.
지금까지 그렇게 공부해왔고, 그 효과는 나름 좋았다고 자부한다.&lt;/p&gt;

&lt;p&gt;기존의 추상화된 지식들을 공부할 때, 추상화를 걷어내면 언제나 엄청난 양의 새로운 지식들이 쏟아져 나온다. 즉, 추상화로 인해 감춰져 있던 지식의 바다를 마주하게 된다.
그러면 나는 항상 스스로 그 바다에 뛰어든다. 그렇게 몇 번 허우적거리고 나면, 어느 순간 지식의 바다는 잠잠해지고 그 안에서 평온함을 느끼고 있는 나 자신을 바라볼 수 있다.&lt;/p&gt;

&lt;p&gt;하지만 짧은 기간 안에 나에게 주어진 일을 수행해야 하는 상황에서, 수많은 사람들이 10년이 넘는 시간 동안 쌓아 올린 기술을 맞닥뜨렸을 때 나는 더 이상 지식의 바다에서 평온함을 느끼지 못했다.&lt;/p&gt;

&lt;p&gt;제한된 시간의 압박과 아무리 허우적거려도 잠잠해지지 않는 지식의 바다는 나를 지치게 만들었고 그렇게 나는 익사하고 말았다.&lt;/p&gt;

&lt;h2 id=&quot;추상화된-지식들&quot;&gt;추상화된 지식들&lt;/h2&gt;
&lt;p&gt;한동안은 제대로 공부를 못했다. 지식 사이에서 평온함을 느껴야 하는데 계속 죽어 나가기만 하니 내가 무엇을 하고 있는지 스스로를 자각하지 못하게 됐다.
스프링이라는 거대한 지식을, 한 번에 이해하려고 덤볐다가, 오히려 잡아먹힌 기분이었다.&lt;/p&gt;

&lt;p&gt;이 굴레에서 벗어나기 위해 코치님들과 참 많은 상담을 했고 공통적인 피드백을 받았다.&lt;/p&gt;

&lt;p&gt;“일단 많은 기능을 경험해 보는 것에 초점을 맞춰라.”&lt;/p&gt;

&lt;p&gt;내가 가장 싫어하는 행위였다.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;곱하기가 있다면, 일단 곱하기를 사용하고, 나누기가 있다면 일단 나누기를 사용해 보라. 그리고 왜 그렇게 되는지는 나중에 생각해 보라.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;나는 이런 행위를 ‘추상화된 지식의 사용’ 이라고 부른다. 그리고 나는, 추상화된 지식을 사용하는 것을 극도로 싫어했다.
그래서, 피드백을 받은 이후로도 나는 계속해서 스프링이라는 거대한 지식에게 덤벼들었고, 죽어 나가기를 반복했다.&lt;/p&gt;

&lt;p&gt;그러다가 코치님에게 한 문장을 듣고나서 나의 생각은 완전히 바뀌었다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“객체의 책임은 작게 나누면서, 왜 학습은 그렇게 하지 않나요?”&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;협력하는-객체들의-공동체&quot;&gt;협력하는 객체들의 공동체&lt;/h2&gt;
&lt;p&gt;지금까지 나는 모든 학습들을 객체에 비유해서 생각해왔다. 그런데, 왜 학습을 객체로 비유하면서 객체지향의 원칙은 적용시키지 않았을까?&lt;/p&gt;

&lt;p&gt;스프링이라는 거대해 보이는 기술도, 하나씩 작게 보면 결국 작은 지식들의 집합이다. 그리고 작은 지식들은 서로에게 협력하며 거대한 지식을 만들어낸다.&lt;/p&gt;

&lt;p&gt;그 사실을 잊고, 거대한 지식을 한번에 수용하려고 하니 당연히 실패할 수 밖에 없었다. 학습을 작게 나누고 내 머릿속에 만들어진 작은 지식들의 집합에서 협력관계를 통해 전체를 바라봤어야 했다.&lt;/p&gt;

&lt;p&gt;기술을 작은 단위로 바라보고 공부를 시작했다. 스프링 그 자체를 공부하는것이 아닌, 스프링에 적용된 기술을 작은 단위로 나누고 그 작은 단위의 지식의 바다에 빠져들기를 반복했다.&lt;/p&gt;

&lt;p&gt;그리고 그제서야 나는 다시 평온함을 찾을 수 있었다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-11/wooteco-3.jpeg&quot; width=&quot;50%&quot; /&gt;
&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 11 Jun 2021 09:00:00 +0900</pubDate>
        <link>https://woowabros.github.io/techcourse/2021/06/11/techcourse-level2-retrospective.html</link>
        <guid isPermaLink="true">https://woowabros.github.io/techcourse/2021/06/11/techcourse-level2-retrospective.html</guid>
        
        
        <category>techcourse</category>
        
      </item>
    
      <item>
        <title>우아한형제들 기획자 소개와 개발자와의 협업문화 인터뷰</title>
        <description>&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#이기호--디렉터급-pm&quot; id=&quot;markdown-toc-이기호--디렉터급-pm&quot;&gt;이기호 / 디렉터급 PM&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#전소영--배민셀프서비스-기획자&quot; id=&quot;markdown-toc-전소영--배민셀프서비스-기획자&quot;&gt;전소영 / 배민셀프서비스 기획자&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#최세지--배민서비스-기획자&quot; id=&quot;markdown-toc-최세지--배민서비스-기획자&quot;&gt;최세지 / 배민서비스 기획자&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#이나영--배민쇼핑라이브-기획자&quot; id=&quot;markdown-toc-이나영--배민쇼핑라이브-기획자&quot;&gt;이나영 / 배민쇼핑라이브 기획자&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#김용훈--배민상회-기획자&quot; id=&quot;markdown-toc-김용훈--배민상회-기획자&quot;&gt;김용훈 / 배민상회 기획자&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#기획자-김현정--개발자-우태균--b마트서비스&quot; id=&quot;markdown-toc-기획자-김현정--개발자-우태균--b마트서비스&quot;&gt;기획자 김현정 ∙ 개발자 우태균 / B마트서비스&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#기획자-김해니--개발자-송인태--라이더서비스&quot; id=&quot;markdown-toc-기획자-김해니--개발자-송인태--라이더서비스&quot;&gt;기획자 김해니 ∙ 개발자 송인태 / 라이더서비스&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;끊임없이 도전하고 혁신하는 우아한형제들!&lt;/strong&gt;&lt;br /&gt;
그 중심에는 가치 있는 서비스를 설계하며&lt;br /&gt;
‘좋은 것을 더 좋게’ 만들기 위해 도전하는 기획자분들이 있습니다.&lt;/p&gt;

&lt;p&gt;이번 인터뷰에서는 기획자분들을 만나보겠습니다.
&lt;img src=&quot;/img/2021-06-07/main.png&quot; alt=&quot;main&quot; style=&quot;width:100%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;들어가기 전에&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;안녕하세요, 인터뷰로 다시 찾아온 인재영입팀 입니다.&lt;br /&gt;
이번에는 두 가지 컨셉의 인터뷰를 진행하였습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;첫 번째 컨셉, 우아한형제들 기획자 단독 인터뷰&lt;/strong&gt;&lt;br /&gt;
우아한형제들의 기획자분들이 가치 있는 서비스를 설계하기 위해&lt;br /&gt;
도전 과제의 목표와 목적을 어떻게 정의하고 문제를 해결하며 일하고 있는지 인터뷰를 통해 알아봤습니다.&lt;br /&gt;
기획 문화와 기획자분들의 성장스토리, 면접 꿀팁이 넘쳐요!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;두 번째 컨셉, 우아한형제들의 기획자와 개발자의 담화 형식의 인터뷰&lt;/strong&gt;&lt;br /&gt;
기획자와 개발자가 도전 과제들을 수행하며 협업하는 과정을 엿볼 수 있었습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;우아한형제들에서 배민다움을 실천하며&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;‘좋은 음식을 먹고 싶은 곳에서’의 서비스 가치와 성과를 만들어가는 아홉 분을 지금 만나보세요. :)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;∙ 본 인터뷰는 방역 수칙을 철저히 준수하여 진행되었습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/recruit.jpg&quot; alt=&quot;recruit&quot; style=&quot;width:80%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;&lt;/p&gt;
&lt;center&gt;이번 인터뷰를 진행한 우아한형제들 구성원들을 소개합니다.  &lt;/center&gt;
&lt;center&gt;좌측부터 시계방향으로 포토팀 김봉우, 인재영입팀 배소은 ∙ 김형우 ∙ 이태형, 포토팀 장진명  &lt;/center&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;center&gt;우아한형제들 지원을 고민하시는 기획자분들께서는  &lt;/center&gt;
&lt;center&gt;제게(인재영입팀 배소은) 언제든 &lt;a href=&quot;https://www.linkedin.com/in/jessicabae/&quot;&gt;메시지&lt;/a&gt; 주세요. :)  &lt;/center&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/img/2021-06-07/lkh001.png&quot; alt=&quot;lkh001&quot; style=&quot;width:30%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;이기호--디렉터급-pm&quot;&gt;이기호 / 디렉터급 PM&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;담당업무 소개&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-우아한형제들에서-맡고-있으신-주요-역할에-대해-소개-부탁드립니다&quot;&gt;Q. 우아한형제들에서 맡고 있으신 주요 역할에 대해 소개 부탁드립니다.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;배달의민족부문에서 배민플랫폼실과 배민B2B서비스실을 맡고 있습니다.&lt;/strong&gt; 먼저, 배달의민족 플랫폼(이하 배민)에서 제공하는 가치는 배민앱 사용자와 라이더, 그리고 사장님이라는 각기 다른 니즈를 가진 사용자들을 만족시킬 때 비로소 상승하는데, &lt;strong&gt;그중 저희 실은 사장님을 위한 기획/개발/운영을 담당하고 있습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;배민B2B서비스실&lt;/strong&gt;은 사장님이 배민에서 장사를 하시며 앱에 최적화된 광고 상품으로 매출을 올릴 수 있도록 하고, 배민사장님광장이라는 사장님을 위한 사이트를 통해 상품과 서비스를 소개하여, 배민 플랫폼 입점 프로세스를 만들고 운영합니다. 또한 배민 서비스를 이용하는 사장님 가게에 대한 모든 앱 서비스를 설정할 수 있는 셀프서비스 또한 제공하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;배민플랫폼실&lt;/strong&gt;은 배민앱에서 비즈니스가 동작하기 위해 필요한 기본 데이터인 업주, 가게, 메뉴, 쿠폰에 대한 정보들을 생성하고, 관리하고, 운영하는 곳입니다. 또한 사용자가 주문한 이후에 사용자 전용의 안심번호를 제공하고, 주문 정보를 사장님의 가게로 전달하는 역할과 사장님이 주문을 확인할 수 있는 “배달의민족 주문~”이라는 소리가 울리는 접수 채널을 만드는 일을 하고 있습니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;조직 성과 관리&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-배민플랫폼실과-b2b서비스실을-관리하시며-가장-중요하게-생각하시는-것은-무엇인가요&quot;&gt;Q. 배민플랫폼실과 B2B서비스실을 관리하시며 가장 중요하게 생각하시는 것은 무엇인가요?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;실장으로서의 역할에서 제가 중요하게 생각하는 것과 제가 맡고 있는 두 실에서 해야 하는 주요 역할로 나누어 이야기 드릴게요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;먼저, 제가 실장으로 꼭 지키려고 염두에 두고 있는 건 두 가지입니다. 첫 번째는 팀이 빠르게 달리면서 목표를 잃지 않고 방향을 잘 잡을 수 있도록 도와드리는 것, 두 번째는 팀에서 리소스가 부족하거나 혹은 프로젝트에 집중하다 보면 놓칠 수 있는 것을 서포트하는 역할&lt;/strong&gt;을 하고 있어요.&lt;/p&gt;

&lt;p&gt;예를 들어 소개하면 저희는 매달 타운홀(이라는 이름의 공개 미팅)을 진행하고 있는데 이때 한 달 동안 있었던 자체 성과를 공유합니다. 배달의민족 서비스는 정말 큰 시스템이기에 각 팀이 담당하는 기능은 전체 시스템의 작은 일부일 수밖에 없어요. 팀에서 만들어낸 결과물이 어떤 비즈니스적인 가치가 있는지, 어떻게 사장님이 사용하고 계신지 설명해드리고 있어요. 또한, 실직속 데이터 분석가분들과 각 팀들의 과제를 같이 풀어나가고 있어요. 우아한형제들은 데이터서비스실에서 잘 관리해 주시는 분석용 데이터베이스에서 거의 대부분의 서비스 데이터를 추출해서 업무에 활용할 수 있지만 데이터 분석을 업무에 잘 활용하는지 여부는 팀 구성원의 개인기에 달려 있는 경우가 많아 실직속으로 데이터 관련한 업무를 서포트할 수 있는 분석가를 두고 같이 협업하고 있어요.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;배민플랫폼실과 B2B서비스실이 배달의민족 플랫폼에서 해야 할 가장 중요한 역할은 저장하고 있는 데이터의 활용 가능성을 넓히면서, 안정적으로 시스템을 운영하는 것이라 생각합니다.&lt;/strong&gt; 여기서 데이터의 활용 가능성을 넓힌다는 것에는 정말 많은 의미가 담겨있어요. 저희가 가지고 있는 데이터는 대부분 사장님을 통해서 만들어지는데, 사장님의 가게/메뉴/광고/쿠폰 등 다양한 정보들을 사장님과 사용자가 모두 만족할 수 있을만한 형태로 저장하고 관리해야 해요. 예를 들어 사장님은 메뉴 이름을 길고 화려하게 적고 싶을 수 있지만, 사용자는 그렇게 적혀 있는 게 눈에 잘 들어오지 않을 수 있거든요. 다양한 데이터로 확장하는 노력들을 꾸준히 하면서도 그 노력이 사장님과 사용자 모두 만족할 수 있는 형태여야 해서 시스템을 기획할 때 장기적인 운영 방향을 그리면서 만들어가고 있습니다.&lt;br /&gt;
&lt;img src=&quot;/img/2021-06-07/lkh002.jpg&quot; alt=&quot;lkh002&quot; style=&quot;width:60%; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;과제 수행 과정&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-배민에서-가장-기억에-남는-프로젝트와-도전적인-과제를-성공적으로-이끈-대표적-사례를-소개해-주실-수-있나요&quot;&gt;Q. 배민에서 가장 기억에 남는 프로젝트와 도전적인 과제를 성공적으로 이끈 대표적 사례를 소개해 주실 수 있나요?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;최근에 작업한 배달대행사와 협업하여 시스템을 연동하고 배달 예상 시간과 사장님의 주문 접수 방법을 고도화한 프로젝트를 소개해드리고 싶어요.&lt;/strong&gt; 배민앱에서 배민라이더스와 번쩍배달 외에 나머지 카테고리의 주문은 배민에서 직접 배달하는 것이 아니라 가게 사장님이 계약하신 배달대행사를 통해서 배달이 이뤄지고 있습니다. 사용자 입장에서는 주문한 음식이 정확하게 언제 오는지, 오고 있는지를 확인하고 싶지만 저희도 음식이 픽업되었는지 주문한 사용자에게 도착되었는지를 알 수 없었어요. 이 문제를 해결하기 위해서 올초부터 일부 &lt;strong&gt;배달대행사와 협업하여 저희가 사장님께 제공하는 주문접수채널에서 배달대행사의 라이더를 바로 호출할 수 있도록 지원하여 사장님께는 편의성을 높이고, 연동된 배달대행사에서 음식을 픽업하고 사용자에게 도착하였는지 등의 데이터를 받아 사용자에게 알려드리고 있습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;또한 이렇게 쌓은 정확한 데이터를 기반으로 분석하여, 음식 주문과 동시에 &lt;strong&gt;배민 서비스 사용자가 음식을 받기까지의 소요시간을 이전보다 정교하게 계산하고 예측해서 리스트에 보여드리는 작업까지 진행&lt;/strong&gt;이 되었어요. 아직 서울 지역에 일부 사장님만 사용하고 계시지만 점차 확대할 생각입니다. 이 작업을 하면서 여러 번에 걸쳐 사장님들을 오프라인으로 찾아뵙고 가게에 필요한 시스템이나 환경 설정도 해드리고 인터뷰도 했는데요, 저희가 
“엇 이건 좀 어려워서 잘 쓰기 어려우실 것 같은데?”라고 생각했던 부분들도 사장님들이 본인들 상황에 맞춰서 너무 잘 사용하시고 많은 의견까지 내주셔서 재미있었던 기억이 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;그리고 20년 4월에 오픈 서비스라는 상품을 롤백했던 이야기를 드리고 싶어요.&lt;/strong&gt;&lt;br /&gt;
최근 면접 때 한 지원자분이 “작년에 신규 상품을 런칭하고 사회적 이슈가 되어 롤백을 결정하고 롤백 한 걸 본 적이 있는데, 그때 분위기가 어땠는지 궁금하다.”라는 질문을 주셔서 저도 그때의 상황을 다시 생각해 봤어요. 일 년이 넘게 준비해서 4월 1일에 오픈한 상품을 5월 1일에 롤백 하는 건 구성원들 입장에서는 행복한 경험은 아니었어요. 하지만 그 일이 있어 &lt;strong&gt;플랫폼이 해야 하는 역할, 사회에서 우리가 해야 하는 역할의 중요성에 대해서 다시 생각해 볼 수 있는 계기가 되었고, 그 기간 이후 회사의 많은 의사 결정들이 이전보다 성숙해졌다고 생각해요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;다시 프로덕트만 집중해서 떠올려보면, 롤백을 결정하고 저희는 5개월 넘게 개발해서 서비스에 적용한 기능을 2-3주 안에 제거해서 과거 버전으로 돌아가야 했어요. 롤백 결정 이후, 빠르게 4월 1일 이전으로 돌아갈 것과 유지할 것을 정리하고 체계적으로 개발해서 진행했습니다. 매일 관련 기획자들이 스탠드업을 해서 서로 싱크를 맞추고, 5월 1일 버전의 서비스를 준비했고, 정말 2-3주 안에 모든 준비를 마쳤어요. 이때 같이 일하면서 
&lt;strong&gt;“이 사람들, 진짜 프로페셔널하게 일한다.”라고 생각했죠. 이미 결정된 롤백 의사결정을 따르면서, 각 도메인 담당자들이 자기가 해야 할 일들을 기계처럼 찾아 정리하고 개발하는 걸 보았고, 10-15개 정도 되는 개발팀이 엮인 일이었음에도 불구하고 계획한 일정에 차질이 없도록 막힘없이 진행되어 신기했습니다.&lt;/strong&gt; 좋은 성과를 낸 프로젝트는 아니지만, 마이크로서비스 아키텍처로 시스템이 많이 나눠져 있음에도 불구하고 정말 빠른 속도를 발휘했고, 완수하고 나서도 느낀 점이 많았던 프로젝트라 말씀드렸어요.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;역량에 관한 생각&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-기호님께서-경험으로-배운-기획자에게-중요한-역량에는-무엇이-있을까요-또한-특별히-그-역량을-중요하게-생각하시는-이유가-있으신가요&quot;&gt;Q. 기호님께서 경험으로 배운 기획자에게 중요한 역량에는 무엇이 있을까요? 또한, 특별히 그 역량을 중요하게 생각하시는 이유가 있으신가요?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;기획자는 각 상황에서 자기가 풀고 있는 문제가 어떤 문제냐에 따라 필요한 능력이 다르다고 생각해요. 그만큼 한 두 가지의 기준으로 역량을 판단하기가 어렵고 여러 가지 능력을 밸런스 있게 갖춘 분들이 일을 잘하시는 것 같아요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;먼저 기획자로서 무엇을 해결해야 하는지 정확하게 이해하고, 해결해야 하는 문제에 집중하는 능력이 가장 중요하다고 생각해요.&lt;/strong&gt;&lt;br /&gt;
기획자에게 커뮤니케이션 능력이나 전반적인 스케줄을 조정하는 능력도 필요하지만, 이건 모두 어떤 문제를 해결할 것인지, 그 문제의 우선순위가 어떻게 되는지를 정확하게 파악한 다음에 일어나는 일이거든요. 무슨 일을 해야 할지 정확하게 파악하지 못한 채 일하면 기획자 뿐만 아니라 그 기획자와 같이 일하는 많은 사람들이 시간을 낭비하게 되죠. 그래서 시간이 조금 걸리더라도 프로젝트 초반에 문제를 파악하고  그에 관해 팀 전체와 합의를 이루게 하는 능력이 중요해요.&lt;/p&gt;

&lt;p&gt;또한, 문제에 집중하는 능력은 이전보다 점점 더 중요해지고 있는데요. &lt;strong&gt;배민에서 기획자를 잘하려면 다양한 직군의 다수의 사람들과 이야기해야 합니다.&lt;/strong&gt; 예를 들어 가게시스템에 있는 배달팁을 기획하는 기획자라면, 본인이 기획한 배달팁의 로직을 가게시스템으로 개발하는 일뿐만 아니라 셀프서비스팀과 논의해서 사장님이 셀프서비스에서 어떻게 직접 설정하실 수 있는지 이야기해야 하고, 배민앱 사용자 서비스를 만드는 배민서비스실에 가서 앱에는 어떻게 표시할지, 주문에서는 어떻게 처리를 해야 할지 논의해야 해요. 그다음 사장님에게 어떻게 가이드 할 것인지 사업실과 논의하고, 고객서비스실과 광고가입센터에도 기획된 내용을 전파해야 합니다. 이렇게 다수의 사람들과 대부분의 구성원이 재택으로 일하는 환경에서 온라인으로 이야기를 나누다 보면 본인이 풀고 있는 문제를 놓치거나 다양한 의견에 휘말려서 처음 풀려고 했던 문제를 놓칠 수 있어요.&lt;br /&gt;
&lt;strong&gt;커뮤니케이션을 많이 하더라도, 본인이 해결하고자 하는 문제와 목표에 집중하여 놓치지 않는 능력이 필요하다고 생각합니다.&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;우아한형제들의 문화&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-배민플랫폼실과-b2b서비스실-두-실의-가장-좋은-협업-환경을-소개해-주세요&quot;&gt;Q. 배민플랫폼실과 B2B서비스실 두 실의 가장 좋은 협업 환경을 소개해 주세요.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;서로 다른 팀끼리 협업을 잘 하기 위해서는 두 가지가 전제되어야 해요. 다른 사람의 업무에 대한 이해와 존중, 이게 그 두 가지인데요.&lt;/strong&gt; 전사적으로도 잘 유지되고 있지만, 저희끼리 타팀에 대한 이해와 존중을 더 잘하기 위해서 노력하고 있어요.&lt;br /&gt;
&lt;strong&gt;한 달에 한 번 있는 실 타운홀 시간에 타 팀에서 하고 있는 과제 중 2-3개를 소개하는 시간이 있고, 이때 단순히 어떤 과제를 하고 있다고 공유하는 것이 아니라, 어떤 고민이 있었고, 어떻게 풀어보았고, 어떤 것을 배웠는지 공유하고 있어요.&lt;/strong&gt; 또한 사업 과제 목표 중심으로 모여서 서로 공유하는 시간을 갖기도 합니다. &lt;strong&gt;예를 들어서 사장님이 입점하는 프로세스를 개선하고자 &amp;lt;시너지 회의&amp;gt;라는 걸 만들어서 주간으로 운영&lt;/strong&gt;하고 있어요. 
입점 프로세스를 개발하는 셀프서비스팀과 광고가입센터를 운영하는 광고운영팀이 매주 만나서 실제 사장님과 통화한 내용이나 발생한 이슈를 공유하고 정책과 프로세스, 시스템 그리고 어떻게 사장님과 커뮤니케이션할 것인지도 정리하고 있어요. 이런 활동들을 통해 다른 팀이나 다른 직군의 업무와 활동들을 이해하는 시간을 가지면서 협업하여 결과를 만들고 있습니다.&lt;/p&gt;

&lt;p&gt;저희 실만 하는 건 아니지만, &lt;strong&gt;부문에서 제가 사회자로 진행하고 있는 &amp;lt;시스템 이슈 회의&amp;gt;를 소개해드리고 싶어요.&lt;/strong&gt; 작년 4월부터 진행했었고, 처음엔 한 달에 한 번 모여서 발생한 장애 회고를 공유하는 시간으로 시작했어요. 이름도 시스템 이슈 회의가 아니라 시스템 장애회의였고요. &lt;strong&gt;한두 달 진행하다 보니, 자연스럽게 장애 내용 뿐만 아니라 각 팀에서 시스템을 더 잘 만들기 위해서 고민했던 것을 공유하는 자리가 되었고 현재 1년째 진행하고 있습니다.&lt;/strong&gt; 한때 한 팀에서 스프링부트 버전업을 하면서 작은 장애가 있었고, 그 내용을 타 팀에 시스템 이슈 회의때 위키로 정리해서 공유하여 버전업하는 다른 팀들도 참고했던 기억이 있습니다. 사소한 내용이더라도, 본인들이 배운 내용을 문서로 정리하고 다른 사람들에게 공유해서 같이 성장할 수 있는 환경을 구축하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/lkh003.jpg&quot; alt=&quot;lkh003&quot; style=&quot;width:40%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;마무리하며&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-기호님과-같은-리더로서의-성장을-꿈꾸는-기획자분들에게-커리어-조언-부탁드립니다&quot;&gt;Q. 기호님과 같은 리더로서의 성장을 꿈꾸는 기획자분들에게 커리어 조언 부탁드립니다.&lt;/h3&gt;
&lt;p&gt;제일 어려운 질문이네요. 커리어 조언이라고 하면, ‘장기적인 안목을 가지고 좋은 기획자로 성장하기 위해서 어떤 경험을 하셔라.’라고 말씀드려야 할 것 같은데, 사실 저는 그렇게 계획성 있는 커리어 패스를 만들지 못했어요. 저는 게임회사에서 SNS나 메신저를 만드는 일을 하다가, 스타트업에 가서 데이팅서비스를 만들었고, 모바일 게임회사에서 데이터 분석과 인게임 마케팅을 제공하는 시스템을 만들었고, P2P금융에 가서 서비스를 만들다가 우아한형제들에 합류했어요. 하나의 도메인에서 커리어를 잘 만들어가신 분들을 보면서 부러울 때도 있었지만, 제가 기획자로 일한 기간은 나름 행복한 시간이었던 것 같아요. 여러 회사에서 여러 서비스를 만들면서 같이 일하는 사람들과 밤늦게까지 고민하고, 시도 때도 없이 일 이야기하고, 새벽에 오픈하기 위해서 사무실에 앉아서 수다 떨면서 대기하고, 오픈하고 QA하고 … 제 SNS에 이때 사진들이 많이 남아있는 걸 보면 이렇게 일했던 시간들이 저한테 즐거운 시간이었던 것 같아요.&lt;br /&gt;
&lt;strong&gt;프로덕트를 만들고, 그 프로덕트가 실제 생각한 대로 동작하도록 만들기 위해서 필요한 일들을 이것저것 하면서 재미있게 지내다 보니, 지금처럼 개발자와 협업하기 위해 개발 이야기를 조금 할 수 있고, 디자이너와 협업할 수 있고, 성과 분석을 위해 어떤 데이터를 봐야 하는지 정도는 알 수 있게 되었습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;현재 하고 있는 일에 더 집중해보세요. 이 일을 성공시키려면 내가 뭘 더 해야 할까? 이 일을 성공시키기 위해 내가 지금 당장 하고 있는 방법 외에도 좋은, 효율적인 다른 방법은 없는지 의심하고, 문제를 깊숙하게 들여다보며 해결책을 찾아보고, 실행하다 보면 잘하게 되고, 잘하면 재미있고, 재미있으면 더 잘하게 됩니다. 굉장히 단순한 loop이면서도, 처음 재미를 느끼는 순간을 발견하는 것이 쉽지는 않아요. 그렇지만 아주 작은 재미라도 찾게 된다면, “아 내가 이걸 재미있어 하는구나”라는 걸 인식하고, 일에서의 재미를 더 찾으려고 노력해보셨으면 합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;color:gray; font-size: 100%; text-align: Center;&quot;&gt;&lt;a href=&quot;https://career.woowahan.com/?keyword=&amp;amp;category=jobGroupCodes%3ABA005002&amp;amp;jobCodes=BA007014,BA007015#recruit-list&quot;&gt;기획직군 모집공고 바로가기&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/jsy001.png&quot; alt=&quot;jsy001&quot; style=&quot;width:30%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;전소영--배민셀프서비스-기획자&quot;&gt;전소영 / 배민셀프서비스 기획자&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;담당업무 소개&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-배민셀프서비스팀의-팀장으로서-맡고-있는-역할에-대해-소개해-주세요&quot;&gt;Q. 배민셀프서비스팀의 팀장으로서 맡고 있는 역할에 대해 소개해 주세요.&lt;/h3&gt;
&lt;p&gt;우아한형제들에는 배민앱으로 주문하는 B2C 고객 외에 B2B 고객인 가게 사장님도 있습니다.&lt;br /&gt;
&lt;strong&gt;배민셀프서비스팀은 B2B 고객을 위해 크게 두 가지 서비스 영역을 관리하고 있는데요. 배달의민족에 입점하기 위한 계약, 승인 시스템과 입점 후에 사장님이 더 쉽고, 효율적으로 가게 관리(메뉴, 정산 등)를 하실 수 있도록 돕는 배민셀프서비스의 기획, 개발, 운영을 담당&lt;/strong&gt;하고 있어요.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;저는 두 플랫폼의 방향성과 목표를 설정하고, 팀 내 기획자분들에게 세부 프로젝트를 분배하거나 일정을 관리하는 일을 담당&lt;/strong&gt;하고 있습니다. 플랫폼을 만들고 운영하다 보면 크고 작은 결정사항들이 있는데, 기획자분들이 혼자 결정하기 어려운 부분을 함께 의논하고 결정하기도 합니다.&lt;/p&gt;

&lt;p&gt;또한, 저희 팀은 목적 조직으로 기획, 개발이 함께 모여 일하고 있는데요. 플랫폼을 만드는 디자인, QA 담당자분들과 함께 데일리 회의를 진행하면서 일의 진행 상황과 팀원들의 컨디션 등을 체크합니다. 월별 회고, 분기별 워크숍을 통해 어떤 플랫폼을 만들고 싶은지에 관한 방향성을 조절하기도 하고요. &lt;strong&gt;이러한 팀 공동의 목표 외에도 기획, 개발 파트를 구성하여 직군별 1:1 면담을 통해 개인의 성장과 고민도 함께하며, 성장을 위한 활동을 장려하고 있습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;협업 방식&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-여러-직군이-함께-일하는-목적조직-팀에서는-협업-체계가-중요할-것-같습니다-협업을-위해-특별히-고려하시는-사항프로세스-툴-등이-있나요&quot;&gt;Q. 여러 직군이 함께 일하는 목적조직 팀에서는 협업 체계가 중요할 것 같습니다. 협업을 위해 특별히 고려하시는 사항(프로세스, 툴 등)이 있나요?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;요구 사항을 수집하고 전달할 때 싱크 회의에서 리뷰 시간을 꼭 가지려고 해요. 구성원들이 생각하는 목표점을 하나로 맞추고 작업을 해야 수정하는 상황을 최소화할 수 있기 때문입니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;그리고 &lt;strong&gt;다양한 목표와 생각을 하나로 맞추기 위한 요소로 여러 툴을 사용&lt;/strong&gt;하는데요&lt;br /&gt;
&lt;strong&gt;디자인과 협업을 위해 Figma를 사용하고 정책문서와 Task의 진행 상황을 확인하기 위한 용도로는 Wiki 와 Jira&lt;/strong&gt;를 활용하고 있어요. 하나의 요구 사항에도 목적과 목표에서부터 구현, 배포 일정까지 여러 직군(기획, 개발, 디자인, QA, 사업 등)간의 커뮤니케이션이 필요해요. 이렇게 다양한 부서와의 협업이 필요하다 보니 효율적으로 커뮤니케이션하기 위해 사소한 것까지도 Wiki 나 Jira에 기록하려고 노력합니다. &lt;strong&gt;Jira는 배포 단위로 관리하고, 상태를 통해 Task의 진행 상황을 확인할 수 있도록 합니다. 많은 사람들이 효율적으로 일할 수 있는 업무 규칙과 프로세스를 함께 만들고 상황에 맞게 변경하기도 합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;또한, 플랫폼을 운영하는 과정에서 개선사항 또는 버그가 팀이 소화할 수 있는 업무량을 초과할 때가 있는데요. 이럴 때 팀에서는 &lt;strong&gt;특정 단위(스프린트)로 운영 개선 과제를 진행하고 있어요. 보통 2주 단위로 기획에서 개선이 필요한 항목들을 나열하고 개발에서는 Jira에 적힌 내용(요구 사항, 우선순위 등)을 확인해서 기간 내 가능한 Task를 확정하고 개발, 검수 과정을 거친 후 배포합니다. 이러한 프로세스를 운영하는 데는 몇 가지 이유가 있는데요.&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;첫 번째는 플랫폼의 안정성과 퀄리티를 유지하기 위해서이고, 두 번째는 해결해야 하는 문제들의 중요도나 시급성을 검토해서 일의 우선순위를 정하기 위해서입니다.&lt;/strong&gt; 지금 당장 급해 보이는 이슈들이 시간이 지나면 이미 해결되어 있거나, 더는 해결해야 하는 이슈가 아닌 것으로 변할 때가 종종 있기 때문이기도 합니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;성취의 순간과 과정&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-소영님께서-가장-기억에-남는-성취의-순간과-그-과정을-이야기해주세요&quot;&gt;Q. 소영님께서 가장 기억에 남는 성취의 순간과 그 과정을 이야기해주세요.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;2019년 4월에 진행했던 먼데이 프로젝트가 가장 기억에 남습니다. 먼데이 프로젝트는 비즈니스적으로는 비즈니스 모델의 확장, 기술적으로는 모놀리틱 아키텍처를 마이크로 서비스 아키텍처(MSA)로 전환한 큰 프로젝트였습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;프로젝트 규모와 영향 범위가 넓다 보니 회사에서도 큰 결정을 내리게 됐는데요. 3개월 동안 아주 시급한 사안을 제외한 모든 신규 프로젝트를 중단하고 먼데이 프로젝트에만 집중하기로 했습니다. &lt;strong&gt;그렇게 TF 인원이 100명을 넘는 거대 프로젝트가 시작되었어요. 배달의민족 시스템 전반을 약 3개월이라는 기간 안에 개편하기 위해서는 빠른 의사 결정, 정확한 커뮤니케이션 등이 필요했습니다.&lt;/strong&gt; 저는 5명의 Project Manager중(개발 3명, PMO 1명, 기획 1명) 기획 PM 역할을 담당했고, 주요 정책들을 결정했습니다. &lt;strong&gt;프로젝트를 오픈하는 날, 모두가 카운트다운을 하면서 배포를 시작했고 박수를 치며 프로젝트 완수를 축하했던 그날의 떨림과 설렘이 아직도 생생하게 기억납니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;이 프로젝트가 특히 기억에 남는 이유&lt;/strong&gt;는 먼데이 프로젝트 전에 받았던 요구 사항 때문인데요. 보통 플랫폼 기획자에게는 어떤 문제가 있고, 어떤 것을 개선하거나 구축해달라는 명확한 요구 사항이 전달되지만 이와 다르게 &lt;strong&gt;프로젝트 목표를 스스로 찾아야 했습니다.&lt;/strong&gt; “이 프로젝트는 어떤 것을 해야 하나요?”라는 질문을 던졌을 때, 제게 돌아온 건 불편사항 100개가 적힌 엑셀 시트였습니다. 2박 3일 정도 엑셀 파일이랑 싸움했던 것 같아요. 불편사항을 분류하고, 가장 크고 많은 것을 해결하는 방법이 무엇인지 분석하여 목표들을 세울 수 있었습니다.&lt;/p&gt;

&lt;p&gt;그중 많은 목표가 먼데이 프로젝트를 통해 달성되었어요. 유연해진 도메인 시스템들은 비즈니스의 확장에 더 잘 대응할 수 있게 되었고, 남은 목표들도 더 빠르게 달성할 수 있었습니다. 이는 자연스럽게 매출 증가까지 이어졌고요. &lt;strong&gt;이 프로젝트를 통해 수많은 사람이 하나의 목표를 함께 달성하는 기쁨과 벅참을 알게 되었고, 어떤 프로젝트도 해낼 수 있을 것 같은 자신감을 얻게 되었습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/jsy002.jpg&quot; alt=&quot;jsy002&quot; style=&quot;width:60%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;성장이야기&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-플랫폼-기획자로서의-역량을-강화하기-위해-어떤-노력을-기울이셨는지-궁금합니다&quot;&gt;Q. 플랫폼 기획자로서의 역량을 강화하기 위해 어떤 노력을 기울이셨는지 궁금합니다.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;가장 먼저, 제가 맡게 된 플랫폼이 어떤 역할을 해야 하는지를 명확하게 정의하려고 노력해요.&lt;/strong&gt; 저는 배달의민족에 입점하기 위해 업주, 가게, 광고 등의 정보를 받고 승인할 수 있는 플랫폼을 담당하고 있는데요. 종종 플랫폼 범위 외의 요구 사항을 전달받았을 때 그 일을 해야 할지 말지를 판단하기 위한 기준이 되어줍니다. 그리고 플랫폼의 역할을 정의하는 과정에서도 이후에 역할 범위를 어떻게 확장할지에 대한 아이디어가 떠오르기도 해요.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;역할을 명확하게 정의한 후에는 여러 부서(사용자, 운영, 사업 등)의 니즈를 이해하고 조율하려고 노력해요.&lt;/strong&gt; 예를 들면 사장님들이 가게 입점 신청을 할 때, 정보를 최소한으로 받고 쉽게 신청하게 할 것인지 아니면 최대한 정확하게 정보를 입력받고 승인해 주는 운영 부서의 효율을 높일 것인지와 같은 서로 다른 의견이 존재할 때가 있습니다. 이럴 때 &lt;strong&gt;양측 니즈를 최대한 만족시킬 수 있는 최선의 해결방안을 찾으려고 노력합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;이러한 해결방안을 찾기 위해서는 시스템 구성을 아는 것이 무엇보다 중요합니다.&lt;/strong&gt; 주문 시스템을 담당할 때는 개발자가 DB 설계를 할 때 의견을 주고받기도 하고, 데이터가 어떻게 흘러가는지, 어느 시점에 어떻게 통신하는지 등을 이해하려고 노력했어요. 이런 노력은 장애가 발생하면 어디가 문제인지 좀 더 쉽게 추측할 수 있도록 해주기도 하고, 플랫폼 성능 향상을 위해서 어디를 개선해야 할지를 찾아낼 수 있게도 해줍니다. 그리고 가장 좋은 건 개발자와 커뮤니케이션을 쉽고 정확하게 할 수 있게 된다는 점이에요.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;마지막으로 좋은 플랫폼을 만들기 위해서는 지구력이 필요하다고 생각하는데요.&lt;/strong&gt; 플랫폼을 만들고 나면 잘 운영되고 있는지, 제거해야 할 비효율적 요소가 있지는 않은 지 등을 지속적으로 살펴야 합니다. 새로운 비즈니스 요구 사항에 맞춰 어떻게 확장되어야 할지 고민하고 개선해야 하기도 하고요.&lt;br /&gt;
&lt;strong&gt;이러한 반복적인 작업이 완성도 높은 플랫폼을 만들어 준다고 생각해요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;우아한형제들 기획 문화&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-미래의-동료들에게-회사와-팀-자랑을-해주세요&quot;&gt;Q. 미래의 동료들에게 회사와 팀 자랑을 해주세요!&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;저희 팀은 ‘셀프서비스’라는 플랫폼을 통해 어떻게 하면 가게 사장님들이 매출을 더 쉽게 올리고, 편리하게 가게 운영을 하실 수 있을지 고민하고 있습니다.&lt;/strong&gt; 얼마 전에 사장님 커뮤니티에서 “배민셀프서비스 진짜 최고네요”라는 글을 본 적이 있는데요. &lt;strong&gt;우리가 만들고 있는 플랫폼이 고객에게 가치를 제공한다고 느끼는 순간이 가장 행복합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;저희 팀은 이렇게 &lt;strong&gt;가게 사장님들에게 의미 있고 좋은 가치를 제공하겠다는 하나의 목표로 기획, 개발이 함께 일하고 있는 팀입니다.&lt;/strong&gt; 얼마 전에는 팀 동료분이 팀에 대한 소개로 “친절과 배려가 많지만 협업할 때는 적극적이고 긍정적으로 피드백하며 가장 좋은 결과를 내기 위해서 노력합니다”라고 한 줄 소개를 써 주셨는데요. &lt;strong&gt;좋은 동료들과 함께 좋은 결과를 만들어나가고 싶은 분들은 결코 후회하지 않으실 거라고 확신합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;저는 우아한형제들에 입사해서 8년째 다니고 있는데요.&lt;/strong&gt; IT업계에서 한 직장에 이렇게 긴 시간 머무는 것을 보기 쉽지 않으셨을 거예요. “어떻게 8년이나 다녔어요?”라는 질문을 심심치 않게 받는데요. 전 늘 같은 답을 합니다. 정체되거나 성장할 수 없다고 느낄 때 이직을 결심하는 것을 자주 보았는데 저는 주문 플랫폼을 4년 정도 기획 운영했고, 지금은 사장님 향 플랫폼을 담당하고 있습니다. &lt;strong&gt;이렇듯 우아한형제들에서는 다양한 도메인을 경험할 수 있습니다. 지금은 팀장 역할을 하고 있는데요. 다른 역할을 통해 새로운 경험을 쌓는 등 우아한형제들은 성장의 기회가 많은 곳입니다.&lt;/strong&gt;&lt;br /&gt;
 &lt;strong&gt;다양한 경험을 통해 성장하고 싶으신 분들이라면 반드시 만족하실 거예요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/jsy003.jpg&quot; alt=&quot;jsy003&quot; style=&quot;width:60%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;마무리하며&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-기획자가-되길-꿈꾸는-분들에게-면접-노하우-한가지만-말씀-부탁드립니다&quot;&gt;Q. 기획자가 되길 꿈꾸는 분들에게 면접 노하우 한가지만 말씀 부탁드립니다.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;지원자분들을 만나면서 질문에 대한 정답을 답변하고자 노력하기보다 질문에 대해서 충분히 생각한 후에, 자기 생각을 이야기해 주셨으면 좋겠다는 생각을 할 때가 있습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;왜냐하면 본인의 생각을 잘 전달하는 것이 기획자로서 갖춰야 할 자질이라고 생각하기 때문입니다.&lt;/strong&gt; 그래서 질문에 다른 답을 하거나, 돌려서 다른 이야기를 할 때 오히려 커뮤니케이션 역량이 부족해 보인다는 느낌을 줄 수 있습니다. 질문에 대한 답을 모르거나, 어려운 경우에는 “모르겠다.” 또는 “경험해본 적이 없다”처럼 솔직하게 이야기해 주세요. &lt;strong&gt;그렇게 하신다면 면접관은 다른 질문을 통해 지원자분을 더 알아갈 수 있고, 지원자분도 다른 답변으로 본인을 더 잘 소개할 수 있는 기회를 얻게 되는 셈이니까요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;여러분 면접에서 만나요. :)&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;color:gray; font-size: 100%; text-align: Center;&quot;&gt;&lt;a href=&quot;https://career.woowahan.com/?keyword=&amp;amp;category=jobGroupCodes%3ABA005002&amp;amp;jobCodes=BA007014,BA007015#recruit-list&quot;&gt;기획직군 모집공고 바로가기&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/csj001.png&quot; alt=&quot;csj001&quot; style=&quot;width:30%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;최세지--배민서비스-기획자&quot;&gt;최세지 / 배민서비스 기획자&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;담당업무 소개&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-세지님께서-맡고-있는-역할과-하루-일과를-소개해-주세요&quot;&gt;Q. 세지님께서 맡고 있는 역할과 하루 일과를 소개해 주세요.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;저는 배민서비스기획팀의 팀장을 맡고 있어요. 저희 팀은 배민 앱의 회원가입부터 가게를 탐색하고 메뉴를 정하는 과정에서 필요한 서비스를 개선하는 과제들을 맡고 있는데요. 도메인으로 소개해 드리면 회원, 검색, 전시, 리뷰 등 다양합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;저의 하루 일과&lt;/strong&gt;는 먼저, 다양한 유관부서로부터 받은 요구 사항을 파악하기 위한 미팅에 참여하는 일부터 시작해요.&lt;br /&gt;
미팅에서는 사업-업주-사용자 모두를 고려하되 사용자 입장에서 문제를 해결할 수 있는 방법을 찾는 데 중점을 두고 있습니다.&lt;/p&gt;

&lt;p&gt;또한, &lt;strong&gt;월 2회 진행하고 있는 ‘배민앱 정기 업데이트’를 위해 앱 개발이 필요한 모든 과제를 취합하고, 주 1회 스프린트 회의를 진행해 과제의 우선순위를 부여하고 작업 범위와 개발 및 QA 일정을 협의한 후, 일정이 확정되면 유관부서에 이를 전파하는 역할&lt;/strong&gt;을 담당하고 있습니다.&lt;br /&gt;
그 밖에도, 팀 내에서 관리하는 지표를 확인하거나 주요 이슈 사항에 대해 팀원들과 논의하고 해결방안을 찾으며 하루를 보내고 있습니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;협업 과정&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-팀은-어떻게-구성되어-있고-타-부서와의-협업은-어떻게-이루어지는지-궁금합니다&quot;&gt;Q. 팀은 어떻게 구성되어 있고, 타 부서와의 협업은 어떻게 이루어지는지 궁금합니다.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;배민서비스기획팀은 세 파트로 나눠서 운영하고 있어요. 1) 가게와 메뉴를 진열하는 전시 파트와 2) 메인, 주소, 알림센터 등 플랫폼 기능을 담당하는 파트 3) 마지막으로 검색/회원파트로 운영하고 있으며 파트별로 3~4명의 기획자가 각자의 담당 도메인을 가지고 있습니다.&lt;/strong&gt; 기획뿐만 아니라 같은 배민서비스실 산하의 배민서비스개발팀도 파트가 동일하게 나뉘어 있고 기획/개발 파트가 모여 데일리 미팅 및 스프린트 회의를 진행하면서 과제와 이슈를 확인하고 작업 우선순위와 일정을 정하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;파트를 운영하게 된 이유는 혼자 기획서를 작성하다 보면 ‘내가 올바른 방향으로 기획을 하고 있는지’, ‘사용자가 과연 이 기능을 편리하게 사용할 수 있을지’ 의문이 들더라고요. 그래서 파트원들과 서로의 생각을 지속적으로 공유하면서, 서로가 미처 고려하지 못한 점을 파악하고 폭넓은 관점을 가질 수 있도록 했어요.&lt;/strong&gt; 그리고 피드백을 주는 동료 입장에서도 본인만의 도메인에 매몰되는 것이 아니라 &lt;strong&gt;다른 도메인을 간접적으로 경험해볼 수 있다는 장점이 있고, 다른 도메인의 영향 범위도 자연스럽게 파악할 수 있어요.&lt;/strong&gt; 무엇보다도 이 과정에서 혼자 일한다는 것이 아니라 &lt;strong&gt;우리 팀 모두가 같은 서비스를 만들어 나간다는 느낌을 받을 수 있다는 것이 가장 큰 장점&lt;/strong&gt;이라고 생각해요.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;배민서비스기획팀은 주로 플랫폼에서 제공하는 &amp;lt;주문에 필요한 다양한 정보들을 배민앱에서 어떻게 노출할 것인지 정리하는 업무&amp;gt;&lt;/strong&gt;를 하고 있어요. 사용자에게 노출할 정보들은 모두 다른 시스템에서 받아와야 해서 가게, 메뉴, 상품, 사장님 서비스 등 다양한 협업 부서와 업무를 진행하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;가장 최근에는 배민1 신규 상품을 판매하고 이를 가게 목록에 진열하는 과제를 진행했는데&lt;/strong&gt;, 상품시스템에서 배민1 상품에 가입한 가게 정보를 전달해 주시고, 가게/혜택시스템에서 고객에게 주문 결정에 도움이 될만한 데이터를 받아와서 가게를 진열하는 작업을 진행했어요. 배민1 서비스를 이용하는 가게는 사장님의 주력 메뉴 이미지가 크게 노출되는데, 사장님이 셀프서비스를 통해 직접 등록한 메뉴 이미지도 배민앱에 크게 노출될 수 있도록 메뉴서비스팀과 협업했어요. 그리고 배민1 가게들이 가게목록에서 어떠한 순서대로 노출하면 좋을지를 사업 부서와 논의하고 법적인 이슈는 없을지 등 &lt;strong&gt;다양한 관점으로 리스크 검토 의견을 받아 정책에 반영하는 과정&lt;/strong&gt;을 거쳤어요. 이처럼 저희는 &lt;strong&gt;하나의 기능을 만들기 위해서 끊임없이 유관부서와 협업하면서 업무를 진행하고 있습니다.&lt;/strong&gt;&lt;br /&gt;
&lt;img src=&quot;/img/2021-06-07/csj002.jpg&quot; alt=&quot;csj002&quot; style=&quot;width:60%; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;성장 이야기&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-세지님께서-맡으신-여러-과제들-중-어려운-과제를-극복하신-사례를-소개해-주실-수-있나요&quot;&gt;Q. 세지님께서 맡으신 여러 과제들 중 어려운 과제를 극복하신 사례를 소개해 주실 수 있나요?&lt;/h3&gt;
&lt;p&gt;저는 팀 매니징을 맡기 이전에는 리뷰와 회원 도메인을 담당했어요. &lt;strong&gt;그전까지는 배민앱에서 사용자가 이용하는 기능 위주로 기획을 해오다가 회원과 리뷰 시스템을 맡으면서 백엔드 시스템을 새로 다시 만드는 프로젝트를 처음 진행하게 되었어요.&lt;/strong&gt; 중장기적 서비스 고도화 방향을 고려해 개발자분들에게 요구 사항을 전달하여 백엔드 시스템 구조를 잡아나가야 했고, 반대로 시스템 구조가 구체화되면서 정책을 다시 고려해야 하는 부분도 생겼어요. 특히 리뷰 정책은 사장님의 영업 매출과도 직접적으로 연결되기 때문에 정책 변경에 대해서 사업/운영 부서와도 밀접하게 커뮤니케이션하며 업주 리스크를 줄여나가야 했고, 고객 문의 응대 가이드를 함께 마련했어요.&lt;/p&gt;

&lt;p&gt;프로젝트 규모가 큰 만큼 스프린트로 나누어서 프로젝트를 세밀하게 관리했지만, 역시나 마지막 스프린트에서 이전 스프린트에서 못다 한 개발까지 하느라 일정이 턱없이 부족했어요. 게다가 엎친 데 덮친 격으로 운영 데이터를 보니 수많은 예외 케이스가 생기면서 프로젝트에 크고 작은 이슈들이 계속 생겨났고요.&lt;br /&gt;
&lt;strong&gt;매일 오전 담당자들이 모두 모여 잔여 작업과 QA 이슈를 체크하고, 주요 이슈에 대해서는 기획-개발-QA가 모여서 이런 케이스와 이슈들을 해결할 수 있는 방안을 논의하고 문제 해결 방향을 즉각 합의했던 것이 가장 효과적인 방법&lt;/strong&gt;이었던 것 같습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;백엔드 시스템과 어드민까지 다방면에서 고민하고 사용자를 넘어 업주 또는 가게 사장님들의 입장까지 고려한 정책 설계, 프로젝트 일정 및 리스크 관리 방법까지 터득할 수 있었던 프로젝트이기에 저를 한층 더 성장시켜 주었다고 생각해요.&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;역량에 관한 생각&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-배민서비스기획팀에서-좋은-성과를-내기-위해서는-어떤-역량이-필요한가요&quot;&gt;Q. 배민서비스기획팀에서 좋은 성과를 내기 위해서는 어떤 역량이 필요한가요?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;배민에서는 하나의 기능을 고민하더라도 수많은 팀과 협업을 거쳐야 고객에게 의미 있는 기능을 제공해 드릴 수 있어요.&lt;/strong&gt;&lt;br /&gt;
예를 들어볼게요. 고객이 메뉴를 선택하려면 메뉴 이미지와 설명이 충분해야 하는데, 이때 사장님이 고퀄리티의 메뉴 이미지를 등록하고 메뉴 설명을 자세히 등록해 주어야만 고객이 메뉴를 손쉽게 고를 수 있거든요. 이 때문에 저희는 가게/메뉴/상품 정보를 관장하는 배민플랫폼실, 사장님서비스를 제공하는 B2B서비스실에 과제의 타당성에 대해서 프로젝트 담당자를 대상으로 설득하는 일을 많이 해요. 이를 위해서는 고객이 어떤 것들을 필요로 하는지 VOC도 꼼꼼히 살펴보고, 타사의 트렌드는 어떠한지, 지표 모니터링을 통해 고객이 어떻게 제품을 사용하고 있는지 잘 파악하고 있어야 해요.&lt;/p&gt;

&lt;p&gt;그리고, &lt;strong&gt;사장님-사용자-비즈니스 사이에서 밸런스를 찾아야 한다는 것인데요.&lt;/strong&gt;&lt;br /&gt;
예를 들면, 가게 목록에 총 리뷰수를 제공한다면 고객에게 주문 선택에 도움을 줄 수 있지만, 신장개업 한 사장님 입장에서는 기존 가게와 리뷰 수의 차이가 너무 크면 가게를 운영하시기 어려우실 거예요. 그래서 저희는 가장 최근 6개월의 리뷰 수를 리스트에 보여드리고 있고, 최대 리뷰 수는 100+로 표기하고 있어요. &lt;strong&gt;이렇게 정책을 정할 때는 사용자-사장님이 모두 윈윈할 수 있는 정책을 끊임없이 찾아야 해요.&lt;/strong&gt; 하지만, 사용자-사장님의 두 입장을 고려하다가 ‘왜 이 과제를 하게 되었는지’에 대해서 그 의미가 흐려지면 안 되기 때문에 &lt;strong&gt;과제의 목적을 분명히 해서 제품을 만드는 모든 구성원이 공통의 목표를 합의하는 것이 중요하다고 생각해요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/csj003.jpg&quot; alt=&quot;csj003&quot; style=&quot;width:60%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;우아한형제들의 기획 환경&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-배민서비스기획팀만의-매력을-소개해-주세요&quot;&gt;Q. 배민서비스기획팀만의 매력을 소개해 주세요!&lt;/h3&gt;
&lt;p&gt;배민서비스기획팀에서 진행하는 모든 과제는 많은 사용자를 대상으로 서비스를 런칭하고 있어서 &lt;strong&gt;내가 맡은 프로젝트에 대한 사용자의 피드백을 즉각적으로 확인할 수 있어요.&lt;/strong&gt; 우리가 만든 제품이 고객에게 얼마나 매력적이었는지, 고객이 좋아하는 서비스인지 바로 알 수 있죠.&lt;br /&gt;
그렇기 때문에 저희 팀에서 일하게 된다면 양질의 피드백을 확인할 수 있어요. &lt;strong&gt;기획자로서 인사이트를 얻을 수 있는 기회들이 많이 열려있고, 이는 기획자로 성장하는데 중요한 환경으로 뒷받침되어줄 것으로 생각해요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;저희 팀의 또 다른 매력은 서비스를 만들어나가는 동료들과 함께 성장할 수 있다는 것&lt;/strong&gt;입니다.&lt;br /&gt;
각자가 맡은 도메인과 지면이 있고 담당 제품에 대해 오너십을 가지고 일하고 있지만, 본인이 맡은 지면에 대해서도 필요하다면, &lt;strong&gt;팀 내 구성원들과 언제든지 자유롭게 아이데이션을 할 수 있고 고민을 나눌 수 있어요. 그리고 다른 지면 정책을 잘 몰라도, 담당자를 통해서 내용을 상세하게 확인할 수 있어 작업 영향 범위를 파악하는 것이 수월하다고 생각해요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;마지막으로 팀에서 여러 서비스 및 제품을 담당하고 있기 때문에, 본인이 원한다면 다른 도메인에도 도전해 볼 수 있어요. &lt;strong&gt;여러 도메인을 경험하면서 다양하고 복잡한 문제들을 해결하기 위해 치열하게 고민할 기회가 항상 열려있어요. 물론 본인이 한 도메인의 전문가로 거듭나기를 원한다면 담당 도메인에 깊게 파고들 수도 있고요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;마무리하며&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-미래-동료가-되기를-희망하는-기획자분들에게-응원의-한-말씀-부탁드립니다&quot;&gt;Q. 미래 동료가 되기를 희망하는 기획자분들에게 응원의 한 말씀 부탁드립니다.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;저희 팀에 지원해 주시는 많은 분들이 주변 사람들이 실생활에서 사용하는 서비스를 만든다는 것과 고객 피드백을 즉각적으로 받을 수 있다는 것에 대한 기대감을 가지고 있더라고요.&lt;/strong&gt; 저도 배민 앱을 담당하면서 이런 기회를 가질 수 있다는 것에서 행운이라고 생각하는데요. 반면에, 많은 사용자가 이용하는 서비스이기 때문에 그들을 이해하기 쉬울 것이라고 생각하지만, 오히려 사용자의 목소리를 하나하나 뜯어보기 어렵더라고요. 앱을 이용하는 방식에 대해 객관적인 판단을 내리기도 어려웠고요. 제가 고객의 목소리에 귀를 기울이지 않는다면, 그들의 목소리는 아무런 의미 없이 흘러 가버리고 결코 고객의 니즈를 알 수 없기 때문에 스스로 노력을 많이 해야 해요.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;사용자 입장에서 그들을 알려는 노력들이 가장 기본이 되는 것 같고요.&lt;/strong&gt; 이것이 바탕이 된다면 이 기능이 왜 제공되어야하는지 많은 설득의 과정도 잘 헤쳐나가고 고객에게 정말 의미 있는 서비스를 만들어 낼 수 있을 것이라고 생각해요. &lt;strong&gt;고객의 니즈를 파악하는 것에 그 누구보다 관심이 많으신 분이라면 저희팀에 오셔서 같이 고객이 ‘좋은 음식을 먹고싶은 곳에서’ 먹을 수 있는 서비스를 만들었으면 좋겠습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;color:gray; font-size: 100%; text-align: Center;&quot;&gt;&lt;a href=&quot;https://career.woowahan.com/?keyword=&amp;amp;category=jobGroupCodes%3ABA005002&amp;amp;jobCodes=BA007014,BA007015#recruit-list&quot;&gt;기획직군 모집공고 바로가기&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/lny001.png&quot; alt=&quot;lny001&quot; style=&quot;width:30%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;이나영--배민쇼핑라이브-기획자&quot;&gt;이나영 / 배민쇼핑라이브 기획자&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;담당업무 소개&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-나영님께서-담당하시는-기획-업무에-대해-소개해-주세요&quot;&gt;Q. 나영님께서 담당하시는 기획 업무에 대해 소개해 주세요.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;우아한형제들에서 최근에 오픈한  ‘배민쇼핑라이브’ 서비스의 기획 업무를 담당하고 있어요.&lt;/strong&gt; 배민쇼핑라이브는 &lt;strong&gt;MD(Merchandising Manager)가 소싱한 상품들을 배민앱 내에서 라이브 방송을 통해 판매하고, 고객은 실시간으로 채팅을 통해 셀러와 소통하며 상품에 대한 정보를 빠르게 얻고 구매할 수 있는 서비스입니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;배민쇼핑라이브에서는 크게 3가지 서비스를 관리&lt;/strong&gt;하고 있는데요. 첫째는 일반 고객들이 라이브 방송을 보고 상품을 구매할 수 있는 배민앱 내의 배민쇼핑라이브 서비스 둘째는 셀러가 배민쇼핑라이브에 입점해서 판매할 상품을 직접 등록하고 이후 판매된 내역을 확인하거나 발주/발송 처리, 정산된 내역 등을 확인할 수 있는 셀러오피스, 셋째는 내부 직원들이 셀러의 입점이나 상품 판매를 승인하거나, 방송을 등록, 진행하고, 컨텐츠를 전시하는 내부 운영어드민 입니다.&lt;/p&gt;

&lt;p&gt;저는 &lt;strong&gt;배민쇼핑라이브가 최초 오픈하는 시점에 백엔드 시스템(셀러오피스, 운영어드민)을 구축했어요.&lt;/strong&gt; 셀러가 어떻게 입점할 수 있는지, 상품 등록할 때는 어떤 항목들이 필요할지, 정산주기는 어떻게되어야 할지 등에 대해 주로 고민하였고 유관부서들과 논의하며 정책을 정하고, 상세 프로세스 등을 기획하여 서비스를 만들어나갔습니다. &lt;strong&gt;오픈 이후에는 MD, PD, 사업 부서 등 유관부서의 요구 사항들을 수집하여 로드맵을 세우고, 운영 효율성을 높이기 위한 과제들을 진행하며 셀러오피스와 운영어드민을 개선하는 업무를 진행했습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;최근에는 일반 고객향의 배민쇼핑라이브 앱 프론트기획을 담당하게 되었어요.&lt;/strong&gt; 유관부서 및 고객의 요구 사항을 수집한 것을 기반으로 서비스의 로드맵을 세우고, 액션 아이템에 대한 상세 기획을 진행하는 업무였습니다. 개발자, 디자이너와의 밀접한 커뮤니케이션을 통해 프로젝트가 목표한 바를 원활하게 이룰 수 있도록 관리하는 것은 백엔드 시스템과 동일하지만, &lt;strong&gt;서비스를 이용하는 주 고객이 다르기 때문에 저의 고민 포인트도 바뀌었어요.&lt;/strong&gt; 배민쇼핑라이브로의 고객 유입을 늘리려면 어떻게 해야할지, 구매 고객의 서비스 사용 경험을 향상시키기 위해선 무엇을 해야할지, 고객이 구매하기 위해서는 무엇이 필요한지 등 &lt;strong&gt;더 좋은 서비스 가치를 제공할수 있도록 고민하고 있습니다.&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;과제 수행 과정&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-배민쇼핑라이브-서비스를-다른-서비스와-비교했을-때-기획자로서-특별히-관리해야-하는-사항이-있으신가요&quot;&gt;Q. 배민쇼핑라이브 서비스를 다른 서비스와 비교했을 때 기획자로서 특별히 관리해야 하는 사항이 있으신가요?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;배민쇼핑라이브 서비스를 기획하며 가장 중요하게 고려하는 것은, 전체적인 커머스 시스템 프로세스를 이해하고 기획하는 것입니다.&lt;/strong&gt; 예를 들면 어떤 기능을 기획할 때 셀러의 상품 데이터가 어느 범위까지 사용되고 영향을 미치는지, 배송 프로세스는 어떻게 되는지 등을 이해하고 있어야만 서비스 영향 범위를 파악하고 놓치는 부분 없이 기획할 수 있어요. 개발자분들과도 커뮤니케이션하기에 용이하고요.&lt;/p&gt;

&lt;p&gt;프론트 앱에 노출되는 기능들은 단순히 프론트 앱 개발만으로 해결되지 않고 운영어드민, 셀러오피스 등의 작업도 함께 병행되는 경우가 많습니다. 그렇기 때문에 &lt;strong&gt;프론트 기획이지만 운영어드민, 셀러오피스의 업무 범위까지도 미리 파악하여 담당 팀에 공유하고, 원하는 일정에 맞춰 일이 진행될 수 있기에 노력하고 있어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;그리고 다른 서비스와 달리 특별하게 관리해야 할 점은 사업과 관련된 것에 관심을 놓지 않는 것 입니다.&lt;/strong&gt; 통신판매중개를 할 것인지 직매입을 할 것인지 등의 사업 방향에 따라 시스템에 영향을 줄 수 있고, MD분들이 새로운 상품군을 소싱 한다면 새로운 상품정보 제공 고시가 추가되어야 하고, 새로운 쿠폰 혜택을 주고 싶을 때는 쿠폰 시스템이 변경되는 등, 시스템과 서비스에 영향을 미칠 수 있기 때문에 우리가 추구하는 사업의 방향성과 소싱하는 상품, 방송 편성 스케줄 등에 대해서도 항상 관심을 가지려 합니다. 이런 &lt;strong&gt;대응 사항이 생겼을 때는 최소한의 스펙으로 빠르게 대응하는 것에 초점을 맞춰 진행하고 있어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;또한 “일반 구매자만이 우리의 고객이 아니다.”라는 점을 항상 염두에 둬요.&lt;/strong&gt; 셀러, 방송 PD, MD, 내부 운영자 모두 우리의 고객이고 서비스의 작은 변화 하나가 이 모두에게 영향을 미칠 수 있거든요. 그렇기 때문에 백엔드나 프론트에 변화가 있을 때 이런 &lt;strong&gt;이해관계자들에게 사전에 공유하고 이슈가 없는지 체크하는 것도 매우 중요합니다.&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;성장이야기&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-우아한형제들에서-일하시며-성장하고-있다고-느끼게-된-계기나-경험이-있으신가요&quot;&gt;Q. 우아한형제들에서 일하시며 성장하고 있다고 느끼게 된 계기나 경험이 있으신가요?&lt;/h3&gt;
&lt;p&gt;저는 ‘매일을 열심히 살다 보면 어느 날 조금은 성장해있겠지’라고 생각하는 타입이지만, &lt;strong&gt;이곳에서 크게 두 번의 경험이 있었고 이전에 해보지 않았던 새로운 업무를 맡아 하나씩 해결해 나갈 때 성장하고 있다고 느끼는 것 같아요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;쇼핑라이브를 담당하기 전에는 ‘배민장부’라는 사장님(업주향) 매출 관리 서비스를 담당&lt;/strong&gt;했습니다. 배민장부 이전에는 배민앱 기획을 담당하고 있었기에, 갑자기 ‘사장님’이라는 고객을 대상으로 한 서비스를 만들어야 한다는 것이 처음에는 굉장히 막막했어요. 더구나 매출이라는 새로운 분야에 대해 서비스를 기획하려니 어렵기도 했고요. 그렇지만 &lt;strong&gt;사장님을 인터뷰하거나 설문조사, 관련 책 읽기 등을 통해 사장님에게 어떤 것이 필요한지 알기 위해 노력했고, 그 정보들을 기반으로 서비스를 만들게 되었습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;오픈 이후에는 서비스 기획뿐 아니라 배민장부 가입자를 늘리기 위해 직접 사업 제안도 해보고, 마케팅 이벤트 계획도 세우는 등의 다양한 업무를 하며 서비스가 성장하기 위한 많은 노력들을 했고 조금씩 사장님들이 배민장부를 좋아해 주시고, 관심을 갖기 시작했습니다. &lt;strong&gt;새로운 고객을 위한 서비스를 만들고 성장시켜 나가는 과정에서 기획 외에 해보지 않았던 분야의 업무도 하며 제 자신도 함께 성장한다는 느낌을 받았어요.&lt;/strong&gt; 이전엔 배민을 바라보는 시각이 2D였다면, 배민장부를 하며 3D로 확장되었다고나 할까요 :)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;두 번째는 바로 현재 제가 맡고 있는 쇼핑라이브 백엔드 시스템을 기획할 때였어요.&lt;/strong&gt; 커머스 서비스를 기획해본 경험이 없는 제게 배민쇼핑라이브는 새로운 도전이었습니다. 인터넷쇼핑으로 물건을 사보기만 했지 셀러가 입점할 때 회사에 제출해야하는 기본적인 서류는 무엇인지부터 시작해서, 배송은 어떤 프로세스로 진행되는지, 결제 데이터는 어떻게 정산되는 것인지 등 기본적인 커머스 시스템을 알고 기획한다는 것이 쉽지 않더라고요.&lt;br /&gt;
그렇지만 타사 벤치마킹도 많이 하고, 커머스 경험이 있는 분들의 조언도 받으며 무사히 서비스를 오픈할 수 있었습니다. &lt;strong&gt;이전과는 다른 새로운 고민을 하며 잘 몰라도 어떻게든 알아가며 서비스를 만들어나가고 고민이 결과물로 만들어졌을 때, 제 스스로도 성장했다고 느껴지는 것 같아요.&lt;/strong&gt;
&lt;strong&gt;첫 방송이 시작되고, 채팅들이 마구 올라가던 순간의 감동을 잊을 수 없어요. ‘내가 또 한 번 해냈구나.’라는 뿌듯한 마음과 생각이 들었어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/lny002.jpg&quot; alt=&quot;lny002&quot; style=&quot;width:60%; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;기획자 역량에 관한 생각&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-배민쇼핑라이브의-서비스-가치를-만들기-위해-기획자가-갖춰야-할-역량은-무엇인가요&quot;&gt;Q. 배민쇼핑라이브의 서비스 가치를 만들기 위해 기획자가 갖춰야 할 역량은 무엇인가요?&lt;/h3&gt;
&lt;p&gt;제가 배민쇼핑라이브 서비스를 기획하며 가장 중요하게 고려하는 부분과 연결되는 것 같기도 한데요.&lt;br /&gt;
&lt;strong&gt;기본적으로는 커머스에 대한 이해를 기반으로 백엔드 시스템과 프론트엔드 그리고 서비스 전반에 걸쳐 고민할 수 있는 자세와 역량이 필요하다고 생각합니다.&lt;/strong&gt; 앞서 말했듯 프론트와 백엔드는 유기적으로 연결되어 있기 때문에 어느 하나만 생각해서는 완성도 있는 서비스를 기획하기 어려워요. 
또한 &lt;strong&gt;라이브커머스 시장이 빠르게 성장하고 있고, 서비스 경쟁이 심화되는 상황인 만큼 이 시장을 이해하고 빠르게 대응해나가는 역량도 필요한 것 같아요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;그리고 서비스 목표를 이루기 위한 실행계획을 단계적으로 세우고, 빠르게 실행해야 하며 이러한 실행계획은 당연히 우리 고객에 대한 정량/정성적인 분석과 이해가 반영된 계획이어야 할 것이고요.&lt;/strong&gt; 유사 서비스들을 사용해보며 같은 기능을 똑같이 제공하는 것이 아니라 ‘이건 왜 이렇게 했을까? 이 기능은 왜 필요했을까?’ 등 &lt;strong&gt;우리 서비스에는 어떻게 적용하면 좋을지를 고민하고 생각해 낼 수 있어야 합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;마지막으로는 개발자, 디자이너, QA, 사업 부서 등 다양한 직군과 함께 협업할 일이 많은 만큼 다양한 요구 사항들을 수집하고 다양한 의견을 조율해 필요한 경우에는 설득하고 납득시킬 수 있는 커뮤니케이션 역량이 필요하다고 생각해요.&lt;/strong&gt; 우리가 ‘왜 이 프로젝트를 해야 하는지’와 같은 최상위 또는 공동의 목표를 정해 한 방향을 보고 나아갈 수 있도록 이해시킬 수 있는 역량이 필요합니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;우아한형제들 문화&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-우아한형제들에-입사하길-잘했다고-생각되는-순간은-언제인가요&quot;&gt;Q. 우아한형제들에 입사하길 잘했다고 생각되는 순간은 언제인가요?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;입사하고 가장 좋았고 잊을 수 없는 순간이 있는데요. 바로 입사 후 첫 번째 우아한데이(현재 전사발표)였습니다.&lt;/strong&gt; 우아한형제들의 전사발표는 매월 첫째 주 금요일에 지난 한 달간 &lt;strong&gt;각 사업 부서의 주요과제 진척사항, 사업 계획과  KPI 등을 공유하는 동시에 회사의 사업 현황과 주요 소식에 대해 공유해 주는 시간인데요.&lt;/strong&gt; 보통의 구성원들은 타 부서에서는 어떤 일을 하고, 어떤 사업적 목표와 성과를 내고 있는지 알기 쉽지 않은데 모든 구성원들이 모인 자리에서 각 사업 부서의 업무를 공유하고 KPI를 달성했다면 잘했다고 칭찬하고, 달성하지 못했다면 동기부여를 해주는  시간이 인상적이었어요. 또 범준님(대표님)도 우리가 가고 있는 방향, 큰 목표를 공유해 주시며, &lt;strong&gt;우리가 가고자 하는 방향에 대해 공감대를 형성하고 일하는 동기를 부여해 주시는 모습이 너무 감동적이어서 우아한형제들에 입사하길 잘했다고 생각했어요.&lt;/strong&gt; ‘어느 회사에서 이렇게 주기적으로 목표와 KPI를 공유해줄 수 있을까?’라는 생각이 들더라고요.&lt;br /&gt;
뿐만 아니라 &lt;strong&gt;주 4.5일제 근무로 매주 월요일 아침에 오후에 출근하는 날이면 ‘아, 우아한형제들에 입사하길 잘했구나’ 생각해요 :)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/lny003.jpg&quot; alt=&quot;lny003&quot; style=&quot;width:40%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;마무리하며&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-나영님이-기획자를-선택하게-되신-계기와-이유를-이야기해주세요&quot;&gt;Q. 나영님이 기획자를 선택하게 되신 계기와 이유를 이야기해주세요.&lt;/h3&gt;
&lt;p&gt;대학 시절 컴퓨터 관련 전공으로 기획, 개발에 대해 쉽게 접할 수 있었습니다. 학부 과제와 공모전에 참여하면서 신규 서비스를 고민하고 &lt;strong&gt;기획하는 것도 종종 경험했고요.&lt;/strong&gt; &lt;strong&gt;서비스에 대한 세부사항을 논의하고 정리해나가는 과정에서 ‘실제로 내가 기획한 서비스가 공개되고 잘 되면 얼마나 보람 있을까, 많은 사람이 사용하는 서비스를 기획하고 싶다’고 생각했습니다. 그때부터 기획자가 되기를 꿈꿨어요&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;운이 좋게도 첫 회사에서부터 많은 사용자가 사용하는 서비스,기획 업무를 맡게 되었고, 좋든 나쁘든 고객의 피드백을 들을 때 ‘이만큼 고객이 우리 서비스에 대해 관심을 가지는구나’라고 보람을 느껴 지금도 이 일을 계속하고 있는 것 같아요. &lt;strong&gt;특히 고객의 불편사항을 개선하여 그 피드백이 칭찬으로 돌아왔을 때의 기쁨과 보람을 느낍니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;color:gray; font-size: 100%; text-align: Center;&quot;&gt;&lt;a href=&quot;https://career.woowahan.com/?keyword=&amp;amp;category=jobGroupCodes%3ABA005002&amp;amp;jobCodes=BA007014,BA007015#recruit-list&quot;&gt;기획직군 모집공고 바로가기&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/kyh001.png&quot; alt=&quot;kyh001&quot; style=&quot;width:30%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;김용훈--배민상회-기획자&quot;&gt;김용훈 / 배민상회 기획자&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;담당업무 소개&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-현재-우아한형제들에서-용훈님이-맡고-있으신-과제-및-프로젝트를-소개해-주세요&quot;&gt;Q. 현재 우아한형제들에서 용훈님이 맡고 있으신 과제 및 프로젝트를 소개해 주세요.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;저는 현재 신선 식재료와 배민감성으로 재해석한 포장용기, 배달비품 등을 판매부터 배송까지 모두 책임지는 ‘배민상회’ 쇼핑몰 내에서 물류 플랫폼을 개선하고, 고도화 과제를 진행하는 PM(Product Manager) 역할을 수행하고 있습니다.&lt;/strong&gt; 대표적으로 2021년 상반기 SCM(Supply Chain Management) 공급망 관리 플랫폼 서비스를 개선하여 새롭게 런칭했는데요. 여기서 의미하는 공급망 관리란 공급자로부터 고객에게 이르는 전체적인 연결고리 관계와 구매/재고/물류/정산관리 등의 여러 기능 및 서브 프로세스를 포함하고 있는 서비스를 지칭합니다. 따라서 &lt;strong&gt;프로세스 자체가 회사 전역으로 광범위하고, 내부 사용자 뿐만 아니라 많은 외부 협력사분들도 같은 도메인을 바라보고, 커뮤니케이션하면서 움직여야 합니다. 그렇기 때문에 내외부 사용자별 또는 전체 프로세스에 대한 이해를 바탕으로 체계적으로 정리하는 데 초점을 맞추고 있습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;협업에 관한 생각&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-다른-직군-부서와의-협업에-있어서-가장-중요한-것은-무엇이라고-생각하시나요&quot;&gt;Q. 다른 직군 부서와의 협업에 있어서 가장 중요한 것은 무엇이라고 생각하시나요?&lt;/h3&gt;
&lt;p&gt;서로 다른 분야의 지식과 다양한 종류의 경험들이 모였을 때 발생하게 되는 이해관계의 충돌과 마찰은 협업 과정에서 피해 갈 수 없는 필수적인 요소인데요. 이때 &lt;strong&gt;기획자는 서로 다른 이해관계를 조정하면서 나오는 의견들을 수렴하여 아이디어를 극대화시키는 역할이 중요합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;이를 잘하기 위해서는 &lt;strong&gt;커뮤니케이션 스킬도 중요하지만 역시나 Product에 대한 지식을 갖추고 있어야 합니다.&lt;/strong&gt; 사업과 서비스 관점의 도메인 지식은 물론이고 개발과 디자이너 관점의 최소한의 지식은 알고 있어야 위와 같은 역할을 잘 수행할 수 있죠. 예를 들어 고객 배송 플랫폼을 개선하려고 하는데 사업적인 목표 달성에 대한 이해도가 없거나, 현재 구조에서 구현이 가능한지 아닌지를 인지하지 못한 상태에서 설계를 시작하고, 커뮤니케이션을 진행한다면 프로젝트가 효율적으로 흘러가지 못하는 상황이 발생할 수 있습니다. 
따라서 &lt;strong&gt;다른 직군 부서와의 협업에 있어서 기획자, 특히 PM(Product Manager)에게 가장 중요한 것은 Product에 대한 이해&lt;/strong&gt;라고 말씀드리고 싶어요.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;여기에 덧붙여 과제 전체 맥락에 대한 내용과 연계성에 대해 혼자서 이해하는 수준으로 끝내는 것이 아닌 정리를 잘하여 동료 구성원들에게 상시적으로 내용과 상황을 공유하고, 좋은 방향으로 갈 수 있도록 커뮤니케이션까지 한다면 금상첨화입니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;과제 수행 과정&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-용훈님께서-맡게-된-과제의-우선순위를-정하고-수행하는-전체-과정이-궁금합니다&quot;&gt;Q. 용훈님께서 맡게 된 과제의 우선순위를 정하고 수행하는 전체 과정이 궁금합니다.&lt;/h3&gt;
&lt;p&gt;기획자로 일을 하다 보면 요청 사항과 진행 과제가 끊임없이 발생하게 되는데요. &lt;strong&gt;과제의 우선순위를 결정하는 가장 중요한 포인트는 ‘시급성’과 ‘난이도’입니다.&lt;/strong&gt; 간략히 풀어서 얘기하면 ‘시급성’은 전략적 중요도와 경영에 미치는 영향이 크므로 시급하게 추진이 필요한데, 현재 시점으로 진행할 것인지, 중장기적 관점으로 추진해야 될지를 판단하는 것을 의미하며 ‘난이도’는 현재 수준에서 과제를 바로 진행할 수 있는지의 높고, 낮음의 수준을 판단하는 것이죠.&lt;/p&gt;

&lt;p&gt;사실 이렇게 우선순위를 잘 정리하고 움직이더라도 시급성 높고, 난이도는 낮은 과제를 동시에 병렬로 진행할 때도 많은 것 같습니다. 중장기적 관점의 전략 과제도 중요한데 지금 당장 개선이 시급한 운영 개선 과제도 중요한 것처럼 말이죠. 또한, 이러한 우선순위 결정을 내릴 때 특정 담당자 혼자서 판단하고, 결정하여 과제를 추진하는 것은 굉장히 위험한 행동이며 &lt;strong&gt;관련 담당자들과 커뮤니케이션하여 우선순위 등을 수시로 조정하고 반영하여 최대한 효율적으로 과제가 진행될 수 있도록 정리하고, 공유합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;이후 선정된 과제에 대해서 &lt;strong&gt;기획자는 정책/사양/기획서 위주로 동료 구성원들에게 리뷰를 진행하고, 진행사항과 결과물을 면밀하게 점검해 나가며 과제 종료 후에도 모니터링하고, 개선 사항 등을 정리하여 다음 플랜을 계획&lt;/strong&gt;합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/kyh002.jpg&quot; alt=&quot;kyh002&quot; style=&quot;width:60%; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;기획자의 역량에 관한 생각&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-좋은-기획자에게-필요한-역량은-무엇이라고-생각하시나요&quot;&gt;Q. 좋은 기획자에게 필요한 역량은 무엇이라고 생각하시나요?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;개인적으로 생각하는 좋은 기획자의 역할은 커뮤니케이션과 구조적인 사고입니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;첫 번째,&lt;/strong&gt; 서비스 기획자는 고객과 시장에서 원하는 니즈를 기반으로 그 본질을 파악하고, &lt;strong&gt;새로운 가치를 서비스 플랫폼으로 만들어내는 즉, 하나의 서비스 플랫폼을 책임지는 PM(Product Manager) 역할&lt;/strong&gt;을 주로 수행하게 되는데요. 이러한 &lt;strong&gt;서비스를 만들어 내는 과정에서 직군마다 사용하는 언어가 모두 다르기 때문에 프로젝트 시작과 끝까지 같은 언어로 이해시키고, 동일한 생각과 방향을 유지할 수 있게 끔 만들어내는 역할&lt;/strong&gt;이 굉장히 중요합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;두 번째,&lt;/strong&gt; &lt;strong&gt;우리의 업무가 고객 니즈에 대한 본질을 파악하여 충족 방안을 마련하는 것이 중요한 업무인 만큼 전체 맥락과의 연계성 속에서 문제를 파악하고, 해결하는 구조적인 사고가 필요합니다.&lt;/strong&gt; 그렇지 못한 경우 고객 니즈 본질과는 무관하게 다른 방향으로 흘러갈 수 있기 때문이죠.&lt;/p&gt;

&lt;p&gt;언급드린 이 두 가지 역량은 저에게도 늘 어려운 숙제이자 도전인데요. 결국 고객을 이해하고 동료를 이해한다면 좋은 프로덕트와 서비스를 제공할 수 있는 확률이 높아지고, 기획자로서의 목표도 이룰 수 있을 거라고 생각합니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;우아한형제들 문화&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-미래의-동료분들에게-회사와-팀-자랑을-해주세요&quot;&gt;Q. 미래의 동료분들에게 회사와 팀 자랑을 해주세요!&lt;/h3&gt;
&lt;p&gt;우아한형제들은 크게 공간의 제약 없이 &lt;strong&gt;편안한 자세로 자유로운 분위기 속에서 일하는 직원들의 모습을 쉽게 찾아볼 수 있는 곳입니다. 또한 스스로의 원칙과 규칙을 세워 일할 수 있는 자율적인 문화를 지향하고, 회사가 직원들에게 ‘관리’ 가 아닌 ‘관심’으로 접근한다는 점을 직접 느낄 수 있는 매력적인 곳이죠.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;현재 &lt;strong&gt;제가 속해 있는 팀은 목적 조직으로 기획/개발자가 한 팀이 되어 도메인의 시작부터 끝까지 모든 고민을 함께 공유하고, 만들어 나가며 출시합니다.&lt;/strong&gt; 예를 들어 프로젝트 진행 시, 기획은 기획만을 준비하고 개발은 개발만을 준비하여 서로 업무 진행 사항 등을 컨펌받는 형식으로만 진행하는 것이 아닌 &lt;strong&gt;스크럼 미팅을 통해 설계 관점과 비즈니스 및 사용성 측면에 따른 결합도, 응집도 등을 서로 공유하고 체크하여 현재와 미래를 모두 아우를 수 있는 최적의 도메인 설계를 목표로 효율적으로 움직입니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;실제 2021년 상반기 SCM 플랫폼 신규 개선 과제를 진행할 당시에도  도메인 범위가 큰 반면 진행과 동시에 정리를 해나가야 하는 상황이 수시로 발생하다 보니 그만큼 개발 점검, QA 이슈 상황이 많이 발생하게 되었는데요. &lt;strong&gt;다행히 팀원분들께서 ‘역할론 관점’과 ‘스트레스’적인 부분보다는 ‘우리’의 관점으로 어떻게 하면 우리의 목표를 더 성공적으로 만들어낼 수 있을지에 대해 함께 고민하고, 체크하고, 보완해 주셔서 과제를 성공적으로 마무리할 수 있었습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;이러한 과정 속에서 &lt;strong&gt;서로 부족한 부분도 자연스럽게 채워나갈 수 있었고, 무엇보다 팀원분들 모두 실력뿐만 아니라 좋은 성품까지 갖추고 계셔서 앞으로 함께 성장하며 미래를 기대할 수 있는 좋은 환경&lt;/strong&gt;을 갖추고 있는 팀으로 말씀드려보고 싶네요. 그리고 제가 이렇게 기획자로서 인터뷰를 진행할 수 있게 된 것도 다 지금의 팀원들 덕분이라고 생각하고 있습니다. ^^&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/kyh003.jpg&quot; alt=&quot;kyh003&quot; style=&quot;width:60%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;마무리하며&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-본-직무에-관심을-가지고-계신-예비-기획자분들께-한-말씀-부탁드립니다&quot;&gt;Q. 본 직무에 관심을 가지고 계신 예비 기획자분들께 한 말씀 부탁드립니다.&lt;/h3&gt;
&lt;p&gt;프로젝트를 진행하다 보면 정체되기도 하고, 상황이 급변하기도 해요. 그러다 보면 정리와 동시에 프로젝트를 진행해야 하는 상황이 발생하기도 하는데요. 이런 상황 속에서도 항상 유연하게 프로젝트를 진행해나가고, 팀워크를 유지할 수 있는 비결은 &lt;strong&gt;책임감을 바탕으로 본인 프로젝트를 꼼꼼하게 완성해나가며 항상 서로를 신뢰하는 긍정적인 영향을 주는 동료분들로 구성되어 있기 때문이라고 생각해요.&lt;/strong&gt;&lt;br /&gt;
새롭게 만나게 될 예비 기획자분들께서도 이러한 긍정적인 영향을 주고받을 수 있는 분이면 좋겠습니다. &lt;strong&gt;마지막으로 커뮤니케이션 스킬도 중요하지만 Product에 대한 지식을 갖추는 부분 꼭! 잊지 마시고요. 주도적으로 업무를 이끌어 나가는 것을 선호하시는 분들께는 분명 좋은 기회가 될 것으로 말씀&lt;/strong&gt;드려 보고 싶네요.&lt;/p&gt;

&lt;p style=&quot;color:gray; font-size: 100%; text-align: Center;&quot;&gt;&lt;a href=&quot;https://career.woowahan.com/?keyword=&amp;amp;category=jobGroupCodes%3ABA005002&amp;amp;jobCodes=BA007014,BA007015#recruit-list&quot;&gt;기획직군 모집공고 바로가기&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/khj001.png&quot; alt=&quot;khj001&quot; style=&quot;width:60%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;기획자-김현정--개발자-우태균--b마트서비스&quot;&gt;기획자 김현정 ∙ 개발자 우태균 / B마트서비스&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;담당업무 소개&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-우아한형제들의-b마트서비스팀에서-맡고-있으신-역할과-하루일과를-소개해-주세요&quot;&gt;Q. 우아한형제들의 B마트서비스팀에서 맡고 있으신 역할과 하루일과를 소개해 주세요.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;김현정님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;안녕하세요. 김현정입니다. B마트에서 팀원들과 함께 B마트 서비스를 만들고 있습니다.&lt;/strong&gt;&lt;br /&gt;
B마트 서비스가 배민마켓이라는 서비스 명칭을 지녔던 시절부터 함께 해왔는데요,&lt;br /&gt;
배민에서 ‘마트 장보기’ 배달이 가능하다는 것이 생소하던 시절부터 &lt;strong&gt;미래로 나아가기 위해 고객에게 어떤 가치를 어떠한 단계를 거쳐 제공할 수 있을까를 고민하고 구현하며, 유저 피드백을 통해 다음을 고민하는 사이클&lt;/strong&gt;을 돌리고 있습니다.&lt;/p&gt;

&lt;p&gt;직무는 서비스 기획이지만, B마트서비스팀에서의 서비스 기획 업무는 PO, PM, 서비스기획, UX 디자이너 등 직무 타이틀에 갇히지 않고, 필요에 따라 경계를 자유롭게 넘나든다고 생각하고 있어요. &lt;strong&gt;서비스의 비전과 목표를 고민하는 일부터 함께 참여하여, 과제의 목적과 목표를 정의하고 이를 해결하기 위한 액션 아이템들을 낼 수 있는 환경에서 일하고 있습니다. 분기별 방향성에 맞게 ‘우리가 이 일을 왜, 어떻게 할 수 있을까?’를 구성원들과 함께 고민하고 있고요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;우선순위, 리소스, 영향 등의 제약 사항들 간에 균형을 유지하면서 로드맵도 그리고, 과제를 구체화시키면서 디자이너분들과 UX도 함께 고민하고, 오픈 후속 계획까지 담당하는 일을 하고 있습니다. 마지막으로 서비스에 대한 방향도 중요하지만 팀원들과 더 효과적으로 즐겁게 일할 수 있는 협업에 대한 방향을 고민하고 시도해보는 일들도 함께 하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;하루 일과를 소개드리면 매일 오전 스크럼을 진행하고, 주 1회는 스크럼 직후 서비스와 관련된 지표를 브리핑하고 특이사항을 공유하는 파트별 회고를 하고 있어요.&lt;/strong&gt; 데일리 업무로는 팀 내외부의 각 이해관계자들을 소집하여, 과제의 방향을 잡아가며 상세기획을 설계하거나 실험 방향을 논의하고 개발/QA 진행 상황과 이슈를 파악하고 대응하면서 하루를 보내고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;우태균님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;안녕하세요. B마트서비스팀에서 백엔드 개발자로 일하고 있는 우태균입니다.&lt;/strong&gt;&lt;br /&gt;
B마트서비스팀은 고객분들이 직접적으로 사용하는 앱과 웹 서비스를 만들고 있는데요.&lt;br /&gt;
저와 같은 백엔드 개발자들은 서비스에 필요한 각종 API를 제공하고 상품, 카탈로그와 같이 노출에 필요한 데이터를 관리하고 제공합니다.&lt;/p&gt;

&lt;p&gt;저를 포함 네 명의 백엔드 개발자들은 여러 영역을 넘나들며 함께 작업하고 있는데요, 최근 저는 다양한 상품을 고객들이 원하는 시점에 원하는 구성으로 보여주기 위해 노력하고 있어요. &lt;strong&gt;개인화 추천 상품 구좌와 AB 테스트를 통한 데이터 기반의 서비스 발전을 위한 기반 작업을 하고 통계 데이터를 수집, 분석하는데 기여하고 있습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;저희 팀은 기획자, 프론트 개발자, 백엔드 개발자들이 모두 함께하는 만큼 커뮤니케이션이 매우 중요합니다.&lt;/strong&gt;&lt;br /&gt;
그렇기 때문에 맡은 &lt;strong&gt;과제의 시작부터 모두 같은 방향을 보고 나아갈 수 있도록 함께 논의하고 있고, 일의 진행 상황을 데일리 스크럼과 상시 회고로 공유하고 있습니다.&lt;/strong&gt; 이런 업무 체계는 백엔드 개발자들끼리도 마찬가지인데요. &lt;strong&gt;코드 리뷰를 포함해 서로의 업무 상황을 수시로 공유합니다.&lt;/strong&gt; 누군가의 부재에도 팀 업무에 차질 없이 대응하고, 맡은 과제의 업무량이 많을 때에도 항상 서로 도움을 주고받을 수 있어, 업무 공유를 중요하게 생각하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;일하는 방식&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-서로가-가장-잘하고-있는-점은-무엇인가요&quot;&gt;Q. 서로가 가장 잘하고 있는 점은 무엇인가요?&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;현정님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;태균님은 언제든 문제를 해결하기 위한 방안에 대해 터놓고 함께 의논할 수 있는 개발자입니다.&lt;/strong&gt; 제가 종종 태균님에게 ‘이 과제는 태균님 이름도 기획에 넣어야된다’라는 이야기를 하곤 하는데요. ‘HOW TO’가 다 정해져 있는 단계가 아니라, ‘우리는 지금 이런 문제가 있고, 문제를 해결하기 위해 어떤 방향성이 가장 적합할까?’를 함께 터놓고 고민해나가고 있기 때문입니다.&lt;/p&gt;

&lt;p&gt;우아한형제들에 입사하기 전에는 ‘개발자들에게 많이 물어보는 것은 좋지만, 모르는 것을 너무 많이 티 내지는 말아야겠다’라는 어리석은 두려움이 있었던 것 같아요. 또는 ‘서비스 과제에 대한 명확한 해결 방향은 기획자가 가지고 있어야 한다.’라는 생각들도 가지고 있었죠.ㅎㅎ&lt;br /&gt;
지금은 문제들을 터놓고 이야기하고, 모르는 것도 바로 물어보면서 협업이 쫀쫀해지고 있다고 생각하고 있는데요, &lt;strong&gt;이렇게 생각이 변하게 된 배경에는 태균님과 같은 개발자분들의 프로덕트에 대한 책임감과 동료와 협업하는 자세가 있어서라고 생각하고 있어요. 고맙습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;태균님은 현재 백엔드 개발자로 일하고 있지만, 앱에 대한 이해도도 높아 백엔드와 앱 모두를 동시에 고려해야 하는 상황의 이슈를 파악하기 위해 논의할 때도 많은 도움이 되고, 커뮤니케이션 능력도 뛰어나셔서 태균님께 열심히 배우고 있는 중입니다. :)&lt;/strong&gt;&lt;br /&gt;
앞으로도 이것저것 더 많이 배울테니 잘 부탁드립니다!&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;태균님:&lt;/strong&gt;&lt;/span&gt; 이렇게 앞에서 칭찬을 들으니 부끄럽네요.ㅎㅎ &lt;strong&gt;현정님은 항상 발전하는 분이에요. B마트 서비스가 빠르게 성장하면서 그동안 하지 못했던 시스템적인 부분들도 많이 챙기게 되었어요.&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;추천 로직, 각종 서비스 지표 관리, AB 테스트 실험과 같은 기존 UX/UI에 익숙하게 진행하시던 기획과는 또 다른 업무임에도 특유의 꾸준함으로 공부하고 성장하며 일이 잘 될 수 있게 큰 역할&lt;/strong&gt;을 해주셨어요.&lt;/p&gt;

&lt;p&gt;항상 밝은 기운으로 일하시는 &lt;strong&gt;현정님은 늘 상대방 입장에서 생각하고 배려심 넘치는 커뮤니케이션을 자랑하세요.&lt;/strong&gt; 일을 하다보면 힘든 순간도 분명 있을 텐데 언제나 긍정적인 기운으로 분위기를 살려주셔서 현정님과 함께 협업할 때면 저도 힘을 내고 일에 더 집중하게 됩니다.&lt;br /&gt;
다른 팀과 협업할 일도 많고 회의도 너무너무 많은 현정님, 부디 지치는 일 없이 언제나 행복하게 함께 일하길 바라요!&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;현정님:&lt;/strong&gt;&lt;/span&gt; 저도 태균님에게 항상 긍정적인 에너지를 받으면서 일하고 있어 고마워요.ㅎㅎ 성장하는 경험은 훗날 미화될 수 있지만 그 과정이 힘들 때도 있는데요, &lt;strong&gt;태균님을 비롯한 B마트서비스팀 구성원들이 만들어주시는 분위기 덕에 여러 심리적 쿠션을 지니고 천천히 발전해 나갈 수 있을 것 같다는 생각을 갖고 있어요. 운이 좋다고 생각하고 있습니다. 팀원들과 함께 일희는 자주 하되 일비는 적게 하면서 일할 수 있었으면 좋겠습니다. :)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/khj002.jpg&quot; alt=&quot;khj002&quot; style=&quot;width:60%; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;협업에 관한 의견&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-협업하시며-가장-신경-쓰시는-점은-무엇인가요&quot;&gt;Q. 협업하시며 가장 신경 쓰시는 점은 무엇인가요?&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;현정님:&lt;/strong&gt;&lt;/span&gt; 협업을 하면서 가장 신경쓰는 부분은 함께 일하는 구성원들이 한배를 타고 가게 하는 거예요. &lt;strong&gt;목적을 성취하기 위해서 함께 일을 하는데, ‘이건 누군가 시켜서 하는 일이다, 해야만 해서 하는 일이다’라는 생각이 조금 덜 들었으면 좋겠고, 해당 과제를 수행하면서 본인의 성장도 함께 느꼈으면 좋겠어요.&lt;/strong&gt; 회사 일이 항상 재밌을 수는 없겠지만 ‘그래도 이 정도면 괜찮다’라고 느끼면서 일할 수 있게 커뮤니케이션하고, 작은 장치들을 조금씩 더 구성해보고 있어요.&lt;br /&gt;
하나의 프로젝트를 위해 다양한 구성원들과 협업하기 때문에 스스로를 돌아보면 아직 모든 구성원들에게 그런 마음을 전달하는 장치를 적용하거나 하지는 못하고 있는데요, 적어도 팀 구성원분들에게만이라도 그 마음이 와닿을 수 있도록 노력하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;태균님:&lt;/strong&gt;&lt;/span&gt; 저도 현정님이 놓은 장치에 당하고 있는 거군요?&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;현정님:&lt;/strong&gt;&lt;/span&gt; 글쎄요.. 그럴지도 몰라요ㅎㅎㅎ 당해주셨다면 감사드리고요ㅎㅎㅎ 태균님은요? 태균님도 팀 내외부 모두 협업이 잦으신 편인데, 협업하시면서 무엇을 가장 신경 쓰시는지 궁금해요.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;태균님:&lt;/strong&gt;&lt;/span&gt; 저도 현정님 얘기에 전적으로 공감해요. 팀의 업무 특성상, 언제 어떤 일이 새롭게 생길지 모르고 사용자와 바로 맞닿아 있는 영역을 개발하기 때문에, &lt;strong&gt;팀 구성원들과 공감하며 과제에 함께 몰두하는 과정이 반드시 필요하다고 생각합니다.&lt;/strong&gt; 현정님이 신경 써 주시는 부분들 덕분에 자칫 다운될 수 있는 분위기도 긍정적으로 타파해나갈 수 있었던 것 같아요.&lt;br /&gt;
협업을 하다 보면 함께 일하는 상대로부터 감정적인 부분에서도 영향을 받게 되는데요. 무작정 밝은 분위기를 넘어 &lt;strong&gt;서로 힘을 주고 생산적으로 나아갈 수 있게 하는 서로를 대하는 태도와 마음가짐이 중요하다고 생각해요. 그리고 중요한 커뮤니케이션을 뒷받침해 주는 건 각자의 역할을 최선으로 하고 있다는 신뢰인 것 같아요.&lt;/strong&gt; 현정님은 누가봐도 너무 열심히해요. 항상 현정님을 보며 더 노력하려합니다.ㅎㅎ&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;역량에 관한 생각&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-b마트서비스팀에서-좋은-성과를-내기-위해서는-어떤-역량이-필요한가요&quot;&gt;Q. B마트서비스팀에서 좋은 성과를 내기 위해서는 어떤 역량이 필요한가요?&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;태균님:&lt;/strong&gt;&lt;/span&gt; 서비스 사용자 즉, 고객의 입장에서 충분히 생각하고 서비스를 발전시켜 나가는 게 중요합니다. 개발자로 일을 하다 보면 편한 길과 어렵지만 보다 서비스에 이로운 길이 보이기 마련인데요. 이때 &lt;strong&gt;생각의 흐름이 개발할 기능에 대한 구현으로부터 시작되면 편한 길에 맞춰 편협한 시각을 갖기 쉬운 것 같아요. 이를 항상 경계해야 하고 실제 사용될 환경부터 내부 시스템까지 고객 입장으로 설계하고 고민하는 게 매우 중요해요.&lt;/strong&gt; 프론트 개발자들에게 제공할 기능을 넘어 어디서부터 시작되어 이 서비스가 제공되는지 큰 흐름을 놓치지 않고 생각해야 합니다.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;현정님:&lt;/strong&gt;&lt;/span&gt; 말씀 주신 부분 외에 저는 &lt;strong&gt;커뮤니케이션 능력, 고객 분석 능력을 꼽아보겠습니다.&lt;/strong&gt; 커뮤니케이션에 대해 먼저 이야기하자면 B마트는 다양한 유관 부서와의 협업 밀도와 빈도 모두 굉장히 높은 편이에요. &amp;lt;가장 좋은 가치를 제공하겠다&amp;gt;라는 큰 꿈은 같지만, &lt;strong&gt;팀마다 서로의 의견이 다를 수 있다는 것은 불가피하다고 생각하고 있어요. 이러한 상황에서 과제가 발의되었던 목적을 돌아보고 서로의 시각이 다른 이유를 살피면서, 더 나은 방향이나 협의점을 함께 모색할 수 있도록 조율해 갈 수 있어야 한다고 생각해요.&lt;/strong&gt; 또 팀원분들과도 빠른 커뮤니케이션을 하면서 서로의 이해도나 공감대를 맞추고, 문제를 해결할 수 있도록 하는 부분이 중요하다고 생각합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;두 번째로는 &amp;lt;고객 분석 능력&amp;gt;이라고 말씀을 드렸는데요,&lt;/strong&gt; &amp;lt;데이터 분석 역량&amp;gt;이라고 말하지 않은 이유는 꼭 쿼리를 직접 짜지 않더라도, 다른 분들과 협업하면서 &lt;strong&gt;서비스 이용 현황을 살피는 능력, 정성적인 리서치에서 발견할 수 있는 인사이트를 모두 포함하고 싶어서&lt;/strong&gt;이기도 해요. 또 통계에 대한 기본적인 개념을 갖추면서 이러한 데이터를 바라보아야 잘못된 해석 등의 오류를 피할 수 있다는 것을 데이터분석팀과 협업하면서 배우고 있어서, 이런 기본적인 통계 지식을 알아가고자 하는 마음가짐을 &amp;lt;고객 분석 능력&amp;gt; 안에 모두 포함하고 싶습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B마트에서 기획자가 실제 과제를 착수할 때, 이 과제에서 우리에게 가장 중요한 지표가 무엇일까 고민하고, 로그 설계에 대한 부분들도 데이터분석팀과 함께 협업하면서 챙기고 있기 때문에, 업무를 하다 보면 자연스럽게 중요도를 느끼게 되는 부분&lt;/strong&gt;이기도 합니다.&lt;br /&gt;
아직은 저도 많이 부족한 부분이라, 개발자분들께 많이 물어보기도 하고, 기획자들끼리 주 1회 서비스 분석 스터디도 함께 하고 있습니다. 처음 입사할 때부터 고객 분석 능력 스킬 셋이 높을 필요는 없어요. 함께 알아가고자 하는 의지만 있어도 충분합니다. :)&lt;/p&gt;

&lt;h3 id=&quot;q-그렇다면-b마트서비스팀의-백엔드-개발자로서는-어떤-기술-역량과-자질이-요구되나요&quot;&gt;Q. 그렇다면, B마트서비스팀의 백엔드 개발자로서는 어떤 기술 역량과 자질이 요구되나요?&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;태균님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;개발 영역에 관계없이 커머스 분야에 필요한 기술역량으로 소개 드릴게요.&lt;/strong&gt;&lt;br /&gt;
B마트는 네이티브 앱과 웹이 적절히 결합된 형태를 취하고 있어요. 그렇기 때문에 &lt;strong&gt;각 환경이 갖는 특성과 JavaScript Interface를 비롯한 데이터 교환의 흐름, 서버와의 통신을 위한 데이터 처리 구조에 익숙하거나 잘 알고 있어야 해요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;저희 백엔드 기술 스택으로는 Java 8 + Spring + Redis + Mysql(Aurora,maria DB) + Queue(aws SNS + SQS)로 이루어져 있어요.&lt;/strong&gt; 주된 작업은 대부분 이 기술 스택으로 이루어지기 때문에 기본적으로 갖추어야 할 역량이라고 볼 수 있습니다. 이 밖에도 모니터링, 로그 시스템, 추천/통계 시스템을 위해 InfluxDB, Kafka, Airflow, Athena, Grafana, Prometheus 등 다양한 기술을 상황에 맞게 선택하여 사용해요.&lt;/p&gt;

&lt;p&gt;배포 환경 구성과 부하 테스트, 각종 스크립트 영역까지 포함하면 더 다양해질 있는데 이런 기술들을 모두 잘하는 건 어렵습니다.&lt;br /&gt;
&lt;strong&gt;그렇게 때문에 개발자는 본인이 잘할 수 있는 개발 분야는 요구받은 것 이상으로 주도적으로 수행해 성취를 이뤄내고, 부족한 분야지만 책임감이 따르는 입장에서는 빠르게 학습하고 습득해 자신의 영역을 넓혀가려는 자세가 뒷받침되어야 합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;그 외 앱 개발 환경도 말씀드리면 Swift, Kotlin 전환, Rx, DI 적용, 아키텍처 변환 등의 과정을 거쳐 지금의 기술 스택을 갖게 되었어요.&lt;/strong&gt; &lt;strong&gt;웹은 Vue.js, React.js 모두 활용되고 있고 디자인 시스템을 비롯한 공통 컴포넌트 확장 등을 통해 끊임없이 더 좋은 모습으로 발전하고 있어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B마트뿐 아니라 우아한형제들은 개발자로서 성장하는데 좋은 환경을 갖추고 있습니다.&lt;/strong&gt; 개인의 역할을 스스로 한정 짓지 않고 주위를 둘러보며 필요한 일들을 하나하나 함께 이루어 나간다면 기술 역량은 자연스럽게 높아진다고 생각해요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/khj003.jpg&quot; alt=&quot;khj003&quot; style=&quot;width:60%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;우아한형제들 문화&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-두-분이-함께-회사와-b마트서비스팀의-매력을-자랑해-주세요&quot;&gt;Q. 두 분이 함께 회사와 B마트서비스팀의 매력을 자랑해 주세요!&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;현정님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;B마트서비스팀은 한 팀에 웹, 앱, 백엔드 개발, 기획자가 모두 한 팀인 목적 조직으로 되어 있어요.&lt;/strong&gt; 디자이너는 다른 팀이지만 호흡을 잘 맞춰와서 거의 한 팀처럼 일하고 있습니다. 때문에 &lt;strong&gt;&amp;lt;어떤 문제를 해결하고 싶다&amp;gt;라는 아이디어가 있을 때, 각 구성원들이 빠르게 의견을 주고받으며 문제 해결에 초점을 맞출 수 있다는 장점이 있어요.&lt;/strong&gt; 팀의 역학관계, 리소스 등 조심스러울 수 있는 부분보다 문제의 본질에 조금 더 초점을 둘 수 있죠.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;서로의 파트들과 동고동락하는 모습을 함께 봐오기 때문에, 서로의 파트에 대한 이해도도 쌓아올릴 수 있는 측면이 있어요.&lt;/strong&gt; 이전 회사들에서 기능조직에서도 있어봤지만, 개인적으로는 &lt;strong&gt;목적 조직만의 가진 장점도 아주 매력적이라고 생각합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;태균님:&lt;/strong&gt;&lt;/span&gt; 맞아요! 특히나 그 구성원분들이 모두 좋은 사람들이라는 점도 너무너무 큰 장점이에요. 이 팀에서 일하면서 즐거웠던 경험이 아주 많거든요. 촉박한 일정이 주어졌을 때도 함께 웃으며 열정적이고 도전적으로 일할 수 있는 팀원들이에요.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;여러 분야의 개발자들이 함께 일하다 보면 서로의 영역에 대해 더 이해하게 되고 그만큼 배우게 되는 점도 많아요. 저의 경우에도 처음에는 앱 개발자로 이 팀에 합류했지만 백엔드 분야의 업무도 조금씩 받아 가며 직무를 전환한 케이스&lt;/strong&gt;에요. 아무리 제가 백엔드 개발을 할 수 있었다 하더라도 서로 히스토리를 모르고 &lt;strong&gt;업무 연계성이 떨어지는 분리된 팀 구조였다면 불가능한 일이었겠죠. 서비스에 관심이 많고 팀이 함께 같은 목표로 나아가는데 의미를 가진 분이라면 저희팀은 단연 최고의 팀이라고 얘기할 수 있어요!&lt;/strong&gt; 현정님~ 현정님은 우아한형제들 회사 자체에 대해서는 어떻게 생각하세요?&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;현정님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;회사가 구성원의 의견에 귀 기울이고, 아쉬운 점들을 개선해나가려는 점들이요. 또 결혼, 임신, 육아하시는 분들이 적용할 수 있는 현실적인 제도들을 지원하고 있고, 그런 제도들을 계속 보강시켜나가려는 점들도 큰 매력이라고 생각합니다.&lt;/strong&gt; 우리가 맞이할 고객의 폭이 넓어질수록, 구성원들의 다양성이 보장된 환경에서 일해야 고객에게 더 좋은 서비스를 만들어갈 수 있다고 생각하고 있는데요, 이런 점에서도 회사가 다양한 환경과 상황의 구성원들과 함께 일할 수 있도록 노력하는 부분들을 긍정적으로 생각하고 있습니다. 재택근무에 대해서 적극적으로 지원하는 부분들도 고맙고요! 그리고, &lt;strong&gt;애용하고 있는 도서비 구매 지원! 마음껏 읽고 싶은 책을 읽을 수 있어서 행복합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;태균님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;다시 강조하지만 전 회사의 소통 문화도 큰 강점인 것 같아요!&lt;/strong&gt; 회사가 꽤 크게 성장했는데도 대표님이 매주 진행하시는 우아한 수다 타임, 매달 진행되는 전사발표는 회사의 방향성 뿐만 아니라 모든 구성원의 소망까지 서로 나누고 함께 나아가려는 모습이라 참 좋다고 생각해요.&lt;br /&gt;
단순히 회사의 직원으로써 맡은 업무만 하는 입장이 아니라 &lt;strong&gt;우아한형제들의 구성원이 되어 함께 고민하고 목소리를 낼 수 있다는 마음을 갖게 해줘요.&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;마무리하며&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-우아한형제들에-입사를-희망하시는-분들에게-응원의-한-말씀-부탁드립니다&quot;&gt;Q. 우아한형제들에 입사를 희망하시는 분들에게 응원의 한 말씀 부탁드립니다.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;태균님:&lt;/strong&gt;&lt;/span&gt; 우아한형제들은 참 특별한 회사라고 생각해요. 밖에서 보았던 우아한형제들은 &lt;strong&gt;구성원들이 똘똘 뭉치는 문화를 가졌다고 생각했는데 입사하고 나니 작은 행사와 문화 하나하나가 구성원들이 함께 참여할 수 있도록 이루어지더라고요.&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;내가 공감하는 일을 좋은 사람들과 함께 만들어가는 이곳에서 같이하게 될 분들이 기대되고 또 응원합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;현정님:&lt;/strong&gt;&lt;/span&gt; 아직도 저희는 갈 길이 멉니다! 이 팀에서는 &lt;strong&gt;내가 하고자 했던 일들을 조금씩 도전해볼 수 있는 기회를 가지게 되실 거라고 생각해요.&lt;/strong&gt; 서비스에 대해서 다양한 구성원들과 빠르게 &lt;strong&gt;서비스를 만들어가면서 함께 고민하고, 성장해나가실 분들 모두 환영합니다. 저희가 더 잘 부탁드려요!&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;color:gray; font-size: 100%; text-align: Center;&quot;&gt;&lt;a href=&quot;https://career.woowahan.com/?keyword=&amp;amp;category=jobGroupCodes%3ABA005002&amp;amp;jobCodes=BA007014,BA007015#recruit-list&quot;&gt;기획직군 모집공고 바로가기&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/khn001.png&quot; alt=&quot;khn001&quot; style=&quot;width:60%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;기획자-김해니--개발자-송인태--라이더서비스&quot;&gt;기획자 김해니 ∙ 개발자 송인태 / 라이더서비스&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;담당업무 소개&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-우아한형제들에서-담당하시는-업무와-역할을-소개해-주세요&quot;&gt;Q. 우아한형제들에서 담당하시는 업무와 역할을 소개해 주세요.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;김해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;안녕하세요. 딜리버리플랫폼팀 라이더서비스파트에서 일하고 있는 서비스기획자 김해니입니다.&lt;/strong&gt;&lt;br /&gt;
배민커넥터가 배달을 수행하기 위한 서비스를 기획하고 운영하며 개선사항을 모니터링(Monitoring)하고, 사업팀과 운영 정책을 수립하고 이를 바탕으로 화면 UI/UX, 어드민을 기획하고 있어요.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;송인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;안녕하세요. 딜리버리플랫폼팀 라이더서비스파트에서 백엔드 개발자로 일하고 있는 송인태입니다.&lt;/strong&gt;&lt;br /&gt;
파트에서 저는 배민커넥트 생애주기에 관련된 업무를 담당하고 있습니다. 저는 라이더 분들이 서비스를 편리하게 사용할 수 있도록 신규 기능을 개발하거나 개선을 진행하고, 시스템 지표들을 모니터링하며 시스템이 안정적으로 동작할 수 있도록 운영하는 업무를 맡고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;일하는 방식&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-두-분은-주로-어떤-업무를-함께-하시나요&quot;&gt;Q. 두 분은 주로 어떤 업무를 함께 하시나요?&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;라이더분들의 라이프 사이클을 함께 관리하고 있어요. ‘배민커넥트’ 런칭 후 라이더 수가 폭발적으로 증가하였고, 이로 인해 배민커넥트의 다양한 사용자들을 위한 기능을 기획, 개발&lt;/strong&gt;하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; 조금 더 상세히 설명드리면, &lt;strong&gt;배민커넥트앱을 통해 더욱 안전하고 편리하게 배달을 수행할 수 있도록 배민커넥트 지원 관리, 시간제 보험 구축, 정산시스템 관리 등의 업무&lt;/strong&gt;를 진행하고 있어요.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; 맞아요. 또한 &lt;strong&gt;라이더분들에게 배달에 필요한 유익한 정보를 제공하기 위해 개인화된 운행 통계를 제공하고, 맞춤형 안내를 하기 위해 브레이즈도 도입&lt;/strong&gt;하고 있죠.&lt;/p&gt;

&lt;h3 id=&quot;q-맡은-과제의-업무-우선순위는-어떻게-정하시나요&quot;&gt;Q. 맡은 과제의 업무 우선순위는 어떻게 정하시나요?&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;분기별 진행해야 하는 큰 과제 단위 업무를 현업부서와 논의하여 우선순위에 따라 진행합니다.&lt;/strong&gt; 요청 업무 외에도 자발적으로 서비스를 운영하면서 발견한 개선사항들을 &lt;strong&gt;기획/개발 프리 플래닝을 통해 정합니다. 기획 프리 플래닝에서는 현업부서에서 한 주간 전달받은 이슈들을 공유하고 주 단위로 꼭 완수해야 하는 업무들을 정리&lt;/strong&gt;해요. 예를 들어 ‘이번 주는 세부 정책 논의가 완료되어야 한다, 사용자 스토리 정의를 시작해야 한다’등의 전체 과제의 세부 실행 목표와 일정을 세웁니다.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;개발 플래닝에서는 개선해야 할 일을 각자 티켓으로 만들고, 매주 금요일에 만나서 티켓을 보며 우선순위를 다 같이 정하고 있어요. 그 후 월요일에 파트 플래닝에서 해당 내용을 기획자분들과 정리하여 해당 주 스프린트에 포함할지 여부를 결정해요.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;q-과제를-진행하는-순서는-어떻게-되나요&quot;&gt;Q. 과제를 진행하는 순서는 어떻게 되나요?&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; 과제의 배경, 목적이 정해지고 나면 &lt;strong&gt;담당자들이 모두 모여 다양한 의견을 주고받을 수 있는 킥오프 미팅(Kickoff meeting)을 진행해요. 미팅에서는 정책을 협의하거나 리스크를 검토해 사용자 스토리를 정의하는 상세기획을 시작합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;저도 상세기획에 참여하여 현재 구축되어 있는 시스템의 영향 범위를 파악하고, 지원할 수 있는 범위안에서 피드백을 주고받아요.&lt;/strong&gt; &lt;strong&gt;기획자분들과 같이 Task를 정리하고 개발 일정을 수립하고 개발을 진행합니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; 기획자인 저는 그동안 &lt;strong&gt;개발에 필요한 기능을 함께 정의하고 QA 담당자분들과 Test Case를 정리하여 QA를 수행합니다. 오픈 전 배포 시나리오를 통해 운영, 시스템에서 챙겨야 할 부분을 정리하고 배포&lt;/strong&gt;합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/khn002.jpg&quot; alt=&quot;khn002&quot; style=&quot;width:60%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;협업에 관한 의견&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-두-분이-함께-협업하여-이룬-성과나-성취의-순간을-이야기-해주세요&quot;&gt;Q. 두 분이 함께 협업하여 이룬 성과나 성취의 순간을 이야기 해주세요.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; 저는 &lt;strong&gt;해니님이랑 같이 라이더분들이 배민 커넥트 앱을 통해서 지원할 수 있게 한 프로젝트가 가장 기억에 남아요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; 저도 이 프로젝트가 가장 인상 깊은데요. 기존에는 외부 시스템을 통해 가입을 해야 해서 프로세스가 복잡했어요. &lt;strong&gt;배민커넥트 지원자들이 지원을 완료하는데 허들이 되었고, 배민커넥트 앱에서 한 번에 가입을 완료할 수 있게 하는 방법을 고민했습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; 맞아요. 지원자뿐만 아니라 관리자도 타 시스템에서 지원관리를 해야 하기 때문에 불편한 점이 많았는데요. &lt;strong&gt;우리 시스템으로 일원화함으로써 관리에 필요한 기본 기능 외에 앞으로 더 다양한 기능을 구현할 수 있는 기반을 만들었어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;지원자는 지원이 편리해지고 관리자는 심사절차가 간편해지면서 라이더분들이 더욱 빠르게 지원을 완료해 배달을 바로 수행할 수 있게 되었어요.&lt;/strong&gt; 이점이 저는 큰 성취의 순간이었어요. &lt;strong&gt;아직 개선할 점이 많이 남아있지만, 이런 성취감이 더 열심히 일할 수 있는 원동력이 된답니다.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;q-협업-과정에서-서로에게-가장-고마웠던-순간을-소개해-주세요&quot;&gt;Q. 협업 과정에서 서로에게 가장 고마웠던 순간을 소개해 주세요.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;항상 해니님한테 고마워요. 해니님은 다른 유관부서와 원활하게 소통하고 그들의 요구 사항을 명확하게 정리하여, 이에 대해 기획 및 정리를 잘 수행해 주십니다. 또한 프로젝트를 진행할 때 다양한 사람들의 의견을 잘 들어주세요.&lt;/strong&gt; 개발하다 발견되는 논의 사항에 대해 이야기를 들어주고 의견을 반영하면서 프로젝트가 성공할 수 있도록 이끌어 나가세요. 그리고 결정적으로 요즘 쿵짝이 잘 맞는 거 같아요! &lt;strong&gt;어떤 업무를 개선해야겠다 하면 벌써 해니님이 생각을 해주시고 있더라고요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;인태님과는 액션배우들 합을 맞춘 것처럼 티키타카 호흡이 좋아요. 특히 제가 고마운 점은 과제를 수행할 때 기획, 개발자 입장에서 고민이 생기는 지점이 많은데요. 그때마다 인태님은 본인이 생각하는 방향을 정말 친절히 설명해 주세요.&lt;/strong&gt; 결론만 공유하는 것이 아닌 ‘스스로 왜 고민하게 되었는지, 어떤 방향을 생각하고 있는지’ 시간을 많이 할애해서 이해시켜 주세요. 그래서 &lt;strong&gt;기획자 입장에서 개발 구현 내용에 대해 선명하게 알 수 있어요. 그리고 과제에 대해 만나서 논의하는 시간도 자주 가져요.&lt;/strong&gt; 만나서 정리하는 시간이 많다 보니 ‘물어볼까 말까 했던 질문’들도 편하게 꺼낼 수 있어서 협업할 때 정말 큰 도움을 받고 있어요.&lt;/p&gt;

&lt;h3 id=&quot;q-타-부서직군과-협업하는-일도-많으실듯한데요-협업-과정이-궁금합니다&quot;&gt;Q. 타 부서/직군과 협업하는 일도 많으실듯한데요, 협업 과정이 궁금합니다.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; 타 조직, 부서에서 요청사항을 JIRA 티켓으로 생성하면 해당 요청에 대해 궁금한 내용, 추가로 정의되어야 하는 정책들을 확인해요. &lt;strong&gt;요청 내용 기반으로 생각하는 방향을 정리합니다. 필요한 경우 미팅을 통해 생각을 맞춰보는 과정을 거쳐요. 그렇게 회의에서 논의하고 결정된 사항들을 WIKI에 정리해두어 담당자들이 언제든지 과제 내용을 확인할 수 있게 해요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; 과제를 시작하게 되면 &lt;strong&gt;담당자들과 자주 소통을 해야 하는데, 이를 위해 Slack 과제 채널을 만들어 소통하고 있어요.&lt;/strong&gt; 과제 채널에서 프로젝트에 참여하는 모든 담당자가 논의할 내용을 빠르게 논의하고 공유할 수 있어 유용합니다. &lt;strong&gt;또한 프로젝트 담당팀 외에 보안, 시스템, 공통으로 함께 사용하는 부분에 대해 지원이 필요한 경우가 생기는데, 이는 각 팀마다 슬랙 Support 채널을 운영&lt;/strong&gt;하고 있어 원활하게 도움받고 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;q-협업할-때-가장-중요하게-생각하시는-세-가지를-꼽아주세요&quot;&gt;Q. 협업할 때 가장 중요하게 생각하시는 세 가지를 꼽아주세요.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;인태님과 함께 생각해 보고 커뮤니케이션, 공유하기, 존중하기 세 가지를 꼽아봤어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;많은 분들이 공감하시겠지만 협업에서 가장 중요한 것은 커뮤니케이션이라고 생각합니다.&lt;/strong&gt; 경험상 저도 만족스럽게 마무리한 과제를 돌이켜보면 담당자들 간에 과제에 대한 생각을 맞추기 위해 많은 커뮤니케이션을 진행했고, 이 때문에 좋은 결과를 낼 수 있었던 거 같아요.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;사내에 일할 때 도움 되는 메시지들이 곳곳에 적혀있는데요. 그중에 가장 인상 깊은 것이 ‘깨알같이 공유하자’입니다.&lt;/strong&gt; 함께 일하는 담당자, 팀원들에게 깨알같이 공유하면 내가 미처 생각하지 못한 영향 범위들을 팀원이 챙겨줄 수 있어요. 또 내가 혼자만 알고 있는 시간이 길어질수록 다른 사람이 고민할 수 있는 시간이 줄어드는 것이기 때문에 깨알같이 공유하는 것이 협업에서 중요하다고 생각합니다.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;그리고 다른 동료의 의견도 존중하려고 노력해야 한다고 생각해요.&lt;/strong&gt; 우리가 해야 하는 일들은 정답이 없기 때문에 서로의 의견을 존중하고 맞춰가는 게 중요하다고 생각합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/khn003.jpg&quot; alt=&quot;khn003&quot; style=&quot;width:60%; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;역량에 관한 생각&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-두-분이-팀에서-함께하고-싶은-동료의-필수-역량-세-가지를-알려주세요&quot;&gt;Q. 두 분이 팀에서 함께하고 싶은 동료의 필수 역량 세 가지를 알려주세요.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; 함께하고 싶은 동료에 대해서 생각해 보면, &lt;strong&gt;저희는 1) 커뮤니케이션 능력이 있고, 2) 함께 일하는 것을 즐거워하고 3) 계속 성장해 나가는 분이 떠올랐어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; 협업에 주요한 점으로도 이야기했듯이, &lt;strong&gt;회사 업무는 혼자 일하는 시간보다 다른 팀원, 협업 부서와 일하고 의견을 맞춰가는 시간이 많기 때문에 커뮤니케이션은 중요한 역량이라고 생각해요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;맞아요. 그리고 함께 일하는 것을 즐거워하는 분이면 좋겠어요.&lt;/strong&gt; 어떤 분이 저희 일하는 모습을 보면서 텔레토비 같다고 하시더라고요. 저희는 텔레토비처럼 동산에 모여서 서로 의견을 주고받으며 업무를 함께 만들어 나가는 것을 좋아해요. 앞에 놓인 여러 문제에 대해 이야기하고 토론하는 것을 즐겨 하는 분이라면 좋겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; 일을 하다 보면 경험하지 못한 도메인을 접하거나, 또는 사용해보지 않은 기술적인 요소들을 써야 하는 경우들이 종종 있는데요, 이런 부분에 대해서 &lt;strong&gt;학습하며 업무에 적용해보는 시도를 하시는 분이 계시면 팀이 같이 성장하는데 많은 도움이 될 거라 생각해요.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;q-이를-통해-팀에서-어떤-노력을-하고-있나요&quot;&gt;Q. 이를 통해 팀에서 어떤 노력을 하고 있나요?&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;파트 안에서 KPT 회고를 시도해보고 있어요. (KPT 회고는 다양한 회고 방법론 중 하나로 Keep, Problem, Try의 약자)&lt;/strong&gt;&lt;br /&gt;
바쁘게 지내다 보면 일주일, 한 달이 금새 지나가고 업무를 하면서 발생한 문제들을 꺼낼 수 있는 기회가 많지 않아요. 매주 파트 회고를 갖는 시간을 정해놓고 &lt;strong&gt;KPT 방법론을 사용해서 우리가 잘하고 있어서 KEEP 할 것들을 정리하고, 한 주 동안 느꼈던 문제점을 얘기하고, 다가오는 주에 해결해볼 수 있는 것을 시도해요.&lt;/strong&gt; 이제  진행해본 지 한 달 정도 되었는데요, 처음에는 방법론을 익히는 데 오랜 시간이 걸렸지만 이제는 30분 안에 충분히 정리가 되더라고요. 예를 들어 1개 과제에 두 명의 개발자가 있을 경우 모호한 업무가 있을 때 잘 챙기지 않는 것 같다는 의견이 있었어요. KPT 회고 시간에 개발자별로 담당 역할을 정의하고 시도해봤는데 다들 만족도가 높아서 지속하게 되었어요. 업무 외에 다른 것들도 시도해보고 있는데요. &lt;strong&gt;재택근무가 길어지다 보니 업무가 겹치지 않으면 서로 만날 시간이 적다는 의견이 있었어요, 매주 근황 토크 시간을 갖고 업무 외 잡담을 나누면서 교류하고 있어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;팀에서 팀원들이 같이 성장할 수 있는 다양한 활동들을 하고 있어요. 대표적으로 테크톡이나 스터디를 많이 진행하고 있습니다.&lt;/strong&gt; &lt;strong&gt;테크톡이라는 별도의 공유하는 시간을 가지고 개발자들끼리 알고 있는 지식이나, 또는 개발을 하면서 새로 알게 된 내용들에 대해서 공유를 하고 서로 성장할 수 있게 도움을 주고 있습니다.&lt;/strong&gt; 또한 서로 같이 학습이 필요한 주제가 있다면 해당 주제에 대해서 자유롭게 스터디를 만들고 참여하여 서로 성장할 수 있는 문화를 만들고 있습니다. 이외에도 &lt;strong&gt;슬랙을 통해 서로에게 도움이 되는 다양한 책이나 기사들을 공유하는데 이 부분 또한 성장하는데 많은 도움이 된다고 생각해요.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;q-일하면서-우아한형제들에서-성장하고-있다고-느끼게-된-계기나-순간들을-소개해-주세요&quot;&gt;Q. 일하면서 우아한형제들에서 성장하고 있다고 느끼게 된 계기나 순간들을 소개해 주세요.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;저는 회고에서 나온 Action Item들을 다음에 적용하면서 일을 진행한  것을 깨달았을 때 성장을 하고 있다고 느꼈던 거 같아요.&lt;/strong&gt; 큰 과제를 마무리하거나, 장애 해소 후 회고를 하면서 개선해야 하는 점들에 대해 다양한 논의를 진행하고, 이를 통해 앞으로 더 잘 챙겨야 할 부분에 대해 반영하는 것이 성장하는데 많은 도움이 되었습니다.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;과제 진행 과정에서 ‘우리가 어떻게 하면 일을 잘할 수 있을까’에 대해 논의를 많이 하고 있어요.&lt;/strong&gt; 논의를 하다가 서로 고민하고 있는 부분에 대해 책을 추천해 주기도 하는데요. &lt;strong&gt;저의 상황과 우리의 환경을 잘 알고 있는 동료들이 추천해 주는 책이라 많은 도움이 되더라고요.&lt;/strong&gt; 책을 읽고 인상 깊었던 부분에 대해 토론해보면서 서로의 생각을 공유하고 있어요. 동료와의 책을 추천하는 과정에서도 스스로의 성장을 느끼고 있습니다. &lt;strong&gt;회사 복지로 도서비가 무제한으로 지원되어서 더욱 부담이 없다는 건 안비밀^^&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;q-우아한형제들의-성장할-수-있는-근무-환경에는-어떤-것들이-있나요&quot;&gt;Q. 우아한형제들의 성장할 수 있는 근무 환경에는 어떤 것들이 있나요?&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;회사에 멋진 동료들이 있다는 것만으로도 성장할 수 있는 근무환경이라고 생각하는데요.&lt;/strong&gt; 특히 사내에 있는 공용공간이 주는 힘이 크다고 생각해요. &lt;strong&gt;회의실을 잡지 않아도 언제든지 모여서 이야기할 수 있는 공용공간이 별도로 마련되어 있다는 점이 참 좋아요.&lt;/strong&gt; 업무 외에 관심사도 나누면서 친분을 쌓을 수도 있고, 담당업무가 아니더라도 고민하고 있는 부분에 대해 해결책을 구해보기도 해요. 동료들과 많은 얘기를 나누면서 함께 성장할 수 있어서 큰 힘이 되고 있어요.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; 저는 사내에서 주기적으로 하는 테크톡이 생각났어요. &lt;strong&gt;각 팀의 개발자분들이 경험했던 내용들에 대해 테크톡을 진행하면서 공유해 주셔서 많은 도움이 되었습니다.&lt;/strong&gt; 또한 회사에서 지원해 주는 &lt;strong&gt;도서구입비 또는 강의비 지원도 너무 많은 도움이 되었어요. 이전보다 망설임 없이 읽거나, 듣고 싶은 강의를 챙겨보고 있습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;q-라이더서비스-백엔드-개발자로-일하시며-스스로-성장하고-있다고-느낀-경험이-있다면-말씀해-주세요&quot;&gt;Q. 라이더서비스 백엔드 개발자로 일하시며 스스로 성장하고 있다고 느낀 경험이 있다면 말씀해 주세요.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; 백엔드 개발자로 일하며 다양한 도전적인 과제들을 수행해왔고, 그중 주문별 &lt;strong&gt;라이더 배치작업 성능 개선 과제를 소개하고자 합니다.&lt;/strong&gt;&lt;br /&gt;
서비스가 빠르게 성장하며 주문별 라이더 배치작업 시스템의 데이터베이스에도 영향을 주기 시작했어요. 시스템 알람을 통해 &lt;strong&gt;장애가 발생하기 전에 로그 및 지표들을 확인하며 두 가지 문제점을 발견하게 되었습니다.&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;첫 번째는 데이터를 병렬로 처리하고 있는데, 데이터양이 방대해진 탓에 사용하는 스레드 개수가 증가하고 있었고 두 번째로는 각각의 스레드들이 독립적으로 작업을 수행하여 전체 배치의 성공 여부와, 배치 작업 완료 시점을 파악하기 어려운 부분이 있었습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;마침, 저희가 사용하는 기술 중에 &lt;strong&gt;스프링 배치로 문제점을 해결할 수 있는 Partitioning 기술을 제공하고 있어서 작업을 하는 스레드수를 손쉽게 제어할 수 있었고 전체 배치 성공 여부 및 완료 시점을 파악할 수 있었습니다. 또한 파트에서 이미 사용하고 있는 기술셋을 이용함으로써 다른 개발자분이 이해하기 쉬운 구조로 만들 수 있었어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;이 경험이 인상 깊었던 것은&lt;/strong&gt; 제가 주도적으로 모니터링을 진행하면서 장애가 발생할 수 있었던 문제를 파악해 사용하는 기술을 조금 더 깊이 있게 학습하며 현재 상황에 필요한 사항을 반영하는 경험을 할 수 있었던 점과 팀분들이 지속적으로 리뷰하고 피드백을 주셔서 문제를 잘 해결해 나가며 더 큰 보람을 느꼈기 때문입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-06-07/khn004.jpg&quot; alt=&quot;khn004&quot; style=&quot;width:60%; display: block; margin: 60px auto 0; padding:1px; border:0px solid #021a40; &quot; /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;우아한형제들 문화&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-두-분이-함께-딜리버리플랫폼팀의-매력문화와-업무환경을-자랑해-주세요&quot;&gt;Q. 두 분이 함께 딜리버리플랫폼팀의 매력(문화와 업무환경)을 자랑해 주세요!&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;저희 팀 모두 서비스에 대한 애정이 남달라요.&lt;/strong&gt; 우리가 만드는 서비스에 대한 애정을 갖고 사용자의 입장에서 고민해요. 예를 들어 &lt;strong&gt;평소 모니터링(Monitoring)을 많이 하고 관련 뉴스 기사도 활발하게 공유하고 있어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;그래서인지 팀원들 모두 업무를 주도적으로 이끌어가는 편이에요.&lt;/strong&gt; 일의 범위를 제한하지 않고 &lt;strong&gt;각자가 해야 할 일을 정하기까지 함께 고민하고, 내가 더 해볼 수 있는 것은 어떤 것인지 먼저 챙겨서 하고 있어요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; 맞아요. 얼마 전 &lt;strong&gt;배민커넥트 앱을 공개했는데 다들 순위가 올라갈 때마다 슬랙 채널에서 이모지 붙이고 기뻐했던 것도 생각나요.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; &lt;strong&gt;그리고 제 의견을 얘기하거나 질문을 할 때 거리낌 없이 얘기할 수 있어요. 막혀있는 부분이 있어서 도움이 필요할 때면 언제든지 달려와주셔서 항상 팀원분들께 감사하게 생각하고 있습니다.&lt;/strong&gt; 신규 입사하시는 분에게도 이런 점은 팀에 적응하는데 큰 도움이 되리라고 생각합니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color:gray; font-size: 140%;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;마무리하며&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;q-우아한형제들의-기획자와-백엔드개발자-직무에-관심을-가지고-계신-분들께-응원의-한-말씀-부탁드립니다&quot;&gt;Q. 우아한형제들의 기획자와 백엔드개발자 직무에 관심을 가지고 계신 분들께 응원의 한 말씀 부탁드립니다.&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color:#073763&quot;&gt;&lt;strong&gt;인태님:&lt;/strong&gt;&lt;/span&gt; 백엔드 개발자 채용에 관심을 가져주셔서 감사합니다. 노력하신 만큼 좋은 성과가 있길 기원하며, &lt;strong&gt;저희 함께 성장하며 재밌게 일할 수 있으면 좋을 것 같습니다. 화이팅!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:#741b47&quot;&gt;&lt;strong&gt;해니님:&lt;/strong&gt;&lt;/span&gt; 우아한형제들의 기획자 채용에 관심을 가져주셔서 감사합니다. &lt;strong&gt;많은 분들이 지원하셔서 저희와 꼭 함께 신나고 재미있게 일했으면 좋겠어요. 빨리 만나요~!&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;color:gray; font-size: 100%; text-align: Center;&quot;&gt;&lt;a href=&quot;https://career.woowahan.com/?keyword=&amp;amp;category=jobGroupCodes%3ABA005002&amp;amp;jobCodes=BA007014,BA007015#recruit-list&quot;&gt;기획직군 모집공고 바로가기&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 07 Jun 2021 15:30:00 +0900</pubDate>
        <link>https://woowabros.github.io/interview/2021/06/07/woowahanpm.html</link>
        <guid isPermaLink="true">https://woowabros.github.io/interview/2021/06/07/woowahanpm.html</guid>
        
        
        <category>interview</category>
        
      </item>
    
      <item>
        <title>우아한형제들 Developer Relations-Updated</title>
        <description>&lt;p&gt;2021년 4월 1일 만우절&lt;br /&gt;
거짓말같이 우아한형제들 조직도에 Developer Relations(DR 파트)가 등장합니다. (두둥!) &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;DR 1호인 제가 입사한지 2년 하고도 3개월, DR 2호가 입사한지 만 1년 그리고 DR 3호의 입사가 한 달 남은 그 시점에서요 :) &lt;br /&gt;
저는 늘 우아한형제들 구성원이었지만 조직도에 내가 속한 조직명이 새롭게 등장한다는 건 또 다른 의미의 소속감을 주었습니다.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;개인의 감회는 잠시 뒤로하고 ㅎㅎ&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;입사 후 Developer Relations 담당자로서 다양한 활동을 알리는 글들을 작성했지만, 이번엔 우아한형제들 Developer Relations에 온전히 초점을 맞춘 글을 작성해 보려고합니다.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;아래 글은 우아한형제들 DR담당자의 온보딩 자료를 기반으로 작성되었습니다.
전문을 공개할 수 없는 부분에 대해서는 일부 생략하였으나 최대한 가감 없이 모든 내용을 그대로 전달드리고자 하였으니 마지막 한 줄까지 많은 관심을 부탁드립니다 :) &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;1우아한형제들-developer-relations-dr파트의-목적&quot;&gt;1.우아한형제들 Developer Relations (DR파트)의 목적&lt;/h2&gt;

&lt;p&gt;우아한형제들 Developer Relations 모든 활동의 목적은 &lt;strong&gt;공통 관심사를 가진 개발자들이 기술 교류 활동을 통해 함께 성장할 수 있도록 격려 및 지원하고 이를 기반으로 우아한형제들 기술 조직의 브랜딩 강화&lt;/strong&gt; 하는 데에 있습니다. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;이러한 목적을 달성하기 위해 우아한형제들 DR담당자들은 각각의 맡은 분야에서 기존의 프로그램 및 이벤트를 발전 및 확대하고 또 새로운 프로그램들을 고민하고 있는데요, 이러한 모든 활동들은 크게 4가지 분야로 나누어지고 또 각 분야는 세분화된 목적성을 갖게 됩니다. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
 &lt;img src=&quot;/img/2021-04-28/DR1.png&quot; style=&quot;width:800px&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;물론 우아한형제들 Developer Relations이 주최하고 있는 하나하나의 활동이 단 하나의 목적만을 가져 모든 활동들이 자로 잰 듯이 4가지 카테고리로 분류되는 것은 아닙니다. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;예를 들어 매달 진행되는 우아한테크세미나의 경우 내/외부 개발자 분들 모두를 대상으로 하는 교육인 만큼 HRD의 목적을 갖도, 또 External Communications의 목적을 갖기도 합니다. 다만, 이러한 1차 분류가 필요한 이유는  우아한테크세미나를 주최하고 운영하는 입장에서 해당 프로그램의 목적이 HRD와 External Communications이라는 이해를 하기 위함이라고 생각해 주시면 됩니다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;2-우아한형제들-dr파트는-어떤-일들을-하고-있나요&quot;&gt;&lt;strong&gt;2. 우아한형제들 DR파트는 어떤 일들을 하고 있나요?&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;앞서 말씀드린 것처럼 4가지 카테고리로 깔끔하게 나눠지진 않겠지만, 이해를 돕기위해 각각의 활동들의 가장 큰 목적을 기준으로 각각의 카테고리안에서 어떤 활동들이 진행되고 있는지 대표 활동들만 선정하여 소개해 드리겠습니다.
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;HR&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;우아한테크캠프 (신입대상) : 매년 여름방학 진행되는  채용 연계형 교육프로그램&lt;/li&gt;
      &lt;li&gt;우아한테크캠프 Pro (재직자 대상) : 4년 이상 경력 개발자(재직자)를 대상으로 진행되는 채용 연계형 교육프로그램&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;HRD&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;우아한테크세미나 : 매달 진행되는 기술세미나.  내/외부 개발자 원하는 누구나 참여 가능하며, 세미나 연사 또한 소속을 제한하지 않고 섭외하고 있습니다.&lt;/li&gt;
      &lt;li&gt;우아한테크러닝 : 연 2회 진행되는 4주-8주 단위의 단기 교육 프로그램. 테크세미나와 마찬가지로 참여와 연사 섭외에 소속을 제한하지 않고있습니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Internal Communications&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;우아한테크토크 : 비정기적으로 진행되는 내부 기술 세미나&lt;/li&gt;
      &lt;li&gt;DR서포터즈 : DR활동을 응원하는 구성원들의 모임&lt;/li&gt;
      &lt;li&gt;우아톤 : 개발 기획 디자인이 함께하는 우아한형제들 내부 해커톤&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;External Communications&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;우아콘 : 매년 1회 진행되는 기술 컨퍼런스&lt;/li&gt;
      &lt;li&gt;외부 행사 후원 : 외부 커뮤니티 및 컨퍼런스에 후원사로 참여&lt;/li&gt;
      &lt;li&gt;기술블로그 &amp;amp; SNS 채널 관리 : 기술조직의 소식을 알리기 위한 컨텐츠 제작 및 홍보&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;3-수많은-이벤트와-프로그램-어떤-사람들을-대상으로-진행되나요&quot;&gt;3. 수많은 이벤트와 프로그램, 어떤 사람들을 대상으로 진행되나요?&lt;/h2&gt;

&lt;p&gt;위에 이벤트 및 프로그램별로 참여 대상자를 간략하게 공유드리긴 하였으나, 큰 의미의 DR 활동이 대상으로 하고 있는 인원은 아래 처럼 구분해 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
 &lt;img src=&quot;/img/2021-04-28/DR2.png&quot; style=&quot;width:800px&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;우아한형제들의 DR 활동이 대상으로 하고 있는 사람들은 사실상 내/외부 개발자 모두라고 할 수 있는데요, DR활동이 대상으로 하고 있는 인원이 달라짐에 따라 활동의 성격과 목적 또한 달라지게 됩니다.&lt;/p&gt;

&lt;p&gt;예를들어 하나의 External Communications 활성화를 위한 이벤트를 기획함에 있어서도 &lt;br /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;우아한형제들 기술조직에 대해 많이 알고 있지 않은 Unknown에 속하는 인원들을 우아한형제들 DR 플랫폼의 Visitor로 전환하기 위한 Attract 활동인지&lt;/li&gt;
  &lt;li&gt;우아한형제들의 기술조직에 대해 관심을 갖고 있는 Contacts로 구분되는 인원을 대상으로 할 때 우아한형제들 입사 지원으로 이끌수 있는 Convert 활동인지&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;에 따라 이벤트의 구성과 측정 가능한 성과가 달라지게 됩니다. &lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;4-dr파트-팀이되어-함께-일하는-방식은&quot;&gt;4. DR파트 팀이되어 함께 일하는 방식은?&lt;/h2&gt;
&lt;p&gt;이런 활동들을 함께 이끌어 나가야 하는 DR 담당자 1,2,3호는 어떻게 함께 일하게 될까요? &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
 &lt;img src=&quot;/img/2021-04-28/DR3.png&quot; style=&quot;width:800px&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;DR 담당자들은 각각의 전문 분야를 기점으로 활동을 기획하고 또 확대해 나갑니다.
해당 전문 분야는 수행하는 활동보다는 대상으로하는 인원에 초점이 맞추어져 있으며 각각 담당하는 분야별 성과 측정 지표를 담당자가 직접 설계합니다.  &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;팀으로 일하는 방식에 대해서는 구상정도의 수준이며 이제 막 하나의 조직으로 함께 일하게 된 담당자들이 함께 더 많은 이야기를 나누고 고민을 공유하여 다듬어나갈 부분이라 이 정도의 소개로 마무리하도록 하겠습니다 :) &lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;DR 업무와 조직에 대한 고민은 2020 1월 DR 2호 입사를 두 달 정도 앞둔 시점에 시작되었습니다.&lt;br /&gt;
오롯이 저의 머릿속에만 있던 파편화된 업무들 각각의 목적, 1년간 자리가 잡힌 각 업무들의 진행 방식 그리고 현재 시점 진행 상황 등등이 제 고민의 시작이었어요.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;처음엔 단순히 새롭게 DR 담당자로 함께 일하게 될 입사자 분께 일종의 “인수인계서”를 작성해보자 라고 시작했던 한 두 장의 끄적거림이 새로운 CTO님의 코멘트와 가이드 그리고 DR 2호와 머리를 맞대고 고민한 시간 덕분에 이렇게 하나의 글로 작성할 분량이 되어 마침내 공유드릴 수 있게 되었습니다. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;지난 2년간 내/외부 다양한 변화에 발맞춰 성장해온 우아한형제들의 Developer Relations,
앞으로의 2년 5년 그리고 10년이 더더욱 기대됩니다 :) &lt;br /&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 28 Apr 2021 13:00:00 +0900</pubDate>
        <link>https://woowabros.github.io/devrel/2021/04/28/devrel-updated.html</link>
        <guid isPermaLink="true">https://woowabros.github.io/devrel/2021/04/28/devrel-updated.html</guid>
        
        
        <category>devrel</category>
        
      </item>
    
      <item>
        <title>[모집] 2021우아한테크캠프 4기</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;우아한개발자가 되고 싶은 이들을 위한 우아한테크캠프 4기를 소개합니다.&lt;br /&gt;
우아한테크캠프는 여름 방학기간을 활용해 진행되는 채용 연계형 교육 프로그램입니다. &lt;br /&gt;
교육은 사회적 상황에 따라 온라인 혹은 온/오프라인 병행 등 안전하고 유연한 교육방식을 준비하고 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;

  &lt;img src=&quot;/img/2021-04-20/poster.jpg&quot; style=&quot;width:800px&quot; /&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;올해-4회차를-맞는-우아한테크캠프는-어떤-특징이-있나&quot;&gt;올해 4회차를 맞는 우아한테크캠프는 어떤 특징이 있나?&lt;/h2&gt;
&lt;p&gt;🏝 &lt;strong&gt;여름방학 8-9주 동안&lt;/strong&gt; &lt;br /&gt;
👩🏽‍💻🧑🏽‍💻 &lt;strong&gt;자기주도형 프로젝트 기반 교육&lt;/strong&gt; &lt;br /&gt;
🤝 &lt;strong&gt;우아한개발자와 함께하는 멘토링 그리고 특강이 팡팡&lt;/strong&gt;&lt;br /&gt;
📍 &lt;strong&gt;채용연계까지&lt;/strong&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;웹프론트엔드-중심으로-백엔드를-함께-배우는-자기-주도형-풀스택-과정&quot;&gt;웹프론트엔드 중심으로 백엔드를 함께 배우는 자기 주도형 풀스택 과정&lt;/h2&gt;
&lt;p&gt;이번 우아한테크캠프는 4기는 웹프론트엔트 중심으로 백엔드를 함께 배우는 자기 주도형 풀스택 과정입니다. 8주 동안 학습 내용을 바탕으로 우아한형제들의 서비스를 커스터마이징한 몇 개의 미니 프로젝트를 수행하며, 실제 서비스를 만들어보는 학습을 통해 하나의 서비스를 이루는 전체 데이터의 흐름과 시스템의 구조를 파악할 수 있는 것을 목표로 진행합니다. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
아래는 참고를 위해 공유드리는 지난 2020 우아한테크캠프에서 실제 수행한 프로젝트 중 하나인 “가계부 모바일웹” 입니다. &lt;br /&gt;
우아한테크캠프에서 진행될 과제 샘플을 미리 보실 수 있습니다. 😉&lt;br /&gt;&lt;br /&gt;
&lt;strong&gt;&lt;a href=&quot;https://bank.woowahan.dev&quot;&gt;가계부 반응형 웹 프로젝트&lt;/a&gt; (3기 장해민, 정진혁 프로젝트)&lt;/strong&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;우아한테크캠프-4기-커리큘럼&quot;&gt;우아한테크캠프 4기 커리큘럼&lt;/h3&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;

  &lt;img src=&quot;/img/2021-04-20/plan.PNG&quot; style=&quot;width:800px&quot; /&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
이번 우아한테크캠프 교육은 1기 우아한테크캠프부터 매년 함께 해주시는 코드스쿼드 윤지수님이 웹프론트엔드를 맡아서 진행해 주실 예정이고, 백엔드는 정호영님이 맡아서 진행하실 예정입니다.
윤지수님의 교육 관련해서는 &lt;a href=&quot;https://codesquad-yoda.medium.com/%EC%9B%B9-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%A4%80%EB%B9%84%ED%95%B4%EC%95%BC-%ED%95%A0%EA%B9%8C-5ac7bb6ff2a9&quot;&gt;웹프론트엔드 개발자, 어떻게 준비해야할까?&lt;/a&gt; 라는 글을 읽어 보시고, 정호영님의 교육 관련해서는 &lt;a href=&quot;https://codesquad-yoda.medium.com/%EC%A7%80%EC%8B%9D%EC%9D%98-%EC%A0%80%EC%A3%BC%EB%A5%BC-%EA%B7%B9%EB%B3%B5%ED%95%98%EA%B8%B0-bb9a697b1bf5&quot;&gt;지식의 저주를 극복하기&lt;/a&gt; 를 읽어 보시길 권해 드립니다.
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;우아한테크캠프는-개발자로서의-성장을-꿈꾸는-여러분을-기다립니다&quot;&gt;우아한테크캠프는 개발자로서의 성장을 꿈꾸는 여러분을 기다립니다.&lt;/h2&gt;
&lt;p&gt;우아한테크캠프는 우아한형제들의 신입개발자 채용 과정이기도 하지만, 개발자가 되고자 하는 분들 누구나 환영하는 참가 자체만으로도 유익한 교육 프로그램, 캠프가 되고자 합니다. &lt;br /&gt;
우아한형제들이라는 회사에서 우아한개발자가 되고자하는 분들을는 포함하여, 개발자로서의 성장을 위해 어떤 것들이 필요하고 어떤 것을 배워야 하는지 궁금하고 경험해보고 싶은 분들을 환영합니다. &lt;br /&gt;
지난 캠프들과 마찬가지로 학력에 대한 제한은 전혀 없습니다. 이미 2-3년의 경력을 가진 분들이 지원하시는 것도 문제가 없습니다. &lt;br /&gt;
프로그래밍에 대한 기본기와 열정만 있다면 누구나 지원 가능하지만, 7/5부터 8/31까지 우아한테크캠프에 풀타임 참여가 가능해야 하고, 2021년 하반기에 취업이 가능한 상태여야 합니다.
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;우아한개발자와-함께하는-우아한테크캠프&quot;&gt;우아한개발자와 함께하는 우아한테크캠프&lt;/h2&gt;
&lt;p&gt;우아한테크캠프 과정에서 우아한형제들에 재직중인 선배 개발자와 함께할 수 있는 여러 기회를 마련할 예정입니다. 우아한개발자 멘토와 함께하는 멘토링을 통해 캠프에 참여하며 겪는 여러 어려움이나 고민을 나눌 것이며, 프로젝트 데모데이에도 우아한개발자를 초대하여 함께 프로젝트를 둘러보며 대화를 나누고 조언을 구할 수도 있습니다. &lt;br /&gt;
또한 신입개발자를 위한 도움되는 내용의 특강과 우아한형제들의 문화를 엿볼 수 있는 특강들을 준비하고 있습니다. &lt;br /&gt;
우아한테크캠프에 대해 더 궁금하신 점은 지난 우아한테크캠프 후기글을 통해 보다 상세히 확인하실 수 있습니다. 😊  &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;2020 우아한테크캠프 운영일기&lt;/strong&gt; &lt;br /&gt;
&lt;a href=&quot;https://woowabros.github.io/devrel/2020/08/14/tecmpcamp_july_1.html&quot;&gt;2020 우아한테크캠프 3기 7월의 일기&lt;/a&gt; &lt;br /&gt;
&lt;a href=&quot;https://woowabros.github.io/devrel/2020/09/08/techcampaugust.html&quot;&gt;2020 우아한테크캠프 3기 8월의 일기&lt;/a&gt; &lt;br /&gt;
&lt;a href=&quot;https://woowabros.github.io/devrel/2020/08/19/techcamp_july_2.html&quot;&gt;우아한테크캠프 인턴들의 7월의 회고&lt;/a&gt; &lt;br /&gt;
&lt;a href=&quot;https://woowabros.github.io/devrel/2020/09/14/techcamp3blog.html&quot;&gt;우아한테크캠프 인턴들의 8월의 마지막 회고&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;우아한테크캠프-faq&quot;&gt;우아한테크캠프 FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Q )&lt;/strong&gt; 코로나19 영향으로 일정이 조정/취소될 수 있나요? &lt;br /&gt;
&lt;strong&gt;A )&lt;/strong&gt;  신입 개발자 양성이라는 목적과 취지에 따라, 계획했던 대로 진행할 예정입니다. 사회적 거리두기 기간이 지속될 경우를 고려하여 모든 가능성을 열어두고 우아한테크캠프의 진행 방식을 구상하고 있습니다. &lt;br /&gt;
캠프 선발과정 및 교육과정은 교육생분들께 가장 안전하고도 효과적인 방식이 될 것이며, 상황에 따라 온/오프라인을 병행 혹은 전체 과정을 온라인으로 진행하는 등 유연한 진행방식을 준비중입니다. &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Q )&lt;/strong&gt; 코딩테스트는 응시 언어는? &lt;br /&gt;
&lt;strong&gt;A )&lt;/strong&gt; 1차 테스트는 알고리즘 및 구조 테스트로 자바스크립트를 이용하여 수행하며, 2차 테스트는 과제 형식으로 자바스크립트 &amp;amp; 타입스크립트 중 선택하여 수행할 수 있습니다. &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Q )&lt;/strong&gt; 우아한테크캠프 운영 시간 및 장소는? &lt;br /&gt;
&lt;strong&gt;A )&lt;/strong&gt; 월요일 1시~6시, 화~금 9시 30분 6시. 우아한테크캠프를 위한 우아한형제들 내 교육장을 마련할 예정이지만, 구체적인 교육방식은 추후 확정해서 상세히 안내드리겠습니다. &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Q )&lt;/strong&gt; 우아한테크캠프 참가자에 지급되는 금액이 있나요? &lt;br /&gt;
&lt;strong&gt;A )&lt;/strong&gt; 월 150만원 활동비를 지급하며, 온라인 진행시 재택근무 지원금 월 10만원을 추가로 지원합니다. &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Q )&lt;/strong&gt; 우아한테크캠프 진행 시 필요한 장비는 지원되나요? &lt;br /&gt;
&lt;strong&gt;A )&lt;/strong&gt; 장비는 회사에서 대여하여 캠프 시작시에 지급합니다. &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Q )&lt;/strong&gt; 우아한테크캠프 참가자에 대한 입사 특전이 있나요? &lt;br /&gt;
&lt;strong&gt;A )&lt;/strong&gt; 우아한테크캠프를 수료한 분들을 대상으로 우아한형제들 신입개발자 채용전형을 진행할 예정이며, 선발 규모는 정해져 있지 않습니다. &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Q )&lt;/strong&gt; 이전 기수의 우아한테크캠프에 탈락했는데 재지원 가능한가요? &lt;br /&gt;
&lt;strong&gt;A )&lt;/strong&gt; 지원요건을 충족하신다면 이전 기수 탈락자도 충분히 지원 가능합니다. &lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;br /&gt;
우아한테크캠프 지원은 &lt;strong&gt;4월 28일 인재영입페이지&lt;/strong&gt;를 통한 서류 접수와 함께 시작됩니다. &lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;지원하러-가기&quot;&gt;&lt;a href=&quot;https://www.woowahan.com/#/recruit/techcamp&quot;&gt;지원하러 가기&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/h3&gt;

&lt;p&gt;기타 문의사항은 &lt;strong&gt;techcamp@woowahan.com&lt;/strong&gt; 으로 주시면 보다 신속하고 상세하게 안내받으실 수 있습니다. &lt;br /&gt;
많은 지원 부탁드립니다.&lt;/p&gt;

</description>
        <pubDate>Tue, 20 Apr 2021 13:00:00 +0900</pubDate>
        <link>https://woowabros.github.io/devrel/2021/04/20/woowa-techcamp_4th.html</link>
        <guid isPermaLink="true">https://woowabros.github.io/devrel/2021/04/20/woowa-techcamp_4th.html</guid>
        
        
        <category>devrel</category>
        
      </item>
    
      <item>
        <title>퇴사 부검</title>
        <description>&lt;p&gt;안녕하세요 (구) &lt;a href=&quot;https://woowahan.oopy.io/60a06399-3f95-4fec-a436-000ad6baff40&quot;&gt;배달의민족 정산시스템팀 개발자&lt;/a&gt;, (현) &lt;a href=&quot;https://www.youtube.com/channel/UCSEOUzkGNCT_29EU_vnBYjg&quot;&gt;유튜브 크리에이터&lt;/a&gt; 이동욱입니다.&lt;/p&gt;

&lt;p&gt;제가 2021년 4월 19일(월) 퇴사를 합니다.&lt;br /&gt;
퇴사에 대한 이야기를 개인적으로 운영하는 유튜브 채널에 부검 발표를 했는데요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/youtube.jpeg&quot; alt=&quot;youtube&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=kE0qicg9Kl0&quot;&gt;배달의민족 개발자 퇴사썰 - 부검 발표 시작합니다.&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;이 영상을 보시고 &lt;strong&gt;기술 블로그에 진심이신 분&lt;/strong&gt;의 연락을 받고, 이렇게 글로 옮기게 되었습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/intro4.png&quot; alt=&quot;intro4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;퇴사 소식을 알리고, 많은 분들이 이제 “남은 팀원들이 얼마나 힘들까” 걱정을 많이 하셨는데요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/intro1.png&quot; alt=&quot;intro1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;하지만,&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/intro2.png&quot; alt=&quot;intro2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/intro3.png&quot; alt=&quot;intro3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://www.lezhin.com/ko/comic/revatoon/163&quot;&gt;레진코믹스 레바툰&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;사실 제가 젤 불쌍하니깐 괜찮습니다.&lt;/p&gt;

&lt;p&gt;이미 유튜브 영상을 보신분들은 재탕이지만, 사알짝 추가된 내용이 있으니 추가된 내용이 무엇인지 확인차 다시 읽어주시면 좋을 것 같습니다.&lt;/p&gt;

&lt;p&gt;물론 영상이 너무 길어서 다 못보신 분들 역시 텍스트로 빠르게 읽어보실겸 봐주시면 좋을것 같습니다 :)&lt;/p&gt;

&lt;h2 id=&quot;0-부검-메일발표블로그&quot;&gt;0. 부검 메일?발표?블로그?&lt;/h2&gt;

&lt;p&gt;넷플릭스의 퇴사 문화로 부검 메일이라는게 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://1boon.kakao.com/ttimes/ttimes_2002250932&quot;&gt;넷플릭스의 퇴사 문화 ‘부검 메일’&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;회사를 떠나는 직원이 퇴사 당일 동료들에게 아래의 내용을 담아 보내는 메일인데요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/netflix.png&quot; alt=&quot;netflix&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 중에서 이 글에서는 아래 4가지에 대해서만 다뤄볼 예정입니다.&lt;/p&gt;

&lt;ol&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;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;배민의 메세지는 누군가 이 글의 댓글로 남겨주시지 않을까요?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;자 그럼 영상 보다 &lt;strong&gt;조금 더 내용이 추가된&lt;/strong&gt; 부검 블로그 시작하겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;1-왜-떠나는지&quot;&gt;1. 왜 떠나는지&lt;/h2&gt;

&lt;p&gt;저는 28살에 처음으로 개발자로 월급을 받기 시작했는데요.&lt;br /&gt;
어느덧 &lt;strong&gt;35살 / 7년&lt;/strong&gt; 경력의 개발자가 되었습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/35.png&quot; alt=&quot;35&quot; /&gt;&lt;/p&gt;

&lt;p&gt;많다면 많고, 적다면 적은 그런 커리어인데요.&lt;br /&gt;
슬슬 &lt;strong&gt;역산&lt;/strong&gt;해서 앞으로 얼마나 내가 왕성하게 활동 할 수 있을지를 고민했습니다.&lt;/p&gt;

&lt;p&gt;운동과 식단 관리를 한다해도 10년? 15년 정도이지 않을까 생각을 하게 되었는데요.&lt;br /&gt;
물론 그 이상의 나이대에도 열심히 활동하시는 선배 개발자분들이 계시기 때문에 저 역시도 잘 관리하면 그 분들처럼 할 수 있지 않을까 예측도 해봤습니다.&lt;/p&gt;

&lt;p&gt;그렇지만 &lt;strong&gt;저는 제가 특별하다고 생각 안해서요&lt;/strong&gt;.&lt;br /&gt;
그 선배님들이 대단하신 분일 수 있기 때문에 보수적으로 생각했을때 지금 처럼 열정적으로 몰입할 수 있는 (체력이 받쳐주는) 시기는 대략 10~15년으로 잡게 되었습니다.&lt;/p&gt;

&lt;p&gt;그렇다면 남은 총알 (창업/이직/직무변경/도전 등등) 은 3발에서 5발정도로 봤는데요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/bullet.png&quot; alt=&quot;bullet&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;적어도 3발&lt;/strong&gt;의 총알이 남아있다면, &lt;strong&gt;1발은 오발&lt;/strong&gt;나도 되지 않을까라고 생각하게 되었습니다.&lt;br /&gt;
그래서 어차피 오발나도 된다면, &lt;strong&gt;쏘고 싶은 과녁에 쏘자&lt;/strong&gt;고 결심합니다.&lt;/p&gt;

&lt;p&gt;요즘 같은 시기에는 저처럼 미드레벨 ~ 시니어레벨의 개발자들은 가만히 있어도 수많은 기회들이 옵니다.&lt;/p&gt;

&lt;p&gt;여기서의 기회란 단순히 링크드인에서 무차별적인 메세지가 아니라, 실제 타 회사의 개발팀장님들이나 그 이상의 직급을 가진분 들과의 접촉 혹은 같이 일했던 지인들의 추천 등 직접적인 기회를 이야기 합니다.&lt;/p&gt;

&lt;p&gt;물론 회사에 남아서 더 활약하고 더 높은 직책으로 가는 것을 노려보는 것도 기회가 될 수도 있습니다.&lt;/p&gt;

&lt;p&gt;이렇게 기회가 많은 상황에서 &lt;strong&gt;커리어의 목표가 없는&lt;/strong&gt; 저는 선택의 기준마저 없다면 제 자리에서 아무것도 못하는 바보가 됩니다.&lt;/p&gt;

&lt;p&gt;그래서 항상 선택의 기준을 가지고 있었는데요.&lt;br /&gt;
그 기준은 &lt;strong&gt;나중에 할 수 있는 이야기가 많은 것을 선택하자&lt;/strong&gt; 입니다.&lt;/p&gt;

&lt;p&gt;저는 나이가 들어가면서, 커리어를 쌓아가면서 계속해서 더 많은 이야기를 쌓고 싶습니다.&lt;br /&gt;
(이건 뭐 뚜렷한 목표라고 하기엔 애매하죠?)&lt;/p&gt;

&lt;p&gt;그래서 이런 간단하지만, 단단한 기준 하나만을 두고 커리어를 계속해서 쌓아왔습니다.&lt;/p&gt;

&lt;p&gt;35살인 지금, 더 많은 이야기를 쌓을 수 있는 선택은 아래 후술할 아주 작은 회사로 이직하는 것 이였습니다.&lt;/p&gt;

&lt;p&gt;그럼 왜 &lt;strong&gt;떠나는게 더 많은 이야기&lt;/strong&gt;가 되는지 설명드리기 위해서 잠깐 과거로 돌아가보겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;우아한형제들-투자-라운드&quot;&gt;우아한형제들 투자 라운드&lt;/h3&gt;

&lt;p&gt;아래는 현 소속사인 우아한형제들의 투자 라운드인데요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/woowa1.png&quot; alt=&quot;woowa1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://thevc.kr/WoowaBrothers&quot;&gt;우아한형제들 투자 라운드 - thevc&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;많은 스타트업들이 부러워할 만큼 매년 좋은 가치의 투자를 이끌어 왔다고 개인적으로 생각합니다.&lt;/p&gt;

&lt;p&gt;여기서 제가 합류한 시기는 &lt;strong&gt;2016년&lt;/strong&gt;입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/woowa2.png&quot; alt=&quot;woowa2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;보시다시피 &lt;strong&gt;시리즈E&lt;/strong&gt; 시점에 합류를 하게 됩니다.&lt;/p&gt;

&lt;p&gt;2016년 배민이라 하면, 사실 &lt;strong&gt;시스템이나 프로세스 등이 굉장히 부족한 시기&lt;/strong&gt;인데요.&lt;br /&gt;
장애대응이나 시스템설계나 시스템 운영부분들이 시리즈E 라고 보기에는 부족한게 많았습니다.&lt;/p&gt;

&lt;p&gt;그럼에도 투자 라운드가 &lt;strong&gt;시리즈 E면 이미 스타트업이라 부르기에는 너무 큰 규모&lt;/strong&gt;입니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;요즘은 시리즈 B,C,D 만 되어도 Exit 하거나 네카라쿠배의 인력들을 흡수하는 경우를 자주 봅니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;이미 기존의 네이버, 카카오, SK플래닛 등의 &lt;strong&gt;대기업 개발자분들의 연봉을 맞춰줄만큼&lt;/strong&gt;의 현금흐름을 갖춘 라운드였기 때문에 저한테 있어서는 &lt;strong&gt;스타트업을 경험했다고 보기는 어려웠습니다&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;제가 진짜 스타트업을 경험해본 이야기를 하려면 &lt;strong&gt;Seed ~ 시리즈D&lt;/strong&gt; 까지의 과정을 경험해봐야만 한다고 생각했습니다.&lt;br /&gt;
그래야 우아한형제들의 경험까지 합쳐서 &lt;strong&gt;스타트업 전체 Cycle을 경험&lt;/strong&gt;해 본 것이기 때문입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/woowa3.png&quot; alt=&quot;woowa3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;아무런 &lt;strong&gt;리스크를 감내하지않고&lt;/strong&gt; 누군가에게 도전이란 단어를 이야기하거나, 나도 도전해봐서 안다 라고 충고하는 것은 기만이라고 생각합니다.&lt;/p&gt;

&lt;p&gt;라떼를 이야기하는 꼰대가 되고싶진 않지만, 그럼에도 &lt;strong&gt;들려줄 이야기가 많은 어른&lt;/strong&gt;이 되고싶기에 저는 좀 더 초기 라운드의 스타트업 경험은 필수라고 계속 생각해왔습니다.&lt;/p&gt;

&lt;p&gt;여기서 주변분들은 아래와 같은 질문을 하시는데요.&lt;/p&gt;

&lt;h3 id=&quot;q-그럼-왜-exit-2019년에-떠나지-않았는지&quot;&gt;Q. 그럼 왜 Exit (2019년)에 떠나지 않았는지?&lt;/h3&gt;

&lt;p&gt;2019년의 정산시스템 상황을 돌이켜보면 다음과 같은 &lt;strong&gt;기술 부채들&lt;/strong&gt;이 남아 있었습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;핀테크 도메인(정산) 으로 인한 망분리 환경&lt;/li&gt;
  &lt;li&gt;IDC 인프라 (DB / 서버를 팀에서 직접 관리)&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&gt;어느 서비스 개발자라 하더라도 개발 하고 싶은 환경은 아니였습니다.&lt;br /&gt;
특히나 &lt;strong&gt;망분리 환경에서 정산 개발을 해보고 싶어요&lt;/strong&gt;라고 지원하는 사람들은 주변에서 1명도 못봤기 때문에 &lt;strong&gt;기술부채와 개발팀 브랜딩&lt;/strong&gt;은 저한테 있어서는 숙제와 같이 남아있었는데요.&lt;/p&gt;

&lt;p&gt;이 상황에서 이직을 한다는 것은 &lt;strong&gt;도망친다는 느낌이 강했습니다&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;“그것 보라고 너도 도망치는거 아니냐고”&lt;br /&gt;
“너도 환경이 싫은데 어디서 약을 파냐고”&lt;br /&gt;
“정산 개발자들은 고인물들만 하는거라고”&lt;/p&gt;

&lt;p&gt;등등의 이야기들을 주변에서 듣는 것도 싫었고, &lt;strong&gt;저 스스로도 그런 생각을 하게 되는건 싫었기 때문&lt;/strong&gt;입니다.&lt;/p&gt;

&lt;p&gt;그래서 그 어느 팀보다 &lt;strong&gt;개발과 일을 하기 좋은 환경을 만들고&lt;/strong&gt; 회사와 팀을 졸업하고 싶었습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/berserk.png&quot; alt=&quot;berserk&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그래서 2020년 동안은 &lt;strong&gt;졸업 조건을 채우는 시간&lt;/strong&gt;이였습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;AWS 클라우드 100% 이전 완료
    &lt;ul&gt;
      &lt;li&gt;펌뱅킹을 통해 &lt;strong&gt;직접 정산&lt;/strong&gt;하는 정산시스템이 100% AWS 클라우드로 인프라 환경이 이전되었습니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;수동 운영 자동화
    &lt;ul&gt;
      &lt;li&gt;100% 다 전환은 못했지만, 많은 부분을 어드민에서 직접 조회/다운로드 하도록 개선&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;모던 프레임워크 전환
    &lt;ul&gt;
      &lt;li&gt;정산시스템은 회사에서 3번째로 PHP에서 Spring + JPA로 전환된 프로젝트이다보니, 이때 &lt;strong&gt;사내 프레임워크&lt;/strong&gt;를 적용했습니다.&lt;/li&gt;
      &lt;li&gt;당시에 &lt;a href=&quot;https://zetawiki.com/wiki/%EA%B0%9C%EB%B0%A5_%EB%A8%B9%EA%B8%B0&quot;&gt;개밥먹기&lt;/a&gt; 해야한다는 판단으로 선택했는데, 어느새 사내에서는 해당 프레임워크를 매니지하지 않고 있어서 신규 입사자가 올 때마다 큰 허들이였습니다.&lt;/li&gt;
      &lt;li&gt;올해 5월이면 이 부분 역시 모던 프레임워크로 전환이 됩니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;쿼리/배치 성능 개선
    &lt;ul&gt;
      &lt;li&gt;쿼리 배치 성능 개선은 이후에 &lt;a href=&quot;https://www.youtube.com/watch?v=zMAX7g6rO_Y&quot;&gt;우아콘&lt;/a&gt;에서 사례를 공유하기도 했습니다&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;개발팀 채용 브랜딩 개선
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://woowahan.oopy.io/60a06399-3f95-4fec-a436-000ad6baff40&quot;&gt;노션&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PWi5_5RG51s&quot;&gt;유튜브-캐치TV&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=V9AGvwPmnZU&quot;&gt;유튜브-EO&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;이 외에도 아래의 활동 등을 진행했습니다.
        &lt;ul&gt;
          &lt;li&gt;팀원 전체에게 1년에 1회 이상 기술블로그 작성 요구&lt;/li&gt;
          &lt;li&gt;우아한테크코스을 위한 팀 홍보용 PPT 준비&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;개인적으로는 99층까지의 던전을 끝까지 클리어 하진 못했지만, &lt;strong&gt;80층까지는 클리어&lt;/strong&gt;했다고 생각해서 이제는 졸업해도 되겠다고 판단하게 되었습니다.&lt;/p&gt;

&lt;h2 id=&quot;2-회사에서-배운-것&quot;&gt;2. 회사에서 배운 것&lt;/h2&gt;

&lt;p&gt;당연한 이야기겠지만, 하루 주문 10만건에서 300만건까지 폭발적으로 성장하는 것을 경험했기 때문에 기술적인 성장을 많이 할 수 있었습니다.&lt;/p&gt;

&lt;p&gt;그리고 그에 맞춰 &lt;a href=&quot;https://jojoldu.github.io/&quot;&gt;제 이력서&lt;/a&gt;에도 쓸 수 있는 것들이 참 많았고요.&lt;/p&gt;

&lt;p&gt;다만 이건 꼭 우아한형제들에서만 배울 수 있는 것은 아니기 때문에 제가 지난 4년의 시간동안 우아한형제들에서 배운 것들을 이야기 하고 싶습니다.&lt;/p&gt;

&lt;p&gt;총 5가지인데요.&lt;/p&gt;

&lt;ol&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;/ol&gt;

&lt;p&gt;이 5가지에 대해서 좀 더 자세히 이야기해보겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;2-1-그-시절엔-그게-맞았다&quot;&gt;2-1. 그 시절엔 그게 맞았다&lt;/h3&gt;

&lt;p&gt;제가 합류한 2016년의 우아한형제들의 시스템 구조는 객관적으로 봐도 &lt;strong&gt;확장 가능한 구조&lt;/strong&gt;로 보기에는 어려웠습니다.&lt;br /&gt;
어찌보면 당연하겠지만, 스타트업의 빠른 속도를 따라가기 위해서는 개발자들은 빠른 출시에만 초점을 맞추기 때문입니다.&lt;br /&gt;
출시를 위해 기술적인 부채들과 확장성 없는 코드들의 개선은 &lt;strong&gt;출시 이후&lt;/strong&gt;로 미루게 되는데요.&lt;br /&gt;
이렇게 한번 미룬 부채들은, &lt;strong&gt;결국은 끝까지 부채로 남아 있었습니다&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;출시하고 나면 부채를 해소할 시간이라는게 스타트업에 있을리가 없겠죠?&lt;/p&gt;

&lt;p&gt;특히 투자를 받기 시작하면, 이제 본인이 원하지 않더라도 &lt;strong&gt;폭발적 성장을 요구 받기 때문에&lt;/strong&gt; 시리즈 A ~ C 사이에는 서비스의 성장에만 초점을 맞추게 됩니다.&lt;/p&gt;

&lt;p&gt;서비스만 성장한 것이지 시스템이 성장하진 못한 상태였기 때문에 제가 합류한 시점에는 이미 엄청나게 기술적 부채가 쌓여 있었고, &lt;strong&gt;도저히 확장이 불가능한 형태의 도메인과 아키텍처로 가득&lt;/strong&gt;한 시기였습니다.&lt;/p&gt;

&lt;p&gt;당시의 저는 이 구조를 보고 불평/불만을 엄청 쏟아냈었는데요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/learn1.png&quot; alt=&quot;learn1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://www.instagram.com/p/CLvTT8eHC0-/&quot;&gt;개발자경수님의 인스타툰&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;막상 제가 정산시스템을 개편하고 3년정도 지나고나니 당시에는 최선이였던 선택들이 이제는 잘못 되었음을 깨닫게 됩니다.&lt;/p&gt;

&lt;p&gt;그리고 그 사이에 &lt;strong&gt;서비스의 정책이 수십번 변하는 것&lt;/strong&gt;을 보면서 어쩔수 없다는 것 역시 알게 됩니다.&lt;/p&gt;

&lt;p&gt;그래서 그 당시의 기술적 부채들 역시도 같은 상황이였지 않을까 수긍할 수 있었습니다.&lt;/p&gt;

&lt;p&gt;그리고 결국은 저를 비롯한 많은 개발자들이 이직해올때 연봉을 맞춰줄 수 있었던 것은 &lt;strong&gt;이 시스템으로 돈을 벌었기 때문&lt;/strong&gt;입니다.&lt;br /&gt;
그래서 지금은 그런 레거시 시스템을 좀 더 애정있게 바라봅니다.&lt;br /&gt;
(물론 가끔은 끓어오르는 화를 삭히기도 합니다.)&lt;/p&gt;

&lt;h3 id=&quot;2-2-회사와-개인의-성장속도는-비례하지-않는다&quot;&gt;2-2. 회사와 개인의 성장속도는 비례하지 않는다&lt;/h3&gt;

&lt;p&gt;이 부분이 우아한형제들에서 가장 크게 배운 점인데요.&lt;/p&gt;

&lt;p&gt;“회사의 성장에 비례하는 건 회사의 가치이지, 개인의 성장은 아니다.”&lt;/p&gt;

&lt;p&gt;보통 많은 스타트업 종사자분들이 회사가 폭발적으로 성장하는 만큼 본인 역시 폭발적으로 성장한다고 &lt;strong&gt;오해&lt;/strong&gt;하시는데요.&lt;/p&gt;

&lt;p&gt;저는 절대로 그렇지 않다는 것을 배웠습니다.&lt;br /&gt;
회사가 10배, 100배 성장했다고 해서 &lt;strong&gt;개인이 같은 시간 동안 그만큼 성장하는 경우는 거의 없었습니다&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/learn2.png&quot; alt=&quot;learn2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://www.youtube.com/watch?v=drBdnrlsq9o&quot;&gt;존잡생각&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;이렇게 폭발적으로 성장하는 스타트업에서는 개인이 깊은 고민을 하기 보다는 &lt;strong&gt;가장 익숙한 방법으로 빠르게 출시&lt;/strong&gt;하는 것이 중요하기 때문입니다.&lt;/p&gt;

&lt;p&gt;가장 익숙한 방법으로 빠른 출시만 몇 년을 하다보면 &lt;strong&gt;규모가 커진 서비스에서의 장애/운영 역량&lt;/strong&gt;은 갖춰지지 않은 경우가 빈번합니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;물론 원래부터 그런 경험과 역량을 갖추고 초기 스타트업에 합류한 경우는 다릅니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;2~3년 전에 했던 방법으로는 더이상 이 규모의 서비스에서는 통하지 않는데, 그것 외에는 해본 경험이 없기 때문에 &lt;strong&gt;이제는 본인의 자리가 없음&lt;/strong&gt;을 느끼게 되는데요.&lt;/p&gt;

&lt;p&gt;사실 이 이야기는 대부분의 초기 스타트업 근무자분들이 경험하는 부분입니다.&lt;/p&gt;

&lt;p&gt;아래는 한동안 SNS에서 크게 공유가 된 글인데요.&lt;br /&gt;
위에서 언급한 문제를 적나라하게 이야기합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://kimchihill.com/2020/03/26/kr-growing-pains-the-law-of-startup-physics-and-psychological-injury/&quot;&gt;스타트업 성장의 법칙과 초기 멤버들의 심리적 부상, 그리고 성장통&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;당신의 야구팀이 하위권을 전전하다, 새로운 구단주를 영입하고, 재무적인 서포트와 함께 선수를 보강하여 플레이오프 진출을 눈앞에 두고 있다고 가정하자.&lt;br /&gt;
이전에 클린업 히터 (4번타자)를 맡던 당신은 애석하게도 부상을 당한 상황이며, &lt;strong&gt;새롭게 보강된 선수로 인해 더 이상 원래의 포지션에서 뛸 수 없는&lt;/strong&gt; 상황이다.&lt;br /&gt;
…
속이 곪는 당신을 뒤로 하고 새롭게 결성된 팀은 빠르게 결속하고 메이저리그 우승이라는 목표를 향해 앞만 보고 전진하는 상황이다.&lt;br /&gt;
당신은 은퇴하거나 다른 팀으로 이적하겠는가?&lt;br /&gt;
혹은 &lt;strong&gt;하위 타선에 서게 되더라도 우승 반지를 이 팀에서&lt;/strong&gt; 기여코 끼고야 말겠는가?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;위 내용보다 좀 더 잔인한 점은 &lt;strong&gt;별도의 부상이 없더라도 역량의 문제로 주전에서 후보로 빠질 수도 있다&lt;/strong&gt;는 것입니다.&lt;/p&gt;

&lt;p&gt;그래서 회사의 성장과 무관하게 &lt;strong&gt;본인 스스로 성장을 챙기지 않으면&lt;/strong&gt; 이후에 본인의 자리는 더이상 없을 수 있다는 점을 알게 됐습니다.&lt;/p&gt;

&lt;p&gt;흔히 스타트업에 합류 하는 것을 &lt;strong&gt;로켓에 올라타는 것&lt;/strong&gt;으로 비유하는데요.&lt;br /&gt;
로켓이 보인다면 &lt;strong&gt;자리가 어디가 됐든 올라타라&lt;/strong&gt;라는 말은 스타트업에서 굉장히 유명한 문구입니다.&lt;br /&gt;
하지만 &lt;strong&gt;회사가 성장하는만큼 본인이 성장하지 못한다면&lt;/strong&gt; 본인이 앉은 자리는 로켓의 연료통일 수도 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/rocket.jpeg&quot; alt=&quot;rocket&quot; /&gt;&lt;/p&gt;

&lt;p&gt;저는 회사가 성장하는 만큼의 속도를 따라잡기 위해 노력하는 것을 좋아하는데요.&lt;br /&gt;
그 부분이 잘맞아서 오랫동안 회사의 일이 즐거울 수 있었지만, 그렇지 않은 분들에게는 작은 스타트업의 합류에 대해서 한번쯤은 고민해볼 필요는 있다고 생각합니다.&lt;/p&gt;

&lt;h3 id=&quot;2-3-근속-연수는-직급을-보장하지-않는다&quot;&gt;2-3. 근속 연수는 직급을 보장하지 않는다&lt;/h3&gt;

&lt;p&gt;수천명이 일하는 조직에서는 개개인의 역량이 크게 드러나지 않지만, 전체 개발자 (인프라/백엔드/프론트/앱/DBA/보안/QA 등)가 100명도 안되는 시점에 합류를 하면 개개인의 실력은 적나라할 정도로 드러나게 됩니다.&lt;/p&gt;

&lt;p&gt;그래서 누가 잘하는 사람인지 아닌지 알게되는데요.&lt;br /&gt;
결론적으로는 &lt;strong&gt;연차, 출신회사는 실력과 크게 상관이 없었습니다&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/learn3.png&quot; alt=&quot;learn3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://comic.naver.com/webtoon/list.nhn?titleId=637931&quot;&gt;전자오락수호대&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;낮은 연차임에도 본인만의 학습 방법을 갖추고 있어 무슨 문제든 해결할 수 있는 믿음을 주는 주니어 분이 있는 반면, 10년전 코드와 방법으로 복붙만 하다가 결국에는 다른 사람이 코드를 다 개선하게 만드는 시니어 분도 있었습니다.&lt;br /&gt;
(물론 연차에 맞게 역량을 발휘하는 분들도 많았습니다.)&lt;/p&gt;

&lt;p&gt;수많은 유형의 개발자들과 TF도 하고, 협업도 하면서 연차와 출신 회사에 대해서는 예전보다는 훨씬 덜 보게 되었습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;물론 그렇다고해서 그간 쌓아오신 커리어를 완전히 무시할수는 없습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;또 한가지 배운게 있다면, 회사의 인재상을 파악하는 방법입니다.&lt;br /&gt;
과거에는 회사의 진급을 공개해주어 모두가 축하하는 문화가 있었는데요.&lt;br /&gt;
이들을 보면 회사가 생각하는 인재상을 볼 수 있었습니다.&lt;br /&gt;
그래서 이들이 잘하는 사람이라는 것을 쉽게 알 수 있어 &lt;strong&gt;같이 일하지 않더라도 이들의 장점을 배울 수 있었습니다&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;“왜 회사에서는 저 분들을 승진시켰을까?”&lt;br /&gt;
“내가 모르는 저 분들의 장점은 무엇일까?”&lt;br /&gt;
“저 분들은 어떻게 일을 하고 학습할까?”&lt;br /&gt;
“내가 저 분들보다 부족한 것은 뭘까?”&lt;/p&gt;

&lt;p&gt;등등을 고민해보는 것이죠.&lt;/p&gt;

&lt;p&gt;어차피 회사에서 일을 하는 시간은 한정되어있기 때문에 &lt;strong&gt;최대한 효율적인 성장&lt;/strong&gt;을 위해서는 사내의 내노라하는 좋은 분들을 타게팅해서 집중적으로 흡수하는게 좋다는 생각이였습니다.&lt;br /&gt;
이렇게 회사에서 밀어주는 분들 역시 연차/나이/출신회사와 크게 상관이 없었습니다.&lt;/p&gt;

&lt;h3 id=&quot;2-4-잘못된-사람을-뽑으면-잘하는-사람들이-퇴사한다&quot;&gt;2-4. 잘못된 사람을 뽑으면 잘하는 사람들이 퇴사한다&lt;/h3&gt;

&lt;p&gt;제가 우아한 형제들에서 배운 것 중 2번째로 중요 포인트입니다.&lt;/p&gt;

&lt;p&gt;개발을 잘하고, 일을 되게 하는 분들에게서는 &lt;strong&gt;참을 수 없는 마지노선&lt;/strong&gt;이라는게 있었는데요.&lt;br /&gt;
이 선을 넘는 분들이 입사하게 되면 여지없이 좋은 분들이 퇴사하였습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/learn4.png&quot; alt=&quot;learn4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그 선을 넘는 행위라는 것들은 대표적으로 다음과 같습니다.&lt;/p&gt;

&lt;ul&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;blockquote&gt;
  &lt;p&gt;아 물론 현재 팀에 이런분들이 계셔서 퇴사하는건 아닙니다.&lt;br /&gt;
서두에서 언급한 것처럼 제 개인의 고민과 기준 때문입니다. :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;물론 여러 테스트와 면접을 통해서 이런 분들이 입사할 확률은 거의 없어졌지만, 행여나 이런 분들이 들어왔을때 팀 전체가 영향을 받기도 했습니다.&lt;/p&gt;

&lt;p&gt;그래서 &lt;strong&gt;애매하면 뽑지말아야하고&lt;/strong&gt;, 확신이 들때만 뽑아야 한다는 것은 제가 면접관으로 활동하는 내내 1순위 기준이 되었습니다.&lt;/p&gt;

&lt;h3 id=&quot;2-5-조직-구조에-따라-역량이-차이날-수도-있다&quot;&gt;2-5. 조직 구조에 따라 역량이 차이날 수도 있다&lt;/h3&gt;

&lt;p&gt;성과라는 것은 개인의 퍼포먼스가 중요합니다.&lt;br /&gt;
다만 그 성과 안에는 오로지 개인의 퍼포먼스만으로 결정되진 않았는데요.&lt;br /&gt;
여러 요소가 있지만, 그 중에서 제가 몰랐던 것은 &lt;strong&gt;조직의 구조&lt;/strong&gt;였습니다.&lt;/p&gt;

&lt;p&gt;어떤 형태의 팀인지, 어떤 형태의 TF 조직인지에 따라서도 &lt;strong&gt;동일한 구성원들인데도 역량의 차이가 발생&lt;/strong&gt;했습니다.&lt;br /&gt;
개발팀/기획팀과 같이 &lt;strong&gt;직군별&lt;/strong&gt;로 팀을 나눌수도 있고, 주문팀/결제팀과 같이 &lt;strong&gt;도메인별&lt;/strong&gt;로 팀을 만들어 여러 직군이 한 팀에 있도록 할 수도 있습니다.&lt;/p&gt;

&lt;p&gt;개개인마다 더 잘 적응하는 구조가 달랐고, &lt;strong&gt;성장하기 좋은 구성도 달랐습니다&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/learn5.png&quot; alt=&quot;learn5&quot; /&gt;&lt;/p&gt;

&lt;p&gt;초기에는 잦은 조직 개편에 대해서 부정적인 생각을 많이 했었는데요.&lt;br /&gt;
그렇게 조직 개편을 할때마다 활동범위나 일의 범위 등이 달라지는걸 경험하면서 &lt;strong&gt;회사에서도 최적의 조직구조를 찾는 중&lt;/strong&gt;이라는 걸 어렴풋이 느낄 수 있었습니다.&lt;br /&gt;
(아닐수도 있습니다. 온전히 저 개인의 생각이라서요.)&lt;/p&gt;

&lt;p&gt;개인의 성과와 성장에 대해서 조직의 형태가 생각보다 큰 영향을 줄 수 있다는 것은 색다른 깨달음이였습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;이 5가지는 제가 어느 회사/어느 규모의 집단을 합류하든 항상 곱씹어볼 최대의 소득이 아닐까 싶습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;3-회사에-아쉬운-점&quot;&gt;3. 회사에 아쉬운 점&lt;/h2&gt;

&lt;p&gt;회사에 아쉬운 점은 많습니다.&lt;br /&gt;
다만, “&lt;strong&gt;그 아쉬운 점을 회사에서 채워주면 퇴사하지 않았을 것이냐&lt;/strong&gt;” 라고 한다면 그건 아닙니다.&lt;/p&gt;

&lt;p&gt;회사에 대한 불만으로 떠나는게 아니라서 회사에서 해줄 수 있는 것은 없습니다.&lt;/p&gt;

&lt;p&gt;저는 개인적으로 생각해도, 주변의 의견을 봐도 회사에서 굉장히 좋은 대우를 받고 있었습니다.&lt;br /&gt;
특히 이직을 준비하면서 제가 받고 있는 대우를 타사와 비교를 하게 되면 더 체감할 수 있었습니다.&lt;br /&gt;
그래서 후련한 마음 보다는 죄송한 마음이 더 큰 것도 사실입니다.&lt;/p&gt;

&lt;p&gt;그래서 “우아한형제들이 이렇게 했으면 떠나지 않았을 것이다” 하는 아쉬운 점은 없습니다.&lt;/p&gt;

&lt;h3 id=&quot;q-지금-기분이-어떠신가요&quot;&gt;Q. 지금 기분이 어떠신가요?&lt;/h3&gt;

&lt;p&gt;누군가는 이제 좋아하는 일을 할 생각에 신나지 않냐고 기대에 찬 질문을 하시기도 했는데요.&lt;/p&gt;

&lt;p&gt;사실 저는 결정을 내렸을때, 마녀사냥의 허지웅님이 언급하신 영화 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%A1%B8%EC%97%85_(1967%EB%85%84_%EC%98%81%ED%99%94)&quot;&gt;졸업&lt;/a&gt;이 떠올랐습니다.&lt;/p&gt;

&lt;p&gt;더스틴 호프먼과 캐서린 로스의 청춘 영화 졸업 엔딩을 보면 &lt;strong&gt;모두가 반대하는 상황속에서&lt;/strong&gt; 주인공 둘은 결혼식에서 도망치고 본인들이 원하는 삶 (여기서는 버스)으로 가는데요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/graduate0.png&quot; alt=&quot;graduate0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이렇게 뛰어가서 탄 &lt;strong&gt;버스안에서의 짧은 시간&lt;/strong&gt;이 이 영화의 실제 엔딩이라는 해석이 저는 참 와닿았습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/graduate1.png&quot; alt=&quot;graduate1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/graduate2.png&quot; alt=&quot;graduate2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/graduate3.png&quot; alt=&quot;graduate3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;퇴사전까지는 기대감을 안고 있겠지만, 막상 현실은 또 어떤 어려움이 있을지 점점 걱정이 되기도 합니다.&lt;/p&gt;

&lt;p&gt;그렇지만 성공하든 실패하든 모든 과정들이 저에게 있어서는 이야기거리라서 손해보진 않을것 같다는 생각을 합니다.&lt;/p&gt;

&lt;p&gt;그래서 4/19일에 퇴사 후, 익일인 4/20일에 바로 새 회사로 출근을 합니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;어서 가서 시스템을 뜯어보고싶네요!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;4-앞으로의-계획&quot;&gt;4. 앞으로의 계획&lt;/h2&gt;

&lt;p&gt;아마 여기까지 보신 분들은 “그래서 어디로 이직해?” 가 궁금하실텐데요.&lt;br /&gt;
이 글은 어디까지나 &lt;strong&gt;우아한형제들의 개발자로서&lt;/strong&gt; 작성하는 글이기 때문에 제 향후 일정은 &lt;strong&gt;새 회사의 개발자로서&lt;/strong&gt; 작성할 예정입니다.&lt;/p&gt;

&lt;p&gt;그래서 이 부분은 &lt;a href=&quot;https://jojoldu.tistory.com/&quot;&gt;개인 블로그&lt;/a&gt;와 &lt;a href=&quot;https://www.youtube.com/channel/UCSEOUzkGNCT_29EU_vnBYjg&quot;&gt;유튜브&lt;/a&gt;를 통해서 언급할 예정입니다.&lt;br /&gt;
(구독과 알림 설정 아시죠?)&lt;/p&gt;

&lt;h2 id=&quot;5-마무리&quot;&gt;5. 마무리&lt;/h2&gt;

&lt;p&gt;시간이 흘러 결국엔 제 도전이 잘 안되서 다시 롤백할 수도 있습니다.&lt;br /&gt;
(물론 회사에 무릎 꿇고 싹싹 빌어야겠죠?)&lt;/p&gt;

&lt;p&gt;롤백을 하면 가장 먼저 쓸 기술 블로그의 짤 역시 벌써 준비해 두었습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/last.png&quot; alt=&quot;last&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://www.slideshare.net/yongho&quot;&gt;하용호님의 Slideshare&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;제가 이런 선택을 했다고 해서, 주변에 이를 종용하진 않습니다.&lt;br /&gt;
그렇지만 (부모님 보시면 혈압으로 쓰러지시겠지만) &lt;strong&gt;효자중에 성공한 사람은 없다&lt;/strong&gt;고 항상 생각합니다.&lt;/p&gt;

&lt;p&gt;올 설 연휴때 이 이야기를 했을때 가족들의 반대가 좀 있었는데요.&lt;br /&gt;
어른들(?)이 반대하는데는 그만큼의 이유가 있겠죠?&lt;br /&gt;
그렇지만 너무 하고 싶을때는 어쩔 수 없는것 같습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://woowabros.github.io/img/2021-04-19/ox.jpg&quot; alt=&quot;ox&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;http://www.yes24.com/Product/Goods/1415779&quot;&gt;소라의 날개&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;지난 4년간 많이 배울 수 있었습니다.&lt;br /&gt;
많은 기회와 권한을 주셔서 정말 감사했습니다.&lt;/p&gt;

&lt;p&gt;아직 배민에는 좋은 개발자분들이 많으신데요.&lt;br /&gt;
그 분들 못지 않게 더 성장하겠습니다.&lt;/p&gt;

</description>
        <pubDate>Sun, 18 Apr 2021 08:30:00 +0900</pubDate>
        <link>https://woowabros.github.io/experience/2021/04/18/autopsy.html</link>
        <guid isPermaLink="true">https://woowabros.github.io/experience/2021/04/18/autopsy.html</guid>
        
        
        <category>experience</category>
        
      </item>
    
      <item>
        <title>제모옥은 젠킨스 조회로직 개선으로 하겠습니다. 근데 이제 비동기를 곁들인</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;제목의 밈은 &lt;a href=&quot;https://www.youtube.com/watch?v=IuBfmQs9wcA#t=65&quot;&gt;조림요정의 휴먼강록체&lt;/a&gt;입니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;평화로운 2020년 9월의 어느 날…&lt;br /&gt;
데일리 미팅을 마치고 일감을 정리하던 저에게 한 가지 요청이 들어왔습니다.&lt;br /&gt;
“우빈님 여기 로직이 오래 걸리면 90초 넘게 걸리고 있는데 한번 개선할 수 있을지 확인 부탁드려요.”&lt;/p&gt;

&lt;p&gt;‘읭 아니 대체 어떤 레거시길래 90초씩이나 걸리는거야’&lt;br /&gt;
라고 생각하며 코드를 열어서 확인했는데요.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/01_its_you.png&quot; style=&quot;width: 500px&quot; /&gt;
  &lt;span style=&quot;display: block; color:#808080; margin-top: 10px;&quot;&gt;너라고..&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;범인은 다섯 달 전의 저였습니다.&lt;br /&gt;
개발자들에게는 흔히 있는 일이라고 하는데… 저만 겪고 있는 건 아니죠?&lt;/p&gt;

&lt;p&gt;오늘 포스팅에서는 위 레거시를 생산하게 된 배경과, 그 해결과정을 정리해서 공유해보려고 합니다.&lt;br /&gt;
크게 어려운 내용은 아니니 해결해가는 과정 자체에 포인트를 두고 가볍게 읽어주시면 감사하겠습니다. 😉&lt;/p&gt;

&lt;h2 id=&quot;5개월-전&quot;&gt;5개월 전…&lt;/h2&gt;

&lt;p&gt;입사 후 &lt;a href=&quot;https://woowabros.github.io/experience/2020/03/02/pilot-project-wbluke.html&quot;&gt;신규입사자 온보딩 과정&lt;/a&gt;을 마무리하고, 팀에서 가장 먼저 받은 첫 번째 과제는 정산시스템 어드민(관리자 페이지)의 최초 진입 화면인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;대시보드&lt;/code&gt;를 만드는 과제였습니다.&lt;br /&gt;
당시 정산 어드민에 로그인한 후 보이는 첫 화면은 좌측 메뉴 바를 제외하고는 특별하게 제공되는 것이 없는 빈 화면이었는데요.&lt;br /&gt;
관리자 페이지를 사용하시는 기획/운영자 분이 수시로 확인하면 좋을 각종 실시간 지표들을 화면에 구축하는 것이 바로 해당 과제의 내용이었습니다.&lt;/p&gt;

&lt;h3 id=&quot;배치-모니터링&quot;&gt;배치 모니터링&lt;/h3&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/02_monitoring_batch.png&quot; style=&quot;width: 500px&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;요구사항에 있는 많은 지표들 중 하나는, 정산시스템의 허리를 담당하고 있는 수십 개의 배치를 개발자가 아닌 운영자 분이 모니터링할 수 있도록 하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;배치 모니터링&lt;/code&gt; 지표였습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;아래에 이어서 나오는 배치 모니터링 분석에 대한 내용은 당시에 &lt;a href=&quot;https://woowabros.github.io/experience/2020/10/08/excel-download.html&quot;&gt;태현님&lt;/a&gt;이 많은 도움을 주셨습니다 🙏&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br /&gt;
배치 모니터링 지표에서는 그날 수행될 예정인 배치가 어떤 것인지 파악할 수 있어야 했고, 해당 배치의 실시간 상태를 확인할 수 있어야 했습니다.&lt;br /&gt;
또한 각 배치의 활성화(on/off) 상태와 더불어 수행 시작/종료 시간도 트래킹할 수 있어야 했습니다.&lt;br /&gt;
즉, 정리하자면 다음과 같은 정보들을 어디선가 얻어오거나 필요에 따라 새롭게 정의해야 했습니다.&lt;/p&gt;

&lt;ul&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;li&gt;운영자가 매일/영업일/매월 1일/수시 등으로 사전에 정의하여 지정&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
저희 팀은 배치 관리 도구로 젠킨스(Jenkins)를 사용하고 있는데요.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/03_jenkins.png&quot; style=&quot;width: 200px&quot; /&gt;
  &lt;span style=&quot;display: block; color:#808080; margin-top: 10px;&quot;&gt;오늘의 주인공 젠킨스 집사님&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;정산시스템에서 이 젠킨스를 통해 관리하고 있는 배치의 형태를 파악해보니 다음과 같이 세 종류로 구분할 수 있었습니다. (이름은 임의로 붙여봤습니다.)&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/04_jenkins_new_items.png&quot; style=&quot;width: 800px&quot; /&gt;
&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Simple Job
    &lt;ul&gt;
      &lt;li&gt;가장 단순한 형태의 배치로, Spring Batch와 Jenkins Job이 1:1인 경우&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Trigger Job
    &lt;ul&gt;
      &lt;li&gt;하나의 주요한 배치 A가 있고, A 배치에게 다양한 파라미터를 제공하며 수행 요청만 하고 자기자신은 종료되는 배치&lt;/li&gt;
      &lt;li&gt;배치 A와 1:N 관계&lt;/li&gt;
      &lt;li&gt;예를 들어, 배치 A에 1번 파라미터를 제공하는 배치, 배치 A에 2번 파라미터를 제공하는 배치 등&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Pipeline Job
    &lt;ul&gt;
      &lt;li&gt;여러 개의 배치 Job을 순차적으로 실행할 수 있는 파이프라인 배치&lt;/li&gt;
      &lt;li&gt;파이프라인 Script로 하위 배치 Job를 단계별로 지정해서 실행&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
이렇게 구해야 하는 배치의 정보와, 현재 배치 시스템의 상황을 파악하고 나니 다음과 같은 고민이 있었습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 수십 개의 배치가 수행된 상태를 실시간으로 조회하기 위해 어떤 방법을 선택해야 하는가?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;크게는 두 가지 방법을 놓고 고민했는데요.&lt;br /&gt;
바로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Spring Batch Metadata Tables&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;젠킨스 API&lt;/code&gt; 였습니다.&lt;/p&gt;

&lt;h3 id=&quot;spring-batch-metadata-tables&quot;&gt;Spring Batch Metadata Tables&lt;/h3&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/05_spring_batch_metadata_tables.png&quot; style=&quot;width: 800px&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.spring.io/spring-batch/docs/current/reference/html/schema-appendix.html&quot;&gt;Spring Batch Metadata Tables(Schema)&lt;/a&gt;는 Spring Batch로 수행된 모든 Job에 대한 정보를 가지고 있는 메타데이터 테이블입니다.&lt;br /&gt;
위 요구사항과 관련한 정보들을 가져오기 위해서는, 그중에서도 BATCH_JOB_INSTANCE 테이블과 BATCH_JOB_EXECUTION 테이블, 그리고 BATCH_JOB_EXECUTION_PARAMS 테이블을 참고해야 할 것으로 보였습니다.&lt;br /&gt;
Spring Batch를 사용하시는 분들은 대부분 아시겠지만, 한번 간단하게 정리해보자면 다음과 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;BATCH_JOB_INSTANCE
    &lt;ul&gt;
      &lt;li&gt;Job Parameter에 따른 배치 수행 정보를 기록&lt;/li&gt;
      &lt;li&gt;동일 파라미터로는 데이터가 발생하지 않음 (배치 수행 불가)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;BATCH_JOB_EXECUTION
    &lt;ul&gt;
      &lt;li&gt;BATCH_JOB_INSTANCE의 자식 테이블로, 모든 성공/실패 내역을 가지고 있음&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;BATCH_JOB_EXECUTION_PARAMS
    &lt;ul&gt;
      &lt;li&gt;실제 수행되었던 배치의 구체적인 모든 파라미터가 기록되는 테이블&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;더 상세한 내용은 &lt;a href=&quot;https://jojoldu.tistory.com/326&quot;&gt;jojoldu님의 블로그&lt;/a&gt;를 참고해보시면 좋습니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
Spring Batch Metadata Tables와 위 요구사항을 매칭해보니, 다음과 같은 문제점들이 보였습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;파이프라인 Job은 메타테이블이 직접적으로 관리하고 있지 않기 때문에 추가 작업이 필요하다.
    &lt;ul&gt;
      &lt;li&gt;파이프라인 하위 배치들의 순서를 알아야 하고, 순서가 달라지면 코드 변경 및 배포가 필요하다.&lt;/li&gt;
      &lt;li&gt;첫 수행 배치 Job과 마지막 수행 배치 Job의 시간을 조회해야 한다.&lt;/li&gt;
      &lt;li&gt;여러 테이블의 조인이 필요하다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Jenkins Job의 활성화 여부는 Jenkins API로만 얻어올 수 있다.
    &lt;ul&gt;
      &lt;li&gt;(아래 캡쳐 참조) 배치 활성화 on/off 는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;빌드 안함&lt;/code&gt; 체크로 관리하고 있다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/06_jenkins_build_false.png&quot; style=&quot;width: 800px&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;jenkins-api&quot;&gt;Jenkins API&lt;/h3&gt;

&lt;p&gt;다음으로는 Jenkins의 API에 대해 고민했는데요.&lt;br /&gt;
&lt;a href=&quot;https://www.jenkins.io/doc/book/using/remote-access-api/&quot;&gt;Jenkins API wiki&lt;/a&gt;가 있긴 하지만, 어떤 API가 있는지 정확하게 정리해주지는 않고 있습니다.&lt;br /&gt;
하지만 우리의 요구사항에 대한 정보를 얻어오기 위해서는 다음 2개의 API면 충분합니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
첫 번째로 Job에 대한 정보를 받아오는 API 입니다.&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${Jenkins_URL}/job/${job_name}/api/json&lt;/code&gt; 으로 요청할 수 있습니다. (Jenkins job 화면에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/json&lt;/code&gt; 을 붙여서 확인해보실 수 있습니다.)&lt;br /&gt;
주요한 필드만 기술해보면 아래와 같습니다. (테스트 환경의 IP 정보는 JENKINS_URL로 표시했습니다.)&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;displayName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test-01&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fullDisplayName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test-01&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fullName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test-01&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test-01&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;buildable&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;builds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hudson.model.FreeStyleBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/3/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hudson.model.FreeStyleBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/2/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hudson.model.FreeStyleBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/1/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;blue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;firstBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hudson.model.FreeStyleBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/1/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;inQueue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;keepDependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lastBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hudson.model.FreeStyleBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/3/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lastCompletedBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hudson.model.FreeStyleBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/3/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lastFailedBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hudson.model.FreeStyleBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/2/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lastStableBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hudson.model.FreeStyleBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/3/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lastSuccessfulBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hudson.model.FreeStyleBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/3/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lastUnstableBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lastUnsuccessfulBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hudson.model.FreeStyleBuild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/2/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;nextBuildNumber&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Job API에서 눈여겨 볼 정보들은 다음과 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;name
    &lt;ul&gt;
      &lt;li&gt;Job 이름&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;buildable
    &lt;ul&gt;
      &lt;li&gt;활성화 여부 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;빌드 안함&lt;/code&gt; 체크 여부)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;lastBuild, lastCompletedBuild, lastFailedBuild
    &lt;ul&gt;
      &lt;li&gt;최신 빌드 URL, 최신 성공 빌드 URL, 최신 실패 빌드 URL&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
두 번째로는 Build에 대한 정보를 받아오는 API 입니다.&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${Jenkins_URL}/job/${job_name}/${build_id}/api/json&lt;/code&gt; 으로 요청할 수 있습니다. (상세 Build 화면에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/json&lt;/code&gt; 을 붙여서 확인해보실 수 있습니다.)&lt;br /&gt;
마찬가지로 주요한 필드만 기술해보면 아래와 같습니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;building&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;displayName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;#3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;duration&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;estimatedDuration&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;116&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fullDisplayName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test-01 #3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;keepLog&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;result&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SUCCESS&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1616924008157&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://JENKINS_URL/job/test-01/3/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Build API에서 눈여겨 볼 정보는 다음과 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;building
    &lt;ul&gt;
      &lt;li&gt;현재 수행중인지 여부&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;duration
    &lt;ul&gt;
      &lt;li&gt;수행된 시간&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;result
    &lt;ul&gt;
      &lt;li&gt;빌드 결과&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;timestamp
    &lt;ul&gt;
      &lt;li&gt;수행 시작 시간&lt;/li&gt;
      &lt;li&gt;timestamp에 duration을 더해서 환산하면 수행 종료 시간이 됩니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(위 2개 API를 제외한 다른 API가 궁금하시면 Jenkins API wrapping 라이브러리인 &lt;a href=&quot;https://github.com/cdancy/jenkins-rest&quot;&gt;Jenkins-rest&lt;/a&gt;를 참고해보셔도 좋습니다!)&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
마찬가지로 Jenkins API와 위 요구사항을 매칭해보니, 다음과 같은 문제점들이 보였습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Trigger Job은 다른 배치를 Trigger만 하고 종료되기 때문에, 정확한 수행시간 등을 모니터링할 수 없다.&lt;/li&gt;
  &lt;li&gt;하나의 배치 당 2번의 API 조회가 필요하다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
Jenkins API를 사용하는 방법에서 가장 큰 문제는, 하나의 API만 가지고는 우리가 필요한 모든 정보를 얻을 수 없다는 것입니다.&lt;br /&gt;
즉, Job API에서는 어디로 가야 Build 정보가 있는지 Build 번호와 URL만 던져줄 뿐이고, 그렇게 찾아간 Build API에서는 반대로 Job에 대한 상세 정보(활성화 여부 등)를 확인할 수 없습니다.&lt;br /&gt;
이렇게 되면 하나의 배치 당 Job API 한번, Build API 한번, 총 2번 API를 찔러야 하고, 결국 모니터링하려는 수십 개의 배치의 2배 만큼 API 호출을 해야하는 상황이었습니다.&lt;br /&gt;
아니 집사님… 친절하게 한번에 다 알려주시면 안됩니까…&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/07_jenkins_cute.png&quot; style=&quot;width: 200px&quot; /&gt;
  &lt;span style=&quot;display: block; color:#808080; margin-top: 10px;&quot;&gt;안알랴줌ㅋ&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Spring Batch Metadata Tables와 Jenkins API 중 고민하다가, 어차피 활성화 여부는 API를 통해 얻어와야 하고, 정보를 조합하기에도 API 쪽이 더 낫다고 생각해 후자를 선택하게 되었습니다.&lt;br /&gt;
장단점에 따라 두 방법을 섞어서 쓰기에는 개발 기간이나 복잡도 측면에서 적합하지 않다고 판단하였습니다.&lt;/p&gt;

&lt;p&gt;집사가 일을 대충하면 목마른 주인이 우물을 파야죠. 연장 가져오겠습니다. ⛏&lt;/p&gt;

&lt;h3 id=&quot;해보자-조회&quot;&gt;해보자, 조회!&lt;/h3&gt;

&lt;p&gt;전체적인 배치 모니터링플로우는 다음과 같습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;운영자가 모니터링하고 싶은 배치를 어드민에 Job 이름/관리용 이름/작업주기/조회유무 정보와 함께 등록한다.&lt;/li&gt;
  &lt;li&gt;등록할 때 Job 이름(batchId)을 기준으로 Jenkins API를 찔러서, 실제 운영되고 있는 배치인지 확인한다.&lt;/li&gt;
  &lt;li&gt;배치가 존재한다면, monitoring_batch라는 별도의 모니터링용 배치 관리 테이블에 저장한다.&lt;/li&gt;
  &lt;li&gt;조회 시에는 등록한 batchId와 작업주기를 기준으로 당일 조회 대상인 배치 리스트를 가져와 일괄 조회한다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;먼저, 필요한 API 정보에 맞게 JobInfo와 BuildInfo를 정의했습니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@ToString&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Getter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastCompletedBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastFailedBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastStableBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastSuccessfulBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastUnstableBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastUnsuccessfulBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isLastBuildEmpty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuild&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getLastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isLastBuildEmpty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@ToString&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Getter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
Build 조회 API URL에 Job 이름이 포함되어 있기 때문에 너무 당연해서 그런지 API에서 Job의 이름을 제공하고 있지 않아서, BuildInfo에서는 추후 활용도를 높이기 위해 조회 후 이미 가지고 있는 Job 이름 정보를 업데이트하기로 했습니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@ToString&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Getter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 해당 빌드의 Job Name. API에서 제공하고 있지 않아 수동으로 update 한다.&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;building&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;updateBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;batchId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocalDateTime&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBuildStartTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Timestamp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toLocalDateTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocalDateTime&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBuildEndTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Timestamp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toLocalDateTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
정산시스템에서는 이미 Jenkins API를 통해 특정 배치를 단건 실행하는 JenkinsConnector라는 모듈이 있었기 때문에, 해당 모듈에 조회 로직을 추가하기로 했습니다.&lt;br /&gt;
RestTemplate을 사용해서 Job의 존재 유무를 확인하는 메서드와 JobInfo, BuildInfo를 조회하는 메서드를 각각 작성했습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;젠킨스 API를 사용하기 위해서는 젠킨스 환경설정에서 사용자별 토큰을 발급하고, Request에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;사용자ID:토큰&lt;/code&gt; 의 형태로 인증 헤더를 보내면 됩니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// JenkinsConnector.java&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;existsJob&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createJobUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Job 조회 API URL&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;ResponseEntity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;responseEntity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;restTemplate&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exchange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requestUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpEntity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createAuthHeaders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;HttpStatus&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statusCode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;responseEntity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getStatusCode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;is2xxSuccessful&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getJobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;address: {}, batchId: {}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createJobUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Job 조회 API URL&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;restTemplate&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exchange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requestUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpEntity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createAuthHeaders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBody&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;JenkinsExecuteException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Job Info Fetching Exception! &quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildInfo&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;address: {}, batchId: {}, buildNumber: {}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createBuildUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Build 조회 API URL&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;BuildInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;restTemplate&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exchange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requestUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpEntity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createAuthHeaders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBody&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;updateBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;JenkinsExecuteException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Build Info Fetching Exception! &quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpHeaders&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createAuthHeaders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;:&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base64Credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Base64&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getEncoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;encodeToString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;

    &lt;span class=&quot;nc&quot;&gt;HttpHeaders&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpHeaders&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpHeaders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;httpHeaders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Authorization&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Basic &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base64Credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpHeaders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
그리고 서비스 로직에서 이 JenkinsConnector를 사용하여 배치 하나 당 Job 조회, Build 조회를 순차적으로 진행하도록 했습니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// MonitoringBatchService.java&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MonitoringBatchResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MonitoringBatchSearchRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;LocalDate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;workingDate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getWorkingDate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MonitoringBatchResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;monitoringBatchResponses&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;monitoringBatchServerRepository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;searchByCondition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
 
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MonitoringBatchResponse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;monitoringBatchResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;monitoringBatchResponses&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;updateBuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;monitoringBatchResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;workingDate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// DB에서 조회한 배치 리스트를 반복문을 돌면서 하나씩 Job, Build 조회&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;updateBuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MonitoringBatchResponse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;monitoringBatchResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocalDate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;workingDate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;monitoringBatchResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
 
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jenkinsConnector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getJobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Job 조회&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
 
        &lt;span class=&quot;nc&quot;&gt;BuildUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuild&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getLastBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 최신 Build 번호 확인&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lastBuild&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;BuildInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jenkinsConnector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuild&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Build 조회&lt;/span&gt;
             
            &lt;span class=&quot;c1&quot;&gt;// ... 상태 업데이트&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JenkinsExecuteException&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Jenkins 에서 조회할 수 없는 배치 Job 입니다. batchId={}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
음, 아주 조회가 잘 되는 것을 확인했습니다. 배포! 👏&lt;/p&gt;

&lt;h2 id=&quot;비동기로-로직-개선&quot;&gt;비동기로 로직 개선&lt;/h2&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/08_completable_fetch.png&quot; style=&quot;width: 700px&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;네, 지금까지 과거 회상 씬이었고요.&lt;br /&gt;
이제 서문에서의 상황으로 돌아가서 이 무지막지한 API 호출을 손볼 차례입니다.&lt;/p&gt;

&lt;p&gt;사실 배치 모니터링은 대시보드의 여러가지 지표 중 지분이 작고 활용도가 적은 부분이라 뒤늦게 인지한 측면도 있었고, 개선 우선순위가 낮기도 했었습니다. &lt;del&gt;핑계&lt;/del&gt;&lt;br /&gt;
확인한 당시에는 등록한 배치 수도 50여 개 가까이 되면서 1회 진입 시 호출하는 API 횟수가 100회에 가까웠습니다.&lt;br /&gt;
API 호출 100회를 동기식으로 조회하니 속도가 안나오는건 당연할수밖에요.&lt;/p&gt;

&lt;p&gt;그래서 비동기 방식으로 슥삭 개선해보기로 했습니다.&lt;br /&gt;
비동기 요청을 처리하기 위해 Java8에 등장한 CompletableFuture를 사용하기로 했고, 그전까지 CompletableFuture를 제대로 써본 적이 없었기에 진행에 앞서 &lt;a href=&quot;https://wbluke.tistory.com/50&quot;&gt;개인 블로그&lt;/a&gt;에 정리도 해보았는데요.&lt;br /&gt;
아래 나올 CompletableFuture의 API를 몇 개만 간단히 정리해보면 다음과 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;supplyAsync
    &lt;ul&gt;
      &lt;li&gt;Supplier 타입을 파라미터 콜백으로 받아서 비동기 요청을 수행하고 반환값을 리턴하는 메서드입니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;join
    &lt;ul&gt;
      &lt;li&gt;위 supplyAsync는 콜백의 반환값을 CompletableFuture가 감싼 형태로 리턴을 하는데요. 받은 CompletableFuture가 끝나기를 기다리고 싶다면 join()으로 Blocking을 걸어서 비동기 작업이 끝나기를 기다릴 수 있습니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;handleAsync
    &lt;ul&gt;
      &lt;li&gt;비동기 작업이 끝난 이후, 해당 결과물과 (혹시나 실패했다면) 예외를 파라미터로 받아 종합적으로 후속 작업을 지정할 수 있는 메서드입니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;allOf
    &lt;ul&gt;
      &lt;li&gt;여러 CompletableFuture를 한번에 Blocking 할 때 사용하는 메서드입니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CompletableFuture까지 훑어봤으니, 이제 동기 로직을 비동기 로직으로 전환해보도록 하겠습니다!&lt;br /&gt;
먼저 기존 어드민 시스템에서 비동기 작업을 담당하고 있던 스레드 풀(Executor)의 설정을 변경했습니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// AsyncConfig.java&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ADMIN_DEFAULT_EXECUTOR_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;threadPoolTaskExecutor&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;POOL_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
 
&lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ADMIN_DEFAULT_EXECUTOR_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Executor&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;ThreadPoolTaskExecutor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ThreadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setCorePoolSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;POOL_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setMaxPoolSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;POOL_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setThreadNamePrefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;admin-default-async-&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
     
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
다들 아시겠지만 위에 나온 threadPoolTaskExecutor의 속성들을 간단하게 정리해보자면 다음과 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;corePoolSize
    &lt;ul&gt;
      &lt;li&gt;스레드의 최소 유지 개수&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;maxPoolSize
    &lt;ul&gt;
      &lt;li&gt;스레드가 최대로 만들어질 수 있는 개수&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;threadNamePrefix
    &lt;ul&gt;
      &lt;li&gt;해당 스레드 풀 내의 스레드 이름 prefix&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;원래 어드민에서 사용하던 비동기 작업은 단건 메일 전송, 위의 JenkinsConnector를 이용한 단건 배치 수행 등의 단순 작업만 존재했기에 스레드 풀 설정이 default 값으로 되어 있었습니다.&lt;br /&gt;
즉, executor의 corePoolSize는 1, maxPoolSize는 Integer.MAX_VALUE 였습니다.&lt;br /&gt;
이를 배치 조회를 위한 다수의 API 호출을 위해 corePoolSize, maxPoolSize를 30개로 상향 조정하였습니다.&lt;/p&gt;

&lt;p&gt;다음으로는 젠킨스의 조회를 담당하는 객체를 두고, CompletableFuture를 사용하여 비동기 조회 방식으로 로직을 구성하였습니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// BatchJobInfoFetcher.java&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Executor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchJobItemFutures&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fetchBatchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Collectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
 
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchJobItemFutures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (1) 전체 Blocking&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;thenApply&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchJobItemFutures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;CompletableFuture:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;Objects:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nonNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Collectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()))&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;c1&quot;&gt;// 하나의 스레드에서 JobInfo 조회가 끝나면, 다른 스레드가 BuildInfo 조회 작업을 진행할 수 있도록 handleAsync()를 사용&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetchBatchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getJobInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (2) 비동기로 Job 조회&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handleAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfoException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (3) Job 조회 후 Build 조회&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getLastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// ... 검증&lt;/span&gt;
 
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetchBatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getJobInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;supplyAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jenkinsConnector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getJobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exceptionally&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;logErrorWithBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetchBatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchJobItemFuture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getBuildInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (4) 비동기로 Build 조회&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handleAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildInfoException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (5) Build 조회 후 가공&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// ... 검증&lt;/span&gt;
 
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
 
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Blocking&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;thenApply&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBuildInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;supplyAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jenkinsConnector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exceptionally&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;logErrorWithBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;logErrorWithBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (6)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Jenkins에서 조회할 수 없는 배치 Job입니다. batchId={}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// log.error로 슬랙 알람 발송&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
코드가 조금 복잡할 수는 있는데요, 크게는 다음과 같은 흐름입니다. (주석 번호 참조)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;(1) 모든 비동기 요청은 결국 각 요청의 결과값이 모두 다 도착해야 화면 응답을 내려줄 수 있기 때문에, 조회가 끝나고 최종적으로는 CompletableFuture.allOf()로 Blocking을 걸어서 모든 응답이 끝났음을 보장해 줬습니다.&lt;/li&gt;
  &lt;li&gt;(2) 먼저 조회해야 하는 batchId 리스트를 보고 순차적으로 Job을 조회하는 비동기 요청을 보냅니다.
    &lt;ul&gt;
      &lt;li&gt;Supplier 타입을 파라미터로 받는 CompletableFuture.supplyAsync()를 사용했습니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;(3) Job을 비동기로 조회한 뒤 Build를 조회하는 후속작업을 지정합니다.&lt;/li&gt;
  &lt;li&gt;(4) Job 조회에서 얻은 최신 buildId를 사용해 Build를 조회합니다.&lt;/li&gt;
  &lt;li&gt;(5) (3)에서와 동일하게 Build를 비동기로 조회한 뒤 Job과 Build를 가공하는 후속작업을 지정합니다.&lt;/li&gt;
  &lt;li&gt;(6) 만약 Job이나 Build 조회 시 예외가 발생하면, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;log.error&lt;/code&gt; (Slf4j)를 남기고 null을 반환하도록 했습니다.
    &lt;ul&gt;
      &lt;li&gt;정산시스템은 log.error가 발생하면 ELK에서 감지 후 슬랙에 에러 알람을 보내도록 되어있습니다.&lt;/li&gt;
      &lt;li&gt;null 반환은 기본적으로 안티 패턴이지만, private 메서드로 내부에서만 사용하기 때문에 에러 시 null을 반환하도록 하고, public 메서드에서 필터링하는 용도로 사용했습니다. 한 건의 조회를 실패하더라도 나머지 정상적인 조회 결과는 보여줘야 하기 때문입니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 로직에서 눈여겨봐야 하는 부분은, &lt;strong&gt;(2) ~ (5)의 과정에서 모두 같은 스레드 풀(threadPoolTaskExecutor)을 사용하도록 했다&lt;/strong&gt;는 점입니다.&lt;br /&gt;
이렇게 개선을 마치고, 베타 서버에서 조회 속도의 드라마틱한 향상을 체감한 뒤 운영 배포를 진행했습니다! 👏&lt;/p&gt;

&lt;h2 id=&quot;1차-배포-후&quot;&gt;1차 배포 후&lt;/h2&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/09_monitoring_batch_failed.png&quot; style=&quot;width: 500px&quot; /&gt;
&lt;/div&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/10_noooooo.png&quot; style=&quot;width: 500px&quot; /&gt;
  &lt;span style=&quot;display: block; color:#808080; margin-top: 10px;&quot;&gt;아..안돼!&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;장애가 났습니다.&lt;br /&gt;
배포 직후에는 화면에 반응이 없길래 ‘왜 속도가 안나오지?’ 했는데, 알고보니 아예 동작을 하지 않았던 것이었습니다.&lt;br /&gt;
더 큰 문제는, 단순히 배치 모니터링 지표만 안나오면 그나마 괜찮은데 &lt;strong&gt;어드민의 다른 기능까지 같이 동작하지 않는&lt;/strong&gt; 이슈가 발생하기 시작했습니다.&lt;/p&gt;

&lt;p&gt;이유인즉슨, 스레드 풀에서 데드락이 발생했고, 같은 스레드 풀을 사용하고 있던 몇 없는 비동기 로직(위에서 언급한 메일 전송, 단건 배치 실행 등)까지도 같이 동작하지 않았던 것이었습니다.&lt;br /&gt;
위 로직대로라면, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;조회 배치 수 &amp;gt;= 스레드 수&lt;/code&gt; 의 조건에서는 데드락 현상이 발생합니다.&lt;br /&gt;
구체적인 설명을 위해 &lt;del&gt;중복이지만 여러분의 스크롤은 소중하기 때문에&lt;/del&gt; 위의 코드를 다시 가져와 보겠습니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// BatchJobInfoFetcher.java&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Executor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchJobItemFutures&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchIds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fetchBatchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Collectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
 
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchJobItemFutures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (1) 전체 Blocking&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;thenApply&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchJobItemFutures&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;CompletableFuture:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;Objects:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nonNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Collectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;c1&quot;&gt;// 하나의 스레드에서 JobInfo 조회가 끝나면, 다른 스레드가 BuildInfo 조회 작업을 진행할 수 있도록 handleAsync()를 사용&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetchBatchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getJobInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (2) 비동기로 Job 조회&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handleAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfoException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (3) Job 조회 후 Build 조회&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getLastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// ... 검증&lt;/span&gt;
 
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetchBatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getJobInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;supplyAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jenkinsConnector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getJobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exceptionally&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;logErrorWithBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetchBatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchJobItemFuture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getBuildInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (4) 비동기로 Build 조회&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handleAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildInfoException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (5) Build 조회 후 가공&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// ... 검증&lt;/span&gt;
 
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
 
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Blocking&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;thenApply&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBuildInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;supplyAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jenkinsConnector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exceptionally&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;logErrorWithBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;logErrorWithBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (6)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Jenkins에서 조회할 수 없는 배치 Job입니다. batchId={}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// log.error로 슬랙 알람 발송&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
예를 들어 조회할 배치 2개, 스레드 풀의 스레드 수를 2개라고 가정해 보겠습니다.&lt;br /&gt;
2개의 스레드가 2개의 배치를 조회 및 가공하는 (2) ~ (3) 번 과정을 수행합니다.
문제는 fetchBatchJobItem() 이라는 (4) ~ (5)의 과정이 (3)의 과정에 포함되는 작업이기 때문에, (2)번 과정에 모든 스레드가 물려있는 상황에서 새로운 (4) ~ (5)번 작업을 위한 스레드를 요청하게 되고, 이는 곧 각자의 스레드가 서로가 끝나기만을 기다리는 데드락 현상으로 이어집니다.&lt;/p&gt;

&lt;p&gt;당시 운영에서 등록해 조회하고 있던 배치는 47개 정도여서, 해당 이슈는 &lt;strong&gt;핫픽스 배포로 스레드 풀의 개수를 초기 설정 30개에서 50개로 상향 조정하여 임시 조치&lt;/strong&gt;하는 방식으로 해소하였습니다.&lt;/p&gt;

&lt;p&gt;이후 정확한 원인 파악을 진행하고, 두 가지 후속조치를 진행하였는데요.&lt;br /&gt;
첫 번째는 &lt;strong&gt;어드민의 기존 기능들이 사용하는 스레드 풀과 대시보드 전용 스레드 풀을 분리&lt;/strong&gt;하였습니다.&lt;br /&gt;
후에 대시보드에서 또 다른 스레드 이슈가 발생하더라도 다른 기능들은 영향을 받지 않게끔 하기 위해서입니다.&lt;/p&gt;

&lt;p&gt;두 번째는 &lt;strong&gt;(2), (4)번 과정의 네트워크 조회 로직만 대시보드 전용 스레드 풀을 사용&lt;/strong&gt;하게 하고, (3), (5)번 과정의 애플리케이션 단에서의 단순 가공 로직은 기본 제공되는 Tomcat의 NIO 스레드 풀을 자연스럽게 이용할 수 있도록 &lt;strong&gt;특별한 스레드 풀 지정을 하지 않았습니다.&lt;/strong&gt;&lt;br /&gt;
(지금 생각해보면 스레드 풀 지정을 하지 않는 것보다, 또 다른 스레드 풀을 두고 별도로 지정하는 것이 더 좋았을 것 같습니다. 톰캣의 스레드 풀은 스레드 생성 제한이 없어서 자칫하면 위험할 수 있기 때문입니다.)&lt;br /&gt;
이렇게 하면 대시보드 스레드 풀의 스레드들이 정확히 네트워크 리소스에만 투입되고, 서로의 작업 간에 pending 되는 일이 없게 됩니다.&lt;br /&gt;
위 후속 조치에 따라 2차 개선한 코드는 다음과 같습니다.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// AsyncConfig.java&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ADMIN_DEFAULT_EXECUTOR_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;adminExecutor&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MONITORING_BATCH_EXECUTOR_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;monitoringBatchExecutor&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MONITORING_BATCH_THREAD_POOL_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
 
&lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Qualifier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ADMIN_DEFAULT_EXECUTOR_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Executor&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;adminExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;ThreadPoolTaskExecutor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ThreadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setThreadNamePrefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;admin-async-&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
 
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Qualifier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MONITORING_BATCH_EXECUTOR_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Executor&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;monitoringBatchExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;ThreadPoolTaskExecutor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ThreadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setCorePoolSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MONITORING_BATCH_THREAD_POOL_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setMaxPoolSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MONITORING_BATCH_THREAD_POOL_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setThreadNamePrefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;monitoring-async-&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
 
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
AsyncConfig.java에서는 스레드 풀을 2개로 분리하고, 대시보드 스레드 풀의 크기를 10개로 조정하였습니다. (필요 이상으로 스레드가 많을 필요도 없기 때문에 운영 상황을 보면서 조절하는 것이 좋습니다.)&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// BatchJobInfoFetcher.java&lt;/span&gt;
 
&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetchBatchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getJobInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handleAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfoException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (3) Job 조회 후 Build 조회&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getLastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// ... 검증&lt;/span&gt;
 
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetchBatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 별도의 스레드 풀 지정하지 않음&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getJobInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;supplyAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jenkinsConnector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getJobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 기존처럼 스레드 풀 지정&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exceptionally&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;logErrorWithBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetchBatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JobInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchJobItemFuture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getBuildInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastBuildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handleAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildInfoException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (5) Build 조회 후 가공&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// ... 검증&lt;/span&gt;
 
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BatchJobItem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 별도의 스레드 풀 지정하지 않음&lt;/span&gt;
 
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Blocking&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;thenApply&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchJobItemFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBuildInfoAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;supplyAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jenkinsConnector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBuildInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threadPoolTaskExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 기존처럼 스레드 풀 지정&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exceptionally&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;logErrorWithBatchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
젠킨스 로직에서는 (3), (5)번 과정에서 대시보드 스레드 풀을 지정하던 부분을 제거하였습니다.&lt;br /&gt;
다음 로그를 보시면, 빨간색 박스의 비동기 로직을 요청하는 메인 스레드는 톰캣의 스레드 풀(NIO)을 사용하고 있는 것을 볼 수 있고, 파란색 박스의 실제 Jenkins API 요청은 직접 지정한 스레드 풀(monitoring-async)을 사용하는 것을 확인할 수 있습니다.&lt;br /&gt;
메인 스트림 스레드와 API 요청 스레드가 분리되었기 때문에 데드락이 걸리지 않게 된 것이죠.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/11_log_batch_job_info_fetcher.png&quot; style=&quot;width: 900px&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;여러 케이스를 테스트하면서 안전성을 두번 세번 확인 후, 다시 2차 배포를 진행했습니다! 👏&lt;/p&gt;

&lt;h2 id=&quot;2차-배포-후&quot;&gt;2차 배포 후&lt;/h2&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-04-06/12_async_is_comfortable.png&quot; style=&quot;width: 500px&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;추가 배포 후 다행히 10개의 스레드로도 기능은 잘 동작했고, 조회 속도도 기대한만큼 나와주었습니다.&lt;br /&gt;
기존 &lt;strong&gt;90초 걸리던 로직이 2초 이내로 개선&lt;/strong&gt;이 되어 무려 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;44배&lt;/code&gt;의 성능 개선율을 보여주었습니다.&lt;/p&gt;

&lt;h2 id=&quot;추가-개선-예정--outro&quot;&gt;추가 개선 예정 + Outro&lt;/h2&gt;

&lt;p&gt;개발 당시에는 비동기 호출 구조에만 정신이 팔려서 인지하지 못하고 있었는데, 이번에 글을 다시 작성하면서 정리하다보니 위 내용은 다음과 같이 개선 가능하다는 사실을 깨달았습니다.&lt;/p&gt;

&lt;p&gt;현재는 하나의 배치를 기준으로 보면 Job 조회 → 최신 Build Id 얻음 → Build 조회 로 &lt;strong&gt;항상 Job을 조회한 후 Build를 조회하도록&lt;/strong&gt; 순차적으로 진행하고 있는데요.&lt;br /&gt;
꼭 Job 정보를 찔러서 최신 Build Id를 알아낸 뒤에 해당 Id 값을 사용해 조회하지 않아도, Jenkins API URL에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lastBuild&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lastCompletedBuild&lt;/code&gt; 등과 같이 고정된 문자열을 사용해서 최신 Build에 대한 조회가 가능하다고 합니다. &lt;del&gt;이럴수가?&lt;/del&gt;&lt;br /&gt;
이렇게 되면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${Jenkins_URL}/job/${job_name}/lastBuild/api/json&lt;/code&gt; 로 특정 Job에 대한 최신 Build 조회가 가능하니, 굳이 Build를 조회하기 전에 Job을 조회하지 않아도 되고, 같은 레벨에서 Job과 Build를 동시에 조회하고 조합하는 구조로 개선할 수 있겠다는 생각이 들었습니다.&lt;br /&gt;
즉, 지금은 Job 50개를 먼저 다 조회한 후, Blocking을 걸어 작업 완료가 보장되면 그 다음 순서로 Build 50개를 조회하는데, 위 구조대로라면 총 100개의 요청을 &lt;strong&gt;순서 상관없이 동시 요청&lt;/strong&gt;하고, 조회 완료 후에는 Map 등으로 가공 로직을 거쳐 원하는 형태의 Job + Build 응답값을 구성할 수 있겠다고 판단을 했습니다.&lt;br /&gt;
요 3차 개선 구조는 조만간 시간이 나면 바로 개선을 진행해볼 예정입니다. 조회 시간도 기대만큼 1초 대로 좀 더 단축이 되면 좋겠네요.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
만들고 개선하고 장애내고 다시 개선하는 일련의 과정을 거치면서, 비교적 친숙하지 않았던 비동기 로직의 맛을 슬쩍 볼 수 있어서 &lt;del&gt;다 끝나고 나서는&lt;/del&gt; 즐거웠습니다.&lt;br /&gt;
무엇보다 미리 데드락 상황을 로컬에서 충분히 재현하고 예측할 수 있었는데 그러지 못한 점이 가장 아쉬웠고요.&lt;br /&gt;
이런 경험을 통해, 또 몇 달 시간이 지났지만 글로 한번 더 정리하면서, 조금 더 &lt;a href=&quot;https://woowabros.github.io/experience/2020/03/02/pilot-project-wbluke.html&quot;&gt;Real-정산지기&lt;/a&gt;를 향해 한걸음 더 나아갔다고 되돌아볼 수 있는 소중한 경험이었습니다.&lt;br /&gt;
긴 글 읽어주셔서 감사합니다-! 😉&lt;/p&gt;
</description>
        <pubDate>Tue, 06 Apr 2021 13:00:00 +0900</pubDate>
        <link>https://woowabros.github.io/experience/2021/04/06/fetch-jenkins-api-async.html</link>
        <guid isPermaLink="true">https://woowabros.github.io/experience/2021/04/06/fetch-jenkins-api-async.html</guid>
        
        
        <category>experience</category>
        
      </item>
    
      <item>
        <title>우아한테크코스 한 달 생활기</title>
        <description>&lt;p&gt;안녕하세요. 테크코스교육개발팀 이원미입니다.&lt;/p&gt;

&lt;p&gt;우아한테크코스(이하, 우테코)도 어느덧 3년 차에 접어들었습니다 : ) 새로운 기수를 맞이할 때면 언제나 설레는 것 같아요.&lt;/p&gt;

&lt;p&gt;아참, 3기에는 커다란 변화가 생겼는데요! &lt;del&gt;(언제나 변화가 일상인 우테코지만..)&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;지난 기수는 웹 백엔드 과정만을 운영했다면, 이번 3기에는 웹 프론트엔드 과정이 신설되어 우테코에 새로운 활력을 불어넣어 주고 있답니다. (New 바람 ~)&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-04-02/wooteco-front.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;그리고 프론트엔드 크루들과 더불어 새로운 프론트엔드 캡틴과 코치들도 합류했습니다. 로이드, 포코, 공원 모두 환영합니다 ❤️&lt;/p&gt;

&lt;p&gt;새로운 과정뿐만 아니라, 기존의 과정들도 차근차근 업그레이드하면서 우테코는 나날이 발전해가고 있어요.
프로그래밍 미션과 글쓰기 미션 모두 열심히 따라와 주고있는 크루들에게도 박수를 보냅니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-04-02/wooteco-back.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;레벨 1 글쓰기 주제는 &lt;b&gt;우아한테크코스 한 달 생활기&lt;/b&gt;입니다.&lt;/p&gt;

&lt;p&gt;백엔드 크루들의 글, 프론트엔드 크루들의 글이 적절히 섞여있으니 읽는 재미가 있으실 거예요.&lt;/p&gt;

&lt;p&gt;우리 크루들은 우테코에서의 첫 생활을 어떻게 보냈을까요?&lt;/p&gt;

&lt;p&gt;우테크루즈, 다시 한번 힘차게 출항합니다. : )&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 style=&quot;font-size:40px; border-bottom: 1px solid gainsboro;&quot;&gt;신세한탄(신세희)의 글&lt;/h1&gt;

&lt;h2 id=&quot;자기-의심과-극복-그-사이에서&quot;&gt;자기 의심과 극복, 그 사이에서&lt;/h2&gt;

&lt;p&gt;한 번도 치열하게 살아본 적 없었다. 모두가 열심히 공부하는 고3 때도, 남들이 스펙이다 대외활동이다 바쁘게 사는 대학 때도 그랬다.
치열하게 살지 않았기 때문에 미래가 무서웠고, 그래서 회피했다.
미래를 이야기하는 분위기에는 언제나 입을 꾹 닫았다.&lt;/p&gt;

&lt;p&gt;이력서와 자기소개서, 채용 시험, 몇 차례의 면접까지 거쳐서 입사하는 기업은 쳐다도 보지 않았다. 도전할 용기도 열정도 없었다.
겨우 한 장의 자기소개서와 한 번의 면접만으로 작은 스타트업에 입사했다. 1년 넘게 일했지만 한 번도 살아있다고 느낀 적 없었다.
눈 씻고 찾아봐도 멋진 구석이라고는 찾아볼 수 없는 삶을 인정하고 싶지 않아서 야근 없는 게 어디냐며 자기 위로를 하곤 했다.&lt;/p&gt;

&lt;p&gt;코로나가 극심해지던 시기, 회사에서 무급휴가를 통보했다. 그제야 정신이 들었다.
‘나 이렇게 살면 안 되겠구나.’
당시에는 급작스레 닥친 상황을 받아들이기 힘들었다. 하지만 이런 상황이 없었다면 스스로 구렁텅이에서 빠져나올 수 없었을 것이다.
지금 와서 되돌아보면 그저 감사할 뿐이다.&lt;/p&gt;

&lt;p&gt;그렇게 회사를 그만뒀고, 개발 공부를 시작했다. 몇 개월을 공부하다가 우아한테크코스에 지원했고, 운 좋게 합격했다.
코딩 테스트도, 프리코스 기간도 나에게는 쉽지 않았기 때문에 얼떨떨했다. 기쁨과 설렘보다는 두려움과 부담감이 컸다.
10개월 동안 내가 과연 해낼 수 있을까? 시작 전 며칠은 숨이 잘 안 쉬어지는 증상을 겪기까지 했다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;우아한테크코스에서의 한 달은 우려한 만큼 힘들었다. 기본기가 부족하다는 것을 매일 실감했다.
미션을 진행하는 것이 버거워 보충 학습이 간절했다. 그렇지만 일주일 내내 페어 프로그래밍만 해도 시간이 부족했다.
부족한 개념을 미처 채우지 못한 채 다음 미션으로 넘어가는 일이 반복됐다.&lt;/p&gt;

&lt;p&gt;모르는 것은 쌓여만 가는데 다른 크루들이 ‘웹 접근성 파악하기’, ‘구조도 그리기’ 등 미션 외의 이벤트에 참여하는 것을 보면 조바심이 났다. 당장 추가적인 학습을 하지 못하는 것에 대한 조바심은 아니었다.
앞으로 점점 더 커져 갈 격차가 두려움으로 다가왔다.
그리고 그 격차를 끝내 감당하지 못하는 순간이 오면 포기하고 싶어질까 봐 그게 가장 겁났다.&lt;/p&gt;

&lt;p&gt;‘다른 크루들과 나를 비교하지 말자. 나의 성장에만 집중하자.’ 많이도 되뇌었지만 쉽지 않았다. 크루들이 남긴 질문에 답변을 남기거나 의견을 나누는 일은 둘째 치더라도, 질문조차 이해하지 못하고 있는 나.
모르는 게 있어 물어보고 싶어도 창피해서 말을 삼키고 마는 나.
이렇게 초라한 나를 매일같이 직면해야 하는 상황에서 작아지지 않기란 어려웠다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;그렇다고 한 달 동안 그저 괴롭기만 했던 것은 아니었다.
지난 한 달은 내가 살면서 가장 생기있게 살아낸 한 달이었다. 열정 넘치는 크루들과 함께 진심을 다해 무언가에 몰입할 수 있는 시간이 소중하고 행복했다.
무엇보다 평생 나를 지배했던 무기력에서 조금씩 벗어나고 있다는 게 좋았다.
우아한테크코스 이전에는 그 흔한 스터디 한 번 해본 적 없었다.
귀찮고, 시간을 내야하고, 내 부족함이 드러날 수 있는 상황들을 회피해왔기 때문이다.
그런데 한 크루가 기초 스터디를 연다는 글을 보고 큰 고민 없이 메시지를 보냈다.&lt;/p&gt;

&lt;p&gt;물론 나는 여전히 나를 다 내려놓지 못했다. 주저하고, 머뭇거리다가 놓쳐버린 기회도 많다.
그렇지만 아주 천천히, 감당할 수 있는 범위 내에서 나를 내려놓고, 부족한 나를 드러내는 연습을 하고 있다.&lt;/p&gt;

&lt;p&gt;아직도 하루하루가 자기 의심과 극복의 반복이다.
앞으로의 성장이 기대되다가도, 자려고 누워서 눈을 감으면 울컥울컥 조급함과 부담감이 올라온다.
그래도 밤늦게까지 남아 공부하다가 크루들과 함께 집에 돌아가던 길에 느낀,
손끝까지 퍼지던 그 ‘살아있음’의 감정으로 남은 날들을 버텨보려고 한다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-04-02/wooteco.001.jpeg&quot; width=&quot;50%&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 style=&quot;font-size:40px; border-bottom: 1px solid gainsboro;&quot;&gt;하루(김하루)의 글&lt;/h1&gt;

&lt;h2 id=&quot;하루-한-달-체험기&quot;&gt;‘하루’ 한 달 체험기&lt;/h2&gt;

&lt;p&gt;사실 나는 최근에 실제 이름을 바꾸었다. 원래는 평범한 한자 이름이었다. 사전에 가족들의 동의를 얻긴 했지만 이름을 바꾼 것은 온전히 나의 선택이었다. 꽤 오래전부터 이름을 바꾸고 싶은 마음은 있었는데, 그와 별개로 이름에 담고 싶었던 나의 뜻 또는 의지가 있었다.&lt;/p&gt;

&lt;p&gt;사람들은 흔히 시간을 ‘과거’, ‘현재’, ‘미래’ 세 가지로 분류한다. 그리고 저마다 다른 가중치를 둔다. 나는 마음으로는 ‘현재’가 가장 중요하다고 생각하면서도, 습관적으로 항상 ‘미래’부터 챙기곤 했다. 지금, 이 순간을 놓치고 있다는 생각이 들 때면 환기 차원에서 ‘오늘을 찾아요’, ‘지금이 우리의 전부’와 같은 노래를 찾아 듣곤 했다. 이 노래들의 가사처럼 ‘오늘 하루’를 소홀히 하지 않고자 하는 나의 바람을 이름에 담았다.&lt;/p&gt;

&lt;p&gt;코로나 여파로 집에만 있어서 바뀐 이름으로 불릴 일이 많이 없었다. 그렇다 보니 나도 모르게 옛날 이름을 쓰는 경우도 더러 있었다. 우테코 시작 전에 문의해보니 본명을 닉네임으로 정해도 된다는 답변을 받았다. 그래서 바꾼 이름인 ‘하루’를 닉네임으로 사용하기로 했다. 줌으로 하는 데일리 미팅이나, 슬랙 메신저에도 항상 ‘하루’라는 사용자 이름이 따라붙고, 코치님, 크루들, 리뷰어님까지 모두 나를 당연하게 ‘하루’라고 불러주셨다. 덕분에 이제는 나의 새로운 이름에 완벽 적응했다. 닉네임을 본명으로 정한 건 잘한 결정이었다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;블로그-할-맛-난다&quot;&gt;블로그 ‘할 맛 난다’&lt;/h2&gt;

&lt;p&gt;작년 12월 프리코스를 진행하면서 처음 블로그를 만들었다. 느낀 점과 배운 점을 기록해두고 싶어서 만들긴 했는데, 당시에 내 글을 불특정 다수에게 공개할 용기는 없었다. 그래서 나만 볼 수 있도록 비공개로 설정해놓고 프리코스 후기를 작성했다. 순수하게 ‘저장소’ 역할만 하는 블로그였다. 그러다 올해 1월 말, 알 수 없는 용기가 생겨 블로그를 새로 단장해서 오픈했다. 그리고 나의 일상과 학습 내용을 하나하나 담아나갔다.&lt;/p&gt;

&lt;p&gt;우테코 과정을 시작한 이후에도 과정에서 배운 내용을 블로그에 틈틈이 포스팅했다. 돌아보니 다루고 싶은 주제를 모두 다루지 못한 점이 아쉬움으로 남는다. 개인적으로 정말 구미가 당기고 더 탐구해서 글로 풀어보고 싶은 주제인데, 생각보다 자료 찾기가 쉽지 않아 포스팅을 포기한 글이 적지 않다. 또, 미션을 진행하면서 시간 관리를 잘 못해서, 정리해야겠다는 생각으로 제목만 써놓고 아예 건드리지 못한 주제도 많다.&lt;/p&gt;

&lt;p&gt;그래도 틈틈이 계속 글을 써왔다는 점은 스스로 칭찬해주고 싶다. 돌아보니 그 사이 10개가 넘는 글을 남겼다. 작성한 글을 크루들에게 소개한 날에는 조회수가 폭발하기도 했다. &lt;em&gt;(FE크루들 영업 당해줘서 고마워요.)&lt;/em&gt; 나의 글이 누군가에게 도움이 되고 피드백을 받는 경험은 이전에 느껴보지 못한 성취감과 만족감을 가져다주었다. 최근에는 감사하게도 한 리뷰어님께서 SNS에 내 블로그를 공유해주신 덕분에, 조회수 최대치를 경신하는 즐거운 경험도 할 수 있었다. 우테코 과정에 참여하지 못했다면 이 모든 새로운 경험을 놓쳤을지도 모른다. 즐거운 마음으로 남은 9개월의 여정도 블로그에 차곡차곡 기록해보려고 한다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;우테코가-판타지인-이유&quot;&gt;우테코가 ‘판타지’인 이유&lt;/h2&gt;

&lt;p&gt;흔히 말하는 대학 과제의 팀플을 떠올려보면, 팀에 속한 ‘모두’가 열심히 한다는 것이 얼마나 비현실적인 이야기인지 알 수 있다. 그런데 그 비현실적인 일이 우테코에서는 벌어지고 있다. 그런 점에서 우테코는 현실보다 판타지에 가깝다고 표현하고 싶다. 주변 사람들이 물으면, 나는 판타지 같은 우테코에서의 생활에 200% 만족한다고 대답한다.&lt;/p&gt;

&lt;p&gt;조직생활을 하는 사람들은 대개 조직 내 불합리한 의사결정을 경험하며 자괴감을 느낀다. 나도 그런 사람 중 하나였다. 퇴사를 결심하며 정했던 단 하나의 목표는 ‘열심히, 즐겁게 일할 수 있는 조직에 속하는 것’이었다. 당시에는 이 목표가 실현 가능한 것인지 확신할 수 없었지만, 우테코 과정에 합류하면서 나는 이 목표를 완벽하게 달성했다. 합리적이고 배려 넘치는 우테코 시스템을 경험할 때, 그리고 열정적인 크루들과 함께할 때, 나는 말로 다 할 수 없는 만족감을 느낀다. 내가 현재 이 조직에 속할 수 있음에, 이 동료들이 나와 함께 해줌에 감사하고 또 감사하다.&lt;/p&gt;

&lt;p&gt;앞서 말한 것처럼 나는 목표를 이미 이루었다. 하지만 우테코는 영원한 과정이 아니다. 그래서 다음 목표는 ‘내년에도 내가 지향하는 조직에 속할 수 있도록, 그 조직에서 필요로 하는 인재가 되는 것’으로 정했다. 우테코에서 한 달 생활을 마친 지금은, 내가 다분히 노력한다면 앞으로도 이 판타지를 이어나갈 수 있으리라는 확신이 든다. ‘열심히, 즐겁게 일할 수 있는 곳’에서 기꺼이 나를 받아줄 수 있도록, 앞으로 더 열심히 나를 단련 시키고 성장해 나갈 것이다.&lt;/p&gt;

&lt;p&gt;시간 내어 읽어주셔서 감사합니다. 🙏&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-04-02/wooteco.002.jpeg&quot; width=&quot;50%&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 style=&quot;font-size:40px; border-bottom: 1px solid gainsboro;&quot;&gt;피케이(박유진)의 글 &lt;/h1&gt;

&lt;h2 id=&quot;기억보단-추억을---우아한테크코스-한-달-생활기&quot;&gt;기억보단 추억을 - 우아한테크코스 한 달 생활기&lt;/h2&gt;

&lt;h3 id=&quot;나-요즘-안-바빠-그냥-조금-정신이-없네&quot;&gt;“나? 요즘 안 바빠… 그냥 조금 정신이 없네.”&lt;/h3&gt;
&lt;p&gt;‘기억보단 기록을’. 다들 한 번쯤 들어보셨죠?
유명한 블로그의 이름이기도 하고, 개발자들 사이에선 이제 불문율이잖아요.
맞아요. 워낙 공부하는 내용이 많은 우리이기에, 기억에만 의존해서는 모든 것을 알고 있기 쉽지 않아요.&lt;/p&gt;

&lt;p&gt;그래서 개발과는 별개로 시간 관리를 철저히 합니다.
습관을 형성하려고 매일 서로 인증하기도 하죠.
블로그나 노트를 작성하기 위해 시간을 투자하기도 해요.
그 와중에 다른 크루와 소통하는 건 또 얼마나 재미있는지…!
정신을 차리고 보면 사람들로 꽉 찬 2호선을 타고 퇴근하는 중이네요. 그렇게 며칠 지내다 보니 한 달 하고도 몇 주가 벌써 지나갔어요.&lt;/p&gt;

&lt;p&gt;우아한테크코스 한 달 생활기…
요즘 그렇지 않아도 주변 사람들이 얼마나 바쁘길래 그렇게 연락이 안 되냐고 묻습니다.
사실은 키보드 좀 만지작거리고 크루들과 직화 제육볶음 몇 번 먹었을 뿐인데…
난 아직 해야 할 것들이 산더미처럼 쌓였는데…
이렇게 빠르게 시간이 흐르다니! 저는 즐겼던 순간밖에 없는데 말이죠.
그래서 바쁘다고 말하기 부끄러워 이렇게 대답합니다.&lt;/p&gt;

&lt;p&gt;“나? 요즘 안 바빠… 그냥 조금 정신이 없네.”&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;오히려-좋아&quot;&gt;“오히려 좋아!”&lt;/h3&gt;
&lt;p&gt;왜 정신이 없냐고요?
우아한테크코스에 들어오기 전까지는 이렇게 짧은 시간 동안 많은 활동을 해본 적이 없었어요.
제게 프로그래밍을 알려주는 존재는 대부분 이름 모를 🇮🇳인도🇮🇳 출신 유튜버들이었거든요.
보통 혼자서 ‘개발할 때 듣기 좋은 플레이리스트’ 들으면서 새벽에 컴퓨터를 붙잡고 있었습니다.
모든 활동이 제 머릿속에서 이루어졌죠.&lt;/p&gt;

&lt;p&gt;이제는 상황이 다릅니다.
요즘 평생 먹지도 않던 아침밥을 챙겨 먹어요.
멀티스레딩을 공부하며 프로그래밍에 입문했다는 크루와 함께 먹는데, 그 크루와 얘기하다 보면 아침밥보다도 든든한 힘을 얻곤 합니다.&lt;/p&gt;

&lt;p&gt;동네 형 같은 어떤 크루는 만날 때마다 매번 새로운 시간 관리 팁이나 기록 관련 노하우를 공유하며 저를 응원해줘요.&lt;/p&gt;

&lt;p&gt;또 다른 크루는 아재 개그와 호탕한 웃음으로 엉뚱한 모습이었다가도, 지식을 공유할 때 교수님과 같은 지적인 모습을 보여주죠.&lt;/p&gt;

&lt;p&gt;“고양이가 최고야… 개발은 힘들다…“라며 매일 본인의 실력을 의심하는 한 크루는 다른 사람의 코드를 기가 막히게 디버깅하며 모두를 놀라게 합니다.&lt;/p&gt;

&lt;p&gt;이렇게 훌륭한 개발자들과 끊임없이 소통하는데 정신이 있을 리가 있나요.
&lt;strong&gt;다행히 요즘 새로 습득하는 지식은 이런 경험들과 함께 추억이 되어 제 머릿속에 들어옵니다.&lt;/strong&gt;
약간 ‘너드’처럼 들릴 수도 있겠지만, 여러분과 함께한 즐거운 시간을 떠올리면 자연스레 그날 주고받았던 대화의 주제가 떠올라요.
요즘 한 크루가 밀고 있는 표현이 생각나네요.&lt;/p&gt;

&lt;p&gt;“오히려 좋아!”.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;잠깐-피케이가-지금-무슨-말을-할지-알-것-같은데-저는-95-정도-반대해요-ㅎ&quot;&gt;“잠깐, 피케이가 지금 무슨 말을 할지 알 것 같은데… 저는 95% 정도 반대해요. ㅎ”&lt;/h3&gt;
&lt;p&gt;페어 프로그래밍을 하며 한 크루가 제게 했던 말입니다.
그러고는 자세를 고쳐 앉고 한 마디 툭 던지네요.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“설득해보세요.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;사실 성격상 아직 프로그래밍에 관련해서 제 주장을 마음껏 펼치기가 굉장히 힘들어요.
스스로의 실력을 의심하고 있는 것도 한몫하죠.
그런데 이곳에서는 본인의 생각을 말해야 할 상황이 늘 생깁니다.
그뿐만 아니라 다른 사람과 함께 실시간으로 코딩을 하며 누구에게나 그 코드가 열려있어요.
와… 다들 어찌 그리 잘하는지. 말 한마디 하고 나면 저도 모르게 눈치를 계속 보게 됩니다.
지금 내가 말하는 내용이 맞나? 나는 왜 이렇게 구현하려고 하는 거지? 그리고 상대방을 설득해야 합니다.
지금 제 옆에 자세를 고쳐 앉은 페어가 대답을 기다리고 있으니까요.&lt;/p&gt;

&lt;p&gt;무려 10시간 동안 이어지는 치열한 토론과 구현.
제가 페어의 의견을 존중하듯 페어도 제 의견을 존중해주는 것이 느껴집니다.
그래서 머릿속에 있는 생각을 점점 더 자주 공유하기 시작해요.
정신을 차리고 보면 어느새 저녁을 먹을 시간이 다가오죠. 주장을 마음껏 펼치기 힘들다고 해놓고 정신없이 얘기하다니.
이 모든 과정마저도 용기 내어 꺼내 보는 말 한마디에 추억으로 바뀝니다.&lt;/p&gt;

&lt;p&gt;“근처에 제가 가는 단골 치킨집 있는데 같이 갈래요? 100% 만족 확실해요.”&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;고생하셨어요-이만-머지할게요-다음-미션-파이팅입니다&quot;&gt;“고생하셨어요. 이만 머지할게요. 다음 미션 파이팅입니다!”&lt;/h3&gt;
&lt;p&gt;코드 리뷰를 받다 보면, 리뷰의 마지막에 자주 보이는 표현입니다.
열정적으로 미션을 진행하고 난 후에 이 문장을 보면 기분이 좋아지죠.
여러분과 함께 많은 것을 배우면서 느끼는 감정과 비슷한 것 같아요.&lt;/p&gt;

&lt;p&gt;앞으로 누군가 제게 왜 그리 바빠 보이냐고 묻는다면 대답이 달라지지는 않을 것입니다.&lt;/p&gt;

&lt;p&gt;“나? 요즘 안 바빠… 그냥 조금 정신이 없네.”&lt;/p&gt;

&lt;p&gt;하지만 우아한테크코스 한 달 생활기를 묻는다면 이렇게 대답할 거예요.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“요즘 추억을 쌓아가며 정신없이 성장하고 있어.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;허술한 주장이라도 같이 생각해보며 바로잡아 주는 크루들. 그리고 과분하다 싶을 정도로 칭찬을 해주는 크루들.
아직 부족한 점이 많지만, 덕분에 무럭무럭 성장한다는 게 느껴지네요. 정말 감사합니다.
그런데 우리는 이제 시작이니까, 앞으로 더 파이팅 해봐요!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-04-02/wooteco.003.jpeg&quot; width=&quot;50%&quot; /&gt;
&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 style=&quot;font-size:40px; border-bottom: 1px solid gainsboro;&quot;&gt;소롱(최솔지)의 글 &lt;/h1&gt;

&lt;h2 id=&quot;무無의-미학&quot;&gt;무無의 미학&lt;/h2&gt;

&lt;h3 id=&quot;우테코에는-내-이름이-없다&quot;&gt;&lt;strong&gt;우테코에는 내 이름이 없다.&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;다른 크루들이 우테코에 합격하고 OT에 참여할 때까지 무엇을 했는지 궁금하다. 나에겐 그 기간이 없었다.&lt;/p&gt;

&lt;p&gt;아침 9시, 백수로서는 꽤 이른 아침에 추가 합격 문자를 받았다. 처음 불합격했을 때는 그다지 아쉽지 않았다. 익숙해질 때도 됐다. 대신 합격 통보에는 익숙해질 기회가 없었다. 아침 먹는 내내 설렜다가, 당일 오후 2시가 OT라는 말을 듣고 당황했다.&lt;/p&gt;

&lt;p&gt;OT 시작 전, 크루들의 사진과 닉네임, 좌우명이 지나갔다. 그 안에 내가 있어서 참 다행이었다.&lt;/p&gt;

&lt;p&gt;무엇이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;있어서&lt;/code&gt; 좋다고 설명하기는 쉽다. 그렇다고 없는 게 항상 나쁘지만은 않다. 없으면, 다른 좋은 일이 또 생기기 마련이다. 이번 기회에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;없어서&lt;/code&gt; 좋다고 말해보려고 한다.&lt;/p&gt;

&lt;h3 id=&quot;우테코에는-규칙이-없다&quot;&gt;우테코에는 규칙이 없다.&lt;/h3&gt;

&lt;p&gt;우테코의 기본 생활 규칙은 단순하고 쉽다. 현대인으로서 무던하게 살아갈 만한 예의를 가지고 있다면야 어길 일이 없다. 데일리 스크럼과 수업, 특강 등을 제외하면 별다른 일정도 없다. 온라인일 때는 내가 언제 쉬러 가는지 확인할 사람도 없다. 중간에 산책하러 가거나 심지어 낮잠을 자도 된다.&lt;/p&gt;

&lt;p&gt;지금까지는 모든 일정을 정형화하려고 노력해왔다. 딱딱 나눈 시간표를 봐야 안심했다. 눈앞에 과제가 있으면 다른 모든 일과가 사치스럽게 느껴졌다. 일과 쉼의 분리가 있는 삶이 열심히 사는 인생 같았다. 하지만 정해진 일정을 하나라도 지키지 못하면 내 삶으로 돌아갈 시간이 미뤄졌고, 결국 나는 더 불안해졌다.&lt;/p&gt;

&lt;p&gt;그래서 처음에는 방종이 참으로 낯설었다. &lt;em&gt;진짜 이렇게 살아도 되나? 진짜 이렇게 살아도 되는구나!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;시간표가 없어지니 나는 오히려 워커홀릭이 되었다. 끝없는 몰입과 집중이 탁 풀리는 사이의 순간을 사랑하게 됐다. 이제야 겨우 코딩과 내 삶이 어떤 균형을 찾아가는 기분이 든다. 학생이 아닌지도 오래되었는데 그동안 나는 왜 스스로를 옭아맬 규칙을 찾아다녔을까?&lt;/p&gt;

&lt;h3 id=&quot;우테코에는-경쟁이-없다&quot;&gt;우테코에는 경쟁이 없다.&lt;/h3&gt;

&lt;p&gt;어린 시절부터 인생은 경쟁의 연속이었다. 무의식중에 남의 실력을 점쳐보고, 이길 수 있을지 가늠하는 나쁜 습관을 길러왔다. 내가 우테코에서 가장 많이 한 말 중의 하나는 ‘저 사람은 왜 여기 있어?’ 아닐까. 그만큼 잘하는 사람이 많고, 자꾸 나와 비교하게 된다. 우테코는 나처럼 열등감 많은 사람이 스트레스 받기 아주 좋은 곳이다.&lt;/p&gt;

&lt;p&gt;초반에는 강의가 너무 무서웠다. 나는 강의 내용을 따라잡기도 벅찬데, 채팅창에는 온갖 모르는 단어들이 난무했다. 알지도 못하면서 적어두기만 한 말들이 늘어갔다. 언제 다 공부해서 남들만큼 할 수 있게 될지 참 아득했다. 포비가 아무리 비교하지 말라고 해도 그게 잘 안됐다. 솔직히 말하면 2주차 즈음 울었다.&lt;/p&gt;

&lt;p&gt;울고 나서 다시 2주 뒤에 포비의 멘탈 강의가 또 있었다. 그때 정말 감동받아서 딱 세 문장을 일기장에 적어놓았다.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;작은 성공을 반복적으로 경험한다. 한 가지라도 꾸준히 지속하자. 위안으로 삼을 거리를 만들어라.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;매일 미션과 추가 학습 목표를 세우는데 달성하기 쉽지 않았다. 마음먹은 만큼 못하면 또 우울해지곤 했다. 기준이 남에게 있으니 부담감만 더욱 늘어났다.&lt;/p&gt;

&lt;p&gt;그래서 포비의 조언에 따라 사고를 조금 바꿨다. 온전히 나만의 기준을 만들었다. 책을 한 권을 읽든 한 줄을 읽든 &lt;em&gt;일단 읽었다고 치는 것이다.&lt;/em&gt; 그리고 ‘오늘 뭐 그렇게 막살지는 않았어’하고 안심하며 잠들면 꽤 괜찮다.&lt;/p&gt;

&lt;p&gt;이 글을 쓰면서 포비가 말하는 성공과 나의 성공이 다르리라는 생각을 잠깐 했다. 그래도 조금은 더 해야하지 않을까, 압박감이 자꾸 생겼지만 이내 접어두었다. 애초에 포비는 이런 부담을 주려고 한 의도가 아니라고 믿기 때문이다. 적어도 나는 ‘안 한 것보단 낫지’라는 위안으로 우테코 생활을 지탱해가고 있다. 처음에는 와닿지 않았던 말대로, 지금의 나는 어제의 나보다 나아졌으니까.&lt;/p&gt;

&lt;p&gt;오롯이 나에게 집중하면 더 이상 남은 보이지 않는다. 이제 그들을 남이 아니라 다른 말로 칭하고 싶다. 우테코의 크루들은 나에게 도움을 주고, 내가 도움 줄 사람들이지 나의 적이 아니다. 이제 남이 없어졌으니 또 무엇이 생길지 기대된다. 없으면, 다른 좋은 일이 또 생기기 마련이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-04-02/wooteco.004.jpeg&quot; width=&quot;50%&quot; /&gt;
&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 style=&quot;font-size:40px; border-bottom: 1px solid gainsboro;&quot;&gt;바다(조아라)의 글 &lt;/h1&gt;

&lt;h2 id=&quot;우아한테크코스-한-달-생활기&quot;&gt;우아한테크코스 한 달 생활기&lt;/h2&gt;

&lt;h4 id=&quot;질문에도-용기가-필요하다&quot;&gt;질문에도 용기가 필요하다.&lt;/h4&gt;
&lt;p&gt;요즘 가장 절실히 느끼고 있는 말이다. 우아한테크코스에는 용기 있는 크루들이 많다.&lt;br /&gt;
슬랙에서도 주저 없이 질문과 토론을 주고받고 강의 중에도 모르는 것이 생기면 바로바로 질문한다.&lt;br /&gt;
사실 처음에는 이것 때문에 많이 힘들었다. 나에겐 &lt;strong&gt;두 가지 용기&lt;/strong&gt;가 없었다.&lt;/p&gt;

&lt;h4 id=&quot;첫-번째-모르는-것을-모른다고-말할-수-있는-용기&quot;&gt;첫 번째, 모르는 것을 모른다고 말할 수 있는 용기&lt;/h4&gt;
&lt;p&gt;첫 번째 용기는 타인과의 관계에서 필요한 용기다.&lt;br /&gt;
리뷰어에게 DM을 보낼 때도 초안을 쓰고 있는 날 보며 한 페어는 나에게 왜 이렇게 모든 일에 신중하냐고 물었다.&lt;br /&gt;
상대가 한 말을 내가 잘 이해한 것이 맞는지, 내 질문이 이상하게 들리지는 않는지, 모든 것이 신경 쓰였다.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;내가 이걸 몰라도 되는 걸까? ‘왜 이런 걸 물어보지?’라고 생각하면 어떡하지?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;질문할 용기가 없어서 모르는 것이 있어도 혼자 찾아서 해결하려고 했다.&lt;/p&gt;

&lt;p&gt;코치와의 면담에서 고민을 얘기할 기회가 있어 이 얘기를 했다.&lt;br /&gt;
워니는 어차피 학습을 위해 모인 곳이고 가르쳐주려고 있는 사람들이니 끊임없이 질문하라고 하셨다.&lt;br /&gt;
그리고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;일주일에 두 번씩 코치들에게 질문하기&lt;/code&gt; 라는 미션을 주셨다.&lt;br /&gt;
&lt;em&gt;“제 닉네임 아세요?”&lt;/em&gt; 같은 것도 질문에 포함된다면 이 미션은 성공한 것이라 할 수 있다.&lt;br /&gt;
사소한 질문이어도 일단 대화를 시작하면 더 많은 질문을 할 수 있었다. 질문은 질문을 낳았다.&lt;/p&gt;

&lt;h4 id=&quot;두-번째-나의-지식수준을-정확히-마주할-용기&quot;&gt;두 번째, 나의 지식수준을 정확히 마주할 용기&lt;/h4&gt;
&lt;p&gt;두 번째 용기는 자신에게 필요한 용기다.&lt;br /&gt;
질문을 하기 위해선 생각을 잘 정리해야 한다. 그러다 보면 자연스레 나의 지식들과 마주하게 된다.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;이걸 왜 이렇게 했냐고 물어보면 어떻게 설명하지?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;어설프게 알고 있는 것들과 정확히 마주할 용기가 없었다. 그냥 일단 회피하고 싶었다.&lt;/p&gt;

&lt;p&gt;페어 프로그래밍은 코드를 구현하는 시간보다 토론을 하는 시간이 더 긴 프로그래밍 방법이다.&lt;br /&gt;
페어 프로그래밍을 하면 내 의견을 &lt;strong&gt;잘 말하는 법&lt;/strong&gt;과 상대의 의견을 &lt;strong&gt;잘 듣는 법&lt;/strong&gt;을 배울 수 있다.&lt;br /&gt;
처음에는 갈등을 피하려고 토론을 피했다. 하지만 내 생각을 얘기했더니 의외로 갈등은 일어나지 않았다.&lt;br /&gt;
그리고 토론을 통해 내가 어설프게 알고 있던 것들을 하나씩 채울 수 있었다.&lt;/p&gt;

&lt;h4 id=&quot;괜찮지-않아도-괜찮아&quot;&gt;괜찮지 않아도 괜찮아&lt;/h4&gt;
&lt;p&gt;미션을 진행할수록 조급하고 불안한 마음이 자주 들어 마음의 여유를 갖는 연습을 했다.&lt;br /&gt;
햇살이 좋은 날, 혼자 걸으며 머릿속으로 스스로에 대해 회고를 하는 것이다.&lt;br /&gt;
조급해하지 말자. 불안해하지 말자. 남들과 비교하지 말자.&lt;br /&gt;
너무 괜찮은 사람이 되려고 하지 말자. 사람은 누구나 실수를 하고 부족한 부분이 있다.&lt;br /&gt;
가끔은 이상한 질문을 해도 괜찮고, 괜찮지 않아도 괜찮다.&lt;/p&gt;

&lt;p&gt;솔직히 말하면, 레벨 1을 마무리하는 지금도 내 의견을 말하는 것이 어렵다. 불안한 마음은 쉽게 없어지지 않는다. &lt;br /&gt;
하지만, &lt;em&gt;‘지금 잘 가고 있는 걸까?’&lt;/em&gt; 라는 생각은 당분간은 하지 않기로 했다. 일단 &lt;strong&gt;‘가고 있음’&lt;/strong&gt; 에 집중하자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-04-02/wooteco.005.jpeg&quot; width=&quot;50%&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 02 Apr 2021 09:00:00 +0900</pubDate>
        <link>https://woowabros.github.io/techcourse/2021/04/02/techcourse-level1-retrospective.html</link>
        <guid isPermaLink="true">https://woowabros.github.io/techcourse/2021/04/02/techcourse-level1-retrospective.html</guid>
        
        
        <category>techcourse</category>
        
      </item>
    
      <item>
        <title>우아한테크캠프 Pro 후기</title>
        <description>&lt;h2 id=&quot;2021년-대한민국-소프트웨어-업계-이야기&quot;&gt;2021년. 대한민국 소프트웨어 업계 이야기&lt;/h2&gt;
&lt;p&gt;지금까지 개발자가 이렇게 좋은 대우를 받았던 적이 있을까? 내가 개발자의 길을 걷기 시작했던 1990년대 후반에서 2000년 초반 벤처 붐이 일면서 잠깐 반짝했던 것 같다.&lt;/p&gt;

&lt;p&gt;하루가 멀다 하고 “전 직원에게 몇 백만 원의 연봉을 인상하기로 했다.”, “몇 백만 원의 복지 포인트를 지원한다.”, “100% 원격 근무로 전환한다.”와 같은 뉴스가 들려오고 있다. 이 모든 뉴스들이 가리키는 것은 역량 있는 좋은 개발자를 유지하고 채용하고자 하는 간절함의 표현이다.&lt;/p&gt;

&lt;p&gt;이와 같은 개발자의 처우 개선은 일반 사용자용 소프트웨어를 개발하는 서비스 개발 회사에 집중되고 있다. 물론 비서비스 개발 회사의 개발자에 대한 처우도 조금씩 나아지고 있지만 서비스 개발 회사의 처우 개선에 비해서는 부족한 현실이다. 그렇다 보니 서비스 개발 회사의 개발자와 솔루션, SI 개발자의 처우에 대한 격차가 점점 더 벌어지고 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;글 전개의 편의성을 위해 일반 사용자용 소프트웨어를 개발하는 회사로 사용자의 피드백을 받아 지속적으로 서비스를 개선해 나가는 회사, 소프트웨어가 회사의 매출에 기여하는 부분이 가장 큰 회사를 서비스 개발 회사로 지칭했으며, 그렇지 않은 SI, 업무용 소프트웨어를 개발 회사 등을 묶어 비서비스 개발 회사로 글을 전개했다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;그렇다면 비서비스 개발 회사에서 일하는 개발자의 처우가 부족한 것이 개발자들의 열정과 역량이 부족해서 일까? 나는 그렇지 않다고 생각한다. 개발자의 길을 걷기 시작할 때의 열정과 역량은 서비스 개발 회사의 개발자와 비서비스 개발 회사 개발자의 비슷한 수준이다. 하지만 시간이 지나면서 역량의 차이가 발생하고, 처우 또한 열악한 상황이 많다 보니 열정 또한 떨어질 수밖에 없다.&lt;/p&gt;

&lt;p&gt;비서비스 개발 회사의 개발자들의 역량 차이가 발생하는 가장 큰 이유는 개개인의 역량이 부족하기 때문이 아니라 일하는 환경 때문이다. 어떻게 성장하는 것이 좋은 개발자로 성장할 것인지에 대한 로드맵을 보고 배울 선배가 부족하며, 성장하려는 열정이 있더라도 어디서부터 어떻게 시작해야 할지 막막한 것이 현실이다. 물론 개인의 노력을 통해 극복할 수 있는 것 아니냐고 반문할 수 있지만 주어진 환경의 틀을 깨고 다른 길을 걷는 것은 상당한 용기와 혜안이 필요하다. 그만큼 역량 있는 개발자로 성장하는데 주변 환경이 중요하다.&lt;/p&gt;

&lt;p&gt;앞에서 잠시 언급했지만 서비스 개발 회사들은 개발자를 채용하기 위해 정말 다양한 수단과 방법을 동원하고 있다. 네이버, 카카오와 같은 업계 1, 2위 회사도 개발자를 구하지 못하는 상황이다 보니 스타트업의 어려움은 말로 표현하기 힘들 정도다.&lt;/p&gt;

&lt;p&gt;개발자에 대한 처우는 계속해서 개선되고 있지만 개발자 채용은 점점 더 힘들어지고 현실이다. 개발자의 처우가 개선되고 있다는 뉴스는 자주 보이지만 상당 수의 개발자는 피부로 체감하기 힘들다. 이 둘의 불일치를 어떻게 해소하면 좋을 것인가가 교육자로서 고민이었고, 이에 대한 한 가지 해결책이 “&lt;a href=&quot;https://edu.nextstep.camp/c/lqsBs7x0&quot;&gt;NEXTSTEP for Enterprise Pro&lt;/a&gt;라는 채용 연계형 교육 과정을 운영하는 것이었다.&lt;/p&gt;

&lt;h2 id=&quot;우아한테크캠프-pro-시작&quot;&gt;우아한테크캠프 Pro 시작&lt;/h2&gt;
&lt;p&gt;나는 교육자의 길을 걷기 시작하기 전부터 대한민국 소프트웨어 생태계의 역량을 한 단계 높이려면 재직자에 대한 재교육이 필요하다고 생각했다. 지금까지 정부, 기업이 지원하는 거의 모든 교육은 취업자 교육에 집중되어 있다. 특히 국비지원 과정을 통해 무분별하게 많은 개발자들이 양산되고 있다. 정부, 기업 주도로 많은 소프트웨어 교육 과정을 운영하는 것도 의미 있다. 단, 이 같은 교육 과정을 통해 배출되는 교육생들의 역량이다. 짧은 기간 동안 집중적으로 학습한 소프트웨어 역량만으로 소프트웨어 회사들이 요구하는 역량을 갖추는 데는 한계가 있다. 단순히 취업만 성공했다고 끝나는 것이 아니라 이렇게 취업한 친구들이 다음 단계로 성장할 수 있는 환경을 만들어 주어야 한다. 계속해서 취업생 교육에만 집중할 것이 아니라 취업자 교육과 재직자 교육을 병행해 운영하는 것이 지금의 소프트웨어 개발자의 품귀 현상을 해소할 수 있는 방법 중의 하나이다.&lt;/p&gt;

&lt;p&gt;2020년. 기업이 교육비를 지원하는 재직자에 대한 재교육 과정을 개설해 볼 수 있는 환경이 무르익었다고 생각했다. 오히려 더 일찍 시작했었어야 할 수도 있다.&lt;/p&gt;

&lt;p&gt;교육생 입장에서는 교육비에 대한 부담을 최소화하면서 역량을 키우고, 좋은 회사로 이직할 수 있는 기회를 얻을 수 있고, 회사 입장에서는 부족한 개발자를 합리적인 비용으로 채용할 수 있다는 확신이 드는 순간 우아한형제들에 이 과정을 제안했다. 그렇지 않아도 개발자 채용에 대한 어려움을 호소하고 있던 상황이라 빠른 속도로 승인을 받을 수 있었다. 그렇게 우아한테크캠프 Pro 과정을 시작했다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-03-15/wootecamp-pro-poster.jpg&quot; alt=&quot;우아한테크캠프 pro 포스터&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;우아한테크캠프-pro-교육-운영&quot;&gt;우아한테크캠프 Pro 교육 운영&lt;/h2&gt;
&lt;p&gt;우아한테크캠프 Pro 교육 과정을 통해 달성하고 싶었던 학습 목표는 크게 두 가지였다. 첫째는 짧은 9주 동안 많은 지식을 전달하는 데는 한계가 있기 때문에 꾸준하게 자기 주도적으로 학습함으로써 프로그래밍에 대한 즐거움을 느끼도록 하는 것이다. 즉, 약간은 떨어져 있는 열정을 다시금 되살리고 싶었다. 둘째는 소프트웨어 장인으로 성장해 나가기 위한 로드맵을 제시하는 것이었다.&lt;/p&gt;

&lt;p&gt;교육 진행 방식은 NEXTSTEP의 모든 교육이 그러하듯 미션 기반, 코드 리뷰 방식으로 진행해 별반 다르지는 않았다. 단, 위 두 개의 목표를 달성하기 위해 몇 가지 장치를 두어 운영했다. 나는 100% 무상으로 지원하는 것이 교육 효과 측면에서 좋지 않을 수도 있다고 생각한다. 이런 철학 하에서 교육비에 대한 지원을 2단계로 나눠 운영했다. 프리코스라는 과정을 통해 선발된 교육생에 대해 50%의 교육비를 지원한다. 교육 과정을 마치고 40명 중 20명을 우수 수료생으로 선발해 30%의 교육비를 추가로 지원하는 구조로 운영했다. 이 같은 구조로 운영하는 것이 교육에 대한 참여도를 높여 학습 효과를 높일 수 있다고 생각한다.&lt;/p&gt;

&lt;p&gt;또 다른 장치는 지식을 전달하기 위한 강의 외에 개발자의 삶, 커리어 패스와 개발자의 로드맵 설계, 현재 겪고 있는 고민들을 공유하고 소통할 수 있는 네트워킹 데이를 별도로 운영했다. 교육생들의 설문 피드백을 보면 이론 강의도 좋았지만 다른 개발자와 소통할 수 있는 이 네트워킹 시간을 통해 많은 공감과 자신감을 얻을 수 있었다고 한다. 앞으로 어떻게 성장해야 할 것인지, 살아가야 할 것인지에 대한 방향을 설정하는데 도움을 얻었다고 한다. 지금까지 함께 소통할 선배, 동료 개발자가 부족했던 개발자들에게 작으나마 도움이 되었다는 피드백은 교육자로 살아가는 나에게도 큰 보람으로 다가왔다.&lt;/p&gt;

&lt;h2 id=&quot;우아한테크캠프-pro-결과&quot;&gt;우아한테크캠프 Pro 결과&lt;/h2&gt;
&lt;p&gt;위와 같이 몇 개의 내적인 동기부여, 외적인 동기부여를 위한 장치를 만들고 교육을 운영한 결과는 내 기대 이상이었다. &lt;a href=&quot;https://brunch.co.kr/@javajigi/19&quot;&gt;Next Step - 온라인 후기&lt;/a&gt; 글에서 볼 수 있듯이 NEXTSTEP은 몇 개의 데이터를 통해 교육생의 교육에 대한 만족도와 교육 효과를 측정하고 있다.&lt;/p&gt;

&lt;p&gt;기존 재직자 과정 중의 하나인 &lt;a href=&quot;https://edu.nextstep.camp/c/8fWRxNWU&quot;&gt;클린코드를 위한 TDD with Java&lt;/a&gt;의 NPS(Net Promoter Score)는 65 ~ 80%, 미션 완료율은 평균 20% 내외이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-03-15/cleancode-with-java.png&quot; alt=&quot;cleancode-with-java&quot; /&gt;&lt;/p&gt;

&lt;p&gt;“클린코드를 위한 TDD with Java” 과정은 오프라인으로 진행할 경우 5주 동안 4개의 미션, 온라인은 8주 동안 4개의 미션을 진행해야 한다. 회사 생활과 병행해야 하기 때문에 교육 기간 동안 4개의 미션을 완료하기가 생각보다 쉽지 않다. “우아한테크캠프 Pro”는 이 보다 미션 난이도가 높고, 9주 동안 6개의 미션을 완료해야 하는 과정이라 모든 미션을 완료해 수료하기 훨씬 더 어려운 과정이다. 그럼에도 불구하고 “우아한테크캠프 Pro”에 대한 미션 완료율은 77.5%에 달한다. 이 과정을 시작할 때 50%만 넘겨도 의미 있겠다 생각했는데 무려 77.5%다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2021-03-15/wootecamp-pro.png&quot; alt=&quot;우아한테크캠프 pro&quot; /&gt;&lt;/p&gt;

&lt;p&gt;미션을 구현하고, 리뷰 요청을 하고 피드백을 받은 경험이 많으면 많을수록 교육에 대한 만족도가 높아진다. 그만큼 교육 과정을 통해 많이 배우고 성장했다고 생각하기 때문이다. 그래서일까? “본 과정을 다른 개발자에게 추천할 의향이 있는가?”라는 설문 결과를 통해 추출한 NPS 점수가 97%에 달한다. 지금까지 재직자 과정을 여러 번 운영해 봤지만 90%를 넘은 적은 처음이다. 그것도 가장 난이도가 높은 과정에서 말이다.&lt;/p&gt;

&lt;p&gt;교육 결과는 좋았다. 그렇다면 이런 좋은 교육의 결과로 몇 명의 개발자가 우아한형제들 입사에 성공했을까? 최종 합격한 개발자의 수는 6명이다. 많다면 많고, 적다면 적은 수이다. 합격자의 수가 더 많았다면 우아한형제들도, 교육생들도 더 좋았겠지만 꼭 채용에 성공한 것만으로 우아한테크캠프 Pro 교육의 효과를 논하기는 힘들 것 같다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;우아한테크캠프 Pro 교육 과정에 참여하면서 9주 동안 얻은 자신감, 프로그래밍에 대한 즐거움, 소프트웨어 장인에 도전하려는 개발자들이 남았다.&lt;/strong&gt; 이 개발자들이 좋은 개발자로 성장해 대한민국 소프트웨어 생태계에 기여하는 모습을 보는 것이 우아한테크캠프 Pro 교육이 진정 효과가 있었다는 것을 증명할 수 있을 것이다. 그런 효과를 볼 수 있는 날이 오기를 기대해 본다.&lt;/p&gt;

&lt;h2 id=&quot;교육-과정-후기&quot;&gt;교육 과정 후기&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;“열정적으로 코딩을 할 수 있다.” 때문에 추천할 거 같습니다. 이번 2달 동안 코드리뷰를 받으면서 정말 열정적으로 코딩할 수 있는 경험이었습니다&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;이렇게 몰입하며 즐겁게 코딩해볼 수 있는 과정이 우리나라에 없기 때문입니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;처음엔 본인이 알고 있던 것을 버리고 다시 새로 받아들이는 과정이 힘들 순 있지만, 힘든 만큼 모든 과정이 끝난 후 코드에 대한 관점이 바뀐 걸 느낄 수 있었습니다. 교육비는 배움에 비해 정말 적은 편이고, 2개월 동안의 짧은 과정이지만 개발 인생이 달라질 거라고 기대합니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;자기 성장이나 좋은 코딩 습관을 들이고 싶은데 어떻게 시작해야 할지 막막할 때, 혹은 구체적인 방법을 몰라 가이드가 필요하다면 아주 적절한 교육일 것 같아요. 하나의 주제를 가지고 다양한 사람들의 다양한 시각을 접할 수 있는 부분도 좋았습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;확장성, 생산성, 신뢰성 높은 코드를 생성하면서 개발에 대한 자신감도 생기고, 유익함도 매우 큰 과정이다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;앉아서 가만히 듣는 수업보다 직접 미션 기반 프로젝트를 진행하면서 교육을 들어서 수업 효과가 배가 된 거 같습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;겉만 자바 개발자, 프로그래머가 아닌 진정한 소프트웨어 개발 전문가로서 자바를 사용하는 프로그래머로서 성장할 수 있는 좋은 교육이었습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;대부분의 회사들이 개발을 잘하는 방법보다는 빨리하는 것을 원하는데 그 고정관념을 좀 깨줄 수 있을 것 같다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;자신의 한계로 도전해볼 수 있는 좋은 기회라서 적극 추천하고 싶습니다. 항상 강의를 들으면서 100%를 배우진 못하지만 성장할 수 있는 계기, 생각의 틀을 깰 수 있는 계기를 만들어주는 기회라서 꼭 추천하고 싶습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;이렇게 많은 시간을 꽉 차게 헛되지 않은 공부에 투자할 수 있는 건 인생에서 그리 많지 않은 기회라 생각합니다. 스스로 공부할 방법을 몰랐던 개발자에게 이정표가 되어주는 과정이고, 앞으로도 스스로 공부할 수 있는 힘을 길러주는 과정이었습니다.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Mon, 15 Mar 2021 11:00:00 +0900</pubDate>
        <link>https://woowabros.github.io/techcourse/2021/03/15/wootecamp-pro.html</link>
        <guid isPermaLink="true">https://woowabros.github.io/techcourse/2021/03/15/wootecamp-pro.html</guid>
        
        
        <category>techcourse</category>
        
      </item>
    
      <item>
        <title>프로모션용 웹앱 빌더, 만다오</title>
        <description>&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/blog-banner.png&quot; /&gt;
  &lt;span style=&quot;display: block; color:#808080; margin-top: 10px;&quot;&gt;만다오 로고. 에디터임을 떠올릴 수 있는 펜촉에서 영감을 얻었습니다.&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;안녕하세요, 웹프론트개발그룹의 장해민입니다.&lt;/p&gt;

&lt;p&gt;우아한 테크캠프를 무사히 마치고 입사 후 약 세달간 민태님, 은정님, 그리고 찬호님과 함께 프로모션용 웹앱 빌더 &lt;strong&gt;만다오&lt;/strong&gt;를 만든 이야기를 공유하려고 합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;만다오(Mandao)&lt;/strong&gt;는 웹프론트개발그룹에서 즐겨하는 &lt;em&gt;카트라이더 러쉬 플러스&lt;/em&gt;의 대표 캐릭터인 &lt;strong&gt;다오&lt;/strong&gt;에서 이름을 따왔으며 &lt;strong&gt;만들어다오&lt;/strong&gt;라는 뜻을 가지고 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;프로모션용-웹앱-빌더가-무엇인가요&quot;&gt;프로모션용 웹앱 빌더가 무엇인가요?&lt;/h2&gt;

&lt;p&gt;배달의민족, 비마트 등 우아한형제들 서비스에서는 매일 다양한 프로모션이 진행됩니다. 쿠폰을 다운받거나 동영상을 시청하고 메뉴를 좌우로 스와이프하는 등 다양한 기능과 형태로 화면이 제작되고 있습니다.&lt;/p&gt;

&lt;p&gt;지금까지는 디자인된 이미지를 잘라서 이어붙이고 쿠폰 다운로드 코드, 앱스킴 등의 연결 링크들을 직접 HTML 코드를 수정해가며 만들었습니다. 필요에 따라서는 프론트엔드 개발자가 직접 개발하기도 하죠.&lt;/p&gt;

&lt;p&gt;코드를 복사하는 과정에서 실수가 발생할 수도 있고 동일한 작업을 베타와 운영 두 번에 걸쳐 진행하는 번거로움도 있었습니다. 또한 화면에 사용될 이미지와 배포될 결과물 파일도 직접 CDN 서버에 수동으로 올려야 했습니다.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/previous-workflow.png&quot; /&gt;
  &lt;span style=&quot;display: block; color:#808080; margin-top: 10px;&quot;&gt;기존 워크플로우&lt;/span&gt;
&lt;/div&gt;

&lt;h2 id=&quot;웹앱을-만드는-웹앱&quot;&gt;웹앱을 만드는 웹앱&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;만다오&lt;/strong&gt;는 이런 문제점들을 해결하기 위해 탄생한 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9C%84%EC%A7%80%EC%9C%84%EA%B7%B8&quot; target=&quot;_blank&quot;&gt;WYSIWYG&lt;/a&gt; 방식의 웹 에디터입니다.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/preview.gif&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;주요-기능&quot;&gt;주요 기능&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;워크스페이스에서 캘린더뷰로 프로모션을 열람하고 관리할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;텍스트, 이미지, YouTube, Lottie, 회전목마 등의 블록 단위로 화면을 구성하고 스타일링할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;그룹을 사용하여 복잡한 형태의 레이아웃을 만들 수 있습니다.&lt;/li&gt;
  &lt;li&gt;쿠폰 다운로드 코드를 생성하고 버튼에 연결할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;프로모션 화면에 사용될 이미지 등의 파일을 자동으로 S3에 업로드합니다.&lt;/li&gt;
  &lt;li&gt;베타와 운영 두 가지 배포를 재작업 없이 동시에 할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;배포 후 프로모션 URL을 제공합니다.&lt;/li&gt;
  &lt;li&gt;… 더욱 다양한 기능이 앞으로 계속 추가될 예정입니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;단순하고-직관적인-작업-빠른-결과&quot;&gt;단순하고 직관적인 작업, 빠른 결과&lt;/h2&gt;

&lt;p&gt;사용자에게 단순한 프로그램을 만들기 위해서 개발자는 복잡한 과정을 거쳐야합니다. 개발자가 편해지면 사용자가 불편해지기 마련입니다.&lt;/p&gt;

&lt;p&gt;만다오로 프로모션을 진행하는 과정은 매우 간단합니다. 화면을 구성하고 배포하면 끝. 많은 과정들이 생략되고 일일이 검증할 필요가 없어지죠. 지금까지 직접 했던 수작업들이 만다오에서는 자동으로 이루어집니다. 구성 작업이 끝나고 만다오에서 배포하면 최종적으로 이벤트 웹서버에 프로모션 앱을 구성하는 메타 정보가 저장됩니다.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/mandao-promotion-workflow.png&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;만다오-블록&quot;&gt;만다오 블록&lt;/h3&gt;

&lt;p&gt;만다오에서는 화면을 구성하는 요소 하나를 &lt;strong&gt;블록&lt;/strong&gt;이라고 부릅니다. 메타 정보에는 쿠폰 등의 프로모션 데이터뿐만 아니라 가장 중요한 화면을 구성하는 블록 데이터가 저장되는데요, 모든 블록은 동일하게 Base를 상속하며 크게 Container와 Container가 아닌 것 두 가지로 구분됩니다. Container는 다른 블록을 자식으로 가질 수 있는 블록이며 Container를 자식으로 가질 수도 있습니다.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/mandao-blocks-structure.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;프로모션 페이지 제작에 특화되었기 때문에 디자인 도구급의 자유도는 제공하지 않고 document flow에 따라 쌓이는 방식을 채택했습니다. 하지만 flex의 유연함 덕분에 Container를 중첩하여 이론상 모든 형태의 레이아웃을 만다오에서 만들 수 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;복잡한 사용성을 배제하고 진입 장벽을 낮추기 위해 현재는 한 단계까지만 에디터에서 지원합니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;만다오 블록은 DOM 구조와 매우 유사하지만 개발자가 아닌 사람들도 쉽게 사용하고 이해할 수 있게 캡슐화했으며 스타일은 CSS의 그것을 그대로 사용하지 않고 Web 이외의 환경에서도 렌더링할 수 있게 일반화했습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;회전목마&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;만다오 회전목마는 WYSIWYG 방식을 가장 잘 활용한 부분이라고 할 수 있습니다. 코드 작성이나 복잡한 설정 없이 회전목마를 손쉽게 구성할 수 있습니다.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/carousel.gif&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;YouTube&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;요즘 핫한 배민 선물하기를 비롯해 이벤트에 YouTube 영상을 자주 삽입하는데요, 만다오에서는 YouTube URL만 있으면 임베드 코드 생성부터 미리보기까지 한 번에 가능합니다.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/youtube.gif&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;숨겨진-또-하나의-만다오-만다오-러너&quot;&gt;숨겨진 또 하나의 만다오, 만다오 러너&lt;/h3&gt;

&lt;p&gt;만다오에서 배포 후 제공되는 URL을 통해 프로모션 화면을 바로 확인해볼 수 있는데요, 만다오 러너가 배포된 메타 정보를 읽어와 화면을 렌더링하고 쿠폰 다운로드 등의 로직을 실행하게 됩니다. 만다오 러너는 에디터에서 편집 기능을 모두 제거한 형태의 렌더러 버전이라고 볼 수 있습니다. 런타임 크기를 줄이기 위해 만다오 러너에서는 React가 아닌 Preact를 사용합니다.&lt;/p&gt;

&lt;h2 id=&quot;uiux&quot;&gt;UI/UX&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://blog.jhaemin.com/frontend-designer&quot; target=&quot;_blank&quot;&gt;모든 사람이 디자인을 해야 한다는 신념&lt;/a&gt;이 있고 웹프론트개발그룹에 디자이너가 없기도 해서 만다오를 최대한 아름답고 사용하기 쉽게 만들기 위해 신경 썼습니다. 사용자 경험을 고려할 때 팀원들과 민태님의 의견이 많은 도움이 되었습니다.&lt;/p&gt;

&lt;p&gt;모든 UI는 최소한의 형태로 유지됩니다. 필요할 때 모습이 나타나고 그렇지 않을 때 사라지죠. 평면처럼 보이지만 다들 저마다의 깊이를 가지고 있습니다. 사용자는 자연스럽게 각 UI의 계층 구조를 감각적으로 이해할 수 있습니다.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/tabs.gif&quot; /&gt;
  &lt;span style=&quot;display: block; color:#808080; margin-top: 10px;&quot;&gt;탭&lt;/span&gt;
&lt;/div&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/toolbar.gif&quot; /&gt;
  &lt;span style=&quot;display: block; color:#808080; margin-top: 10px;&quot;&gt;툴바&lt;/span&gt;
&lt;/div&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/dialog.gif&quot; /&gt;
  &lt;span style=&quot;display: block; color:#808080; margin-top: 10px;&quot;&gt;만다오 다이얼로그&lt;/span&gt;
&lt;/div&gt;

&lt;h3 id=&quot;만다오-핸들&quot;&gt;만다오 핸들&lt;/h3&gt;

&lt;p&gt;복잡한 DOM 구조를 WYSIWYG으로 편집할 때 좋은 사용자 경험을 제공하기 위해 많은 고민을 했습니다. 트리 형태로 중첩되는 HTML 특성상 각 계층간의 간격이 없으면 마우스 포인터로 요소를 선택하는 것은 불가능합니다. 트리의 깊이가 깊어질수록 상태는 더욱 심각해지죠. 이런 문제를 해결하기 위해 만다오 핸들을 디자인했습니다.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/handle.gif&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;만다오 핸들은 최소한의 UI로 전체적인 페이지의 형태를 유지하면서 각 요소를 선택할 수 있는 방법을 제공합니다. 핸들에 호버하면 요소의 이름을 힌팅하면서 어떤 영역이 선택될 지 보여줍니다. 미리보기 화면에서 핸들은 사라지며 온전한 페이지를 확인할 수 있습니다. 이 외에도 사용자 경험을 향상시키기 위해 많은 고민을 한 흔적들이 구석구석 숨어있고 앞으로 더욱 섬세하게 다듬어갈 예정입니다.&lt;/p&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/promotion-screenshots.png&quot; /&gt;
  &lt;span style=&quot;display: block; color:#808080; margin-top: 10px;&quot;&gt;그동안 배민앱을 이용하면서 지나쳤을 수 있는 다양한 프로모션이 만다오로 제작되었습니다.&lt;/span&gt;
&lt;/div&gt;

&lt;h2 id=&quot;마케터님들의-만다오-사용-후기&quot;&gt;마케터님들의 만다오 사용 후기&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;이다하 (배민마케팅팀)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;마케터가 기본적으로 따로 따로 하고 있던 쿠폰 업무, 이미지 업로드, 서버 배포 등의 캠페인 실행의 전 과정이 하나로 통합 되었다는 부분이 가장 좋았어요. 번거로운 일이 줄어드니까 일의 효율이 올라가고, 정말 필요한 일에 더 집중도 할 수 있게 되었습니다. 또 사용자의 편의를 생각한 UI 구성 덕분에 새로운 마케터가 와도 쉽게 적응할 수 있다는 점도 너무 좋습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;박지영 (배민마케팅팀)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;만다오는 마케터가 수동으로 하던 업무를 손쉽게 해결할수 있도록 해준다는 점에서 업무의 효율성에 많은 기여를 하고 있습니다. 직관적인 UI와 편리한 사용성도 좋지만, 저는 개인적으로 메인에 이벤트 일정을 한데 모아 보여주는 달력 지면이 참 좋았습니다.
프로모션이 날이 갈수록 많아지고 복잡해져서 과거 프로모션을 참고하거나, 지금 운영 중인 프로모션이 어떤 것이 있는지 한 번에 파악하기 어려웠는데 그 부분을 해소시켜주었어요. 추후에 만다오로 모든 프로모션 페이지를 만들게 된다면 누구든 만다오에 들어와서 이벤트 일정을 살필 수 있을 것 같아 더욱 기대가 됩니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;이동민 (배민마케팅팀)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;만다오가 있기 전에는 이벤트를 운영하는 데 시간이 많이 필요했습니다. 한정된 시간 중 마케터가 이벤트 기획을 하는 시간이 상대적으로 줄어들 수 밖에 없었는데요. 만다오가 이벤트 세팅과 운영 시간을 줄여 주니까 더 중요한 것에 집중할 수 있게 된 것 같습니다. 또한 유저에게 실제 어떻게 노출되는지를 만다오에서 미리 미리 확인할 수 있다는 점이 참 좋은 것 같아요! 만다오는 매주 업데이트가 되고 있는데요. 더 좋은 기능을 위해 노력해주시는 분들께 정말 감사드립니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;최혜영 (배민마케팅팀)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;만다오 덕분에 이벤트 페이지 노출까지 각기 따로 따로 진행했던 4~5개의 과정이 만다오 페이지 안에서 모두 가능해졌어요. 별개로 이벤트페이지 어드민 같은 딱딱한 이름이 아니라 만다오라는 귀여운 이름도 맘에 쏙 듭니다. 메인의 달력 지면에서 페이지별 미리보기가 가능한 것 뿐만 아니라 각 설정 복사, 디바이스 목업 미리보기, 배포 담당자 상세와 배포 시간 목록까지 이벤트 페이지 배포 자체의 본 기능 뿐만 아니라 직접 설정하고 운영하는 측면에서도 더욱 편의성을 살려주신 디테일에 감동했습니다. (최고에요)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;이수진 (배민마케팅팀, 만다오 팬)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;만다오를 처음 접했을 때 그야말로 ★신.세.계★였습니다. 그동안 이벤트 세팅을 위해 여러 프로그램 (Cyberduck, Filezilla, Jenkins…) 을 열고 닫기를 반복했습니다. 긴급하게 이벤트 수정을 하거나 세팅이 필요할 때도, 오랜 시간이 소요되어 민첩하게 대응하기 어려웠습니다.
하지만 이제는 만다오 덕분에 누구나 쉽고 빠르게 이벤트 세팅이 가능해졌고 업무 효율도 증대되었습니다. 이외 기종별 프리뷰, 캘린더, 복사하기 등과 같이 사용자를 배려해주신 섬세한 기능들은 늘 이용하면서 감동받고 있습니다. 만다오를 만들어주신 모든 분들께 진심으로 감사 인사를 드리며 앞으로도 잘 부탁드리겠습니다!!!!!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;마치며&quot;&gt;마치며&lt;/h2&gt;

&lt;p&gt;오래 전부터 에디터 개발에 대한 깊은 갈망이 있었는데요, 만다오를 만들며 해소가 되고 있습니다. 만다오는 이제 버전 &lt;strong&gt;1.0&lt;/strong&gt;으로 막 출발을 한 상태이며 앞으로 다양하고 재미있는 에디터 기능과 타 서비스와의 연동 계획이 많이 준비되어있으니 기대해주세요!&lt;/p&gt;

&lt;p&gt;&lt;del&gt;나중에 만다오로 만다오를 만들어ㅂ…&lt;/del&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;다음은-각각-만다오의-워크스페이스캘린더뷰와-인프라를-도맡아-개발해주신-이찬호님과-전은정님의-글입니다&quot;&gt;다음은 각각 만다오의 워크스페이스(캘린더뷰)와 인프라를 도맡아 개발해주신 이찬호님과 전은정님의 글입니다.&lt;/h3&gt;

&lt;h2 id=&quot;이찬호님의-글&quot;&gt;이찬호님의 글&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;우아한 형제들에 입사하기위해 진행한 우아한 테크캠프에서는 2개월동안 4개의 프로젝트를 진행했습니다. 프론트엔드 정수를 갈고 닦기 위해 진행하는 모든 프로젝트에서는 라이브러리 사용이 금지되었죠. 그 덕에 저희는 드래그앤 드롭, store를 위한 pub/sub 패턴, routing등을 직접 javascript로 구현하고, 화면에서 보여주는 모든 컴포넌트 디자인을 css로 해야했습니다.&lt;/li&gt;
  &lt;li&gt;이 과정을 거치고 입사한 신입개발자들이 처음 진행하게된 프로젝트가 만다오입니다. 어떤 기능을 구현하기 위해 이것과 비슷한 기능을 하는 잘 만들어진 라이브러리가 있는지 확인하기 전에 &lt;strong&gt;어떻게 하면 구현할 수 있을까&lt;/strong&gt;? 고민하기 시작했습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/timeline.png&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;타임라인-블럭-쌓기&quot;&gt;타임라인 블럭 쌓기&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;드디어 개발자로 입사하기위해 갈고 닦았던 알고리즘 실력을 보여줄 때가 됐습니다.&lt;/li&gt;
  &lt;li&gt;알고리즘 문제와 개발상황에서 문제를 해결하기 위한 알고리즘은 시작부터 달랐습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;text-align: center; margin: 50px 0;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-08/mandao/algorithm.png&quot; /&gt;
&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;(백준에 없는 문제입니다)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;이런식으로 문제를 명확하게 정의해주지 않고, 테스트케이스를 제공해주지도 않으며, 이 문제의 치명적인 엣지 케이스도 알려주지 않았습니다.&lt;/li&gt;
  &lt;li&gt;문제 정의부터 필요했습니다.
    &lt;ul&gt;
      &lt;li&gt;시간순으로 보여야 한다. 이벤트 시작시간 순으로, 시작시간이 같다면 끝나는 시간 순으로&lt;/li&gt;
      &lt;li&gt;겹치면 다음칸으로&lt;/li&gt;
      &lt;li&gt;최대 이벤트 개수는 몇 개가 될까? → 배민에서 평생동안 프로모션을 몇개 진행 할까? → 최대로 배치해야하는 블록의 개수가 몇개가 될까?&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Visit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 1.정렬&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;sortArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;blockList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 
&lt;span class=&quot;nx&quot;&gt;blockList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;c1&quot;&gt;// 2.예외 처리&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;endIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;timeLineFirstDateIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;startIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;timeLineEndDateIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
 
    &lt;span class=&quot;c1&quot;&gt;// 3.블록 배치&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Visit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;startIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Visit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Visit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;endIndex&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;newVisit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;endIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;문제는 거창했지만 코드는 간단하네요.&lt;/li&gt;
  &lt;li&gt;저는 블럭을 쌓기 위해 각 층의 상태를 나타내는 1차원 number배열인 visit을 선언하고, 모든 블럭을 돌면서 검사를 진행했습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
  &lt;li&gt;정렬입니다. 들어오는 블럭들을 시작시간순으로 정렬, 시작시간이 같다면 끝나는 시간으로 정렬 해줍니다.&lt;/li&gt;
  &lt;li&gt;예외처리입니다. 블럭들이 타임라인 밖으로 나간 경우입니다. 이런 블럭들은 타임라인에서 보여주지 않아야하므로 제외했습니다.&lt;/li&gt;
  &lt;li&gt;예외처리를 하고 남은 블록들은 새로 들어오는 블럭의 시작 index가 현재 층의 index보다 크거나 같으면 그 자리에 블록을 넣습니다. 블럭을 넣고 현재 층의 index를 넣은 블럭의 끝나는시간index로 바꿔주면 끝입니다.
    &lt;ul&gt;
      &lt;li&gt;만약 시작 index가 더 작다면 (겹치는 상황) 새로운 층에 블럭을 넣어줍니다&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
  &lt;li&gt;이렇게 타임라인에 블록은 예쁘게 쌓이게 됐습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;전은정님의-글&quot;&gt;전은정님의 글&lt;/h2&gt;

&lt;p&gt;안녕하세요!&lt;/p&gt;

&lt;p&gt;웹프론트개발그룹의 신입 개발자 전은정입니다. 개발자로의 전직을 희망한지 14개월차, 입사한지는 4개월차 🤣 에 불과한 꼬마 개발자이기에 &lt;del&gt;기술블로그이지만&lt;/del&gt; 기술적인 내용을 논하기엔 벅차다는 생각이 드네요. 입사 후 첫 프로젝트를 진행하며 느낀 점 위주의 회고를 풀어볼까 합니다.&lt;/p&gt;

&lt;h3 id=&quot;-웹프론트개발그룹-을-살짝-홍보합시다&quot;&gt;😇 웹프론트개발그룹 을 살짝 홍보합시다&lt;/h3&gt;

&lt;p&gt;일단 저는 우아한형제들에 소속된 대부분의 프론트엔드 개발자분들과는 달리 웹프론트개발그룹 에만 소속되어 있는데요, 여러 가지 역할 중에 하나가 공통 도구 개발이라고 할 수 있을 거 같아요.&lt;/p&gt;

&lt;p&gt;현업 개발자가 된 지 얼마 되지 않았긴 하지만 우형이 아니더라도 다양한 서비스의 최전선에서 개발을 하고 계신 분들은 하루하루 개발하고 처리해야 할 피처, 이슈, 버그 들이 가득하다고 알고 있어요.&lt;/p&gt;

&lt;p&gt;그런데 회사 차원에서는 꼭 불특정 다수의 고객을 마주하게 되는 서비스와 직접 연걸된 것은 아니더라도 프론트엔드 개발이 필요한 부분이 많이 있을거에요. 여러가지 이유로 우형에서는 서비스를 하는 팀에는 소속되지 않은 프론트엔드 개발자로 구성된 이러한 조직을 꾸리게 되었는데, 그 중 하나가 공통 도구 개발이고, 점차 디자인시스템 등으로 확장되어 갈 거 같아요.&lt;/p&gt;

&lt;h3 id=&quot;-백오피스-개발은-생각보다-훨씬-즐거운-거였어요&quot;&gt;🤩 백오피스 개발은 생각보다 훨씬 즐거운 거였어요&lt;/h3&gt;

&lt;p&gt;사실 저는 개발자를 준비하면서 서비스를 하는 회사에 가고 싶다는 생각만 갖고 있었지 백오피스 개발에 대해서는 특별히 관심을 가져본 적이 없었어요. 아는 건 쥐뿔도 업으면서 ‘백’오피스라고 하니 왠지 모르게 지루하고 무료하지 않을까 라는 막연하고 어리석은 생각만 가지고 있었던 거 같아요. 하지만 실제로 만다오 프로젝트를 진행하면서 이런 생각이 모두 뒤집히게 되었는데, 다음의 이유들이 큰 역할을 했다고 생각해요.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;서비스에 대한 니즈가 너무나 정확해&lt;/p&gt;

    &lt;p&gt;해민님이 배민 앱에서 프로모션 화면이 제작되는 기존의 방식을 소개해주었는데요, 처음 만다오 프로젝트를 시작하면서 꼬마 개발자로 가득한 우리 팀의 정신적, 기술적 지주인 민태님한테 이러한 상황을 공유받았을 때는 정말 충격 그 자체였던 거 같아요. 지금까지 수고해오신 디자이너와 마케터 분들이 존경스럽고 왠지 모르게 죄송한 마음이 들었어요.&lt;/p&gt;

    &lt;p&gt;제가 서비스의 일선에서 개발을 해본 적은 없지만 상상을 해본다면, 앱에 대한 후기로 니즈를 파악할 수도 있겠지만 대부분의 경우에는 고객들에게 이런 것이 필요할거야, 이런건 불편할 거 같아 라는 추측에 기반하게 되지 않을까 싶어요.&lt;/p&gt;

    &lt;p&gt;백오피스 서비스는 사용자 수가 많진 않아도 우리가 바로 옆에서 함께 하는 분들을 위한 서비스인만큼 현재의 상태가 어떤 불편함을 야기하고 있는지에 대한 명확한 인지가 가능해서인지 서비스에 대해 더욱 주체적으로 고민하는 개발자가 잠시라도 되어볼 수 있는 좋은 기회가 되었다고 생각해요.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;고객의 피드백이 바로 옆에서&lt;/p&gt;

    &lt;p&gt;만다오를 개발하면서 손에 꼽을만한 기억에 남는 순간 중 하나는 단연코 마케팅 팀에 만다오를 처음으로 시연했던 순간이라고 할 수 있어요 (오프라인으로 진행하지 못한 것이 천추의 한이에요). 당시에 만다오는 여전히 갈 길이 먼 상태였음에도 불구하고 마케터 분들의 반응은 가히 폭발적이었어요. 온라인 시연을 마친 후에 팀원들끼리 마케터와 개발자는 다른 종족이구나, 그들의 텐션은 저 세상에 있구나 하며 우스갯소리를 했었는데 딱히 틀린 말은 아니겠지만 그만큼 만다오에 대한 니즈가 넘치고 있었다는 반증이었구나 싶어요.&lt;/p&gt;

    &lt;p&gt;개발자를 꿈꾸며 자체 서비스를 하는 회사에 들어가고 싶다는 생각을 했던 이유 중에 하나가 고객의 생생한 피드백 에 있었는데, 이번 만다오 개발은 그보다 훨씬 더 선명하고 즉각적인 피드백을 전달받을 수 있는 행복한 기회였던 거 같아요.&lt;/p&gt;

    &lt;p&gt;( 열화와 같은 성원으로 개발 동력을 채워주신 마케팅 팀에 감사 인사드려요 🥰 )&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;서비스의 효과가 내 눈 앞에&lt;/p&gt;

    &lt;p&gt;만다오를 런칭한 뒤에 디자이너와 마케터 분들이 만다오를 통해 작업하는 상황을 저희는 가끔씩, 몰래몰래 지켜보곤 했어요. 누가 어떻게 사용하고 있고, 이전에는 어떤 문제가 있었는데 만다오를 통하니까 어떤 변화들이 있는지를 직접 보고 알 수 있으니까 너무나 뿌듯했어요.&lt;/p&gt;

    &lt;p&gt;사용자가 모두 같은 회사 식구들이다보니 편리하다는 감사 인사, 추가적인 요청, 우리 팀도 이용하고 싶다는 문의 등등이 팀장님을 통해 직접적으로 들려왔고, 저희도 모르는 사이에 새로운 프로모션이 만다오에 추가되어서 고객들을 맞이하고 있었어요.&lt;/p&gt;

    &lt;p&gt;우리의 결과물이 고객들을 잘 만족시키고 있는걸까? 에 대한 답이 직접적으로 확인이 된다니 말해 뭐해, 참말로 즐겁네요.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;-백오피스-개발은-즐거웠지만-인프라는-어려워-어디까지-퍼블릭하게-오픈되어도-되는지-모르겠다&quot;&gt;🤯 백오피스 개발은 즐거웠지만 인프라는 어려워 (어디까지 퍼블릭하게 오픈되어도 되는지 모르겠다)&lt;/h3&gt;

&lt;p&gt;입사 후 첫 프로젝트였던 백오피스 개발이 좋고 행복하고 즐거운 기회였다고 열심히 얘기했지만 쓴 맛도 그만큼 가득했던 것 또한 참트루입니다.&lt;/p&gt;

&lt;p&gt;만다오 핵심 역할이 몇 가지 있겠지만 그 중에서도 핵심은 ‘자동화’에 있다고 생각합니다. 베타/운영 환경에 따른 중복 업무를 제거하여 생산성를 올리고 오류 가능성을 줄이는 것이지요. 이는 보안을 위해 베타/운영 환경이 분리되어 있기 때문에 필연적으로 발생하는 이슈였습니다.&lt;/p&gt;

&lt;p&gt;만다오를 런칭하더라도 이 부분이 해결되지 않으면 결국 마케터 분들은 코드로부터 해방될 뿐, 같은 작업을 두 번 해야하는 운명은 피할 수 없는 것이었어요. 이를 해결하기 위해 인프라, 보안팀 등 어벤저스와 같은 여러 유관 부서와의 논의가 진행되었고, 만다오 서비스의 특성과 필요가 인정되어 새로운 인프라를 개척하기까지에 이르게 되었어요.&lt;/p&gt;

&lt;p&gt;이전까지는 사내 시스템이라고 해봐야 공통인증시스템을 사용해 본 것이 전부였는데, 아예 새로운 인프라를 구축하는 과정은 정말 신세계였어요. 신입 개발자인 저에게는 외계어를 엿들으며 역사적인 순간 (?) 의 산 증인이 되는 좋은 기회가 되었어요. AMI, Security Group, 다양한 권한 설정 등 이번 기회가 아니었으면 최소 몇 달 간은 존재의 여부도 모르고 관심도 갖지 않았을 여러 개념들을 접하게 되었습니다. 언젠가는 제가 이런 것들을 설명할 수 있는 그 날이 오면 좋겠어요.&lt;/p&gt;

&lt;p&gt;하지만 어벤저스와 같은 유관 부서의 지원에도 불구하고 인프라 이슈는 런칭 전 날까지 이어졌는데요. 우아한 테크캠프의 커다란 교훈, ‘배포를 미리, 자주 하자’ 를 뼛 속 깊이 새기게 되었습니다. 배포를 계속 실패하다가 드디어 성공! 하고 나면 서비스의 이쪽에서 문제가 터지고, 해결! 집에 가자 하면 저쪽이 부서지고, 도장깨기를 하며 하마터면 밤을 지새울 뻔 했습니다. 정말 많은 분들이 도움을 주셨지만 그 중에서도 특히 밤 늦게 까지 도움주신 채용님께 감사 인사를 전하고 싶습니다..&lt;/p&gt;

&lt;h3 id=&quot;-만다오는-아직까지-순항중&quot;&gt;🎊 만다오는 아직까지 순항중&lt;/h3&gt;

&lt;p&gt;만다오를 런칭한 지 이제 겨우 일주일 째입니다. 아직까지는 순항하고 있네요. 런칭하는 날에 모니터링보드를 십수번씩 드나들었던 것을 생각하면 이제 정신 건강도 잘 지켜지고 있습니다.&lt;/p&gt;

&lt;p&gt;첫 프로젝트 시작의 설렘부터 기쁨, 고난과 역경, 런칭 전후의 초조함까지 4개월이 안되는 시간동안 개발자로서의 한 사이클을 진하게 경험한 기분이 들어요. 먼 훗날 이 글과 만다오 소스코드를 보며 이불킥 할 날이 오겠지만 지금은 일단 기쁘고 뿌듯한 마음만 가지고 앞으로도 만다오가 열심히 일 해 주기를 바랄 뿐입니다.&lt;/p&gt;
</description>
        <pubDate>Mon, 08 Mar 2021 09:30:00 +0900</pubDate>
        <link>https://woowabros.github.io/woowabros/2021/03/08/mandao.html</link>
        <guid isPermaLink="true">https://woowabros.github.io/woowabros/2021/03/08/mandao.html</guid>
        
        
        <category>woowabros</category>
        
      </item>
    
      <item>
        <title>검색을 위한 데이터 다루기</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;안녕하세요. 우아한형제들 검색개발팀 정철입니다.&lt;/p&gt;

&lt;/blockquote&gt;

&lt;p&gt;배달의민족 검색시스템에서 검색에 사용되는 데이터를 적재하면서 경험했던 어려움과 해결했던 방법을 공유하고자 합니다.&lt;/p&gt;

&lt;h2 id=&quot;검색시스템이란&quot;&gt;검색시스템이란?&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;먹고 싶은 음식을 찾는 첫 단계&lt;/code&gt; &lt;br /&gt;
배달의민족에서 검색시스템은 주문하고 싶은 가게 또는 메뉴를 빠르게 찾을 수 있도록 도와주는 여러 기능을 개발하고 있습니다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;검색 기능&lt;/li&gt;
  &lt;li&gt;인기검색어&lt;/li&gt;
  &lt;li&gt;1인분, 채식 등의 테마 지면 리스팅&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;배달 빠른 순, 배달팁 낮은 순&lt;/code&gt;과 같은 정렬과 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;최소주문금액, 쿠폰, 예약&lt;/code&gt;등의 필터 기능&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-03/s1.jpg&quot; /&gt; &lt;span style=&quot;display: block; color:#808080;&quot;&gt;검색개발팀이 제공하는 서비스&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;단순하다고 생각될 수 있는 시스템이지만 실시간으로 가게에 대한 정보를 동기화하기 위해서 십여개의 외부시스템으로부터 실시간 정보를 저장해야 하며, 시간, 위치를 기반으로 복잡한 수식으로 가게의 여러정보를 계산해야하는 복잡한 시스템입니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;추가되는-서비스-늘어나는-과부하&quot;&gt;추가되는 서비스, 늘어나는 과부하&lt;/h2&gt;
&lt;p&gt;검색시스템은 위의 소개했던 것과 같은 서비스를 제공하기 위해서 광고, 메뉴, 리뷰, 통계… 등 십여 개의 데이터를 aws의 SQS를 사용하여 수신하고 이를 검색엔진 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Elasticseach&lt;/code&gt;에 저장하고 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-03/s2.jpg&quot; /&gt;&lt;span style=&quot;display: block; color:#808080;&quot;&gt;데이터 수신 구조&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
초기 시스템 설계 시 들어오는 데이터의 양이 그렇게 많지 않았고 예측 가능했기 때문에 개별적으로 들어오는 이벤트를 건바이건으로 update request를 만들어서 반영하였습니다.&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 가게 이벤트 수신&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@SqsListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;shopSqs&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deletionPolicy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NEVER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tagsUpdateListen&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@Payload&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShopChangeEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shopChangeEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acknowledgment&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acknowledgment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;shopElasticsearch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createUpdateRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shopChangeEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 리뷰 이벤트 수신&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@SqsListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;reviewSqs&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deletionPolicy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NEVER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tagsUpdateListen&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@Payload&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ReviewChangeEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reviewChangeEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acknowledgment&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acknowledgment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;shopElasticsearch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createUpdateRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reviewChangeEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;baemin-search/_update/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1234567&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;doc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;shopName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;배민의 맛집가게&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;송파구 방이동 44-2&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;하지만 가게가 증가함에 따라 가게가 오픈하는 시간대나 주문이 많아서 메뉴 품절 등의 상황이 많이 발생하는 경우에는 이벤트를 많이 수신하게 되었고 그에 따라 모든 부담이 Elasticsearch에 집중되면서 Elasticsearch Writer Thread Pool이 가득 차서 request가 rejected 되는 문제와 Disk I/O 문제로 cpu 수치가 기하급수적으로 상승하는 문제가 발생하였습니다.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;이런 상황 속에 현재 상태를 유지하기도 어려워졌고 더불어 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;배달 빠른 순, 배달팁 낮은 순&lt;/code&gt;정렬/필터와 같이 사용자에게 편의를 줄 수 있는 여러 feature를 저희 시스템 문제로 개발이 지연되는 문제가 발생하였습니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;원인-분석&quot;&gt;원인 분석&lt;/h2&gt;
&lt;h3 id=&quot;문제-1-잦은-변경에-의한-disk-io-이슈&quot;&gt;문제 1. 잦은 변경에 의한 Disk I/O 이슈&lt;/h3&gt;
&lt;p&gt;Elasticsearch의 Index는 Lucene 기반의 작은 segment 파일로 구성되어 있습니다. 이 segment는 검색 요청을 빠르게 처리하기 위해서 여러 개로 생성이 되어있습니다. 하지만 이 segment는 속도, 성능, 동시성 이슈, 압축 등의 이유로 immutable 한 속성을 가지고 있기 때문에 Index에 대한 업데이트 요청이 오게 되면 기존 segment에 mark만 하고 새로운 segment를 생성하여 데이터를 기록하는 동작을 진행합니다.&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-03/s3.jpg&quot; /&gt;&lt;span style=&quot;display: block; color:#808080;&quot;&gt;이미지 출처 구글&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;저희에 문제는 바로 여기에 있었습니다. 잦은 업데이트로 인해 다량의 segment가 생성되면서 Disk I/O가 증가하게 되었고 그 결과 cpu가 동반 상승했으며, 삭제 대상 segment를 지우고 단편화 해소를 위해 동작하는 force merge 시에도 부하가 발생하는 문제가 확인되었습니다. &lt;br /&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-03/s4.jpg&quot; /&gt;&lt;span style=&quot;display: block; color:#808080;&quot;&gt;문제의 cpu 상태&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;문제-2-건바이건-요청으로-인한-thread-pool-초과&quot;&gt;문제 2. 건바이건 요청으로 인한 thread pool 초과&lt;/h3&gt;
&lt;p&gt;가게에 해당하는 속성 변경 이벤트가 몰리는 시간대에는 최대 수십만 건 이상의 이벤트가 발생합니다. 이 이벤트를 건바이건으로 업데이트를 하면서 Elasticsearch의 write thread pool을 모두 점유하고 queue까지 가득 차게 되면서 일부 이벤트가 정상적으로 업데이트 되지 못하고 rejected 되는 경우가 빈번하게 발생하였습니다.&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-03/s5.jpg&quot; /&gt;&lt;span style=&quot;display: block; color:#808080;&quot;&gt;rejected request 개수&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;정답은-언제나-기본에-있다&quot;&gt;정답은 언제나 기본에 있다&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;To optimize insert speed, combine many small operations into a single large operation. Ideally, you make a single connection, send the data for many new rows at once, and delay all index updates and consistency checking until the very end.&lt;br /&gt;
출처 : https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html&lt;/p&gt;

  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;insert 성능을 높이기 위해서는 작은 여러 연산을 큰 하나의 연산으로 만들어라.&lt;/code&gt; 라는 말을 위의 mysql doc에서 볼 수 있듯이 그렇게 배웠고 그렇게 개발을 진행했었습니다.&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Elasticsearch 또한 같은 개념을 가지고 있으며 단건 request 수행 보다 Bulk request의 효능이 큰 것은 여러 벤치마킹을 통해서도 입증이 되었습니다.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;그럼 우리도 이 문제를 해결하기 위해 bulk로 동작을 시키는 방법을 적용해보기로 했습니다. 하지만 언제나 문제는 쉽게 해결되지 않듯이 역시 문제가 있었습니다.
검색의 현재 구조는 모든 이벤트를 별도의 sqs를 listen 하여 받고 있기 때문에 서로 다른 sqs에서 데이터를 받아서 처리하기에는 무리가 있었습니다.&lt;/p&gt;

&lt;p&gt;그러다 Elasticsearch의 resthighlevelclient java api에서 &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-docs-bulk-processor.html&quot;&gt;Bulk processor&lt;/a&gt; 라는 기능을 사용하여 request를 모아서 업데이트하는 기능을 발견하게 되었습니다.
Bulk Processor는 하나의 독립적인 프로세스를 실행시키고 request를 buffer에 모아서 정해진 시간, 크기 등에 맞게 Elasticsearch에 데이터를 Bulk request를 만들어서 flush하도록 동작하고 있습니다.&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-03/s6.jpg&quot; /&gt;&lt;span style=&quot;display: block; color:#808080;&quot;&gt;Bulk processor 구조&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;이걸 사용해서 저희의 문제를 풀어보기로 했으며 있는 그대로 사용하지 않고 조금 더 나은 성능을 만들기 위해 튜닝도 함께 진행했습니다.&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;튜닝-1&quot;&gt;튜닝 1.&lt;/h3&gt;
&lt;p&gt;기존 Bulk processor는 DocWriteRequest를 담는 List를 가지고 있는 BulkRequest라는 Buffer용 객체를 사용하여 데이터를 담고 시간, 사이즈 등의 flush 타이밍이 되면 해당 버퍼를 BulkProcessorHandler를 통해 전달하고 Elasticsearch에 Bulk request를 요청하는 구조로 되어있습니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// BulkRequest (Buffer 역할을 하는 객체)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BulkRequest&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ActionRequest&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CompositeIndicesRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WriteRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BulkRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;REQUEST_OVERHEAD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * Requests that are part of this request. It is only possible to add things that are both {@link ActionRequest}s and
     * {@link WriteRequest}s to this but java doesn't support syntax to declare that everything in the array has both types so we declare
     * the one with the least casts.
     */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DocWriteRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ArrayList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * Adds a list of requests to be executed. Either index or delete requests.
     */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BulkRequest&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DocWriteRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DocWriteRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// BufferProcessor add메소드를 통해 BulkRequest에 request를 만들어서 담는 부분&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bulkProcessor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IndexRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;twitter&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;_doc&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* your doc here */&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bulkProcessor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DeleteRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;twitter&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;_doc&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// BulkProcessor Handler&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BulkRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bulkRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executionId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Runnable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toRelease&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{};&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bulkRequestSetupSuccessful&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;listener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;beforeBulk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executionId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bulkRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;acquire&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;toRelease&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;semaphore:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;CountDownLatch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;latch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CountDownLatch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;withBackoff&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bulkRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ActionListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BulkResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;onResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BulkResponse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;listener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;afterBulk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executionId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bulkRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;latch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;countDown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;onFailure&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;listener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;afterBulk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executionId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bulkRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;latch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;countDown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bulkRequestSetupSuccessful&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concurrentRequests&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;latch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;InterruptedException&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;currentThread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;interrupt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ParameterizedMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Bulk request {} has been cancelled.&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executionId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;listener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;afterBulk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executionId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bulkRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ParameterizedMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Failed to execute bulk request {}.&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executionId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;listener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;afterBulk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executionId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bulkRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bulkRequestSetupSuccessful&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// if we fail on client.bulk() release the semaphore&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;toRelease&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;저희는 이 부분에서 수신한 이벤트를 Bulk processor에 add 할 때 Update request를 만들어서 buffer에 밀어 넣는 부분이 번거로웠고 같은 index에 동일한 Update Request 규칙을 만들때도 모든 이벤트 수신부분에 일괄 적용하기 어려웠습니다. 그래서 buffer 역할을 하는 BulkRequest를 걷어내고 Update Request를 만들기 위한 Shop이라는 객체를 만들고 이 객체들을 담을 수 있는 Map으로 대체하였습니다&lt;br /&gt;&lt;br /&gt; 
각 이벤트 수신위치에서는 Bulk Processor에 add 할 때 각 이벤트별 변경 부분만 전달할 수 있도록 별도의 객체(ShopMenu, ShopReview..)들을 구성하였고, 이 값들을 전달받은 Bulk processor는 Shop객체로 전환하여 buffer에 저장을 하도록 구성하였습니다.(&lt;span style=&quot;color: red; weight: bold;&quot;&gt;이 부분 코드 및 활용은 튜닝2에서 다룰 예정&lt;/span&gt;) 그리고 별도의 serializer 정책을 적용해서 flush 주기에 BulkProcessorHandler에 데이터를 전달하여 필요한 부분만 업데이트 될 수 있도록 BulkRequest를 생성하는 등의 작업을 진행하였습니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Bulk processor 도입으로 인한 효과를 이론적으로 생각했던 부분이었고 테스트를 통해 검증도 해봤지만 실제 운영에서도 어느 정도 효과가 발생될지 궁금했었습니다. 기대감을 가지고 운영에서 확인해봤습니다.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;운영 데이터 기준 이벤트 수신 건수는 총 &lt;em&gt;9,261,187개&lt;/em&gt; 였습니다.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Bulk processor 도입전에는 모든 이벤트를 단건으로 처리하였기 때문에 총 update request는 이벤트 수신건수와 동일하게 9,261,185개 였습니다.&lt;br /&gt;
Bulk processor 도입후에는 update request를 모아 Bulk request를 만들면서 request건수는 233,949건 발생하였습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;도입 전 : 9,261,185건&lt;br /&gt;
도입 후 : 233,949건&lt;/p&gt;

&lt;/blockquote&gt;

&lt;p&gt;Elasticsearch에 요청하는 request 건수가 &lt;span style=&quot;color:#d23c3c; font-weight:700&quot;&gt; 총 97.5% &lt;/span&gt; 감소하였습니다.
이로 인해 write thread pool 감소로 많은 이벤트 수신 시 발생하던 rejected가 해소되었고, bulk로 단일 요청 대비 응답 대기 시간 및 네트워크 부하 감소 효과를 받았습니다.&lt;/p&gt;

&lt;h3 id=&quot;튜닝-2&quot;&gt;튜닝 2.&lt;/h3&gt;
&lt;p&gt;튜닝 1에서 얻은 효과도 좋았지만 조금 더 성능을 올려보고 싶었습니다. Bulk request가 single request보다 효능은 있지만 Bulk의 사이즈가 커질수록 오히려 Elasticsearch에 부담을 줄 수 있기 때문에 Bulk에 담기는 request를 더 줄여보고 싶었습니다.&lt;/p&gt;

&lt;p&gt;데이터를 가만히 보니 검색에서 사용하는 모든 데이터는 shopId를 기준으로 업데이트 쿼리가 만들어졌습니다. 그럼 request를 add 하는 순간에 동일한 가게에 대한 request가 존재하면 변경되는 부분만 기존 request에 넣어주면 되겠다는 생각을 가지게 되었습니다.&lt;br /&gt;&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-03/s11.jpg&quot; /&gt; &lt;span style=&quot;display: block; color:#808080;&quot;&gt;가게 중심으로 request 단일화 과정&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;그래서 다음과 같이 Bulk processor에 buffer역할을 하는 map의 키를 shopId로 부여하고 value를 Shop 객체로 부여를 하였고 각 이벤트를 통해 들어오는 요청을 하나의 Shop으로 묶어서 Bulk request를 만들도록 진행하였습니다.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;실제&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;코드는&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;더&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;복잡하여&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;예시&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;코드를&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;기재합니다&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * data는 유연하게 받을 수 있도록 제네릭을 사용하였고, 실제 검색에서는 Shop객체를 받고 있다.
 * acknowledgments는 수신된 이벤트들에 대한 정상 처리 여부에 따라 sqs에 ack 처리를 하기 위해 보관  
*/&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Getter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Setter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BulkData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IndexDomain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Acknowledgment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acknowledgments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Builder&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BulkData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Acknowledgment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acknowledgments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;acknowledgments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acknowledgments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Getter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Setter&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Shop&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IndexDomain&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Menu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;menus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;nd&quot;&gt;@Builder&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Menu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;menus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;shopNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;menus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;menus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;subject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 이벤트 변경정보를 가지는 객체의 공통 추상 클래스&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShopUpdatableDomain&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UpdatableDomain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Shop&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Shop&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 메뉴 변경정보를 가지고 있는 ShopMenu&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Getter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Setter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@NoArguments&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShopMenu&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShopUpdatableDomain&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Menu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;menus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;nd&quot;&gt;@Builder&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShopMenu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Menu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;menus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;shopNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;menus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;menus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Shop&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setShopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setMenus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;menus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 리뷰 변경정보를 가지고 있는 ShopReview&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Getter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Setter&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@NoArguments&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShopReview&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShopUpdatableDomain&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Builder&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShopReview&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;shopNumber&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;subject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Shop&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setShopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setContent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;shop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setSubject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 이벤트 수신과 Bulk processor에 이벤트 내용 전달&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@SqsListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;menu-sqs&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deletionPolicy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NEVER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;shopMenuV3UpdateListen&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@Payload&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ShopMenuEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eventDto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acknowledgment&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acknowledgment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bulkProcessor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BulkProcessorBucket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ShopMenu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ShopMenu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventDto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getShopId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;menus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventDto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMenus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@SqsListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;reviewSqs&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deletionPolicy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NEVER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tagsUpdateListen&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@Payload&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ReviewChangeEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reviewChangeEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acknowledgment&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acknowledgment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bulkProcessor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BulkProcessorBucket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ShopReview&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ShopReview&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;shopNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventDto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getShopId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventDto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventDto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getSubject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;// bulk processor add 코드&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Slf4j&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BulkProcessor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;S&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IndexDomain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Closeable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BulkData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datas&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;synchronized&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BulkProcessorBucket&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;idValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// bulk buffer안에 동일한 가게가 존재하는지 조회&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;datas&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;containsKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;BulkData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bulkData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;datas&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            
            &lt;span class=&quot;c1&quot;&gt;// 들어온 이벤트 데이터를 기존 shop 변경분 정보의 매핑&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bulkData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;datas&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BulkData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
해당 튜닝 포인트도 효과가 있었습니다. Bulk request를 만들어서 flush하는 주기에 같은 가게 아이디로 묶이는 이벤트 종류별 건수와 횟수에 대한 정보는 아래와 같이 적지 않은 수치를 볼 수 있었으며 실제로 이에 대한 효과도 볼 수 있었습니다.&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-03/s7.jpg&quot; /&gt;&lt;span style=&quot;display: block; color:#c2b4b4;&quot;&gt; request 군집 지표&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;성능-테스트-및-실제-운영-리소스-변화&quot;&gt;성능 테스트 및 실제 운영 리소스 변화&lt;/h2&gt;
&lt;h3 id=&quot;성능테스트-결과&quot;&gt;성능테스트 결과&lt;/h3&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-03/s8.jpg&quot; /&gt;&lt;span style=&quot;display: block; color:#c2b4b4;&quot;&gt; 27만건 무작위 이벤트 테스트 결과&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;27만 건의 데이터를 무작위로 전송했고 리소스 변화량을 체크해봤습니다.
CPU 사용량은 15% 이상 감소되었고 request 단위가 작아지면서 write complete 수도 30배 정도 감소하는 효과를 얻었습니다.&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;운영-결과&quot;&gt;운영 결과&lt;/h3&gt;
&lt;p&gt;실제 운영에 적용 결과 위의 처음 문제가 발생하던 시기에 피크시간 기준 61%를 육박하던 cpu가 비교 대상 기준 이벤트가 수십만건이 더 추가되었음에도 불구하고 최대 29%정도의 안정적인 상태를 유지하고 있습니다.&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;/img/2021-03-03/s10.jpg&quot; /&gt; &lt;span style=&quot;display: block; color:#c2b4b4;&quot;&gt;안정된 시스템&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;이 문제 해결로 배달 빠른 순, 배달팁 낮은 순과 같이 실시간성 데이터가 들어가야하는 서비스가 적용될 수 있었고 고객에게 더 좋은 가치를 드리는게 가능해졌습니다.&lt;/p&gt;

&lt;p&gt;2021년에는 검색창이 하단으로 옮겨지고 인기 검색어 지면 등 많은 기능들이 추가되고 있습니다. 이 글을 읽고 모든 코드를 보고 싶거나, 검색개발팀에 관심이 생겼다면 &lt;a href=&quot;https://resume.woowahan.com/jobs/view.aspx?cc=244001&amp;amp;jidx=105376&amp;amp;pidx=10893&amp;amp;bidx=166014&quot;&gt;[배민서비스실] 검색서비스 개발자 모집&lt;/a&gt; 에 많은 지원 부탁드립니다.&lt;/p&gt;

&lt;p&gt;긴 글 읽어주셔서 감사드립니다.&lt;/p&gt;
</description>
        <pubDate>Tue, 02 Mar 2021 09:30:00 +0900</pubDate>
        <link>https://woowabros.github.io/woowabros/2021/03/02/search-system.html</link>
        <guid isPermaLink="true">https://woowabros.github.io/woowabros/2021/03/02/search-system.html</guid>
        
        
        <category>woowabros</category>
        
      </item>
    
  </channel>
</rss>