<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>영감을 (inspire) 주고픈 개발 블로그</title>
    <link>https://inspire12.tistory.com/</link>
    <description>프로그래밍, 프로그래머, 백엔드, 풀스택,주식,생각, 경험, 아토피 치료</description>
    <language>ko</language>
    <pubDate>Wed, 26 Aug 2026 08:02:04 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>inspire12</managingEditor>
    <image>
      <title>영감을 (inspire) 주고픈 개발 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/2290173/attach/42d0e6ee0dcf4d4189e0fcb879c30475</url>
      <link>https://inspire12.tistory.com</link>
    </image>
    <item>
      <title>오늘의 읽기: 토스에서 일하며 깨달은 성장과 리더십</title>
      <link>https://inspire12.tistory.com/497</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Preview&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://evan-moon.github.io/2022/05/07/toss-retrospective/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://evan-moon.github.io/2022/05/07/toss-retrospective/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786276578746&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;토스에서 일하며 깨달은 성장과 리더십&quot; data-og-description=&quot;이번 포스팅에서는 필자가 지난 2년 반 동안 몸 담았던 직장인 토스에서 경험하고 느꼈던 것들에 대해서 한번 편하게 적어보려고 한다. 사실 토스에서의 퇴사는 이미 3월에 진행했지만, 그 동안 &quot; data-og-host=&quot;evan-moon.github.io&quot; data-og-source-url=&quot;https://evan-moon.github.io/2022/05/07/toss-retrospective/&quot; data-og-url=&quot;https://evan-moon.github.io/2022/05/07/toss-retrospective/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/erH8fX/dJMb9cBXo3G/fZKYeyI7xUiK4PGDA5kVD0/img.jpg?width=320&amp;amp;height=320&amp;amp;face=0_0_320_320,https://scrap.kakaocdn.net/dn/jKc2n/dJMb8PGLR4y/UHcrAGMvFsxRUNhXlf1Yi1/img.jpg?width=320&amp;amp;height=320&amp;amp;face=0_0_320_320,https://scrap.kakaocdn.net/dn/kbC8F/dJMb8XkvduD/LKxkdI8WGyPqAQK8Nsmz5K/img.jpg?width=546&amp;amp;height=573&amp;amp;face=0_0_546_573&quot;&gt;&lt;a href=&quot;https://evan-moon.github.io/2022/05/07/toss-retrospective/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://evan-moon.github.io/2022/05/07/toss-retrospective/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/erH8fX/dJMb9cBXo3G/fZKYeyI7xUiK4PGDA5kVD0/img.jpg?width=320&amp;amp;height=320&amp;amp;face=0_0_320_320,https://scrap.kakaocdn.net/dn/jKc2n/dJMb8PGLR4y/UHcrAGMvFsxRUNhXlf1Yi1/img.jpg?width=320&amp;amp;height=320&amp;amp;face=0_0_320_320,https://scrap.kakaocdn.net/dn/kbC8F/dJMb8XkvduD/LKxkdI8WGyPqAQK8Nsmz5K/img.jpg?width=546&amp;amp;height=573&amp;amp;face=0_0_546_573');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;토스에서 일하며 깨달은 성장과 리더십&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 필자가 지난 2년 반 동안 몸 담았던 직장인 토스에서 경험하고 느꼈던 것들에 대해서 한번 편하게 적어보려고 한다. 사실 토스에서의 퇴사는 이미 3월에 진행했지만, 그 동안&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;evan-moon.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글은 2022년에 쓰여진 글입니다. 하지만 글에 나온 가치는 저한테 꽤나 큰 감명을 주었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추천 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토스가 어떻게 그렇게 빠르게 일을 할 수 있는지에 대해 개개인의 최종 의사결정권자(DRI)를 얼마나 중시하는지에 대한 내용을 보면서 &quot;주인 의식을 가지고 재밌게 일할 수 있는 환경이구나&quot; 라는 생각을 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문화가 제대로 잡혀 있지 않은 환경에서 주인 의식을 가지고 일을 하다보면 흔히 &quot;현타&quot;를 느끼기 쉽습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://brunch.co.kr/@javajigi/63&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;잘될 때는 모두가 공을 나눠같지만 안되었을 때는 가장 앞 서서 이야기한 사람(주체적으로 일한 사람)이 질타를 받는 경우가 많거든요&amp;nbsp;&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1786279922409&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;문화는 직선으로 나아가지 않는다&quot; data-og-description=&quot;작년 주식 시장이 서서히 오르기 시작할 때, 이광수라는 분을 지켜보고 있었다. 처음 알게 된 건 김어준의 겸손은힘들다 뉴스공장을 통해서였다. 회사를 갑작스럽게 그만두게 된 배경, 부동산과&quot; data-og-host=&quot;brunch.co.kr&quot; data-og-source-url=&quot;https://brunch.co.kr/@javajigi/63&quot; data-og-url=&quot;https://brunch.co.kr/@javajigi/63&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/SYjcB/dJMb8UafwkG/lMyP9rxuURec2lGLh3ieLK/img.jpg?width=1280&amp;amp;height=317&amp;amp;face=0_0_1280_317,https://scrap.kakaocdn.net/dn/O9sm8/dJMb8QMrTAp/ShTpJlAKBOupFyO354ptf1/img.jpg?width=1280&amp;amp;height=317&amp;amp;face=0_0_1280_317&quot;&gt;&lt;a href=&quot;https://brunch.co.kr/@javajigi/63&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://brunch.co.kr/@javajigi/63&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/SYjcB/dJMb8UafwkG/lMyP9rxuURec2lGLh3ieLK/img.jpg?width=1280&amp;amp;height=317&amp;amp;face=0_0_1280_317,https://scrap.kakaocdn.net/dn/O9sm8/dJMb8QMrTAp/ShTpJlAKBOupFyO354ptf1/img.jpg?width=1280&amp;amp;height=317&amp;amp;face=0_0_1280_317');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;문화는 직선으로 나아가지 않는다&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;작년 주식 시장이 서서히 오르기 시작할 때, 이광수라는 분을 지켜보고 있었다. 처음 알게 된 건 김어준의 겸손은힘들다 뉴스공장을 통해서였다. 회사를 갑작스럽게 그만두게 된 배경, 부동산과&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;brunch.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사 창업자의 경우 자기의 의견을 관철 시키려는 경우가 많은데 이런 조직은 초반에는 빠르게 성장할 수 있지만, 규모가 커져 창업자가 모든 걸 케어할 수 없는 순간이 오면 더 이상 성장할 수 없습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토스는 개개인의 결정을 존중하고 책임을 가지는 환경입니다. 그러면서도 실수에 관대한 문화라는 것도 놀라웠습니다. 무엇을 하겠다하는 것과 책임을 진다는 건 실패도 온전히 감내하는 것이 일반적이거든요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실패를 두려워하지 않고 새로운 시도를 할 수 있는 환경은 자칫하면 폐업까지도 갈 수 있는 스타트업의 환경 상 쉽지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 스타트업에 있을 때 &lt;b&gt;실패했다는 사실 자체가 아니라 실패에서 무엇을 배웠는지 인지&lt;/b&gt;하고 이 &lt;b&gt;실패를 다른 사람들에게 공유&lt;/b&gt;하는 시도가 부족했다고 느꼈습니다. 지표는 떨어지고 있고 이전에 시도했던 것들과 담당자들이 나가면서 목적을 잃고 배회하고 다듬어지지 않은 상태로 남겨진 상태를 많이 느꼈습니다. 글에도 나왔듯이 실패를 장려하기 보다 실패를 경질하는 문화를 더 많이 경험해서 그런 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;단순히 누군가 실패를 경험했을 때 그를 비난하지 않는 것이 아니라, 그보다 적극적인 액션들이 함께 동반되어야한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문장도 크게 공감되었습니다. 비난을 안 한다해도 그 사람은 소극적이 될 수 밖에 없습니다. 오히려 서로 도와주고 발전하려는 모습이 있어야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽으면서 토스는 각 개인이 실력자들이 빛을 보는 환경이라고 느꼈습니다. 실제로 그렇고요. 그러던 토스가 신입 개발자를 뽑기 시작하며 현재 실력보다 잠재력을 보고 뽑은 &quot;주니어 개발자&quot;라는 페르소나가 생기며 조직이 달라진 것도 인상 깊었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주니어 개발자들이 문화에 적응하지 못하는 모습과 그들을 위해 새로운 문화를 만들고 받아들이는 부분도 꽤나 현실적으로 들렸습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 또한 조직이 성장하면서 겪어야하는 문화의 변화니까요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글을 보면서 토스에서 일하고 싶다는 생각이 들었습니다. 저도 주도적으로 일하고 싶다는 생각을 많이 하고 싶고, 그런 환경에서 더 몰입을 할 수 있었거든요. 하지만, 또 하나 링크를 건 자바지기 박재성님의 글처럼 그런 환경은 혼자서만 만들 수는 없던 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문화를 만드는 건 매니저의 역할과 설득이 필요하다고 생각이듭니다.&amp;nbsp;&lt;/p&gt;</description>
      <category>후기 /컴퓨터 관련 책</category>
      <author>inspire12</author>
      <guid isPermaLink="true">https://inspire12.tistory.com/497</guid>
      <comments>https://inspire12.tistory.com/497#entry497comment</comments>
      <pubDate>Sun, 9 Aug 2026 22:55:50 +0900</pubDate>
    </item>
    <item>
      <title>오늘의 읽기: 동일성은 왜 프로그래밍에서 가장 어려운 문제인가</title>
      <link>https://inspire12.tistory.com/493</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Preview: 원글&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://evan-moon.github.io/2026/08/02/why-identity-is-hard-in-programming/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://evan-moon.github.io/2026/08/02/why-identity-is-hard-in-programming/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1785744201316&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;동일성은 왜 프로그래밍에서 가장 어려운 문제인가&quot; data-og-description=&quot;얼마 전 JEP 401, 그러니까 자바의 가 OpenJDK master에 머지됐다는 소식을 봤다. 쉽게 말해 메모리 주소나 식별자(ID) 대신 객체 내부의 값 자체를 기준으로 삼는, 즉 값(Value)처럼 동작하는 객체 타입을&quot; data-og-host=&quot;evan-moon.github.io&quot; data-og-source-url=&quot;https://evan-moon.github.io/2026/08/02/why-identity-is-hard-in-programming/&quot; data-og-url=&quot;https://evan-moon.github.io/2026/08/02/why-identity-is-hard-in-programming/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dqNk6C/dJMb9dHCVfj/5TDuKKw2eXTIEdOaZz1RZK/img.png?width=320&amp;amp;height=320&amp;amp;face=0_0_320_320,https://scrap.kakaocdn.net/dn/bhJPzv/dJMb9kmq9aO/5Ouyq7F7ci0w4K0kSt7a51/img.png?width=320&amp;amp;height=320&amp;amp;face=0_0_320_320,https://scrap.kakaocdn.net/dn/cVoaZb/dJMb9fZJ1Zg/AsDRdbACsfQ6BlalR1zpk1/img.jpg?width=640&amp;amp;height=480&amp;amp;face=0_0_640_480&quot;&gt;&lt;a href=&quot;https://evan-moon.github.io/2026/08/02/why-identity-is-hard-in-programming/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://evan-moon.github.io/2026/08/02/why-identity-is-hard-in-programming/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dqNk6C/dJMb9dHCVfj/5TDuKKw2eXTIEdOaZz1RZK/img.png?width=320&amp;amp;height=320&amp;amp;face=0_0_320_320,https://scrap.kakaocdn.net/dn/bhJPzv/dJMb9kmq9aO/5Ouyq7F7ci0w4K0kSt7a51/img.png?width=320&amp;amp;height=320&amp;amp;face=0_0_320_320,https://scrap.kakaocdn.net/dn/cVoaZb/dJMb9fZJ1Zg/AsDRdbACsfQ6BlalR1zpk1/img.jpg?width=640&amp;amp;height=480&amp;amp;face=0_0_640_480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;동일성은 왜 프로그래밍에서 가장 어려운 문제인가&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;얼마 전 JEP 401, 그러니까 자바의 가 OpenJDK master에 머지됐다는 소식을 봤다. 쉽게 말해 메모리 주소나 식별자(ID) 대신 객체 내부의 값 자체를 기준으로 삼는, 즉 값(Value)처럼 동작하는 객체 타입을&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;evan-moon.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추천 이유&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글은 공부하기 꽤 좋은 주제라서 추천드립니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java를 공부하면 어느 정도 레벨에서 equals와 == 그리고 hashmap 동작이 다르다는 점을 알게 되는데요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 equals를 재정의 해야한다를 넘어서 왜 해야하는지를 생각할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이를 넘어 프로그래밍 언어학과 의미론적으로 &quot;동일&quot;하다는 의미를 어떻게 다루는지 생각해볼 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 강의를 만들 때 꼭 언급하면 좋을 것 같다는 생각을 했습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;ldquo;같다&amp;rdquo;는 말의 차이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;500원 동전 두개와 천원 지폐 하나는 같은 것일까요?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내용이 같으면 같아도 되는지 아니면 다른 물건이니 다르게 생각해야하는지 이 두개를 나눠서 생각해야합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 Value 와 Entity 두 개념을 따로 생각해야합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 이 각 언어별로 이 고민을 어떻게 해결하는지 잘 정리해놨습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 같은 경우는 primitive와 objetct를 나눕니다. 기본적으로 객체를 만들면 엔티티를 취급합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;자바는 원래 equals와 hashCode를 직접 오버라이드하는 방식이었다. 사용자에게 동일성에 대한 계약 정의를 짬때린 것인데, &lt;br /&gt;문제는 그 계약을 지키기가 생각보다 어렵고 실수해도 아무도 안 알려준다는 데 있다. (그냥 공감되서 발췌했습니다.)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 이 부분은 record가 등장하면서 나아졌습니다. 이번에 Value Objets가 추가되며 더 나아졌습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일하다는 걸 정리하면 3가지로 생각할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;background-color: #111111; color: #e8e6e1; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;무엇을 보나&lt;/td&gt;
&lt;td&gt;부르는 이름&lt;/td&gt;
&lt;td&gt;코드에서는&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;애초에 한 사람인가&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;참조 동일성&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;===로 객체를 비교할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;생김새가 같나&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;구조적 동등성&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;JSON.stringify로 비교할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;주민번호가 같나&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;도메인 동일성&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;id가 같은지 볼 때&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값과 엔티티를 가르는건 시간이란 부분도 재밌었습니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;값은 변하지 않는 것이다. 42는 변하지 않는다. 정체성은 시간에 따라 서로 다른 값들과 결부되는 안정적인 논리적 실체다. 상태는 그 정체성이 특정 시점에 갖는 값이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 같다는 건 알고리즘의 문제가 아닌 기준이란 이야기도 이해되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;es-toolkit의 isEqualWith 함수가 수백 줄인 것도 그래서다. 즉, &amp;ldquo;같다&amp;rdquo;라는 것을 정의하려면 알고리즘이 복잡한 게 아니라 기준을 잡아주는 결정이 많이 필요하다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공리를 어기면 자료구조가 티 안 나게 망가진다 이 부분에서&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;메모이제이션도 같은 위험을 안고 있다. 캐시 키의 동등성이 추이성을 어기면 같은 입력인데도 캐시 히트가 났다 안 났다 한다. 성능 문제처럼 보이지만 사실은 정확성 문제고, 캐시된 값이 잘못 재사용되는 순간 결과 자체가 틀어진다.&lt;br /&gt;같은 두 값은 반드시 같은 해시를 가져야 한다.&lt;br /&gt;자바에서 equals를 오버라이드하면 hashCode도 반드시 같이 오버라이드하라고 하는 이유가 이것이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일성에 대한 정의를 제대로 하지 않으면 언제는 같지만 언제는 다른 경우가 펼쳐집니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 운영하면서 문제를 찾고 디버깅하기 가장 어려운 부분입니다. 실제 개발할 때는 찾아내지 않을 수도 있거든요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이번 글은 동일성이 왜 각기 다른지부터 언어별로 어떤 처리를 하는지, 그리고 어떻게 다뤄야하는지를 잘 풀어쓴 글이라 추천합니다&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>후기 /컴퓨터 관련 책</category>
      <author>inspire12</author>
      <guid isPermaLink="true">https://inspire12.tistory.com/493</guid>
      <comments>https://inspire12.tistory.com/493#entry493comment</comments>
      <pubDate>Wed, 5 Aug 2026 18:47:58 +0900</pubDate>
    </item>
    <item>
      <title>오늘의 읽기: 서버 모니터링 분석 가이드</title>
      <link>https://inspire12.tistory.com/490</link>
      <description>&lt;h1&gt;서버 모니터링 분석 가이드 글 소개&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원글: 서버 모니터링 분석 가이드&lt;br /&gt;&lt;a href=&quot;https://kciter.so/posts/server-monitoring-analysis-guide/&quot;&gt;https://kciter.so/posts/server-monitoring-analysis-guide/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 개발자라면 한 번쯤 꼭 읽어볼 만한 글이라고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모니터링 시스템을 구축하는 방법이나 대시보드를 만드는 방법에 대한 글은 꽤 많습니다. 그런데 막상 대시보드에 나타난 지표를 어떻게 읽어야 하는지, 어떤 지표들을 조합해서 문제의 원인을 좁혀야 하는지를 설명하는 글은 생각보다 많지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저도 이전에 블로그에 성능 모니터링 시스템을 구축하고 테스트한 내용을 적은 적이 있습니다. 하지만 돌이켜보면 시스템을 어떻게 구성했는지에 대해서는 적었어도, 실제 운영에서 그래프가 변했을 때 무엇을 의심해야 하는지는 충분히 다루지 못했던 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원글을 읽으면서 가장 기억에 남았던 문장은 이것입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리소스 지표는 혼자 읽으면 거짓말을 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모니터링 지표는 문제의 원인을 바로 알려주는 정답이라기보다 서버에서 나타나고 있는 현상에 가깝습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU가 올랐다거나 메모리가 늘었다는 사실만으로는 정확한 원인을 알 수 없습니다. 개발자는 여러 지표를 같이 보면서 현재 어떤 일이 벌어지고 있는지 추론해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 의미에서 이 글은 서버 지표를 해석할 때 사용할 수 있는 몇 가지 공식을 꽤 친절하게 정리하고 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #212b36; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;트래픽(Traffic)&lt;/b&gt;: 얼마나 들어오고 있는가?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지연 시간(Latency)&lt;/b&gt;: 얼마나 걸리는가?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에러(Errors)&lt;/b&gt;: 얼마나 실패하는가?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포화도(Saturation)&lt;/b&gt;: 얼마나 차 있는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CPU 사용률은 지연 시간과 같이 봐야 한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU 사용률이 높다고 해서 무조건 문제가 있는 것은 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트래픽을 처리하면서 CPU를 충분히 사용하고 있다면 자연스러운 상황일 수도 있습니다. 반대로 CPU가 계속 놀고 있다면 필요 이상으로 비싼 인프라를 사용하고 있다고 볼 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 것은 CPU 사용률 자체보다 응답 시간과 함께 어떻게 변하고 있는지를 보는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU가 포화 상태에 가까워지면서 응답 시간까지 증가한다면 연산 처리에서 병목이 생기고 있을 가능성이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 CPU에는 여유가 있는데 응답 시간이 느려지고 있다면 DB, 외부 API, 네트워크처럼 I/O가 발생하는 영역을 먼저 의심해볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 내용처럼 보이지만, 실제 장애 상황에서는 특정 지표 하나에 먼저 시선이 가는 경우가 많습니다. 원글에서는 이 부분을 그래프와 함께 설명하고 있어서 이해하기 좋았습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;메모리는 최고점보다 GC 이후 최저점을 봐야 한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 사용량이 계속 올라갔다 내려가는 그래프를 보면 처음에는 메모리 누수를 의심하기 쉽습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 GC가 있는 애플리케이션에서는 객체가 생성되면서 메모리가 증가하고, GC가 실행되면서 다시 감소하는 패턴이 자연스럽게 반복됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 중요한 것은 메모리가 얼마나 높이 올라갔는지가 아니라, GC 이후에 어디까지 내려오는지를 보는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GC가 실행된 뒤에도 메모리 최저점이 조금씩 높아지고 있다면, 계속 살아남는 객체가 늘어나고 있다는 의미일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상태가 계속되면 힙 한계에 가까워지고, GC가 점점 더 자주 실행됩니다. 결국 CPU 사용량과 응답 시간이 먼저 나빠지고, 마지막에는 OOM으로 프로세스가 종료될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로는 메모리 누수를 발견했을 때 바로 원인을 찾으려고 붙잡고 있기보다, 힙 덤프를 남기고 우선 재시작해서 서비스를 복구하라는 부분도 인상 깊었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장애 상황에서는 원인을 바로 찾는 것보다 복구와 증거 보존이 먼저라는 점을 다시 생각하게 됐습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;처리 시간이 늘어나면 풀과 큐가 같이 무너진다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글에서 가장 좋았던 부분 중 하나는 처리 시간의 증가가 연쇄 장애로 이어지는 과정을 설명한 부분입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;트래픽이 늘어나지 않았더라도 요청 하나를 처리하는 시간이 길어지면 동시에 처리 중인 요청 수는 증가합니다.&lt;br /&gt;예를 들어 DB에서 슬로 쿼리가 발생해 요청 처리 시간이 길어지면, 스레드나 DB 커넥션이 이전보다 오랫동안 반환되지 않습니다.&lt;br /&gt;그러면 스레드 풀과 커넥션 풀이 점점 고갈되고, 처리되지 못한 요청은 대기 큐에 쌓이기 시작합니다.&lt;br /&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;큐에 요청이 쌓이면 응답 시간은 더 길어집니다. 클라이언트에서는 타임아웃이 발생하고, 재시도까지 붙으면 실제 트래픽보다 더 많은 요청이 서버로 들어올 수 있습니다.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;상황이 더 나빠져 헬스 체크 요청까지 처리하지 못하면 로드 밸런서가 해당 서버를 제외합니다. 그러면 남은 서버들이 더 많은 트래픽을 받게 되고, 결국 다른 서버도 순서대로 무너질 수 있습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트래픽은 그대로인데 하나의 느린 의존성 때문에 전체 클러스터가 영향을 받을 수 있다는 이 시나리오는 저도 실제로 경험한 적이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;당시에는 서버가 호출하던 외부 AI API의 응답이 느려지면서 요청이 애플리케이션 내부에 계속 쌓였습니다. 외부 API를 기다리는 요청들이 오랫동안 자원을 점유했고, 시간이 지나면 일부 Pod가 새로운 요청과 헬스 체크까지 제대로 처리하지 못하는 상태가 됐습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;알림이 울릴 때마다 급하게 클러스터에 접속해 문제가 생긴 Pod를 수동으로 재시작했던 기억이 있습니다. Pod를 재시작하면 쌓여 있던 요청과 연결이 정리되면서 잠시 정상화됐지만, 외부 API의 지연이 계속되는 한 같은 문제는 다시 반복됐습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;돌이켜보면 Pod 재시작은 서비스를 임시로 복구하기 위한 대응이었을 뿐, 장애의 원인을 해결한 것은 아니었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 부분을 읽으면서 풀 고갈이 항상 풀 크기가 작아서 발생하는 문제는 아니라는 점도 다시 생각하게 됐습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DB나 외부 시스템이 느려져 자원의 반환이 늦어지고, 그 결과로 풀이 고갈되는 상황도 많습니다. 이런 상황에서 원인을 해결하지 않은 채 풀 크기만 늘리면 느린 하위 시스템에 더 많은 요청을 동시에 보내면서 오히려 문제를 키울 수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결국 풀 고갈을 발견했을 때는 &amp;ldquo;풀의 크기가 충분한가?&amp;rdquo;만 물을 것이 아니라, &amp;ldquo;왜 자원이 제때 반환되지 않고 있는가?&amp;rdquo;를 함께 확인해야 합니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;큐는 공짜가 아니다, 전체&amp;nbsp;처리량은&amp;nbsp;가장&amp;nbsp;좁은&amp;nbsp;단이&amp;nbsp;결정한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대기 큐에 대한 내용도 기억에 남았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처리하지 못한 요청을 큐에 쌓아두면 당장은 요청을 거절하지 않아도 됩니다. 그래서 큐가 서버를 보호해주는 장치처럼 느껴질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 유입 속도가 처리 속도보다 계속 빠르다면 큐는 문제를 해결하는 것이 아니라 문제 발생을 뒤로 미루는 역할만 하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐에 쌓인 요청도 메모리를 사용하고, 대기 시간이 길어질수록 사용자가 이미 연결을 끊은 요청을 뒤늦게 처리하는 상황도 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 큐에도 최대 크기와 대기 시간 제한이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 감당할 수 없는 상황이라면 모든 요청을 받아서 늦게 실패시키는 것보다, 일부 요청을 빠르게 거절하는 것이 전체 시스템을 지키는 데 더 나을 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;모니터링을 바라보는 세 가지 시간&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원글 후반부에서는 모니터링을 세 가지 시간으로 나눠 설명합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;장애가 발생하기 전, 미리 문제를 찾는 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;장애가 발생한 동안, 응급 처치를 하는 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;장애가 끝난 뒤, 같은 문제를 반복하지 않기 위한 시간&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;같은 대시보드를 보더라도 언제 보고 있느냐에 따라 던져야 하는 질문이 달라집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 세 가지 시간을 구분하지 않으면 장애가 발생한 상황에서 근본 원인을 찾느라 복구가 늦어지거나, 반대로 재시작만 반복하면서 같은 장애를 계속 겪게 될 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;미리 문제를 찾는 시간&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;평소에 대시보드를 보는 목적은 지금 장애가 발생했는지를 확인하는 것이 아니라, 앞으로 문제가 될 가능성이 있는 부분을 미리 찾는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원글에서는 하루 5분이라도 대시보드를 둘러보면서 서비스의 평소 모습을 익혀두라고 이야기합니다. 트래픽이 시간대별로 어떤 모양을 그리는지, 평소 CPU 사용률은 어느 정도인지, P99는 어느 범위에서 움직이는지 알아야 평소와 다른 변화도 발견할 수 있기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 부분을 읽으면서 모니터링에서도 결국 기준이 되는 것은 절대적인 숫자보다 서비스의 평소 상태라는 생각이 들었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CPU가 70%라는 숫자만 봐서는 높은지 낮은지 판단하기 어렵습니다. 평소 20%를 유지하던 서버가 갑자기 70%가 된 것과, 항상 60~70% 사이에서 안정적으로 동작하던 서버는 전혀 다른 상태이기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또 알람은 순간적으로 발생하는 문제를 잡는 데는 효과적이지만, 매일 조금씩 느려지는 문제를 발견하기는 어렵습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 알람은 한 번도 울리지 않았지만 지난주 같은 요일과 비교했을 때 동일한 트래픽에서 P99가 계속 나빠지고 있을 수 있습니다. 이런 변화는 하루 단위 그래프만 보면 알아차리기 어렵기 때문에 지난주나 지난달의 같은 시간대와 비교하는 패널이 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;메모리 누수나 DB 성능 저하, 캐시 히트율 감소처럼 서서히 진행되는 문제는 장애가 발생하기 전에 이런 추세 비교를 통해 먼저 발견할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;가장 위험한 배포 직후&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원글에서는 특히 배포 직후 30분을 가장 집중해서 그래프를 봐야 하는 시간으로 설명합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버에 발생하는 많은 장애가 갑작스러운 하드웨어 고장보다는 배포나 설정 변경처럼 사람이 시스템에 가한 변화에서 시작되기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이때 가장 먼저 필요한 것은 그래프에 배포 시각을 표시하는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;장애를 분석할 때 가장 먼저 묻게 되는 질문 중 하나가 &amp;ldquo;이 지표의 변화가 배포 전부터 있었는가, 배포 이후에 발생했는가?&amp;rdquo;이기 때문입니다. 배포 마커 하나만 있어도 원인을 좁히는 시간이 크게 줄어듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다만 배포 직후 P99나 CPU가 잠깐 증가했다고 해서 바로 문제가 생겼다고 판단해서는 안 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;새로 실행된 서버는 캐시가 비어 있고 DB 커넥션을 다시 맺어야 하며, JVM 환경에서는 JIT 컴파일도 충분히 진행되지 않은 상태일 수 있습니다. 그래서 배포 직후에는 응답 시간이 일시적으로 나빠질 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;중요한 것은 순간적인 값보다 방향입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;배포 직후 지표가 높아졌다가 몇 분 동안 다시 정상 범위로 내려온다면 워밍업 과정일 수 있습니다. 반대로 시간이 지나도 회복하지 않거나 계속 나빠진다면 문제가 있는 배포일 가능성이 높습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원글에서 이야기한 것처럼 다음과 같은 기준을 미리 정해두는 것도 좋다고 생각합니다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;배포 이후 에러율이 일정 수준을 넘거나, P99가 10분 안에 회복되는 추세를 보이지 않는다면 별도의 토론 없이 롤백한다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;장애가 발생한 상태에서는 계속 지켜볼지, 롤백할지를 두고 판단이 늦어지기 쉽습니다. 그래서 판단 기준은 문제가 발생하기 전에 팀에서 합의해두는 것이 중요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;응급 처치의 시간&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;장애가 실제로 발생했을 때는 원인 분석보다 먼저 영향 범위를 확인해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;전체 사용자가 문제를 겪고 있는지, 특정 API만 느린지, 특정 지역이나 일부 사용자에게만 문제가 발생했는지를 먼저 파악해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원글에서는 이를 응급실의 환자 분류에 빗대어 트리아지라고 설명합니다. 전체 API가 느리다면 DB나 캐시처럼 여러 기능이 공유하는 자원을 의심할 수 있고, 특정 API만 느리다면 해당 API의 쿼리나 외부 호출로 범위를 좁힐 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음으로 확인할 것은 최근에 변경된 내용입니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;애플리케이션 배포&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;인프라나 설정 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;피처 플래그 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;배치 작업 실행&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;마케팅 푸시로 인한 트래픽 변화&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;장애 직전에 변경된 내용이 있다면 그것이 원인일 가능성이 높기 때문에, 복잡한 분석을 시작하기 전에 되돌릴 수 있는지 먼저 확인해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 장애 중에는 대부분 복구가 원인 규명보다 우선입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;롤백, 문제 기능 비활성화, 스케일 아웃, 프로세스 재시작 등을 통해 우선 사용자가 서비스를 다시 사용할 수 있도록 해야 합니다. 로그와 메트릭, 힙 덤프 등 분석에 필요한 증거가 남아 있다면 근본 원인은 서비스가 복구된 뒤에 찾아도 늦지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;저도 앞에서 이야기한 외부 AI API 장애 당시에는 Pod를 재시작하면서 우선 서비스를 복구했습니다. 당시에는 반복되는 수동 재시작이 근본 해결책은 아니었지만, 장애가 진행 중인 상황에서 사용자의 영향을 줄이기 위한 응급 처치로는 필요했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다만 문제가 반복된다면 그다음부터는 재시작 자체를 대응 전략으로 삼기보다 타임아웃, 서킷 브레이커, 요청 수 제한, 재시도 정책 등을 통해 느린 외부 시스템의 문제가 전체 서버로 번지지 않도록 구조를 바꿔야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;장애가 끝난 뒤의 시간&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서비스가 정상화되었다고 해서 장애 대응이 끝난 것은 아닙니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;장애 중에는 &amp;ldquo;배포를 되돌렸더니 정상화됐다&amp;rdquo; 정도의 상관관계만 확인하고 넘어갈 수 있습니다. 하지만 장애가 끝난 뒤에는 왜 해당 배포가 문제를 일으켰는지, 왜 테스트나 리뷰 과정에서 발견하지 못했는지까지 확인해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원글에서는 장애 이후 그래프를 바탕으로 다음 네 시점을 정리하라고 이야기합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;문제의 첫 흔적이 나타난 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;알람이 울린 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;사람이 대응을 시작한 시간&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;서비스가 복구된 시간&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 흔적부터 알람까지의 간격이 길었다면 감지하지 못한 전조가 있었다는 뜻입니다. 다음에는 그 전조를 알람이나 대시보드 패널로 만들 수 있는지 검토해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;알람부터 복구까지 시간이 오래 걸렸다면 대응 절차에 문제가 있었을 수 있습니다. 배포 시각을 찾느라 시간을 보냈다면 배포 마커를 추가하고, 롤백 여부를 결정하지 못해 지연됐다면 롤백 기준을 미리 정하는 식입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 포스트모템의 결과는 단순한 장애 보고서나 반성문이 되어서는 안 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;새로 추가해야 할 알람&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;대시보드에 필요한 지표&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;자동화할 복구 절차&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;수정해야 할 코드와 설정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;다음 장애에서 판단을 빠르게 할 기준&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이처럼 다음 장애를 더 빠르게 발견하고, 더 짧게 끝낼 수 있도록 만드는 변경 목록이 남아야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또 장애 원인을 사람에게 돌리지 않는다는 원칙도 중요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;ldquo;누가 잘못 배포했다&amp;rdquo;에서 끝나면 같은 문제가 다시 발생할 수 있습니다. 그보다는 왜 해당 상황에서 그런 판단을 내릴 수밖에 없었는지, 검증 절차나 시스템에 어떤 안전장치가 없었는지를 확인해야 재발을 막을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결국 세 가지 시간은 다음과 같이 정리할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;평소에는 이상을 알아차릴 수 있도록 정상 상태를 익히고, 장애 중에는 원인보다 복구를 우선하며, 장애 후에는 같은 문제를 반복하지 않도록 시스템을 바꾼다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모니터링은 장애가 발생했을 때만 대시보드를 여는 일이 아니라는 점이 이 부분에서 가장 잘 드러났습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모니터링은 만든느 것보다 대시보드에 나타나는 지표를 보고 현재 어떤 현상이 발생하고 있는지 파악하고, 여러 지표의 관계를 통해 가능한 원인을 하나씩 좁혀가는 과정이 더 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 장애 대응에는 경험이 중요하다는 이야기를 많이 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 직접 장애를 겪어본 경험은 분명히 중요합니다. 하지만 개발자 생활을 하다 보니 장애에도 반복해서 등장하는 패턴이 있고, 지표를 해석하는 데도 어느 정도 공식이 있다는 생각이 듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 그런 공식들을 시각적인 자료와 함께 잘 정리한 글입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔가 제 8년 정도 일하면서 쌓은 노하우가 공개된 것 같은 느낌도 드네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 경험이 많지 않은 백엔드 개발자나, 모니터링 대시보드는 만들어두었지만 지표를 어떻게 읽어야 할지 막막한 개발자라면 꼭 한 번 읽어보기를 권합니다.&lt;/p&gt;</description>
      <category>후기 /컴퓨터 관련 책</category>
      <category>서버 모니터링 가이드</category>
      <category>오늘의 읽기</category>
      <author>inspire12</author>
      <guid isPermaLink="true">https://inspire12.tistory.com/490</guid>
      <comments>https://inspire12.tistory.com/490#entry490comment</comments>
      <pubDate>Fri, 24 Jul 2026 01:30:33 +0900</pubDate>
    </item>
    <item>
      <title>GraphQL스러운 코드는 무엇일까? 4편: 도메인 표현 N+1 문제 해결하기</title>
      <link>https://inspire12.tistory.com/489</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Preview&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;background-color: #ffffff; color: #6bacce; text-align: start;&quot; href=&quot;https://inspire12.tistory.com/485&quot;&gt;1편: REST와 GraphQL의 같은 의도와 다른 표현&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784785427512&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도, 다른 표현&quot; data-og-description=&quot;회사에서 GraphQL 기반의 서버-클라이언트 통신을 적극적으로 사용하고 있습니다. GraphQL은 REST와 다른 타입 시스템과 요청 문법을 가진 API 기술입니다. 서버-클라이언트 통신에서 널리 사용되는 RE&quot; data-og-host=&quot;inspire12.tistory.com&quot; data-og-source-url=&quot;https://inspire12.tistory.com/485&quot; data-og-url=&quot;https://inspire12.tistory.com/485&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cpjKKu/dJMb9iITZCQ/vKykmUMpsifDsdK5hV7H21/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/sjkP8/dJMb9gxyGqx/5RY4Rq8NJnfksSx8nPikx0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gzXRI/dJMb9b349SM/fraBoHlCIWSHI7IscoeC4K/img.jpg?width=455&amp;amp;height=463&amp;amp;face=0_0_455_463&quot;&gt;&lt;a href=&quot;https://inspire12.tistory.com/485&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inspire12.tistory.com/485&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cpjKKu/dJMb9iITZCQ/vKykmUMpsifDsdK5hV7H21/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/sjkP8/dJMb9gxyGqx/5RY4Rq8NJnfksSx8nPikx0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gzXRI/dJMb9b349SM/fraBoHlCIWSHI7IscoeC4K/img.jpg?width=455&amp;amp;height=463&amp;amp;face=0_0_455_463');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도, 다른 표현&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;회사에서 GraphQL 기반의 서버-클라이언트 통신을 적극적으로 사용하고 있습니다. GraphQL은 REST와 다른 타입 시스템과 요청 문법을 가진 API 기술입니다. 서버-클라이언트 통신에서 널리 사용되는 RE&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inspire12.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://inspire12.tistory.com/487&quot;&gt;2편: 다른 표현을 위한 GraphQL에서 요청을 처리하는 방식&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784785426349&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;GraphQL스러운 코드는 무엇일까? 2편: 다른 표현을 위한 GraphQL에서 요청을 처리하는 방식 (Schema, Reso&quot; data-og-description=&quot;1편: REST와 GraphQL의 같은 의도 GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도와 다른 표현회사에서 GraphQL 기반으로 클라이언트-서버 통신을 적극적으로 사용하고 있습니다. GraphQL &quot; data-og-host=&quot;inspire12.tistory.com&quot; data-og-source-url=&quot;https://inspire12.tistory.com/487&quot; data-og-url=&quot;https://inspire12.tistory.com/487&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/BJwJI/dJMb84qlQbq/681McT5AMrzSC9M2m2B4m0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bym3ZE/dJMb86oaUpw/OXfmsnePbe8jk669n93IkK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/DClea/dJMb87gjNYU/EzVyYe0AOxQHChqQSJnBkk/img.png?width=2432&amp;amp;height=1262&amp;amp;face=0_0_2432_1262&quot;&gt;&lt;a href=&quot;https://inspire12.tistory.com/487&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inspire12.tistory.com/487&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/BJwJI/dJMb84qlQbq/681McT5AMrzSC9M2m2B4m0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bym3ZE/dJMb86oaUpw/OXfmsnePbe8jk669n93IkK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/DClea/dJMb87gjNYU/EzVyYe0AOxQHChqQSJnBkk/img.png?width=2432&amp;amp;height=1262&amp;amp;face=0_0_2432_1262');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GraphQL스러운 코드는 무엇일까? 2편: 다른 표현을 위한 GraphQL에서 요청을 처리하는 방식 (Schema, Reso&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1편: REST와 GraphQL의 같은 의도 GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도와 다른 표현회사에서 GraphQL 기반으로 클라이언트-서버 통신을 적극적으로 사용하고 있습니다. GraphQL&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inspire12.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inspire12.tistory.com/488&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;3편: GraphQL의 철학 이해하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784785468120&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;GraphQL 스러운 코드는 무엇일까? 3편: GraphQL의 철학 이해하기&quot; data-og-description=&quot;1편: REST와 GraphQL의 같은 의도와 다른 표현 GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도와 다른 표현회사에서 GraphQL 기반으로 클라이언트-서버 통신을 적극적으로 사용하고 있습&quot; data-og-host=&quot;inspire12.tistory.com&quot; data-og-source-url=&quot;https://inspire12.tistory.com/488&quot; data-og-url=&quot;https://inspire12.tistory.com/488&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dybEjD/dJMb8WMCYRx/LQJ0M4W1MIH4pNltn2YVUK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/lvQnD/dJMb8QMpvSP/KRJaCLInMf0qJEdDSF8uA0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/iiWIu/dJMb8Yp8F2o/WEJnZE1X968b30p9aKNEn0/img.jpg?width=455&amp;amp;height=463&amp;amp;face=0_0_455_463&quot;&gt;&lt;a href=&quot;https://inspire12.tistory.com/488&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inspire12.tistory.com/488&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dybEjD/dJMb8WMCYRx/LQJ0M4W1MIH4pNltn2YVUK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/lvQnD/dJMb8QMpvSP/KRJaCLInMf0qJEdDSF8uA0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/iiWIu/dJMb8Yp8F2o/WEJnZE1X968b30p9aKNEn0/img.jpg?width=455&amp;amp;height=463&amp;amp;face=0_0_455_463');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GraphQL 스러운 코드는 무엇일까? 3편: GraphQL의 철학 이해하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1편: REST와 GraphQL의 같은 의도와 다른 표현 GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도와 다른 표현회사에서 GraphQL 기반으로 클라이언트-서버 통신을 적극적으로 사용하고 있습&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inspire12.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;예제코드&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 글들에서는 GraphQL스럽다는 것이 Query 문법을 사용하는 것이 아니라, Schema와 데이터를 중심으로 사고하는 것이라는 점을 살펴봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL Schema에서는 User, Post, Comment와 같은 객체와 관계를 자연스럽게 표현할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 관계를 풍부하게 표현하는 것만으로 좋은 서버 구조가 완성되지는 않습니다. 오히려 서버 내부에서는 새로운 문제가 생기기 시작합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;User에서 posts를 조회하고, 각 Post에서 comments를 조회하고, 각 Comment에서 author를 조회하기 시작하면 서버 내부에서는 조회 횟수가 빠르게 증가할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL은 데이터를 자유롭게 표현할 수 있게 해주지만, 서버는 그 표현을 효율적으로 실행하기 위한 구조를 함께 고민해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 GraphQL의 표현력을 유지하면서 대표적인 조회 성능 문제인 N+1과 이를 해결하는 DataLoader를 먼저 살펴보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;N + 1 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Field Resolver는 관계를 표현하지만 조회 비용을 숨깁니다. 서버를 개발하면서 이 조회 비용은 매우 중요한 포인트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL에서는 관계를 자유롭게 표현할 수 있지만, 서버는 그 관계를 실제 조회로 바꿔야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1784786081767&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type Query {
  users: [User!]!
}

type User {
  id: Int!
  name: String!
  posts: [Post!]!
}

type Post {
  id: Int!
  title: String!
  authorId: Int!
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Resolver는 다음처럼 구성할 수 있습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1784786093883&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Resolver(() =&amp;gt; UserType)
export class UserResolver {
  constructor(
    private readonly userService: UserService,
    private readonly postService: PostService,
  ) {}

  @Query(() =&amp;gt; [UserType])
  users(): Promise&amp;lt;User[]&amp;gt; {
    return this.userService.getUsers();
  }

  @ResolveField(() =&amp;gt; [PostType])
  posts(
    @Parent() user: User,
  ): Promise&amp;lt;Post[]&amp;gt; {
    return this.postService.getPostsByUserId(user.id);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 입장에서는 자연스럽고, 원하는 값을 얻을 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 서버 입장에서는 매 유저를 조회할 때마다 posts 를 조회하게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;사용자(User)가 N명이면 Posts는 N번을 추가로 조회합니다&lt;br /&gt;유저 조회 1번 + Posts 조회 N번 총 N+1 조회가 이루어집니다&lt;/span&gt;&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;N+1은 GraphQL만의 문제는 아닙니다&lt;/h4&gt;
&lt;p data-end=&quot;4000&quot; data-start=&quot;3970&quot; data-ke-size=&quot;size16&quot;&gt;여기까지 보면서 REST를 많이 사용해보신 분들은 REST에서도 동일한 문제를 겪었다고 느끼실텐데요. 정상입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4000&quot; data-start=&quot;3970&quot; data-ke-size=&quot;size16&quot;&gt;도메인을 객체로 표현하는 방식등에서는 공통적으로 나타나는 문제점입니다. 대표적으로 ORM(JPA 등)에서도 이런 문제는 해결하고 가야하는 점입니다.&lt;/p&gt;
&lt;p data-end=&quot;4000&quot; data-start=&quot;3970&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4000&quot; data-start=&quot;3970&quot; data-ke-size=&quot;size16&quot;&gt;REST에서도 다음 코드라면 동일한 문제가 발생합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1784786185993&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async getUsersWithPosts() {
  const users = await this.userRepository.findAll();

  return Promise.all(
    users.map(async (user) =&amp;gt; ({
      ...user,
      posts: await this.postRepository.findByUserId(user.id),
    })),
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N+1은 GraphQL의 고유한 문제가 아니라, 객체 관계를 개별 조회하는 실행 방식에서 발생하는 문제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL이 N+1을 새로 만든 것은 아닙니다.&lt;/p&gt;
&lt;p data-end=&quot;4342&quot; data-start=&quot;4281&quot; data-ke-size=&quot;size16&quot;&gt;다만 Field Resolver 구조에서는 관계 필드를 독립적으로 조회하기 쉽고, 개발자가 놓치기 쉬워 N+1 문제가 더 자주 드러납니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DataLoader로 조회를 요청 단위로 묶습니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL에서는 DataLoader를 이용해 이 N+1 문제를 좀 더 구조적으로 해결할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Resolver는 서로 독립적으로 실행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DataLoader는 이 독립적인 Resolver들이 발생시키는 조회를 한 번의 조회로 합쳐줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게 사용하는지 코드로 먼저 보여드리겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Repository에 배치 조회를 추가합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1784786263517&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;findByUserIds(userIds: number[]): Promise&amp;lt;Post[]&amp;gt; {
  return this.posts.filter((post) =&amp;gt;
    userIds.includes(post.authorId),
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DataLoader를 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DataLoader가 하는 일은 생각보다 단순합니다. Resolver가 각각 요청한 userId를 모아서 한 번에 조회한 뒤(IN Query) 다시 각 Resolver에게 결과를 매핑해 나눠주는 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1784786308729&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Injectable()
export class PostsByUserLoader {
  constructor(
    private readonly postService: PostService,
  ) {}

  readonly loader = new DataLoader(async (userIds) =&amp;gt; {
    const posts = await postService.findByUserIds(userIds);

    return groupByUser(posts, userIds);
  });
}

# groupByUser는 조회된 Post를 authorId별로 나눈 뒤, DataLoader가 전달한 userIds 순서에 맞춰 결과를 반환하는 예제 함수입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Field Resolver에서는 개별 조회 대신 DataLoader에 조회를 위임하도록 설정해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1784786364195&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ResolveField(() =&amp;gt; [PostType])
posts(
  @Parent() user: User,
  @Context() context: GraphqlContext,
): Promise&amp;lt;Post[]&amp;gt; {
  return context.loaders.postsByUser.load(user.id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 서버에서는&lt;/p&gt;
&lt;pre id=&quot;code_1784789741446&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- Before: users 조회 1회 + posts 조회 N회

SELECT users
SELECT posts WHERE userId = 1
SELECT posts WHERE userId = 2
SELECT posts WHERE userId = 3
...&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1784789771459&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- Before: users 조회 1회 + posts 조회 N회

SELECT users
SELECT posts WHERE userId IN (...)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번의 조회로 SQL쿼리로 바꿔서 처리가 됩니다. (IN Query를 통해 데이터베이스와의 왕복 횟수를 크게 줄일 수 있습니다)&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;DataLoader는 요청마다 새로 만들어집니다&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;300&quot; data-end=&quot;355&quot; data-ke-size=&quot;size16&quot;&gt;앞에서 DataLoader를 사용해 N+1 문제를 해결했습니다.&lt;/p&gt;
&lt;p data-end=&quot;126&quot; data-start=&quot;69&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 DataLoader는 애플리케이션이 시작할 때 한 번만 생성해서 계속 사용하면 되지 않을까요?&lt;/p&gt;
&lt;p data-end=&quot;146&quot; data-start=&quot;128&quot; data-ke-size=&quot;size16&quot;&gt;결론부터 말하면 그렇지 않습니다.&lt;/p&gt;
&lt;p data-end=&quot;232&quot; data-start=&quot;148&quot; data-ke-size=&quot;size16&quot;&gt;DataLoader는 하나의 GraphQL 요청(Request)을 기준으로 생성되고 함께 종료되는 &lt;b&gt;Request Scope&lt;/b&gt;의 생명주기를 가집니다&lt;/p&gt;
&lt;p data-end=&quot;308&quot; data-start=&quot;234&quot; data-ke-size=&quot;size16&quot;&gt;하나의 요청 안에서는 여러 Field Resolver가 같은 DataLoader를 공유하며, 발생한 조회를 모아 한 번에 처리합니다.&lt;/p&gt;
&lt;p data-end=&quot;357&quot; data-start=&quot;310&quot; data-ke-size=&quot;size16&quot;&gt;하지만 새로운 GraphQL 요청이 들어오면 새로운 DataLoader가 생성됩니다.&lt;/p&gt;
&lt;p data-end=&quot;446&quot; data-start=&quot;359&quot; data-ke-size=&quot;size16&quot;&gt;이는 DataLoader의 목적이 데이터를 오래 보관하는 것이 아니라, 하나의 요청 안에서 발생하는 조회를 모으고 중복을 제거하는 것이기 때문입니다.&lt;/p&gt;
&lt;p data-end=&quot;745&quot; data-start=&quot;627&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;298&quot; data-start=&quot;280&quot; data-ke-size=&quot;size16&quot;&gt;DataLoader의 라이프 사이클을 좀 더 들여다 보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784787940368&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GraphQL Request
        &amp;darr;
 DataLoader 생성
        &amp;darr;
 Resolver들이 공유
        &amp;darr;
 Batch 조회
        &amp;darr;
 요청 종료
        &amp;darr;
 DataLoader 제거&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 하나의 DataLoader를 애플리케이션 전체에서 공유(Singleton)한다면, 서로 다른 요청의 조회 결과가 같은 DataLoader를 통해 처리될 수 있습니다. 사용자 권한, Locale, Tenant, A/B 테스트 그룹처럼 요청마다 달라질 수 있는 정보가 섞여 예상하지 못한 문제가 발생할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;627&quot; data-end=&quot;745&quot; data-ke-size=&quot;size16&quot;&gt;즉 DataLoader는 하나의 요청 안에서 여러 Resolver의 조회를 효율적으로 묶어주는 Request Scope의 Batching 도구라고 이해하는 것이 더 정확합니다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;1267&quot; data-end=&quot;1306&quot; data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GraphQL은 객체와 관계를 자연스럽게 표현할 수 있는 강력한 도구입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 표현력이 좋아질수록 서버는 그 관계를 실제 데이터 조회로 변환해야 하고, 이 과정에서 N+1과 같은 성능 문제가 발생할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DataLoader는 이러한 문제를 해결하기 위한 대표적인 방법으로, 독립적으로 실행되는 Field Resolver의 조회를 요청 단위로 묶어 데이터베이스 접근을 효율적으로 줄여줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 조회 횟수만 줄인다고 해서 GraphQL 서버가 잘 설계되는 것은 아닙니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL의 표현력은 유지하면서 서버 구조는 어떻게 복잡해지지 않게 만들까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 글에서는 GraphQL의 표현력을 유지하면서도 도메인 간 경계를 어떻게 나누고, DDD 관점에서 서버 구조를 어떻게 설계할 수 있는지 이야기해보겠습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/유저 서비스 flow</category>
      <category>DataLoader</category>
      <category>graphql</category>
      <category>graphql n+1</category>
      <author>inspire12</author>
      <guid isPermaLink="true">https://inspire12.tistory.com/489</guid>
      <comments>https://inspire12.tistory.com/489#entry489comment</comments>
      <pubDate>Thu, 23 Jul 2026 15:58:27 +0900</pubDate>
    </item>
    <item>
      <title>GraphQL스러운 코드는 무엇일까? 3편: GraphQL의 철학 이해하기</title>
      <link>https://inspire12.tistory.com/488</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Preview&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;background-color: #ffffff; color: #6bacce; text-align: start;&quot; href=&quot;https://inspire12.tistory.com/485&quot;&gt;1편: REST와 GraphQL의 같은 의도와 다른 표현&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784455014200&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도와 다른 표현&quot; data-og-description=&quot;회사에서 GraphQL 기반으로 클라이언트-서버 통신을 적극적으로 사용하고 있습니다. GraphQL 은 GraphQL 만의 독특한 시스템은 가장 많이 쓰이는 Rest 문법과 철학부터 사용법까지 차이가 크게 있습니&quot; data-og-host=&quot;inspire12.tistory.com&quot; data-og-source-url=&quot;https://inspire12.tistory.com/485&quot; data-og-url=&quot;https://inspire12.tistory.com/485&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/1v0oK/dJMb84qlnEj/Ow5OdP1lXDrSsGZsxoZs5K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b8VlYk/dJMb84qlnEk/QMXgyQ5icMcM8X1U49OzZ0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bojFTb/dJMb85W6bkX/Mjzn0KP8AyZZVuEzrrMbOK/img.jpg?width=455&amp;amp;height=463&amp;amp;face=0_0_455_463&quot;&gt;&lt;a href=&quot;https://inspire12.tistory.com/485&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inspire12.tistory.com/485&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/1v0oK/dJMb84qlnEj/Ow5OdP1lXDrSsGZsxoZs5K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b8VlYk/dJMb84qlnEk/QMXgyQ5icMcM8X1U49OzZ0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bojFTb/dJMb85W6bkX/Mjzn0KP8AyZZVuEzrrMbOK/img.jpg?width=455&amp;amp;height=463&amp;amp;face=0_0_455_463');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도와 다른 표현&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;회사에서 GraphQL 기반으로 클라이언트-서버 통신을 적극적으로 사용하고 있습니다. GraphQL 은 GraphQL 만의 독특한 시스템은 가장 많이 쓰이는 Rest 문법과 철학부터 사용법까지 차이가 크게 있습니&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inspire12.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inspire12.tistory.com/487&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2편: 다른 표현을 위한 GraphQL에서 요청을 처리하는 방식&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784455064632&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;GraphQL 스러운 코드는 무엇일까? 2편: 다른 표현을 위한 GraphQL에서 요청을 처리하는 방식&quot; data-og-description=&quot;1편: REST와 GraphQL의 같은 의도 GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도와 다른 표현회사에서 GraphQL 기반으로 클라이언트-서버 통신을 적극적으로 사용하고 있습니다. GraphQL &quot; data-og-host=&quot;inspire12.tistory.com&quot; data-og-source-url=&quot;https://inspire12.tistory.com/487&quot; data-og-url=&quot;https://inspire12.tistory.com/487&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bxF9g8/dJMb86PezpC/WaOnn9ytnehZ8UTXivMPEk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/yR10e/dJMb84Ybyrk/KHu7QXV1ZwKcLpaXUXnL0K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/n2PPO/dJMb82MPZaY/k8YqDx8WTAM1beCvv5ACWK/img.jpg?width=455&amp;amp;height=463&amp;amp;face=0_0_455_463&quot;&gt;&lt;a href=&quot;https://inspire12.tistory.com/487&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inspire12.tistory.com/487&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bxF9g8/dJMb86PezpC/WaOnn9ytnehZ8UTXivMPEk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/yR10e/dJMb84Ybyrk/KHu7QXV1ZwKcLpaXUXnL0K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/n2PPO/dJMb82MPZaY/k8YqDx8WTAM1beCvv5ACWK/img.jpg?width=455&amp;amp;height=463&amp;amp;face=0_0_455_463');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GraphQL 스러운 코드는 무엇일까? 2편: 다른 표현을 위한 GraphQL에서 요청을 처리하는 방식&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1편: REST와 GraphQL의 같은 의도 GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도와 다른 표현회사에서 GraphQL 기반으로 클라이언트-서버 통신을 적극적으로 사용하고 있습니다. GraphQL&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inspire12.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Preview&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 글에서는 REST와 GraphQL이 같은 목적을 서로 다른 방식으로 표현한다는 점과, GraphQL 요청이 Schema와 Resolver를 통해 서버 코드로 연결되는 과정을 살펴봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 GraphQL을 친숙하게 느끼는 것에서 시작해 다른 표현에 익숙하는데 집중했다면 이번 글은 이 시리즈의 제목인 GraphQL스럽다는 게 무엇인지, GraphQL을 쓰면 어떤 생각의 변화가 자연스럽게 이뤄지는지 알아보려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GraphQL스러운 코드는 무엇일까?&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST를 그대로 GraphQL 옮긴다면 아래와 같이 나오게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1784783057209&quot; class=&quot;elm&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;type Query {
  getUserProfile(userId: ID!): UserProfile!
  getUserPosts(userId: ID!): [Post!]!
  getUserFollowers(userId: ID!): [User!]!
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것도 GraphQL입니다. 동작도 잘합니다. 그러나 GraphQL스럽지는 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능 단위 API를 Query로 옮겼을 뿐, 데이터 모델을 중심으로 설계하지 않았기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 GraphQL스럽게 쓰면 아래와 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1784783107723&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type Query {
    user(id: ID!): User!
}

type User {
    id: ID!
    profile: Profile!
    posts: [Post!]!
    followers: [User!]!
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 구조에서는 API를 추가하는 것이 아니라 기존 데이터 모델을 확장하게 됩니다.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;User는 하나의 화면을 위한 타입이 아닙니다. Profile 화면에서도, Home 화면에서도, 게시글 화면에서도 같은&amp;nbsp;User를&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL에서는 새로운 기능이 생겼을 때 &quot;새로운 Query를 만들까?&quot;보다 &quot;기존 User나 Post에 어떤 관계를 추가하는 것(재사용)이 자연스러울까?&quot;를 먼저 고민하게 됩니다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;공식 문서에서 이야기하는 GraphQL의 지향점: 제품 중심(Product-centric)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GraphQL 공식 문서를 보면 GraphQL은 단순히 새로운 API 문법이나 REST를 대체하기 위한 기술로 소개하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GraphQL은 &lt;/span&gt;&lt;b&gt;&lt;span&gt;클라이언트 애플리케이션을 만들기 위한(Query Language designed to build client applications)&lt;/span&gt;&lt;/b&gt;&lt;span&gt; 질의 언어라고 설명합니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GraphQL이 추구하는 철학으로 다음과 같은 특징을 제시합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;Product-centric&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Hierarchical&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Strongly typed&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Client-specified response&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Self-documenting&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가장 중요한건 제품 중심(&lt;/span&gt;&lt;span&gt;Product-centric)으로 서버 내부 구현보다 UX가 필요로 하는 데이터 모델 중심으로 설계가 되게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제품 중심이란 말의 뜻&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제품 중심이란 말이 좀 추상적으로 느껴집니다. 이 부분을 좀 더 구체적으로 말하면 아래와 같습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;GraphQL에서는 REST처럼 엔드포인트를 먼저 설계하기보다, 클라이언트가 탐색할 수 있는 데이터 모델과 관계를 Schema로 표현합니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;REST를 사용할 때는 &quot;API 하나 만들어주세요.&quot; 라는 요청이 많았다면,&lt;br /&gt;GraphQL을 사용하면서는 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;User에서 couple도 같이 받을 수 있을까요?&lt;/li&gt;
&lt;li&gt;posts 아래에서 commentCount도 선택할 수 있으면 좋겠습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 Schema와 데이터 관계에 대한 이야기가 더 많아졌습니다.&lt;br /&gt;물론 REST도 이와 같이 개발을 할 수는 있습니다. 다만 GraphQL을 쓰면 API를 추가하는 것보다 기존 데이터 모델을 어떻게 확장할 것인지에 대한 논의가 좀 더 자연스럽게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL은 API를 늘리는 것이 아니라 데이터를 확장하는 방향으로 설계하도록 유도합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;GraphQL을 쓰게되면 화면보다 재사용 가능한 타입을 먼저 고민하게 됩니다.&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API를 설계할 때는 서버가 어떤 API를 제공할지부터 고민하는 경우가 많았습니다. 반면 GraphQL에서는 화면에서 어떤 데이터가 필요한지에 대한 논의가 먼저 시작되는 경우가 많았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;GraphQL은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;조합을 서버가 아니라 클라이언트에게 넘깁니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST에서는&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;UserDetailResponse
UserPageResponse
HomeResponse&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;GET /home
{
    &quot;user&quot;: ...
    &quot;posts&quot;: ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 계속 생깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL에서는&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;User
Post
Comment&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1177&quot; data-start=&quot;1172&quot; data-ke-size=&quot;size16&quot;&gt;를 만들고 화면은&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;query {
    user {
        nickname
    }

    posts {
        title
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1226&quot; data-start=&quot;1218&quot; data-ke-size=&quot;size16&quot;&gt;쿼리로 조합해 데이터를 요청합니다.&lt;/p&gt;
&lt;p data-end=&quot;1226&quot; data-start=&quot;1218&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1247&quot; data-start=&quot;1228&quot; data-ke-size=&quot;size16&quot;&gt;REST에서는 서버가 어떤 화면인지 알고 응답을 조합합니다.&lt;/p&gt;
&lt;p data-end=&quot;1247&quot; data-start=&quot;1228&quot; data-ke-size=&quot;size16&quot;&gt;GraphQL에서는&amp;nbsp;클라이언트가&amp;nbsp;필요한&amp;nbsp;화면을&amp;nbsp;직접&amp;nbsp;조합합니다.&lt;/p&gt;
&lt;p data-end=&quot;1247&quot; data-start=&quot;1228&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1247&quot; data-start=&quot;1228&quot; data-ke-size=&quot;size16&quot;&gt;이게 GraphQL다운 설계입니다.&lt;/p&gt;
&lt;p data-end=&quot;1247&quot; data-start=&quot;1228&quot; data-ke-size=&quot;size16&quot;&gt;기능을 추가하는 것이 아니라 User라는 데이터 모델을 풍부하게 만드는 방향으로 발전합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 REST는&amp;nbsp;API를&amp;nbsp;추가하는&amp;nbsp;방향으로&amp;nbsp;생각하게&amp;nbsp;만들고,&amp;nbsp;GraphQL은&amp;nbsp;기존&amp;nbsp;데이터&amp;nbsp;모델을&amp;nbsp;어떻게&amp;nbsp;확장할지&amp;nbsp;고민하게&amp;nbsp;만듭니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 GraphQL스럽다는 건 기능(Function)을 먼저 만드는 것이 아니라 데이터(Model)를 먼저 표현하는 것입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;REST와 GraphQL은 지향점이 다릅니다.&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지금까지만 보면 REST보다 GraphQL이 뛰어나다고 느낄 수 있는데 그렇진 않습니다. REST도 여전히 강점이 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;REST는 HTTP의 철학에 충실한 API 구조입니다. &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1164&quot; data-start=&quot;1146&quot;&gt;리소스를 URL로 식별합니다.&lt;/li&gt;
&lt;li data-end=&quot;1190&quot; data-start=&quot;1165&quot;&gt;HTTP Method의 의미를 사용합니다.&lt;/li&gt;
&lt;li data-end=&quot;1213&quot; data-start=&quot;1191&quot;&gt;상태 코드를 응답 의미에 활용합니다.&lt;/li&gt;
&lt;li data-end=&quot;1278&quot; data-start=&quot;1214&quot;&gt;ETag, Last-Modified, Cache-Control 같은 HTTP 캐시 기능을 활용합니다.&lt;/li&gt;
&lt;li data-end=&quot;1328&quot; data-start=&quot;1279&quot;&gt;중간 프록시와 CDN이 URL과 HTTP Method를 기준으로 동작할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 REST는&amp;nbsp;HTTP가&amp;nbsp;제공하는&amp;nbsp;의미(URL,&amp;nbsp;Method,&amp;nbsp;Cache)를&amp;nbsp;적극적으로&amp;nbsp;활용하도록&amp;nbsp;설계되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그에 반해 GraphQL은 일반적으로 여러 요청이 하나의 /graphql 엔드포인트와 POST 요청으로 전달됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1784467370286&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;POST /graphql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때문에 CDN이나 브라우저가 일반적인 REST GET 요청처럼 요청의 의미를 바로 파악하고 캐시하기 어렵습니다. 별도의 persisted query, GET 기반 Query, 응답 캐시 전략 등이 필요할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1643&quot; data-start=&quot;1548&quot; data-ke-size=&quot;size16&quot;&gt;또한 파일 다운로드, 정적 리소스, 웹훅, HTTP 리다이렉션처럼 HTTP 자체의 의미가 중요한 API는 REST나 일반 HTTP 엔드포인트가 더 자연스러울 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1643&quot; data-start=&quot;1548&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1643&quot; data-start=&quot;1548&quot; data-ke-size=&quot;size16&quot;&gt;GraphQL을&amp;nbsp;이해하는&amp;nbsp;가장&amp;nbsp;좋은&amp;nbsp;방법은&amp;nbsp;REST를&amp;nbsp;버리는&amp;nbsp;것이&amp;nbsp;아니라,&amp;nbsp;REST와&amp;nbsp;GraphQL이&amp;nbsp;각각&amp;nbsp;어떤&amp;nbsp;문제를&amp;nbsp;더&amp;nbsp;자연스럽게&amp;nbsp;해결하는지&amp;nbsp;이해하는&amp;nbsp;것입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL스럽다는 것은 단순히 Query를 사용하는 것이 아니라 Schema 중심, 데이터를 중심으로 사고하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL스럽게 설계하면 User, Post, Comment처럼 객체와 관계가 자연스럽게 늘어납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 객체 간 관계를 세밀하게 표현할수록 또 다른 문제가 생깁니다.&lt;br /&gt;User를 조회하면 Post를 조회하고, Post에서 Comment를 조회하고, Comment에서 Author를 조회하는 구조가 만들어질 수 있습니다.&lt;br /&gt;이것이 GraphQL에서 자주 이야기하는 N+1 문제로 이어집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL의 장점은 표현력입니다. 그리고 표현력이 커질수록 그 표현을 효율적으로 실행하는 것이 다음 과제가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음&amp;nbsp;글에서는&amp;nbsp;GraphQL의&amp;nbsp;표현력을&amp;nbsp;유지하면서도&amp;nbsp;성능과&amp;nbsp;도메인&amp;nbsp;구조를&amp;nbsp;어떻게&amp;nbsp;설계하는지&amp;nbsp;이야기해보겠습니다.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/유저 서비스 flow</category>
      <category>graphql</category>
      <category>GraphQL 철학</category>
      <category>제품 중심</category>
      <author>inspire12</author>
      <guid isPermaLink="true">https://inspire12.tistory.com/488</guid>
      <comments>https://inspire12.tistory.com/488#entry488comment</comments>
      <pubDate>Thu, 23 Jul 2026 14:33:21 +0900</pubDate>
    </item>
    <item>
      <title>GraphQL스러운 코드는 무엇일까? 2편: 다른 표현을 위한 GraphQL에서 요청을 처리하는 방식 (Schema, Resolver)</title>
      <link>https://inspire12.tistory.com/487</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inspire12.tistory.com/485&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;1편: REST와 GraphQL의 같은 의도&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784454490221&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도와 다른 표현&quot; data-og-description=&quot;회사에서 GraphQL 기반으로 클라이언트-서버 통신을 적극적으로 사용하고 있습니다. GraphQL 은 GraphQL 만의 독특한 시스템은 가장 많이 쓰이는 Rest 문법과 철학부터 사용법까지 차이가 크게 있습니&quot; data-og-host=&quot;inspire12.tistory.com&quot; data-og-source-url=&quot;https://inspire12.tistory.com/485&quot; data-og-url=&quot;https://inspire12.tistory.com/485&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/1v0oK/dJMb84qlnEj/Ow5OdP1lXDrSsGZsxoZs5K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b8VlYk/dJMb84qlnEk/QMXgyQ5icMcM8X1U49OzZ0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bojFTb/dJMb85W6bkX/Mjzn0KP8AyZZVuEzrrMbOK/img.jpg?width=455&amp;amp;height=463&amp;amp;face=0_0_455_463&quot;&gt;&lt;a href=&quot;https://inspire12.tistory.com/485&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inspire12.tistory.com/485&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/1v0oK/dJMb84qlnEj/Ow5OdP1lXDrSsGZsxoZs5K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b8VlYk/dJMb84qlnEk/QMXgyQ5icMcM8X1U49OzZ0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bojFTb/dJMb85W6bkX/Mjzn0KP8AyZZVuEzrrMbOK/img.jpg?width=455&amp;amp;height=463&amp;amp;face=0_0_455_463');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GraphQL 스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도와 다른 표현&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;회사에서 GraphQL 기반으로 클라이언트-서버 통신을 적극적으로 사용하고 있습니다. GraphQL 은 GraphQL 만의 독특한 시스템은 가장 많이 쓰이는 Rest 문법과 철학부터 사용법까지 차이가 크게 있습니&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inspire12.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;예제 코드: https://github.com/inspire12/blog-article-example-graphql-tutorial&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784461823970&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - inspire12/blog-article-example-graphql-tutorial&quot; data-og-description=&quot;Contribute to inspire12/blog-article-example-graphql-tutorial development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot; data-og-url=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d1Xlpx/dJMb9aKRLV5/5DuEqxm6kK3aFGOdqrxQGK/img.png?width=1200&amp;amp;height=600&amp;amp;face=997_125_1042_173,https://scrap.kakaocdn.net/dn/Q5yWW/dJMb88GhUlU/sKERmIaJV3yhEFdZkjP010/img.png?width=1200&amp;amp;height=600&amp;amp;face=997_125_1042_173&quot;&gt;&lt;a href=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d1Xlpx/dJMb9aKRLV5/5DuEqxm6kK3aFGOdqrxQGK/img.png?width=1200&amp;amp;height=600&amp;amp;face=997_125_1042_173,https://scrap.kakaocdn.net/dn/Q5yWW/dJMb88GhUlU/sKERmIaJV3yhEFdZkjP010/img.png?width=1200&amp;amp;height=600&amp;amp;face=997_125_1042_173');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - inspire12/blog-article-example-graphql-tutorial&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to inspire12/blog-article-example-graphql-tutorial development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1편에서는 REST와 GraphQL이 같은 목적을 서로 다른 방식으로 표현한다는 점을 살펴봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2편에서는 GraphQL에서 요청을 다루기 위해 사용하는 Resolver, Schema 등에 대한 개념을 다져나가려고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;우선 REST와 비교해서 요청을 핸들링하는 부분의 공통점과 차이점을 알면 좋습니다.&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Controller 와 Resolver&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;REST에서는 &lt;b&gt;Controller&lt;/b&gt;가 요청의 진입점입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;GraphQL에서는 &lt;b&gt;Resolver&lt;/b&gt;가 GraphQL 요청의 실행 진입점입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트의 요청은 하나의 엔드포인트(/graphql)로 전달되고, 요청한 &lt;b&gt;필드&lt;/b&gt;에 따라 &lt;b&gt;Schema&lt;/b&gt;에 연결된 &lt;b&gt;Resolver&lt;/b&gt;가 실행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST에서는 URL과 HTTP Method를 기준으로 Controller 메서드를 찾을 수 있습니다. (+ Swagger)&lt;/p&gt;
&lt;pre id=&quot;code_1784383873027&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Get(':id')
getUser(@Param('id') id: number) {
  return this.userService.getUser(id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL에서는 Query.user처럼 Schema에 정의된 타입과 필드를 기준으로 Resolver를 찾을 수 있습니다. (+ Playground)&lt;/p&gt;
&lt;pre id=&quot;code_1784383906868&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Query(() =&amp;gt; User)
user(@Args('id') id: number) {
  return this.userService.getUser(id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Resolver는 무엇을 기준으로 실행될까? Schema와 필드(field)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;REST에서는 Controller에 선언된 URL과 HTTP Method를 통해 실행할 메서드를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GraphQL의 Resolver는 &lt;b&gt;Schema&lt;/b&gt;에 정의된 &lt;b&gt;필드&lt;/b&gt;와 연결됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음과 같은 Schema가 있다고 가정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;elm&quot;&gt;&lt;code&gt;type Query {
  user(id: Int!): User!
}

type User {
  id: Int!
  name: String!
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 &lt;/span&gt;&lt;span&gt;Query&lt;/span&gt;&lt;span&gt; 타입에 정의된 &lt;/span&gt;&lt;b&gt;&lt;span&gt;user&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;b&gt; 필드&lt;/b&gt;는 다음 Resolver와 연결됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Query(() =&amp;gt; User)
user(
  @Args('id', { type: () =&amp;gt; Int }) id: number,
) {
  return this.userService.getUser(id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트가 &lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt; 필드를 요청하면 GraphQL 실행 엔진은 Schema를 기준으로 해당 필드를 확인하고, 연결된 Resolver를 실행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Schema의 Query.user
        &amp;darr;
UserResolver.user()
        &amp;darr;
UserService.getUser()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Resolver가 임의로 실행되는 것이 아니라, Schema에 정의된 필드를 기준으로 실행됩니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GraphQL Schema란 무엇일까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL Schema는 클라이언트와 서버가 통신하기 위한 계약(Contract)입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 기술적으로 표현하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL API에서 사용할 수 있는 요청(Query, Mutation, Subscription), 타입, 입력값, 반환값을 정의하는 명세입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GraphQL의 Operation에는 일반적으로 다음 세 가지가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Query&lt;/b&gt;: 데이터를 조회합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Mutation&lt;/b&gt;: 데이터를 생성하거나 변경합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Subscription: 서버에서 발생한 변경을 지속적으로 전달받습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 Schema를 다시 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1784383972457&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type Query {
  user(id: Int!): User!
}

type User {
  id: Int!
  name: String!
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 스키마만 보고도 우리는 다음 정보를 알 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;586&quot; data-start=&quot;475&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;499&quot; data-start=&quot;475&quot;&gt;user라는 Query가 존재합니다.&lt;/li&gt;
&lt;li data-end=&quot;526&quot; data-start=&quot;500&quot;&gt;id라는 Int 타입의 인자를 받습니다.&lt;/li&gt;
&lt;li data-end=&quot;545&quot; data-start=&quot;527&quot;&gt;null은 허용하지 않습니다.&lt;/li&gt;
&lt;li data-end=&quot;560&quot; data-start=&quot;546&quot;&gt;User를 반환합니다.&lt;/li&gt;
&lt;li data-end=&quot;586&quot; data-start=&quot;561&quot;&gt;User에는 id와 name이 존재합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, API를 호출하는 데 필요한 정보가 Schema에 정의되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;GraphQL 요청은 Schema를 기준으로 검증됩니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Schema는 API 문서 역할만 하는 것이 아닙니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GraphQL 서버는 요청을 실행하기 전에 Schema를 기준으로 요청이 유효한지 검증합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 다음 요청은 정상적인 요청입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;query {
  user(id: 1) {
    id
    name
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;반면 &lt;/span&gt;&lt;span&gt;User&lt;/span&gt;&lt;span&gt; 타입에 존재하지 않는 필드를 요청하면 검증 단계에서 실패합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;query {
  user(id: 1) {
    id
    age # Schema에 없는 필드
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;User&lt;/span&gt;&lt;span&gt; 타입에 &lt;/span&gt;&lt;span&gt;age&lt;/span&gt;&lt;span&gt; 필드가 정의되어 있지 않기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span&gt;Int!&lt;/span&gt;&lt;span&gt;로 정의되어 있으므로 문자열을 전달할 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;query {
  user(id: &quot;1&quot;) {
    id
    name
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GraphQL 서버는 Resolver를 실행하기 전에 다음 내용을 확인합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;요청한 필드가 Schema에 존재하는지 확인합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;필요한 인자가 전달되었는지 확인합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;인자의 타입이 올바른지 확인합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;반환 타입에서 요청할 수 있는 필드인지 확인합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;null을 허용하지 않는 값이 누락되지 않았는지 확인합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청이 검증에 실패하면 Resolver는 실행되지 않습니다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;GraphQL 요청
    &amp;darr;
Schema 기준 검증
    &amp;darr;
검증 성공
    &amp;darr;
Resolver 실행&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Schema는 단순한 API 문서가 아닙니다. 요청을 검증하는 타입 시스템이며, Resolver와 Playground도 Schema를 기준으로 동작합니다.&lt;br /&gt;그래서 GraphQL에서는 Schema가 중심이 됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;REST에도 API 명세를 기반으로 Swagger를 통해 문서화가 가능합니다.&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예제 코드 http://localhost:3000/swagger&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2426&quot; data-origin-height=&quot;1102&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pOLSQ/dJMcadpb5oP/8bvwmM25G7VWSECzv0dGL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pOLSQ/dJMcadpb5oP/8bvwmM25G7VWSECzv0dGL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pOLSQ/dJMcadpb5oP/8bvwmM25G7VWSECzv0dGL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpOLSQ%2FdJMcadpb5oP%2F8bvwmM25G7VWSECzv0dGL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2426&quot; height=&quot;1102&quot; data-origin-width=&quot;2426&quot; data-origin-height=&quot;1102&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swagger를 함께 사용하면 다음 내용을 API 문서로 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;REST에도 같은 역할을 하는 개념이 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Controller, Request DTO, Response DTO를 통해 API의 입력과 출력을 정의할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Get(':id')
getUser(
  @Param('id') id: number,
): Promise&amp;lt;UserResponse&amp;gt; {
  return this.userService.getUser(id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;class UserResponse {
  id: number;
  name: string;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 API 명세 자체가 GraphQL만의 개념은 아닙니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다만 GraphQL에서는 Schema가 문서, 타입 정의, 요청 검증, Resolver 연결의 기준을 함께 담당합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST에서는 API 정보가 Controller, DTO, Swagger 등에 흩어질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL에서는 Schema 하나가 이 모든 것의 기준이 됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;span&gt;GraphQL에서는 &lt;span&gt;Schema 기반으로&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Playground를 제공해 문서화가 가능합니다.&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예제 코드 실행 후 http://localhost:3000/graphql 접속&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2432&quot; data-origin-height=&quot;1262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnidzv/dJMcahkXNta/Y2cGQeYekjnLL88XLVQW61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnidzv/dJMcahkXNta/Y2cGQeYekjnLL88XLVQW61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnidzv/dJMcahkXNta/Y2cGQeYekjnLL88XLVQW61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbnidzv%2FdJMcahkXNta%2FY2cGQeYekjnLL88XLVQW61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2432&quot; height=&quot;1262&quot; data-origin-width=&quot;2432&quot; data-origin-height=&quot;1262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GraphQL API를 개발할 때 Playground, GraphiQL, Apollo Sandbox와 같은 도구를 함께 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 도구들은 GraphQL 요청을 작성하고 실행할 수 있는 클라이언트입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;query {
  user(id: 1) {
    id
    name
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;REST API를 테스트할 때 사용하는 Postman이나 Swagger UI와 유사한 역할을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다만 GraphQL Playground는 서버가 제공하는 Schema를 조회하여 다음 기능을 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;사용할 수 있는 Query와 Mutation을 보여줍니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;인자와 반환 타입을 보여줍니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;요청 필드를 자동완성합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Schema에 없는 필드를 요청하면 오류를 표시합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;타입 간의 관계를 탐색할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;GraphQL 서버
    &amp;darr;
Schema 제공
    &amp;darr;
Playground가 Schema 조회
    &amp;darr;
문서와 자동완성 구성&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Playground가 Resolver 코드를 직접 분석하는 것은 아닙니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Schema를 조회하고, Schema에 정의된 타입과 필드를 기준으로 UI와 자동완성을 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 Schema가 바뀌면 Playground도&amp;nbsp;자동으로&amp;nbsp;바뀝니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이처럼 GraphQL에서는 Schema가 서버와 클라이언트 도구를 연결하는 중심 역할을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;REST와 GraphQL의 요청 처리 비교&lt;/span&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 123px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;역할&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;REST&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;GraphQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;요청&amp;nbsp;진입점&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Controller&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Resolver&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;작업&amp;nbsp;식별&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;HTTP Method&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;와 URL&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Query / Mutation 필드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;입력값&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;Path, Query String, Body&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Arguments, Input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;비즈니스&amp;nbsp;로직&amp;nbsp;호출&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Service 호출&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Service 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;일반적인&amp;nbsp;응답&amp;nbsp;형식&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;JSON&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;데이터&amp;nbsp;조회&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;&amp;nbsp;Repository 또는 ORM&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Repository 또는 ORM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;계약&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;RequestDTO, ResponseDTO&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Scheme&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;문서도구&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Swagger&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;playground&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST에서는 HTTP Method와 URL이 어떤 Controller를 실행할지 결정합니다. 반면 GraphQL에서는 Schema에 정의된 필드가 어떤 Resolver를 실행할지 결정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지만 보면 GraphQL은 Controller가 Resolver로, Swagger가 Playground로 바뀐 구조처럼 보일 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 GraphQL의 핵심은 단순히 요청의 진입점이나 개발 도구가 바뀐 데 있지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL은 클라이언트가 실행할 기능뿐 아니라, 원하는 데이터의 구조까지 Query에 직접 표현하도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 글에서는 GraphQL에 왜 별도의 Query 문법이 필요한지, 그리고 이러한 표현 방식이 Schema와 Resolver 설계에 어떤 영향을 주는지 살펴보겠습니다.&lt;/p&gt;</description>
      <category>개발/유저 서비스 flow</category>
      <category>Field</category>
      <category>graphql</category>
      <category>Resolver</category>
      <category>Schema</category>
      <author>inspire12</author>
      <guid isPermaLink="true">https://inspire12.tistory.com/487</guid>
      <comments>https://inspire12.tistory.com/487#entry487comment</comments>
      <pubDate>Sun, 19 Jul 2026 18:48:29 +0900</pubDate>
    </item>
    <item>
      <title>SIPE 사담콘 5기 발표 후기</title>
      <link>https://inspire12.tistory.com/486</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Preview&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 2분기(3월~7월), SIPE(사이프) 다섯 번째 기수에 참여 했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;사이프는&lt;/span&gt; 개발자 동아리로 사이드 프로젝트 보다 다양한 활동과 네트워킹 위주의 개발자 동아리입니다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 SIPE 5기에 지원서를 내며 발표를 많이 하겠다는 이야기를 했었는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 이번 사담콘 발표를 포함해 3번의 발표를 하며 초기 목표는 달성한 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1차 라이트닝 토크쇼: 주식 관련&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;사이프톤(사이프 해커톤) 발표&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;사담콘: 개발자의 온보딩&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;---&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사담콘이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://event-us.kr/sipe/event/128290&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://event-us.kr/sipe/event/128290&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784101631842&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;SIPE 다섯 번째 컨퍼런스 - 사담콘 야호, 파라미터나 줘야지 - 이벤터스&quot; data-og-description=&quot;개발자들의 지식 공유와 네트워킹의 장 : 최신 기술 트렌드와 실무 경험을 나누는 컨퍼런스입니다.&quot; data-og-host=&quot;event-us.kr&quot; data-og-source-url=&quot;https://event-us.kr/sipe/event/128290&quot; data-og-url=&quot;https://event-us.kr/sipe/event/128290&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/93oVt/dJMb87N9fFD/jJNtaGkXIxkBHkkdKmiBD0/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/b6adNG/dJMb84qkY3k/9dFKH6uAghFVKtObieeRwk/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/MsEDs/dJMb9bwexnS/KbdYGSFjpEXHFx2ykRFxA1/img.png?width=600&amp;amp;height=350&amp;amp;face=0_0_600_350&quot;&gt;&lt;a href=&quot;https://event-us.kr/sipe/event/128290&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://event-us.kr/sipe/event/128290&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/93oVt/dJMb87N9fFD/jJNtaGkXIxkBHkkdKmiBD0/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/b6adNG/dJMb84qkY3k/9dFKH6uAghFVKtObieeRwk/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/MsEDs/dJMb9bwexnS/KbdYGSFjpEXHFx2ykRFxA1/img.png?width=600&amp;amp;height=350&amp;amp;face=0_0_600_350');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SIPE 다섯 번째 컨퍼런스 - 사담콘 야호, 파라미터나 줘야지 - 이벤터스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개발자들의 지식 공유와 네트워킹의 장 : 최신 기술 트렌드와 실무 경험을 나누는 컨퍼런스입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;event-us.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://5th-sadamcon.sipe.team&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://5th-sadamcon.sipe.team&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784101993024&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;SIPE 다섯 번째 컨퍼런스 - 사담콘 야호, 파라미터나 줘야지&quot; data-og-description=&quot;2026년 7월 11일 토요일, 서울 마포구 마포대로 122 5층 박병원홀에서 열리는 SIPE 다섯 번째 컨퍼런스 사담콘에 참여하세요.&quot; data-og-host=&quot;5th-sadamcon.sipe.team&quot; data-og-source-url=&quot;https://5th-sadamcon.sipe.team&quot; data-og-url=&quot;https://5th-sadamcon.sipe.team&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/FAxVJ/dJMb85v1sli/wOeCBEaz7T8dmoZvKUCUI1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/tBHrz/dJMb88fdanz/30djj12MuWwuZ4DpOKljBK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bn6Qkz/dJMb8TCmiyh/C1EbkNYvkz2Y37MQHhuDf0/img.jpg?width=1200&amp;amp;height=1200&amp;amp;face=609_388_717_506&quot;&gt;&lt;a href=&quot;https://5th-sadamcon.sipe.team&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://5th-sadamcon.sipe.team&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/FAxVJ/dJMb85v1sli/wOeCBEaz7T8dmoZvKUCUI1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/tBHrz/dJMb88fdanz/30djj12MuWwuZ4DpOKljBK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bn6Qkz/dJMb8TCmiyh/C1EbkNYvkz2Y37MQHhuDf0/img.jpg?width=1200&amp;amp;height=1200&amp;amp;face=609_388_717_506');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SIPE 다섯 번째 컨퍼런스 - 사담콘 야호, 파라미터나 줘야지&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2026년 7월 11일 토요일, 서울 마포구 마포대로 122 5층 박병원홀에서 열리는 SIPE 다섯 번째 컨퍼런스 사담콘에 참여하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;5th-sadamcon.sipe.team&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FZKN2/dJMcaf8kYYH/kB0cgR1VhlQMXkWOpcjF21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FZKN2/dJMcaf8kYYH/kB0cgR1VhlQMXkWOpcjF21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FZKN2/dJMcaf8kYYH/kB0cgR1VhlQMXkWOpcjF21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFZKN2%2FdJMcaf8kYYH%2FkB0cgR1VhlQMXkWOpcjF21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;475&quot; height=&quot;244&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;618&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사담콘은 SIPE의 행사 중 하나로 꽤 규모가 있는 컨퍼런스 입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참여자 분들이 자신이 겪었던 개발 경험을 나누는 자리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사담콘 준비 과정&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사담콘을 준비하며 온라인 리허설을 필수로 진행했습니다. 저를 포함한 참가자분들 모두 이 리허설이 큰 도움이 되었다고 했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서인지 다들 발표 시간도 준수하고 내용 전달도 굉장히 깔끔했었던 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표는 이전에 블로그, 링크드인에 올린 스타트업 3개월차에 적은 글을 기반으로 구성했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 때 이후로 여러 가지 생각이 섞인 부분이 있어서 제 백그라운드에 대한 지나친 소개와 AX에 대한 try catch 등을 이야기하다보니&amp;nbsp;&amp;nbsp;10분 정도 시간을 오버해서 16분 저도가 되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피드백 이후로 온보딩과 관련된 부분을 더 자세하게 다루고, 제 스토리나 AX와 관련된 부분을 제거했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덕분에 9분 정도로 이야기를 끝내고 질의 응답에 더 시간을 쏟을 수 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사담콘 후기&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 분들의 발표 내용이나 퀄리티가 상당히 좋다고 느껴졌습니다. 실제 경험을 기반으로 기술적인 이야기를 풀었는데, 지식이 많이 늘어났습니다. 다른 분들은 이런 시도들을 하고 있다는 생각도 많이 들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사담콘에는 150명 정도의 분들이 참여해주셨는데 진행도 깔끔하고 딜레이되는 부분도 없지 스무스하게 진행 된 것 같습니다. 쉬는 시간 질의응답 세션에서 저도 많이 물어본 것 같습니다. 그 과정에서 발표 때도 좋았지만, 그 뒤에 있던 이야기들도 많이 공감이 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;창완님의 경우(모던 프론트엔드 라이브러리 패키징 가이드)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nodejs 개발에 대한 어려움에 대해 이야기하면서 버전업과 하위 버전 처리에 대한 이야기도 했던 것같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상우님의 경우(AI&amp;nbsp;시대,&amp;nbsp;개발자의&amp;nbsp;AX는&amp;nbsp;무엇인가)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AX를 회사 내에 도입한 이야기를 했는데, 쉬는 시간에 말을 걸었을 때, 제 경험과 이야기하며 여러 공감을 했던 것 같습니다. 특히 저는 AX를 사용하는 도구를 만들어드려도, 막상 사용하시는 분들이 자체적으로 claude나 codex에서 자료를 던져서 해달라는 식으로 쓰는 경우가 많았습니다. 내가 만들어준 도구에 대한 러닝 커브 등 때문에 실제로 사용하지 않는 경험에 대해 공감을 했던 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진욱님은(CRUD에서&amp;nbsp;복잡한&amp;nbsp;아키텍처로:&amp;nbsp;AI&amp;nbsp;시대의&amp;nbsp;서버&amp;nbsp;엔지니어링&amp;nbsp;의사결정)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계정팀에 일하면서 설계를 작게 시작한다는 주제였는데, 저도 계정팀에서 일한 경험이 있어서 그 부분에 대한 공감대를 이야기했었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;발표 이후 질의 응답 (시간 상 못했던 것들도 포함 )&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표가 끝나고 slido를 통해 질문을 받았는데요. 현장에서 답변 드린 부분도 있지만, 답변을 못했던 부분, 생각이 정리된 부분들도 있어서 받았던 질문들에 대해 다시 답변 글을 적어보았습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;온보딩 경험을 나누어주셨는데 거꾸로 팀원을 맞이하는 기존 팀으로서 새로운 개발자 팀원의 온보딩을 효과적으로 도우려면 어떤 것을 갖추면 좋을까요?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a;&quot;&gt;- 이 부분은 팀장(매니저)의 입장과 팀원의 입장이 조금 다를 거라 생각합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot; data-poll-vote-id=&quot;1098c68b-9f7b-468e-9398-5a30ca6fbf2e&quot; data-testid=&quot;open-text-vote&quot;&gt;
&lt;div data-popover-placement=&quot;bottom&quot;&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;공통적인 부분으로 로컬에서 앱을 실행 하는 것과 팀 내 개발 문화에 대한 공유가 제일 도움이 될 것 같습니다.&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;그 다음으로는 스몰 토크 관련으로 그동안 무슨 일을 했는지에 대한 질문들과 그 일들과 팀이 그동안 했던 점과 하고자하는 부분에 교차점들을 생각해보면 좋을 것 같습니다.&amp;nbsp;&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;마지막으로 같이 페어 플래닝, 페어 프로그래밍(with AI), 페어 리뷰 형태로 진행해본다면 다른 팀, 회사에서 경험했던&amp;nbsp;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;PR 문화와 코드 리뷰 문화와의 차이점을 서로 알아가고 오해가 생길 시점들을 먼저 이야기할 수 있고 기술적인 부분도 자연스럽게 같이 이야기할 수 있었습니다. 기존 팀원 입장에서도&lt;/span&gt;&amp;nbsp;도움이 많이 되었습니다.&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;매니저의 입장에서&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;- 온보딩을 주기 위해선 짧은 주기의 확실한 목표를 주는 게 가장 중요하다고 생각합니다.&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;첫날 가장 먼저 줘야하는 건 팀 리소스에 대한 권한, 계정 신청이고 해당 프로세스를 거치고 당일에 컴퓨터에서 회사에 서버 혹은 앱을 실행하고 디버깅 등을 할 수 있으며 팀 내 lint 나 컨벤션 등에 대한 세팅을 하는 게 가장 좋다고 생각을 합니다.&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;첫 주에는 하루 단위, 그 다음은 주 단위로 해야할 일들을 체크리스트로 하다보면 개발을 진행을 하는 게 좋았던 것 같습니다.&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;만약 지연이 된다면, github 내에 코드 리뷰 했던 기록이나 git log 혹은 브랜치 등을 보게 하는 것도 꽤나 도움이 되는 부분이라고 생각합니다.&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;그리고 이런 지연점들을 모아 개선점을 잡는 게 좋지 않을까 싶습니다.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;팀원의 입장에서&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;- 팀원의 입장에서 새로운 사람과 친하게 지내고 싶어도 사실 아직 어떤 성향인지 몰라 어색하기도 하고 실제 온보딩은 팀장이 진행하고 버디가 도와주는 형태가 대부분이기 때문에 초반에 인사 정도만 나누고 질문에 대해 대답하는 게 일반적인 것 같습니다. 그리고 회사나 팀마다 다르겠지만 초창기에는 팀장님과 우선 이야기를 하고 접근하는게 좀 더 맞는 방향일 것 같습니다.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;가장 도움이 되었던 건 정리된 링크, 온보딩 문서 등에 대한 공유입니다. 대부분 문서들은 파편화되기 쉽고 보고 계신 분들이 있기 때문에 쉽사리 위치를 변경하기도 어렵습니다. 신규 입사 입장에서는 고문서 수집과 비슷한데요. 그런 부분에 대해서 링크형태로 볼 수 있는 목차가 있다면 훨씬 도움이 될 거라 생각이 듭니다.&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-testid=&quot;reaction-breakdown-popover&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;신입으로서는 어떤 마음가짐을 가지고 있어야 할지도 궁금합니다&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신입이라면, 이런 고민을 하시는 분이라면, 우선 &lt;b&gt;관찰&lt;/b&gt;을 많이 해보라고 말씀드리고 싶습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫인상이 물론 중요하고 수습을 통과해야하지만, 회사가 정말 좋은 곳인지 아닌지도 판단해야합니다. 또 마라톤이기 때문에 여유를 가지고 무엇을 먼저 해야 하는지 생각해보는 것도 중요하다고 생각합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음으로 회사에 잘 적응하고 싶다는 관점에서는 우선 팀장님이 주시는 미션들이 있다면 이게 가장 최우선이 되겠죠&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이런 온보딩이 없는 환경이라면 기존 팀원들의 일들에 대해 도움을 줄 수 있는 방법에 대해 고민하는 것입니다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;내가 이 분들의 수시/상시 업무들을 뺏어와야지, 혹은 자동화 해야 겠다.&lt;/span&gt; 도 좋은 접근일 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 팀장 입장에서는 신규 팀원이 들어오면 온보딩이란 일이 생긴 것이고, 온보딩에서 가장 어려운 부분은 신규 팀원이 어디까지 알고 있는지 입니다. 그래서&amp;nbsp;내 고민과 이해 정도를 바깥으로 공유하는 것이 꽤 좋은 전략인 것 같습니다. 발표 때도 일지를 적을 때 온보딩 문서를 최신화한다는 생각과 전략으로 진행해보라고 했던 부분입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;입사 초기에 회사에 대해 잘 모르는 상황에서 이런 말을 해도 될까하는 부분도 있었을텐데 이와 같이 내 편을 만드는 과정에서 조심스러웠던 점이나 그걸 어떻게 해결하셨는지 궁금합니다.&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분이 가장 공감이 됩니다. 잘 모르는 상황이기 때문에 최대한 근거를 우선 글로 적었습니다. 이 부분은 AI의 도움도 꽤 많이 받은 것 같습니다. 제가 잘못 생각했을 가능성도 있고, 실제로 사용되자 않는 deprecate 한 부분일 수도 있습니다. 이 부분은 레거시 히스토리가 섞여 있을 수 있어서 AI가 잘 못 잡아주던 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이야기를 꺼낼 때 최대한 가볍고 편안하게 의견을 물어봤던 것 같습니다. 가장 중요한 목적은 공감대이기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이야기를 주고 받을 때 간단하게 아 그렇구나라고 넘어갈 수도 있지만, 기술적으로 파고드는 질문을 나눌 수도 있습니다. 이럴 때 정리된 글(공식 문서의 링크, 혹인 기업의 개발 블로그 글등)을 같이 이야기를 하면서 이야기를 하면 서로 얼라인을 맞추는데 도움이 된 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 이야기를 들어줄만한 사람인지도 잘 판단해야했던 거 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;시니어면 코드리뷰뿐만아니라 스크럼이나 협의체같은 ai가 할수 없는 것도 많이 원할텐데 회사에 도입된 개발 문화가 있을까요?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 들어간 회사는 스타트업이라 기대치가 낮았는데, 생각보다 개발자 문화가 나쁘진 않았습니다. 매일 스크럼을 진행했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 B2C 서비스이기 때문에 협의체는 콜라보 관련된 내용이 많아 대부분 마케팅 선에서 끝났던 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 할 수 없는 부분은&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;당장 처리해야하는 업무들이 많으면 문서화를 계속 미루게 되는데 문서화를 해야할 좋은 시점이 있나요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;문서화는 빠르면 빠를 수도 좋습니다. 하지만 문서화는 정말 귀찮은 과정이고 의사 결정이 자주 바뀌면 문서는 쓸모가 없어지는 경우도 많습니다. 다만&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; AI가 나오면서 문서화가 너무 편해졌습니다. 내가 AI와 이야기하던 맥락과 의논 점들을 최대한 간단하게 정리해서 핵심 요약 형태로 글을 만드는 것들을 반복하고 AI에게 몇 번 피드백을 주다보면 문서화가 편해집니다. 특히 문서를 쓰려고하면 완성본부터 떠올리기 때문에 문서를 적는데 막막하고 시작하기 어려운 느낌이 강해서 미뤄지는 부분도 있는 것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀 내에 스크럼 문화가 있다면 스크럼에 적었던 맥락들을 따로 히스토리화 해보다보면 자연스럽게 문서가 되기도 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트가 끝나고 회고 모임 등을 해보는 것도 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;개인적으로 문서는 개발 관련 설명보다 &lt;b&gt;의사 결정의 히스토리(변경 사항)&lt;/b&gt;와 사용법이라면 재현 가능한 형태(스크립트 형태도 추천)와 주의할 점 정도&amp;nbsp;&lt;/span&gt;성공적이라고 생각합니다. 이 정도만 갖춰진다면 최대한 간결한 형태로 문서를 메모로서 처음 접근하고 의견을 나눠보는 식으로 방향을 잡는 걸 추천드립니다. 너무 힘을 쓰는 건 좋지 않다고 생각이 듭니다.&amp;nbsp;&amp;nbsp;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;첫&amp;nbsp;회사도&amp;nbsp;개발을&amp;nbsp;직접&amp;nbsp;하는&amp;nbsp;회사인거&amp;nbsp;같은데,&amp;nbsp;대기업을&amp;nbsp;퇴사한&amp;nbsp;이유가&amp;nbsp;궁금합니다,,&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;희망 퇴직을 해줬고 돈을 좀 많이 줬습니다.(&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;솔직하게)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;퇴직을 마음 먹을 때 &lt;b&gt;사이프 3기&lt;/b&gt;를 했었는데요. 그동안은 회사의 일들만 하다보니&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;우물 안 개구리같은 느낌을 받았고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;매너리즘과 불안감이 조금 있었지만, 밖으로 나가는 것에 대한 부담감도 있었습니다. 사이프 내에서 같이 미션을 하고 공부를 하면서 우물 밖을 경험해보니, 다른 회사에서 일하는 것도 재밌을 것 같다는 생각을 들었습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;또한 퇴사하고&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt; 회사에서 주는 월급 이외에서 돈을 벌어보는 경험을 해보고 싶었습니다. 은퇴 후에 경험할 걸 지금 해보고 싶었습니다. 내가 정말 경쟁력이 있는지 지금 확인해야 미래의 모습도 그려볼 수 있을 거라 생각을 했었습니다. 그래서 퇴사하고 바로 취업하지 않고 강사나 1인 개발자 생활을 좀 더 했던 것 같습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;저는&amp;nbsp;다음주에&amp;nbsp;스타트업으로&amp;nbsp;첫출근하는&amp;nbsp;신입입니다&amp;nbsp;시니어&amp;nbsp;관점에서&amp;nbsp;이야기해주셨는데,&amp;nbsp;같은&amp;nbsp;스타트업으로써&amp;nbsp;스타트업에서&amp;nbsp;신입이&amp;nbsp;살아남으려면&amp;nbsp;어떤거부터&amp;nbsp;해보면&amp;nbsp;좋을까요&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 시니어 연차에 가까워지다보니 시니어 기준으로 이야기를 했던 거 같습니다. 하지만, 제가 이야기한 방법들에는 연차가 그렇게 중요하진 않은 것 같습니다. (PR을 빠르게 올리는 거 정도가 훨씬 더 어려울 수는 있겠네요.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 일지를 적고, 온보딩 문서에 기여한다는 마인드를 가진 다는 부분은 꼭 적용해보셨으면 합니다. 한 번 알려준 걸 두 세번 물어보지 않을 수 있고, 제대로 이해하고 있는지 아닌지를 공개해놓는게 도움을 받기 더 쉬울거라 생각합니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;주니어나 신입 분들의 성장을 어떻게 도와드리는 게 가장 좋을까요?&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a1a1a;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;저는 의견을 나눌 때 고려한 점과 고려했어야 하는 점들을 여러 관점에서 물어봤던 것 같습니다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 기능을 추가할 때 기존 코드 내에 비슷한 부분이 있는지 확인해봤는지,&lt;/li&gt;
&lt;li&gt;코드가 과도하진 않은지, 고려할 필요없는 것까지 고려가 된 건지,&lt;/li&gt;
&lt;li&gt;DB 작업을 할 때면 쿼리 패턴과 인덱스에 대해서 고려한 부분이 있는지,&lt;/li&gt;
&lt;li&gt;IO 작업이나 비동기 타이밍 관련 이슈가 있지는 않은지,&lt;/li&gt;
&lt;li&gt;고려하지 않은 엣지 케이스들이 존재하는지,&amp;nbsp;&lt;/li&gt;
&lt;li&gt;실제 서비스에 반영 되었을 때 모니터링은 어떻게 해야할지 등등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등등&amp;nbsp;이런 질문들을 좀 정리해놓고 일정이 촉박하지 않을 때 물어보면 도움이 많이 되셨던 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;플랜 리뷰는 어떻게 진행하시나요?&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;질의응답 때는 DB 설계부터 전체적인 부분을 다 한다고 했는데요. 좀 더 정리해서 말씀을 드려보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;우선 개발을 담당한 사람이 전반적인 플랜 문서를 짜옵니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;여기에 필수적으로 들어가는 건 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AS-IS -&amp;gt; To-Be&lt;/li&gt;
&lt;li&gt;DB 스키마&amp;nbsp;&lt;/li&gt;
&lt;li&gt;요구사항 특이점과 트레이드 오프&amp;nbsp;&lt;/li&gt;
&lt;li&gt;업무 분리 및 각 플로우 설명&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;입니다. 최대한 러프하게 빠르게 진행하려고 합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;제가 아직 팀에 들어간지 얼마 안되었기 때문에 가능하다면 팀 내 플랜 문서 전에 페어 플래닝 등을 요청해서 기존 프로세스에서 놓친 부분이 있는지 의견을 나누는 편입니다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;플랜 리뷰는 그 사안에 따라 좀 다릅니다. 일반적으로 질의 응답으로 구성되고 이번에 플래닝 때 제가 들었던 건 대부분 &quot;과하다&quot; 라는 의견이었는데요. 시간이 촉박해 AI에게 많이 맡겼더니 설계가 너무 추상화가 되어버렸던 기억도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이렇게 플랜 리뷰를 거치는 가장 큰 목적은 팀원 전부가 리스크를 공유하기 위해서가 큽니다.&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;&amp;nbsp;프로덕션에 나간 코드는&lt;/span&gt; 개인의 책임이 아니라 팀의 책임으로서 되어야합니다. 로직이나 히스토리를 모르면, 다른 팀원들은 대응하기 어렵고 억울할 수도 있다고 생각합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;시니어한테 기대하는 팀원의 역할이 궁금해요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시니어한테 기대하는 팀원으로서 역할이라고 해석해서 답을 하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 저도 정확히 모르겠습니다. 팀장님도 이 부분에 대해 말할 때 굉장히 추상적으로 표현했었거든요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일정 관리부터 시작해서 팀 내 조언, 플래닝, 모니터링까지. 사실 다른 곳에서 경력을 쌓아서 실력이 좋아도 팀 내 프로세스와 코드 베이스를 완전히 이해하려면 시간이 필요하기 마련입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타트업이다보니, 시니어가 많지 않은 환경이라 시니어에 대한 환상이 있는 건가 싶기도 했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 팀원들에게 주려는 건 우선적으로 다양한 시각으로 접근하는 것과 의사 소통 이지 않을까 싶습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주니어가 많은 환경에서는 팀이 부당한 일을 받아도 그게 당연한 줄 알고 감내하는 경우도 봤습니다. 저도 그랬던 거 같고요. 그래서 책임에 대한 경계에 대해 이야기하는 것도 좀 중요하다고 생각합니다.&amp;nbsp;&lt;/p&gt;</description>
      <category>후기</category>
      <author>inspire12</author>
      <guid isPermaLink="true">https://inspire12.tistory.com/486</guid>
      <comments>https://inspire12.tistory.com/486#entry486comment</comments>
      <pubDate>Sun, 12 Jul 2026 17:25:26 +0900</pubDate>
    </item>
    <item>
      <title>GraphQL스러운 코드는 무엇일까? 1편: REST와 GraphQL의 같은 의도, 다른 표현</title>
      <link>https://inspire12.tistory.com/485</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 GraphQL 기반의 서버-클라이언트 통신을 적극적으로 사용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;GraphQL은 REST와 다른 타입 시스템과 요청 문법을 가진 API 기술입니다.&lt;span&gt; 서버-클라이언트 통신에서 널리 사용되는 REST API와는 철학부터 요청을 표현하는 방식까지 큰 차이가 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 GraphQL을 처음 문서나 책으로 접하면&amp;nbsp;이 차이점(혁신점)에만 몰두한 나머지, 사실은&amp;nbsp;같은&amp;nbsp;문제를&amp;nbsp;다른&amp;nbsp;방식으로&amp;nbsp;표현하고&amp;nbsp;있다는&amp;nbsp;점을&amp;nbsp;놓치기&amp;nbsp;쉽습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 방식 모두 클라이언트가 서버의 데이터와 기능을 사용하도록 연결한다는 목적이 있기 때문에, 공통점도 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 처음 GraphQL을 공부할 때 책으로 먼저 접했습니다. 그러다 보니 GraphQL이 기존 웹 API와는 전혀 다른 새로운 통신 시스템인 것처럼 느껴졌습니다. 그래서 실제 개발에서 쓸 때 약간의 삽질을 했던 기억이 있습니다. 오히려 REST API와 닮은 부분을 발견하고 나서야 GraphQL을 제대로 이해하기 시작했다는 생각이 들었습니다. 결국 새로운 기술도 친숙함에서 시작해야 더 빠르게 이해할 수 있는 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이번 GraphQL 관련 시리즈를 적어보면서 다음과 같은 흐름으로 글을 써보려고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;친숙함 느끼기&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;REST에서도 마주하고 해결했던 문제들&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;차이점 받아들이기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GraphQL에서 접근한 해결방식과 철학 이해하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL에서 자주 이야기되는 문제들 가운데에는 REST API에서도 마주할 수 있고, REST 방식 안에서 해결할 수 있는 것들이 많습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N+1, 데이터 오버페칭, 도메인 경계와 같은 문제들은 GraphQL에서만 발생하거나 GraphQL로만 해결할 수 있는 문제가 아니기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;299&quot; data-start=&quot;232&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;299&quot; data-start=&quot;234&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;REST의 한계를 GraphQL이 해결했다&quot; 는 말은 틀렸습니다.&lt;br /&gt;GraphQL은 새로운 문제를 해결하는 기술이라기보다, 기존 HTTP API를 다른 철학과 문법으로 표현한 기술입니다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;graphql 을 배우는 첫 단계: 친숙함부터 느끼기&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST, GraphQL 도 결국 같은 목적(서버-클라이언트 간의 통신)입니다. 그렇기에 개발자가 실제로 하는 일도 크게 다르지 않습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글의 내용을 코드로도 확인할 수 있도록 GitHub에 예제 코드를 올렸습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/inspire12/blog-article-example-graphql-tutorial&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784461802827&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - inspire12/blog-article-example-graphql-tutorial&quot; data-og-description=&quot;Contribute to inspire12/blog-article-example-graphql-tutorial development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot; data-og-url=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d1Xlpx/dJMb9aKRLV5/5DuEqxm6kK3aFGOdqrxQGK/img.png?width=1200&amp;amp;height=600&amp;amp;face=997_125_1042_173,https://scrap.kakaocdn.net/dn/Q5yWW/dJMb88GhUlU/sKERmIaJV3yhEFdZkjP010/img.png?width=1200&amp;amp;height=600&amp;amp;face=997_125_1042_173&quot;&gt;&lt;a href=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/inspire12/blog-article-example-graphql-tutorial&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d1Xlpx/dJMb9aKRLV5/5DuEqxm6kK3aFGOdqrxQGK/img.png?width=1200&amp;amp;height=600&amp;amp;face=997_125_1042_173,https://scrap.kakaocdn.net/dn/Q5yWW/dJMb88GhUlU/sKERmIaJV3yhEFdZkjP010/img.png?width=1200&amp;amp;height=600&amp;amp;face=997_125_1042_173');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - inspire12/blog-article-example-graphql-tutorial&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to inspire12/blog-article-example-graphql-tutorial development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;둘 다 CRUD를 한다&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순한 CRUD를 구현한다면 서버 내부의 애플리케이션 로직은 REST API와 GraphQL에서 크게 다르지 않을 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1783218668980&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// REST (controller)
@Get(':id')
getUser(id) {
    return userService.getUser(id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1783218681996&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// GraphQL (resolver)
@Query()
user(id) {
    return userService.getUser(id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;위와 같이 일반적으로 Service 레이어를 따로 빼서 쓰는 레이어드 아키텍처에서 만약 REST로 쓰다가 GraphQL로 마이그레이션을 한다면&lt;span&gt;&amp;nbsp;보는 것처럼&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Service 레이어와 그 밑의 레이어들은 그대로 사용할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;GraphQL 을 배우는 두번째 단계: 같은 기능, 다른 표현&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 레벨에서는 보면 비슷하지만 실제 요청을 하는 문법과 표현은 다릅니다 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GraphQL에서 데이터를 요청하는 방식&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;REST는 URL과 HTTP Method(GET, POST 등) 를 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;GET /users/1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 GraphQL API에서는 리소스별 URL마다 Controller 메서드를 연결하기보다, 하나의 GraphQL 엔드포인트로 요청을 전달합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;// 모든 요청은 일반적으로 이 엔드포인트로 전달됩니다.
POST /graphql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트는 해당 엔드포인트에 GraphQL 쿼리를 전달하여 필요한 데이터와 필드를 요청합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;applescript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;query {
  user(id: 1) {
    id
    name
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;REST는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자원 중심&lt;/b&gt;으로 표현합니다. 그래서 URL로 요청을 위한 엔드포인트를 정의할 때 명사를 쓰고, 동사를 쓰지 않습니다. (동사는 HTTP Method로 표현합니다)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;반면 GraphQL은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;무엇을 받고 싶은지&amp;nbsp;&lt;/b&gt;를 표현하는 질의 언어 형태로 요청을 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;데이터를 처리하는 방식&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 클라이언트는 GraphQL 스키마에 정의된 필드와 인자를 사용해 쿼리를 작성합니다. 서버에서는 요청된 필드에 연결된 Resolver가 실행되어 필요한 데이터를 조회합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 요청 방식은 다르지만, 서버 내부에서는 두 요청이 같은 애플리케이션 로직으로 연결될 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot;&gt;&lt;code&gt;REST Controller ─┐
                 ├─ UserService ─ Repository(Prisma) ─ Database
GraphQL Resolver ┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 GraphQL을 처음 학습할 때는 완전히 새로운 서버 구조로 접근하기보다, 기존 웹 API의 요청 진입점과 표현 방식이 바뀐 것으로 시작하는 편이 이해하기 쉽습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;GraphQL에서 요청에 응답하는 방식&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청을 표현하는 방식이 달라지는 만큼, 응답을 표현하는 방식에도 차이가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST&lt;/p&gt;
&lt;pre id=&quot;code_1784378247916&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// REST 응답 데이터
{
  &quot;id&quot;:1,
  &quot;name&quot;:&quot;영학&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL&lt;/p&gt;
&lt;pre id=&quot;code_1784378268517&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// GraphQL 질의
query {
  user(id:1){
    id
    name
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제 응답은 GraphQL 응답 규격에 따라 &lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; 객체 내부에 반환됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1784380382526&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 실제 GraphQL 응답 데이터
{ 
  &quot;data&quot;: {
    &quot;user&quot;: { 
        &quot;id&quot;: 1,
        &quot;name&quot;: &quot;영학&quot; 
     } 
   }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 둘다 json 포맷으로 진행을 합니다. GraphQL은 이 부분이 한번 래핑된 형태로 사용되지만, GraphQL 역시 HTTP에서는 일반적으로 JSON 응답을 사용합니다..&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL을 처음 배울 때는 이를 완전히 새로운 통신 구조로 받아들이기보다, 기존 API가 다루던 문제를 다른 문법과 철학으로 표현한 것으로 이해하는 편이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL이 해결하는 문제는 낯설지 않습니다. 낯선 것은 그 문제를 표현하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;물론 표현 방식이 달라진 만큼, 이를 지원하는 서버의 구성 요소와 요청 처리 방식도 달라집니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 글에서는 REST API의 요청 진입점이 GraphQL에서 Resolver로 어떻게 표현되는지, 스키마와 서버 코드는 어떻게 연결되는지, 그리고 Playground와 같은 개발 도구는 어떤 역할을 하는지 살펴보겠습니다.&lt;/p&gt;</description>
      <category>개발/유저 서비스 flow</category>
      <category>graphql</category>
      <category>graphql 시작하기</category>
      <author>inspire12</author>
      <guid isPermaLink="true">https://inspire12.tistory.com/485</guid>
      <comments>https://inspire12.tistory.com/485#entry485comment</comments>
      <pubDate>Tue, 7 Jul 2026 18:29:10 +0900</pubDate>
    </item>
    <item>
      <title>오늘의 독서: 거인의 노트</title>
      <link>https://inspire12.tistory.com/483</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Preview&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만에 개발과 관련되지 않은 책을 읽었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책을 읽게 된 건 정말 우연이었다.&lt;br /&gt;퇴근 후 혼자 공부하러 가는 작업 공간에 이 책이 있었고, 무심코 읽기 시작했다가 밤을 새우며 끝까지 읽게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 『거인의 노트』라는 제목 때문에 대단한 사람들의 성공담을 모아놓은 책이라고 생각했다.&lt;br /&gt;그런데 실제로는 &amp;ldquo;어떻게 기록해야 스스로에게 도움이 되는가&amp;rdquo;에 대한 책에 가까웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dansz3/dJMcafmgurR/i8lAEsWFBTahubA0hacwl0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dansz3/dJMcafmgurR/i8lAEsWFBTahubA0hacwl0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dansz3/dJMcafmgurR/i8lAEsWFBTahubA0hacwl0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdansz3%2FdJMcafmgurR%2Fi8lAEsWFBTahubA0hacwl0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;276&quot; height=&quot;400&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=312730732&amp;amp;srsltid=AfmBOor0f6M28XhW_qXu5t1BSRpGfrJfZGvsAfA18sPud0b0S_8gmdFG&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;출판서 링크&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;책 내용&lt;/h3&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&quot;자기화된 것만 이해할 수 있다.&quot;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책을 읽으며 가장 크게 남았던 문장이다.&lt;br /&gt;그리고 동시에 내가 그동안 느껴왔던 생각들과도 맞닿아 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무리 좋은 이야기를 들어도 사람마다 받아들이는 방식은 다르다.&lt;br /&gt;심지어 같은 사람이어도 언제 그 내용을 접하느냐에 따라 울림의 크기가 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나 역시 같은 책을 다시 읽거나, 같은 내용을 다시 공부할 때 전혀 다른 깊이로 이해되는 순간들이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 정말 이해했다고 느끼는 순간은,&lt;br /&gt;새로운 내용이 기존에 알고 있던 것들과 연결되기 시작할 때였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 연결이 바로 &amp;lsquo;자기화&amp;rsquo;인 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 연결되지 않으면 아무리 많이 봐도 이해할 수 없었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;기록은 기억이 아니라 집중하기 위함이다&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분도 정말 공감됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강의를 들을 때 수동적으로 듣기만 하는 건 생각보다 굉장히 힘들다.&lt;br /&gt;나 역시 다른 사람을 가르쳐본 경험이 있지만, 정작 누군가의 강의를 온전히 집중해서 듣는 건 쉽지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 학생들에게 무조건 열심히 들으라고 말하기도 어려웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책에서는 기록을 단순 필기가 아니라고 이야기한다.&lt;br /&gt;강사의 말을 그대로 받아 적는다고 해서 맥락까지 내 것이 되는 건 아니기 때문이다.&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;공부는 얼마나 요약을 잘하느냐이다.&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;기록은 결국 '생각'이 들어가야 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;무엇을 중요하게 느꼈는지, 왜 이 내용이 인상 깊었는지, 내가 기존에 알고 있던 것과 어떻게 연결되는지를 정리해야 비로소 내 것이 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;책은 기록에 관한 이야기지만, 오히려 기록에 너무 많은 시간을 쓰지 말라고 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;잠깐 고개를 들고 생각을 정리하는 시간이 없으면 좋은 기록은 나오기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 밖에도 책에는 정말 공감되는 이야기들이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;휘발되는 지식을 붙잡고 싶은 마음,&lt;br /&gt;나를 이해하기 위한 기록 방법,&lt;br /&gt;중요한 경험을 남기는 습관,&lt;br /&gt;한 가지 주제를 끝까지 붙들고 생각하는 힘.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 잡념 없이 하나의 생각을 오래 유지하며 스토리를 만들어가는 과정에 대한 이야기가 인상 깊었다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어릴 때의 나는 책 읽는 걸 좋아했다.&lt;br /&gt;공부도 좋아했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글을 읽으며 여러 방향으로 생각을 확장하는 과정이 정말 재미있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 학원을 다니고 선행학습을 하면서부터,&lt;br /&gt;맥락보다는 이미 정리된 답을 빠르게 받아들이는 방식에 익숙해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스스로 생각하고 자기화할 시간 없이&lt;br /&gt;외우는 게 정답이라고 믿게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때부터 공부가 재미없어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중학교와 고등학교 시절에는 책도 점점 덜 읽게 되었다.&lt;br /&gt;내 생각으로 판단하는 게 두려웠고,&lt;br /&gt;내 방식이 틀렸다고 느끼기도 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;돈을 썼지만 아이러니하게도 성적도 오히려 떨어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 대학교와 회사에서 다시 스스로 답을 찾아가는 경험을 하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배움의 중심에 내가 있는 상태였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 결과를 떠나서 그 과정 자체가 정말 재미있었다.&lt;br /&gt;그리고 그런 경험들은 지금까지도 오래 기억에 남아 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책은 내가 좋아했던 배움의 방식이 무엇이었는지 다시 떠올리게 해준 책이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 누군가를 가르칠 때도, 결국 중심에는 자기 자신이 있어야 한다는 걸 다시 느끼게 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무엇보다 내가 지금 가고 있는 방향이 틀리지 않았다는 확신을 준 책이었다.&lt;/p&gt;</description>
      <category>후기</category>
      <author>inspire12</author>
      <guid isPermaLink="true">https://inspire12.tistory.com/483</guid>
      <comments>https://inspire12.tistory.com/483#entry483comment</comments>
      <pubDate>Sun, 10 May 2026 19:46:14 +0900</pubDate>
    </item>
    <item>
      <title>2026 소비자 브랜드 AX 서밋 후기 (달파, aws, databrick)</title>
      <link>https://inspire12.tistory.com/482</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Preview&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4월 마지막 날 달파에서 진행한 소비자 브랜드 AX 서밋을 다녀왔습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교육 휴가도 쓸 겸 다른 분야에선 AI를 어떻게 쓰고 있는지 궁금해서 신청하게 되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;1부는 소비재에서 AX와 트랜드에 대한 내용&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2부는 AX를 실제로 실현하기 위한 본인의 경험이 주요 내용이었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1부는 소비재 도메인의 비전공자 분들을 대상으로 진행한 내용이 많다는 인상을 받았습니다. 제가 소비재 쪽 지식이 있었다면 인사이트가 있었겠지만, 그렇지 않아서 아쉬웠습니다.&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;비전공자도&amp;nbsp;&lt;/span&gt;AI를 도입할 수 있다와 데이터 축적 필요성 등 이미 인지하는 내용이기도 했습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2부는 실제 AX 도입과정의 시행착오와 함께, 제가 고민하고 해결하려고 하는 분야이기 때문에 공감되고 도움되는 내용이 많았습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;행사 페이지&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://event-us.kr/dalphaax/event/123245&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://event-us.kr/dalphaax/event/123245&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1777792095603&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;BRAND AX SUMMIT 2026 - 이벤터스&quot; data-og-description=&quot;글로벌 AI 트렌드부터 실제 기업 사례까지, 소비재 브랜드 AX를 입체적으로 이해하기 위한 컨퍼런스&quot; data-og-host=&quot;event-us.kr&quot; data-og-source-url=&quot;https://event-us.kr/dalphaax/event/123245&quot; data-og-url=&quot;https://event-us.kr/dalphaax/event/123245&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cME6Eo/dJMb85vSBIz/DJ587R4IBkCHEBQ41sWpNK/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/oBtfD/dJMb84qcgtV/sfEbP6yLKlD3eGe8L1YKT0/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/Isbdw/dJMb8UHSMCS/KrDBAvqmR2aKy7pejVSBNK/img.png?width=600&amp;amp;height=350&amp;amp;face=0_0_600_350&quot;&gt;&lt;a href=&quot;https://event-us.kr/dalphaax/event/123245&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://event-us.kr/dalphaax/event/123245&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cME6Eo/dJMb85vSBIz/DJ587R4IBkCHEBQ41sWpNK/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/oBtfD/dJMb84qcgtV/sfEbP6yLKlD3eGe8L1YKT0/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540,https://scrap.kakaocdn.net/dn/Isbdw/dJMb8UHSMCS/KrDBAvqmR2aKy7pejVSBNK/img.png?width=600&amp;amp;height=350&amp;amp;face=0_0_600_350');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;BRAND AX SUMMIT 2026 - 이벤터스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;글로벌 AI 트렌드부터 실제 기업 사례까지, 소비재 브랜드 AX를 입체적으로 이해하기 위한 컨퍼런스&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;event-us.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;패션기업의 Agent 구현사례: AI Ready Data의 중요성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;F&amp;amp;F 디지털 본부 프로세스 담당 박봉섭 이사&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인상깊었던 세션은 마지막 세션은 마지막에 있었던 이 세션이었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금처럼 AI가 대단해지기 전부터 AI를 도입하기위해 노력을 했고 몇 년에 걸쳐 실제로 많은 실패들이 있었습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1차 시도 RAG &amp;rArr; 실패&lt;/li&gt;
&lt;li&gt;2차 시도 Text To SQL &amp;rArr; 실패&lt;/li&gt;
&lt;li&gt;3차 시도 MCP - snowflake 오픈 시 바로 &amp;rArr; 실패&lt;/li&gt;
&lt;li&gt;4차 시도 openAI Vector store &amp;rarr; 문서량 많으면 할루시네이션 &amp;rArr; 실패&lt;/li&gt;
&lt;li&gt;5차 시도 Snowflake Semantic layer &amp;rarr; &amp;rArr; 보류&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6차에선 직접 온톨로지를 만들고 AI Agent 생태계를 구성하고자 했습니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API 호출이 아니라 기능의 본질적인 의미를 이해&lt;/li&gt;
&lt;li&gt;온톨로지나 지식 그래프&lt;/li&gt;
&lt;li&gt;컴퓨터가 이해할 수 있도록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PoC 까진 성공적이었지만, Production으로 갈때 문제가 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;토큰 비용&lt;/li&gt;
&lt;li&gt;Agent 도구: 자체 도구의 한계&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 그 사이 AI가 발전해 Claude opus 가 되면서 지식 그래프 검색 성능 및 토큰 효율성이 증가하며 진정한 의미로 AX가 가능해졌다고 했습니다. 그리고 이런 Agent의 발전으로 인해 mcp 를 줄이고 cli 형태로 전환하며 전사적으로 사용하는 AX 시스템 구축이 되었다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2OW7q/dJMcahqLAIM/cwfVKLBamzStIwh3b9vbPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2OW7q/dJMcahqLAIM/cwfVKLBamzStIwh3b9vbPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2OW7q/dJMcahqLAIM/cwfVKLBamzStIwh3b9vbPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2OW7q%2FdJMcahqLAIM%2FcwfVKLBamzStIwh3b9vbPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;602&quot; height=&quot;448&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8THDT/dJMcaiDaX7w/Olkhk8tBkPZstMMNa0Spi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8THDT/dJMcaiDaX7w/Olkhk8tBkPZstMMNa0Spi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8THDT/dJMcaiDaX7w/Olkhk8tBkPZstMMNa0Spi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8THDT%2FdJMcaiDaX7w%2FOlkhk8tBkPZstMMNa0Spi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;602&quot; height=&quot;448&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 또한 이슈가 있었는데요. 바로 실무자들이 &quot;검은 화면의 cli 터미널 환경을 쓸 줄 모른다는 것이었습니다.&quot;&amp;nbsp; 개발자가 아니다보니 당연한 부분이었습니다. 결국 AX는 실무자들에게 도움이 되어야하는데, 모든 실무자들을 만족하는 환경을 구축하긴 불가능합니다. cli 환경은 이런 상황에 특화되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기때문에 현재는 매 주 금요일마다 전사적인 온라인 강의를 통해 지속적으로 클로드 코드와 cli 사용법에 대한 교육을 진행한다고한 부분도 크게 인상 깊었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AX가 실제로 작동을 한다는 걸 알게되면 온갖 부서로부터 요구사항이 몰리게 됩니다. 그렇기 때문에 이때는 업무의 우선 순위를 제대로 세우는게 중요해집니다. 매출이나 운양&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;브랜드 AX의 실제 구현 Use Case 와 Agentic OS&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;달파 유선빈 이사&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에 소개할 내용은 달파가 어떻게 AI Agent를 work 시키는지에 대한 내용이었습니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소비재 데이터를 어떻게 지식 그래프와 온톨로지를 만들어서 AI&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 구조로 만드는지에 대한 내용까지 상당히 인상 깊었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;산업 분야별로 온톨로지 형태를 만들고 그 다음에 기업이나 프로젝트에 특화된 형태로 재구축하는 방향이&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 팀 내 개발자들이 쓰는 AX 방법들을 한 곳에 모아야한다는 내용이 굉장히 인상 깊었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AX skill, tool 에 대한 정리 필요 &amp;amp; 사용에 대한 도구 필요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;1010&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sJ64T/dJMcahEf5ra/fcQUmEHz0S1kXOzYANL5i0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sJ64T/dJMcahEf5ra/fcQUmEHz0S1kXOzYANL5i0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sJ64T/dJMcahEf5ra/fcQUmEHz0S1kXOzYANL5i0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsJ64T%2FdJMcahEf5ra%2FfcQUmEHz0S1kXOzYANL5i0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;651&quot; height=&quot;459&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;1010&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1552&quot; data-origin-height=&quot;1118&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWrlZb/dJMcafNgSfB/q3kFYX0F098Owv8LXDzvsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWrlZb/dJMcafNgSfB/q3kFYX0F098Owv8LXDzvsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWrlZb/dJMcafNgSfB/q3kFYX0F098Owv8LXDzvsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWrlZb%2FdJMcafNgSfB%2Fq3kFYX0F098Owv8LXDzvsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;638&quot; height=&quot;460&quot; data-origin-width=&quot;1552&quot; data-origin-height=&quot;1118&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IC4LI/dJMcah5m3TE/YRrAmOVQc6w4l8tVwkt2MK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IC4LI/dJMcah5m3TE/YRrAmOVQc6w4l8tVwkt2MK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IC4LI/dJMcah5m3TE/YRrAmOVQc6w4l8tVwkt2MK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIC4LI%2FdJMcah5m3TE%2FYRrAmOVQc6w4l8tVwkt2MK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;582&quot; height=&quot;440&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;AX 시대, 소비재 브랜드가 나아가야 할 방향은?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Beauty Selection 구본호 Head of AX&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째로 인상 깊었던 내용이었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 엑셀로 데이터를 다루고 있는 산업 현장에서 어떻게 AI를 도입해서 AX로 전환을 할 수 있는지가 큰 주제였습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 데이터를 한 곳에 모아야한다는 내용이 핵심이었습니다.&amp;nbsp; 그렇지 않고 개개인이 AI를 도입하면 모든 정보는 흩어지게됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;828&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/15FbB/dJMcadojI0j/mFuMRFcAHtYgFhu28KcPik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/15FbB/dJMcadojI0j/mFuMRFcAHtYgFhu28KcPik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/15FbB/dJMcadojI0j/mFuMRFcAHtYgFhu28KcPik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F15FbB%2FdJMcadojI0j%2FmFuMRFcAHtYgFhu28KcPik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;443&quot; height=&quot;271&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;828&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1326&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Duhq0/dJMcaarDKzm/HaJ2T06Z3bVUi155YQnrNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Duhq0/dJMcaarDKzm/HaJ2T06Z3bVUi155YQnrNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Duhq0/dJMcaarDKzm/HaJ2T06Z3bVUi155YQnrNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDuhq0%2FdJMcaarDKzm%2FHaJ2T06Z3bVUi155YQnrNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;446&quot; height=&quot;296&quot; data-origin-width=&quot;1326&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1888&quot; data-origin-height=&quot;1126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byuEh6/dJMcab48dIm/Io9NTRMoaS2CFYEkG70d51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byuEh6/dJMcab48dIm/Io9NTRMoaS2CFYEkG70d51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byuEh6/dJMcab48dIm/Io9NTRMoaS2CFYEkG70d51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyuEh6%2FdJMcab48dIm%2FIo9NTRMoaS2CFYEkG70d51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;555&quot; height=&quot;331&quot; data-origin-width=&quot;1888&quot; data-origin-height=&quot;1126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 다양한 리더 입장분들에게서 들은 AI 도입에 대한 생각을 이야기한 부분도 인상깊었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;942&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDfgeH/dJMcadojJFA/4NOWqMJSZJkeRdHV0DrgBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDfgeH/dJMcadojJFA/4NOWqMJSZJkeRdHV0DrgBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDfgeH/dJMcadojJFA/4NOWqMJSZJkeRdHV0DrgBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDfgeH%2FdJMcadojJFA%2F4NOWqMJSZJkeRdHV0DrgBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;560&quot; height=&quot;354&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;942&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lmJsZ/dJMcacprKRb/27IbFbaRueDkW5eeZ02CFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lmJsZ/dJMcacprKRb/27IbFbaRueDkW5eeZ02CFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lmJsZ/dJMcacprKRb/27IbFbaRueDkW5eeZ02CFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlmJsZ%2FdJMcacprKRb%2F27IbFbaRueDkW5eeZ02CFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;478&quot; height=&quot;347&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AX는 결국 사업을 잘 이해하는 사람이 가능합니다. 즉 엔지니어도 사업을 잘 이해 해야합니다. 엔지니어도 기획을 할 수 있어야 한다는 내용은 저도 크게 공감을 했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 내용이 사업이 엔지니어링을 이해해야 된다면 이번엔 엔지니어도 사업을 이해해야한다는 내용이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통적으로 이야기하는 건 AX를 도입을 하기위해서 현재 일하는 방식들을 정리하고, 사용하는 데이터의 의미를 구체화하고 데이터 구조를 세워야한다는 내용이었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 데이터 리터러시가 마련이되어야 회사에 도움이되는 AX가 가능해집니다. 이전 글에도 적었지만 도구에 매몰되는 게 아니라 데이터의 주권을 가져오는 것이 중요하며, 그 이후 전사적으로 참여가 이루어져야한다는 것도 공감이 되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔지니어도 사업을 잘 이해해야하고 사업도 엔지니어링을 이해하는 게 필수라는 것에 큰 공감을 얻었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 컨퍼런스를 들으며 제가 회사에서 하고자 하는 방향이 그래도 틀리진 않았다는 생각이들었습니다. 그건 하나 얻어간 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 다니는 회사가 인간 관계를 깊게 하는 과정, 사랑이란 감정을 다루다보니 데이터화 시킨 다는 게 쉽지가 않습니다. 데이터화 시키고 AI와 연결하기 위해서 어떻게 해야할지 많은 고민을 하게 된 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>후기</category>
      <author>inspire12</author>
      <guid isPermaLink="true">https://inspire12.tistory.com/482</guid>
      <comments>https://inspire12.tistory.com/482#entry482comment</comments>
      <pubDate>Thu, 7 May 2026 00:17:26 +0900</pubDate>
    </item>
  </channel>
</rss>