<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[재그지그의 개발 블로그]]></title><description><![CDATA[웹 프론트엔드 개발과 관련한 포스트를 작성하고 있습니다.]]></description><link>https://wormwlrm.github.io</link><generator>GatsbyJS</generator><lastBuildDate>Mon, 06 Apr 2026 17:59:00 GMT</lastBuildDate><item><title><![CDATA[나는 하루 5분만 바꾸기로 했다]]></title><description><![CDATA[책 『나는 하루 5분만 바꾸기로 했다』를 읽고 작성한 서평입니다.]]></description><link>https://wormwlrm.github.io/2026/04/07/I-decided-to-change-it-for-only-five-minutes-a-day.html</link><guid isPermaLink="false">https://wormwlrm.github.io/2026/04/07/I-decided-to-change-it-for-only-five-minutes-a-day.html</guid><pubDate>Tue, 07 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1944263718896af5d2408d94606c0214/29d31/1.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.12883435582822%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAMEAgEF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAC/9oADAMBAAIQAxAAAAHFcro4JKbRFo088oH/xAAbEAACAgMBAAAAAAAAAAAAAAABAgARAxIhIv/aAAgBAQABBQLJSxQpDPjDUXhXzoWgHFFDZYTRdjd9/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8BiT//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwGDP//EABsQAAICAwEAAAAAAAAAAAAAAAARITEBAkGh/9oACAEBAAY/AqHAl4WPWx51ktEnCCzJ/8QAHhABAAICAgMBAAAAAAAAAAAAAQARITFBUWFxgZH/2gAIAQEAAT8hqBpe6hJAxeSPuDqaFcXcUyEQ1F5ITUNm4lKt7lTltG9aBFL9ivvP/9oADAMBAAIAAwAAABDr68L/xAAXEQEBAQEAAAAAAAAAAAAAAAABEQAh/9oACAEDAQE/EJ2OmMaam//EABcRAAMBAAAAAAAAAAAAAAAAAAABESH/2gAIAQIBAT8QuVGjGoRn/8QAHhABAAMAAgIDAAAAAAAAAAAAAQARITFBUXFhocH/2gAIAQEAAT8QFu24q6eomjRTR+o+dZUEYvdQrPyGE4QvmKq2dLT5plT2rNB3oj7Tvt4i5TTbaQbaqTx3CQZVwUhoGT//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;북카페에서&quot;
        title=&quot;북카페에서&quot;
        src=&quot;/static/1944263718896af5d2408d94606c0214/6aca1/1.jpg&quot;
        srcset=&quot;/static/1944263718896af5d2408d94606c0214/d2f63/1.jpg 163w,
/static/1944263718896af5d2408d94606c0214/c989d/1.jpg 325w,
/static/1944263718896af5d2408d94606c0214/6aca1/1.jpg 650w,
/static/1944263718896af5d2408d94606c0214/29d31/1.jpg 700w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;햇볕이 따스하니 책 읽기 좋은 날씨였다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;날씨가 좋았던 지난 주말, 올해의 첫 책을 읽었습니다. 마포에 있는 &lt;a href=&quot;https://naver.me/56R6OkJX&quot;&gt;채그로&lt;/a&gt;라는 북카페였는데, 창문으로 보이는 한강 전망이 참 예쁘더라고요.&lt;/p&gt;
&lt;p&gt;이 책은 예전 글또에서 만났던 &lt;a href=&quot;https://www.jeewhan.com/&quot;&gt;지환&lt;/a&gt;님께 선물받은 책입니다. 이 책을 받은 건 아마 3년 전쯤이었던 것 같아요. 당시 글또 운영진 모임에서 비슷한 주제로 고민을 나눴고, 그때 지환님이 이 책을 소개해 주셨던 것으로 기억합니다.&lt;/p&gt;
&lt;p&gt;이 책을 다시 읽게 된 계기는 작년에 &lt;a href=&quot;/2025/12/31/2025-Retrospect.html&quot;&gt;연말 회고&lt;/a&gt;를 쓰면서입니다. 회사 업무가 바빠지기도 하고 자기 계발을 할 시간이 줄어들다 보니 내가 바라는 모습을 잘 지키지 못하고 살아가고 있다는 느낌을 많이 받았습니다. 운동이나 책 읽기, 글쓰기처럼 노력을 들여야 하는 활동의 우선순위가 밀리니까 스스로가 &lt;em&gt;게을러지지 않았나&lt;/em&gt; 싶은 생각이 들었습니다.&lt;/p&gt;
&lt;p&gt;사실 기존에도 루틴 관리를 유지해 보려는 시도가 있었지만, 언젠가부터 매너리즘을 느꼈는지 루틴을 꾸준히 지키고 최신화하려는 노력을 잘 이어가지 못했습니다. 회고를 정리하다 보니 그 공백이 한꺼번에 크게 느껴지더라고요.&lt;/p&gt;
&lt;p&gt;그래서 올해 세운 목표 중 하나가, 바로 &lt;strong&gt;노력을 들여야 하는 습관을 붙들 수 있는 보상 체계를 제대로 고민해 보는 일&lt;/strong&gt;이었습니다. 작게라도 매일 이어지는 루틴과, 그걸 유지하게 만드는 동기 부여가 어떻게 맞물려야 하는지 다시 정리해 보고 싶었습니다.&lt;/p&gt;
&lt;p&gt;이번 포스트를 통해 &lt;strong&gt;삶의 계획을 세우긴 하지만 이를 잘 지키지 못하고 무너지는 분&lt;/strong&gt;들께 도움이 되었으면 좋겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;책-소개&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B1%85-%EC%86%8C%EA%B0%9C&quot; aria-label=&quot;책 소개 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;책 소개&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/66390c9c9b7d688b17035e3d14a2fac4/9cab2/2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 85.2760736196319%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAACW0lEQVQ4y5WUS09TURCA+U0uXBDUNQQVdScbEx+RjY/E+AATTUiUBKPRhcbErRhirJQC0iZQCm2ppRRa6ItHK4K0ty339j7aYl+fsS2oCLRMMpnJOXO+zJwzZxrYI6VSqWLL/sFajd6N35GGv0E7m4V8jlIxB6U8lHK/V4B81Va0UMxXwf9C9wUqsojXv8JX9xKu+WXMdj8uzwrOuRVsM0u4F8NoaeW/cwcCZVnC5gxgsiww6QgwZvVhtgewOkOMWQNYZ0JHA2pqCkmMkZLiZLQk8YSAEBfQlC1keQstLZHNqrt3WROoqlIZKMtJwhtJzM4NTK4fhMIx0mmJTPaoQCWFkhLwR+KM+0Rs7hhGxzpzgQRLUQlRTJDJquVWqLNkiWQixqRXwBIUmfULTLvWWFiMM+2JIiQSZLcrGZbqeeW0lmJbS+JZFZmKKKxtKnyLqURWRSIbMilVYvun9qdnawGTYhLbjJ/3Iz7e6IP0jwZ5NxKifyiAzbtOOiuSzsj196GaUvF6Nuj7tMj5a0Mca/3AqYsDDBojCFEFcnmKuVz9GQYFD/bvX/DEzRi8Bno/99F8/zmmgBHHpokBrw6fMFe7DwulQtl/5nrM5dELPLTconOqgyvjp2kbbuSMvom38y/ocXbyyH67NrBYBb5yP+HBRAcvnd102+5yx3yV9pEWbk5cQpA3CcYXeD3fW5kgh5W8k2GPs4sW3XHah5s5q2+iTX+Cc/qTtA408tTRyT3LdbqsN+r/eh7BxfCyDlN4CGPYgHF1cFcNyx/RhfqYjToOB+6dh/XIfrG/AD5I7f2borYbAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;표지&quot;
        title=&quot;표지&quot;
        src=&quot;/static/66390c9c9b7d688b17035e3d14a2fac4/a6d36/2.png&quot;
        srcset=&quot;/static/66390c9c9b7d688b17035e3d14a2fac4/222b7/2.png 163w,
/static/66390c9c9b7d688b17035e3d14a2fac4/ff46a/2.png 325w,
/static/66390c9c9b7d688b17035e3d14a2fac4/a6d36/2.png 650w,
/static/66390c9c9b7d688b17035e3d14a2fac4/9cab2/2.png 864w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이 책은 루틴 관리 앱 &lt;a href=&quot;https://myroutine.today/ko&quot;&gt;마이루틴&lt;/a&gt;의 대표 옥민송 님이 쓴 책입니다. 목표나 계획을 세우더라도 이것을 꾸준히 지키는 것은 매우 힘든데, 이를 사소한 성취로부터 시작해서 점차적으로 쌓아 가는 방법을 소개하는 자기 계발서입니다.&lt;/p&gt;
&lt;p&gt;책은 총 4장으로 나뉘어 있으며, 다음과 같은 내용을 다루고 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;1장: 루틴의 필요성 알기&lt;/li&gt;
&lt;li&gt;2장: 아주 작은 루틴으로 시작하기&lt;/li&gt;
&lt;li&gt;3장: 뼈대 루틴 세우고 가지 루틴 쌓기&lt;/li&gt;
&lt;li&gt;4장: 루틴 세트 유지하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;분량은 약 270쪽 정도로, 여유롭게 시간을 내어 읽으면 하루 만에도 부담 없이 완독할 수 있는 정도의 분량이었습니다. 자기계발서인 만큼 별도의 사전 지식은 필요하지 않고, 저자의 경험과 사례를 중심으로 이야기가 전개되기 때문에 편안하게 읽을 수 있었습니다.&lt;/p&gt;
&lt;p&gt;그럼 지금부터 각 장에서 인상 깊었던 내용을 정리해 보겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;루틴의-필요성-알기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%A3%A8%ED%8B%B4%EC%9D%98-%ED%95%84%EC%9A%94%EC%84%B1-%EC%95%8C%EA%B8%B0&quot; aria-label=&quot;루틴의 필요성 알기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;루틴의 필요성 알기&lt;/h2&gt;
&lt;p&gt;이 책을 읽은 이유는 작년에 연말 회고를 하면서 내가 바라던 모습을 잘 지키지 못하고 있다는 생각이 들었기 때문이라고 말씀드렸습니다. 그래서 루틴 관리를 통해 내가 얻을 수 있는 것이 무엇인지에 대한 호기심이 있었는데, 이를 1장에서부터 짚고 넘어갑니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;내가 삶의 고점에 있든 저점에 있든, 치열하게 살든 느긋하게 살든 나를 위한 작은 행동을 실천하고 마음에 드는 순간을 늘려가고 있다. 하루하루 작은 성취감을 쌓아가는 일상에 감사하고 덕분에 힘든 순간이 와도 스스로를 잘 받아들일 수 있다.
…
내 삶을 잘 살아가기 위해서는 자기 신뢰가 필요하다. 나를 믿을 수 있을 때 일상은 보다 여유로워지고 위기는 덜 두려워지니까.&lt;/p&gt;
&lt;p&gt;- 55p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;저자는 루틴의 필요성 중 하나로 &lt;strong&gt;자기 신뢰의 구축&lt;/strong&gt;을 이야기합니다. 누구나 삶을 살아가다 보면 힘든 시기가 오기 마련인데, 루틴은 그럴 때마다 자신을 믿고 지탱해 줄 수 있는 근거가 된다는 내용입니다. 지금까지 루틴은 목표를 향해 나아가는 수단으로만 생각했는데, 이 부분을 읽으면서 루틴이 일종의 심리적 안전망 역할도 할 수 있겠다는 생각이 들어 흥미로웠습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;작은 루틴은 오래 했을 때 큰 힘을 발휘한다.
…
목표를 달성하는 방법은 하나가 아니니까 자신에게 맞는 방법을 찾을 때까지 짧게 짧게 시도해보는 게 좋다. 남들에게는 어렵지만 내게는 쉬운 게 있다. 남들에게는 재미없지만 내게는 즐거움을 주는 것도 있다.&lt;/p&gt;
&lt;p&gt;- 63p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;보통 새해 목표를 세우게 되면 욕심이 생겨서 자기 자신을 루틴에 맞추게 되는 경우가 많습니다. 하지만 저자는 내가 이미 습관적으로 하고 있는 행동을 루틴화하고 이를 기반으로 루틴을 확장해 나가는 방법을 제안합니다. 한 번 세운 루틴을 끝까지 지키려고 하기보다는, 나에게 맞는 방법을 찾기까지 꾸준한 수정과 시도가 필요하다고 강조합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;정리하고 나니 하루에 몇 시간씩, 한 달 만에 다 끝내버리고 싶은 욕심이 생겼지만 참았다. 결국 성공하지 못할 테니까.
…
이 루틴은 100일만 하기로 마음먹었다.
…
막연히 늘어지는 것보다는 마무리를 정해야 지속할 수 있을 것 같았다.&lt;/p&gt;
&lt;p&gt;- 69p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;저는 어떤 일을 할 때 한꺼번에 끝내려고 하는 경향이 강합니다. 그리고 어떤 목표를 세우면 꾸준히 해야 한다고 생각합니다. 그렇지만 시간이 갈수록 이를 잘 지키지 못하는 경우가 많아졌고 스스로를 게으르다고 생각하곤 해서 이 부분을 읽으면서 좀 찔렸네요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;나는 성장이 필요한 매 순간 시험 기간처럼 살았다.
…
머릿속에 자리 잡은 강박이 몸도 마음도 불편하게 만들 뿐이었다.
…
그래서 요즘은 성장에 대한 조급함이 생기면, 5분만 써서 무엇을 할지를 정한다.
…
성장에는 시간이 걸린다.&lt;/p&gt;
&lt;p&gt;- 72p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;루틴이 강박이 되지 않도록, 그리고 조급한 마음이 들면 조그마한 무언가라도 해보는 것을 추천하는 부분입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;나는 무리하는 시기에는 모든 것을 챙기려고 하지 않는다.
…
동시에 아무리 힘든 시기에도 어떤 선 아래로 떨어지지 않도록 노력한다.
…
내가 좋은 시기에도, 힘든 시기에도 변함없이 나를 챙기고 있다는 증거가 되기 때문이다. 삶의 오르막에서도 내리막에서도 내가 스스로를 챙기고 있다는 사실 자체가 주는 안정감이 있다.&lt;/p&gt;
&lt;p&gt;- 91p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;루틴을 아주 엄격하게 지킬 필요는 없지만, 그렇다고 해서 루틴을 완전히 놓아버리지는 말라는 내용입니다. 저는 사실 루틴을 만들었지만 내려놓았던 적이 많았거든요. 제게 이 부분은 마치 상방과 하방이 있는 루틴 세트를 관리하는 느낌으로 읽혔습니다. 좋은 시기에는 루틴을 확장해 나가고, 힘든 시기에는 루틴의 바닥을 지키는 식으로요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;감정 일기를 쓰다 보면 스트레스 받을 때의 행동 패턴이 보인다.&lt;/p&gt;
&lt;p&gt;- 93p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;본인의 일상에 대한 메타 인지가 있어야 루틴도 잘 관리할 수 있다는 내용입니다. 메타 인지를 중요하게 생각하는 저에게도 와닿는 부분이었습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;가끔 넘어지면 많은 생각을 하지 않고 잘 주저앉아 있다가, 잘 일어나려 한다.
…
매일 기본 루틴을 지키다 보면 지금 이 순간도 지나가는 시간임을 느낀다. 기본 루틴이 나의 바닥을 높여주었고 그 바닥에서 빠져나오는 것을 도와주었다.&lt;/p&gt;
&lt;p&gt;- 96p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;어느 정도 반복되는 말이지만 루틴이 일종의 심리적 안전망 역할을 한다는 점이 다시 한 번 강조되는 부분입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;원하는 게 있는데 아무리 생각해도 쉬운 방법이 떠오르지 않거나 빠른 시간 안에 해야 한다면 할 수밖에 없는 환경을 세팅한다.&lt;/p&gt;
&lt;p&gt;- 102p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;큰 목표만 세워 두고 매일의 실행이 비어 있으면, 결국 &lt;em&gt;언젠가 해야지&lt;/em&gt; 로 남기 쉽다는 이야기가 1장 전체에 깔려 있는 메시지처럼 느껴졌습니다. 제가 올해 고민하고 있는 보상 체계도 결국 &lt;em&gt;매일 조금이라도 움직이게 만드는 장치&lt;/em&gt; 에 가깝기 때문에 와닿았습니다.&lt;/p&gt;
&lt;h2 id=&quot;아주-작은-루틴으로-시작하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%95%84%EC%A3%BC-%EC%9E%91%EC%9D%80-%EB%A3%A8%ED%8B%B4%EC%9C%BC%EB%A1%9C-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0&quot; aria-label=&quot;아주 작은 루틴으로 시작하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;아주 작은 루틴으로 시작하기&lt;/h2&gt;
&lt;p&gt;2장에서는 내 일상으로부터 루틴을 시작하는 방법에 대해 알아봅니다. 나를 루틴에 맞추는 것이 아닌, 루틴을 나에게 맞추는 것으로부터 시작합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;루틴 관리를 더는 미룰 수 없다고 결심하고 제일 먼저 한 것은 일상 돌아보기였다.
…
나는 아침부터 저녁까지 하루 일과를 돌아보며 아침에 눈 떠서 밤에 잠들 때까지 어떤 행동을 하는지, 그 중 반복하는 활동이 있는지, 앞으로도 계속 하고 싶은 행동이 있는지를 살펴보았다.&lt;/p&gt;
&lt;p&gt;- 112p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;내가 무의식적으로 하는 행동 중에서 루틴으로 삼을 수 있는 행동이 무엇인지 살펴보는 과정을 소개합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;루틴을 기록할 때는 루틴만 나열하지 말고 언제 할지 함께 기록하자.
…
성공 가능성을 극대화하고 싶다면 하나 더 신경 쓸 게 있다. 바로 ‘언제 할지’를 정하는 것이다.
…
이 시작 행동이 단단한지 체크해야 한다. 다시 말해 기준이 되는 상황이나 행동이 매일 있어야 그 상황과 행동에서 이어갈 새로운 루틴도 잘 챙길 수 있다.&lt;/p&gt;
&lt;p&gt;- 125p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;개인적으로 아주 중요하다고 생각하는 부분입니다. 루틴을 꾸준히 유지하기 위해서는 그 행동이 일어나는 계기, &lt;strong&gt;트리거(trigger)&lt;/strong&gt; 가 단단하고 명확해야 한다는 점을 강조합니다. 트리거는 행동의 촉매 역할을 하기 때문입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;작은 루틴 하나 한다고 뭐가 달라질까?
…
더 중요한 사실은 좋은 행동이 좋은 행동을 부른다는 것이다.&lt;/p&gt;
&lt;p&gt;- 135p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이렇게 해서 작고 사소한 내 일상을 루틴화했을 때, 당장 내 일상이 바뀌는 일은 없지만 긍정적인 생각과 행동이 이어지는 선순환이 시작된다는 내용입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;첫째, 시작 루틴은 무조건 쉽고 간단하게 만든다.
…
둘째, 내가 이미 하고 있는 활동에서 시작하자.
…
셋째, 기존 행동 중 반복하고 싶은 게 없다면 매일 반복되는 일에 루틴을 추가해보자.
…
넷째, 일단 시작하자.&lt;/p&gt;
&lt;p&gt;- 137p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;제목처럼 하루 5분 같은 단위로 시작하자는 메시지가 여기서 구체화됩니다.&lt;/p&gt;
&lt;h2 id=&quot;뼈대-루틴-세우고-가지-루틴-쌓기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%BC%88%EB%8C%80-%EB%A3%A8%ED%8B%B4-%EC%84%B8%EC%9A%B0%EA%B3%A0-%EA%B0%80%EC%A7%80-%EB%A3%A8%ED%8B%B4-%EC%8C%93%EA%B8%B0&quot; aria-label=&quot;뼈대 루틴 세우고 가지 루틴 쌓기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;뼈대 루틴 세우고 가지 루틴 쌓기&lt;/h2&gt;
&lt;p&gt;3장에서는 루틴을 확장하는 방법에 대해 알아봅니다. 작은 루틴에서 시작해서, 그 루틴을 뼈대로 삼아 가지 루틴을 쌓아 나가는 방법입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;사람들에게 무엇을 하고 싶냐고 물었을 때 가볍게 떠오르는 루틴은 지향하는 지점이긴 하지만 진지하게 열망하지는 않을 가능성이 크다. 그래서 자주 언급하면서도 잘 지키지 못하는 것이다.&lt;/p&gt;
&lt;p&gt;- 174p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;솔직히 말해서 찔린 부분입니다. 연말마다 회고를 하며 연간 목표를 세우지만, 그 목표를 정말 진지하게 열망하면서 세웠다고 생각하지는 않거든요. 목표를 이룰 만한 동기와 간절함의 부족은 루틴의 실패에도 영향을 준다는 내용입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;잘 지키고 있는 뼈대 루틴 다음, 이미 반복되는 일상 행동 다음, 시간이 확보되는 시점, 없애고 싶은 안 좋은 습관이 시작되려는 순간이 루틴을 하기 좋은 때다.&lt;/p&gt;
&lt;p&gt;- 182p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;루틴의 또 다른 구성 요소인 동기입니다. 나의 일상에서 불만족스러운 부분을 발견했을 때, 이를 동기 부여로 삼아 루틴을 시작하는 계기로 만들라는 이야기죠.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;시작 루틴의 핵심은 책을 펴기만 해도, 운동복을 입기만 해도 달성으로 보는 것이다. 정말 하기 싫은 날이라면 책을 펴기만 해도, 운동복을 입기만 해도 괜찮다. 그것만으로도 책을 읽기 위해, 운동을 하기 위해 노력한 것이며 오늘은 못 했지만 앞으로 계속할 거라는 시그널을 스스로에게 준 것이다.&lt;/p&gt;
&lt;p&gt;- 187p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 부분은 새롭게 느껴졌는데, 어떤 루틴을 정말 하기 싫은 날에는 루틴의 시작 행동만 해도 달성으로 인정한다는 내용입니다! 루틴의 달성 자체는 관대하게 인정하되, 그 루틴을 유지하려는 노력은 계속하라는 메시지로 이해했습니다.&lt;/p&gt;
&lt;p&gt;3장은 하나의 굵은 루틴을 축으로 두고, 거기에 얹을 작은 루틴들을 정리하는 파트였습니다. 모든 걸 동시에 늘리지 말고 뼈대를 먼저 세우라는 말이, 제가 너무 많은 루틴을 여러 개 동시에 잡았다가 무너져 본 경험과도 잘 맞아떨어졌습니다.&lt;/p&gt;
&lt;h2 id=&quot;루틴-세트-유지하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%A3%A8%ED%8B%B4-%EC%84%B8%ED%8A%B8-%EC%9C%A0%EC%A7%80%ED%95%98%EA%B8%B0&quot; aria-label=&quot;루틴 세트 유지하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;루틴 세트 유지하기&lt;/h2&gt;
&lt;p&gt;4장은 루틴 세트를 유지하는 방법에 대해 알아봅니다. 루틴을 끝까지 지속하는 방법에 대해 설명합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;사람의 행동은 세 가지 요소에 의해 일어난다. 계기, 동기, 그리고 능력. 다시 말해 어떤 행동을 해야 한다는 걸 기억해내고, 그 행동을 하고자 하는 동기가 있고, 그 행동을 할 수 있는 능력이 있다면 행동하게 되는 것이다.&lt;/p&gt;
&lt;p&gt;- 207p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;루틴의 구성 요소를 설명합니다. 이렇게 보니 뭔가 3대 영양소(?) 설명하는 것 같네요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;무엇을, 언제까지, 왜 해낼지를 명확히 하는 것. 이 세 가지가 모두 중요하다. 해내야 하는 것이 무엇인지 모르면 애초에 해낼 수가 없고, 기간이 명확하지 않으면 한없이 미뤄지며, 이유가 명확하지 않으면 동기가 약해졌을 때 되살리지 못하고 포기해버린다.&lt;/p&gt;
&lt;p&gt;- 245p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;루틴을 왜 해야 하는지를 아는 것은 나의 능력과 동기를 동시에 끌어올리는 데 도움이 된다는 내용입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;루틴을 하는 행동을 쉽게 만드는 것이다.
…
매일 퇴근 후에 책을 읽기로 했다. 그런데 퇴근하고 피곤한 몸으로 침대에 쓰러져 ‘아, 책 읽어야 하는데’라고 생각할 때와 피곤한 몸으로 침대에 쓰러졌는데 옆에 책이 펼쳐져 있을 때 중 언제 더 책을 읽기 쉬울까?&lt;/p&gt;
&lt;p&gt;- 226p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;내가 지키고 싶은 루틴은 어떤 환경이 갖춰져 있을 때 더 쉽게 지킬 수 있을까에 대한 고민을 해보게 되었습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;목표, 기간, 이유, 루틴이 명확해졌다면 그 다음 할 일은 회고 일정을 잡는 것이다.
…
막연한 계획이 아니라 날짜와 시간까지 명확하게 정해야 한다. 마치 약속을 잡듯 시간, 장소까지 정해 기록해두는 것이 좋다.&lt;/p&gt;
&lt;p&gt;- 248p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 부분도 인상 깊게 느낀 부분인데, 루틴 진행에 대한 스스로의 회고 일정을 마치 약속처럼 잡으라는 내용입니다. 저도 최근에는 월간 회고를 진행하고 있는데, 스스로의 다짐이지만 이것을 캘린더에 기록하면서 마치 약속과 동일하게 취급한다는 개념이 신선하게 와닿았습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;루틴 자체로 동기 부여가 잘 안 된다면 더 잘할 수 있도록 보상 혹은 벌칙을 정하는 것도 방법이다.
…
- 255p&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;저의 목표 달성을 방해하는 유혹들에게 지지 않도록 보상과 벌칙에 대한 부분도 고민하며 읽었습니다. 게임과 SNS 같은 도파민성 유혹도 있고, 귀찮음과 게으름 같은 인간 내면의 본질적인 유혹도 잘 관리하고 싶었거든요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;기간이나 횟수 정하기&lt;/li&gt;
&lt;li&gt;공개적으로 실천하기&lt;/li&gt;
&lt;li&gt;보상 혹은 벌칙 마련하기&lt;/li&gt;
&lt;li&gt;같이 하기&lt;/li&gt;
&lt;li&gt;준비 루틴 정하기&lt;/li&gt;
&lt;li&gt;목표를 명확히 하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;최종적으로 루틴을 유지하기 위한 방법들을 정리한 부분입니다. 내용 자체는 어느 정도 다 아는 내용이지만 이런 루틴의 실행을 돕는 환경들이 제 주변에서 꽤 멀어졌구나 새삼 느끼게 되었습니다.&lt;/p&gt;
&lt;h2 id=&quot;마치며&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%A7%88%EC%B9%98%EB%A9%B0&quot; aria-label=&quot;마치며 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;마치며&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ee98f36db26b142d1df0f0e50f47eab1/8e1fc/3.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQCBQb/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABXJW8ZIaD/8QAGxABAQABBQAAAAAAAAAAAAAAAgMBAAQSEyH/2gAIAQEAAQUChE0xUe62r42qiA8di//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABURAQEAAAAAAAAAAAAAAAAAABAx/9oACAECAQE/Aaf/xAAcEAACAgIDAAAAAAAAAAAAAAAAAQIREiEiMUH/2gAIAQEABj8CuWykto6MfJDkzJcbP//EABsQAQACAgMAAAAAAAAAAAAAAAEAIRFBMVGB/9oACAEBAAE/Ic4l5wjqWBlAG5cXbp9lAIc1FUwaT//aAAwDAQACAAMAAAAQ2w//xAAVEQEBAAAAAAAAAAAAAAAAAAAQMf/aAAgBAwEBPxCH/8QAFhEBAQEAAAAAAAAAAAAAAAAAAREA/9oACAECAQE/EEQRmu//xAAcEAEBAQACAwEAAAAAAAAAAAABEQAhYTFRgZH/2gAIAQEAAT8QCkqSgjrGs/cJLabfaaR4T4PI/lMCM1RTueSRVXt7d//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;루틴&quot;
        title=&quot;루틴&quot;
        src=&quot;/static/ee98f36db26b142d1df0f0e50f47eab1/6aca1/3.jpg&quot;
        srcset=&quot;/static/ee98f36db26b142d1df0f0e50f47eab1/d2f63/3.jpg 163w,
/static/ee98f36db26b142d1df0f0e50f47eab1/c989d/3.jpg 325w,
/static/ee98f36db26b142d1df0f0e50f47eab1/6aca1/3.jpg 650w,
/static/ee98f36db26b142d1df0f0e50f47eab1/8e1fc/3.jpg 900w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;메모와 아이패드를 통해 루틴 계획을 진지하게 짜는 중&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;인용구가 굉장히 많다는 점에서 느끼셨겠지만, 루틴에 대한 저자의 관점과 생각에서 많은 부분이 와닿았습니다. 루틴을 꾸준히 지키는 것이 왜 중요한지, 루틴을 어떻게 시작할 수 있는지, 그리고 루틴을 어떻게 유지할 수 있는지에 대한 저자의 생각이 제 고민과 잘 맞아떨어졌기 때문이겠죠.&lt;/p&gt;
&lt;p&gt;저는 개발자다 보니까 제가 가진 사전 지식을 바탕으로 이 내용을 이해하게 되더라고요. 내가 하루에 허용할 수 있는 루틴의 쿼터는 얼마인지, 루틴을 유발하는 트리거는 무엇인지, 이루고 싶은 루틴을 백로그에 넣어 관리한다든지, 일상을 다이어그램 또는 유한 상태 머신으로 나타낸다든지 하는 식으로요.&lt;/p&gt;
&lt;p&gt;이런 식으로 &lt;em&gt;루틴을 관리하는 앱을 내가 만든다면 어떻게 UI를 구성했을까?&lt;/em&gt; 를 상상하면서 읽으니 꽤 재밌었습니다. 시각화 방법에 고민하고 있는 부분이 있어서 아직 완성하지는 못했지만, 나중에 결과물을 한 번 공유해볼게요.&lt;/p&gt;
&lt;p&gt;내용의 깊이감은 사실 특별할 것 없이 무난했지만, 저에게 생각할 거리를 많이 던져준 책이라서 개인적으로는 재미있게 읽었습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Safari에서 그라데이션 배경에 트랜지션이 적용되지 않았던 이유]]></title><description><![CDATA[Safari 18 이하 버전에서 CSS 함수의 인자로 참조된 currentColor가 리페인트를 일으키지 않았기 때문입니다.]]></description><link>https://wormwlrm.github.io/2026/01/14/Safari-Gradient-Transition.html</link><guid isPermaLink="false">https://wormwlrm.github.io/2026/01/14/Safari-Gradient-Transition.html</guid><pubDate>Wed, 14 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;프론트엔드 개발자라면 한 번쯤은 이런 상황을 겪어보셨을 겁니다. &lt;em&gt;“Chrome에서는 분명히 잘 되는데, Safari에서만 안 되네요?”&lt;/em&gt; 네, 오늘도 어김없이 Safari입니다.&lt;/p&gt;
&lt;p&gt;요즘 회사 프로젝트 QA 기간 막바지라 크로스 브라우징 테스트를 열심히 하고 있는데요, 역시나 Safari 이슈가 저를 반겨주더라구요. 아직 해결하지 못한 몇몇 이슈들이 남아있어서 요즘 글쓸 소재가 넘쳐나는 호사(?)를 누리고 있습니다.&lt;/p&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExbWtybTBuNWE0dGJ6Z2c5bjc3aGRpYnRkaDBxZGJwMW4zc29ueHYyciZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/dAWZiSMbMvObDWP3aA/giphy.gif&apos; alt=&apos;그라디언트&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;그라데이션과 트랜지션을 조합하면 세련된 느낌을 얻을 수 있다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이번에 마주한 이슈는 Safari 18 이하 버전에서 CSS &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt; 값을 이용해 구현된 그라데이션 트랜지션을 적용했음에도 불구하고 제대로 적용되지 않는 현상입니다. 원인을 파악하고 나니 브라우저 엔진 자체의 렌더링 최적화 과정에서 발생한 버그였고, 이를 해결하는 방법도 찾아서 공유해보려고 합니다.&lt;/p&gt;
&lt;p&gt;이번 포스트를 통해 &lt;strong&gt;CSS 그라데이션에 트랜지션 효과를 적용하는 방법&lt;/strong&gt;이 궁금하신 분들, 그리고 &lt;strong&gt;Safari에서 해당 트랜지션이 동작하지 않는 이슈를 겪고 계신 분들&lt;/strong&gt;에게 도움이 되길 바랍니다.&lt;/p&gt;
&lt;h2 id=&quot;tldr&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#tldr&quot; aria-label=&quot;tldr permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;TL;DR&lt;/h2&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;CSS 그라데이션 배경은 &lt;code class=&quot;language-text&quot;&gt;background-image&lt;/code&gt; 속성에 &lt;code class=&quot;language-text&quot;&gt;linear-gradient()&lt;/code&gt; 등의 CSS 함수를 사용하여 구현함&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;background-image&lt;/code&gt;는 기본적으로 트랜지션이 적용되지 않는 불연속(discrete) 속성이지만, &lt;code class=&quot;language-text&quot;&gt;linear-gradient()&lt;/code&gt; 내부에 &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;를 사용하면 &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt; 속성의 트랜지션에 따라 그라데이션 색상도 자연스럽게 전환됨&lt;/li&gt;
&lt;li&gt;그러나 특정 Safari 버전에서는 &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt; 값이 변경되어도 &lt;code class=&quot;language-text&quot;&gt;background-image&lt;/code&gt; 내부의 &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;가 업데이트되지 않는 버그가 있음&lt;/li&gt;
&lt;li&gt;이는 Safari(WebKit)가 &lt;code class=&quot;language-text&quot;&gt;background-image&lt;/code&gt; 내 CSS 함수로 참조된 &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt; 변경을 감지하지 못해 리페인트가 트리거되지 않기 때문&lt;/li&gt;
&lt;li&gt;이를 해결하기 위해서는 &lt;code class=&quot;language-text&quot;&gt;background-color: currentColor&lt;/code&gt;와 같은 리페인트를 유도하는 속성을 추가하는 방법을 고려할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;그라데이션-트랜지션-구현하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B7%B8%EB%9D%BC%EB%8D%B0%EC%9D%B4%EC%85%98-%ED%8A%B8%EB%9E%9C%EC%A7%80%EC%85%98-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0&quot; aria-label=&quot;그라데이션 트랜지션 구현하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;그라데이션 트랜지션 구현하기&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;/d3a98bebc0d0656d5a611211316bf8e9/2.mov&quot; control autoplay muted loop playsinline width=&quot;100%&quot;&gt;&lt;/video&gt;
&lt;em&gt;그라데이션 트랜지션의 동작 예시, 1번은 호버 시 트랜지션, 2번은 버튼 클릭 시 트랜지션&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;우선 그라데이션 배경의 색상이 자연스럽게 변하는 정상적인 상황을 재현한 예시를 제작해보았습니다.&lt;/p&gt;
&lt;p&gt;위 영상에는 그라데이션 배경이 적용된 &lt;code class=&quot;language-text&quot;&gt;&amp;lt;div&gt;&lt;/code&gt;가 2개 보이는데요, 첫 번째는 호버 시 트랜지션, 두 번째는 버튼 클릭 시 트랜지션을 적용한 예시를 볼 수 있습니다. 그라데이션이 예쁘게 잘 전환되네요!&lt;/p&gt;
&lt;p&gt;이러한 그라데이션을 구현하기 위해서는 어떻게 CSS를 작성해야 할까요? 만약 아래와 같은 코드를 작성하면 의도한 대로 트랜지션 효과가 적용될까요?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.box&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* 초기 그라데이션 배경 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;135deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #ff6b6b 0%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #4ecdc4 100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/* 트랜지션 효과 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; background-image 0.5s ease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.box:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* 호버 시 그라데이션 배경 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;135deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #9b59b6 0%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #4ecdc4 100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;video src=&quot;/00b05826bc5541e3b05d20ce66b4f800/3.mov&quot; control autoplay muted loop playsinline width=&quot;100%&quot;&gt;&lt;/video&gt;
&lt;em&gt;의도한 대로 나오지 않는다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;위 코드를 그대로 적용하면 트랜지션 효과가 전혀 적용되지 않고 색상이 뚝 끊기듯이 변하는 것을 볼 수 있습니다. 그 이유는 바로 &lt;code class=&quot;language-text&quot;&gt;background-image&lt;/code&gt; 속성은 트랜지션을 적용할 수 없는 불연속(discrete) 속성이기 때문입니다. 그래서 일반적으로 그라데이션 배경에 트랜지션을 적용하기 위해서는 약간의 트릭을 사용해야 합니다.&lt;/p&gt;
&lt;h3 id=&quot;투명도-조절으로-구현하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%88%AC%EB%AA%85%EB%8F%84-%EC%A1%B0%EC%A0%88%EC%9C%BC%EB%A1%9C-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0&quot; aria-label=&quot;투명도 조절으로 구현하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;투명도 조절으로 구현하기&lt;/h3&gt;
&lt;p&gt;가장 일반적인 방법은 &lt;code class=&quot;language-text&quot;&gt;::before&lt;/code&gt; 혹은 &lt;code class=&quot;language-text&quot;&gt;::after&lt;/code&gt; 를 사용해 전환할 그라데이션 배경을 만들고, 가상 요소의 &lt;code class=&quot;language-text&quot;&gt;opacity&lt;/code&gt; 값을 조절하는 것입니다. 구글에 검색해보았을 때 레퍼런스도 가장 많고 간단한 방법입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://keithjgrant.com/posts/2017/07/transitioning-gradients/&quot;&gt;Transitioning Gradients&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://savvy.co.il/en/blog/css/transitioning-gradients/&quot;&gt;Animating Gradients: A Guide to Smooth Transitions in CSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;scss&quot;&gt;&lt;pre class=&quot;language-scss&quot;&gt;&lt;code class=&quot;language-scss&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.box &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* 초기 그라데이션 배경 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;135deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #ff6b6b 0%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #4ecdc4 100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.box::after &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* box를 덮는 가상 요소 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* 호버 시 그라데이션 배경 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;135deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #9b59b6 0%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #4ecdc4 100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* box를 덮는 가상 요소의 투명도를 조절하여 그라데이션 배경을 표시 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; opacity 0.5s ease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* 초기 가상 요소의 opacity는 0 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.box:hover::after &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* 호버 시 가상 요소의 opacity를 1로 변경 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;video src=&quot;/2afd209035656f8dbd1859da4bd3fecb/4.mov&quot; control autoplay muted loop playsinline width=&quot;100%&quot;&gt;&lt;/video&gt;
&lt;em&gt;의도한 대로 나온다!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이 방법은 단순히 레이어의 투명도 조절을 통해 그라데이션 배경을 전환하는 방법이기 때문에 대부분의 브라우저에서 잘 동작합니다. 하지만 이와 같은 방법을 사용하기 어려운 경우에는 다른 방법으로도 트랜지션을 구현할 수 있는데, 바로 &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;를 활용하는 방법입니다.&lt;/p&gt;
&lt;h3 id=&quot;code-classlanguage-textcurrentcolorcode로-구현하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code-classlanguage-textcurrentcolorcode%EB%A1%9C-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0&quot; aria-label=&quot;code classlanguage textcurrentcolorcode로 구현하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;로 구현하기&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/Reference/Values/color_value#currentcolor_%ED%82%A4%EC%9B%8C%EB%93%9C&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;&lt;/a&gt;는 CSS에서 현재 요소의 &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt; 속성 값을 참조하는 키워드입니다. 이를 통해 다른 속성이 &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt; 속성 값에 따라 자동으로 변경될 수 있게 하는데요, 즉, &lt;code class=&quot;language-text&quot;&gt;color: red&lt;/code&gt;로 설정하면 &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;도 &lt;code class=&quot;language-text&quot;&gt;red&lt;/code&gt;가 되는 거죠.&lt;/p&gt;
&lt;p&gt;이를 활용하면 &lt;code class=&quot;language-text&quot;&gt;background-image&lt;/code&gt; 속성 내부에서 &lt;code class=&quot;language-text&quot;&gt;linear-gradient&lt;/code&gt;가 &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;를 참조하게 하는 경우, &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt; 속성을 변경하는 방식으로 그라데이션의 트랜지션을 쉽게 구현할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.box&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* 초기 color 값 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #ff6b6b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/* color에 transition 적용 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; color 0.5s ease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/* currentColor를 사용한 gradient, currentColor는 현재 요소의 color 속성 값을 참조 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;135deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentColor 0%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #4ecdc4 100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.box:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* 호버 시 color 값 변경 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #9b59b6&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;video src=&quot;/4d04d1ea4c1d473d052144475c4be795/5.mov&quot; control autoplay muted loop playsinline width=&quot;100%&quot;&gt;&lt;/video&gt;
&lt;em&gt;위 방법도 잘 된다! 무엇보다 코드가 매우 간결함&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이 키워드를 활용하면 &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt; 속성 하나만 변경해도 연관된 모든 스타일이 함께 바뀌기 때문에 유지보수가 편리합니다. 또한, &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt; 속성은 인라인 스타일을 통해 외부에서 쉽게 주입할 수도 있기 때문에, 그라데이션 구성 요소가 동적이어야 하는 경우의 트랜지션을 더욱 쉽게 구현할 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;safari의-렌더링-최적화-문제&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#safari%EC%9D%98-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%B5%9C%EC%A0%81%ED%99%94-%EB%AC%B8%EC%A0%9C&quot; aria-label=&quot;safari의 렌더링 최적화 문제 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Safari의 렌더링 최적화 문제&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;/bd535d865886dbc53c4cff36c2de1158/6.mov&quot; control autoplay muted loop playsinline width=&quot;100%&quot;&gt;&lt;/video&gt;
&lt;em&gt;좌측은 Safari 18, 우측은 Safari 26. 똑같은 코드인데 왜 여기서만 안 될까?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Chrome에서 테스트했을 때는 그라데이션 트랜지션이 의도한 대로 완벽하게 동작했습니다. 그런데 Safari에서 확인해보니… 색상이 아예 변하지를 않더라구요. 몇 번의 삽질(?)과 테스트를 통해 정확하게 Safari 18 이하의 버전에서 해당 코드가 동작하지 않는 것으로 범위를 좁혀낼 수 있었습니다.&lt;/p&gt;
&lt;p&gt;Chrome과 Safari 26 버전에서는 마우스를 올리면 빨간색에서 파란색으로 0.5초에 걸쳐 자연스럽게 전환됩니다. 하지만 Safari 18 이하에서는 색상이 뚝 끊기듯이 변하거나 아예 색상 변경이 일어나지 않는 경우도 있었습니다.&lt;/p&gt;
&lt;p&gt;정확한 원인을 파악하기 위해, Safari 브라우저의 개발자 도구를 통해 렌더링 타임라인을 살펴보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c18c1f0a11615eda33a0d88df52ecd6b/73caa/1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 76.07361963190185%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAADA0lEQVQ4y12UW28cRRCF5+8iIYFAPPAEUt544F8gBYEDjgQJjsBsfHd2s7bX9t5mLzN7cbxzn+md6Z7bh6adRA4PR6dVXX26qrq6DG86wXEclJRst1uyNCWJY0SSsBWCKIo0x1GEiBOiKCRNEjbzOUJJ6qqiLEuq92ys7kOCOCZuhNKMLC/0Ok4zglgQxIlGGAs8P9LrKBFMZnM2cUhdVuR5TlEUmo2TvR0uXr3EPGpht88IzVuiYQev+xph3SBm12ztPonZJbxskcx6JNNL8vWcvCh1ZkqpjzAGrX0G56cMz09ZDW5J7QVx32Rrm/jzWxz7ko11gX31lrs3fZLliMC+IlnZyLwgyyRSSrIs0yUzBuu5TiPJJCLLGfomO+YuP3R/5JuTb/ni8Cs+O/ic786e8Ld1yPftJ3x59DXrcA01VFVJWdUolSNVjuG7cyJ/RRIu2YZreqtT9u3nHK5ecLR6yfF6j5P1Hi37T45Wf/Gv9QcHyxfkcsMygKtlRrH1oVaUSmC87pm8GbucTyUnpuD4NuFiUnO7gBv7AdcWjJcwWsFwgd57OxUcTyT71wGtiyVn45hW18b4+eiSpwdTdrsZzzoJzzoxOw3a0Uf82o543nb5rRPwe9tjpx2y2wnY7Qp2Tl2etmx+OXH46Z8Jxsbp497P0QVBQS2BAsgfoUCEDpVKkCLQPmobartMfNb2BCUCrMkQw7QvmMzGFEVNmkm2aaaLm0mFlOqBVc7du3eEUYzjetrH9Tz9EJuNQ78/YOO4XPV6GLPlFXPLpCpr/fwyy3SD5kppNL1V5Dn39/fEcYznebpFfN/Xfp7rMhqNcF2XXiO4uBuwXFuUZaWbtBF9LKiR5/qAEIIwDLVPFIba3nxJy7IIfJ/xeIxhrW5YLOdUZfUQ4f8E1XvBJrJPBKNI24MgYDab6YhHwyFG3zxnZpn6TaTMPk254TzXoh8u0vtK6bSrssR1HAaDgb7wukl5OO1g2RPqqtZODR7/zQ9optBjTtNUT5dmUo1HIx1hv9/nP0DbWvajArPiAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;렌더링&quot;
        title=&quot;렌더링&quot;
        src=&quot;/static/c18c1f0a11615eda33a0d88df52ecd6b/a6d36/1.png&quot;
        srcset=&quot;/static/c18c1f0a11615eda33a0d88df52ecd6b/222b7/1.png 163w,
/static/c18c1f0a11615eda33a0d88df52ecd6b/ff46a/1.png 325w,
/static/c18c1f0a11615eda33a0d88df52ecd6b/a6d36/1.png 650w,
/static/c18c1f0a11615eda33a0d88df52ecd6b/e548f/1.png 975w,
/static/c18c1f0a11615eda33a0d88df52ecd6b/73caa/1.png 1110w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;정상 케이스&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;우선 정상적으로 동작하고 있던 Safari 26에서의 타임라인을 보면, 트랜지션이 발생할 때 브라우저의 페인팅 단계가 매 프레임마다 잘 발생하는 것을 볼 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/282dd08e5c75d67d5a86acb1b2232897/0f246/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 62.576687116564415%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAABj0lEQVQ4y7WS3W4TMRCF9/0fCoGQuKkQ3LRcQGgbEtJu1ln//+7mQ3ZImkTlBoSlT2c88ozGx+5uHjwlOnLOiEGwGwXDrkdK2dBaNy2lsM8JbSM7ZVFSYq3FGEMIoWndd1aPhJhw3lPmmblMrDcrrte+EgKkeJnf7y/23c/lknHbo8SAU4qoFcNmRbSWaM0ZlmQ00XtiSsQYX6X79PYNtx/e8+3jDWLxlSKeSf2G3D81PTE8k3/ck5QkTxMppWbTUY90i7tbvn+54+nxASO2RGHwvSKOGr2WxJ1qZGNIYiAY0yasvtWJjuq9xzlHp7TBeo91jpATMmt6P+BLwGXfaHEJlJLZl6n5Nle/5/nkYX20SidHRQge7xyD2LLcPrKWK6SVSDs2FWpgpwXGaoIPbargPe8WM5/vJVoKQowopeimaTp1d9YRfYQZ5mk+kVOm5HLhW71mra3XdPXBUmpfp6vBkdr0UBA5z79m/jF3HCbnQ9zVIKcDLw1echfxNb+bprP67o+H/5L/0PDKl3/lF8rE8PuGVOVwAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;문제 케이스&quot;
        title=&quot;문제 케이스&quot;
        src=&quot;/static/282dd08e5c75d67d5a86acb1b2232897/a6d36/3.png&quot;
        srcset=&quot;/static/282dd08e5c75d67d5a86acb1b2232897/222b7/3.png 163w,
/static/282dd08e5c75d67d5a86acb1b2232897/ff46a/3.png 325w,
/static/282dd08e5c75d67d5a86acb1b2232897/a6d36/3.png 650w,
/static/282dd08e5c75d67d5a86acb1b2232897/e548f/3.png 975w,
/static/282dd08e5c75d67d5a86acb1b2232897/0f246/3.png 1118w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;문제 케이스 1: 색상 변경이 아예 발생하지 않는 상황&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;반면 문제가 되는 케이스에서는 iOS Safari와 PC Safari에서 서로 다른 증상을 보였습니다. iOS Safari에서는 &lt;strong&gt;색상 변경이 아예 발생하지 않는 상황&lt;/strong&gt;을 마주할 수 있었습니다. 실제로 페인트 단계가 전혀 발생하지 않은 것을 확인할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/cbb6e8a84f2381cfa75261f226c0e55c/cf98e/2.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 80.98159509202453%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAQABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIBAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB2mGiCor/xAAZEAACAwEAAAAAAAAAAAAAAAAAEQEhMQL/2gAIAQEAAQUCtW2c4Tv/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAVEAEBAAAAAAAAAAAAAAAAAAAgUf/aAAgBAQAGPwKr/8QAGRABAAIDAAAAAAAAAAAAAAAAAQAgQVGR/9oACAEBAAE/ITbHCIM0L//aAAwDAQACAAMAAAAQWM//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAdEAEAAgEFAQAAAAAAAAAAAAABABExECFBgbHw/9oACAEBAAE/EAVQVbAVDlMM1FKaT1dPruf/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;문제 케이스&quot;
        title=&quot;문제 케이스&quot;
        src=&quot;/static/cbb6e8a84f2381cfa75261f226c0e55c/6aca1/2.jpg&quot;
        srcset=&quot;/static/cbb6e8a84f2381cfa75261f226c0e55c/d2f63/2.jpg 163w,
/static/cbb6e8a84f2381cfa75261f226c0e55c/c989d/2.jpg 325w,
/static/cbb6e8a84f2381cfa75261f226c0e55c/6aca1/2.jpg 650w,
/static/cbb6e8a84f2381cfa75261f226c0e55c/7c09c/2.jpg 975w,
/static/cbb6e8a84f2381cfa75261f226c0e55c/01ab0/2.jpg 1300w,
/static/cbb6e8a84f2381cfa75261f226c0e55c/cf98e/2.jpg 2150w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;문제 케이스 2: 트랜지션 없이 그라데이션 변경이 뚝 끊겨 발생하는 상황&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;반면 PC Safari에서는 &lt;strong&gt;트랜지션 없이 그라데이션 변경이 뚝 끊겨 발생하는 상황&lt;/strong&gt;이 있었습니다. &lt;em&gt;‘스타일 무효화됨’&lt;/em&gt; 과 &lt;em&gt;‘스타일 재검토됨’&lt;/em&gt; 이 반복될 뿐, 실제 페인트 단계는 트랜지션의 마지막 프레임에서만 발생한 것을 확인할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;이를 통해 문제의 원인을 확실히 파악할 수 있었습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“구 버전 Safari 브라우저의 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/Performance/Guides/Critical_rendering_path&quot;&gt;중요 렌더링 경로&lt;/a&gt;에서 리페인팅 단계가 누락되어 발생한 문제구나!”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;왜 이런 현상이 발생하는 걸까요? Safari 렌더링 엔진의 내부 동작이라 정확하게 알 순 없었지만, 다음과 같이 추론해보았습니다.&lt;/p&gt;
&lt;p&gt;일반적으로 &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt; 속성이 변경되면 브라우저는 해당 요소와 연관된 스타일을 다시 계산하고 화면을 갱신(repaint)합니다. 그런데 Safari에서는 &lt;code class=&quot;language-text&quot;&gt;linear-gradient()&lt;/code&gt; 내부의 &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;에 대해서는 이 과정이 정상적으로 동작하지 않았습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;색상 변경이 아예 발생하지 않는 상황&lt;/strong&gt;에 대해서는, 아무래도 Safari에서 &lt;code class=&quot;language-text&quot;&gt;linear-gradient()&lt;/code&gt; 함수가 처음 렌더링될 때 &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;를 실제 색상 값으로 해석한 뒤, 이를 &lt;strong&gt;정적 값으로 캐싱&lt;/strong&gt;하기 때문으로 보입니다. 이후 &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt; 속성이 변경되어 &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;의 참조 값이 바뀌더라도, &lt;code class=&quot;language-text&quot;&gt;linear-gradient()&lt;/code&gt; 입장에서는 이미 캐싱된 값을 사용하기 때문에 변경을 감지하지 못하는 것이죠.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;트랜지션 없이 그라데이션 변경이 뚝 끊겨 발생하는 상황&lt;/strong&gt;에 대해서는, Safari 개발자 도구의 프레임 별 메시지를 통해 그 단서를 추측해볼 수 있었습니다. &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;의 값이 바뀌는 순간 기존의 리페인팅을 취소하고 새로 들어온 값을 기준으로 그라데이션을 계산하려고 하는데, 이것이 매 프레임마다 발생해서 연쇄적으로 취소가 이어진 현상으로 보입니다.&lt;/p&gt;
&lt;h2 id=&quot;해결-방법&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95&quot; aria-label=&quot;해결 방법 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;해결 방법&lt;/h2&gt;
&lt;p&gt;자, 이제 해결책을 알아볼 차례입니다.&lt;/p&gt;
&lt;h3 id=&quot;강제-리페인트-유도&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B0%95%EC%A0%9C-%EB%A6%AC%ED%8E%98%EC%9D%B8%ED%8A%B8-%EC%9C%A0%EB%8F%84&quot; aria-label=&quot;강제 리페인트 유도 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;강제 리페인트 유도&lt;/h3&gt;
&lt;p&gt;가장 간단한 해결책은 &lt;strong&gt;리페인트를 강제로 유도하는 것&lt;/strong&gt;입니다. 페인트가 일어나지 않아서 생긴 문제니까 페인트를 일으키는 속성을 추가하면 되겠죠.&lt;/p&gt;
&lt;p&gt;결과물에 영향을 주지 않으면서 강제 리페인트를 유도하기 위해서는 &lt;code class=&quot;language-text&quot;&gt;background-color: currentColor&lt;/code&gt;를 함께 추가하는 것을 고려할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.box&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #ff6b6b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; color 0.5s ease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* background-color 속성에도 currentColor 속성을 추가하여 강제 리페인트를 유도 */&lt;/span&gt;
&lt;span class=&quot;gatsby-highlight-code-line&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; currentColor&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;135deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentColor 0%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #4ecdc4 100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;video src=&quot;/87926876b732c22b4f584b1ded2ef849/9.mov&quot; control autoplay muted loop playsinline width=&quot;100%&quot;&gt;&lt;/video&gt;
&lt;em&gt;강제 리페인트 유도&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이게 왜 동작할까요? &lt;code class=&quot;language-text&quot;&gt;background-color&lt;/code&gt; 속성의 &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt;는 Safari에서도 정상적으로 리페인트를 트리거합니다. 그리고 &lt;code class=&quot;language-text&quot;&gt;background-image&lt;/code&gt;가 &lt;code class=&quot;language-text&quot;&gt;background-color&lt;/code&gt; 위에 렌더링되기 때문에, 추가한 &lt;code class=&quot;language-text&quot;&gt;background-color&lt;/code&gt;는 시각적으로 보이지 않습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/75fd37846c39cc9506e95309ab523b15/43fbc/8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 33.12883435582822%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAAAsTAAALEwEAmpwYAAABWklEQVQoz5WO7W6bQBBFef8X6odUS5b6pTTFxInj1gZjdtllARPAELAL9olYVfmVPxnp6s7MmV1d54ObMVtIZp5mvtTMVjUfvZJPy4r5+sj83vBlEfPZVfjyQGYShJAopRBCoLXGGEMURTRNg7MOYnyR4W5yvG2G5xeso4I7P8fdHFgGOZ6f82efI1ViH4dhSFVVjOP4qmEYuFwuOIlWpCZBiogk0ahYomKBUpIsTdH/uVYxaWqQUqITgzEpcRzbhJNPabuuw5livr+ucL2+SRyZt8i0Yq8LZFpbD2T2utvFB4SpEElpuSp61KFDFz3JU2/vfJESqoL6ecDZxhU3d1t+r0Lcx731r7crfnobbh921n8s/vLrPrDzN3fLzcPe6vtiy+POEKiKQNUU7YDTnq88HU/297I5Uz3/o2zPFMeeqj1TNifbT2xSUXd2N7GpP/YjpxG6AfoBXgBCbAmGbJLqFgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;background-color&quot;
        title=&quot;background-color&quot;
        src=&quot;/static/75fd37846c39cc9506e95309ab523b15/a6d36/8.png&quot;
        srcset=&quot;/static/75fd37846c39cc9506e95309ab523b15/222b7/8.png 163w,
/static/75fd37846c39cc9506e95309ab523b15/ff46a/8.png 325w,
/static/75fd37846c39cc9506e95309ab523b15/a6d36/8.png 650w,
/static/75fd37846c39cc9506e95309ab523b15/43fbc/8.png 797w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;&lt;code class=&quot;language-text&quot;&gt;background-image&lt;/code&gt; 렌더 시 &lt;code class=&quot;language-text&quot;&gt;background-color&lt;/code&gt;를 같이 설정해두는 것이 좋다는 권장 사항도 있다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;결과적으로 &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt;가 변경되면 &lt;code class=&quot;language-text&quot;&gt;background-color&lt;/code&gt;의 변경으로 인해 리페인트가 발생하고, 이 과정에서 &lt;code class=&quot;language-text&quot;&gt;background-image&lt;/code&gt;의 그라데이션도 함께 다시 그려지는 거죠.&lt;/p&gt;
&lt;h3 id=&quot;code-classlanguage-textpropertycode로-css-변수-애니메이션&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code-classlanguage-textpropertycode%EB%A1%9C-css-%EB%B3%80%EC%88%98-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98&quot; aria-label=&quot;code classlanguage textpropertycode로 css 변수 애니메이션 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;@property&lt;/code&gt;로 CSS 변수 애니메이션&lt;/h3&gt;
&lt;p&gt;저는 위의 방법으로 문제를 해결했는데, 글을 작성하면서 새로운 방법으로 문제를 해결하는 법도 알게 되어 이를 소개해보고자 합니다. 바로 CSS의 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@property&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@property&lt;/code&gt; 규칙&lt;/a&gt;을 사용하는 것입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* gradient-color 변수 정의 */&lt;/span&gt;
&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@property&lt;/span&gt; --gradient-color&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;syntax&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&amp;lt;color&gt;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;initial-value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #ff6b6b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;inherits&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; false&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.box&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--gradient-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #ff6b6b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* --gradient-color 변수에 transition 적용 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; --gradient-color 0.5s ease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    135deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--gradient-color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 0%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    #4ecdc4 100%
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.box:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--gradient-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #9b59b6&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;video src=&quot;/bf48aa0c012e2bd09d1002ed4e23f5cb/7.mov&quot; control autoplay muted loop playsinline width=&quot;100%&quot;&gt;&lt;/video&gt;
&lt;em&gt;&lt;code class=&quot;language-text&quot;&gt;@property&lt;/code&gt;로 CSS 변수 애니메이션&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이 방법이 동작하는 이유는 &lt;code class=&quot;language-text&quot;&gt;@property&lt;/code&gt;로 정의된 변수는 브라우저가 &lt;strong&gt;명시적으로 추적하는 대상&lt;/strong&gt;이 되기 때문입니다. &lt;code class=&quot;language-text&quot;&gt;currentColor&lt;/code&gt; 처럼 다른 속성으로부터 참조되는 값이 아니라, 직접 변경되는 값으로 취급됩니다. 이로 인해 Safari에서도 &lt;code class=&quot;language-text&quot;&gt;@property&lt;/code&gt; 변수의 변경을 정상적으로 감지하고 올바르게 리페인트를 트리거합니다.&lt;/p&gt;
&lt;h2 id=&quot;마무리&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%A7%88%EB%AC%B4%EB%A6%AC&quot; aria-label=&quot;마무리 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;마무리&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExcnZ4cXo3MXNrOWJ5cGRkdWh5eW16azMwNnlqNzVlZmRtMnlxNjFjaiZlcD12MV9naWZzX3NlYXJjaCZjdD1n/dNgK7Ws7y176U/giphy.gif&apos; alt=&apos;safari&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;어쩌다 보니 새해 첫 기술 포스트도 Safari와 함께…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;오늘은 이렇게 해서 구 버전 Safari의 렌더링 최적화 과정에서 발생한 버그를 해결하는 과정에 대해 다루어보았습니다. 문제의 해결 방법은 간단했지만, 브라우저의 중요 렌더링 경로에 대한 이해가 없었더라면 아마 쉽게 해결하지 못했을 것 같아요. 새삼 기본기(?)를 잘 닦아두는 게 중요하다는 생각이 듭니다.&lt;/p&gt;
&lt;p&gt;혹시 비슷한 문제를 겪고 계신 분들께 이 글이 도움이 되길 바랍니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[다섯 마리의 토끼를 쫓았던 2025년 회고]]></title><description><![CDATA[올해 있었던 사건들과 작성한 글을 되돌아보며 내년의 목표를 새롭게 다짐해 봅니다.]]></description><link>https://wormwlrm.github.io/2025/12/31/2025-Retrospect.html</link><guid isPermaLink="false">https://wormwlrm.github.io/2025/12/31/2025-Retrospect.html</guid><pubDate>Wed, 31 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;어느덧 2025년도 끝을 향해 가고 있습니다. 매년 연말마다 써 온 연간 회고도 올해로 벌써 일곱 번째가 되었네요. 연말 회고를 쓰다 보면 휴대폰 앨범과 인스타그램 스토리를 뒤적거리게 되는데, 그러다 보면 추억에 젖어서 시간이 금방 가더라구요.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/10044199e72c7013557a1972199543be/71c1d/1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.87116564417178%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAADGklEQVQozwXBWW/aBgAAYL+s0prRAiEkHMaY047BJoCDTTkGmBvMGYLDlXAfw1GyKoEsbShp05BmSTYpo9qmVbvepqmTpmqaJu1lWl+2h0l72q/Z9wEmk8Jmg90uczBE8/2Nw/3qb69vbq9HLz8ZXZ0Pm41Mr5MubkSa28la0f9i0vjp+9kfb+bzi34uQQE0hSZjVDrqzKd9k6PW5Ljz47fTp4+aJ+Pa1flwjy8O+5kSF91tsSaVxIqCX17tvf3l9mzMFdh1IBayp8OOpI/gsr7Lp/2Dva2Pz3qv5pNfX7/65vPZ/oBrbDKMj4y4MEorCdMIy1gHrVw+5aoWKCD8voVl1raL/l4j8+nF7tHDytlJa359dPnsw3IpzHgJljZ6rAaLQZ7zrfZzNI0r1LDMsY6FAziQja/XS8HHe9wRX/zq5uB2xs+mjXY90qtHdgdscyeQStgJIxgk4TilVkoXEFgMKUV6nUytlgLDWoCvBW+njZtJ/eVsMD/rzo5L+/XgYNM9qgceDiPdHX8l63Za1Cq5UHj/XUSzBKuEAsGdFakASLqhrSjaztpaWfqz09r5fq6ZpcKUwQiJuRAx/SDyUScY8xpJCxxwYQSqDNo1TrMCki34SBUAywSEYYU0SO3I8qNu4nJUOawwaa/JZlLWozgfQ4/zlgJj1qklKrlADQpRtchulOC6RQe2DMCye4qlBa1SaDEscnF7r8qWku56xtPJP+jm6U7KNsxYT9t+Ege3NmK5CPVkWMFQWHTvHR0kAlYW7+pBsQdXlP1algbDbnPIu9bNks/7kXHDucMS1RBSjdvf/PD1v3//+d8/b//6/efZdCRfFmhBMbCml2LwEo0pPDgYskI0Ks8HLN2k7XmTGRXpdoJoRPETvjyfjQ+7m/Pr6Xdf3Bx0chFKk/VoABR+Tyq6Y8Mgn12HQJKiHxuy6LhAPCk7H286thnziHNxfsyBLFGGRXp1mUs4yxlv3IPGnBBA6kV2vRiU3EWU913YSju+yuetgxR2uoM/6+AHBdNF48FpleRTaCWoDVhlXhtEIKAGkq4ZJP8D9NXoPwhS+LAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;토끼&quot;
        title=&quot;토끼&quot;
        src=&quot;/static/10044199e72c7013557a1972199543be/a6d36/1.png&quot;
        srcset=&quot;/static/10044199e72c7013557a1972199543be/222b7/1.png 163w,
/static/10044199e72c7013557a1972199543be/ff46a/1.png 325w,
/static/10044199e72c7013557a1972199543be/a6d36/1.png 650w,
/static/10044199e72c7013557a1972199543be/e548f/1.png 975w,
/static/10044199e72c7013557a1972199543be/3c492/1.png 1300w,
/static/10044199e72c7013557a1972199543be/71c1d/1.png 1536w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;토끼 사냥&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;2024년 회고의 컨셉은 &lt;strong&gt;도전&lt;/strong&gt;이었고, 2025년의 컨셉은 &lt;strong&gt;다섯 마리의 토끼&lt;/strong&gt;입니다. 작년은 도전을 통해 다양한 영역에서 새로운 시각을 얻을 수 있었던 해였는데요, 올해는 그 시도를 바탕으로 일과 삶의 균형을 잘 챙기고자 했던 한 해였습니다.&lt;/p&gt;
&lt;p&gt;다섯 마리의 토끼를 모두 놓치지 않겠다는 마음으로 1년을 시작했지만, 한꺼번에 모든 것을 다 챙기려다 보니 결과적으로는 약간의 아쉬움이 남는 한 해였던 것 같습니다. 한 영역에 집중을 하다 보면 다른 영역에서 소홀해지는 일들이 있었거든요.&lt;/p&gt;
&lt;p&gt;나의 에너지 총량은 유한하고, 모든 영역에서 항상 최상의 컨디션을 유지할 수는 없다는 것을 다시 한번 깨닫는 한 해였습니다.&lt;/p&gt;
&lt;p&gt;이번 회고에서는 작년에 세운 목표의 달성률을 점검하고, 올해 있었던 주요 사건들을 되짚어본 뒤, 새해 목표를 세워보는 순서로 정리해 보려 합니다.&lt;/p&gt;
&lt;h2 id=&quot;2024년에-세웠던-목표&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2024%EB%85%84%EC%97%90-%EC%84%B8%EC%9B%A0%EB%8D%98-%EB%AA%A9%ED%91%9C&quot; aria-label=&quot;2024년에 세웠던 목표 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2024년에 세웠던 목표&lt;/h2&gt;
&lt;p&gt;우선 작년 회고글에서 세웠던 목표들을 다시 한번 살펴보겠습니다.&lt;/p&gt;
&lt;h3 id=&quot;일과-삶의-균형을-잘-맞추기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%9D%BC%EA%B3%BC-%EC%82%B6%EC%9D%98-%EA%B7%A0%ED%98%95%EC%9D%84-%EC%9E%98-%EB%A7%9E%EC%B6%94%EA%B8%B0&quot; aria-label=&quot;일과 삶의 균형을 잘 맞추기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;일과 삶의 균형을 잘 맞추기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;점수: ⭐⭐⭐&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/86bc181a81fc10cf2bcfe973b0529db6/1cfc2/2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 85.88957055214723%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAACFElEQVQ4y32U2U7bUBCG8/5P1Ceoql4Q9QIQDYshtLEdx8uxz758lR1IiR0YaTSSPfPPP9tZ8SYppZN911G8cxhjJrXOnfl8jHuX1RLsPcHR7nY5T08Zz1lGvtv9B0mXgVdzhuBJsSOlMMaQkidGg0uekOLkMdrjXxYszxg67+lFiWgfCV6RQgVugzQ3PPo929jRRo12lm7oUUrhPrRhAei9Y5AaKTXe/Mb130jmCu0eeA4VL0mwNn/I7AGpJFLKy4CL5oYXcDcE9ZNo1sTQoqLnOTSszSv3saZK6uuST2UHg1S3BHtLDAecvsbIilYp7u2eMvRksWXjCkywi6nPABMHG8mkoVTd5CCHga5raduWphfTdAu3pQjXaF8vAed7NAL+NbAzsJWOsm4pi5yiKGnaAmFfkCFDsUGH/VnsiDUxDDFitGbfK3LlWTeOG+HZqkg9KIZe0PcDQlaIcE+uf7BT3+lNTtdXGGNPw1kdp+unknrRoZ0nk5EnGansce9sUWDLYto85Utq/4tSX2GtQQhB13XTCl0seZTaRrYGqn1DPFSkIiflOe6Q07prBHeY0CziTiWf3e9ox172Gv/6CvuSsPlNeNhAWSKrO2TIz05vMeX5Pb99IWlNbGpivps0NQ1JG756UFZzyotHYtxNISb9kIpLrTpj+BnTcXp1XU86P7M5uwXDz8C/SjjacUvGZCEE/gFQtTIXi9FCuAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;오각형&quot;
        title=&quot;오각형&quot;
        src=&quot;/static/86bc181a81fc10cf2bcfe973b0529db6/a6d36/2.png&quot;
        srcset=&quot;/static/86bc181a81fc10cf2bcfe973b0529db6/222b7/2.png 163w,
/static/86bc181a81fc10cf2bcfe973b0529db6/ff46a/2.png 325w,
/static/86bc181a81fc10cf2bcfe973b0529db6/a6d36/2.png 650w,
/static/86bc181a81fc10cf2bcfe973b0529db6/1cfc2/2.png 900w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;일과 삶의 오각형&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;작년에 세웠던 목표를 이상적으로 잘 챙기지 못했다는 아쉬움이 있어서 3점을 주었습니다. &lt;strong&gt;일과 삶&lt;/strong&gt;이라고 뭉뚱그려 이야기했지만 여기에는 일, 취미, 연애, 건강, 자기계발이라는 다섯 가지의 카테고리가 있었습니다. 연애는 너무 개인사라서 제외하고 말하자면…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;일&lt;/strong&gt;: 상반기에는 번아웃이 와서 힘든 시간을 보냈지만, 잘 극복해냈고 하반기부터는 업무에 완전히 몰입하면서 좋은 마무리로 이어졌습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;취미&lt;/strong&gt;: 다른 영역에서의 몰입도가 취미 활동의 의욕에도 영향을 끼쳤습니다. 연초에는 의욕이 많이 떨어졌지만, 연말에 밴드 공연이라는 성취를 이루면서 좋은 마무리로 이어졌습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;건강&lt;/strong&gt;: 상반기에는 꾸준한 운동 습관을 유지했지만, 시간이 갈수록 운동 강도와 빈도 면에서 게을러졌다는 점을 부인할 수 없을 것 같네요. 연말부터는 운동에 대한 의욕을 못 느껴서 행동으로 옮기지 못했던 시간이 길었습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자기계발&lt;/strong&gt;: 역시 상반기에는 글쓰기에 꾸준한 노력을 들였으나, 중간에 공백기가 꽤 있었고 목표로 했던 글 개수를 채우지 못해서 아쉽습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;한 영역에서 느낀 부정적 감정이 다른 영역에도 영향을 끼치게 되는 경험을 하면서 &lt;em&gt;‘삐뚤한 오각형’&lt;/em&gt; 으로 지냈던 시간이 많았던 것 같습니다. 모든 영역에서 항상 완벽함을 유지할 수는 없다는 생각도 들었고, 현실적인 균형에 더 신경 써야겠다는 결론을 내리게 되었습니다.&lt;/p&gt;
&lt;h3 id=&quot;회사에서-1인분-이상의-몫-해내기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%9A%8C%EC%82%AC%EC%97%90%EC%84%9C-1%EC%9D%B8%EB%B6%84-%EC%9D%B4%EC%83%81%EC%9D%98-%EB%AA%AB-%ED%95%B4%EB%82%B4%EA%B8%B0&quot; aria-label=&quot;회사에서 1인분 이상의 몫 해내기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;회사에서 1인분 이상의 몫 해내기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;점수: ⭐⭐⭐⭐&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExOHAzOXBxdTY2bHJicDJrcnplbjlnMGRvMzA3aWJvdzI4OXl6cHMxYiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/6g9fN5IYV9Oc8/giphy.gif&apos; alt=&apos;꽃&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;사두용미&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;회사 업무에서는 4점을 주었습니다. 초반에는 업무에 대한 의욕이 많이 떨어졌지만 이를 잘 극복해내고 하반기에는 몰입해서 좋은 결과물들을 낼 수 있었기 때문입니다.&lt;/p&gt;
&lt;p&gt;연초에는 번아웃이 찾아왔습니다. 그 이유는 갑작스러운 스펙 변경으로 인해 기존에 (꽤 열심히) 구현해둔 부분들이 많이 폐기되기도 했고, 공감할 수 없는 의사 결정들이 이어지면서 점점 무기력해지는 느낌이 들었기 때문입니다. 게다가 &lt;a href=&quot;https://www.bbc.com/korean/news-42843167&quot;&gt;1월 증후군&lt;/a&gt;도 겹치면서 스트레스가 상당하던 시기가 있었습니다.&lt;/p&gt;
&lt;p&gt;출근하는 게 싫다고 느껴질 정도로 힘든 시기였지만, 다행히 팀원들과 솔직하게 감정을 나누고, 시간의 흐름과 업무에 대한 책임감을 바탕으로 서서히 회복할 수 있었습니다. 이후에도 프로젝트 출시일이 여러 차례 연기되거나 기획이 자주 바뀌는 등 개발 외적인 변경 상황이 계속 이어졌는데, 한 번 면역이 생긴 덕분(?)인지 크게 멘탈이 흔들리지 않고 잘 대처할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;좋게 이야기하자면 외부의 변경과 자극에 덜 민감해졌다고 이야기할 수도 있지만, 나쁘게 말하자면 이해하기 어려운 의사결정에 대해서 적극적으로 반박하지 않고 수용하게 되는 태도가 생겼다고도 볼 수 있는 것 같습니다.&lt;/p&gt;
&lt;p&gt;물론, 개발의 결과물에 대해서는 여전히 주인의식과 책임감을 가지고 있습니다! 주어진 스펙을 최대한 좋은 결과물의 코드로 구현하기 위해 매일 결과물을 다듬고 개선하는 데에 집중하고 있거든요.&lt;/p&gt;
&lt;p&gt;다만 대기업이다 보니 &lt;em&gt;상위 레벨에서 결정된 사항에 대해서는 개발자 개인의 레벨에서 타협하기 힘든 부분이 있다&lt;/em&gt; 라는 점을 받아들이게 된 것 같습니다. 이게 말로 이해하는 건 쉽지만, 실제 상황에서 받아들이는 것은 쉽지 않은 일이더라구요. 😅&lt;/p&gt;
&lt;p&gt;한편으로, 올해 회사에서 개발한 업무의 큰 줄기를 정리해 보니 다음과 같았습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;회원 가입과 댓글/대댓글, 미디어 자동 재생, 소셜 로그인 등의 스펙 구현&lt;/li&gt;
&lt;li&gt;1차·2차 QA 대응&lt;/li&gt;
&lt;li&gt;인터렉션이 포함된 페이지 구현 및 인터렉션 패턴의 일반화·추상화 작업&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;스펙 구현에 있어서 결과물은 훌륭한 퀄리티로 완성했다고 자부할 수 있지만, 종종 작업 방향의 갈피를 정확히 못 잡고 헤맨 적이 있어서 조금 아쉬움이 남습니다. QA 기간 때에는 야근을 많이 해서 체력적으로는 힘들었지만 등록된 티켓을 하나씩 처리해나가는 것은 나름 의미있게 느껴졌구요. 작년에 이어서 복잡한 인터렉션 작업도 여전히 처리하게 됐는데, 이건 정말 할 때마다 어렵고 힘든 일이라는 걸 느낍니다.&lt;/p&gt;
&lt;p&gt;4분기에는 TF를 통해 평소 글또와 커피챗을 통해 알고 있던 &lt;a href=&quot;https://junilhwang.github.io/TIL/&quot;&gt;준일&lt;/a&gt;님과 같은 프로젝트에서 협업하게 되었는데 그 경험이 인상 깊었습니다. 낯선 코드베이스임에도 불구하고 능숙하게 적응해 나가는 모습, 적극적인 기술 공유 해주시는 모습, AI를 업무에 적극적으로 활용하고 계시는 모습이 멋있고 대단하게 느껴졌습니다.&lt;/p&gt;
&lt;p&gt;그러다보니 올해는 개인적으로 제가 팀 내 기술 공유에 적극적으로 참여하지 못한 것이 아쉽게 느껴져서, 이를 내년의 목표로 삼아보려고 합니다.&lt;/p&gt;
&lt;h3 id=&quot;데일리-크리에이티브-책-완독하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%8D%B0%EC%9D%BC%EB%A6%AC-%ED%81%AC%EB%A6%AC%EC%97%90%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EC%B1%85-%EC%99%84%EB%8F%85%ED%95%98%EA%B8%B0&quot; aria-label=&quot;데일리 크리에이티브 책 완독하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;데일리 크리에이티브 책 완독하기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;점수: ⭐&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/efec371af969f47623a50edf05c6fd8b/7bf07/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 52.14723926380368%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABNUlEQVQoz42S2W6DQAxF+f//isQr5SEsw86wikUJi0DAjeyGVikk6kiWPYCuj69RhmHA5XLB9XqFrutQVRW6/gVN0+D7Puhs28ax15+OQh90XQcS7vuO6z3GceTYzy78qYGyLgsSKZlGCMHZNE1YloU4jtG2LTdb1/VAc0arLMuCsiyR5zmKouCcpimyLEOWpSiKHFJKfkfU8zy/iB0J1wVpmiCKIoRhCCljroMgQBD4/IxI6e66Lt+Jeic+CBJhFIVwHIdH9jwPQtg8sm3bLFBVFZqmYULy+Z3Yk3DlkUjIdR3Ovu89hQVTUU2iZ/6dLqUsv70j35IkYb9odKrrun4h+rvhtx7SaBTkFRFSJu9utxumafrXhn89DEMel4L8MwyDBR1HwLYt/gv6vue43+8/Dc4IHwlm/c9QyGXeAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;3트&quot;
        title=&quot;3트&quot;
        src=&quot;/static/efec371af969f47623a50edf05c6fd8b/a6d36/3.png&quot;
        srcset=&quot;/static/efec371af969f47623a50edf05c6fd8b/222b7/3.png 163w,
/static/efec371af969f47623a50edf05c6fd8b/ff46a/3.png 325w,
/static/efec371af969f47623a50edf05c6fd8b/a6d36/3.png 650w,
/static/efec371af969f47623a50edf05c6fd8b/e548f/3.png 975w,
/static/efec371af969f47623a50edf05c6fd8b/7bf07/3.png 1128w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;3트도 실패, 이 책을 읽는 것은 왜 이리 힘든 것일까…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;올해 3월까지는 책 읽고 느낀점 메모하기를 유지했지만 그 이후로는 흐지부지되고 말았고 결국 완독하지 못 했네요. 요즘 들어 노력을 들여야 하는 습관이 얼마나 지키기 힘든 것인지를 새삼 깨닫고 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;일기-쓰기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%9D%BC%EA%B8%B0-%EC%93%B0%EA%B8%B0&quot; aria-label=&quot;일기 쓰기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;일기 쓰기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;점수: ⭐⭐&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;상반기에는 월간 개인 감정 기록 정리도 시도했고, 하반기부터는 업무 일지를 쓰기 시작했습니다. 이를 잘 유지하고 싶어서 개인적으로 리마인더도 쓰고 있는데, 꾸준한 습관으로는 잘 이어지지 않고 있는 것 같아서 2점을 주었습니다.&lt;/p&gt;
&lt;p&gt;데일리 크리에이티브 책 완독의 실패 이유도 &lt;em&gt;노력을 들여야 하는 습관&lt;/em&gt; 의 어려움 때문인데, 이를 잘 극복하기 위해서 보상 체계를 한 번 잘 짜봐야 할 듯 합니다.&lt;/p&gt;
&lt;h3 id=&quot;분야와-상관없이-새로운-도전-시도하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%B6%84%EC%95%BC%EC%99%80-%EC%83%81%EA%B4%80%EC%97%86%EC%9D%B4-%EC%83%88%EB%A1%9C%EC%9A%B4-%EB%8F%84%EC%A0%84-%EC%8B%9C%EB%8F%84%ED%95%98%EA%B8%B0&quot; aria-label=&quot;분야와 상관없이 새로운 도전 시도하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;분야와 상관없이 새로운 도전 시도하기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;점수: ⭐⭐&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;사실 작년에 많은 도전을 했었는데요, 그러다 보니 올해는 경험의 폭을 넓히는 것보다는 깊이를 쌓는데 더 신경을 썼던 한 해였습니다. 새로운 도전의 깊이도 크지는 않다 보니, 이것저것 &lt;em&gt;다양한 체험&lt;/em&gt; 들을 했다는 느낌이 더 많이 드는 것 같아서 2점을 주었습니다.&lt;/p&gt;
&lt;p&gt;개인적으로는 장거리 운전도 해보고, 새로운 밴드 팀에도 들어가고, 혼자 해외를 가보기도 하고, AI를 통해 좀 더 아웃풋을 내보려고 하는 등 여러 방면에서 소소하지만 의미 있는 시도를 했다고 생각합니다.&lt;/p&gt;
&lt;h3 id=&quot;블로그-테마-오픈소스로-공개하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%B8%94%EB%A1%9C%EA%B7%B8-%ED%85%8C%EB%A7%88-%EC%98%A4%ED%94%88%EC%86%8C%EC%8A%A4%EB%A1%9C-%EA%B3%B5%EA%B0%9C%ED%95%98%EA%B8%B0&quot; aria-label=&quot;블로그 테마 오픈소스로 공개하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;블로그 테마 오픈소스로 공개하기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;점수: 🌧️&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;블로그 테마 관리에 대한 우선 순위가 지금은 많이 낮아진 상태라서 요 목표도 잠정적으로는 중단을 하고자 합니다.&lt;/p&gt;
&lt;h2 id=&quot;2025년-타임라인&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2025%EB%85%84-%ED%83%80%EC%9E%84%EB%9D%BC%EC%9D%B8&quot; aria-label=&quot;2025년 타임라인 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2025년 타임라인&lt;/h2&gt;
&lt;p&gt;아래는 2025년에 있었던 주요 사건들을 타임라인 형식으로 정리한 것입니다.&lt;/p&gt;
&lt;h3 id=&quot;유니코드-문자열-정규화&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%A0%95%EA%B7%9C%ED%99%94&quot; aria-label=&quot;유니코드 문자열 정규화 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;유니코드 문자열 정규화&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2024/12/30/String-Normalize.html&quot;&gt;normalize 메서드를 이용해 유니코드 문자열 정규화하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7c8481e81c692796af86b5f93ed2d72b/0786c/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 42.331288343558285%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABQklEQVQoz3WQi26DMAxF+/+fNqlsWqV2rLCGQCGQhEdIKNDHnZytVVetlqxE9vXJdRaXywUUpmuR7CJwFkPkCRolwFmENIkQblZ4f1si+lyjyBhSFkGKDH2nMFjj54lDubgCa63wunzBx2aF5GuLeLuB7WrMo0WtS2zDNRpdwZoa1jTguwgi5xhcjx/GA/BwOEBKBaU1KilRVhWM6eHcAFJwzjFNM7rOwDoHzlPkRYFxmnBl/AE6Z5GmKUohUFUl8jzHfr/3GQQByrKEEALGGMRxjCRhUEqhaZr/V3bOeaCU0sOuwHEcvXvqEazve2itb7phGJ4DSUBCclMUBdq2xfS7EtUITECCWGu94+nZyiRkjHkQgbMs80On0wnn8xlhGHqH9Ai5Jh39KwX1b8B7u49BNQJSHo9Hf87zfLvTSbB7h9/b/WPvlK2G+AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;1&quot;
        title=&quot;1&quot;
        src=&quot;/static/7c8481e81c692796af86b5f93ed2d72b/a6d36/3.png&quot;
        srcset=&quot;/static/7c8481e81c692796af86b5f93ed2d72b/222b7/3.png 163w,
/static/7c8481e81c692796af86b5f93ed2d72b/ff46a/3.png 325w,
/static/7c8481e81c692796af86b5f93ed2d72b/a6d36/3.png 650w,
/static/7c8481e81c692796af86b5f93ed2d72b/0786c/3.png 663w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;결합 문자가 포함된 글자를 어떻게 정렬할 수 있을까?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;회사 업무 중 유니코드 문자열 정규화의 필요성을 느끼게 되어 작성한 글입니다. 시기 상으로 정확하게는 작년 12월 말에 작성한 글인데요, 작년 회고 글 이후에 작성한 글이라 요번 회고에서 제일 먼저 다루게 되었습니다.&lt;/p&gt;
&lt;p&gt;문제를 해결하는 코드를 ChatGPT로부터 알게 되었는데, 정확한 동작 원리에 대해서는 알지 못해서 이를 정리해보고자 글을 작성했습니다. 그런데 해당 스펙이 제거되는 바람에 실제 업무에서는 사용하지 못하게 됐다는 후문이… 😅&lt;/p&gt;
&lt;h3 id=&quot;글빼미-고도화&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%B9%BC%EB%AF%B8-%EA%B3%A0%EB%8F%84%ED%99%94&quot; aria-label=&quot;글빼미 고도화 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글빼미 고도화&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7afc6c8c40a4b210aab701e24c763440/774b6/geultto-owl-slack.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 83.43558282208589%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAACkklEQVQ4y5VTa4+bMBC8//+Hqn7ou9eqH+8uIYSAweZhk8RAgLS6kMxW65xpU6mVijSaXWOW8e74rgpXWD8+UpKm1LUtGmtx6DpMpxOm6UTnaaL/ee46XVGRZsiyDFIVlOaaojijTJUkyxpFadAPRxyGI9rD6Njl/TX+hRGnacIdV7VdDyFz5NUOUlsIWSBJFUWxgNYG/fgDXT+gPQxouh79eEQ/fp+L+/g0na8F76s3+Lr6DJUWCNchVqsVlJQoi5yUkrTf7ynPczJaUxAEVBTF349MRPhUvqYvqw8kE0UiFSSEoDAMSUpFUkqkaYqnpyfHXdehaVpcAPC3f8Ip7McemcxQFIVDnucOlTHYKoVk+YRYCJRlCa01xnHE5XLBNE0O5/N5xrXgoUccx0iSxDErEUIgThJsogjxZnOzzvv83s1mM+f8Q1ew7VosFgtEUYT1eo0gCLAKAqzD0OV+PXzJmaP12vWa3zGWy6VT7woej0eXMIypUWmNvbVo2JcNo3nhFm3bwtrGrVlrZzSNBddxBbu+Q10b2G4kYwfS24Z27ZG2zYCd7VDvO2ztFVVtsW97h7qu3cR3piTgMk+Z3hev8HHxFlmisApDd3whUkipsNnErjfcKzb/w8MDEiFwvlxuhuEfZ5uv1Tv6Ft5TnhUkZUZKSoqiiLTWLpZSOv8ZY2gYBod/+ZCGcYRSyinxluGY+6mLHEkUQqQpqqpCWZTo+97Z5fn5+QaTv3psVp6et4KHnyC/87Zi2zhLvdjIW4cx24aNyjdCZtIpdbGUrmcMv8bKOTbG8EBumB3Ck3cFD4eDU8F/YUXMrMIr4zVm70NWynu8R716Ljz7kOX6q8W98rzdbn/zqJnZxz5nf/JJfwIFQvEkJbXqpAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;피드백 봇&quot;
        title=&quot;피드백 봇&quot;
        src=&quot;/static/7afc6c8c40a4b210aab701e24c763440/a6d36/geultto-owl-slack.png&quot;
        srcset=&quot;/static/7afc6c8c40a4b210aab701e24c763440/222b7/geultto-owl-slack.png 163w,
/static/7afc6c8c40a4b210aab701e24c763440/ff46a/geultto-owl-slack.png 325w,
/static/7afc6c8c40a4b210aab701e24c763440/a6d36/geultto-owl-slack.png 650w,
/static/7afc6c8c40a4b210aab701e24c763440/774b6/geultto-owl-slack.png 738w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;AI를 이용한 피드백을 받을 수 있다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;1월 1일을 기점으로, 글또 활동 중에 개발한 봇 &lt;a href=&quot;/2024/10/12/Geultto-Owl-Project.html&quot;&gt;글빼미&lt;/a&gt;의 AI 피드백 기능을 오픈했습니다. 글빼미는 기존에 글또 참여자들이 제출한 글의 어뷰징을 방지하는 목적만 있었는데, 이번 업데이트를 통해 제출한 글에 자동으로 피드백을 남겨주는 기능을 추가했습니다.&lt;/p&gt;
&lt;p&gt;이 기능을 1월 1일에 배포하기 위해 작년 12월부터 &lt;a href=&quot;https://heuristicwave.github.io/&quot;&gt;지훈&lt;/a&gt;님과 퇴근 후 짬짬이 논의를 하면서 AI를 활용한 블로그 자동 피드백 시스템 개발을 시작했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8ad839ec6d939f0393dd5629f1f3ab07/985a9/9.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 30.67484662576687%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABT0lEQVQY042MTW/aUBRE+aPdZ9WfUqm7bKqqSYOyKVLTRaKkICUhmFIaLEoDBlOFGNuAsfm0n/0cfCI/pKrLjDRXM6OrU0ikxLHHiHBDIkJkHJEmguckRoqQ50SQipA0jtSW93zfyX3O9/9VyM/DyOW00uTLdYvSjU7pVqdYbvLpos7n7z/5eK5xfNXgpNzk6LLB0eUPipVf6iffS7U/fG30mS23e2Cp3uPN+2+8/XDFweEF784aNIcTaoaD1neo9mw0w6Fm2FR7YzTDVlnr2yrfdS2uOyOCjdgDn9wZ9XaX++4AvTdkOLLYrgJWgUe0WZKlgtdKAaXY4k91/EWHqfeb2byNNdGx3BaPTou/Yx3Xa+N6HeJkjUwFiYyQacxul/1zlmV7YCxCAt9gsTaZ+gOWa5PFymQWmCq784Hq88UALzCVp36fYGUBOQgFy4EvvK64IRbwgM0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;성윤님 블로그&quot;
        title=&quot;성윤님 블로그&quot;
        src=&quot;/static/8ad839ec6d939f0393dd5629f1f3ab07/a6d36/9.png&quot;
        srcset=&quot;/static/8ad839ec6d939f0393dd5629f1f3ab07/222b7/9.png 163w,
/static/8ad839ec6d939f0393dd5629f1f3ab07/ff46a/9.png 325w,
/static/8ad839ec6d939f0393dd5629f1f3ab07/a6d36/9.png 650w,
/static/8ad839ec6d939f0393dd5629f1f3ab07/e548f/9.png 975w,
/static/8ad839ec6d939f0393dd5629f1f3ab07/3c492/9.png 1300w,
/static/8ad839ec6d939f0393dd5629f1f3ab07/985a9/9.png 1512w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;&lt;a href=&quot;https://zzsza.github.io/diary/2025/03/30/geultto-operation-retrospective/#%EB%B4%87-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B0%9C%EB%B0%9C-1&quot;&gt;성윤님이 블로그&lt;/a&gt;에서 언급하길, 이것을 꿈의 실현이라고 말씀주신 점이 개발자 입장에서 매우 보람찼다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글또 운영자이신 성윤님이 많이 기대해주셨고, 좋아해주신 기능이어서 상당히 뿌듯했습니다. 추후에는 글또의 공식 블로그에도 &lt;a href=&quot;https://geultto.github.io/blog/geultto-owl/introduction/&quot;&gt;『글또의 제출 글 검수 자동화 봇: 글빼미를 소개합니다!』&lt;/a&gt;라는 제목으로 시리즈 글을 게시하기도 했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/abc76b1dd8381f986619a710f7d96b1a/169e3/17.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 46.012269938650306%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAABbUlEQVQoz11QSW7cMBCcZ3g00WinJC4SV0lWEB99DnLwyT9I/n8to3tCw/ChwGY1WVXdl/e///Dn7TeO3aNVAY3yKIXGtde4dpJRDAaFWFD0CjdCN/NJXDUumOQCbSyGXuBSdyPE6wTjV8zaQ9kEaTxG7aAWD20j5iVAuw2jsngqGxRli+Le4Xrvcat63OsedTPgXrW4XG8VlujhQoQLO5zfsLoIZRyObcd5/oJ1iSHViqoZ0HQCdTugaQWqusetbBhl1ZFgDSUVUkqwJBg2hPSMkI7HPe4Po7BjsZF7cTsZaT+Z14vnHo3OCSe54jhfWEzqlZv0yKyBk0ptoYzFrFYGcdQncG0cv6UeC4pJs1h2+v4pi1MvfyTQP0pF9Tgb9EI+BMmdRqRxaAwfD77TWLyCeCDtP7nv485mJK7+JyOQKScsftTslEkxKXYjLp/fQfwkzedJKakmfCa0PrED7SuPnPf3FZn7+pb2nusPakARKTu9Ai4AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;회고 피드백&quot;
        title=&quot;회고 피드백&quot;
        src=&quot;/static/abc76b1dd8381f986619a710f7d96b1a/a6d36/17.png&quot;
        srcset=&quot;/static/abc76b1dd8381f986619a710f7d96b1a/222b7/17.png 163w,
/static/abc76b1dd8381f986619a710f7d96b1a/ff46a/17.png 325w,
/static/abc76b1dd8381f986619a710f7d96b1a/a6d36/17.png 650w,
/static/abc76b1dd8381f986619a710f7d96b1a/e548f/17.png 975w,
/static/abc76b1dd8381f986619a710f7d96b1a/3c492/17.png 1300w,
/static/abc76b1dd8381f986619a710f7d96b1a/169e3/17.png 1682w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;이번 회고에 달린 피드백&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;여담으로 현재 회고에 대해 제가 받은 피드백은 위 사진과 같습니다.&lt;/p&gt;
&lt;h3 id=&quot;글또-운영진-모임&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-%EC%9A%B4%EC%98%81%EC%A7%84-%EB%AA%A8%EC%9E%84&quot; aria-label=&quot;글또 운영진 모임 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 운영진 모임&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8418ae7387aae906cd6cb83c57730069/72e01/6.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAUBAwT/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAGTLWLQWg//xAAZEAACAwEAAAAAAAAAAAAAAAABAgAREhP/2gAIAQEAAQUCzKMCGkbS6UDsJ//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAECAQE/AUf/xAAdEAABBAIDAAAAAAAAAAAAAAABAAIQERIhIkGR/9oACAEBAAY/AtUV17BpvELJpOo//8QAGxAAAwEBAAMAAAAAAAAAAAAAAAERIUExUXH/2gAIAQEAAT8hbxYvpBlAkaM2eR32QKMUnze4f//aAAwDAQACAAMAAAAQAA//xAAXEQADAQAAAAAAAAAAAAAAAAAAARFx/9oACAEDAQE/EHpUf//EABcRAAMBAAAAAAAAAAAAAAAAAAABEVH/2gAIAQIBAT8QWQo//8QAHBABAQADAAMBAAAAAAAAAAAAAREAITFBYZFx/9oACAEBAAE/EEokeYN42E10oWZQNhRx2Rgk16efmSTNTtb3fyYUjuV9v3P/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;운영진 모임&quot;
        title=&quot;운영진 모임&quot;
        src=&quot;/static/8418ae7387aae906cd6cb83c57730069/6aca1/6.jpg&quot;
        srcset=&quot;/static/8418ae7387aae906cd6cb83c57730069/d2f63/6.jpg 163w,
/static/8418ae7387aae906cd6cb83c57730069/c989d/6.jpg 325w,
/static/8418ae7387aae906cd6cb83c57730069/6aca1/6.jpg 650w,
/static/8418ae7387aae906cd6cb83c57730069/7c09c/6.jpg 975w,
/static/8418ae7387aae906cd6cb83c57730069/72e01/6.jpg 1024w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;1월 초에는 글또 운영진 모임에 참석했습니다. 글또 운영진 크루 별 활동 내역 공유와 남은 기간 동안의 방향성을 정리하고 네트워킹을 진행하는 자리였습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ebd36ba018eec33ccaa8f7ce022c93b6/cd78c/7.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 49.69325153374233%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAACl0lEQVQozyWSW2/aBgCF/Tpp0v7c0qhZtDXSpGna4zRpSranRGsbFkhIgVAIFxuDwTbGF0ywISaBuCU3GDRbUnXdlixrHqbuJ3xT6MN5POfoXIRcocCjpUdsbERY/GIJrVIhDPYZdDsc+j5SoYDXbHJ61EetVth+luDd39e8Gp8yPh1yfhwyHZ1wMTnn5voPhOWVZb5c+gw595zFhQXW11ap7GZJRaOUd7NI6R3EdBpdLpFPJ1n+YYXXv04JA5+w63HQcekHHuFBh6uLCcIwPETMJslubyHvZtAkcUa2agpNTcU1DJRCASmTwaoq9Lo+o+GQjqEROBZdx6Rj1vEMncvpLwjT82NS0afsbEVJxzdxG3U6TZvAtdhr1PEdB7NWQyvJaCUJ22wwPTvBVasELQdXU2mUS+zpKr9NxggVWWL1x+/JpbZRxDxt26TTvHe28CwTS9XQ5DI1ScKoyPR7+4yPX9LUagRNG1spI6Z3UIv5D4Kra2t8vviQeqWEIuVxTZ223WDP0GlbJoZS5Xk8wW4ihV6RaRgaL4IAQyzSqqt0nQaeZWBVy1zeCw7DPvH1n0hEIxSzO9iGiqkq6GUJzzaxNBWlKFIrijhaFVkWOQkHuNUyfb/Ffsumben0O3tcvZogjM+OyWxHyaWekU1s4WgKtl4jFYshZzMoxSILDxeZm5vnm6+/Ir61wfl9ZL3G0b7HUeDT8xx6XvPDyicvB+SSMfLJTeKRx6x89y3peIzkz0/JxDfRxQLzcw/46ONPEASBT+cfzP7XMnWGg2B2l/Cgy1HP5/erC4Trv94yHZ0yGr7Ab7dYj0TwWu6sj8nojLdvrhj0D4nGNnn85AmarnP37pY3ry+5vflzhrt/bri7vea/9//yP8tAWaW4JEWsAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;운영진 모임&quot;
        title=&quot;운영진 모임&quot;
        src=&quot;/static/ebd36ba018eec33ccaa8f7ce022c93b6/a6d36/7.png&quot;
        srcset=&quot;/static/ebd36ba018eec33ccaa8f7ce022c93b6/222b7/7.png 163w,
/static/ebd36ba018eec33ccaa8f7ce022c93b6/ff46a/7.png 325w,
/static/ebd36ba018eec33ccaa8f7ce022c93b6/a6d36/7.png 650w,
/static/ebd36ba018eec33ccaa8f7ce022c93b6/e548f/7.png 975w,
/static/ebd36ba018eec33ccaa8f7ce022c93b6/cd78c/7.png 1236w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;남은 기간동안 무엇을 해보면 좋을까?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;저는 이 자리에서 &lt;em&gt;남은 기간동안 글빼미의 피드백 강도 설정 기능 추가 구현을 하겠다&lt;/em&gt; 고 약속했고…&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 390px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/49cf96cd08d0edcea34ca3a2f1067d0d/727ba/feedbackLevel.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 123.31288343558282%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAZCAIAAAC+dZmEAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC1klEQVQ4y42Uy24cRRSG+2F4CF6AHUJ5hKzIA7Bhw0WCbLLIIpssYIUEkUAyCIOUZANJDEGyZYxt7JnuGbtnutp9qamqrktXd91RzyQhmoxj//pUZ1H665w6dVSRYZTs7faU5kXBOQ/XkDFGa22tjbocxPfvUZD9tbt7kechBO/9282ccyGEUiry3qteWeteHblcjXPOWmedM8Yopd48ccjcSjk6PZydx1kGppMJACCJkyQep2fT8+lkPkvTNE2SxFq7ZpZSRkK0/+zvTMb70+lZlmVJkpyenIzPZvv/Tg7H55N0Pjo9HccxxnjN33VdpJXKspyQBmPMGMMYw7peMAlwlzc95pI2DYQQY6y1XjcLIY6PjhBC12nVutkYwxijlJZlOaSFcLFYXFxcFEVZ1TWEMAd5URRVVa2e55WGO1tr27blnFNKhRB8KcZ409DVk3C2isJa617Kez+YpZQHBwdpmr7ZzzW51/SibOfcYimM0LBiXJYlQphR5r13m7QahyGz955SyhhrmqHhlFKEECENY8xdopX5Rbf39vYuK9tfotfLRrCGsIar5AgNQAillBsrXw3sUHYIgRBCm6YhDaWUYEwIQcv7d1Iuc7s1nLXWmG4Yz7Y9PD45GY2zvPAhGOutC9YPaOuUsRtxPvRdH2Ghk3l5BqpZgYjUWKj/aTW5hKKRbW8iJhVGqCFYcOadddZciTWK8lZ0KjJaka6aZec5AN4Zo3tr1FVoZ7RWffT5N89v3v7h1t1HN+88fP+Tnz/4dPtKbnz2y3sfb/20E0d/HIPt7acPfv3zweODrWfJ1rP4Sn7cSb7/fTSa1ZH3tsnn88m4LMByKlwI/q28/IaMjrhoS4jKqi6riouWcbERLtrVbk1IvoAA1pTzSGutlRqGdYibpZUGAMRJHKy/8fWX79796J0vPvzq+ePoOp+G915r3SsVQvhtevTd30+/3X8yWRT/AXTCcg2Yu4OAAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;피드백&quot;
        title=&quot;피드백&quot;
        src=&quot;/static/49cf96cd08d0edcea34ca3a2f1067d0d/727ba/feedbackLevel.png&quot;
        srcset=&quot;/static/49cf96cd08d0edcea34ca3a2f1067d0d/222b7/feedbackLevel.png 163w,
/static/49cf96cd08d0edcea34ca3a2f1067d0d/ff46a/feedbackLevel.png 325w,
/static/49cf96cd08d0edcea34ca3a2f1067d0d/727ba/feedbackLevel.png 390w&quot;
        sizes=&quot;(max-width: 390px) 100vw, 390px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;요 작업 이후에 실제로 글빼미 피드백 강도 설정 기능을 구현했다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://heuristicwave.github.io/&quot;&gt;지훈&lt;/a&gt;님과의 협업을 통해 실제로 피드백 강도 설정 기능을 추가했습니다. 또한 &lt;a href=&quot;https://geultto.github.io/blog/geultto-owl/feedback/&quot;&gt;해당 기능의 구현 과정&lt;/a&gt;을 글또 블로그에도 정리해서 올렸습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8a51effebdfb187c6aa017130cb7818d/b4294/8.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.12883435582822%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAIBA//EABYBAQEBAAAAAAAAAAAAAAAAAAECAP/aAAwDAQACEAMQAAAB6VtTWIMy5aNDb//EABoQAAMAAwEAAAAAAAAAAAAAAAABEQIQQRL/2gAIAQEAAQUCR0xSaqTcJTO+juv/xAAWEQEBAQAAAAAAAAAAAAAAAAAQARH/2gAIAQMBAT8B0p//xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQIBAT8ByDP/xAAbEAACAgMBAAAAAAAAAAAAAAAAARExECFBIP/aAAgBAQAGPwLZGN9IFFDSuznn/8QAHhAAAwABBAMAAAAAAAAAAAAAAAERQSExUXEQYaH/2gAIAQEAAT8hZXoRbX0bUWKe7Ug2zNHEwsDXU5m+IveqpWcjx0VtqXx//9oADAMBAAIAAwAAABDg0UD/xAAWEQEBAQAAAAAAAAAAAAAAAAABECH/2gAIAQMBAT8QAE2z/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAxEf/aAAgBAgEBPxBTlkgXb//EABsQAQEAAwEBAQAAAAAAAAAAAAERACExQVFh/9oACAEBAAE/EK24bc/chR4AgQKC33LyeFNvHBQUWiY9AEIcG3BrmwVZ8p5AyQNga19YEAaDxizVblfce5//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;1등&quot;
        title=&quot;1등&quot;
        src=&quot;/static/8a51effebdfb187c6aa017130cb7818d/b4294/8.jpg&quot;
        srcset=&quot;/static/8a51effebdfb187c6aa017130cb7818d/d2f63/8.jpg 163w,
/static/8a51effebdfb187c6aa017130cb7818d/c989d/8.jpg 325w,
/static/8a51effebdfb187c6aa017130cb7818d/b4294/8.jpg 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;럭키 드로우에서 1등했다. 성윤님~ 이거 잘 쓰고 있어요…!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;여담인데 이날 럭키 드로우에서 1등 상품인 구글 픽셀 버즈에 당첨되었습니다. 마침 쓰던 무선 이어폰이 고장나는 바람에 요거로 교체해서 잘 쓰고 있습니다. 😅&lt;/p&gt;
&lt;h3 id=&quot;독서&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%8F%85%EC%84%9C&quot; aria-label=&quot;독서 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;독서&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2025/02/02/Micro-State-Management-with-React-Hooks.html&quot;&gt;리액트 훅을 활용한 마이크로 상태 관리&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8a5a8b11c139085ee6310e0bd44cec2b/e2d85/1.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFA//EABYBAQEBAAAAAAAAAAAAAAAAAAIBA//aAAwDAQACEAMQAAABZnasGyhgyf8A/8QAGBAAAwEBAAAAAAAAAAAAAAAAAAECAxH/2gAIAQEAAQUCqm1ph06zKiqUDfX/AP/EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAEDAQE/AYj/xAAXEQADAQAAAAAAAAAAAAAAAAAAARIh/9oACAECAQE/AawpH//EABwQAAAGAwAAAAAAAAAAAAAAAAABAhARMRKR0f/aAAgBAQAGPwLglGmwOjppH//EABsQAAICAwEAAAAAAAAAAAAAAAABEUEhMVGx/9oACAEBAAE/IZQ5adCRZt3I8eoh2cFCeEs8HMbbP//aAAwDAQACAAMAAAAQQD//xAAXEQEBAQEAAAAAAAAAAAAAAAABABFR/9oACAEDAQE/EFbkPt//xAAXEQADAQAAAAAAAAAAAAAAAAAAAREx/9oACAECAQE/EIdDph//xAAcEAEAAgMBAQEAAAAAAAAAAAABABEhMXFBscH/2gAIAQEAAT8QMIJjCJ3cuWfQbHH8Yb7WPSYSBKWy3XPkI2nk8dY/JsaKn//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;책&quot;
        title=&quot;책&quot;
        src=&quot;/static/8a5a8b11c139085ee6310e0bd44cec2b/6aca1/1.jpg&quot;
        srcset=&quot;/static/8a5a8b11c139085ee6310e0bd44cec2b/d2f63/1.jpg 163w,
/static/8a5a8b11c139085ee6310e0bd44cec2b/c989d/1.jpg 325w,
/static/8a5a8b11c139085ee6310e0bd44cec2b/6aca1/1.jpg 650w,
/static/8a5a8b11c139085ee6310e0bd44cec2b/7c09c/1.jpg 975w,
/static/8a5a8b11c139085ee6310e0bd44cec2b/01ab0/1.jpg 1300w,
/static/8a5a8b11c139085ee6310e0bd44cec2b/e2d85/1.jpg 1411w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;회고를 하면서 알게 된 사실인데… 올해는 기술 서적을 한 권밖에 읽지 않았습니다. 작년에는 네 권 읽었는데, 의식적으로 독서하려는 노력을 안 했더니 결과적으로는 아쉬운 한 해가 된 것 같네요. 😢&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/2025/02/02/Micro-State-Management-with-React-Hooks.html&quot;&gt;『리액트 훅을 활용한 마이크로 상태 관리』&lt;/a&gt; 는 회사에서 스터디 목적으로 구매한 책이었는데, 실제로 추후에 전역 상태 관리 라이브러리를 도입하는 과정에서 책을 읽은 경험이 많은 도움이 되었습니다. 결론적으로 저희는 팀에서 Zustand 를 도입해서 잘 사용하고 있습니다.&lt;/p&gt;
&lt;p&gt;평소에도 독서를 많이 하는 스타일은 아니긴 한데, 내년에는 독서 습관을 좀 더 의식적으로 챙겨봐야겠다는 생각이 듭니다. 그래도 분기 별로 한 권을 읽어보는 것을 목표로, 그리고 유튜브를 보는 시간 대신 책 읽는 시간을 늘려보는 것을 목표로 삼아보려고 합니다.&lt;/p&gt;
&lt;h3 id=&quot;갤럭시-s25&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B0%A4%EB%9F%AD%EC%8B%9C-s25&quot; aria-label=&quot;갤럭시 s25 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;갤럭시 S25&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/22c0fe590e8ee5ce1247a162493ee70f/ee644/10.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 86.50306748466258%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAARABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAEDBAL/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/2gAMAwEAAhADEAAAAdeKbEtaWNV9gyK//8QAGxABAAMAAwEAAAAAAAAAAAAAAgABAxAREjL/2gAIAQEAAQUCWoqLRqHUda150GVqUSaX1x//xAAVEQEBAAAAAAAAAAAAAAAAAAAgIf/aAAgBAwEBPwGj/8QAFxEAAwEAAAAAAAAAAAAAAAAAARESIP/aAAgBAgEBPwESsf/EABwQAAICAgMAAAAAAAAAAAAAAAABESECIhBhcf/aAAgBAQAGPwKlLKjFdG8JnptSISFz/8QAHBAAAgICAwAAAAAAAAAAAAAAASEAESBxQWGR/9oACAEBAAE/IVYOoQx4CG7ipdJOKjLS5lQAGH//2gAMAwEAAgADAAAAEK/XgP/EABgRAAIDAAAAAAAAAAAAAAAAAAERABAh/9oACAEDAQE/ECxU2//EABgRAQEAAwAAAAAAAAAAAAAAAAERABAh/9oACAECAQE/EAKcZeb/AP/EAB8QAQACAQMFAAAAAAAAAAAAAAEAEWEhMUEQUXGRsf/aAAgBAQABPxB9AtEKhyypDtBv2wrQ+g2uSV8S1YvXklY+Du8vEIiGJ9E4On//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;폰&quot;
        title=&quot;폰&quot;
        src=&quot;/static/22c0fe590e8ee5ce1247a162493ee70f/6aca1/10.jpg&quot;
        srcset=&quot;/static/22c0fe590e8ee5ce1247a162493ee70f/d2f63/10.jpg 163w,
/static/22c0fe590e8ee5ce1247a162493ee70f/c989d/10.jpg 325w,
/static/22c0fe590e8ee5ce1247a162493ee70f/6aca1/10.jpg 650w,
/static/22c0fe590e8ee5ce1247a162493ee70f/7c09c/10.jpg 975w,
/static/22c0fe590e8ee5ce1247a162493ee70f/01ab0/10.jpg 1300w,
/static/22c0fe590e8ee5ce1247a162493ee70f/ee644/10.jpg 1403w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;갤럭시 S20은 자신의 후임자 사진을 촬영하는 것을 마지막으로 그 임무를 마쳤다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;2월 초에 새 스마트폰을 구입했습니다. 원래 쓰던 스마트폰은 갤럭시 S20, 이번에 구입한 스마트폰은 갤럭시 S25입니다.&lt;/p&gt;
&lt;p&gt;저는 원래부터 계속 갤럭시를 써온 사람이라 이번에도 갤럭시 시리즈로 넘어가게 되었습니다. 저는 스마트폰을 웬만하면 고장날 때까지 쓰는 편이라서(?) 거의 5년만에 바꿨습니다.&lt;/p&gt;
&lt;p&gt;그래도 기왕 사는 김에 저렴하게 사고 싶어서 사전 행사 정보를 열심히 찾아보느라… 살짝 피곤했던 기억이 나네요.&lt;/p&gt;
&lt;h3 id=&quot;프론트엔드-반상회&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%B0%98%EC%83%81%ED%9A%8C&quot; aria-label=&quot;프론트엔드 반상회 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;프론트엔드 반상회&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d9995552501c71d1c3ed2da64ec6b926/72e01/11.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 56.44171779141104%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIEA//EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHMRklKCv/EABkQAAIDAQAAAAAAAAAAAAAAAAABAgMSEP/aAAgBAQABBQKvZbGTMCHz/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGhAAAgIDAAAAAAAAAAAAAAAAABEBAiAxQf/aAAgBAQAGPwJx0djWH//EABoQAQADAQEBAAAAAAAAAAAAAAEAESExQYH/2gAIAQEAAT8hQ1R6Al3Z9KlFdQByaNnrP//aAAwDAQACAAMAAAAQDy//xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QUtv/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQIBAT8QBywv/8QAHBABAAIDAAMAAAAAAAAAAAAAAQARITFBUWFx/9oACAEBAAE/EO6M9ltrHYQN0bpB9jSCBqjmIKFgS3LlmYZFaYgo7W18z//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;프론트엔드 반상회&quot;
        title=&quot;프론트엔드 반상회&quot;
        src=&quot;/static/d9995552501c71d1c3ed2da64ec6b926/6aca1/11.jpg&quot;
        srcset=&quot;/static/d9995552501c71d1c3ed2da64ec6b926/d2f63/11.jpg 163w,
/static/d9995552501c71d1c3ed2da64ec6b926/c989d/11.jpg 325w,
/static/d9995552501c71d1c3ed2da64ec6b926/6aca1/11.jpg 650w,
/static/d9995552501c71d1c3ed2da64ec6b926/7c09c/11.jpg 975w,
/static/d9995552501c71d1c3ed2da64ec6b926/72e01/11.jpg 1024w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;모임은 즐겁다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;2월 초에는 글또 프론트엔드 반상회를 다녀왔습니다. 주최자나 발표자가 아닌 그냥 참석자로 다녀와서 편하고 즐겁게 네트워킹을 하고 왔습니다. 퀴즈 대회에서 1등 상품도 받아서, 같은 조였던 분들과 후속 커피챗 약속도 잡고 좋은 추억을 남겼습니다.&lt;/p&gt;
&lt;h3 id=&quot;번아웃&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%B2%88%EC%95%84%EC%9B%83&quot; aria-label=&quot;번아웃 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;번아웃&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2025/02/16/Analyzing-the-Reasons-of-My-Burnout.html&quot;&gt;어느 날, 무기력이 찾아왔다&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExdGk1cjN3M2RwbzhuZHRqeDRsdnJkZDZoeGRwM2cyN2JqbHUwYm1rbSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/3oD3YGIVrRGbe5YGNa/giphy.gif&apos; alt=&apos;시지프스&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;시지프스가 된 기분&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;2월 초에 작성한 글로, 연초에 왔던 번아웃에 대해 분석하고 정리한 글입니다. 아무래도 제 블로그에서 평소에 다루지는 않았던 부정적 감정에 대한 포스트인만큼 인상깊게 봐주신 분들이 많았습니다.&lt;/p&gt;
&lt;p&gt;사실 이 글을 작성할 때까지만 하더라도 완전히 번아웃이 해소된 것은 아니었지만, 나의 부정적 감정을 글로 정리하고 공유하는 과정을 통해 외부의 자극이나 변화에 있어 더 의연하게 대처할 수 있는 방법을 찾을 수 있었습니다. 그런만큼 저에게 있어서는 당시의 감정을 글로 정리하는 과정이 멘탈 회복에 있어서 많은 도움이 되었던 것 같습니다.&lt;/p&gt;
&lt;h3 id=&quot;크롬에서의-뷰포트-단위&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%81%AC%EB%A1%AC%EC%97%90%EC%84%9C%EC%9D%98-%EB%B7%B0%ED%8F%AC%ED%8A%B8-%EB%8B%A8%EC%9C%84&quot; aria-label=&quot;크롬에서의 뷰포트 단위 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;크롬에서의 뷰포트 단위&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2025/03/02/Viewport-Resize-Behavior.html&quot;&gt;안드로이드 크롬에서 CSS vh 단위가 이상하게 동작했던 이유&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2c7f1ea363bb37953fc8d030309893bf/1c1a4/11.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 63.190184049079754%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABYlAAAWJQFJUiTwAAAC20lEQVQ4y12SXW/bZBiG+wN3xik/giFNCHEKnCFtbAeANpC2roMOQdVVojtIR2mTtEnsfPgr/nbixE7StGmbpLHjJBeyXYmPW3qeV/b73tdj+b23DL2NaxkErknPtWk2mwwGQ24mV6iKQtc2sz3PtpBaLaa3t3Q8D1Nv03dM+p5FW1UxDINUW9u/vOXxTz/z6NtXPN3Z483uLpqmIio6P77a5usfdvjs2Wte7O6xf3BA1/c5ODzk+etdPn/6ki9fvGXn198pHB3lQL3T4Z064tMDnZdCn+H4gp7v4PYDOmHI9+c+D9/pFIwR44sQ23VQLQMpvOGLQ5Ovjhzs0QTP1dlsNmzNp9fkSrK+TBJUy2Y4DInj6H5vlfXh1QTTsZlcjv7jSSWbJqv1mq1gdEGSJFxOrllEMVG0YND38IOA6WzKKo5YLuaw2XA3nWC5DpYfZJDUczubZ6Cg57BOgbPbCf9WnCQotsPlxYAoXuBeJ9TDGZN4w/j6JgNOxgP+L9my8y8sVyv4loylNXF1CbVVxXFsJMOkUinxyfYxD5685/H+KbpUw3BcKvV6dtOWbWPfV6Mh5pdSrlRRZJlWq4UsS5xXa5xpLkHPp1qtYrVVnLaCpuRngn6XpnhOS5Ky57TSqB2XyzmwUK5htDVkWUZVVQSxjmJ59HwfQRBQFJWWJCMrSjbY7XQ5rVTQVDXzKIqCJEkIwlkOrIl10nDrmoqlazSaTUTdI+j1EMU6mqZlg9JKzf1eF6kpoGl65tHbWhbscvU8B74/LvLNfpkHzwo83Dnhjz9LCJqd/aNisUij0UAURer1OoJQw+n4nBRP2Ds65aPvPvDx8w/8VjihVPorB/aCkKZuU5ItzhQbzXJZLWPmd3e4rovneVmZpkkYhiSrNf2gT9vQKUpm5mkoGjdX4xyYtmhxxzpesIoXJMv4nwjFMfP5nCiKmM1mWc5SpWv6Lkl9y4hosWBz7/kb3xWh+/sZF1MAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;뷰포트&quot;
        title=&quot;뷰포트&quot;
        src=&quot;/static/2c7f1ea363bb37953fc8d030309893bf/a6d36/11.png&quot;
        srcset=&quot;/static/2c7f1ea363bb37953fc8d030309893bf/222b7/11.png 163w,
/static/2c7f1ea363bb37953fc8d030309893bf/ff46a/11.png 325w,
/static/2c7f1ea363bb37953fc8d030309893bf/a6d36/11.png 650w,
/static/2c7f1ea363bb37953fc8d030309893bf/e548f/11.png 975w,
/static/2c7f1ea363bb37953fc8d030309893bf/1c1a4/11.png 1046w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;크롬에서 뷰포트 단위가 이상하게 동작하는 이유&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;3월 초에 작성한 글로, 안드로이드 크롬에서 CSS vh 단위가 이상하게 동작하는 이유를 정리한 글입니다. &lt;a href=&quot;https://www.linkedin.com/posts/wormwlrm_android%EC%9A%A9-chrome%EC%97%90-%EC%A0%81%EC%9A%A9%EB%90%A0-%ED%91%9C%EC%8B%9C-%EC%98%81%EC%97%AD-%ED%81%AC%EA%B8%B0-%EC%A1%B0%EC%A0%88-%EB%8F%99%EC%9E%91-%EB%B3%80%EA%B2%BD%EC%82%AC%ED%95%AD%EC%97%90-activity-7205149281278689280-N2It?utm_source=share&amp;#x26;utm_medium=member_desktop&amp;#x26;rcm=ACoAACgLhg4BijD8gCWg6vrZtr-NUATsEvp9Ud4&quot;&gt;사실 예전에 링크드인에 간단히 해당 내용&lt;/a&gt;을 정리해서 올린 적이 있었는데, 이를 블로그에도 포스트로 정리해 보았습니다.&lt;/p&gt;
&lt;h3 id=&quot;도쿄-워케이션&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%8F%84%EC%BF%84-%EC%9B%8C%EC%BC%80%EC%9D%B4%EC%85%98&quot; aria-label=&quot;도쿄 워케이션 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;도쿄 워케이션&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b925f3811599bbd359b1adecc7db052a/9ecec/12.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.12883435582822%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEEA//EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAHRPOpQwJJXNUk4f//EABwQAAMBAAIDAAAAAAAAAAAAAAABAhESEyEiMf/aAAgBAQABBQLBPz7UYfHLxPkXNsnUjWjts//EABYRAQEBAAAAAAAAAAAAAAAAABEAEP/aAAgBAwEBPwEjf//EABcRAAMBAAAAAAAAAAAAAAAAAAABEhD/2gAIAQIBAT8Bop7/AP/EABwQAAEFAAMAAAAAAAAAAAAAAAABEBEhMQIyYf/aAAgBAQAGPwIjzGQSoauRSvp2P//EAB8QAQACAgICAwAAAAAAAAAAAAEAEUFRITFhgXGRsf/aAAgBAQABPyHb9gZrYUAh4mxcS3rv3mWhedRADkvmtRG09sVGqfmEeoj3A8p//9oADAMBAAIAAwAAABCwEzD/xAAXEQEBAQEAAAAAAAAAAAAAAAABABEQ/9oACAEDAQE/EAjsnml//8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAECAQE/EFJkBZY3/8QAHxABAAIDAAEFAAAAAAAAAAAAAQARITFBYYGRocHw/9oACAEBAAE/EEFW6FrV4jLrKKF1stfaAo0Hq+Y2QxtVV9N8CVEFiI5GXY5HS9vH1Dc1GlPzMIKiZFIcaDZhmbR6jvCgFFXkGf/Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;베이스캠프&quot;
        title=&quot;베이스캠프&quot;
        src=&quot;/static/b925f3811599bbd359b1adecc7db052a/6aca1/12.jpg&quot;
        srcset=&quot;/static/b925f3811599bbd359b1adecc7db052a/d2f63/12.jpg 163w,
/static/b925f3811599bbd359b1adecc7db052a/c989d/12.jpg 325w,
/static/b925f3811599bbd359b1adecc7db052a/6aca1/12.jpg 650w,
/static/b925f3811599bbd359b1adecc7db052a/7c09c/12.jpg 975w,
/static/b925f3811599bbd359b1adecc7db052a/9ecec/12.jpg 1050w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;도쿄 베이스캠프에서 찍은 사진&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;3월 말, &lt;a href=&quot;https://fficial.naver.com/contentDetail/57&quot;&gt;회사에서 추첨으로 진행하는 워케이션&lt;/a&gt;에 당첨되어 도쿄를 다녀오게 되었습니다.&lt;/p&gt;
&lt;p&gt;회사에서 숙소와 조식을 지원해주고 퇴근 후에는 자유롭게 시간을 보낼 수 있는 만큼, 경쟁이 엄청 치열한데 정말 운 좋게 당첨이 되었습니다! 사실 확률로 봤을 때는 미당첨이 당연한 만큼 결과 확인도 안 하고 있었는데, 당첨이 되었다는 사실을 나중에 알고는 정말 크게 놀랐죠.&lt;/p&gt;
&lt;p&gt;일본을 두 번 가보긴 했지만 도쿄는 처음 가보는 곳이고, 혼자서 해외로 나가보는 것도 처음이라서 설레기도 하고 긴장도 되었습니다. 항공권은 직접 예매해야 했는데 그때가 하필 벚꽃 개화 시즌이라서 상당히 비쌌다는… 후문이 있긴 합니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/34adb422bc988d965dcea640621a36d8/4b190/16.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMBAgT/xAAWAQEBAQAAAAAAAAAAAAAAAAADAAH/2gAMAwEAAhADEAAAAWqvjFHEG3//xAAaEAACAgMAAAAAAAAAAAAAAAABAgAhEyJB/9oACAEBAAEFArnSbVtnZsps/wD/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwFX/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/AZGP/8QAGRAAAgMBAAAAAAAAAAAAAAAAAAERIWEQ/9oACAEBAAY/AsG5Twogp1z/xAAaEAADAQEBAQAAAAAAAAAAAAAAAREhMUGR/9oACAEBAAE/IW6qng7Nl8CrjCezS7g09DFD/9oADAMBAAIAAwAAABAIH//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPxDXUIn/xAAXEQADAQAAAAAAAAAAAAAAAAAAASFB/9oACAECAQE/EFaOj//EABwQAQADAQADAQAAAAAAAAAAAAEAESExQVGxgf/aAAgBAQABPxA9zDFLv4SwYGcq6r0XsalDcKqopJU6ULL5Cct6fexuPmvk/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;조식&quot;
        title=&quot;조식&quot;
        src=&quot;/static/34adb422bc988d965dcea640621a36d8/6aca1/16.jpg&quot;
        srcset=&quot;/static/34adb422bc988d965dcea640621a36d8/d2f63/16.jpg 163w,
/static/34adb422bc988d965dcea640621a36d8/c989d/16.jpg 325w,
/static/34adb422bc988d965dcea640621a36d8/6aca1/16.jpg 650w,
/static/34adb422bc988d965dcea640621a36d8/4b190/16.jpg 800w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;업무에 몰입 및 집중할 수 있도록 지원을 정말 잘 해주어서 좋았다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;워케이션은 정말 만족스러웠습니다. 우선은 조식이 정말 잘 나왔습니다. 제가 아침을 잘 챙겨먹는 스타일은 아닌데 정갈하게 차려진 조식이 마음에 들어서 매일 일찍 일어나서 먹었던 기억이 나네요.&lt;/p&gt;
&lt;p&gt;또한 숙소 내에 업무 공간이 잘 갖추어져 있어서 업무에도 잘 몰입할 수 있었습니다. 각 방마다 허먼 밀러 의자와 모니터가 있고, 공용 공간에서도 넓은 라운지가 있어서 분위기를 환기할 수도 있었습니다.&lt;/p&gt;
&lt;p&gt;다른 워케이션 참가자들과의 네트워킹도 지원해서 시간이 맞는 분들과는 같이 점심 또는 저녁을 먹기도 했고, 근처에 있는 명소를 같이 돌아보기도 했습니다. &lt;em&gt;일하러 돌아가는 길조차 여행이 될 수 있다&lt;/em&gt; 는 표현이 참 적절하게 느껴지더라구요.&lt;/p&gt;
&lt;p&gt;다만 개인적으로 저는 &lt;em&gt;디지털 노마드&lt;/em&gt; 의 삶과는 잘 안 맞는다는 걸 깨달았습니다. 그냥 쉴 때 쉬고, 일할 때 일하는 게 좋은 스타일인 것 같더라구요. 일 하는데 자꾸 놀고 싶은 마음(?)이 들더라구요. 😅&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/6739a5e3b2628106a228f5ebf2f04552/a2510/15.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIEBf/EABYBAQEBAAAAAAAAAAAAAAAAAAECA//aAAwDAQACEAMQAAABjfQTO5AE/8QAGhAAAgMBAQAAAAAAAAAAAAAAAQIAAxEEIv/aAAgBAQABBQJKVMZa1ICmZ76UGIpz/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAEDAQE/ARLL/8QAFhEBAQEAAAAAAAAAAAAAAAAAEQEQ/9oACAECAQE/Aauf/8QAGhAAAgMBAQAAAAAAAAAAAAAAAAEREjEhUf/aAAgBAQAGPwIWGkzwVUrHh//EABkQAAMBAQEAAAAAAAAAAAAAAAERIQAxUf/aAAgBAQABPyG0WUaCdAAPucdXqbxcYcIZGCaYMrR4N//aAAwDAQACAAMAAAAQa9//xAAYEQACAwAAAAAAAAAAAAAAAAAAMQERIf/aAAgBAwEBPxCgidM//8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAx/9oACAECAQE/ECNQl//EABwQAQEAAwEAAwAAAAAAAAAAAAERACExUUFxsf/aAAgBAQABPxA4PiDZPD653FKe8eT5wNUCAaHtwT3CrBt8wpk0AlDv6ZRGqU0aM//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;돈카츠&quot;
        title=&quot;돈카츠&quot;
        src=&quot;/static/6739a5e3b2628106a228f5ebf2f04552/6aca1/15.jpg&quot;
        srcset=&quot;/static/6739a5e3b2628106a228f5ebf2f04552/d2f63/15.jpg 163w,
/static/6739a5e3b2628106a228f5ebf2f04552/c989d/15.jpg 325w,
/static/6739a5e3b2628106a228f5ebf2f04552/6aca1/15.jpg 650w,
/static/6739a5e3b2628106a228f5ebf2f04552/7c09c/15.jpg 975w,
/static/6739a5e3b2628106a228f5ebf2f04552/a2510/15.jpg 1000w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;숙소 근처에 돈카츠 집이 있어서 갔는데 존맛&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;TMI지만 개인적으로 이번 일본 워케이션에서 가장 맛있었던 음식은 &lt;a href=&quot;https://maps.app.goo.gl/1B72PDyV9KBgykHLA&quot;&gt;돈카츠&lt;/a&gt;였습니다. 사진 보니까 또 먹고 싶네요… 😋&lt;/p&gt;
&lt;p&gt;아무튼 해외를 다녀온 만큼 워케이션 후기에 대해서 네이버 블로그에 글을 써볼 예정입니다.&lt;/p&gt;
&lt;h3 id=&quot;글또-회고&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-%ED%9A%8C%EA%B3%A0&quot; aria-label=&quot;글또 회고 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 회고&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2025/05/11/Adios-Geultto.html&quot;&gt;나의 청춘을 함께한 커뮤니티, 글또를 졸업합니다&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExN3JydTJ2em5jMjkyYmhudWw0cXpudjdlNDIxdnl1b21uMGJrdDNmeCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/dxCSx7uOPQjVtpw4P5/giphy.gif&apos; alt=&apos;졸업&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;글또는 10기를 마지막으로 공식적인 활동이 종료되었다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;5월에 작성한 글로, 글또가 10기를 끝으로 공식적인 활동을 종료하게 되었는데 이를 졸업에 비유하여 회고를 작성한 글입니다.&lt;/p&gt;
&lt;p&gt;회고를 작성하는 과정에서 휴대폰 앨범 속 사진과 예전에 작성한 글을 계속 찾아보게 되었는데, 당시에 겪고 있던 여러 불안감과 고민, 추억들이 자꾸 떠올라서 감상에 잠기게 되더라구요.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c59ae3dc1757d1db44fd35a77b4861e3/b8c63/14.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 34.355828220858896%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAAA+0lEQVQoz2VR7U7DMAzM+z/kNAHrNsQv2iT+PmSXFgSOTj47tpX42u12w+VywfV6LfTeQUQn5pynZ2ZEBOpE/OcRaDnAzODuSAt3uHnFB+IX/2s5BPETN1WFmIJN0YUxVYonkg/lQnJ1wxAuiFnFaRLJHeaOpmaYyiATePg5PHPZkEVHvgvBfB+U9SsNvDwW3J8PfI6telp+g8XQiTFI0CdjkhQ/4oSogUWrLmNVBxFjuT/w+rbg+f4BEd1fSCxIL/l9teLZnD5faOYg0YJ+308WrIMqZx5Q88q1fdn7LkqA2DfsKVQE+uhY1w1jTvRtKwGP+0MNU011SpQvHbwk6mxqEgEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;분석&quot;
        title=&quot;분석&quot;
        src=&quot;/static/c59ae3dc1757d1db44fd35a77b4861e3/a6d36/14.png&quot;
        srcset=&quot;/static/c59ae3dc1757d1db44fd35a77b4861e3/222b7/14.png 163w,
/static/c59ae3dc1757d1db44fd35a77b4861e3/ff46a/14.png 325w,
/static/c59ae3dc1757d1db44fd35a77b4861e3/a6d36/14.png 650w,
/static/c59ae3dc1757d1db44fd35a77b4861e3/e548f/14.png 975w,
/static/c59ae3dc1757d1db44fd35a77b4861e3/3c492/14.png 1300w,
/static/c59ae3dc1757d1db44fd35a77b4861e3/b8c63/14.png 2712w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;아직도 200명 가까운 분들이 슬랙에서 활동을 이어나가고 계심&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글또의 활동이 끝난 지 벌써 반 년이 넘게 지났지만, 아직도 많은 분들이 슬랙에서 활동을 이어나가고 있습니다. 비공식적으로 글쓰기를 계속 이어나갈 수 있는 모임도 유지되고 있고, 대나무숲에는 아직도 하루에 2~3건 씩 새로운 고민들이 올라오고 있습니다. 생일 축하 글도 계속 유지되고 있구요.&lt;/p&gt;
&lt;p&gt;열정 넘치는 사람들이 자발적으로 활동을 이어나가고 있다는 점을 보면서 글또의 영향력이 여전히 우리에게 남아있다는 것을 느꼈습니다.&lt;/p&gt;
&lt;h3 id=&quot;글드컵&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%93%9C%EC%BB%B5&quot; aria-label=&quot;글드컵 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글드컵&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2025/06/29/Planning-Event-for-Writing-Competition-with-AI.html&quot;&gt;AI와 함께하는 글쓰기 토너먼트 대회, 글드컵 진행 후기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 480px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e28efacd7a85152689103dddba0470e4/e85cb/poster.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 150.30674846625766%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAIAAACjcKk8AAAACXBIWXMAAAsTAAALEwEAmpwYAAAFp0lEQVQ4y1WTSY8kRxXHX+SelZW15FK5b1WZlUtlVlVmVnVVdVd3Ty/Te49nejw0xj0abCHjhQNgbsY++GLLGiEkX3xDSD4gIWFO3DhY8gfwhQPigsSBA+ITcEFRjRBITxGpF/GL/z8j3gNgWsB2gJOAV0EwoOWCFEGvQM6SLq7p4gq5K9CmIMfQ9qFpQqOHN7MSpjakDLyCs6IFnQDkBPQp4e/y1VOuvCH8XQxLCV5qOSDom80K8PIGbqg4Jeio7UCrrw6mwWTV3zpx9m7Dw1tlfOyMll1/gh11NuKCBk3jHu5izbYHoo1HKaL0gnFqIT9tzG6F+S2fXzDuFmOXoCTQHWBYdKDtYr/YA69Cp7+JjedeQVhziB/tPH798vlbkD1G9gKMCnoFSENMdiPsn1cAG7hXVlPo9kEdgTam/B1Ibn7x8ydff/UJW90R3jbSp8goMdwN8c6mhf8UnyHaIFpIy5GcgDpCxhSFx718/cXb/X9++/LFe++AuSatChkVkmN8ipJg/ZYDeJIGeFRSyq4EMwOzppJzq598cC39/Y9vv/ODC3CPSHvGOlO6VxD2Fkghdt72NraVGN9kO3QDL44jsJfU6IpxFz+9Mv721WOnWEN8Dfb2ZJw8u5wjew5ShNRkoyzoqDtA+pSRvVij69RohqtONNdN6/0T8a+/f/rrl29MZlvgbD8/Cb98PxOsDHpjDIsmhqHl0EYeOKrW5Vr+NBiEhcX2JfjgjP3L7179158+/MlRww+HVlrfLNU3r2LGrfHTNE3AVSVaIEWCkzNqBOayp+sDhT4dcb/5kfbn377yj6/f+uiCP6ocsFdaP8urEno5rmKs3PbwV8sTvcL2A86IBbdwZXrLpz+77f7h0/KbX86/P6e9KAZz0dSjgavjUsGwBZurClDbPRjL7x51U7dF26WjNnoicRzTn79QX363s/KZpl8jrXixLVaxDmJItF1cUaCkSEmhG5qG/MaBsh2ynOoolqs2YWyS762Zyxi5tgHGcqcwP36qMFoMnRDJQ1ATrIyMMegTUh6s03bhsFTX4YK5qrQCCS1tFBpNzp+BXt2t2vPJANopoecYkULAz60khDMHa9bQB7weNYwI+WvGHo9t5lnFN70x+HudYGwEESg5MkvCmaH7JsFdrqSgFfRgl/R2wJw3rFTwS/AP55n2vSMfvAMmXPcGI8IoSW9J9degFbjD5CHgSctBnyCr5pIjJtonvFUj2qH761dX6q9+nMrZLpcec96MDvfZ+ABZ+OYwoqSA1BTpBZhTZM8IbyXkp2x20ujPNLl5llJf/ix7/YHJehVOZg8Jd4HMEhkTpOW4twh9RFlT2psx/RUb7vDJoZjuc82mwCFLZnZH8nbSFtuimD7ghnt0sKC8GWlNCT0ntBQoLWHMgrbHtFOx/pwPFqyREhRF06jbJAOVCXosx1GMkbDejHFK0ihoY0TpCalGQHUcout1nKTj5VJ/Irtxz3K6UluVW4Yqhk7XMzu2pfQsW/EzwRhKXkbLPtFxiJYFlKgBJZ+en737w7uL88Ozh+vLs52g7zx/7fy1Z6dv3l3dPNp/dLF7ery4PN97fvfk8upED2JoqKSgAiHIQHfiNF1t11VdJGk0jAJebI1GcV3ndT2q6zxOBnESOp6TF2lZFZrtAtsm+C4AI9CNVj7O8nGWjuJnNydPHh1fnu9/5+lpkg0Xi/LwweLwYLXeme2u56tVdfP4YTQMAWjENgEojmD4vEgn01GWJ3u7W9cXD6qqmJZ5Ps7CaDCdjIo8SbPhclnVdbE1n8ZJCEAhmgegWCBZkuZorkFzDUQyAFRbVpJ0OC3zdJS8cn3INltAsojiKZYHRAPBAMXhwPB9kHjE5yGmpxuLrXKxKNfr+cnDNSZpDmjunkH3JMX+D/yf1CZIlm2ITEOk+SYi/3/pvyTF/hsE890PGPaiUgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;포스터&quot;
        title=&quot;포스터&quot;
        src=&quot;/static/e28efacd7a85152689103dddba0470e4/e85cb/poster.png&quot;
        srcset=&quot;/static/e28efacd7a85152689103dddba0470e4/222b7/poster.png 163w,
/static/e28efacd7a85152689103dddba0470e4/ff46a/poster.png 325w,
/static/e28efacd7a85152689103dddba0470e4/e85cb/poster.png 480w&quot;
        sizes=&quot;(max-width: 480px) 100vw, 480px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;6월 말, 글또 내에서 진행한 글쓰기 토너먼트 대회, 글드컵의 진행 후기를 정리한 글입니다.&lt;/p&gt;
&lt;p&gt;글드컵은 글또 10기 활동 기간 동안 참여자들이 작성한 글 중 최고의 글을 가려내는 토너먼트 대결 이벤트로, 글쓰기 배틀이라는 독특한 아이디어에 AI가 심판으로 참여했다는 점 덕분에 많은 분들이 흥미를 느끼고 뜨거운 반응을 보내주셨습니다.&lt;/p&gt;
&lt;p&gt;AI를 아주 적극적으로 활용한 행사였는데, 포스터 제작부터 홍보 문구 작성, 대진표 구성, 그리고 행사의 핵심인 평가 프롬프트 작성에 이르기까지, 거의 모든 과정에서 AI의 손길이 닿지 않은 곳이 없었죠.&lt;/p&gt;
&lt;p&gt;AI와 함께 행사를 성공적으로 이끌며, 우리 일상과 업무에 AI를 어떻게 실용적으로 접목할 수 있는지에 대한 새로운 통찰을 얻을 수 있었습니다.&lt;/p&gt;
&lt;h3 id=&quot;소셜-로그인-구현하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0&quot; aria-label=&quot;소셜 로그인 구현하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;소셜 로그인 구현하기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2025/07/31/OIDC-with-PKCE.html&quot;&gt;클라이언트 환경에서 안전한 소셜 로그인을 구현하는 핵심 메커니즘, OIDC와 PKCE 알아보기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;
            &lt;img src=&apos;/2bbce8300b8d65ac4cce3d428d3ad57c/12.gif&apos; alt=&apos;OIDC&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;OIDC와 PKCE로 안전한 소셜 로그인 구현하기&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;7월 말에 작성한 글로, 당시 회사 프로젝트에서 페이스북 소셜 로그인을 구현하는 업무를 맡게 되었는데, OAuth 전반적인 개념에 대한 이해가 부족해서 공부한 내용을 정리한 글입니다.&lt;/p&gt;
&lt;p&gt;OAuth 도메인 자체를 많이 다뤄보지 않았고, 그러다 보니 낯선 개념들이 많아서 글 작성보다도 학습을 하는 데에 시간이 꽤 걸렸던 기억이 나네요. 나름 기술 포스트인만큼 데모 영상도 촬영하면서 작성에 공을 많이 들였던 글이기도 합니다.&lt;/p&gt;
&lt;h3 id=&quot;유럽-여행&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%9C%A0%EB%9F%BD-%EC%97%AC%ED%96%89&quot; aria-label=&quot;유럽 여행 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;유럽 여행&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 540px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1a59fcef99d7bf403b2690ceba293a0c/07484/5.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 111.65644171779141%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAWCAYAAADAQbwGAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFn0lEQVQ4yy2VWW9cBxmGz78gTdKWQIjicWzXTlI79uyLZ/WsZ5ZzZjkzZ2Y8xzPjbRbPZrseJ94TJ7Hjtokd3AZILxAgpUKIqiABLULiBnELd0jcwx94UEwvPr3f1SO93ye9r3B1OMflWxkuD3433+1Xh1W+P6oyNFXAkTjAnz9nJneOP/+Q9GwIdTaAW7Jijkyh909gjxqwhgwIV28leUcn/x90S+HKkHKh7w6rjJiq3LYucsdRx544ZCb3El/2GEkNIWacOKImbFE9UzPjOEQ99pAe4dLNGJcGknxvIMmlAZlLAxKXB9O8o0tyWZfmylCRa3cr6PTzWGNP8SqHuCIWgikHrrgFh2jEJhqwRfS4wgaEt7Brt+cY0Nf40cQyP7hb5epwnvdH5/jh3TLX7pS4MVlnwr+PI/kCb2YXk/seXtGClPPil+14EhbcCQvTISPC9YllJgOH+PKfY0ts4pAfYozsYZMe45A/5q57kzueLQyRJ/jUL3AleziDkwQkB4W5MGopTDzrwRrS4w5PIXxgX8edOcImFpnyjGPwmTEHprGEbNjCIlZRwRyJMemXMYQ1XHIYt2RkRrIRSNqRcx4ish1/zIacX0IYc25hijTRu8cwB6Yw+j7E7hsnIFqIxCxEE1bEhJ2obCMQN+CLmXFFzIhJJyHJRVwRiaeDJJQEnswJwqizf2HP6nfhChpw+o14/RYqBZHVRppuM0u5FCcQsaMVY3RW8qTzIpG0FzHtJ1PMEkqFmYk7sUe6CDpTE3viCXKxiD/hIJr2E03NUJ5N0GsqdBsqa7UscclDNhPk+aMV/v2XU04XcnSUAL9+scq3v3pBPKNyd7qO8O6oRkI74R9/PeejVJCFkJ01VeSbN494ftCkWkkiJ/1U8zGOSjIHmsT5kzbHHY1iKsDzrXX+8+UB+8EqiUkV4cZUjRnlOf2qhuibJC95mVUCvD5tc1qWub+o8ObVBsepEKropF5JUi+nSeb8xDMaVU+LaW8Lva3JtHUFYdDeI5M6IeN2YwmakZUAIWkaV8hCJO6k3y7yx1/ucNCdI6eGSSX9ZJUAyXiQhtTDNtPljm8XQ2QPb3r37VNW+er1CU83G2jLVXKlKEoxipTxIKU8lApR1joNDrfX6S9lqJaizCohNjMlCvk6ofQK7vQJWa2HNldBcGVP+dfXZxx1M8gRO728yN++esz2VpmY5CSb8bPf1njcqXDUn+fj9Qp9yUsmWyGS3yGqdHDJB5hD65h8iwi6KY1f/OwZWw2V+ZiDXjbE55saq/MS+XyQaGKaSi5IKRtEU8K8bs6y09EIZnuYxEMMwfuMu7rophbQmToINyaX0IvHiBmFUilArBBk1mfhYT1PphRlrpxguVagXk7ySI3yZKNErb2OIbDDsLHKLdMyOsMiQ6YWOmML4aahxnTymIicQlUDpNU0L7fL/Pfvn/Fqa4Wft0v889sXnLdU+ssZJKXCbUuZQcMCg8YGOnMHnanLgHGVD109hOvjZcbdPWyRVZzS23B4xlxzi3Yni6IEWa7M8+zRNuXyEnFlgUFDlQFDg0Fzm0HrBiP2DhO+Naxij2SuhHBlUObaaI4h8wr60D6m6BHh3D7afInW6hpeaZ0R1w4T3g3GHB1GrC0GzOvc8++Qn+uwtFRALSQoahEqZRnhvTGN6/fqjDg+4p5/G1P0MR7lU5LFWeLFB9jiRxfHtySOMcZOsMWfkiu12OjW+XSvylo7xye7i7w57fO7V9sI732QvwhSnbHJmHMdS/yEYOGYtOojnoqi5Gs0G21ajTWy2ibzC4vsraocrBbYaxc5217kDy8f8OdXO/z27D7C+yNvy6jETf0K4zO7OFJnpLUWpXKQykKclZrMT4/b/OZ0jc925y8AP9mp8cVejS+Puvzp5X2+Oevz9Wmf3//4Af8DrbOfGsERZTIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;동선&quot;
        title=&quot;동선&quot;
        src=&quot;/static/1a59fcef99d7bf403b2690ceba293a0c/07484/5.png&quot;
        srcset=&quot;/static/1a59fcef99d7bf403b2690ceba293a0c/222b7/5.png 163w,
/static/1a59fcef99d7bf403b2690ceba293a0c/ff46a/5.png 325w,
/static/1a59fcef99d7bf403b2690ceba293a0c/07484/5.png 540w&quot;
        sizes=&quot;(max-width: 540px) 100vw, 540px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;7박 9일 미친 동선&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;9월 말에는 가족 및 친척과 함께 유럽 여행을 다녀왔습니다. 아무래도 어른들과 함께 가는 여행이다 보니 패키지 여행으로 다녀왔고, 7박 9일 동안 스페인과 포르투갈을 둘러보는 일정으로 다녀왔습니다.&lt;/p&gt;
&lt;p&gt;저는 유럽도 처음, 패키지 여행도 처음이었는데 생각보다(?) 일정이 빡셌습니다. 1일 1도시를 둘러보는 버스 투어였는데, 버스로 이동하는 시간이 하루에 네다섯 시간 정도는 되는 것 같더라구요.&lt;/p&gt;
&lt;p&gt;그리고 패키지 여행 특성 상 시간 약속을 칼같이 지켜야 했는데, 관광지에서도 남은 시간을 따져가며 촉박하게 둘러볼 수 밖에 없었던 것이 아쉬웠던 기억이 나네요.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2f23ca615311350e1067576d4b8379f8/4b190/13.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.12883435582822%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQBAv/EABYBAQEBAAAAAAAAAAAAAAAAAAMAAf/aAAwDAQACEAMQAAAB04cemrIkuA16JZ//xAAaEAACAwEBAAAAAAAAAAAAAAAAEQECEwMg/9oACAEBAAEFAkIRbojaDSoysz5//8QAGBEAAwEBAAAAAAAAAAAAAAAAAAESEBH/2gAIAQMBAT8BlkvOH//EABgRAAMBAQAAAAAAAAAAAAAAAAABEhEh/9oACAECAQE/AbRaNZ0//8QAGxAAAQQDAAAAAAAAAAAAAAAAAAEQITERIEH/2gAIAQEABj8CeimhUJwc0//EABwQAQABBAMAAAAAAAAAAAAAAAEAEBEhMUFhof/aAAgBAQABPyGvHN9QSBuGOWQdxOhm4SzSxP/aAAwDAQACAAMAAAAQs/kP/8QAFxEBAQEBAAAAAAAAAAAAAAAAAAFhEf/aAAgBAwEBPxDNislcP//EABgRAQADAQAAAAAAAAAAAAAAAAABEVFh/9oACAECAQE/EI1dUC9v/8QAHhABAAIBBAMAAAAAAAAAAAAAAQARMSFRYYFBkbH/2gAIAQEAAT8QeMeMvtBwNLWhW+pngXziCX8ZczcJJbongEtgAtR2MIAxENc+4MYn/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;포르투&quot;
        title=&quot;포르투&quot;
        src=&quot;/static/2f23ca615311350e1067576d4b8379f8/6aca1/13.jpg&quot;
        srcset=&quot;/static/2f23ca615311350e1067576d4b8379f8/d2f63/13.jpg 163w,
/static/2f23ca615311350e1067576d4b8379f8/c989d/13.jpg 325w,
/static/2f23ca615311350e1067576d4b8379f8/6aca1/13.jpg 650w,
/static/2f23ca615311350e1067576d4b8379f8/4b190/13.jpg 800w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;강가 절벽을 바라보며 여유로움을 즐길 수 있었던 포르투&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;그럼에도 불구하고, 낭만 하나 만큼은 제대로 느낄 수 있었던 여행이었습니다. 기억에 남는 관광지로는 몬세라트, 성 가족 성당, 구엘 공원, 알함브라 궁전 등등 정말 많았지만 개인적으로 가장 좋았던 곳은 포르투였습니다. 여유와 편안한 분위기, 사람들의 친절한 태도 덕분에 가장 즐거운 기억이 남는 곳이었습니다.&lt;/p&gt;
&lt;p&gt;해외 여행을 다녀오고 나서 네이버 블로그에 여행 포스트를 남기려고 하는데, 이번 년도의 여행기는 아직 작성하지 못했습니다. 그래서 내년 초에는 꼭 여행기를 작성해보려고 합니다.&lt;/p&gt;
&lt;h3 id=&quot;강의&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B0%95%EC%9D%98&quot; aria-label=&quot;강의 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;강의&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2025/11/02/Programmatic-Technical-Blog-Writing.html&quot;&gt;『실용주의 기술 블로그 글쓰기』 수강 후기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/51eab3ee60f4046e63216dbc6417eecb/04293/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 31.288343558282207%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABNUlEQVQY0z2QW08CMRSE9wcYL0tv2wvtAsKKElZcTXwlMfogkqCv6v//FZ9pMTxMOj09M+dMq3okCeNECJHUTgu3zuP8mMb6E3c+IKRGKoN1ofT50uMYx6NGaUOV0oTD4Yvdx5733Z77zcDmYWB4fKLvN6z7DQ/DkWcjpS3T2YzV6o7tdsvh85Ou60htizaWSummmGTh9bwjtlNimuBD/Ecq93Yyo3G+bJ1SSzdf8Pbyyu/3D1YbpBBY66lyZGU8UlukNjQ2/EcNJWo+M3ItD8+8lhJ5v2by3DMbeuSy5UzXNNpSCSG4nTuWN9fcrtZly0W3PBkdYzZcXNbk4TmWMg06xgIbI9JZRkqhlKESUpX/WNwscSFyVQtGQhWD84urgsxz/fim0cbh7JgQEsFHnA1obYvuD6XDpQiGzLvYAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;강의&quot;
        title=&quot;강의&quot;
        src=&quot;/static/51eab3ee60f4046e63216dbc6417eecb/a6d36/3.png&quot;
        srcset=&quot;/static/51eab3ee60f4046e63216dbc6417eecb/222b7/3.png 163w,
/static/51eab3ee60f4046e63216dbc6417eecb/ff46a/3.png 325w,
/static/51eab3ee60f4046e63216dbc6417eecb/a6d36/3.png 650w,
/static/51eab3ee60f4046e63216dbc6417eecb/e548f/3.png 975w,
/static/51eab3ee60f4046e63216dbc6417eecb/3c492/3.png 1300w,
/static/51eab3ee60f4046e63216dbc6417eecb/04293/3.png 2654w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;11월 초에 작성한 글로, 예전에 8월 쯤 인프런에서 수강했던 &lt;a href=&quot;https://www.inflearn.com/course/%EA%B8%B0%EC%88%A0-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EA%B8%80%EC%93%B0%EA%B8%B0&quot;&gt;『실용주의 기술 블로그 글쓰기』&lt;/a&gt; 강의 수강 후기를 정리한 글입니다.&lt;/p&gt;
&lt;p&gt;8~10월은 제 기술 블로그의 공백기입니다. 사실 7월 이후에 이런저런 일로 인해 글쓰기에 대한 열정이 식었었거든요. 그런데 이 강의를 다시 듣고 후기를 작성하면서 글쓰기에 대한 열정과 자신감을 되찾을 수 있었습니다.&lt;/p&gt;
&lt;p&gt;결론적으로 올해에는 9개의 글을 작성해서 &lt;em&gt;1년 동안 12개의 글을 쓰겠다&lt;/em&gt; 는 목표를 달성하지는 못 했습니다. 하지만 강의를 정리하면서 얻은 노하우를 바탕으로 글쓰기 템포를 다시 정상화한 만큼 내년에는 꾸준한 글쓰기를 진행할 수 있을 것 같습니다.&lt;/p&gt;
&lt;h3 id=&quot;ios-브라우저의-버그&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ios-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EB%B2%84%EA%B7%B8&quot; aria-label=&quot;ios 브라우저의 버그 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;iOS 브라우저의 버그&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2025/11/29/iOS-ScrollTo-GetClientBoundingRect-Bug.html&quot;&gt;iOS 브라우저에서 스크롤과 좌표 계산 API를 함께 썼더니 생긴 일&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/15a3315d6334b4c6751299e52e4d3025/66900/1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 76.68711656441718%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA10lEQVQ4y61U2wqDMAz1//9NH4QOYYhvY15gGzhdm7ZnpNvEeavOBQ69JD05TUMDay1mYQwsEbSUuFQV6PGANRpLZwJMGDvYSCqckyNOh+QFkeB+vX3FDC2Yy4Te3Cz4Rgo/maYyrt0bKRwGdkrecyKCUgrGmJF/FWF/3TQN4jhGGIYoimI/IY+sTkq5T+FfazhUqLV2+Flh/0BZloiiyCHLsv2ErKxtWweu5SpC37U313ALoY80mArqJ8nz3PUgI01T/5WFEKjrevSy3QdB5Jqbwb3oI3wCPB+he9Qr9WkAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;iOS 버그&quot;
        title=&quot;iOS 버그&quot;
        src=&quot;/static/15a3315d6334b4c6751299e52e4d3025/a6d36/1.png&quot;
        srcset=&quot;/static/15a3315d6334b4c6751299e52e4d3025/222b7/1.png 163w,
/static/15a3315d6334b4c6751299e52e4d3025/ff46a/1.png 325w,
/static/15a3315d6334b4c6751299e52e4d3025/a6d36/1.png 650w,
/static/15a3315d6334b4c6751299e52e4d3025/e548f/1.png 975w,
/static/15a3315d6334b4c6751299e52e4d3025/3c492/1.png 1300w,
/static/15a3315d6334b4c6751299e52e4d3025/66900/1.png 2630w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;11월 말에 작성한 기술 포스트입니다. 당시에 회사 프로젝트의 2차 QA가 진행 중이어서 이것저것 다양하고 황당한(?) 버그들을 많이 만날 수 있었는데요. 그 중에서도 기억에 남는 버그였어서 글로 정리해보았습니다.&lt;/p&gt;
&lt;p&gt;이미 겪었던 문제의 해결 과정을 서술하는 글이기도 하고, 버그의 데모도 재현하고 확인하는 과정을 거쳐서 작성했기 때문에 더 확실한 이해를 도모할 수 있었던 글이기도 합니다. 이러한 형식의 글은 글쓰기의 무게감이 너무 무겁지 않아서 글을 쓰는 입장에서도 부담스럽지 않고 작성하기가 편한 것 같습니다.&lt;/p&gt;
&lt;p&gt;이것 외에도 하나 더 작성하고 싶은 버그 해결 과정이 있는데, 요거는 내년 초에 작성해보는 것을 목표로 하고 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;밴드-활동&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%B0%B4%EB%93%9C-%ED%99%9C%EB%8F%99&quot; aria-label=&quot;밴드 활동 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;밴드 활동&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e3de742096822bd17e38ba1aa52aa4d4/0f98f/4.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 56.44171779141104%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAQADBf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/aAAwDAQACEAMQAAAB5DqlMWX/xAAZEAACAwEAAAAAAAAAAAAAAAABEQAQEjH/2gAIAQEAAQUC0yTG7HP/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAaEAEBAQADAQAAAAAAAAAAAAABABEhMUFh/9oACAEBAAE/IXorl9WBykAcC82I6Qv/2gAMAwEAAgADAAAAEID/AP/EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAEDAQE/EFf/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAgEBPxBH/8QAGxABAAMBAAMAAAAAAAAAAAAAAQARMSFBYYH/2gAIAQEAAT8Quk2AHYiFF9YEjgvmMwEzkQtQuryCEF9T/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;밴드&quot;
        title=&quot;밴드&quot;
        src=&quot;/static/e3de742096822bd17e38ba1aa52aa4d4/6aca1/4.jpg&quot;
        srcset=&quot;/static/e3de742096822bd17e38ba1aa52aa4d4/d2f63/4.jpg 163w,
/static/e3de742096822bd17e38ba1aa52aa4d4/c989d/4.jpg 325w,
/static/e3de742096822bd17e38ba1aa52aa4d4/6aca1/4.jpg 650w,
/static/e3de742096822bd17e38ba1aa52aa4d4/7c09c/4.jpg 975w,
/static/e3de742096822bd17e38ba1aa52aa4d4/01ab0/4.jpg 1300w,
/static/e3de742096822bd17e38ba1aa52aa4d4/0f98f/4.jpg 1920w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;사내 밴드 동아리 연말 파티에서 이소라 밴드 공연을 했다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;12월에는 밴드 공연을 했습니다. 작년에 이어서 총 세 번째 공연이네요.&lt;/p&gt;
&lt;p&gt;올해 초에 업무 번아웃이 겹치면서 사실 밴드 활동에 대한 의욕도 잃었었는데, 충분한 여유를 갖고 꾸준히 합주를 하면서 다시금 밴드 활동에 대한 재미를 느낄 수 있었습니다. 아무래도 공연이라는 목표를 잡으니 동기부여가 더 잘 되었던 것 같구요.&lt;/p&gt;
&lt;p&gt;다만 연습과는 별개로 공연 당일에는 긴장도 많이 되고 실수도 해서 완성도 면에서는 아쉬움이 남긴 합니다. 그렇지만 제가 음악에 있어서는 완벽보다는 완성에 의미를 두는 만큼 이번 공연도 개인적으로는 즐거운 경험이 되었던 것 같습니다.&lt;/p&gt;
&lt;p&gt;공연을 마치고 집에 돌아오는 길에 작년에 같은 팀으로 공연을 했던 분과 만나서 이런저런 이야기를 나누었는데요, 연주하는 기타와 곡들이 잘 어울리고 작년보다 많이 성장한 모습이 인상적이라고 칭찬해주셔서 기분도 좋고 뿌듯했습니다.&lt;/p&gt;
&lt;h2 id=&quot;올해를-한-마디로-정리하자면&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%98%AC%ED%95%B4%EB%A5%BC-%ED%95%9C-%EB%A7%88%EB%94%94%EB%A1%9C-%EC%A0%95%EB%A6%AC%ED%95%98%EC%9E%90%EB%A9%B4&quot; aria-label=&quot;올해를 한 마디로 정리하자면 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;올해를 한 마디로 정리하자면&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;다섯 마리 토끼를 한 번에 다 잡으려다 보니 아쉬움이 남는 한 해&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;일과 삶의 균형을 잘 맞추고자 했던 한 해였지만, 다섯 마리 토끼를 한꺼번에 다 잡으려다 보니 완벽하게 챙기지 못한 점이 아쉬움으로 남는 한 해였습니다. 현실적으로 모든 영역에서 완벽함을 유지할 수는 없다는 것을 깨달았기도 하구요.&lt;/p&gt;
&lt;p&gt;그런 만큼, 정말 각 분야에서 지키고 싶은 최소한의 기준선을 정해놓고 집중력을 유연하게 옮겨가면서 조절하는 시간을 보내봐야겠다는 생각이 듭니다.&lt;/p&gt;
&lt;p&gt;또한 한 분야에서 느낀 감정이 다른 분야에도 영향을 끼치는 경우가 있다고 느꼈는데요, 나쁜 영향은 전염되지 않도록 격리할 수 있는 방법을 고민해보려고 합니다.&lt;/p&gt;
&lt;h2 id=&quot;새해-목표-다짐을-한-마디로-정리하자면&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%83%88%ED%95%B4-%EB%AA%A9%ED%91%9C-%EB%8B%A4%EC%A7%90%EC%9D%84-%ED%95%9C-%EB%A7%88%EB%94%94%EB%A1%9C-%EC%A0%95%EB%A6%AC%ED%95%98%EC%9E%90%EB%A9%B4&quot; aria-label=&quot;새해 목표 다짐을 한 마디로 정리하자면 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;새해 목표 다짐을 한 마디로 정리하자면&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;유연한 오각형으로, 천천히 꾸준하게&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;올해 아쉬움의 포인트는 모든 영역에서 완벽함을 유지하려다 보니 느낀 점이라는 것을 깨달았습니다. 그래서 내년에는 너무 거창한 목표를 세우기보다는 &lt;strong&gt;소소하지만 현실적으로 달성할 수 있는 목표&lt;/strong&gt;들을 세워보려고 합니다.&lt;/p&gt;
&lt;p&gt;또한, 보다 현실적인 목표 달성을 위해 &lt;strong&gt;구체적인 숫자를 포함해서 목표&lt;/strong&gt;를 세워보려고 합니다. 이를 통해 목표 달성률을 측정할 수 있어 더 현실적인 연간 계획을 세울 수 있을 것 같더라구요.&lt;/p&gt;
&lt;p&gt;내년에는 달성하고 싶은 목표와 습관 유지를 위해 필요한 최소한의 노력을 정의해두고, 나머지의 집중력과 몰입도는 유연하게 조절하면서 효율적으로 시간을 보내보려고 합니다.&lt;/p&gt;
&lt;h3 id=&quot;일과-자기-계발&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%9D%BC%EA%B3%BC-%EC%9E%90%EA%B8%B0-%EA%B3%84%EB%B0%9C&quot; aria-label=&quot;일과 자기 계발 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;일과 자기 계발&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;사이드 프로젝트 1개 완성하기&lt;/li&gt;
&lt;li&gt;블로그에 포스트 12개 작성하기&lt;/li&gt;
&lt;li&gt;책 4권 이상 읽기&lt;/li&gt;
&lt;li&gt;팀에 기술 공유 세션 2회 진행하기&lt;/li&gt;
&lt;li&gt;노력을 들여야 하는 습관의 보상 체계를 고민해보기&lt;/li&gt;
&lt;li&gt;매달 말에 목표 달성률 점검하기&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;삶과-취미&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%82%B6%EA%B3%BC-%EC%B7%A8%EB%AF%B8&quot; aria-label=&quot;삶과 취미 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;삶과 취미&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;밴드 공연 1회 이상 하기&lt;/li&gt;
&lt;li&gt;올해 다녀온 해외 여행 포스트 작성하기&lt;/li&gt;
&lt;li&gt;운동 습관 되살리기 (일단 주 1회부터…!)&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[iOS 브라우저에서 스크롤과 좌표 계산 API를 함께 썼더니 생긴 일]]></title><description><![CDATA[WebKit 기반 브라우저에서 두 API를 함께 사용할 경우 좌표가 정상적으로 측정되지 않는 현상에 대해 소개하고 해결 방법에 대해 공유합니다.]]></description><link>https://wormwlrm.github.io/2025/11/29/iOS-ScrollTo-GetClientBoundingRect-Bug.html</link><guid isPermaLink="false">https://wormwlrm.github.io/2025/11/29/iOS-ScrollTo-GetClientBoundingRect-Bug.html</guid><pubDate>Sat, 29 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;
            &lt;img src=&apos;https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExZmtqdG5la2wxeXVrbWJ3YWYxemJkYWpscGUxdXZjb2VxcjJqeWlndSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/yr7n0u3qzO9nG/giphy.gif&apos; alt=&apos;ios&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;애플 타도! iOS 타도! Safari 타도!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;프론트엔드 개발자라면 누구나 크로스 브라우징 이슈를 겪게 마련입니다. 그 중에서도 iOS 환경 대응은 악명이 높기로 유명하죠.&lt;/p&gt;
&lt;p&gt;최근에 회사에서 QA 업무를 하다가 이러한 iOS 이슈를 여러 개 처리하게 됐는데, 그 중에서도 정말 황당하고 어이없는 케이스가 있어서 이렇게 글로 정리하게 되었습니다. (이 억울함을 나만 알 수는 없다!)&lt;/p&gt;
&lt;p&gt;제가 담당한 이슈는 iOS Safari 브라우저에서 댓글 입력 중 멘션 기능을 사용할 때 발생했습니다. 사용자가 &lt;code class=&quot;language-text&quot;&gt;@&lt;/code&gt;를 입력하면 멘션 레이어가 표시되는데, iOS에서만 이 레이어가 화면을 뚫고 나가버리는 것이 문제였죠.&lt;/p&gt;
&lt;p&gt;알고 보니 모바일 브라우저에서 스크롤 위치를 고정하기 위해 사용하던 API와 멘션 레이어 위치를 계산하기 위한 API가 연달아 사용되었더니 좌표 계산이 정상적으로 동작하지 않는 것이 문제더라구요.&lt;/p&gt;
&lt;p&gt;그런데 그 원인과 해결책을 알고 나니 참… 마음이 참 그렇더라구요. 😂 &lt;em&gt;혹시나&lt;/em&gt; 했는데 &lt;em&gt;역시나&lt;/em&gt; 여서 WebKit 개발자한테 좀 섭섭하다는 감정도 들었네요.&lt;/p&gt;
&lt;p&gt;아무튼 오늘은 해당 버그를 소개하고 그 해결책까지 알아보는 시간을 가져보려고 합니다. 이번 글을 통해 &lt;strong&gt;iOS와 Safari(정확히는 WebKit)에 고통받고 있는 프론트엔드 개발자&lt;/strong&gt; 분들께 도움이 되길 바랍니다.&lt;/p&gt;
&lt;h2 id=&quot;tldr&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#tldr&quot; aria-label=&quot;tldr permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;TL;DR&lt;/h2&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;iOS Webkit 기반 브라우저에서 발생하는 문제로 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Window/scrollTo&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Window.scrollTo&lt;/code&gt;&lt;/a&gt; API 와 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Element/getBoundingClientRect&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Element.getBoundingClientRect&lt;/code&gt;&lt;/a&gt; 를 동시에 쓰는 경우에 발생함&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Window.scrollTo&lt;/code&gt; API를 호출할 때 실제 스크롤 가능한 영역보다 더 크거나 작은 값으로 호출을 하면 이것이 절삭된 값으로 반영되는 것이 아닌, &lt;code class=&quot;language-text&quot;&gt;Element.getBoundingClientRect&lt;/code&gt; 를 통해 얻어오는 좌표에도 영향을 주는 현상이 있음&lt;/li&gt;
&lt;li&gt;따라서 스크롤 직후 좌표를 얻어오는 로직을 작성해야 한다면:
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;setTimeout&lt;/code&gt; 을 이용해 브라우저에게 레이아웃 재계산을 위한 여유 시간을 주거나&lt;/li&gt;
&lt;li&gt;실제 스크롤 가능한 영역까지 최대/최소값으로 절삭하는 로직을 직접 추가해주는 방식을 고려할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;문제의-발견&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%AC%B8%EC%A0%9C%EC%9D%98-%EB%B0%9C%EA%B2%AC&quot; aria-label=&quot;문제의 발견 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;문제의 발견&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/362e27698f8e71418bae1f8c6f6b78d3/38a65/7.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 32.515337423312886%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAAAsTAAALEwEAmpwYAAAB0ElEQVQoz0WRfUsTARzHb7GNxpbOyW1uy7zdbnfnHk9tSWrTnBkpFBQRCEUsDKGC3sOcFNHLkNLdblr0ZzK33cQeXoDrxXziDqI/Pvwe/vj+vl9+wveTE3q9HqfdLoOzM87Pf9C3bXd2sO0Bw+EfWtYxpmlhttpY1hFW+9ilZbWx2kd8PmhiD84QJhJJFFVHktPMlW+wcKtCrlBEkhVkJUO2UGSv0UDPyIyGI0TGRXz+y3gued0anZgkMSkTCI3x9FkNoZQvsLxaJaNqpOS0SzqTQVE1FFV1Rev1OoWsTiIRJxoV8Xq9CIKAz+dDklVUvYAYu8qL7R2EYslgZXUN4/pNcqU5pouz6PkZl+mC0xvUd3cplYqkUilEUcTv9+PxCPj8fqZSzvEcsfg1Xr95ixBLJJlfrPB4q8ajJ1tsPnjI3Y37LtX1e9xe3+T9h48Y+awrGAgEXHf/BCVZcx060V/uvELQ9TRpNUulusHSyh0Wl9eYnV9iprxA3iij5Q0ae+/QtCxTksJIeJxgKEwwNEpoZMyNGk9KBK9EeF7bRvj5+xedTod+v0+323Vxvu5UZ9857XAxHPLl6zdMs03TtP7TtDg4NDlsmuzvf6JvD/gLEk8WfW7bF2gAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;멘션&quot;
        title=&quot;멘션&quot;
        src=&quot;/static/362e27698f8e71418bae1f8c6f6b78d3/a6d36/7.png&quot;
        srcset=&quot;/static/362e27698f8e71418bae1f8c6f6b78d3/222b7/7.png 163w,
/static/362e27698f8e71418bae1f8c6f6b78d3/ff46a/7.png 325w,
/static/362e27698f8e71418bae1f8c6f6b78d3/a6d36/7.png 650w,
/static/362e27698f8e71418bae1f8c6f6b78d3/e548f/7.png 975w,
/static/362e27698f8e71418bae1f8c6f6b78d3/38a65/7.png 1075w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;좌측은 페이스북, 우측은 인스타그램. 대충 이러한 멘션 기능(?)을 만들고 있었다.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;제가 받은 티켓의 내용을 간단하게 설명하자면, 댓글 입력창에 &lt;code class=&quot;language-text&quot;&gt;@&lt;/code&gt;를 입력하면 멘션 기능이 활성화되는데 그 멘션 레이어가 iOS에서만 화면을 뚫고 나간다는 이슈였습니다.&lt;/p&gt;
&lt;p&gt;멘션 레이어는 사용자가 입력한 &lt;code class=&quot;language-text&quot;&gt;@&lt;/code&gt; 글자 바로 위/아래에 나타나야 했기 때문에, 해당 글자의 위치를 좌표로 알아내야 했고 이를 &lt;code class=&quot;language-text&quot;&gt;getBoundingClientRect&lt;/code&gt; API를 사용해 해결하고 있었습니다.&lt;/p&gt;
&lt;p&gt;그런데 저는 예전에 분명히 화면을 뚫고 나가지 않도록 해당 요소의 좌표를 계산해서 최대 높이 제한을 해둔 적이 있었거든요. 그리고 해당 버그가 기존 iOS에서 이미 발생한 적이 있었어서, &lt;em&gt;“아~ iOS에서는 스크롤 직후 좌표 계산 시 타이밍 이슈가 있구나~”&lt;/em&gt; 라고 생각하고 이미 &lt;code class=&quot;language-text&quot;&gt;setTimeout&lt;/code&gt; 을 적용해 해결한 적도 있었습니다.&lt;/p&gt;
&lt;p&gt;코드를 좀 더 살펴보니 &lt;code class=&quot;language-text&quot;&gt;setTimeout&lt;/code&gt; 을 적용한 부분이 리팩토링을 하면서 사라진 것을 확인했고, 다시 해당 코드를 복원하는 방식으로 간단하게 해결하려고 했습니다.&lt;/p&gt;
&lt;p&gt;그런데… 로직의 연관된 부분을 찾아보다가 뭔가 이상한 걸 발견했습니다. 모바일 브라우저에서는 가상 키보드가 떠오르기 때문에 인풋 위치를 키보드 위로 고정시키기 위해 매 타이핑마다 스크롤 API를 호출하고 있었는데요. 이 스크롤 값을 이리저리 조절해보니… 어떨 때는 정상적으로 동작하는 경우가 있는 것이었습니다.&lt;/p&gt;
&lt;p&gt;호기심이 생겨 조금 더 살펴보았더니 문제는 바로 &lt;strong&gt;스크롤 값이 음수로 설정되고 있는 경우&lt;/strong&gt; 에만 발생하는 것이었습니다. 이 음수 스크롤 값이 뭔가 이상한 일을 일으키고 있었던 거죠.&lt;/p&gt;
&lt;h2 id=&quot;실제-데모&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%8B%A4%EC%A0%9C-%EB%8D%B0%EB%AA%A8&quot; aria-label=&quot;실제 데모 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;실제 데모&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/15a3315d6334b4c6751299e52e4d3025/66900/1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 76.68711656441718%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA10lEQVQ4y61U2wqDMAz1//9NH4QOYYhvY15gGzhdm7ZnpNvEeavOBQ69JD05TUMDay1mYQwsEbSUuFQV6PGANRpLZwJMGDvYSCqckyNOh+QFkeB+vX3FDC2Yy4Te3Cz4Rgo/maYyrt0bKRwGdkrecyKCUgrGmJF/FWF/3TQN4jhGGIYoimI/IY+sTkq5T+FfazhUqLV2+Flh/0BZloiiyCHLsv2ErKxtWweu5SpC37U313ALoY80mArqJ8nz3PUgI01T/5WFEKjrevSy3QdB5Jqbwb3oI3wCPB+he9Qr9WkAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;데모&quot;
        title=&quot;데모&quot;
        src=&quot;/static/15a3315d6334b4c6751299e52e4d3025/a6d36/1.png&quot;
        srcset=&quot;/static/15a3315d6334b4c6751299e52e4d3025/222b7/1.png 163w,
/static/15a3315d6334b4c6751299e52e4d3025/ff46a/1.png 325w,
/static/15a3315d6334b4c6751299e52e4d3025/a6d36/1.png 650w,
/static/15a3315d6334b4c6751299e52e4d3025/e548f/1.png 975w,
/static/15a3315d6334b4c6751299e52e4d3025/3c492/1.png 1300w,
/static/15a3315d6334b4c6751299e52e4d3025/66900/1.png 2630w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;직접 만든 데모 페이지&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이것이 실존하는 문제인지를 명확하게 보여드리기 위해 Next.js로 간단한 데모 페이지를 만들어봤습니다.&lt;/p&gt;
&lt;p&gt;우선 제일 위에 있는 핑크색 상자는 &lt;code class=&quot;language-text&quot;&gt;getBoundingClientRect&lt;/code&gt;를 이용해 뷰포트 최상단으로부터의 &lt;code class=&quot;language-text&quot;&gt;top&lt;/code&gt; 값을 보여주도록 설정했습니다.&lt;/p&gt;
&lt;p&gt;또한 아래에 있는 세 개의 회색 버튼은 클릭 시 &lt;code class=&quot;language-text&quot;&gt;scrollTo&lt;/code&gt; API와 &lt;code class=&quot;language-text&quot;&gt;getBoundingClientRect&lt;/code&gt; API를 연달아 호출합니다. 첫 번째는 &lt;code class=&quot;language-text&quot;&gt;0&lt;/code&gt;, 두 번째는 &lt;code class=&quot;language-text&quot;&gt;-1000&lt;/code&gt;, 세 번째는 &lt;code class=&quot;language-text&quot;&gt;-5000&lt;/code&gt;만큼 Y값을 조정하도록 했습니다. 그리고 반환된 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/DOMRect&quot;&gt;DOMRect&lt;/a&gt;의 &lt;code class=&quot;language-text&quot;&gt;top&lt;/code&gt; 을 별도 상태에 저장하게 했죠.&lt;/p&gt;
&lt;p&gt;불필요한 스타일 등을 제거하고 핵심 로직만 남긴 코드는 다음과 같습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setTop&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; divRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HTMLDivElement&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleClick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;top&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// top으로 스크롤 이동&lt;/span&gt;
  window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scrollTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; top &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 그 직후 divRef의 top 값을 상태에 저장&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setTop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;divRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;divRef&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;getBoundingClientRect.top: &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;window.scrollTop(0)&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;window.scrollTop(-1000)&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;window.scrollTop(-5000)&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;video src=&quot;/14544b83b0500a8fa98ee601a4035237/2.mov&quot; control autoplay muted loop playsinline width=&quot;100%&quot;&gt;&lt;/video&gt;
&lt;em&gt;좌측이 PC Chrome, 우측이 PC Safari&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;PC Chrome과 Safari에서는 두 번째, 세 번째 버튼을 눌러도 &lt;code class=&quot;language-text&quot;&gt;getBoundingClientRect&lt;/code&gt;로 얻어온 &lt;code class=&quot;language-text&quot;&gt;top&lt;/code&gt; 값이 그대로 유지됩니다. 왜냐하면 우리가 스크롤을 아무리 음수로 설정한다고 해도, 실제로 스크롤이 0보다 작아질 수는 없다는 것을 직관적으로 알고 있으니까요.&lt;/p&gt;
&lt;p&gt;이는 사실 &lt;a href=&quot;https://drafts.csswg.org/cssom-view/#dom-window-scroll&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;scroll&lt;/code&gt; 스펙&lt;/a&gt;에도 명시된 내용입니다. 실제 스크롤 가능한 영역보다 더 크거나 작은 값을 넣으면 절삭(clamp)되는 것이 DOM API에 정의된 브라우저의 기본 동작이거든요.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8e60ac18b37170fb53643533e22c16c5/1a867/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 71.16564417177914%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB/klEQVQ4y42T23KbMBRF8/8f1+lDbMc2wY4NErqBxM0mvqyO5DhN0kxbZjZwBLPYZx/xAPA6TWhjecoFO6Fx1mKtRWud1DQNp9Mpvsr1ev1W92cP92IYBqwxGHODOOc4HA70fc/5fOZfx53zDjxOE1LKJCEEpVQ0PtCGgPc+uYzXEOvQUrcDPgTatuVyufzpMLrJsozNZkOe5yxWGbKqEqiu66To2jcNrglY36W1CPwYxcO9iA+iO2MMSimqN1h0NY7jf+X3ueXDAa0VlRRUyiC0RSrDXmqk9cmV9w2qDozH1xvkS35vwNtN2w0Y16BtjTIuOY0txQ/9axAf3aaWY6iFrNgWgrzUbMuKfVGwFxJZd8hKobSmUopSSNque5/8R3fJYQKeTzS6QpUFuiywUmBEia0UUuq0liRKXCXRUqZ8v+b3G9h6zMuGfJ2xmi9Y/vzB6vGR5TJntnim2O7wssSVBU4UjLpiGvpbhh8Gc8swnvuW6XikbnuUrdOEtWsQ1iNsQzdOHI4T4+FIN45cxh5Or39puQs4rcj3kqdsw2I+Y7FcMVtvmWc7StPg2wEX954PnLo2/q/fO7wDh77HhY4ybhkpEMqwM56tum2VruvSMJwPHIP/BPzkMJbXCDQV4mXPdp2xmc94yTKeVxmb9TPBuiQfpSomq1PL3wF/AdrcNDhIcPFLAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;스펙&quot;
        title=&quot;스펙&quot;
        src=&quot;/static/8e60ac18b37170fb53643533e22c16c5/a6d36/3.png&quot;
        srcset=&quot;/static/8e60ac18b37170fb53643533e22c16c5/222b7/3.png 163w,
/static/8e60ac18b37170fb53643533e22c16c5/ff46a/3.png 325w,
/static/8e60ac18b37170fb53643533e22c16c5/a6d36/3.png 650w,
/static/8e60ac18b37170fb53643533e22c16c5/e548f/3.png 975w,
/static/8e60ac18b37170fb53643533e22c16c5/3c492/3.png 1300w,
/static/8e60ac18b37170fb53643533e22c16c5/1a867/3.png 1998w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;분명히 브라우저 자체에서 min/max 처리가 되어야 함. 그래야만 하는데…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;그런데 똑같은 코드를 iOS에서 실행해보면…&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;/fcec39152aec90aa0eca9059c68f936f/4.mov&quot; control autoplay muted loop playsinline height=&quot;700px&quot;&gt;&lt;/video&gt;
&lt;em&gt;??&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;스크롤을 음수로 설정하면 그 값이 실제 좌표에도 영향을 주는 것을 확인할 수 있었습니다. 즉, &lt;code class=&quot;language-text&quot;&gt;scrollTo({ top: -5000 })&lt;/code&gt; 을 호출하게 되면 실제 스크롤은 &lt;code class=&quot;language-text&quot;&gt;0&lt;/code&gt; 까지만 이동하지만, 핑크색 상자의 &lt;code class=&quot;language-text&quot;&gt;top&lt;/code&gt; 좌표는 &lt;code class=&quot;language-text&quot;&gt;5098px&lt;/code&gt; 로 측정이 됩니다.&lt;/p&gt;
&lt;p&gt;이 현상은 양수 방향으로도 적용되더라구요. 즉, y를 &lt;code class=&quot;language-text&quot;&gt;10000&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;20000&lt;/code&gt; 같은 큰 값으로 설정하면 &lt;code class=&quot;language-text&quot;&gt;top&lt;/code&gt; 좌표가 음수 방향으로 &lt;code class=&quot;language-text&quot;&gt;-9902px&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;-19902px&lt;/code&gt; 로 측정이 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;해결-방법&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95&quot; aria-label=&quot;해결 방법 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;해결 방법&lt;/h2&gt;
&lt;p&gt;자, 이제 문제는 확인했으니 해결책을 찾아야겠죠. 이러한 문제가 발생하는 것 자체는 브라우저의 버그이기 때문에 어쩔 수가 없는 것이고… 어쨌든 사용자에게 버그처럼 보이지 않도록 우리가 직접 해결해야 합니다. 제가 찾은 해결방법은 총 2개입니다.&lt;/p&gt;
&lt;h3 id=&quot;code-classlanguage-textsettimeoutcode-으로-여유-시간-주기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code-classlanguage-textsettimeoutcode-%EC%9C%BC%EB%A1%9C-%EC%97%AC%EC%9C%A0-%EC%8B%9C%EA%B0%84-%EC%A3%BC%EA%B8%B0&quot; aria-label=&quot;code classlanguage textsettimeoutcode 으로 여유 시간 주기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;setTimeout&lt;/code&gt; 으로 여유 시간 주기&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;scrollTo&lt;/code&gt; API 호출 직후에 해당 문제가 발생하기 때문에, 레이아웃을 재계산할 시간을 브라우저에게 충분히 부여하는 방법입니다. 저는 &lt;code class=&quot;language-text&quot;&gt;setTimeout&lt;/code&gt;을 적당히 주었더니 문제가 발생하지 않더라구요.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleClick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;top&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scrollTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; top &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;setTop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;divRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 적당한 지연 시간&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;video src=&quot;/c887865baeec1389bfab0061f1e4a031/5.mov&quot; control autoplay muted loop playsinline height=&quot;700px&quot;&gt;&lt;/video&gt;
&lt;em&gt;&lt;code class=&quot;language-text&quot;&gt;setTimeout&lt;/code&gt; 으로 적당한 시간 주기&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;다만 이 방법은 순간적이긴 하지만 화면에 깜빡임을 발생시킬 수 있다는 단점이 있습니다. 또한 &lt;code class=&quot;language-text&quot;&gt;setTimeout&lt;/code&gt;의 지연 시간을 얼마나 줘야 하는지도 명확하지 않아서 약간 불안정할 수 있어요.&lt;/p&gt;
&lt;h3 id=&quot;스크롤-값에-minmax-직접-적용하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%8A%A4%ED%81%AC%EB%A1%A4-%EA%B0%92%EC%97%90-minmax-%EC%A7%81%EC%A0%91-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0&quot; aria-label=&quot;스크롤 값에 minmax 직접 적용하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;스크롤 값에 min/max 직접 적용하기&lt;/h3&gt;
&lt;p&gt;조금 더 확실한 방법은 스크롤 불가능한 영역으로 API가 호출되지 않도록 직접 최대/최소값 절삭 로직을 추가하는 겁니다. 브라우저가 자동으로 해줘야 하는 걸 우리가 직접 하는 거죠.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;/85eb3e1546a37a78600a1b7467efbd5a/6.mov&quot; control autoplay muted loop playsinline height=&quot;600px&quot;&gt;&lt;/video&gt;
&lt;em&gt;스크롤 범위를 직접 제한&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;저는 음수 방향의 스크롤만 고려해서 일단 최소값이 &lt;code class=&quot;language-text&quot;&gt;0&lt;/code&gt;이 되도록 설정해두었는데요, 만약 양수 방향의 스크롤도 함께 고려한다면 아래와 같이 작성하시면 됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 최소값: 페이지 최상단&lt;/span&gt;
Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// 최대값: 페이지 최하단 - 뷰포트 높이&lt;/span&gt;
  Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;scrollHeight &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHeight&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;두 방법 중에서는 &lt;strong&gt;방법 2가 더 안정적&lt;/strong&gt;입니다. &lt;code class=&quot;language-text&quot;&gt;setTimeout&lt;/code&gt;은 타이밍 이슈가 있을 수 있지만, 직접 값을 절삭하는 방식은 확실하게 문제를 방지할 수 있거든요.&lt;/p&gt;
&lt;h2 id=&quot;최종-결론&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B5%9C%EC%A2%85-%EA%B2%B0%EB%A1%A0&quot; aria-label=&quot;최종 결론 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;최종 결론&lt;/h2&gt;
&lt;p&gt;혹시나 해서 이 문제가 iOS 내 다른 브라우저에서도 발생하는지 확인해봤습니다. 결과는… 예상대로 iOS Chrome에서도 동일한 문제가 발생하더라구요. 단순히 Safari만의 문제가 아니라는 뜻이죠. 이는 곧 두 브라우저에서 공통으로 사용되는 브라우저 엔진인 &lt;strong&gt;WebKit의 문제&lt;/strong&gt;라고 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;실제로 &lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=218891&quot;&gt;WebKit 버그 트래커&lt;/a&gt;에서 비슷한 오류 제보를 찾을 수 있었는데, 아직까지 대응이 되지 않은 걸 보니 당분간은 직접 해결해줘야 할 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 556px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ec18ae75653c166e797772209a56b871/96638/8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 36.809815950920246%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAAAsTAAALEwEAmpwYAAABBElEQVQoz2NIjQk4XJkX805KVumRjJzSY2lZxcdSMgooNCmYISsx9HZdUdJ/dS29//qGpv/VNXX+S0rL/5eWVSQLM5hb2l3z8g3+Lyuv/EdWXvmvtKwiTiwlo4BXHoQZDA1Nrjk7Of/X1jX8q6Vj8F9CSg7sQmwY5AIpGQX8LizPibna35D5X1pW6beCgvJfBSW1v0oqGmCsrKoJ5isqq/+VV1SFuxBE48IMvh5Od6NDfP5b2Dv9N7Jy/G9gaPpfz8AEHJ4GRqb/NbT0/uvoGf5X0yAubBmERKV28ApKPDDz8L+qaeN1VVNT95qElPw1CSk5MJaUlofT0rKK16RkFMA0LgwAvCTBWbRqPOcAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;펀치&quot;
        title=&quot;펀치&quot;
        src=&quot;/static/ec18ae75653c166e797772209a56b871/96638/8.png&quot;
        srcset=&quot;/static/ec18ae75653c166e797772209a56b871/222b7/8.png 163w,
/static/ec18ae75653c166e797772209a56b871/ff46a/8.png 325w,
/static/ec18ae75653c166e797772209a56b871/96638/8.png 556w&quot;
        sizes=&quot;(max-width: 556px) 100vw, 556px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;꿀밤펀치&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;프론트엔드 개발자 입장에서는 이런 브라우저 엔진 버그까지 직접 처리해야 한다는 게… 참 답답한 일입니다. 그래도 이걸 수정하는 PR을 올리고 팀원분들께 설명드렸더니 다들 경악하시면서 공감해주셔서 나름의 위로를 얻었습니다. 😂&lt;/p&gt;
&lt;p&gt;하지만 어쩔 수 있나요, 이게 프론트엔드 개발자의 숙명이니까요. 혹시 비슷한 문제를 겪고 계신 분들께 이 글이 도움이 되길 바라며 글을 마칩니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[『실용주의 기술 블로그 글쓰기』 수강 후기]]></title><description><![CDATA[강의 『실용주의 기술 블로그 글쓰기』 의 내용을 정리하고 느낀 점을 공유합니다.]]></description><link>https://wormwlrm.github.io/2025/11/02/Programmatic-Technical-Blog-Writing.html</link><guid isPermaLink="false">https://wormwlrm.github.io/2025/11/02/Programmatic-Technical-Blog-Writing.html</guid><pubDate>Sun, 02 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;7월에 마지막으로 글을 쓴 후, 자의 반 타의 반으로 한동안 글쓰기를 쉬게 되었습니다. 아무래도 글또가 끝나다 보니 강제로라도 글을 쓸 동기가 없어진 데다, 회사 일과 개인사 때문에 글쓰기에는 다소 소홀했던 것 같네요.&lt;/p&gt;
&lt;p&gt;문득 올해 작성한 글의 개수를 세어보니 6개밖에 안 되더라구요. 이전에 비하면 많이 줄어든 숫자이기도 하고, 한 달에 하나의 글을 쓰는 것이 목표였는데 그것을 달성하지 못한 점도 아쉬웠습니다. &lt;em&gt;노력이 필요한 습관&lt;/em&gt; 은 유지하는 것이 참 어렵다는 것을 느꼈고, 지금이야말로 글쓰기에 대한 동기 부여가 다시금 필요한 시점임을 깨닫게 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/120ebffd23a2bdf5f49169ee2a0fe224/229ad/1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 36.809815950920246%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAAAsTAAALEwEAmpwYAAABlklEQVQozzWR227TQBRF/Q+gNk3iYMe52fF9bMd2fI0bS2m4lRZRIdHCGxISD0iIz1/IU3g4DzMarVn7bOXp+2+6/kxzOLIvW4rqeer2mqrpyIsGP4w5dD3H0xvypqfqTmT1kV3Rsts3JGlBIBLOr9+jpFmJZfuIOCUIEwKxI97lOJ7Asj2W6y3jqYa59fDCGH1pMZkZjNQ5V7MF6nyDqq+4HE2J4gylrA+keSkN/1u1XU9Vd9TtUZ4dL0TEGSLJSPY1WdGQly0iLZgZJlPtGThIKUO81caWlhvLxVia0mqxsuT92rTRjbUEJmnO54dPfH36wv3HO9q24ZU2ZzLVuLxS5Rulqhp8Z0sYpbh+JMG2G2DaPq5lomk6Ly4mcgWu63H37Sc/fv3h8fYRz/PQjRUTdS6BMnKaV2xtn1AkmJbD1vEldNjfYLmxHGkdxhmhSHGivSyjiGr0+YKJqjEaz3h5McYPE5TT+S3Z4Yb65hbRnIn3R6J/tsN4QSw/rA897z48kCQpjhtgub5sf2h3SBcKQXfd8xdW1uGF/gLYnwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;강의 구매&quot;
        title=&quot;강의 구매&quot;
        src=&quot;/static/120ebffd23a2bdf5f49169ee2a0fe224/a6d36/1.png&quot;
        srcset=&quot;/static/120ebffd23a2bdf5f49169ee2a0fe224/222b7/1.png 163w,
/static/120ebffd23a2bdf5f49169ee2a0fe224/ff46a/1.png 325w,
/static/120ebffd23a2bdf5f49169ee2a0fe224/a6d36/1.png 650w,
/static/120ebffd23a2bdf5f49169ee2a0fe224/e548f/1.png 975w,
/static/120ebffd23a2bdf5f49169ee2a0fe224/3c492/1.png 1300w,
/static/120ebffd23a2bdf5f49169ee2a0fe224/229ad/1.png 1356w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;강의를 구매하게 된 계기&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;사실 저는 올해 8월에 글또 운영자이신 &lt;a href=&quot;https://zzsza.github.io/&quot;&gt;성윤&lt;/a&gt;님이 만드신 강의 &lt;a href=&quot;https://www.inflearn.com/course/%EA%B8%B0%EC%88%A0-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EA%B8%80%EC%93%B0%EA%B8%B0/dashboard&quot;&gt;『블로그 페이지뷰 300만이 알려주는 실용주의 기술 블로그 글쓰기』&lt;/a&gt;를 수강했습니다. 성윤 님의 노하우가 가득 담겨 있을 것 같은 제목(?)이라 흥미로웠고, 당시에 인프런에서 할인 중이어서 단돈 1,000원에 구매할 수 있었죠. (내돈내산! 😎) 저는 회사 점심시간에 틈틈이 강의를 들으면서 공감이 가는 부분들과 배울 점들을 비교하면서 들었던 기억이 나네요.&lt;/p&gt;
&lt;p&gt;지금처럼 글쓰기에 대한 동기 부여의 필요성을 느낀 상황에서 해당 강의에 대한 리뷰를 작성하는 것이 도움이 될 것 같아 이번 글을 작성하게 되었습니다. 단순히 강의 내용을 요약하기보다는 해당 강의를 들으면서 제가 느낀 점과 배운 점들을 중심으로 공유하고자 합니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3d50815250685a446d852dda9bcb28a2/ab986/2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 63.190184049079754%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB8ElEQVQ4y3VT2ZKjMAzk/39uax+SecmQQDgDtiFgfGDTW1JCapPZVVUj2xJtXU5yWeHa18j7EoWokXclsluJa18x6ExoBbEM6LVCP0vW9XBDKZsXanVDJisk92WCtQ7GWqwhgGV7IIYIxA0xBIT1afuUDVi9R/QBdzMjudsZIQQYb1G3DQ6HA06nE87nM9q2RXpOkWUZvtMURVng6+sLp+8TLpcL0jRl7bzDFjdMViOhz7qusN6hlwJFUaBpGnRdh2EYmJTWt7aFUoptdLafSynhvccWIyY7I5mt5tSIdNu292w+9v8TypA4OMIXYVjZ8Ilti5zm8XiEcw4xxh8+FMyD8K8IyUChW2t/4HLJkGU5Zq2ZlM52TWR88V7DnZBunqYJ16JAVVVcy7Iscb0WTFg3DWuqXZ7nqKqa/fSycEOpB8rc/50y1W4H7Rf6yRjOYK8tBeDDCu0WWG/hveNZfWsKj48xGMYRfd9DSgWlBgghIITkNXW1F4J9hnmEWx1cDLCR5nB6jM1OSPDryhEJKSGV4lGRRCYVj9FOPi8aFIwPAbpvsXQNJm+QUMiIj1exEWKknN7GwoUVLvjHC3oKpbzYBdp5mMMB5vcvDMEgaWeBwdwhlxHqCckYnnrESV0ZQg8vG/k1cw+xKHRaMrKxwh8biuj4R0o40gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;수료증&quot;
        title=&quot;수료증&quot;
        src=&quot;/static/3d50815250685a446d852dda9bcb28a2/a6d36/2.png&quot;
        srcset=&quot;/static/3d50815250685a446d852dda9bcb28a2/222b7/2.png 163w,
/static/3d50815250685a446d852dda9bcb28a2/ff46a/2.png 325w,
/static/3d50815250685a446d852dda9bcb28a2/a6d36/2.png 650w,
/static/3d50815250685a446d852dda9bcb28a2/e548f/2.png 975w,
/static/3d50815250685a446d852dda9bcb28a2/3c492/2.png 1300w,
/static/3d50815250685a446d852dda9bcb28a2/ab986/2.png 2114w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;인프런에서 수료증 같은 걸 발급해 주길래? 일단 받아놨다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이번 글을 통해 &lt;strong&gt;기술 블로그 글쓰기에 대한 강의에서는 어떤 내용을 다루고, 강의를 수강한 입장에서 후기가 궁금하신 분들&lt;/strong&gt;께 도움이 되었으면 좋겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;강의-개요&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B0%95%EC%9D%98-%EA%B0%9C%EC%9A%94&quot; aria-label=&quot;강의 개요 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;강의 개요&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/51eab3ee60f4046e63216dbc6417eecb/04293/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 31.288343558282207%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABNUlEQVQY0z2QW08CMRSE9wcYL0tv2wvtAsKKElZcTXwlMfogkqCv6v//FZ9pMTxMOj09M+dMq3okCeNECJHUTgu3zuP8mMb6E3c+IKRGKoN1ofT50uMYx6NGaUOV0oTD4Yvdx5733Z77zcDmYWB4fKLvN6z7DQ/DkWcjpS3T2YzV6o7tdsvh85Ou60htizaWSummmGTh9bwjtlNimuBD/Ecq93Yyo3G+bJ1SSzdf8Pbyyu/3D1YbpBBY66lyZGU8UlukNjQ2/EcNJWo+M3ItD8+8lhJ5v2by3DMbeuSy5UzXNNpSCSG4nTuWN9fcrtZly0W3PBkdYzZcXNbk4TmWMg06xgIbI9JZRkqhlKESUpX/WNwscSFyVQtGQhWD84urgsxz/fim0cbh7JgQEsFHnA1obYvuD6XDpQiGzLvYAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;프로필&quot;
        title=&quot;프로필&quot;
        src=&quot;/static/51eab3ee60f4046e63216dbc6417eecb/a6d36/3.png&quot;
        srcset=&quot;/static/51eab3ee60f4046e63216dbc6417eecb/222b7/3.png 163w,
/static/51eab3ee60f4046e63216dbc6417eecb/ff46a/3.png 325w,
/static/51eab3ee60f4046e63216dbc6417eecb/a6d36/3.png 650w,
/static/51eab3ee60f4046e63216dbc6417eecb/e548f/3.png 975w,
/static/51eab3ee60f4046e63216dbc6417eecb/3c492/3.png 1300w,
/static/51eab3ee60f4046e63216dbc6417eecb/04293/3.png 2654w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;강의 프로필&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;강의 『블로그 페이지뷰 300만이 알려주는 실용주의 기술 블로그 글쓰기』는 데이터 사이언티스트 변성윤 님이 제작한 기술 블로그 운영 노하우를 담은 강의입니다. 성윤님은 데이터 분석을 주로 다루는 기술 블로그 &lt;a href=&quot;https://zzsza.github.io/&quot;&gt;&lt;em&gt;어쩐지 오늘은&lt;/em&gt;&lt;/a&gt; 을 8년째 운영 중이십니다.&lt;/p&gt;
&lt;p&gt;강의는 기술 블로그를 시작하는 분부터 이미 운영 중인 분들까지 모두에게 도움이 되는 실용적인 내용으로 구성되어 있습니다. 단순하게 글쓰기의 기법을 다루는 것에 그치지 않고, 동기 부여와 기술 블로그의 운영 노하우와 글쓰기 파이프라인 구조화 등 기술 블로그를 &lt;em&gt;꾸준히&lt;/em&gt; 운영하는 데에 필요한 다양한 주제를 포괄적으로 다루고 있습니다.&lt;/p&gt;
&lt;p&gt;현재 기준으로 약 3,000명 이상의 누적 수강생과 4.8점이라는 높은 강의 평점을 기록하는 등 많은 분들께 사랑받고 있는 강의이기도 합니다.&lt;/p&gt;
&lt;p&gt;저 역시 2018년부터 기술 블로그를 운영하면서 나름의 노하우를 쌓아왔는데요, 이 강의를 통해 제 경험을 객관적으로 돌아보고 다른 사람의 시각에서 바라본 새로운 인사이트를 얻을 수 있었습니다.&lt;/p&gt;
&lt;h2 id=&quot;강의-커리큘럼&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B0%95%EC%9D%98-%EC%BB%A4%EB%A6%AC%ED%81%98%EB%9F%BC&quot; aria-label=&quot;강의 커리큘럼 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;강의 커리큘럼&lt;/h2&gt;
&lt;p&gt;강의는 10개의 섹션으로 구성되어 있는데, 이 중에서도 인상 깊었던 주제를 간략히 소개하고 제가 느낀 점을 덧붙이도록 하겠습니다.&lt;/p&gt;
&lt;h3 id=&quot;기술-블로그-글쓰기의-어려움&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%B0%EC%88%A0-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EA%B8%80%EC%93%B0%EA%B8%B0%EC%9D%98-%EC%96%B4%EB%A0%A4%EC%9B%80&quot; aria-label=&quot;기술 블로그 글쓰기의 어려움 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;기술 블로그 글쓰기의 어려움&lt;/h3&gt;
&lt;p&gt;기술 블로그를 운영하고자 하는 개발자는 많지만, 이를 꾸준히 실천하는 것은 매우 어려운 일입니다. 그 이유에 대해, 강의자는 &lt;em&gt;‘저항’&lt;/em&gt; 이라는 개념을 통해 이를 설명합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;기술 블로그를 꾸준히 운영하는 것이 어려운 이유는 &lt;strong&gt;저항이 발생&lt;/strong&gt;하기 때문&lt;/li&gt;
&lt;li&gt;저항은 더 높은 차원으로 발전하려고 할 때 발생하는 마음가짐으로, 두려움이 클수록 저항도 커짐&lt;/li&gt;
&lt;li&gt;따라서 두려움을 인정하고 이를 극복하려는 결심과 행동이 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;강의자는 이런 저항을 만드는 유형을 다음과 같이 분류했습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;꾸준히 쓰는 것이 어렵다&lt;/li&gt;
&lt;li&gt;글의 만족스럽지 않다&lt;/li&gt;
&lt;li&gt;글의 소재가 떠오르지 않는다&lt;/li&gt;
&lt;li&gt;글을 썼지만 사람들의 반응이 없다&lt;/li&gt;
&lt;li&gt;글을 쓸 심리적 여유가 부족하다&lt;/li&gt;
&lt;li&gt;자신감이 없다&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;그리고 이러한 저항을 극복하고 꾸준함을 유지하기 위한 핵심 요소로 다음과 같은 공식을 제시합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;꾸준함 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;=&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 글을 쓰는 물리적 환경 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\times&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;×&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 동기 부여 (내적, 외적) &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\times&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;×&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 실행 (루틴)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;저는 이 섹션에 깊이 공감이 갔습니다. 지식 정리와 포트폴리오를 목적으로 기술 블로그를 처음 시작했을 때, 처음 몇 주는 높은 열정으로 글을 썼지만 시간이 지날수록 저항감이 커져서 꾸준함을 유지하기 어렵다는 느낌을 받았거든요. 퇴근 후에는 피곤해서 침대에 눕고 싶었고, 어떤 글을 써야 할지도 막막했습니다.&lt;/p&gt;
&lt;p&gt;저는 이런 어려움을 &lt;em&gt;글또&lt;/em&gt; 라는 글쓰기 모임을 통해 극복할 수 있었습니다. &lt;em&gt;글쓰기를 해야만 하는 환경&lt;/em&gt; 을 만들어, 매주 마감에 맞춰 글을 쓰고 다른 사람들과 공유하면서 자연스럽게 루틴이 형성되었죠. 하지만 글또 활동이 끝난 후, 제가 최근에 다시 느낀 글쓰기 저항감이 위 카테고리와 정확히 일치한다는 걸 깨달았습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;꾸준히 쓰는 것이 어렵다 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 글을 강제로 쓰게 만드는 환경이 사라졌다&lt;/li&gt;
&lt;li&gt;글의 만족스럽지 않다 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 내가 만족할 만큼의 퀄리티를 위한 노력과 시간을 들이는 것이 체력적으로 조금 부담스럽다&lt;/li&gt;
&lt;li&gt;글의 소재가 떠오르지 않는다 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 최근에는 개발적인 이슈나 새로운 기술에 대해 관심을 크게 기울이지 않았다&lt;/li&gt;
&lt;li&gt;글을 썼지만 사람들의 반응이 없다 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; AI 영향인지 기술 블로그 조회수가 전반적으로 줄어든 것 같다&lt;/li&gt;
&lt;li&gt;글을 쓸 심리적 여유가 부족하다 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 회사 일과 개인사로 최근에 여유가 없었다&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;일단 이 강의를 수강하는 사람이 기술 블로그 운영과 글쓰기에 어려움을 느끼는 사람일 가능성이 높기 때문에, 이렇게 공감대 형성을 하고 시작하는 부분에서 작은 위로(?)를 받게 되어서 좋았습니다.&lt;/p&gt;
&lt;p&gt;또한 제가 느끼고 있는 불확실한 감정을 명확하게 정의해 주니, 이를 극복하기 위한 방향성을 찾을 수 있겠다는 생각과 함께 다음 파트가 더 궁금해졌습니다.&lt;/p&gt;
&lt;h3 id=&quot;글의-독자-설정-및-좋은-글에-대한-정의-설정하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EC%9D%98-%EB%8F%85%EC%9E%90-%EC%84%A4%EC%A0%95-%EB%B0%8F-%EC%A2%8B%EC%9D%80-%EA%B8%80%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EC%9D%98-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0&quot; aria-label=&quot;글의 독자 설정 및 좋은 글에 대한 정의 설정하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글의 독자 설정 및 좋은 글에 대한 정의 설정하기&lt;/h3&gt;
&lt;p&gt;다음 섹션에서 강의자는 글쓰기의 목표와 대상 설정에 대해 설명합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;글의 독자: 기본적으로 나를 위한 글
&lt;ul&gt;
&lt;li&gt;미래의 나는 다른 사람&lt;/li&gt;
&lt;li&gt;일단 기본적으로 자신이 잘 이해하는 걸 목표로 하기&lt;/li&gt;
&lt;li&gt;완벽주의 지양하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;좋은 글: 자기가 생각하기에 좋은 글의 특징을 구체적으로 정의하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 부분에 대해서도 공감이 갔는데, 기본적으로 저도 글을 쓸 때 &lt;em&gt;‘미래의 나’&lt;/em&gt; 를 독자로 상정하고 글을 씁니다. 지금 당장 이해하기 어려운 개념이라도, 시간이 지나서 다시 읽었을 때 이해할 수 있도록 정리하는 것이 목표이기 때문이죠. 그래서 나중에 문득 저의 예전 글을 찾아볼 때, &lt;em&gt;‘내가 이 때는 이런 지식도 알고 있었구나!’&lt;/em&gt; 하는 생각도 종종 하거든요.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;‘좋은 글에 대한 정의를 구체적으로 정한 적이 있는가?’&lt;/em&gt; 에 대해서도 고민해 보았는데, 생각해 보니 &lt;a href=&quot;https://geultto.github.io/curation/&quot;&gt;글또 10기에서 큐레이션&lt;/a&gt;을 운영했던 경험이 떠올랐습니다. 수백 개의 글 속에서 하다 보니 어떤 기준으로 좋은 글을 선별해야 할지 고민한 적이 있었거든요. 명확한 대상 독자 설정과 내용의 깊이뿐만 아니라 글의 배치와 시각적 요소 등 독자 친화적인 다양한 요소를 고려했던 것들이 떠올랐습니다.&lt;/p&gt;
&lt;p&gt;제가 생각하는 좋은 글에 대한 정의는 &lt;a href=&quot;https://geultto.github.io/blog/writing/curation-first/&quot;&gt;인터뷰&lt;/a&gt;로도 정리한 적이 있어서, 관심 있는 분들은 참고하시면 좋을 것 같습니다.&lt;/p&gt;
&lt;h3 id=&quot;글쓰기-파이프라인&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EC%93%B0%EA%B8%B0-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8&quot; aria-label=&quot;글쓰기 파이프라인 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글쓰기 파이프라인&lt;/h3&gt;
&lt;p&gt;글쓰기 파이프라인은 기술 블로그에 소재를 찾는 것에서부터 글을 발행하기까지의 전체 흐름을 정리한 것입니다. 파이프라인을 구성하면 내가 글쓰기의 단계 중에서 어느 위치에 있는지, 그리고 어려움을 겪고 있다면 어느 부분에서 문제가 발생하는지 명확히 알 수 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;글쓰기에 집중할 수 있는 환경을 조성하기
&lt;ul&gt;
&lt;li&gt;공개 선언하기, 불안한 환경 만들기, 같이 하기…&lt;/li&gt;
&lt;li&gt;환경을 분석해서 해결 방법을 모색하고 움직일 수밖에 없는 환경을 만들기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;소재를 찾을 때는 공부 파트와 글쓰기 파트를 분리&lt;/li&gt;
&lt;li&gt;AI 잘 활용하기&lt;/li&gt;
&lt;li&gt;내적 동기와 외적 동기를 잘 활용하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;글쓰기에 대한 기술적 파이프라인 구축 자체는 &lt;a href=&quot;/2022/08/20/Personal-Branding-from-Technical-Writing.html&quot;&gt;『기술 글쓰기를 통해 개인 브랜딩을 구축하는 나만의 방법』&lt;/a&gt;이라는 글에서 다룬 적이 있어서 아주 크게 새로운 내용은 아니었지만, &lt;em&gt;글쓰기 환경 조성&lt;/em&gt; 에 대한 부분이 최근에 느꼈던 결핍 중에서 비중이 컸던 것 같아 다시 한번 생각해 보게 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/6cd031f04385a37b9ddda246b4b5147e/0b533/6.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 175.46012269938652%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAjCAYAAACU9ioYAAAACXBIWXMAAAsTAAALEwEAmpwYAAAIhUlEQVRIxyWUWYhciXmF75MnwSR4wYYQz4MNwdgTSSO11K3qruru6qquqlt3v7fuXnepW3Vr7dq61IuWbmkUacYaZskQxmNGNmScYGPHxlnJgonJgj1xDCYOxCRMYgIh+CEkhDjYb1+Q8vA//C+H859z/iPIpV3UcpXaZhH5+lXKa1e4fPEy9c0CWXUXtbCBtFWkulGgXa1yakmMa0Xcwhri5QvcNbd4PSzyilfkpVYBQS9u0mnKFDcK9CyZQKyzt1vFqZQ5KF/nXC5xWr3Gyd4aN3afZ1q6SL51kWzzMlnpKq8Nytz6yxXed+e8dS4iFC9doLRRQG80OOzYHOctHq4SXl0FPD5PeeMo4HZHZOpUyJQifm0Dq7KBUt5A3FqjWLjEtc/4/MpnHT5V+DSCtLNJZWMDa2edjtFg2W1zf57y1t0pv/nigs//2iFv3JrwcJFzb9zhrBdxJ4s4ixzOOjEvORKvanv8hlblLaeOUNm4wu6l52isX+AwbfPC7WPunpzw6Ow2r79wh9funfHy2W0enJ5yfnjEzemSk8mCo9GM1XDByWjOyXjBzekxx5MVQmhaGPUmtfXnGaddxlmXeZ4x78Ys84hFnjDpxHRDj047Yhh7BKaOrQeE8YhgMCPIpxh2QlNyET73+I95/eScuHyV2PUZpH1mo0OOJiOmWcSynzHPc/Iood1yiNwE0z2g1T5B9+Y0Gi2kpovYsGmKNsIfxet8K7rEi9oaltaiE3SY5AuOjo45Ob3NYjZnkOdEXoAlyThmQF3PqJkjqkrG3r5FpeFRboSUdmSEr7c+yR86n+JcvIBpp4Rej2lik9g2nm5jayZ6s4klS6iNJobSYl+JqMoZFbFN3V6wJ8Zsrm+yuVFC+Kpzga9Zn+a4dhFbd3BVk7bZInLaJEFG7Gdk8RBDVlEbErpkoTQdNC1G1yJE0UF8crLYQpJshG+MPb7R2WfVuEpLtbEljTw5YD49ZzE9Z35whzyb4RguekNCaxr4Tpc0XdLtHRNGM2w7J81uMDq4h/C1tMHvpmUWtSvYmoMja2RBzji/QeR1aDsRvuVjqwYtWcVSWkgNjSiaEUULgnCG442I00Ncf4zwe3GFP4mLLKqX8K0QTzOJ7IR+OmeQzRnnCw6nJ6RuQGiYtBQLS/OfsnnCKopn+OGEpLMiTJYIf9Au8aedCnNxi3YrxFNNevGY6egmy+kZ89GKaZYxSwL6vouv23hWQr9/Spod0RT/PzaVik61piN8r3eBb45EulKV2PLwFJ1hOmM2uslicouj+S1uT6c8nGYss4h2y8fRfQIvxzJiNCVE09rUahaNpovw4+OP8/VJmXblCqnl4UoKeTziYHDMsDNnGPcZ+S2mYYth4ONZIZI9oqb0qMop+0rGTj2huGdy7fI6wr8fP8tfHF7hUL1AbLbxJJlu0GOQzhl2ZuRRj36UEVsWbdPG1H0kI0MyckQtY1/tUpV77FRdynKC8G8nn+C96cdZ7j+HJ+t4jSaTzpOfjQh0j8SJSL0YV9VxVAtdCxCNHk1zSF0KqEptqnLC9p5F1egjvLf6JP+6+ASr2q/iKwZeXaSXDAkCH22/hv7kOyQVrdHEkgwU2aOuJIhaTnm7zvb1IsWNElsb22xc3UD4j7Nn+dHyWQ73nyNUDbxag27Yx3NctGodQ5QxFAP5KbCJLHvsKyk10WWnsM1OsUpps8rW9TJbhTLCf979Jf5l+TGWtQvEukGiOXTjHnGS4JouSq2JqVpPAU3ZQlJ89tWMmpQ8LYXt7QalzQrFwpMpI/zXvY/y3uKXWdQukpkWsWYz642ZD6Z00xmD7orp6BRLeVISOpJoIUkBYsN/ql+xVGNrvcTm+jbXrxQQ/ufBB/nR6iMs65fomiZhvcpBNmc+On0an07YI/W7qPsiltRCEw0GQUZqhSROB9fJCaMDHLtLHI0QfvLgA/zz4UdYipfpWRqxVGeRz5nmc3rtHomTELkppqyjywaW7uO2OoTBkE62xPP6DMZ3CNtTOsMzhJ/cfz//tPwQs8ZlckslkRtMkgH9sMeoM+EgXxDZIZqkYnfGpOkBw/yYpH2A5+Q4ds7ejkSlVGev7iD87/1n+MfFh5g0rpJbCrFc56AzZtFfkjk+crXC7uYWlfIeShBgtCJCf4TdyvC8AVGyYHr4kHY8x1BDhJ8+fIYfLj/IqH6N3FToqDI3xkcsh4ekThtd11FVld3dXXzPf7o7jouqaohine3SHuPpA2QlQJYchJ+9+Az/sPgFBrV1ckOmZxqsRisOsslTU6rlGi3LRtM0JFHE0jXi0MNxHNbW1qjua8TJCtPM6PVvIfzs4fv4wfwXGTaLjD2bzNCYZhNG6ZhJvmQ2Oib0uhiazna5RkXx2G46FApFtq6XaNQU6vsK9ZpKo24g/PTB+/j+/AMMm9vMvRZT3yZTm3R0lcxx6LgeqesTWC6ddEnQOSbon+N7PVwnRTcCFMVDaprU9qUnGv4cfzv5MEO/xvj4ZfpHnyM5+AxONMcOJ7h+jmN5RPGAfP4CrvfEjIwoGdP1u0zSOf1ogK3aaE0N4b/v/zx/Nf4oYeUivmFguiPM9Db28AHu9BWs5ZtYNz6PevRF9NN3UI6/SPPotxBXj1GHL+NkD7DbK6z4EMeIEH585/18Z/4xzuxr3DIvsdIuMZEvE1efJ9y/SrtRIJbLJJZE6raIg4Cw3cFOJpj5LYzhPZTJI8SD19mfvYnww6MP8zePGnznjRbvvuny7tsx734h43dedHl82+LNmxaPFjr3xwqnnQZTv8LA2qWjFgkbBVqVdbSdNeTSGmLxGsK3z67wZ6/4fPORzrdea/HXnw1593HK997J+LsvD/j7r474wVdGfP/LI7772znffifnz9/u8vu/HvOllwLePnN4dWVwdyizbFf5PwUbsz7wFk3gAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;공개&quot;
        title=&quot;공개&quot;
        src=&quot;/static/6cd031f04385a37b9ddda246b4b5147e/0b533/6.png&quot;
        srcset=&quot;/static/6cd031f04385a37b9ddda246b4b5147e/222b7/6.png 163w,
/static/6cd031f04385a37b9ddda246b4b5147e/ff46a/6.png 325w,
/static/6cd031f04385a37b9ddda246b4b5147e/0b533/6.png 500w&quot;
        sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;사실 이번 글도 이번 주말 내에 완성하고 싶어서, 인스타 스토리에 공개 선언하기 방법을 썼다&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;루틴을 만들겠다는 목표를 세우면 어렵고, 무언가를 하고 싶어서 루틴이 필요하다고 생각하기&lt;/li&gt;
&lt;li&gt;완벽보다는 완성을 목표로 삼기&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 파트에서 가장 인상 깊었던 부분은 목표 설정 방식이었습니다. 저는 그동안 &lt;em&gt;‘한 달에 하나의 글을 쓰자’&lt;/em&gt; 라는 루틴을 만들었는데, 최근에는 이게 그저 억지로 만든 규칙처럼 느껴졌거든요.&lt;/p&gt;
&lt;p&gt;강의를 듣고 목표를 &lt;em&gt;‘1년에 12개의 글을 쓰고 싶다’&lt;/em&gt; 로 바꿨는데요. 수치상으로는 똑같지만, 느낌이 완전히 달랐습니다. 특히 그동안 글을 못 쓴 시간을 생각하면 남은 기간 동안 더 열심히 해야겠다는 동기부여가 확실히 되더라구요.&lt;/p&gt;
&lt;h3 id=&quot;글쓰기-세부-과정-소개&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EC%93%B0%EA%B8%B0-%EC%84%B8%EB%B6%80-%EA%B3%BC%EC%A0%95-%EC%86%8C%EA%B0%9C&quot; aria-label=&quot;글쓰기 세부 과정 소개 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글쓰기 세부 과정 소개&lt;/h3&gt;
&lt;p&gt;이 부분은 글을 쓰는 과정 중 활용할 수 있는 기술적인 방법을 다룹니다. 강의자는 글쓰기 과정 중에서 다음과 같은 방법들을 활용해 글을 작성한다고 설명합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;예상 독자 설정&lt;/li&gt;
&lt;li&gt;목차 구조 잡기&lt;/li&gt;
&lt;li&gt;빠른 초안 작성 후 내용 보강&lt;/li&gt;
&lt;li&gt;셀프 피드백 (소리 내며 읽기, 일단 배포하고 읽기, 자고 읽기 등등)&lt;/li&gt;
&lt;li&gt;이미지 도식화하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 부분 역시 전의 파트에서 언급한 글에서 다룬 적이 있어서 크게 새로운 내용은 아니었지만, &lt;em&gt;셀프 피드백&lt;/em&gt; 에 대한 구체적인 방법론이 제가 실천하고 있던 방법이라서 반가웠습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ffd2534bbd689b6bfb5458e0d76a0432/f73a1/5.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 89.57055214723925%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAAAsTAAALEwEAmpwYAAACo0lEQVQ4y42UaW/bRhBA9f//VJEPBYoigW04umgeOmiSEine4rHXK5aUHEdtgg7wOMfODIbEcBcAxphfcj/XWt9iv89f3Ise5R4vihzPdQkCnzQ93w/5lSzuxVLNKG2nmbH2MCr6QTCMklGoj7xHbO7HhHmrOVWapNRsI8E2lmwiSZgr8itkLVxaqw1ZY0gbTVp/ojEklZ6aLuwkaWVICohy2BwVXqRYHyROKHAjgRdJtuH4YSeFIasg/UScz5NOr3warmzanHWT87WIea5PfCtjVs2Ft2uF05Zs25JNU7BpCxzLtfyJbVsgtWahtGavSxxzwTU5X/uQp/6db13I9yFhOcSsxxOOzDjQcKCe2H/C+r4ukEbNE15ERjC4+P0by+qJdf0y4bQrnOt2wu0cdoM75e0esLGg91C2odaKVr1RqSca/UrSfiFq/iBuv5D1f1OJF0rxTK1e6djSsflPGrVCGzlPWI5n3gefsHNxqxV+tWFXb9jXa4Jqya5acWi3xMOOqPeJ+uABn/cuQGllv6Eh7MGrRrzW8NdF8mcmWDeafQdBBzurrxZDOMDxARvzOxB2bQyGpFP4+YhbSJ6Tntfkyvek4yVueY5blufZXqc9h1qzr9S/8EuJnBpqQ5VrksRwSjS+Iwlcyc6TZKkmSw2p1dmsz2d98zXpDWufTxpl91Ab29BwSTSXWHN0BUd/5D0QRHs56dAbP/TRHUkOgjIzlOlMlRnye0MwyLRj3DUMQU23vNCvbywzxKFBhFdE2P7EeLxxmBn2DUZpFvahT1fMscGEDWKTMm4zxnXKsDwh3MuMn/+wvXxChzWkHZw7TNzODafbZlToZkTXI6ocUNWNsp8p+h/23bdUw1xjc+sBY38985u77f+I3RKhJEIKlFL8Awz3YouihVRWAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;napkin ai 활용하기&quot;
        title=&quot;napkin ai 활용하기&quot;
        src=&quot;/static/ffd2534bbd689b6bfb5458e0d76a0432/a6d36/5.png&quot;
        srcset=&quot;/static/ffd2534bbd689b6bfb5458e0d76a0432/222b7/5.png 163w,
/static/ffd2534bbd689b6bfb5458e0d76a0432/ff46a/5.png 325w,
/static/ffd2534bbd689b6bfb5458e0d76a0432/a6d36/5.png 650w,
/static/ffd2534bbd689b6bfb5458e0d76a0432/f73a1/5.png 822w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;Napkin AI를 활용해 위 개념을 도식화 해보았다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;또한 &lt;a href=&quot;https://www.napkin.ai/&quot;&gt;Napkin AI&lt;/a&gt;를 활용한 이미지 도식화 방법은 해당 강의를 통해 처음 알게 됐는데, 텍스트로 된 개념을 시각적으로 쉽게 표현하는 데에 큰 도움이 될 것 같아 앞으로 종종 활용해보고 싶다는 생각이 들었습니다.&lt;/p&gt;
&lt;h3 id=&quot;seo와-글-발행-전략-및-사례-공유&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#seo%EC%99%80-%EA%B8%80-%EB%B0%9C%ED%96%89-%EC%A0%84%EB%9E%B5-%EB%B0%8F-%EC%82%AC%EB%A1%80-%EA%B3%B5%EC%9C%A0&quot; aria-label=&quot;seo와 글 발행 전략 및 사례 공유 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;SEO와 글 발행 전략 및 사례 공유&lt;/h3&gt;
&lt;p&gt;다음 섹션에서 강의자는 SEO 전략과 글 발행 전략에 대해서 설명합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;SEO 전략: 검색 엔진에서 내 글이 잘 노출되었으면 좋겠다&lt;/li&gt;
&lt;li&gt;글 발행 전략: 사람들이 내 글을 많이 읽었으면 좋겠다&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 파트에서 SEO 전략은 다음과 같은 네 가지 유형으로 나눌 수 있다고 설명합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;온 페이지 SEO: 웹 페이지 내 HTML, 키워드 요소 등 최적화&lt;/li&gt;
&lt;li&gt;테크니컬 SEO: 웹 사이트 내 기술적 측면 최적화&lt;/li&gt;
&lt;li&gt;오프 페이지 SEO: 웹 사이트 외부 접근 관점에서의 최적화&lt;/li&gt;
&lt;li&gt;에디토리얼 SEO: 콘텐츠 품질 중심의 최적화&lt;/li&gt;
&lt;li&gt;프로그래머틱 SEO: 자동화된 도구와 기술을 활용한 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 부분에 대한 지식도 예전에 &lt;a href=&quot;/2023/05/07/SEO-for-Technical-Blog.html&quot;&gt;『기술 블로그를 위한 SEO』&lt;/a&gt;라는 글로 정리해 둔 내용이 있고, 그 내용과 크게 다른 부분이 있지는 않아서 복습한다는 느낌으로 들었습니다.&lt;/p&gt;
&lt;h3 id=&quot;faq&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#faq&quot; aria-label=&quot;faq permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;FAQ&lt;/h3&gt;
&lt;p&gt;강의의 마지막 부분에서는 일반적으로 자주 묻는 질문(FAQ)에 대한 답변을 다룹니다. 여기서는 다음과 같은 주제들이 포함되어 있습니다. 정답이 없는 질문에 대해 강의자의 식견과 노하우가 담긴 답변을 들을 수 있던 파트여서 좋았습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;적절한 글의 분량은 얼마인가요&lt;/li&gt;
&lt;li&gt;블로그 플랫폼을 옮기고 싶어요&lt;/li&gt;
&lt;li&gt;블로그를 종류 별로 나누거나 합치고 싶어요&lt;/li&gt;
&lt;li&gt;회사에서 배운 지식을 글로 써도 될까요&lt;/li&gt;
&lt;li&gt;글의 문체는 어떻게 해야 하나요&lt;/li&gt;
&lt;li&gt;본문에 이미지를 첨부하는 방법은 어떤 것이 좋을까요&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;위 질문에 대한 저의 생각은 아래와 같습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;적절한 글의 분량은 얼마인가요 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 저는 TTR(Time To Read) 기준으로 10분 내외 분량을 선호합니다.&lt;/li&gt;
&lt;li&gt;블로그 플랫폼을 옮기고 싶어요 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 저도 SEO 관점에서 블로그를 너무 자주 옮기는 것은 좋지 않다고 생각합니다.&lt;/li&gt;
&lt;li&gt;블로그를 종류 별로 나누거나 합치고 싶어요 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 저도 기술 블로그는 GitHub Pages에, 여행 후기는 네이버 블로그를 활용하는 등 주제 별 블로그를 운영하고 있습니다.&lt;/li&gt;
&lt;li&gt;회사에서 배운 지식을 글로 써도 될까요 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 회사의 정책에 따라 다르겠지만, 일반적으로 허락을 구하고 작성하려 합니다.&lt;/li&gt;
&lt;li&gt;글의 문체는 어떻게 해야 하나요 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 저는 딱딱한 문체보다는 친근한 구어체를 선호해서 이렇게 작성하고 있습니다.&lt;/li&gt;
&lt;li&gt;본문에 이미지를 첨부하는 방법은 어떤 것이 좋을까요 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\rightarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 저는 GitHub 리포지토리에 이미지 파일과 문서를 함께 형상 관리 하고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;개인적으로는 이 부분에서의 질문 수가 더 다양했으면 좋았겠다는 생각이 들긴 했습니다. 궁금하긴 하지만 어디 가서 물어보기엔 애매한 질문들, 사실 기술 블로그도 콘텐츠 창작자인 만큼 &lt;em&gt;‘애드센스를 이용한 콘텐츠 수익화에 대한 질문도 간단히 언급했다면 어떨까?’&lt;/em&gt; 하는 생각도 들었구요. 또한 작년에 나온 강의지만 기술 블로그에 AI를 잘 활용하는 방법이 있었다면 어떨까 하는 생각도 들었네요.&lt;/p&gt;
&lt;h3 id=&quot;글쓰기-레벨&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EC%93%B0%EA%B8%B0-%EB%A0%88%EB%B2%A8&quot; aria-label=&quot;글쓰기 레벨 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글쓰기 레벨&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b5548b685c93a4cdb43ba7d051c5ddfe/599ea/4.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 36.809815950920246%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAABL0lEQVQoz5VQy07DMBDMN/MpPXBBSFw5cENCQkAvFT2VCxJ90CZVqdqkTm3HjmM7rjMoVoPK44Kl0a52d2Z3HBGSYzKdYb6IkSRLLOIE48kU220KzgukWQbGOChlX2g5jHPs9xSUUuxIjh0hUKpCpLUOxBZCCAgpUQgBYwy89/jvi6y1KJWCUgpSlkHIORdEpZRhqGmabyR3OKC0Br7xoXeKqBvqSO3Fk9k45HGcYDZ/D3kpOIajPg7OYJTucPY0wIYXoedPBbuks7der3DTO4eTFTarGMOLK8A1yLMUt71LiIIhXWcYXj+g0vqXg6grdEVRUDw/3qGSCloxvA3u4UyN2losXl5D9NpALD+A4xF/Cx4LrWVZqrDd2hqEMRhrUNc1crYP/2usBWE0xJ+CnzMKGM6DdFQCAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;글쓰기 레벨&quot;
        title=&quot;글쓰기 레벨&quot;
        src=&quot;/static/b5548b685c93a4cdb43ba7d051c5ddfe/a6d36/4.png&quot;
        srcset=&quot;/static/b5548b685c93a4cdb43ba7d051c5ddfe/222b7/4.png 163w,
/static/b5548b685c93a4cdb43ba7d051c5ddfe/ff46a/4.png 325w,
/static/b5548b685c93a4cdb43ba7d051c5ddfe/a6d36/4.png 650w,
/static/b5548b685c93a4cdb43ba7d051c5ddfe/e548f/4.png 975w,
/static/b5548b685c93a4cdb43ba7d051c5ddfe/3c492/4.png 1300w,
/static/b5548b685c93a4cdb43ba7d051c5ddfe/599ea/4.png 1926w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;글쓰기 레벨이라는 개념을 통해 정리해 주심&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이 파트는 강의가 발매되고 난 후 추후에 추가된 내용인데요, 글쓰기에 대한 레벨을 정의해서 스스로가 어떤 단계에서의 글쓰기 방식에 있는지, 더 영향력 있는 글쓰기를 위해서는 어떤 관점에서 노력을 해야 하는지에 대해 설명하는 내용입니다.&lt;/p&gt;
&lt;p&gt;그 내용을 간단하게 요약하자면 다음과 같은데요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lv1&lt;/strong&gt;: 책, 강의 등 이미 정리된 지식을 스스로 기록하면서 정리하는 단계&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lv2&lt;/strong&gt;: 기술 기반의 문제 해결법을 정리하는 단계&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lv3&lt;/strong&gt;: 경험 기반의 문제 해결법을 정리하는 단계&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lv4&lt;/strong&gt;: 생각의 구조화와 통찰을 제시하는 단계&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;재미있는 점은 레벨이 높아질수록 기술적인 내용의 비중은 오히려 낮아진다는 점입니다. 물론 기술 블로그인 만큼 기술적 깊이도 중요하지만, 더 높은 단계로 갈수록 본인만의 관점과 통찰이 더욱 중요해진다고 합니다.&lt;/p&gt;
&lt;p&gt;제가 이해하기에 레벨이 높은 글을 작성한다는 것은 다음과 같은 과정으로 나아가는 길이라고 생각했습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;처음에는 어떤 도구를 잘 쓰는 법에 집중&lt;/li&gt;
&lt;li&gt;점차 그 도구를 활용해서 문제를 해결하는 법에 집중&lt;/li&gt;
&lt;li&gt;그 도구를 사용하는 스스로의 모습으로부터 특징을 찾아내고, 최적화, 패턴화, 그룹화, 추상화 등을 통해 통찰을 얻음&lt;/li&gt;
&lt;li&gt;결론적으로는 그 도구로부터의 물리적 거리는 멀어지지만, 그 도구를 활용하는 사람과 집단에 더 큰 가치를 제공할 수 있게 되고 이것이 더 큰 영향력을 발휘하게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이런 관점은 꼭 기술 글쓰기뿐만 아니라 사업, 교육, 투자 등 다른 분야에서도 적용할 수 있는 개념인 것 같아서 흥미롭게 읽었습니다.&lt;/p&gt;
&lt;p&gt;실무자 입장에서 작성할 수 있는 세세한 고민도 좋지만, 거시적인 시야를 위해서는 다양한 레벨을 오가면서 글을 쓸 수 있어야 한다고 생각하는데요. 그렇다면 제가 최근에 블로그에 쓴 글 중에서는 이러한 레벨별 비율이 어느 정도 될까요?&lt;/p&gt;
&lt;p&gt;후기글을 제외한 최근 10개의 글을 기준으로 대략적으로 나눠보면 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5b3e55d4f97c977f8484bfed3afd189b/68e9c/7.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 82.82208588957054%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAABb0lEQVQ4y6VUiY6CQAzl/z9R1mONrCKHzAVzlbeZbjSouKtuk5cGprz2tWUyTGwcR7xic/HZ7aExBtvtlrFarZDnOXa7HWOxWGC/36MoCoQQZknvCJ1zaNsWTdMwDocDe9F1qKoKXdfhdDqBiK6+O/vsP5Ln7K7C5M+w0UP5AToM2JgKn6aCdD1ijIxplZcK54jOz5038BQRKEIFy+RSSJad2qC1fp6QRoKOw8uTzh71Lr1phh7GjtCWUDQBX21Apx1P2HvPsh9WaK1FWZbsRyL44FEPqV9AiAQ9JEQIISGE4E34VbKUEsvlkr33Ab1WcEq8LvnSMyLewWlAbI+IgwANCu74AVvmcLpDCP6x5Lss6TA5IpBWGEdiRFXByyOUUqwiSU5/1fNrw4T6PclXZJOAREh9D7IWfrOGWy8Rjeb2nDEr+TbjVdWpr86BeoMofyacFruua5Z/RzjNdiv/nSssS5NNSPs3d4P8hdsKvwGQnDqxCOnZcQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;비율&quot;
        title=&quot;비율&quot;
        src=&quot;/static/5b3e55d4f97c977f8484bfed3afd189b/a6d36/7.png&quot;
        srcset=&quot;/static/5b3e55d4f97c977f8484bfed3afd189b/222b7/7.png 163w,
/static/5b3e55d4f97c977f8484bfed3afd189b/ff46a/7.png 325w,
/static/5b3e55d4f97c977f8484bfed3afd189b/a6d36/7.png 650w,
/static/5b3e55d4f97c977f8484bfed3afd189b/68e9c/7.png 654w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;&lt;code class=&quot;language-text&quot;&gt;3:2:3:2&lt;/code&gt;로 나름 적절한 비율을 유지 중&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;다행이게도(?) 나름 적절한 비율을 유지 중이네요. 앞으로 작성할 글의 방향도 한 분야에 너무 치우치지 않게 의도적인 노력을 해보려고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8dd6646522a2cb66d17ea249a09c7b15/f793b/8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 12.269938650306749%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAZ0lEQVQI14XHUQqDMBAAUe9/w0LRaCI1m2QNiB+tG6doD9CB9zHdcXzw80LvhWFOPNzCc3zhwvWZPiRciNRaiVGI8pNzuanq/ZISZkYHsL9PXDHGYgzZmLQR1obXxqSGXxuyNU7+9wWbL5iiI0JetAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Lv2&quot;
        title=&quot;Lv2&quot;
        src=&quot;/static/8dd6646522a2cb66d17ea249a09c7b15/a6d36/8.png&quot;
        srcset=&quot;/static/8dd6646522a2cb66d17ea249a09c7b15/222b7/8.png 163w,
/static/8dd6646522a2cb66d17ea249a09c7b15/ff46a/8.png 325w,
/static/8dd6646522a2cb66d17ea249a09c7b15/a6d36/8.png 650w,
/static/8dd6646522a2cb66d17ea249a09c7b15/e548f/8.png 975w,
/static/8dd6646522a2cb66d17ea249a09c7b15/3c492/8.png 1300w,
/static/8dd6646522a2cb66d17ea249a09c7b15/f793b/8.png 1404w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;갑자기 만난 익숙한 제목의 글&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;여담이지만 글에서 Lv2 좋은 글 예시로 제 글을 언급해주셔서 뭔가 뿌듯했습니다. 해당 글이 궁금한 분들은 아래 링크에서 읽어보실 수 있어요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2020/08/12/History-of-JavaScript-Modules-and-Bundlers.html&quot;&gt;JavaScript 번들러로 본 조선시대 붕당의 이해&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/2018/10/03/What-is-the-difference-between-javascript-and-ecmascript.html&quot;&gt;JavaScript와 ECMAScript는 무슨 차이점이 있을까?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;강의-후기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B0%95%EC%9D%98-%ED%9B%84%EA%B8%B0&quot; aria-label=&quot;강의 후기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;강의 후기&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExOXNqNHNwOWZkZmcwZXM0cDh1cGh6d3QxaXVheWR4bHE2anJja3lkZiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/l3OWNSxXiBNxereDFn/giphy.gif&apos; alt=&apos;수강 후기&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;식어버린 글쓰기 열정을 되살릴 수 있도록 도움을 준 강의&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;강의를 전체적으로 들으면서 느낀 점은 &lt;strong&gt;단순히 글쓰기 기술만 다루는 것이 아니라, 블로그 운영 전반에 대한 깊은 통찰을 제공&lt;/strong&gt;한다는 것이었습니다. 특히 제시된 프레임워크와 접근 방식들은 기술 블로그뿐만 아니라 다른 분야의 글쓰기나 프로젝트에도 활용할 수 있을 것 같았습니다.&lt;/p&gt;
&lt;p&gt;기술 블로그에 입문하는 분들께도 물론 많은 도움이 될 내용이지만, 특히 &lt;strong&gt;저처럼 기술 블로그를 운영하지만 슬럼프를 경험하고 있는 분들&lt;/strong&gt;께도 큰 도움이 될 것 같다는 생각이 들었어요. 비슷한 입장에서 공감할 수 있는 내용도 많았고, 같은 문제를 바라보는 성윤 님의 색다른 관점을 통해 &lt;em&gt;아하!&lt;/em&gt; 하는 순간들도 많았거든요.&lt;/p&gt;
&lt;p&gt;또 하나 재미있었던 점은 &lt;strong&gt;제가 이미 실천하고 있던 많은 방법들이 글또 활동을 통해 배운 것들&lt;/strong&gt;이라는 걸 새삼 깨달았다는 것입니다. 이를 통해 글또 활동이 제 글쓰기 여정에 얼마나 큰 영향을 미쳤는지 다시 한번 실감할 수 있었구요.&lt;/p&gt;
&lt;p&gt;무엇보다도 저에게는 글쓰기에 대한 동기가 떨어져 있던 시기에 이 강의를 다시 들으면서 글쓰기의 즐거움과 의미를 되찾을 수 있었다는 점이 가장 큰 수확이었습니다. 혹시라도 나중에 글쓰기에 대한 열정이 떨어지거나 슬럼프를 겪는다면, 이 강의를 다시 한번 들어보면서 스스로를 다잡아야겠다는 생각이 들었습니다.&lt;/p&gt;
&lt;p&gt;마지막으로 강의의 마지막 부분에서 제시한 액션 아이템들을 점검하며 글을 마무리하고자 합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;블로그를 운영하는 이유를 명시적으로 남겨두기&lt;/strong&gt;: &lt;a href=&quot;/manifesto&quot;&gt;글쓰기 매니페스토&lt;/a&gt; 문서를 작성함&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;내가 생각하기에 좋은 글 분석하기&lt;/strong&gt;: &lt;a href=&quot;https://geultto.github.io/curation/&quot;&gt;글또 10기 큐레이션&lt;/a&gt; 경험을 통해 정리한 바 있음&lt;/li&gt;
&lt;li&gt;☑️ &lt;strong&gt;글쓰기 프로세스 점검&lt;/strong&gt;: 기존의 글쓰기 파이프라인이 잘 동작하지 않은 만큼 재점검이 필요해 보이니 개선할 부분을 찾아보자&lt;/li&gt;
&lt;li&gt;☑️ &lt;strong&gt;글을 작성할 환경과 전략 만들기&lt;/strong&gt;: 1년 12개의 글 작성이라는 목표를 설정했으니, 남은 기간 내 목표 달성을 위한 전략을 구체적으로 세워보자!&lt;/li&gt;
&lt;li&gt;☑️ &lt;strong&gt;꾸준한 실천&lt;/strong&gt;: 매주 일정 시간을 확보해 글쓰기에 집중하자&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[클라이언트 환경에서 안전한 소셜 로그인을 구현하는 핵심 메커니즘, OIDC와 PKCE 알아보기]]></title><description><![CDATA[Facebook 로그인 예제를 통해 OIDC와 PKCE를 활용한 안전한 인증 코드 교환 과정에 대해 알아봅니다.]]></description><link>https://wormwlrm.github.io/2025/07/31/OIDC-with-PKCE.html</link><guid isPermaLink="false">https://wormwlrm.github.io/2025/07/31/OIDC-with-PKCE.html</guid><pubDate>Thu, 31 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b93c5e9c584ac0927712720095dfe012/108f8/0.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB4klEQVQ4y5WU22obMRCG/cot9Ka9KJRAb3qgF32GltASCmmgfQUXCulVcGkgjvdor/coaVfSfkVab+wSO7gDv2Y0SL9mRhpNikoghERISSM7hOpwvrKW/wnh902EEFyFLVehIghCfl8v6PserQ3a7IE2GONg72CtRbVDIJO6EUSFZS2hKitW65JjxB06wkmnzUBY1oq6KomCW7IsI44ikiQhimKiKCKOY2+HYcgiCJjP5+R5juNxkVk7kHad3kQoWoIwYjr9weXlL2azmSe6uZl77YkWC9I0JQgC7y/LcidK/o3QDdpY73SnHStjqvdSdoOb7C4cUrF3Ndpn79bxIOG20Ifs/bhH2HYGl7W2vdfW4rXZzI09hnBzKXkloB9T7h/Aw6LHCJUSTP8YHn+EJ6fw4gu8uoCX5/D0Ezz6AG+/4RfnRUVRNixXa+Jk6e3BV9MI5TtmoqTg53XL88+KkzPJm6+SdxeC1+eCkzPBs1PJ+++SOM08SZJmBGHM7SIkSVcb34q6Htp1UtQSJSpUGZPnGVm2om3W0ObQrulUjStLmiusdS2nvR5tPzdm+7BdU1eNpKgVadGxLDoaqZGtQSjjtWq13+D0LtpRdxoh2+0tF9XwW1Qb+HqV9+H9BzD+UH8BgCCDli+VN/0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;소셜 로그인&quot;
        title=&quot;소셜 로그인&quot;
        src=&quot;/static/b93c5e9c584ac0927712720095dfe012/a6d36/0.png&quot;
        srcset=&quot;/static/b93c5e9c584ac0927712720095dfe012/222b7/0.png 163w,
/static/b93c5e9c584ac0927712720095dfe012/ff46a/0.png 325w,
/static/b93c5e9c584ac0927712720095dfe012/a6d36/0.png 650w,
/static/b93c5e9c584ac0927712720095dfe012/108f8/0.png 777w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;흔히 마주칠 수 있는 소셜 로그인, 그 이면에 숨겨진 보안 메커니즘에 대해 생각해보기&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;최근 프로젝트에서 페이스북 소셜 로그인 기능을 구현하는 업무를 맡게 되었습니다. 기존에는 구글과 애플 로그인이 이미 구현되어 있었고, 서버에서 &lt;code class=&quot;language-text&quot;&gt;nonce&lt;/code&gt; 와 &lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt; 값을 발급받아 사용하는 &lt;a href=&quot;https://auth.wiki/ko/hybrid-flow#security-considerations&quot;&gt;하이브리드 플로우&lt;/a&gt; 방식을 사용하고 있었습니다. 그래서 저는 페이스북 역시 동일한 방식으로 구현할 수 있을 것이라 예상했죠.&lt;/p&gt;
&lt;p&gt;하지만 &lt;a href=&quot;https://developers.facebook.com/docs/facebook-login/guides/advanced/oidc-token/&quot;&gt;페이스북 공식 문서&lt;/a&gt;를 확인해보니, 예상과 달리 클라이언트에서 추가적인 보안 조치를 적용해야만 액세스 토큰을 얻을 수 있다는 점을 알게 되었습니다. 바로 &lt;strong&gt;PKCE가 적용된 OIDC 인증 방식이 필요&lt;/strong&gt;하다는 것이었습니다.&lt;/p&gt;
&lt;p&gt;물론 클라이언트에서 추가 인증 과정을 생략하고 액세스 토큰을 받아오는 방법도 있었지만, 이는 보안상 취약점이 있어 권장되지 않는 방식이었습니다. 그래서 가능하다면 PKCE가 적용된 OIDC 인증 방식을 써야 한다는 점을 알게 되었죠.&lt;/p&gt;
&lt;p&gt;사실 OAuth의 전체적인 흐름에 대해 잘 알지 못했던 터라, 낯선 용어들을 접하니 막막함이 느껴지더라구요. 그렇지만 회사 업무인 만큼 팀 동료들에게도 이 개념을 잘 설명할 수 있어야 했기에 학습에 대한 동기부여로도 이어졌습니다. 그래서 본격적인 기능 구현에 앞서 열심히 자료를 찾아보며 해당 개념을 이해하려고 노력했고, 결과적으로 코드 리뷰도 잘 마치고 기능 구현까지 성공적으로 완료할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;그래서 오늘은 제가 직접 경험한 페이스북 로그인 구현 사례를 바탕으로, OIDC와 PKCE를 활용해 클라이언트 측에서 어떻게 안전하게 사용자 인증을 구현할 수 있는지 알아보고자 합니다. &lt;strong&gt;OIDC와 PKCE의 개념을 이해하고 실제 적용 방법이 궁금하신 분들&lt;/strong&gt;께 도움이 되기를 바랍니다.&lt;/p&gt;
&lt;h2 id=&quot;개념-정리&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC&quot; aria-label=&quot;개념 정리 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;개념 정리&lt;/h2&gt;
&lt;p&gt;PKCE가 적용된 OIDC 방식의 소셜 로그인을 다루는 만큼, 필수적으로 등장하는 개념인 &lt;strong&gt;OAuth 2.0&lt;/strong&gt;, &lt;strong&gt;OIDC (OpenID Connect)&lt;/strong&gt;, 그리고 &lt;strong&gt;PKCE (Proof Key for Code Exchange)&lt;/strong&gt; 에 대해 간단히 정리해보겠습니다.&lt;/p&gt;
&lt;h3 id=&quot;oauth-20&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#oauth-20&quot; aria-label=&quot;oauth 20 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;OAuth 2.0&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7c39a08288bb5dec75ab7d8787ecf9ee/f73a1/oauth.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 76.68711656441718%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB60lEQVQ4y3VU2a7iMAzt//8d84DUChige6FM1+zJubJLoWi4lizHS04dL42kDKgqjzi+oyg8tAKTMUCeG+x2GdJUQwqyBoQQWAoBXK8Kf3YZisJB68UfORegVWAgMg7DhMfjgWkSrBMrFUBxC+BykXSlwEz3vWcHInISOevQ9x2OxyMOhwPO5zPa9g4lFdaYbxT820fZR8sTCNAz6JacczBmsXnvcTqdkCQJS9KJ7fPOivMBSGmTToEkiR/tP5RlibZtuRRd1zELITDPM+ZZfAecxhnjOG0CZz7fmjvyPEff91BKvVhKCTELaGV+z1BrDWP0UxqWXdfjdrthHEcGItvqJ13M8jsgOagBK9B6Kc8K7Pd7VFX1sm+BKZGvgEoZSCFfz6Fgqlt6zbiGlOU0Tdwoay0zxUmhfn+yNfYVTKy0wjwtNU3TlEeJMs0yGuaCy2CM/R+Qzt6tQ/tJUi5PHIaBZ/RyuTDw2iRrHE/pukHR59CGj/Vav+ycQVkWPPBxHDM3TQ1nzWZ2l4QiYwL6PqBpBLrOg3RyWgvW87xHUwuMw7bDmvWqmpFeHxh6in9mSHvaNB7nvz3q2kPK5Wu0w1VlkcQNy2X530Q7XJYWSXJDXTv+mTDgshnhuV7hVdzFjqf97VuZ9K1/bcoP9WqQQRuALGsAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;OAuth 2.0&quot;
        title=&quot;OAuth 2.0&quot;
        src=&quot;/static/7c39a08288bb5dec75ab7d8787ecf9ee/a6d36/oauth.png&quot;
        srcset=&quot;/static/7c39a08288bb5dec75ab7d8787ecf9ee/222b7/oauth.png 163w,
/static/7c39a08288bb5dec75ab7d8787ecf9ee/ff46a/oauth.png 325w,
/static/7c39a08288bb5dec75ab7d8787ecf9ee/a6d36/oauth.png 650w,
/static/7c39a08288bb5dec75ab7d8787ecf9ee/f73a1/oauth.png 822w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;OAuth 2.0 시퀀스 다이어그램, 출처는 &lt;a href=&quot;https://auth.wiki/ko/oauth-2.0&quot;&gt;여기&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OAuth 2.0&lt;/strong&gt; 은 &lt;strong&gt;권한 부여(Authorization)에 사용되는 프로토콜&lt;/strong&gt;로, 클라이언트(애플리케이션)가 사용자를 대신하여, 또는 애플리케이션 자체가 특정 자원에 대해 제한된 접근 권한을 얻을 수 있도록 하는 역할을 합니다.&lt;/p&gt;
&lt;p&gt;구글 드라이브에 접근 권한을 요구하는 SNS 서비스를 이용하는 시나리오를 한 번 떠올려봅시다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;철수는 SNS 웹 사이트의 구글 로그인 버튼을 클릭합니다.&lt;/li&gt;
&lt;li&gt;웹 사이트가 구글의 권한 허용 페이지로 리다이렉트되며, 이 액세스에 대한 동의를 제공하라는 메시지가 표시됩니다.&lt;/li&gt;
&lt;li&gt;철수는 동의 버튼을 클릭합니다.&lt;/li&gt;
&lt;li&gt;그러면 SNS로 리다이렉트가 되는데, 이때 SNS는 구글로부터 권한을 부여받는 과정을 거칩니다.&lt;/li&gt;
&lt;li&gt;SNS는 구글로부터 액세스 토큰을 받아, 철수가 구글 드라이브에 올린 사진첩에 접근할 수 있게 됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;이처럼 우리는 소셜 로그인을 시도할 때, 내 구글 계정의 ID와 비밀번호를 해당 서비스에 직접 입력하는 것이 아니라, 구글의 권한 동의 페이지로 리다이렉트되는 경험을 해보셨을 겁니다.&lt;/p&gt;
&lt;p&gt;여기에서 동의 버튼을 누르게 되면 해당 서비스는 구글로부터 해당 권한을 실행할 수 있는 &lt;strong&gt;액세스 토큰(Access Token)&lt;/strong&gt; 을 받게 되는데요, 서비스는 그 토큰을 이용해서 비로소 내가 가진 자원에 접근할 수 있게 되죠.&lt;/p&gt;
&lt;p&gt;이처럼 사용자는 자신의 구글 ID와 비밀번호를 해당 사이트에 직접 제공하지 않고, 구글을 통해 안전하게 자원에 접근할 권한을 위임합니다. 이 흐름이 바로 OAuth 2.0의 핵심입니다.&lt;/p&gt;
&lt;p&gt;이 과정에는 네 가지 핵심 개념이 등장합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;자원 소유자(Resource Owner)&lt;/strong&gt;: 사용자 본인&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;클라이언트(Client)&lt;/strong&gt;: 우리가 개발하는 애플리케이션 (구글 로그인을 연동하려는 서비스)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;권한 부여 서버(Authorization Server)&lt;/strong&gt;: 사용자를 인증하고 클라이언트에게 액세스 토큰(Access Token)을 발급해주는 서버,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자원 서버(Resource Server)&lt;/strong&gt;: 사용자의 정보(자원)를 실제로 보유하고 있는 서버 (예: 페이스북, 구글)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;그리고 OAuth 2.0에는 액세스 토큰을 발급받기 위한 인증 흐름의 종류를 정의하는 &lt;strong&gt;권한 부여 유형(Grant Type)&lt;/strong&gt; 도 네 가지가 존재합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;권한 코드 인증(Authorization Code Flow)&lt;/strong&gt;: 클라이언트가 권한 코드를 요청하고, 이 코드를 액세스 토큰으로 교환하여 발급받는 방식&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;암묵적 인증(Implicit Flow)&lt;/strong&gt;: 클라이언트가 직접 액세스 토큰을 요청하고 발급받는 방식&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;리소스 소유자 비밀번호 자격 증명 인증(ROPC)&lt;/strong&gt;: 사용자의 아이디와 비밀번호를 클라이언트가 직접 받아 OAuth 서버에 전달해 토큰을 발급받는 방식&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;클라이언트 자격 증명 인증(Client Credentials Flow)&lt;/strong&gt;: 클라이언트 시크릿을 사용하여 액세스 토큰을 발급받는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;그 중에서도 &lt;a href=&quot;https://auth.wiki/ko/authorization-code-flow&quot;&gt;권한 코드 인증 플로우&lt;/a&gt;라는 녀석이 오늘 이야기할 PKCE와 관련이 깊으니 기억해둘 필요가 있습니다.&lt;/p&gt;
&lt;p&gt;여기서 중요한 점은 OAuth 2.0은 &lt;strong&gt;인증(Authentication)&lt;/strong&gt; 이 아니라 &lt;strong&gt;권한 부여(Authorization)&lt;/strong&gt; 를 위한 프로토콜이라는 점입니다. 즉, OAuth 2.0은 사용자가 누구인지에 대한 정보를 확인하지 않습니다.&lt;/p&gt;
&lt;h3 id=&quot;oidc&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#oidc&quot; aria-label=&quot;oidc permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;OIDC&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/943c6f3f1a55910abf27fd1c68a21e15/2a50c/oidc.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 82.82208588957054%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAACJklEQVQ4y4VUi5KiMBDc//9Cz1WXVVeQR8IzIZDQWz2CJ2rdpWpIyKPT0zOTD2snVNWAtg0IAZimSQyYEDzQNB5a9bCG85jXAO8naN1DKwulLJwLMv9RlhN+zgZZFjCOWDU/AtdkwOGgofW0usw5L/P7vcJ+r9E2ww2QH2t7DMMgm4uiwG63Q1mWCIGXjJhJ/bfxvACWuoS1Ft576du2hXNOAJ0bYIyVzU3T4HK5iHHM/d6HB+YzQzYepi0LHBtjUFUVTscTlFKILzGyLEOapsjzXNa1Lu9n7gyrskJdN+j7XjaRJfvL5QdRFOHrEOF4PKLrOpGA8tAD7i8KtXJbABcwusADi/GQgHcGzvV3L7hv0Tf6iuSiO8PpQfF/ib9IQFsuImCSXNeAHJhugOv9WyAG5XrNEMcx8rxAmmaiX5EXIlWW5Q8aLmljRljrJLqPRhZkU1W1sHnX/Bheg+LcKABa6bsxlZIkwfl0xul4hpXUecq7MMGP0xqQH06+a2TFi+qqgbFGxnSXqcM8XErwLeBjnT4Hg9oxsqyi7XaLzWYjwJSjqdtXl4PcctOCUWTZsed/CF7YDIMTAEaUTG9pNiJLM6ntOyC1rqsepe7QMzBNK4Ds+36AKhoksYL3N83+MgeM8TCdhzGjuC6JrTXw/d3ievUvrw3/43jAbqeh1LSqWabZ5yclyLD9k6Ou59eGyHz3lmg9G5nJul/mxDnp5f0Mcz/P/wJ9wS8OxAUx8gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;OIDC&quot;
        title=&quot;OIDC&quot;
        src=&quot;/static/943c6f3f1a55910abf27fd1c68a21e15/a6d36/oidc.png&quot;
        srcset=&quot;/static/943c6f3f1a55910abf27fd1c68a21e15/222b7/oidc.png 163w,
/static/943c6f3f1a55910abf27fd1c68a21e15/ff46a/oidc.png 325w,
/static/943c6f3f1a55910abf27fd1c68a21e15/a6d36/oidc.png 650w,
/static/943c6f3f1a55910abf27fd1c68a21e15/2a50c/oidc.png 925w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;OIDC 시퀀스 다이어그램, 출처는 &lt;a href=&quot;https://auth.wiki/ko/openid-connect&quot;&gt;여기&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이러한 이유로 등장한 &lt;strong&gt;OIDC(OpenID Connect)&lt;/strong&gt; 는 OAuth 2.0 위에 구축된 프로토콜로, &lt;strong&gt;사용자 인증을 위한 표준화된 방법을 제공&lt;/strong&gt;합니다. OIDC는 사용자 인증과 ID 정보를 액세스 토큰과 함께 &lt;strong&gt;ID 토큰(ID Token)&lt;/strong&gt; 형태로 제공합니다.&lt;/p&gt;
&lt;p&gt;그런데 OIDC는 왜 필요한 걸까요? 단순히 OAuth 2.0으로 발급받은 토큰으로 로그인한 계정의 정보를 API로 조회하면 충분하지 않을까요?&lt;/p&gt;
&lt;p&gt;이는 OAuth 2.0의 근본적인 목적과 관련이 있습니다. OAuth 2.0의 액세스 토큰은 특정 자원에 접근할 수 있는 권한만을 증명할 뿐, 그 토큰을 사용하는 사람이 정말 토큰의 주인인지는 보장하지 않습니다. 만약 공격자가 액세스 토큰을 탈취한다면, 다른 사람인 척하며 자원에 접근할 수도 있겠죠. 이처럼 액세스 토큰과 프로필 API의 조합만으로는 인증된 사용자가 접근한다는 사실을 온전히 보장하기 어렵습니다.&lt;/p&gt;
&lt;p&gt;즉, OAuth 2.0의 액세스 토큰과 프로필 API는 사용자의 &lt;em&gt;리소스 접근&lt;/em&gt; 만 보장할 뿐, &lt;em&gt;사용자가 인증되었고 누구인지&lt;/em&gt; 는 보장하지 않습니다. 그래서 ID 토큰이라는 추가적인 인증 정보가 필요하며, 이 정보를 ID 토큰 형태로 제공하는 것이 OIDC의 핵심입니다.&lt;/p&gt;
&lt;p&gt;ID 토큰은 &lt;strong&gt;JWT 형식&lt;/strong&gt;으로 만들어집니다. 덕분에 클라이언트 애플리케이션은 구글, 페이스북 등 여러 제공자를 OIDC로 연동하더라도, 각각의 사용자 정보를 일관된 방식으로 안전하게 처리할 수 있다는 장점이 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;pkce&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#pkce&quot; aria-label=&quot;pkce permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;PKCE&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e396e72f8375b83956a741c8c0a593bd/1e043/13.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 77.91411042944786%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAAsTAAALEwEAmpwYAAACJklEQVQ4y41UabOiMBD0//8tP7zdh/eBCHLIpYIncnj3Vk9VWHHfh03VMDOVpDPdk9C6XC44Ho84HA7iT6eTxLT9fo/tdiu22+0kz7IMcRxjPBzC1nWMOx24lgWO1+uFVpIkME0TQRDAMAzM53MsFgtYlgXOrVYrAX88HsjzHPvdDhvumc2gaxrm3S4i2/4L6Ps+2u22gPV6PUynU6lgs9nUi9S4Xq8CTuAkTeF4Hn5rmvgakCdzIanfbjf876iqCizm19eXFFMDvi96Pp9CTdn9fhf7Kafe1JTGqhsV0nhiFEViaZqKdtTVcRyRgNVwjp5yhGHYkEPFLXaNm0n5U7PPxZ+DhZCVmq8pu64r3VUdVjnj2WwmHWeu67rkaq3neVgulyjLsgk4Go3Q7/dF3PF4LDYYDGQzrxQ3EtS27fowzvFA7iHLGpBUqRFp01MzXm4aKX1SVxRVA+kbGhKQL+F8Pku3CFwUhdw1gqqYc4x/GgSrAflhZTR2UcWkx07SqBNpk666Cev1un6a71UKIF9Hp9PBZDIRLbvdnnhqy9fDmJ75cDjE97cGTdNER+4hkwbger2C7y+lGgrNPEk2UlUcB4ijI+ZGhiR9wPcr2HaJMDwjy44ig9K6BvT9EIZhwfMCmKYt3rIcOM4SQRCLpwyu68CyTERRKJqrv1SjKfyEYQnXLeB5JTwvh+MUcJ0Mjp0jCC4wzQJpmqOqShRF+c+bf7/YfwApwLcJx/UWSwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;rfc7636&quot;
        title=&quot;rfc7636&quot;
        src=&quot;/static/e396e72f8375b83956a741c8c0a593bd/a6d36/13.png&quot;
        srcset=&quot;/static/e396e72f8375b83956a741c8c0a593bd/222b7/13.png 163w,
/static/e396e72f8375b83956a741c8c0a593bd/ff46a/13.png 325w,
/static/e396e72f8375b83956a741c8c0a593bd/a6d36/13.png 650w,
/static/e396e72f8375b83956a741c8c0a593bd/1e043/13.png 690w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;PKCE의 표준을 정의한 &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc7636&quot;&gt;RFC 7636&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PKCE(Proof Key for Code Exchange)&lt;/strong&gt; 는 OAuth 2.0의 권한 부여 유형 중 &lt;strong&gt;권한 코드 플로우(Authorization Code Flow)에 추가되는 보안 강화 확장&lt;/strong&gt; 으로, &lt;em&gt;“픽시”&lt;/em&gt; 라고 발음합니다.&lt;/p&gt;
&lt;p&gt;권한 코드 플로우는 서버로부터 액세스 토큰을 바로 전달받는 것이 아니라, 토큰을 교환하기 위한 &lt;strong&gt;권한 코드(Authorization Code)&lt;/strong&gt; 를 먼저 발급받고, 이 코드를 사용하여 액세스 토큰을 요청하는 방식입니다. 비유하자면 &lt;em&gt;액세스 토큰 교환권&lt;/em&gt; 을 발급해서 전달하는 것과 같죠. 이를 통해 액세스 토큰이 URL에 직접 노출되지 않도록 할 수 있다는 것이 장점입니다.&lt;/p&gt;
&lt;p&gt;그런데 문제는 이 권한 코드도 URL을 통해 전달되기 때문에, 코드 자체가 탈취될 경우 해당 코드로 액세스 토큰을 발급받을 수 있다는 점입니다. 액세스 토큰이 쉽게 탈취되지 않도록 &lt;em&gt;액세스 토큰 교환권&lt;/em&gt; 을 발급했는데, 이 교환권이 탈취당한다면 결국 액세스 토큰을 탈취당하는 것과 마찬가지라 조삼모사와 같은 상황이 되는 셈이죠.&lt;/p&gt;
&lt;p&gt;만약 별도의 서버를 구축해 클라이언트별 고유값인 시크릿(Client Secret)을 안전하게 숨길 수 있다면 문제가 없지만, 모바일 앱이나 브라우저에서 실행되는 SPA(Single Page Application) 등에서는 이 시크릿이 쉽게 노출될 수 있다는 문제가 있습니다.&lt;/p&gt;
&lt;p&gt;좀 더 구체적인 시나리오를 살펴보자면…&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;악성 브라우저 확장 프로그램&lt;/strong&gt;: 사용자가 설치한 브라우저 확장 프로그램은 웹 페이지의 내용을 읽거나 수정할 권한을 가지므로 악의적으로 제작된 확장 프로그램은 페이지가 리디렉션될 때 URL에서 권한 코드를 쉽게 빼낼 수 있음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프록시 서버 또는 악성 Wi-Fi&lt;/strong&gt;: 사용자가 신뢰할 수 없는 프록시 서버나 공용 Wi-Fi를 사용할 경우, 공격자는 사용자의 모든 웹 트래픽을 들여다볼 수 있으므로 권한 코드가 탈취될 수 있음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;서버 로그&lt;/strong&gt;: 웹 서버(Nginx 등)나 클라우드 서비스(Cloudflare Workers 등)는 일반적으로 모든 요청 URL을 로그로 기록하므로, 로그 파일 접근 권한이 공격자에게 넘어가면 권한 코드 또한 탈취될 수 있음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Referer 헤더 유출&lt;/strong&gt;: 사용자가 권한 코드가 포함된 URL로 리디렉션된 후, 해당 페이지에 있는 링크를 클릭하여 다른 사이트로 이동하면 HTTP의 Referer 헤더에 이전 페이지의 URL(권한 코드 포함)이 담겨 넘어갈 수 있음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XSS 공격&lt;/strong&gt;: 앱에 XSS 취약점이 존재하는 경우, 악성 스크립트가 클라이언트의 권한 코드를 탈취할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open Redirect 취약점&lt;/strong&gt;: 공격자가 &lt;code class=&quot;language-text&quot;&gt;redirect_uri&lt;/code&gt; 가 악성 URI로 변조된 링크를 클릭하도록 유도하면 공격자가 권한 코드를 탈취할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;결국 모든 문제의 원인은 바로 &lt;strong&gt;권한 코드가 클라이언트의 URL에 노출되어 탈취당할 위험이 있기 때문&lt;/strong&gt;입니다. 그렇기 때문에 PKCE에서는 액세스 토큰은 URL 로 전달되는 게 아니라, 주로 별도로 마련된 토큰 조회 API 를 통해서 발급됩니다. HTTPS 프로토콜을 사용해 통신하기 때문에 이 토큰은 TLS 암호화로 보호되죠.&lt;/p&gt;
&lt;p&gt;따라서 토큰을 제대로 발급받기 위해서는, 인증을 요청한 클라이언트가 토큰을 요청한 클라이언트와 동일한 주체임을 인증 서버에 증명해야 합니다. &lt;em&gt;‘인증을 요청한 것도 나고, 이 코드를 전달받은 것도 나니까 진짜 액세스 토큰을 내놔!’&lt;/em&gt; 라고 요청하는 것이죠.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/bf0420f6f5623f00f9f50a4b67df2d81/764be/pkce.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 82.82208588957054%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAACEklEQVQ4y6VU2Y7cMAyb///M3e1O7stnfHFBOclk2qIvNSDEsS2aoiQ/rM1oGoNx3JESoFTBNEV4Dxml0ApnyLlg6B2eTw2tk+yrLYn/ttX/h3MZz6dC22o4FzFNXhyMjogxCOB9DIPD968NWscKqCKe3wpKHYDnQTprrWCNRt/3WNcF8zwjhICUEmKMYuX3G26DewLIUO7nvN+xLIsYQWnTNIlxzTsP55yY9x4p5ctXAEsuB2i1nDIKyl/ZcGn3O7ZtwzAM6PoO0zRDay3gD6AcwsvxCpjLNf8D9DhLGay1Ysu8QiklkghD7yKcDXixxe0SiNO2bljXFfseRBIy5JrRBimV95BjoOjpEjaEeHzDFRr1o2ZcqxHcSOdylVcN+UpK/VrrLtGpDbPedR3GcZT5OE7Y9100k7CNRYpJcF5ZPm49avif45SCjHjpMIyS/XwBpluWcxGdzjmFDnsQ/cZhFN1SzJIUWs4ZYY9X6V2Ad4bU1BgLY4yESgbUkvXI9fvl+UpieRU2b+BBv3vRxTkvjJqmQdu2V3HTqCkZn53DJNH/rVNY6cwy6dc2q/NT+DNBNK5x/2xH1h8jIAH6PPAf4yx6YRzqQ/KwJuHrc0XbGsQIrEtC13o4i7duOTuoaTQ+PmaorTbCukZ8fbLIj9fGuyxP0jzV91CrjHkKx3t4FOytXHiu7x2srQBaZ/nnl4A/V08zvm+AoGoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;다이어그램&quot;
        title=&quot;다이어그램&quot;
        src=&quot;/static/bf0420f6f5623f00f9f50a4b67df2d81/a6d36/pkce.png&quot;
        srcset=&quot;/static/bf0420f6f5623f00f9f50a4b67df2d81/222b7/pkce.png 163w,
/static/bf0420f6f5623f00f9f50a4b67df2d81/ff46a/pkce.png 325w,
/static/bf0420f6f5623f00f9f50a4b67df2d81/a6d36/pkce.png 650w,
/static/bf0420f6f5623f00f9f50a4b67df2d81/764be/pkce.png 806w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;PKCE의 시퀀스 다이어그램, 출처는 &lt;a href=&quot;https://blog.logto.io/ko/how-pkce-protects-the-authorization-code-flow-for-native-apps&quot;&gt;여기&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이를 위해서 PKCE는 &lt;strong&gt;보증 키(Proof Key)&lt;/strong&gt; 라는 개념을 사용합니다. 이를 통해 클라이언트가 권한 코드를 요청할 때, 해당 코드가 실제로 이 클라이언트에 의해 요청되었음을 증명하죠. 이 과정은 다음과 같이 진행됩니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;클라이언트가 증명을 위한 임의의 비밀 문자열 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 을 생성&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt;를 특정 방식(주로 SHA256)으로 해싱하여 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt;를 생성&lt;/li&gt;
&lt;li&gt;클라이언트는 로그인 요청 시 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 를 권한 부여 서버(예: 페이스북)로 전송&lt;/li&gt;
&lt;li&gt;권한 부여 서버는 이 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 를 저장한 뒤, 권한 코드를 클라이언트에게 발급&lt;/li&gt;
&lt;li&gt;클라이언트는 발급받은 권한 코드와 함께, 원본 비밀 문자열인 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 권한 부여 서버에 보내 액세스 토큰을 요청&lt;/li&gt;
&lt;li&gt;권한 부여 서버는 전달받은 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt;를 저장해둔 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt;와 비교/검증하여 일치할 경우에만 액세스 토큰을 최종 발급&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 와 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 라는 용어가 갑자기 등장해서 낯설게 느껴지실 수도 있는데요, 여기서 중요한 부분은 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 라는 임의의 변수를 해싱(hashing)해서 나오는 값이 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 라는 것입니다.&lt;/p&gt;
&lt;p&gt;해싱의 특성상 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 알면 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 를 만들 수 있지만, 반대로 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 만으로는 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 유추할 수 없다는 점이 PKCE의 핵심입니다.&lt;/p&gt;
&lt;p&gt;이 과정을 통해 인증 서버는 클라이언트가 실제로 권한 코드를 요청한 주체임을 검증할 수 있습니다. 만약 권한 코드가 탈취되더라도, 원본 비밀값인 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt;를 알지 못하면 토큰을 발급받을 수 없습니다. PKCE는 이처럼 권한 코드 플로우의 보안을 크게 강화합니다.&lt;/p&gt;
&lt;p&gt;이러한 흐름을 표준으로 정의한 것이 바로 &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc7636&quot;&gt;RFC 7636&lt;/a&gt;입니다.&lt;/p&gt;
&lt;h2 id=&quot;페이스북-로그인-예제&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%B6%81-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%98%88%EC%A0%9C&quot; aria-label=&quot;페이스북 로그인 예제 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;페이스북 로그인 예제&lt;/h2&gt;
&lt;p&gt;이야기가 길어졌네요. 이렇게 해서 세 가지 개념의 이론을 정리해보았으니, 이제 본격적으로 페이스북 로그인에서 요구하는 PKCE가 적용된 OIDC 코드 플로우를 구현하는 예제를 살펴보겠습니다.&lt;/p&gt;
&lt;h3 id=&quot;페이스북-앱-생성&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%B6%81-%EC%95%B1-%EC%83%9D%EC%84%B1&quot; aria-label=&quot;페이스북 앱 생성 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;페이스북 앱 생성&lt;/h3&gt;
&lt;p&gt;페이스북 로그인을 구현하기 위해서는 먼저 &lt;a href=&quot;https://developers.facebook.com/apps/&quot;&gt;페이스북 개발자 센터&lt;/a&gt;에서 앱을 생성해야 합니다. 아래 단계를 따라 앱을 생성합니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/98baa9d0084045f8a1cf61447b49cf9c/65d79/6.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 49.69325153374233%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABQklEQVQoz6WQy07DMBBF/dHdsUJCYgmbRll10f+AH+ChAhItC1YUFTU0cZzYcWJnLhqTRGkBIcFIRx471vHNiNlshjiOMZ1OGeI1iiLq+gDv4zgeiKII8/mcFosFlqsVbq9vcH4ywdnxBKIsS1SVAUAgatG2LdV1zSu4iCj0Pd57OOfIOQdrLWxdw2uLq4sjPFyeQsi8wOtWISssqaqlsnLYbN4oSd6pKAoyxpC1dsB7T52c+LEerto2EKU2SNICSluqPci3wPLpme7uH2m9fqHtNiEp5QALu+RfhJxYaK2hdQlbGT4l5zyyLKM0zULCPM8HxsIwo4PiUQmlFHa7FGmaBgEnVp2A92OUUjzfML+maahpGvTwmTEGIs9zsJQJ/acMPyGlRPf7OIS/i17UiamT0y+M7+6xl3As/yviu1f+wwcl8+4CYuuqKgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;1&quot;
        title=&quot;1&quot;
        src=&quot;/static/98baa9d0084045f8a1cf61447b49cf9c/a6d36/6.png&quot;
        srcset=&quot;/static/98baa9d0084045f8a1cf61447b49cf9c/222b7/6.png 163w,
/static/98baa9d0084045f8a1cf61447b49cf9c/ff46a/6.png 325w,
/static/98baa9d0084045f8a1cf61447b49cf9c/a6d36/6.png 650w,
/static/98baa9d0084045f8a1cf61447b49cf9c/65d79/6.png 905w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;우선, 페이스북 개발자 센터에 접속하여 우측 상단의 &lt;em&gt;‘앱 만들기’&lt;/em&gt; 버튼을 클릭합니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/6a07f129665bf408dade4a41cdc0492a/1cfc2/7.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 53.987730061349694%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB50lEQVQoz1WR0XLaMBBF+e1mBgLTTp/gt6AdEhpKSZtQAsRgA7ZlSbZlyxa5nV0DQx/O7N21dLW7bvX7ffR6Pdx9ukO73Uan02Hu7xuo1u12+cwtg8EAo9E3TKdTDIdD9PsDfPn8Fa08z1GWJYJDgCRJUFUVkxuLorCsrbV8huJFE1prKKUYY3IURYEWF6RCYgQSKfiCcw772EIoi9PJsSkZOFejrmvWVDudTtdcSsk+bEgvyUQijmNY2xyu64ZLV7eQARkR9DjVLp2yYZqmPO5ut0MQBAgCn7Xv+4iiiL9RFEIwYRgiyzIekaAHLo1dDVOtsfU8rNcreJ6PrR8iimK+aPIcxhiGcto7wd+MuXbIhpfFWvoRRYE4SaDJoLQwZYnCWhSVQ1nVqE8OtXOonGNN0X188N3/OiRRUDyESII91OEIIwSyMEIeC+gwRhYJ1oxQyGKFUmpUSqOkprSG5h2mKXQUIpr8wvZpjtX4B/M+mWH9OMN2+gz99g613EASfzdQSw9y6UG/eUjXO4jpb+gwBHk1hscjwu9P2ExmWAzHeB2O8TJ8wMvoJ1YPc0R/ljg+L3CYvzKkL3m82EA8zqCPh7PheeRSachDDLGPkIYx9DHikYtEokjUTWwwlMsUVmXNyOcd/gNTxC1VvnzR4AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;2&quot;
        title=&quot;2&quot;
        src=&quot;/static/6a07f129665bf408dade4a41cdc0492a/a6d36/7.png&quot;
        srcset=&quot;/static/6a07f129665bf408dade4a41cdc0492a/222b7/7.png 163w,
/static/6a07f129665bf408dade4a41cdc0492a/ff46a/7.png 325w,
/static/6a07f129665bf408dade4a41cdc0492a/a6d36/7.png 650w,
/static/6a07f129665bf408dade4a41cdc0492a/1cfc2/7.png 900w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;두 번째 단계로 넘어가면 &lt;em&gt;‘이용 사례’&lt;/em&gt; 를 추가할 수 있는데요. 여기에서 &lt;em&gt;‘Facebook 로그인을 통한 인증 및 사용자의 데이터 요청’&lt;/em&gt; 항목을 선택한 후 나머지 단계를 거쳐 앱 생성을 완료합니다. 앱 생성을 완료하면 앱 목록에서 앱 ID를 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/80e9966d67b82ce6affb63ba63674277/6c745/8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 45.39877300613497%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABW0lEQVQoz63R227aMBzHcb/2lkDgYjfdM6xvMnHXwy0rykEpKRVhlITEdk6EEL5V3KHtouvFNEsf/W3L/skHcXX1lclkgmVZ2Lb9VkcjLNvmk2UZI8fBHo8ZO47pf7Ztvl1fs3BdPN/n+2yGM5kynX5BSKX5s3XHI+soIo1jGqWopaTOc6Pc76myzMwVacp+szGSODbrC5kjfm5fSNKMvu/pgWa3Yz2bsby7I7q5YTXU21ue7+9JfsxRnkf1+EgVhtTLJU0UUQQBycMDaj5HxMmBbXakrHvKDqrNjjoMeRmCo4j10xPxamUk24R0l5OnGTrbo7PMqIYTlyVVECCklJxOJzhDWTfmWsVigfZ9tOf95roo1zMK36cMAsqh+r4ZF55HEYaIrus4n8/m/Y5tS900qKp6l/5FfUBcPuMS2rYtSkq0Uqi/0B8QQ9DF0A6Hw9smrf+JuAT9r8BX5maT0pa2WNQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;3&quot;
        title=&quot;3&quot;
        src=&quot;/static/80e9966d67b82ce6affb63ba63674277/a6d36/8.png&quot;
        srcset=&quot;/static/80e9966d67b82ce6affb63ba63674277/222b7/8.png 163w,
/static/80e9966d67b82ce6affb63ba63674277/ff46a/8.png 325w,
/static/80e9966d67b82ce6affb63ba63674277/a6d36/8.png 650w,
/static/80e9966d67b82ce6affb63ba63674277/6c745/8.png 893w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;앱 생성이 완료되었다면, &lt;em&gt;‘이용 사례’&lt;/em&gt; 메뉴에 들어가 페이스북 로그인 설정을 위해 &lt;em&gt;‘맞춤’&lt;/em&gt; 을 선택합니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/dd2ba3f7e64eeb58b8f30b543ad863f3/6c745/9.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 58.89570552147239%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAABz0lEQVQoz3VS2W4iMRDkz+EFDdeXJJ/BW7RSXjZSQByBESgcw4zHx4yPcWW7mUS7sFgq2W5Xl9vt6kwmE/R6PXS7XSRJguFwiH6/z+skGWAwGGI0GjHG4/EPptMpZrMZFosFnp6fMUiGzO00TcTtsNaiqmp4H/BoeO+ZV9c1mqbhmHMWnaqqEGPkICGEAKU1jKmQ5wVDKc2JdIm1Ds575hFiWw/llmWJTl1bDsT2hA4MJTqPyyVHWUqYqmrFLGquykIIAecc8ymXIKVEh0i3gt/V0I1Eoj098fupVPH5nKEoBIQoYamoh4IhwJGoD8hygSwvUGoDG679JFbtPKQxMFQtPb+NS61vBKmXAPRmi2q1glotYdZrmPUHbJoyXJoifn4Ch8M/iLsd1Ol0L0gje/mF5esblm9z7BcfMMcj9OEIm2Ww54xnd7kgCnGF1mjSFHI+vxckSfE+w+7lFaffM4j3BZrtFmG75SRebzbwLWhN8bBcQu73//8UFwKsdxBlyRayPsC3XgsxQpkKQiqUSsHUlttE2equhyQYG2ilUeQFsuzCv+jIe86x7/BXa9rEq4/p9x/ZRmsNqRTbo2o9SDPZ58eLrR8JHJMK8o+xvwDJEY29q0/J7AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;4&quot;
        title=&quot;4&quot;
        src=&quot;/static/dd2ba3f7e64eeb58b8f30b543ad863f3/a6d36/9.png&quot;
        srcset=&quot;/static/dd2ba3f7e64eeb58b8f30b543ad863f3/222b7/9.png 163w,
/static/dd2ba3f7e64eeb58b8f30b543ad863f3/ff46a/9.png 325w,
/static/dd2ba3f7e64eeb58b8f30b543ad863f3/a6d36/9.png 650w,
/static/dd2ba3f7e64eeb58b8f30b543ad863f3/6c745/9.png 893w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;‘클라이언트 OAuth 설정 항목’&lt;/em&gt; 에 위치한 &lt;em&gt;‘유효한 OAuth 리디렉션 URI’&lt;/em&gt; 를 입력하는 칸으로 이동합니다.&lt;/p&gt;
&lt;p&gt;이곳에는 소셜 로그인 후 페이스북이 사용자를 다시 돌려보낼 URL을 입력해야 합니다. &lt;code class=&quot;language-text&quot;&gt;localhost&lt;/code&gt;도 가능하지만, HTTPS 프로토콜 적용을 권장합니다. 저는 &lt;code class=&quot;language-text&quot;&gt;https://localhost:3000/callback&lt;/code&gt; 을 입력했습니다.&lt;/p&gt;
&lt;h3 id=&quot;클라이언트-앱-생성&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%95%B1-%EC%83%9D%EC%84%B1&quot; aria-label=&quot;클라이언트 앱 생성 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;클라이언트 앱 생성&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/220d225897c887e91b88664c2d07ddb2/ecf19/10.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 39.263803680981596%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA7ElEQVQoz61SyaqEQAz04O7Fi6iIoOCGo4ji8gWuJ/3/j6khgR6c57s8eIeikmo6qaRbMk0TBMMwIOK/4n5XokQImqZBVVWGiIkVRfnohHuu6/pXUenexXVdeJ7HcBznk8dxjCAIOCaOoghhGML3fdi2/e1QBNQpSRKM44i+75HnOXNVVei6DkVRoG1bvF4vNE2DsiwxTRMXpykeBUkchgHHcWCeZ2zbhmVZOD/PE9d1Yd93rOvKEGd1XfMKLMt6OqQxsixjp4Q0TRnkjhxTLHRi0mhsscfHo9CSZVnmjne+4+eZGPfXR/mPb/MGXwHGoyKQoVoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Next&quot;
        title=&quot;Next&quot;
        src=&quot;/static/220d225897c887e91b88664c2d07ddb2/a6d36/10.png&quot;
        srcset=&quot;/static/220d225897c887e91b88664c2d07ddb2/222b7/10.png 163w,
/static/220d225897c887e91b88664c2d07ddb2/ff46a/10.png 325w,
/static/220d225897c887e91b88664c2d07ddb2/a6d36/10.png 650w,
/static/220d225897c887e91b88664c2d07ddb2/ecf19/10.png 948w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;루트 경로의 페이지, 버튼을 누르면 로그인이 시작된다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이와 더불어 클라이언트 앱 생성도 해야 하는데요, 저는 &lt;a href=&quot;https://nextjs.org/docs/app/api-reference/cli/create-next-app&quot;&gt;create-next-app&lt;/a&gt; 을 사용하여 Next.js 앱을 생성하였습니다. 그리고 로컬 서버 실행 시 간단하게 HTTPS 환경을 적용하도록 &lt;code class=&quot;language-text&quot;&gt;next dev --experimental-https&lt;/code&gt; 명령어를 사용했습니다.&lt;/p&gt;
&lt;p&gt;생성한 페이지는 총 2개로, 루트 경로(&lt;code class=&quot;language-text&quot;&gt;/&lt;/code&gt;)에는 페이스북 로그인을 시작하는 버튼을 배치하고, 리다이렉션 경로(&lt;code class=&quot;language-text&quot;&gt;/callback&lt;/code&gt;)에는 페이스북에서 리다이렉트 후의 로직을 담은 페이지를 구현하려고 합니다.&lt;/p&gt;
&lt;p&gt;이제 페이스북 로그인 버튼을 눌렀을 때 실행되는 로직을 구현하겠습니다.&lt;/p&gt;
&lt;h3 id=&quot;code-classlanguage-textcode_verifiercode-생성&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code-classlanguage-textcode_verifiercode-%EC%83%9D%EC%84%B1&quot; aria-label=&quot;code classlanguage textcode_verifiercode 생성 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 생성&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 607px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a6ba6c6cac950a85fb916db178697cb0/ef9e5/2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 57.668711656441715%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAAB1UlEQVQoz41T686aUBDk/d9KY4wxop8Gucn9CIIiICrenWa2sT/apv1INuw57OxlZtHatsXhcEAcxyjLLZIkQNNUWK/X2Gw2SJIETdPgu4+22+0E5PselCpgmimSuIBt20jTFI7jyPcwDFGWJfI8l+L8ppQC8fR593w+oTEoimPkRYZEVQiCO8KwRKIirFMlIHbLxATu93tJTn+1Wsk7iiJkWfazw6IooE902EsXru0gDn1YpgnPCWB8WcjSHKZlCnixWMD3fbiuK0k9z5OC9Nnh9XqFVlV7eCsfrhGJ+baC7yQILAVrFsKzI6GDAHbHicg5/a7rUNe1+LTT6cSEFdIsRdsewG5pBFV1ha47o25qMIYCvd/v/4vCagxmBRLMZOTjwwtHosrH4xG32w2Px0OMArDA76YR0Ov1YBjGL6MAk8lEeGPB8/mM+/2Oy+UiY9J45vNHQnZFUtkFE3BkdsBuXq/XP8f7GwUaV8KyLFGPiakg1ePZNE3M53PZwyAIxNd1HePxWGI4CfeVlH0mkbXp9/sSyGTD4VCABHHs6XQq95+7wWCA2WyG0WiE5XIpRiyLSkKOypXYbrfyF9AoDBeWopASGrvgmfeMpc+9ozikh0YOfwAE23zQHsSO9gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;code_verifier&quot;
        title=&quot;code_verifier&quot;
        src=&quot;/static/a6ba6c6cac950a85fb916db178697cb0/ef9e5/2.png&quot;
        srcset=&quot;/static/a6ba6c6cac950a85fb916db178697cb0/222b7/2.png 163w,
/static/a6ba6c6cac950a85fb916db178697cb0/ff46a/2.png 325w,
/static/a6ba6c6cac950a85fb916db178697cb0/ef9e5/2.png 607w&quot;
        sizes=&quot;(max-width: 607px) 100vw, 607px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;&lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 의 표준&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;가장 먼저, 클라이언트에서 암호화된 문자열 쌍을 생성해야 합니다. 이 과정은 서버와의 통신 없이 클라이언트에서 자체적으로 수행됩니다. 저희는 일단 웹 애플리케이션을 기준으로 설명하려고 하니, TypeScript를 사용하여 생성해보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7822c736645ef8365f309cca714cdc9d/5b4a1/1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 54.601226993865026%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAABp0lEQVQoz62T2Y7aQBBF/f//FKQoCOYxYWAAg03AC9h4wza9uMEnciOYPI6iXOnqSqVau6odIQS+7xNFEWVZcjqdOB6PxHFMnucM6Pv+y3SqqmL0bcRkMmExn/M2fWM6mTD+MWa9WvPIyJfh9PRINOKuaI2wKntteb1JatVS678oa7I6IxEVpSwtz9cLparpbgZH3TSrwufXbsFP7533/ZL5YcXisCZqE47XM7FlylFk7KuQ8XbKKF6yCWcs4wXfQ59NtUcYhaM7TVZknIuM4lKSV4XVsq4sn7anvagrzmVuY7Iit3GX5kKan1Fa4dR1zWw2Y/nxwXq1wl27bFwX3/MJDoGl53mEYWiX53seO9/n926H67psN1sO+4P1GRbsGGMYFpNlmdWiLO22/hXO/X5nSNp13UuVUraa1holBVoKq52SmE5ZCnFFSml9nvpKOIwdBgFxFBEEAWma2hEHW3g8sw1SdmHCNkjYHBJ2UUYYJw+fMLI33LbtZ8KmaezItiOlbJePygKhDY28cVU3Gmm4CEMtDUobtFKv7p7P5Dwv/H9g+Cl/ANdoSLnqhu2OAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;난수&quot;
        title=&quot;난수&quot;
        src=&quot;/static/7822c736645ef8365f309cca714cdc9d/a6d36/1.png&quot;
        srcset=&quot;/static/7822c736645ef8365f309cca714cdc9d/222b7/1.png 163w,
/static/7822c736645ef8365f309cca714cdc9d/ff46a/1.png 325w,
/static/7822c736645ef8365f309cca714cdc9d/a6d36/1.png 650w,
/static/7822c736645ef8365f309cca714cdc9d/5b4a1/1.png 831w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;&lt;code class=&quot;language-text&quot;&gt;Math.random()&lt;/code&gt; 는 &lt;a href=&quot;https://namu.wiki/w/%EB%82%9C%EC%88%98%EC%83%9D%EC%84%B1&quot;&gt;시드 기반으로 유사 난수&lt;/a&gt; 를 제공하기 때문에 보안을 위한 난수 생성 용도로는 별도의 API 사용을 권장하고 있다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;PKCE 표준에 따르면 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 는 임의의 문자열이어야 하는데, 이 문자열은 &lt;strong&gt;암호학적으로 안전한 무작위 문자열&lt;/strong&gt;이어야 합니다. 여기서 암호학적으로 안전한 난수란, 무작위성(엔트로피)이 충분히 높아 예측이 불가능한 난수를 의미합니다.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;Math.random()&lt;/code&gt;은 시드 기반으로 유사 난수를 생성하기 때문에, 예측 가능한 패턴이 있어 보안 용도로는 적합하지 않습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f8e5c0387a27c275cadc4e6c1fc64cfb/02cd5/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 52.760736196319016%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB8ElEQVQoz32TWW+bUBCF+f+/qO+VGqmJ7TiJwUBs8AJe4LLv2P6quY6r9qFFOjqcM6O5M5fBsG0b0zIxTRN/4zObzZhMJiwWC94/PrCWFtPpFMuyWNpLHMfhdrv9E8bG83n68YRlWrw8vzCbTpm/znmbC94wF6bWs+mM+ewV23b432PkY0XWl2RdSdYWVGNDOTa09HSMtAyaH8jblE12JKxj4vLIsVLsC0XaZozXC4adenxsl8zXC6y9i7l3eN9Y+GlAWEcE1emO8sihTbDCOd/cnzyfXD79CfPTJ9/3K4L6QH8ZMCIVEycxx+jEOT6j0oQ0zzSf4jORioiSmDhVOkdlKVmRkWYpUaJQiSKKz5xVxOVywfh0XX1/9tLGdRx8z8PzPDabDXmW09Q1dSWoKIpCvzdNo1GWpdZFXlCWFbfrDaNtW/q+/41hGBCvrmutx3HUnpzedi1d1+m4eAKJ913HdRzuH0W6kdVZrVa6q+12q9l1Xe2JllWRvAdLbLfbsV6v8X0Px12xCtR9bdywYBccCIOAMAwJgkAXET4cDpqlsPCf00h3/TDo0eumpeiu94JlJUajRxHkea7HFa6qSt+TFHqwjCe+5IgnI/+1h0rFRFFEkiQ6IU1TsizTWlgppQto/RUTyIESkw7lefwpvwB3Ezu76/4PZgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;난수&quot;
        title=&quot;난수&quot;
        src=&quot;/static/f8e5c0387a27c275cadc4e6c1fc64cfb/a6d36/3.png&quot;
        srcset=&quot;/static/f8e5c0387a27c275cadc4e6c1fc64cfb/222b7/3.png 163w,
/static/f8e5c0387a27c275cadc4e6c1fc64cfb/ff46a/3.png 325w,
/static/f8e5c0387a27c275cadc4e6c1fc64cfb/a6d36/3.png 650w,
/static/f8e5c0387a27c275cadc4e6c1fc64cfb/02cd5/3.png 821w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;&lt;code class=&quot;language-text&quot;&gt;window.crypto.getRandomValues()&lt;/code&gt; 로 안전한 난수를 생성하자&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이를 대체하는 함수로는 JavaScript의 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;window.crypto.getRandomValues()&lt;/code&gt;&lt;/a&gt;가 있는데요, 이 메서드를 사용하면 무작위성이 충분히 큰 난수를 생성할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 는 43자에서 128자 사이의 길이를 가지며, &lt;strong&gt;&lt;a href=&quot;https://base64.guru/standards/base64url&quot;&gt;Base64URL 인코딩&lt;/a&gt;&lt;/strong&gt; 을 사용하여 표현합니다. Base64URL은 URL에서 안전하게 사용할 수 있도록 일부 문자를 대체한 Base64 인코딩 방식으로, 일반적인 Base64 인코딩과 유사하지만 &lt;code class=&quot;language-text&quot;&gt;+&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;/&lt;/code&gt; 문자를 각각 &lt;code class=&quot;language-text&quot;&gt;-&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;_&lt;/code&gt; 로 대체하고 마지막 패딩 문자 &lt;code class=&quot;language-text&quot;&gt;=&lt;/code&gt; 를 제거한다는 특징이 있습니다.&lt;/p&gt;
&lt;p&gt;이러한 제약 조건을 만족하는 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 생성하는 TypeScript 코드는 다음과 같습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Base64URL 인코딩을 적용한 문자열 생성 함수&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; getBase64UrlEncoded &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bytes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Uint8Array&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  window
    &lt;span class=&quot;token comment&quot;&gt;// Base64 인코딩을 적용&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;btoa&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bytes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;byte&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromCharCode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;byte&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Base64URL 인코딩에서 사용하는 문자로 변환&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replaceAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;+&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;-&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replaceAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;_&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replaceAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;=&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 43자에서 128자 사이의 길이를 가지는 code_verifier 생성 함수&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; generateCodeVerifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Uint8Array 배열을 생성&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bytes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Uint8Array 배열에 무작위 값을 채움&lt;/span&gt;
  window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;crypto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getRandomValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bytes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Base64URL 인코딩을 적용하여 code_verifier 생성&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; codeVerifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getBase64UrlEncoded&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bytes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; codeVerifier&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;code-classlanguage-textcode_challengecode-생성&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code-classlanguage-textcode_challengecode-%EC%83%9D%EC%84%B1&quot; aria-label=&quot;code classlanguage textcode_challengecode 생성 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 생성&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 616px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8423413918a55146f8840cee364a1c40/40040/4.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 55.21472392638037%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAABcklEQVQoz42S2Y7CMAxF+f9fq9QHllIKpSt7C3QFCsWjYykZaZ4m0pUTx/v1pG1bqapKLpeL7HY7yfNckiSR0+kkWZZJmqYSx7HqxnGU7/drwdvoOMgJF4IFQWAdt9uthGGoCTabjURRpP/okOiwISE+gMI4GrAoClWWZSmv10u6rpO+72UYBnk+n4qmaVSPI+CNDX+8uduAKKiG1sH9ftfA3HGs61r+c2zLOOz3exvser1qRkZxu90UVEc1SJIBOni/33pH2oA4H49HOZ/PChOIGaE/HA46EgiiE/TYoQeM6vF4/LbM53K5VAckA1+tVgpIQK7XayWDgLyxYSOm06kSSREwrgHJ6DiOOs9mMzWaz+fi+75lFPDGZrFYiOd5tgBTPa1rQGZG6ewe2WjzL+sQx6y5Gxh2P5+PJUYDQojruprZ7BkZCW52Ez3VsIu8+aczdpSCKIY5akCyMRuUVMcHjMEcTAKqMBLwx8yMDZ0wwx/I/T11gw6JjAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;code_challenge&quot;
        title=&quot;code_challenge&quot;
        src=&quot;/static/8423413918a55146f8840cee364a1c40/40040/4.png&quot;
        srcset=&quot;/static/8423413918a55146f8840cee364a1c40/222b7/4.png 163w,
/static/8423413918a55146f8840cee364a1c40/ff46a/4.png 325w,
/static/8423413918a55146f8840cee364a1c40/40040/4.png 616w&quot;
        sizes=&quot;(max-width: 616px) 100vw, 616px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;&lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 의 표준&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 생성했다면 이를 기반으로 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 를 생성해야 합니다. &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 를 생성하는 방법은 크게 두 가지가 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Plain&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 그대로 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;S256&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 SHA-256 해시한 후, Base64URL 인코딩을 적용합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;1번의 경우에는 PKCE 적용을 하는 의미가 사실상 없기 때문에, 2번의 방법을 사용하여 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 를 생성하는 것이 일반적입니다. 따라서 이번 예제에서도 &lt;code class=&quot;language-text&quot;&gt;S256&lt;/code&gt; 방식을 사용하여 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 를 생성하려고 합니다. 그런데 웹 환경에서 SHA-256 해시는 어떻게 적용할 수 있을까요?&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ffd70804bfd6dd0c1de4c399a4746882/5b4a1/5.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAACg0lEQVQ4y3WUa2/TMBSG+/9/D3xCIARsfGFUYmzQLk2T5p7m7ti550H26NgQJHrk1+c4zmvHJxshBI7j4HkerusSxzFJkpDnudFRFBm01jHf9wnCgKIsWfW9vmRTVRWfPn7i+uqKmy83bL9ueff2LXff79jefOX1q9cmd/vt1uSvrz/z+eoaxz7yr2uzsNIxIOcOOXWIUdKOyvR7JnpGRmbTH5gZGKinlmKSVDInVzWprKl7wbIubOSouEv3bK1vhjtvx61zz723w29ivCbCq0P8JsIXCVa6482PD7z3f2Adv7CNfvLR23NqAqZlZjMtC8M8Ma6LYdD9ZTb08/SCYX6Mj8vCOOv8/BjTeppY9B6m7crWG9jZCT/thJ1zxvIKHk45dlDx4OYcvNLovZs9cfBLnLAx8WPYkNQL8wKbuluJq5G9k7B3U3bHmGNYkkvIxErWruTtSlrPxOVgSKqRczO/IBN6Qv2VuxU3G4lzSVJ2xIUiLXviXBkd5dKQi4lKrZTywvKS9veEhYJDNhOkgjBT+Gn72CY1QdrgBAV2UJDWE1UHhYRS/WmfY5Y8TROiqamrCiUlrRBIKWmUdjTTqoG2bWmahrppEKJFn91WSnRRNEI8tcuysFFK4ToOlhtiRxVuUhGGIfYpxAnOnPwI3/NMJV3QFRUGgdGn08lUWlmWjwe7rmsT2Fs29/sDB+fEw4PF8WjjHG1s+4BlWWaMLsHz+WxKM01Toy9oY2bCeZ7olEIpSd8ps+yu68yAC+L3Nugl/e96quW+7wmihCwvjAP9do3W2oXW2oH+MehlFUVh9AWdu8TNHo7jSFRIslKQ55lJZllmBmitH9COn7v4m+cOfwHkzHABSi2jbgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;S256&quot;
        title=&quot;S256&quot;
        src=&quot;/static/ffd70804bfd6dd0c1de4c399a4746882/a6d36/5.png&quot;
        srcset=&quot;/static/ffd70804bfd6dd0c1de4c399a4746882/222b7/5.png 163w,
/static/ffd70804bfd6dd0c1de4c399a4746882/ff46a/5.png 325w,
/static/ffd70804bfd6dd0c1de4c399a4746882/a6d36/5.png 650w,
/static/ffd70804bfd6dd0c1de4c399a4746882/5b4a1/5.png 831w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;JavaScript에서 SHA-256 해시를 적용할 수 있는 네이티브 메서드&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;바로 JavaScript 에서는 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;crypto.subtle.digest()&lt;/code&gt;&lt;/a&gt; 메서드를 사용하여 SHA-256 해시를 생성할 수 있습니다. 이 메서드는 비동기적으로 동작하므로, &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; 와 &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; 구문을 사용하여 처리해야 하며, HTTPS 환경에서만 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;이렇게 나온 해시를 다시 Base64URL 인코딩하면 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 가 생성됩니다. 이를 TypeScript 로 구현한 코드는 다음과 같습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// code_challenge 생성 함수&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; generateCodeChallenge &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;codeVerifier&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// TextEncoder는 문자열을 Uint8Array로 인코딩하는 데 사용&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; encoder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TextEncoder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// code_verifier를 Uint8Array로 변환&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; encodedCodeVerifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; encoder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;codeVerifier&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Uint8Array 데이터를 SHA-256 알고리즘으로 해싱, 반환값은 Promise&amp;lt;ArrayBuffer&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; hashedCodeVerifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;crypto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subtle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;digest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;SHA-256&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    encodedCodeVerifier
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// ArrayBuffer로 변환된 해시 값을 Uint8Array로 변환&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bytes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hashedCodeVerifier&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Base64URL 인코딩을 적용하여 code_challenge 생성&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; codeChallenge &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getBase64UrlEncoded&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bytes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; codeChallenge&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;code-classlanguage-textcode_verifiercode-를-저장&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code-classlanguage-textcode_verifiercode-%EB%A5%BC-%EC%A0%80%EC%9E%A5&quot; aria-label=&quot;code classlanguage textcode_verifiercode 를 저장 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 저장&lt;/h3&gt;
&lt;p&gt;PKCE 흐름에서는 클라이언트로 리다이렉트가 된 후, 최종적으로 액세스 토큰을 요청할 때 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 사용해야 합니다. 따라서 이 값을 리다이렉트 페이지에서도 접근할 수 있게 저장해두는 것이 중요합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;code_verifier&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; codeVerifier&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이를 위해서는 로컬 스토리지나 세션 스토리지 등을 활용할 수 있겠죠.&lt;/p&gt;
&lt;h3 id=&quot;인증-서버에-요청-전송&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%9D%B8%EC%A6%9D-%EC%84%9C%EB%B2%84%EC%97%90-%EC%9A%94%EC%B2%AD-%EC%A0%84%EC%86%A1&quot; aria-label=&quot;인증 서버에 요청 전송 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;인증 서버에 요청 전송&lt;/h3&gt;
&lt;p&gt;이제 생성된 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 를 포함하여 사용자를 페이스북 인증 페이지로 보내야 할 차례입니다. &lt;a href=&quot;https://developers.facebook.com/docs/facebook-login/guides/advanced/oidc-token/&quot;&gt;공식 문서에서 제공하고 있는 파라미터&lt;/a&gt;를 참고하여 아래와 같은 URL을 구성하고, 사용자를 해당 URL로 리다이렉트합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://www.facebook.com/v11.0/dialog/oauth?&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;client_id=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;FACEBOOK_APP_ID&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 필수값, 페이스북 개발자 센터에서 발급받은 앱 ID&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;scope=openid&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 필수값, OIDC with PKCE 에서는 반드시 openid로 설정 필요&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;response_type=code&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 필수값, OIDC with PKCE 에서는 위해서 반드시 code로 설정 필요&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;redirect_uri=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;FACEBOOK_REDIRECT_URI&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 필수값, 페이스북 앱 생성시 설정한 URI&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;code_challenge=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;codeChallenge&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 필수값, 위의 코드로 생성한 code_challenge 값&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;code_challenge_method=S256&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 권장값, code_challenge의 해싱 방법으로 여기서는 S256을 사용, 기본값은 plain&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;state=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;state&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 권장값, CSRF 공격을 방지하기 위한 임의의 문자열&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;nonce=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;nonce&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 필수값, OIDC에서 ID 토큰의 재생 공격을 방지하기 위한 임의의 문자열&lt;/span&gt;

router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://auth.wiki/ko/id-token#id-%ED%86%A0%ED%81%B0-%EA%B2%80%EC%A6%9D&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;nonce&lt;/code&gt;&lt;/a&gt; 는 ID 토큰의 위조 및 재사용을 방지하기 위해, &lt;a href=&quot;https://auth.wiki/ko/authorization-code-flow#state%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-csrf-%EA%B3%B5%EA%B2%A9-%EB%B0%A9%EC%A7%80&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt;&lt;/a&gt; 는 인증 요청에 대한 응답의 무결성과 &lt;a href=&quot;https://namu.wiki/w/CSRF&quot;&gt;CSRF&lt;/a&gt; 공격을 방지하기 위해 클라이언트가 검증해야 하는 값입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 URL을 통해 사용자는 페이스북의 로그인 페이지로 리다이렉트됩니다. 그러면 버튼 클릭 시 위와 같이 페이스북의 인증 페이지로 리다이렉트가 됩니다. 사용자는 페이스북 계정으로 로그인하고, 애플리케이션에 권한을 부여하는 과정을 거치게 되죠.&lt;/p&gt;
&lt;p&gt;
            &lt;img src=&apos;/fc1ebed0cd8227d479cc52c46adb5b27/11.gif&apos; alt=&apos;로그인&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;페이스북 로그인 버튼 클릭 시 인증 요청을 보내는 모습&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;최종적으로 페이스북 로그인 버튼 클릭 시 실행할 함수는 다음과 같은 형태로 작성할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleFacebookLogin&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; codeVerifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateCodeVerifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; codeChallenge &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateCodeChallenge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;codeVerifier&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateRandomString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// CSRF 공격 방지를 위한 임의의 문자열 생성&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; nonce &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateRandomString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ID 토큰의 재생 공격 방지를 위한 임의의 문자열 생성&lt;/span&gt;

  localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;code_verifier&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; codeVerifier&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// code_verifier를 로컬 스토리지에 저장&lt;/span&gt;
  localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;state&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// state를 로컬 스토리지에 저장&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 위에서 작성한 URL&lt;/span&gt;
  router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;리다이렉트-uri에서-액세스-토큰-획득&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%A6%AC%EB%8B%A4%EC%9D%B4%EB%A0%89%ED%8A%B8-uri%EC%97%90%EC%84%9C-%EC%95%A1%EC%84%B8%EC%8A%A4-%ED%86%A0%ED%81%B0-%ED%9A%8D%EB%93%9D&quot; aria-label=&quot;리다이렉트 uri에서 액세스 토큰 획득 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;리다이렉트 URI에서 액세스 토큰 획득&lt;/h3&gt;
&lt;p&gt;사용자가 성공적으로 인증을 마치면, 페이스북은 지정된 &lt;code class=&quot;language-text&quot;&gt;redirect_uri&lt;/code&gt; 로 사용자를 리다이렉트 시킵니다. 이때 URL의 쿼리 파라미터로 &lt;code class=&quot;language-text&quot;&gt;code&lt;/code&gt; 와 &lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt; 가 포함되는데요, &lt;code class=&quot;language-text&quot;&gt;code&lt;/code&gt; 에는 ID 토큰을 요청할 수 있는 권한 코드가 담겨 있고, &lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt; 는 CSRF 공격을 방지하기 위해 사용됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;plaintext&quot;&gt;&lt;pre class=&quot;language-plaintext&quot;&gt;&lt;code class=&quot;language-plaintext&quot;&gt;https://localhost:3000/callback?code={code}&amp;amp;state={state}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;여기서 클라이언트는 CSRF 공격을 방지하기 위해, 2단계에서 생성한 &lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt; 값을 먼저 검증해야 합니다. 요청에 보낸 &lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt; 값과 콜백 URI에 포함된 &lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt; 값을 비교하여 일치하는지 확인하는 과정을 거칩니다. 만약 일치하지 않는다면 CSRF 공격이 의심되므로, 인증 과정을 중단하고 에러를 발생시킵니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// callback.tsx&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;state&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Invalid state parameter&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// CSRF 공격 방지를 위한 검증&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그 후, 획득한 &lt;code class=&quot;language-text&quot;&gt;code&lt;/code&gt;와 함께 숨겨두었던 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 사용하여 최종적으로 액세스 토큰을 교환하는 API 를 호출합니다.&lt;/p&gt;
&lt;p&gt;페이스북 서버는 전달받은 &lt;code class=&quot;language-text&quot;&gt;code_verifier&lt;/code&gt; 를 해싱한 후, 저장해두었던 &lt;code class=&quot;language-text&quot;&gt;code_challenge&lt;/code&gt; 와 비교합니다. 값이 일치하면, 인증된 클라이언트라고 판단하고 액세스 토큰과 ID 토큰 등이 포함된 JSON 응답을 반환합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// callback.tsx&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; codeVerifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;code_verifier&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://graph.facebook.com/v11.0/oauth/access_token?&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;client_id=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;FACEBOOK_APP_ID&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 페이스북 개발자 센터에서 발급받은 앱 ID&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;redirect_uri=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;FACEBOOK_REDIRECT_URI&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 페이스북 앱 생성 시 설정한 URI&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;code_verifier=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;codeVerifier&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 페이스북 로그인 요청 시 생성한 code_verifier&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;code=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;code&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 페이스북 로그인 후 리다이렉트된 URI에서 추출한 code&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// {&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   &quot;access_token&quot;: string // 페이스북 API에 접근할 수 있는 액세스 토큰&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   &quot;expires_in&quot;: number // 토큰의 유효 기간 (초 단위)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   &quot;id_token&quot;: string // JWT 형식의 ID 토큰, 사용자의 인증 정보를 포함&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//   &quot;token_type&quot;: &quot;bearer&quot; // 토큰의 유형, 일반적으로 &quot;bearer&quot;로 설정됨&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// }&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; accessToken &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;access_token&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 액세스 토큰을 획득!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;
            &lt;img src=&apos;/2bbce8300b8d65ac4cce3d428d3ad57c/12.gif&apos; alt=&apos;성공&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;페이스북 인증 후 PKCE를 거쳐 액세스 토큰을 획득하는 모습&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이로써 모든 인증 과정이 안전하게 완료되며, 획득한 액세스 토큰으로 페이스북 API를 호출하거나, &lt;code class=&quot;language-text&quot;&gt;id_token&lt;/code&gt;을 활용해 사용자 정보를 확인하여 자체 로그인 처리를 할 수 있게 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;마무리&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%A7%88%EB%AC%B4%EB%A6%AC&quot; aria-label=&quot;마무리 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;마무리&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExdHk0cmZ5OGM0NWw3MThwaDlwNThhY2R3cW15Y2s2aGU0YTZqYWVvZCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/UqB9KRApovhliUMnSu/giphy.gif&apos; alt=&apos;소셜 로그인&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;이제 다른 서비스의 소셜 로그인을 붙이는 것도 수월하겠지?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이렇게 해서 PKCE가 적용된 OIDC 인증 과정을 페이스북 로그인 구현을 통해 살펴보았습니다.&lt;/p&gt;
&lt;p&gt;저도 이 글을 정리하면서 단순히 &lt;em&gt;소셜 로그인&lt;/em&gt; 으로만 알고 있었던 개념들 속에 숨겨진 여러 보안 메커니즘을 이해하게 되었습니다. 그리고 이러한 보안 메커니즘이 도입된 이유와 그 배경에 있는 고민들을 이해하게 되니, 단순히 기능을 구현하는 것을 넘어 보안 원리를 이해하고 적용하는 것이 얼마나 중요한지 깨닫게 되었습니다.&lt;/p&gt;
&lt;p&gt;처음에는 저도 낯선 용어들을 마주치며 막막함을 느꼈지만, 하나씩 개념을 정리하고 실제로 코드를 작성해보면서 베일에 싸여 있던 OAuth 2.0, OIDC, PKCE의 개념이 점차 명확해졌습니다.&lt;/p&gt;
&lt;p&gt;이제는 누군가 제게 소셜 로그인 구현에 대해 묻는다면, 좀 더 자신 있게 안전한 방향을 제시할 수 있을 것 같더라구요.&lt;/p&gt;
&lt;h2 id=&quot;참고-자료&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C&quot; aria-label=&quot;참고 자료 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;참고 자료&lt;/h2&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ibm.com/kr-ko/think/topics/oauth&quot;&gt;OAuth(오픈 인증)란 무엇인가요?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://auth.wiki/ko/oauth-2.0&quot;&gt;OAuth 2.0은(는) 무엇인가요?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[AI와 함께하는 글쓰기 토너먼트 대회, 글드컵 진행 후기]]></title><description><![CDATA[아이디어부터 실행에 이르기까지, 글쓰기 토너먼트 대회의 기획과 진행을 AI와 함께 한 후기를 공유합니다.]]></description><link>https://wormwlrm.github.io/2025/06/29/Planning-Event-for-Writing-Competition-with-AI.html</link><guid isPermaLink="false">https://wormwlrm.github.io/2025/06/29/Planning-Event-for-Writing-Competition-with-AI.html</guid><pubDate>Sun, 29 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;지난달, 글 쓰는 개발자 커뮤니티 글또 10기의 성공적인 마무리를 기념하며 색다르고 재미있는 이벤트를 개최했습니다. 바로 글쓰기 토너먼트 대회, &lt;strong&gt;글드컵&lt;/strong&gt; 입니다.&lt;/p&gt;
&lt;p&gt;글드컵은 &lt;em&gt;‘글또 제출글 월드컵’&lt;/em&gt; 의 줄임말로, 글또 10기 활동 기간 동안 참여자들이 작성한 글 중 최고의 글을 가려내는 토너먼트 대결 이벤트입니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/107469b09b2c592b00509600bd581a7a/71c1d/0.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.87116564417178%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAADFElEQVQozx2S7U8TdwDH709atmx7MV8oiwwLHPfwu9899CgkNUAZZC+WabZBGoRlTgMITkHLGOrGDIo4ipT2KC2spV7v2ruzNwuCbvGxm7oH4B56tZ7Bd9/kk0/yefFFsrOw7wt0qA8M9lGne8n+Yw3f9RDDfVT/cfTsAL4rQjsHzSxlK6xzhy9r3h2RqmhMRaUNESCXh3APxrV3Blhfq7+tw4Pi/vYASXsbSY5l8f8y0JZpU2Z3Rfha914brm0jPgwGDjwUiLJEIo8T9NIEujTREAnVC1NY/AqITaKxSU/sB09+DpgStGWqnCPMLO4WqMSP2Ozw0QD18fTpw+62D3EU2i0wrs5WVVjVoKszeyL1LN1eWg/8te63JPB3it4S/A+SnaX11o2bxNPIl9Lltu1woyMDxJTpnQzYyQBLgru3qXIOFGP+hDATWZhevTVq3G4sCp1C5JflpRl1+aQ2f2RkpHlglL8xR1YUZl+287SRY+4vos9TwC1y24m2xZvj89fH7mYmdtL1Wytdv14bW5gLFdcG56cOn5nCv/+ZPDHSsLmAIlaOcRQ43nuIPPhuN/fR8xS4F22NR69qOaEoT++KTRvx7pXojJ4XtLWR+1HPyxRVSpDTgzVbiyhi5+D/Gaql4YMOUHMxyD5aoV6kYTHeXRS6NpdaDJF4meZuXO06Ndndf9HXGwI9IdAbIo+PEelbAHFU5uEyTte+d/2UdzP82R8x4nUB2nlgipijQkumy3n4z2/on9H6UgqU1sCTFezZKvk0Sf6bIhB3g0tO1NW9/86xT5sfCC3VArMZbrJk1tF4W+UNERgSdFSvo7C2TNsyrChsRaErCmPlaMTSmDPDTI2v48jngwNDgdW5xpPf1G4naVdvtlXOlPbvZWQpS4aOwpgStSdSRhYaEjREErkXh1+N4sFxGDyHfX0WC57Des7jkVng6ryteg0R7GWpqgLXf/rkwsDBu+GmVwptSLQl02aWQl4VePd33i1wrv526Lyre6sF3tF4R+WM7H62W2CSl+omvz2khzF3w2er3n16h38DyRnjrCUVlDoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;콘셉트&quot;
        title=&quot;콘셉트&quot;
        src=&quot;/static/107469b09b2c592b00509600bd581a7a/a6d36/0.png&quot;
        srcset=&quot;/static/107469b09b2c592b00509600bd581a7a/222b7/0.png 163w,
/static/107469b09b2c592b00509600bd581a7a/ff46a/0.png 325w,
/static/107469b09b2c592b00509600bd581a7a/a6d36/0.png 650w,
/static/107469b09b2c592b00509600bd581a7a/e548f/0.png 975w,
/static/107469b09b2c592b00509600bd581a7a/3c492/0.png 1300w,
/static/107469b09b2c592b00509600bd581a7a/71c1d/0.png 1536w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;‘포켓몬스터의 대전 마냥, 글쓰기로 배틀을 해본다면 어떨까?’ 라는 아이디어로 시작하게 된 행사&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;‘글쓰기로 모인 사람들인 만큼 글쓰기로 배틀을 한다면 어떨까?’&lt;/em&gt; 라는 참신한 아이디어에서 시작된 이 행사는 총 한 달의 준비 기간을 거쳐 약 70여 명의 참여자와 함께 기술 및 비기술 분야별 우승자를 가려냈습니다. 특히, 글쓰기 배틀이라는 독특한 아이디어에 &lt;strong&gt;AI가 심판으로 참여했다는 점&lt;/strong&gt; 덕분에 많은 분들이 흥미를 느끼고 뜨거운 반응을 보내주셨습니다.&lt;/p&gt;
&lt;p&gt;글쓰기 토너먼트 대회라는 새로운 형식의 행사를 통해 글또 참여자분들에게 즐거운 경험을 선사하고, 제가 애정하는 커뮤니티의 마무리를 장식하는 행사가 되었다는 점에서 글드컵은 저에게도 특별한 행사로 기억될 것 같습니다.&lt;/p&gt;
&lt;p&gt;이번 행사는 단순히 글또 10기의 마무리를 넘어 &lt;strong&gt;AI를 적극적으로 활용하여 기획하고 운영한 이벤트&lt;/strong&gt;라는 점에서 저에게 더 의미 있는 경험이었습니다. 포스터 제작부터 홍보 문구 작성, 대진표 구성, 그리고 행사의 핵심인 평가 프롬프트 작성에 이르기까지, 거의 모든 과정에서 AI의 손길이 닿지 않은 곳이 없었죠. AI와 함께 행사를 성공적으로 이끌며, 우리 일상과 업무에 AI를 어떻게 실용적으로 접목할 수 있는지에 대한 새로운 통찰을 얻을 수 있었습니다.&lt;/p&gt;
&lt;p&gt;그래서 오늘은 글드컵이라는 행사를 기획하고 준비하는 과정과 함께, 이 과정에서 AI를 어떻게 효과적으로 활용했는지 그 노하우를 자세히 공유하고자 합니다. 이번 글이 &lt;strong&gt;AI를 활용한 행사 기획과 운영에 대한 통찰을 얻고 싶은 분&lt;/strong&gt; 또는 &lt;strong&gt;행사 기획 및 운영에 AI를 접목하는 방법을 궁금해하는 분&lt;/strong&gt;들께 도움이 되기를 바랍니다.&lt;/p&gt;
&lt;h2 id=&quot;글드컵이란&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%93%9C%EC%BB%B5%EC%9D%B4%EB%9E%80&quot; aria-label=&quot;글드컵이란 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글드컵이란&lt;/h2&gt;
&lt;p&gt;아무래도 진행한 대회에 대한 소개가 필요할 것 같아서, 글드컵이 무엇인지부터 간단히 소개해 드리겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;글드컵&lt;/strong&gt;은 &lt;strong&gt;글또 10기 활동 기간 중 제출된 글을 대상으로 최고의 글을 가려내는 토너먼트 대결 이벤트&lt;/strong&gt;입니다. 참여자들은 본인이 쓴 글 중 하나를 선택해 토너먼트에 참가하고, 대진표에 따라 AI가 심판 역할을 맡아 글을 평가하는 방식으로 진행됐습니다. 글 평가는 기존 큐레이션 크루가 활용했던 다음 네 가지 지표를 AI에게 전달해서 진행했습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;글의 구조적 완성도&lt;/strong&gt;: 논리적인 흐름과 짜임새 있는 구성을 평가&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;내용의 독창성과 전문성&lt;/strong&gt;: 주제의 참신함과 내용의 깊이를 평가&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;가독성과 표현력&lt;/strong&gt;: 문장의 명확성, 이해하기 쉬운 표현력을 평가&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;독자 친화성&lt;/strong&gt;: 독자의 흥미를 유발하고 공감을 이끌어내는 정도를 평가&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 기준에 따라 AI는 각 글을 객관적이고 일관적으로 평가했으며, 더 높은 점수를 받은 글이 다음 라운드로 진출하는 토너먼트 방식으로 최종 우승작을 가려냈습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;기술 토너먼트:&lt;/strong&gt; 특정 기술, 개발 방법론, 아키텍처 등 기술적인 내용을 깊이 다루는 글&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비기술 토너먼트:&lt;/strong&gt; 글쓰기 경험, 회고, 커리어, 학습 방법, 커뮤니티 활동 등 비기술적인 경험이나 생각을 공유하는 글&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;글드컵 토너먼트는 제출 글의 성격을 고려해 크게 두 개의 대회로 나뉘었습니다. 참가자들은 본인이 쓴 글 중 하나를 골라 &lt;strong&gt;기술 토너먼트&lt;/strong&gt;나 &lt;strong&gt;비기술 토너먼트&lt;/strong&gt; 중 한 분야에만 지원할 수 있습니다. 이는 아무래도 특정 기술의 동작 원리를 깊게 다룬 글과 개인적인 회고 글을 똑같은 기준으로 평가하는 것이 어렵다고 판단했기 때문입니다.&lt;/p&gt;
&lt;h3 id=&quot;탄생-배경&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%83%84%EC%83%9D-%EB%B0%B0%EA%B2%BD&quot; aria-label=&quot;탄생 배경 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;탄생 배경&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/043dada1ba47e46bc321be00ebbaec3e/65c7b/9.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 60.73619631901841%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAABx0lEQVQoz42Su24aURCGeQQ6hN0DyRZeJIoY5z0oKBEVokEgBI9CHURjITpbltLQRBFdCm9grwYCCntBsIAX2OWPzjhrsUQ4PtKcmTnSfHM7oS93Pdw+fMevoQrLmmO9XmO322G73b5q9jabzeB5Htg5HA7/iP8ekmURgvAITdMgSxJURYUkSuSLoghFUaDregB47hDQd6bTKcajMenhcIjRaERQZk8mE8zn81ewYRgkpmmSHFceYtd+v4eqqhAEAYPBAP1+n6rzRVM1SsDAlmXBdV14rveiPS/YMjMcx6HKqKq/wSwBq2q1WtEM16uX2TLIf1tmg99sNlSpu3cpAcvsL4a9MzkOPLsUZnS7XWSzWVSrVdRqNTQaDeTzeVQqFdTrdRSLRbRaLQryWzwFBYDNZhORSAQcxyEejyOTySAcDpOfTCYRjUZRKpUCwNNWA8B2uw2e55FKpQiQy+UQi8WQSCQIenlxgXK5/H5gp9PBR44jIM9foVAo4Dp9g0/XaaRvPiOe+ECjeDfQXi4g9gWIsozfuoXlcgHDYH/MgmGa9Ods2w4s5E3g05OCrw/3+NmT8O2HBN3ewbAdOM8b2jTb+mnwOeAfiNFT6Uzged0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;새벽&quot;
        title=&quot;새벽&quot;
        src=&quot;/static/043dada1ba47e46bc321be00ebbaec3e/a6d36/9.png&quot;
        srcset=&quot;/static/043dada1ba47e46bc321be00ebbaec3e/222b7/9.png 163w,
/static/043dada1ba47e46bc321be00ebbaec3e/ff46a/9.png 325w,
/static/043dada1ba47e46bc321be00ebbaec3e/a6d36/9.png 650w,
/static/043dada1ba47e46bc321be00ebbaec3e/65c7b/9.png 795w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;새벽에 떠오른 뻘생각… 역시 새벽 감성이어야 새로운 아이디어가 샘솟는다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글드컵은 3월 2일 새벽에 문득 떠오른 아이디어에서부터 시작되었습니다. 그날은 &lt;a href=&quot;/2025/03/02/Viewport-Resize-Behavior.html&quot;&gt;『안드로이드 크롬에서 CSS vh 단위가 이상하게 동작했던 이유』&lt;/a&gt; 포스트를 제출하기 위해 밤을 새고 있던 날이었죠.&lt;/p&gt;
&lt;p&gt;아침이 되고 나서야 글을 완성하고 잠자리에 들려는데, 불현듯 &lt;em&gt;‘포켓몬스터 대전처럼 글또에서 대결의 요소가 있는 행사를 해 볼만한 게 있을까?’&lt;/em&gt; 하는 생각이 들었습니다. 내가 수집한 포켓몬을 필드에 내보내서 상대방의 포켓몬과 대결하는 것이 포켓몬 배틀의 흥미로운 요소인데, 이를 &lt;em&gt;‘글또 10기 내에서 작성한 글을 각자 하나씩 골라 상대방과 대결을 붙여보는 것도 재밌겠다’&lt;/em&gt; 는 생각이 들더라구요.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a9aee2ceb4d1aeff6c2d7fc9f73670e2/2215f/6.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 92.02453987730061%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB1UlEQVQ4y32Uaa7CMAyEcxEo+1oo+05Z1AoQ9z+Pnz5Lg6IK3o/BceKMx3ZDaDabVkWSJJamqeV5bufz2e31ev3gdDrZ4XDwdVEUfj6fz208Hlv4RTidTq0sS7vf73a5XJxE5PhY7a3Xa8uy7H/CyWTiF4/Ho1+YzWa2WCxsuVy6FVCm9Wg0+k1Ixvf7bc/n016vlz0eDy8RxQI+Sm+3m6t1wkaj4QQx6vW6dTodL1ugnF6vZ91u9wP8wWBg/X7fhsOh7wV+GAAbgCwAAoJZs88loHPukLRWq7kA2dBqtWy323lzmdx2u7XVauUWcIZPH+kfPdtsNh6Lj3raw5rEQRPlspqP5RJBAqSA5nOmhCRQ6Sj2oUC43++dSGpEqiSoII61LKB0vgi1xodCv/g8pAASLGVJAf1DhYagPQEyVwghmRg7KikDIhLg00NIUYUFKAKoBqzZJ5kPhUlrgqiNpw04b7fbRiwWJfJpmdaIC/QANSjBag1QjY9iPTshjsXyquAKyIyHoD7SBpVYnX78GbHWhFEaKJU+cFHfGUGx5VzvFSLaQKmUqbIp10uGlQAcvWUFxhdkBREI2v88vfiNfrvwiyBO4IQojL8r+qGJffsnqhJU8QfoDSQd+Ra++wAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;글쓰기 대결&quot;
        title=&quot;글쓰기 대결&quot;
        src=&quot;/static/a9aee2ceb4d1aeff6c2d7fc9f73670e2/a6d36/6.png&quot;
        srcset=&quot;/static/a9aee2ceb4d1aeff6c2d7fc9f73670e2/222b7/6.png 163w,
/static/a9aee2ceb4d1aeff6c2d7fc9f73670e2/ff46a/6.png 325w,
/static/a9aee2ceb4d1aeff6c2d7fc9f73670e2/a6d36/6.png 650w,
/static/a9aee2ceb4d1aeff6c2d7fc9f73670e2/e548f/6.png 975w,
/static/a9aee2ceb4d1aeff6c2d7fc9f73670e2/3c492/6.png 1300w,
/static/a9aee2ceb4d1aeff6c2d7fc9f73670e2/2215f/6.png 1548w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;ChatGPT에게 처음 시켜봤던 글쓰기 대결의 결과&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;과연 이 아이디어가 현실에서 실현 가능할지 궁금했습니다. 그래서 바로 ChatGPT에게 두 개의 글 링크를 던져주고 더 잘 쓴 글을 골라달라고 요청했습니다. AI가 웹 크롤링을 원활하게 할 수 있어야 이 아이디어가 현실이 될 수 있었거든요.&lt;/p&gt;
&lt;p&gt;다행히(?) ChatGPT는 서로 다른 두 글을 비교해서 더 나은 글을 선정해 낼 수 있었습니다. 이로써 평가 프롬프트를 정교하게 다듬으면 글쓰기 배틀이라는 아이디어를 실현할 수 있겠다는 확신을 얻었습니다.&lt;/p&gt;
&lt;p&gt;이 아이디어를 운영진 채널에 공유했을 때의 반응은 뜨거웠습니다. 다만, 이 단순한 아이디어를 구체적인 행사로 만들기까지 얼마나 많은 기획과 준비가 필요할지는 미지수였기에, 본격적인 행사 준비는 글또 10기 활동 기간이 끝난 후 다시 논의해 보기로 했습니다.&lt;/p&gt;
&lt;p&gt;그렇게 시간이 흘러 글또 마지막 제출을 앞둔 날, 함께 이 아이디어를 진행해보고 싶은 분이 계신지 운영진 채널에 다시 물었습니다. 다행히 같은 큐레이션 운영진이었던 &lt;a href=&quot;https://heehehe-ds.tistory.com/&quot;&gt;희선&lt;/a&gt;님께서 흔쾌히 함께해 주시기로 했고, 그렇게 한 달간의 긴 여정이 시작되었습니다.&lt;/p&gt;
&lt;h2 id=&quot;준비하기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%A4%80%EB%B9%84%ED%95%98%EA%B8%B0&quot; aria-label=&quot;준비하기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;준비하기&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExMmkxM2JxM3E2NHJjMGJ6NmNmMW8zMzVuaThnM3VxcHdseXcycDZrMiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/1ziiQ8TVfLgeGWUOFx/giphy.gif&apos; alt=&apos;슥삭&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;자… 그럼 뭐부터 해볼까요?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;본격적으로 행사를 준비하려고 하니, 생각보다 많은 부분을 고민해야 했습니다. 어떤 AI 모델을 사용할지, 어떻게 참여자를 모집할지, 대진표는 어떻게 만들지 등등… 이 과정에서의 고민 과정을 공유합니다.&lt;/p&gt;
&lt;h3 id=&quot;ai-모델-선정&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ai-%EB%AA%A8%EB%8D%B8-%EC%84%A0%EC%A0%95&quot; aria-label=&quot;ai 모델 선정 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AI 모델 선정&lt;/h3&gt;
&lt;p&gt;글드컵 아이디어를 구체화하면서 가장 먼저 고민했던 건 &lt;strong&gt;어떤 AI 모델을 사용할지&lt;/strong&gt;였습니다. 단순히 두 글의 링크를 던져주고 승자만 알려주는 방식은 가장 간단했지만, 저희는 단순히 승패만을 알고 싶었던 게 아니었거든요.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/4cc8aab6003ceebec61a9877ae705443/6a6e9/10.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 87.11656441717791%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAAB70lEQVQ4y4WUWXKDQAxEc4nE+xJs8MZi9s127n8qpZ5ABMof+eiSRjP0SC0NH852LzfnKFGcSJYXEkZ3ObqeHI6ufDsHWa03/2K5WivwPywASZJmEoSR+H4gYRTJ5XrTQ4vlavgI39Zj33gGQu90lizPpaobzTQvSimrWqq6Vr/o10VZSdO0eq7q1/in80XJB0LXO0mcpBLHidzjRPwg1JKdw3EonyqA63m97w7yWPkTQvTzg0DLBjc/UMLPr5nM5gu1HeZqv2bzITZfLKclQ6illZWWFyeJappmuWpJSWTNJay5+Hy5agy98ScZomGaZgMJ2SIBl4w1BV280HMkwDcQTwjJoGkfSorIEJjw15uv4AwgG0CMRKzbbxrmWmqqN5IVdv/tqD5oiB3DYjZCfxquNyo+jbBsrCnjDmNtzfkxyHSz3U01LKtuppgztEKCx+MpreKheL5+dF03jTxfLz1Lk5BgQkjJiJz0jaF05pGYZU3G1ukxbArenp4Odq8hZJSNhjaHzB3W/DHQ8q0pNMJAgyDlInst5gN7NcT5drvbTwebzege65BigWV87/9EvPU/STo52OMhIMlASMsJIDiNqWlM22pT7AdRN62CprHPQHfrbo+mvD29SN9yOHnLWA5TAcJzDjAVWBty9tHwF6XH851YOiejAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;AI 모델&quot;
        title=&quot;AI 모델&quot;
        src=&quot;/static/4cc8aab6003ceebec61a9877ae705443/a6d36/10.png&quot;
        srcset=&quot;/static/4cc8aab6003ceebec61a9877ae705443/222b7/10.png 163w,
/static/4cc8aab6003ceebec61a9877ae705443/ff46a/10.png 325w,
/static/4cc8aab6003ceebec61a9877ae705443/a6d36/10.png 650w,
/static/4cc8aab6003ceebec61a9877ae705443/6a6e9/10.png 826w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;AI가 판단을 내리기까지의 과정을 듣고 싶다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;토너먼트 참가자들은 AI에게 평가받는 자신의 글이 상대방의 글과 비교했을 때 어떤 면에서 뛰어나고, 어떤 면에서 부족한지, 본인 글의 점수는 어떻게 매겨진 것인지 그 이유를 알고 싶을 것이라고 생각했습니다. 즉, 더욱 의미 있는 정보를 제공하려면 평가 과정을 알 수 있어야 합니다. 이는 곧 AI가 단계 별로 생각하는 과정을 보여줄 수 있는 모델, &lt;strong&gt;&lt;a href=&quot;https://modulabs.co.kr/blog/reasoning-model-ai&quot;&gt;추론 모델(reasoning model)&lt;/a&gt;&lt;/strong&gt; 이 필수적이라고 결론 내렸죠.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 560px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c9b2664c280c59fbfcbccacfc8d15897/b06ae/11.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 56.44171779141104%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAACbklEQVQozz2SzU/TcBzGe4eZMLbR9e332nYb2+jatVs3GAIeNCZGjNEYIjCj6InERNFED8ZEORjv/gOG4M2DIIgDiYjAQYUIQWUDxPAywM0EuZpO45PP4ZMnefK9fBk/jwRJFiQiSFQQKUAhRanXNDMQiASDmhZvstMt6abWuJU2E42NmTa78Wi6+VgsnuZ5yLAcwlQNBYPECaVqCCIMACSEuGt93Vd7J99OPR0YHBuf+Di/kC+srXxbLaz/aD/f5ap2Mz4WhKN6W2uraVqWZcUNw7ZThhFPWJbPx/Vev7m5sbGeX1laWiru7JR+7d8fvpffy2ez16qqapg6FkSienMmk0wmE1YiZafMuKnruh6L1bi9fX131sulganp34eH5VJ58eti/3D/ym6hs6vHGfv9MBQIJfSwFQsnjagRCaqUBFUlHArUeny3b919/PzVqYdPDg4Ot7Y2c7O5T/Oftja3L1zMVle7Gc4PFaW+QdOorFBZkWVFUVVKZYyJx8N2ZnuuPHh249Hgl+Xl2dm50bHRoZGh3PjEmXMdzphlQTSitWRSSVO3Td0yNCOmGXpMjzXU1XHdl3q+r62urRZ2trf3dvd+7u+XS6VisXj85GmXy8NwHCJYDiqEYokgQBAAkgQkCUPo8frPdlx+Pf7mxcuRqemZ3MTku/czC58X5z7Mt51oP+KqZXgOIqgQEhAlLIoO0j9BCMmY1kuQioBWHgFXQAKkIlS9Xp4RBWQ32Q161EqkKaUYIicQYoRkQmSMMcIIwkrzXxAEgGVF5zJGAQQVCGRRwKKABQ458JjnEO8I4nn4F44DFSDHQZ+P/wMn7cppQYPYjAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;클로드 포켓몬&quot;
        title=&quot;클로드 포켓몬&quot;
        src=&quot;/static/c9b2664c280c59fbfcbccacfc8d15897/b06ae/11.png&quot;
        srcset=&quot;/static/c9b2664c280c59fbfcbccacfc8d15897/222b7/11.png 163w,
/static/c9b2664c280c59fbfcbccacfc8d15897/ff46a/11.png 325w,
/static/c9b2664c280c59fbfcbccacfc8d15897/b06ae/11.png 560w&quot;
        sizes=&quot;(max-width: 560px) 100vw, 560px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;Claude가 포켓몬스터 게임을 플레이 중. 추론 모델 특성 상 판단을 내리기까지의 과정을 직접 볼 수 있다!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이러한 추론 모델에 대한 아이디어를 처음 접한 건 &lt;a href=&quot;https://www.twitch.tv/claudeplayspokemon&quot;&gt;트위치에서 Claude가 포켓몬스터 게임을 플레이하는 방송&lt;/a&gt;을 보면서였습니다. AI가 특정 논리적 과정을 거쳐 판단을 내리는 모습을 굉장히 흥미롭게 봤는데요, 이 기억이 떠올라서 우리 행사에도 적용할 수 있겠다는 영감을 얻었죠.&lt;/p&gt;
&lt;p&gt;그래서 추론 과정을 보여줄 수 있는 AI 모델들을 찾아보다가 Gemini가 눈에 들어왔습니다. Gemini의 제공 모델들을 살펴보니, Gemini 2.5 Flash와 Gemini 2.5 Pro에서 추론 과정을 확인할 수 있다는 것을 알게 되었죠. 마침 최근에 Gemini Advanced 무료 쿠폰을 받은 터라 이를 활용하기로 했습니다.&lt;/p&gt;
&lt;h3 id=&quot;아이데이션&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%95%84%EC%9D%B4%EB%8D%B0%EC%9D%B4%EC%85%98&quot; aria-label=&quot;아이데이션 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;아이데이션&lt;/h3&gt;
&lt;p&gt;AI 모델 선정까지 마친 후, 저는 희선님과 오프라인으로 만나 글드컵 아이디어를 구체적인 행사로 만들기 위한 이야기를 시작했습니다. 당시 정해진 것이라곤 &lt;em&gt;‘AI를 활용해 글또 10기 제출글로 토너먼트 대결을 진행한다’&lt;/em&gt; 는 큰틀 뿐이었죠.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/932ea1f8de9a36b4045c6610d2acb46f/38af3/15.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 31.901840490797547%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABD0lEQVQY012Q25KDIBBE8/+/l00iKGw0lhpXUZAUiJfeYlLJg/MyXQVzZrpPZ/7AhQkYPcIYA+895nlGCIG0cx6xftIC5wtD93xi6BUmrTFqjXVd6X3fd+qnyVpUVYUkSZCmKUQmkGUZhBCQUqKuaoLHwZe1KH9zFPKOPJPgnNPsEpYv9BTFMAy4Xa8EiZ+kkCjLEkopbNuGTznnaFlc/Hu/o21baGMQliNwHMB4CiEkQbuu+1qI/aMjPM9zWhrBZfGAav8QpheC89i37Q3smhY8uYCzBHVdU5bj+M70CG2aBowx8DSF5BmKG0df1pido1gIuPiAbfFYl4BjHS+MNqMD1SuKpO976MnAWktZ/wOVmsfb6AHr1AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;아이데이션&quot;
        title=&quot;아이데이션&quot;
        src=&quot;/static/932ea1f8de9a36b4045c6610d2acb46f/a6d36/15.png&quot;
        srcset=&quot;/static/932ea1f8de9a36b4045c6610d2acb46f/222b7/15.png 163w,
/static/932ea1f8de9a36b4045c6610d2acb46f/ff46a/15.png 325w,
/static/932ea1f8de9a36b4045c6610d2acb46f/a6d36/15.png 650w,
/static/932ea1f8de9a36b4045c6610d2acb46f/38af3/15.png 894w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;아이디어 회의 후 기록 정리&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;행사의 진행자가 단 두 명뿐이었기에, 최대한 리소스를 절약하자는 데 공통적으로 의견이 모였습니다. 이러한 기조 아래, 저희는 다음과 같은 핵심 항목들을 논의했습니다.&lt;/p&gt;
&lt;p&gt;가장 먼저 논의한 부분은 &lt;strong&gt;기술과 비기술 토너먼트의 구분 필요성&lt;/strong&gt;이었습니다. 글또는 글 쓰는 개발자 커뮤니티인 만큼 기술 관련 글이 많지만, 회고록이나 일상 글도 상당수 존재했죠. 이 두 유형의 글을 동일한 평가 기준에 따라 평가하면 형평성 문제가 발생할 수 있고, 결과에 대한 참가자들의 납득을 얻기 어려울 것이라고 판단했습니다. 그래서 기술과 비기술 토너먼트를 별도로 진행하기로 결정했습니다.&lt;/p&gt;
&lt;p&gt;다음은 &lt;strong&gt;참여자 모집 방식&lt;/strong&gt;이었습니다. 구글 폼을 활용해 참가자를 모집하되, 5월 초 연휴 전까지 마감을 목표로 했습니다. 그리고 진행자의 리소스를 고려하여 각 토너먼트별 최대 64명으로 인원을 제한했습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;대결 진행 방식&lt;/strong&gt;은 토너먼트 특성상 많은 수의 대결(&lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N - 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10903em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)이 발생하기에, 모든 대결을 실시간으로 할 수는 없었습니다. 이에 따라 대결은 미리 진행하고, 결과를 날짜별로 나누어 배포하기로 했습니다. 다만, 참가자들의 흥미를 더 끌기 위해 8강부터는 라이브 진행도 고려했죠.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;결과 공유 방식&lt;/strong&gt;의 경우, 인터랙티브한 전용 웹페이지 제작은 리소스 부담이 크다고 봤습니다. 그래서 간단하게 노션 페이지를 만들고, 대진 진행에 따라 결과를 수동으로 업데이트하는 방식을 택했습니다. 각 대진의 상세 결과는 별도의 페이지에서 확인 가능하게 했고요.&lt;/p&gt;
&lt;p&gt;마지막으로 &lt;strong&gt;대진표 제작&lt;/strong&gt;은 매일 업데이트가 필요하고 시각적으로도 잘 보여야 해서, &lt;a href=&quot;https://mermaid.js.org/&quot;&gt;Mermaid&lt;/a&gt; 로 코드를 작성하고 노션에 임베드하는 방식을 활용했습니다. 노션이 Mermaid를 지원했기에 가능했던 일이죠. 그리고 &lt;strong&gt;참여자 보상&lt;/strong&gt;은 전체 예산을 확보한 뒤 그 안에서 분배하기로 했습니다.&lt;/p&gt;
&lt;p&gt;이렇게 희선님과 함께 글드컵 진행의 큰 틀을 잡은 후, 세부적인 기획 방향을 고민하기 시작했습니다.&lt;/p&gt;
&lt;h3 id=&quot;포스터-제작&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%8F%AC%EC%8A%A4%ED%84%B0-%EC%A0%9C%EC%9E%91&quot; aria-label=&quot;포스터 제작 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;포스터 제작&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/04ce7f9691c441c0380a3a9e82bdb732/6976b/2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 65.03067484662577%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABYlAAAWJQFJUiTwAAADOElEQVQ4y32TWW8bBRSFR2JRKqAJNHFSxw5jOYmXiWfG9owdL/Uy9ngdr3GTNJuTVKJUakFifygFokpUKhLwwBv/gj8EbZFQ6iWbH6iUfEiR4AXElY7OvdI5R+flCk+fPefXp8/pDU/p9YcMBkN6wxMOByf0B0MGw2MOB8cMjo7pD48u797RKcOTM/qDY4bDo0vt4eCMPw77CG/MBkjnMtzabOKQEkxLaWJGlkq7xKSUQow3+bgbpJ7xMqkWEZNrrG1Y7Her2KIdHNE2mdVttu7d4YqvjPDahIOI9xrrOZEp0c+YXCKZUthcCXFFNplQK7QKHoKKyOveHHP5Ls1WipYVxZbdwWvd5e5+hQf3CsybewjCjMykU8Quioy9G2EqbpHK61jlIOOayexynYVwGGdAYVw2UWtd8paJUUzjqezQ2vuAO9tt3t+scLP7HsKsFMejhJE1HZeaIpYrYFk5rGqGUCpLut6h3ipRtgrEihbxcod0oUiqUCCYqZJp3KLSaWN12uhmHWHZrHDwcJ3vDtbI1lbQjRLZmkW2VmMpkWOjdpNvuwl+OSiyXW2ipnPkyzHMagJ/bJl57QYZM4lRyjAXCCMkGiv8/GWSnz7RKW9t41CS2Bd8ODwS0z6dh7d3uG94eLLq5evdVW7kbrBVk+jWA4TiIfREgvtthc/XQ+iagvCqv8yHuxE2awEmI03c4RROn8z1RQnHUoTHtzv8uGfww26Kx90GFUPjo5aTT1sOMnEfEV3ji5V5DjYXUXwLCI6widUqYFYN3LEKdp+OKOs4pDBTbplHO3Ue7Jp8tp3j0UaJaK5IKBZCX1bwxVJIsRyugMaCqmH3RxDcwWWsRoFyLY8UyzIvhclmExhGEpdHRtWTrLXyrDXzBCMJfnv2O3++fMnZaMTpaMRoNLrc/2YhHpL4fj/Ek65KIakxPuvBJyssBVXetLmYcStoWphoJMyUGLj8pP8bQfd7+GZD4qsNP2lN5ardg6p4CSpexq6J2N0KjWKMlXKUGdcShy96l8bz83MuLi7+BeEV2wLjjnnGpl1cdcm8Y3fzts3JxJSDtybnuC76aeQ1GkYQm3ORF73+P4H/1fAvGrkt4bOn2zAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;포스터 깎기&quot;
        title=&quot;포스터 깎기&quot;
        src=&quot;/static/04ce7f9691c441c0380a3a9e82bdb732/a6d36/2.png&quot;
        srcset=&quot;/static/04ce7f9691c441c0380a3a9e82bdb732/222b7/2.png 163w,
/static/04ce7f9691c441c0380a3a9e82bdb732/ff46a/2.png 325w,
/static/04ce7f9691c441c0380a3a9e82bdb732/a6d36/2.png 650w,
/static/04ce7f9691c441c0380a3a9e82bdb732/e548f/2.png 975w,
/static/04ce7f9691c441c0380a3a9e82bdb732/3c492/2.png 1300w,
/static/04ce7f9691c441c0380a3a9e82bdb732/6976b/2.png 2172w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;포스터 깎기의 흔적. 가장 힘든 것은 이미지 생성 완료까지 기다려야 했던 것…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;AI 모델 선정과 더불어, 행사의 얼굴이 될 포스터 제작에도 바로 착수했습니다. 포스터 제작에는 &lt;strong&gt;ChatGPT&lt;/strong&gt;를 활용했는데요. 당시 &lt;strong&gt;GPT-4o&lt;/strong&gt;의 이미지 생성 모델이 막 추가되어 지브리풍 이미지를 만드는 것이 유행이었거든요.&lt;/p&gt;
&lt;p&gt;저는 원하는 느낌과 분위기, 조명과 배경, 그리고 유사한 포스터 레퍼런스 등을 불렛 리스트 형태로 입력하며 이미지 수정 요청을 반복했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/91c853b295265554674a9fe2ebfa9324/31aff/12.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 80.98159509202453%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAAsTAAALEwEAmpwYAAABnklEQVQ4y32U6Q6CMBCEeRHvA0U0ingAKvHWxN+8/5us+TZZ0iD4Y1Pabqc7O1O88Xgsh8NB8jyXLMt0PB6P5chemqZlbLdbXSN3t9vJ6XSSxWIhnU5Her2eeNPpVFarlQyHQxmNRsIFBN/7/V4ul4vMZjNd832/zCP4Zn0wGChYCUi0223pdrtlMF+v13I+n7UiIggCrcTNs3kJaIu2YMEa9O73u1Z5u92Umnu4LjxujeP4JxFAKF+vV+0V4PP5XFqt1l9Qz0pn4n5DGcDn86mgXBpFkY60yFi59AmPpk4mkx/abEIRUHpJDkAIhBhNVTYCUiGCFEUhn89H3u+3BlbijF36A9jv99UO1Q2SwzBUmgS+S5JEg542VekBhg/d/pkoUH08HvJ6vVQU5uRyAT6s9l57aABUWq2QgwBCncqo2PVrYw8xLc12+2g+xH8Ig11cUzfahl7wdOpUpiJAl8ulvhJ7fi7dWmO7j9sFxMj4DhFQF9qw2Ww2/wFJ4vaqKPTQ/jamsr2aRpUBJBkqbpUks4eyFijMyOV17x/ALwyr2NV1VZj6AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;프롬프트&quot;
        title=&quot;프롬프트&quot;
        src=&quot;/static/91c853b295265554674a9fe2ebfa9324/a6d36/12.png&quot;
        srcset=&quot;/static/91c853b295265554674a9fe2ebfa9324/222b7/12.png 163w,
/static/91c853b295265554674a9fe2ebfa9324/ff46a/12.png 325w,
/static/91c853b295265554674a9fe2ebfa9324/a6d36/12.png 650w,
/static/91c853b295265554674a9fe2ebfa9324/31aff/12.png 823w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;포스터 제작을 위해 입력했던 프롬프트 키워드들&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;팁 하나를 드리자면, 이렇게 반복해서 요구사항을 수정할 때는 AI에게 현재까지의 요구사항을 다시 정리해 달라고 요청하면 훨씬 깔끔하게 프롬프트를 관리할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 480px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e28efacd7a85152689103dddba0470e4/e85cb/poster.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 150.30674846625766%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAIAAACjcKk8AAAACXBIWXMAAAsTAAALEwEAmpwYAAAFp0lEQVQ4y1WTSY8kRxXHX+SelZW15FK5b1WZlUtlVlVmVnVVdVd3Ty/Te49nejw0xj0abCHjhQNgbsY++GLLGiEkX3xDSD4gIWFO3DhY8gfwhQPigsSBA+ITcEFRjRBITxGpF/GL/z8j3gNgWsB2gJOAV0EwoOWCFEGvQM6SLq7p4gq5K9CmIMfQ9qFpQqOHN7MSpjakDLyCs6IFnQDkBPQp4e/y1VOuvCH8XQxLCV5qOSDom80K8PIGbqg4Jeio7UCrrw6mwWTV3zpx9m7Dw1tlfOyMll1/gh11NuKCBk3jHu5izbYHoo1HKaL0gnFqIT9tzG6F+S2fXzDuFmOXoCTQHWBYdKDtYr/YA69Cp7+JjedeQVhziB/tPH798vlbkD1G9gKMCnoFSENMdiPsn1cAG7hXVlPo9kEdgTam/B1Ibn7x8ydff/UJW90R3jbSp8goMdwN8c6mhf8UnyHaIFpIy5GcgDpCxhSFx718/cXb/X9++/LFe++AuSatChkVkmN8ipJg/ZYDeJIGeFRSyq4EMwOzppJzq598cC39/Y9vv/ODC3CPSHvGOlO6VxD2Fkghdt72NraVGN9kO3QDL44jsJfU6IpxFz+9Mv721WOnWEN8Dfb2ZJw8u5wjew5ShNRkoyzoqDtA+pSRvVij69RohqtONNdN6/0T8a+/f/rrl29MZlvgbD8/Cb98PxOsDHpjDIsmhqHl0EYeOKrW5Vr+NBiEhcX2JfjgjP3L7179158+/MlRww+HVlrfLNU3r2LGrfHTNE3AVSVaIEWCkzNqBOayp+sDhT4dcb/5kfbn377yj6/f+uiCP6ocsFdaP8urEno5rmKs3PbwV8sTvcL2A86IBbdwZXrLpz+77f7h0/KbX86/P6e9KAZz0dSjgavjUsGwBZurClDbPRjL7x51U7dF26WjNnoicRzTn79QX363s/KZpl8jrXixLVaxDmJItF1cUaCkSEmhG5qG/MaBsh2ynOoolqs2YWyS762Zyxi5tgHGcqcwP36qMFoMnRDJQ1ATrIyMMegTUh6s03bhsFTX4YK5qrQCCS1tFBpNzp+BXt2t2vPJANopoecYkULAz60khDMHa9bQB7weNYwI+WvGHo9t5lnFN70x+HudYGwEESg5MkvCmaH7JsFdrqSgFfRgl/R2wJw3rFTwS/AP55n2vSMfvAMmXPcGI8IoSW9J9degFbjD5CHgSctBnyCr5pIjJtonvFUj2qH761dX6q9+nMrZLpcec96MDvfZ+ABZ+OYwoqSA1BTpBZhTZM8IbyXkp2x20ujPNLl5llJf/ix7/YHJehVOZg8Jd4HMEhkTpOW4twh9RFlT2psx/RUb7vDJoZjuc82mwCFLZnZH8nbSFtuimD7ghnt0sKC8GWlNCT0ntBQoLWHMgrbHtFOx/pwPFqyREhRF06jbJAOVCXosx1GMkbDejHFK0ihoY0TpCalGQHUcout1nKTj5VJ/Irtxz3K6UluVW4Yqhk7XMzu2pfQsW/EzwRhKXkbLPtFxiJYFlKgBJZ+en737w7uL88Ozh+vLs52g7zx/7fy1Z6dv3l3dPNp/dLF7ery4PN97fvfk8upED2JoqKSgAiHIQHfiNF1t11VdJGk0jAJebI1GcV3ndT2q6zxOBnESOp6TF2lZFZrtAtsm+C4AI9CNVj7O8nGWjuJnNydPHh1fnu9/5+lpkg0Xi/LwweLwYLXeme2u56tVdfP4YTQMAWjENgEojmD4vEgn01GWJ3u7W9cXD6qqmJZ5Ps7CaDCdjIo8SbPhclnVdbE1n8ZJCEAhmgegWCBZkuZorkFzDUQyAFRbVpJ0OC3zdJS8cn3INltAsojiKZYHRAPBAMXhwPB9kHjE5yGmpxuLrXKxKNfr+cnDNSZpDmjunkH3JMX+D/yf1CZIlm2ITEOk+SYi/3/pvyTF/hsE890PGPaiUgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;포스터&quot;
        title=&quot;포스터&quot;
        src=&quot;/static/e28efacd7a85152689103dddba0470e4/e85cb/poster.png&quot;
        srcset=&quot;/static/e28efacd7a85152689103dddba0470e4/222b7/poster.png 163w,
/static/e28efacd7a85152689103dddba0470e4/ff46a/poster.png 325w,
/static/e28efacd7a85152689103dddba0470e4/e85cb/poster.png 480w&quot;
        sizes=&quot;(max-width: 480px) 100vw, 480px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;글드컵 포스터&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이렇게 약 13번의 수정 과정을 거쳐 위와 같은 최종 포스터를 완성했습니다. 개인적으로는 ChatGPT 를 이용해 생성한 이미지는 전체적으로 이미지 톤이 따뜻하고 부드러운 질감으로 표현되어 제가 원하는 분위기를 잘 살려냈습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/861a16704b529def8308d05348805339/dcccd/14.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 60.122699386503065%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAADQElEQVQozy2S60+bBRjFn7IhIKVcennb0vftzbZ0QAttN8rKZUA2yCLGySYqXhamQmWlXHSdMspljG3KNjbZLcuMkUAEN5lubNG4GBOjiYmRLxpj4v+gf8HPUPfhJCfnec75cHLk9z/+JDszz+nzi8wt3mL++gpzF24wNfcRi0vX2Xz0mInsh1y48gmPf9zi/MWbXLvxKRcXb3J7eYP73/7EzJnLTE4v8P0PPyPLq2uICCIGxFiNuNqRIhciOyk2u+h9NfnkbuaZhj5EX5XjIuUYfZ2YfPv/94qQHp9C7mzcR4ps6CwhLLVtDKSO8ZS3FTH40HY1MHn6MlqwnbxClQpPG/bwEUQcyA4nztgrFCtR8vVenNUHuHT1M2T9ywdIgRWDI4jZH2VhtBVHpA2b2485EGfm7BKJ7hQ7SgLYnbUM9B9iIrWfF3pf5vm+IWxamPzSXTR2p1m8toys3f0aKVIwan78ahnfLeyl79kwmteDt66Jo2+NUmhP4Iz0YFermB3r5t9f3+afvz8mOdSP6q3DFXuJfKWRzAfzyOcbD9HpFUJVlVhNBjIH9cTDLqx2G1p1IwOpU0i+E3/idQxqgnPjXfz1oI9fVp7j6OEm9PY4wZZ+JE/l1PQCsnbvEVLqRXF6MDgC+DUTpa5ayiq92ELtJNPZXGe2YCdK6Aj19buZ7PEy91oVNXWNWMO9uCI9iE4jO3cF+eKr7cAA4u3A4KqhO6Gi9+9FzFHU+g4GtwN1DoqVCFr9IfLVLiaOJTjZ38xOeweu2IuUagkkz8XU/FVk/d4mOpMPY6CBMqORGu1pbE43BY4QznATybFZpMBHsTVKga2Zzu7DXBrZw8ybtcRbOinxdFGihJA8N9kzS8jq+l3sTjcHu1ppbd7NvtYG9rXEaErECIYiDKUnkEIn5ZVRqmujHGiLE48EScSCJPbU4fbVobijSFGA2bNLyPLKam6UJaUGLIoJj0fN8W2twqzwRv/gk2EXYa4ox61aqLSacNgs2CwmDPoSRKfP/WTezyK/bW2RHEqRPD7CuycyTM9MMzwyzkDyONnpWdbW75B8Z5jR8QzDIydyGB07mUN6NEMq/R5j4xkGk8NsPvyG/wDQ4LUqfkv/2QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;제미나이&quot;
        title=&quot;제미나이&quot;
        src=&quot;/static/861a16704b529def8308d05348805339/a6d36/14.png&quot;
        srcset=&quot;/static/861a16704b529def8308d05348805339/222b7/14.png 163w,
/static/861a16704b529def8308d05348805339/ff46a/14.png 325w,
/static/861a16704b529def8308d05348805339/a6d36/14.png 650w,
/static/861a16704b529def8308d05348805339/e548f/14.png 975w,
/static/861a16704b529def8308d05348805339/dcccd/14.png 1127w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;좌측이 ChatGPT, 우측이 Gemini로 생성한 이미지&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;한편, Gemini로도 포스터 제작을 시도해 보았지만, 이미지의 느낌과 퀄리티에서 확실히 차이가 느껴졌습니다. Gemini 포스터에서는 한자처럼 보이는 문자가 섞여 나오고 현실감이 부자연스러워서 흡사 중국산 짝퉁(…) 같은 느낌을 지울 수 없었죠.&lt;/p&gt;
&lt;p&gt;두 모델 모두 생성형 이미지에 한글 문구나 추가 이미지를 직접 삽입하는 기능은 완벽하게 지원하지 못하는 듯했습니다. 하지만 전반적인 이미지 퀄리티 면에서는 ChatGPT의 결과물이 더 만족스러웠고, 해당 이미지를 포스터로 활용하기로 결정했습니다.&lt;/p&gt;
&lt;h3 id=&quot;참여자-모집-및-홍보-전략&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B0%B8%EC%97%AC%EC%9E%90-%EB%AA%A8%EC%A7%91-%EB%B0%8F-%ED%99%8D%EB%B3%B4-%EC%A0%84%EB%9E%B5&quot; aria-label=&quot;참여자 모집 및 홍보 전략 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;참여자 모집 및 홍보 전략&lt;/h3&gt;
&lt;p&gt;다음으로 고려한 것은 홍보 문구 작성과 참여자 모집 방법이었습니다. 글또 구성원들에게 글드컵이 어떤 이벤트인지 명확히 설명하고, 참여하고 싶은 마음이 들게 하는 홍보 문구가 필요해서 공을 많이 들였습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5c5faf6f497431e2c0c0717dbfb297aa/34e70/20.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 61.34969325153374%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAABxUlEQVQoz4VT246bMBTM//9On/uYVV+2yq60TcJlwQHMvZgA4RKSqeasoJs+bJFGxwY8Zzxjb759f8Lh7QfKLMAwjBjHAeM4YZwmDMMguN/v+OpZvrNucJuQpRpBGEEFEYJQIzh5SBINrTWCIICONMIwRBzHiKIIVVXBVAZlWeJ6va5kH4T3GV1pw9cZPF1AJRXmoQQwPqi43W6yYKn/YlXIcR6f8O46cGwbvuchzwvpXhSFgONl3jSNqJqmSfB520LIjmlWwPcVfN/HSSko24E6WDg57zgej9jv91IJ13VhWzYc24FlWTDGiOq/HgI4lyGiMIDWsfhGv2pjMA7jGgzV9H2/zgnOicctA6irUtSxu+d5UjnP8xxJkkgQaZoiyzIkcYI0+RgzMH5v2xbzPAvphqxt2wkRt6GUkp9JwnTP5zO6rlvBxayXywVt08r8gVASnGe8vrxiu93Ctu3/nruvzqMQsiON3+12MNVvGJ4zY+S8EXVdr5XvmTTXLJUKl8Rly03TYv9rj+fnn3g7ujhYzpoqkyTYkOrpL71jcPSZHtIWWvCJsBHTU3qXV9BZKT/yHYOhpwRvCpUuqkjE2l/69Yr+AYsYkOERb09RAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;대진표&quot;
        title=&quot;대진표&quot;
        src=&quot;/static/5c5faf6f497431e2c0c0717dbfb297aa/a6d36/20.png&quot;
        srcset=&quot;/static/5c5faf6f497431e2c0c0717dbfb297aa/222b7/20.png 163w,
/static/5c5faf6f497431e2c0c0717dbfb297aa/ff46a/20.png 325w,
/static/5c5faf6f497431e2c0c0717dbfb297aa/a6d36/20.png 650w,
/static/5c5faf6f497431e2c0c0717dbfb297aa/e548f/20.png 975w,
/static/5c5faf6f497431e2c0c0717dbfb297aa/34e70/20.png 1053w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;슬랙에 공유한 대회 소개&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;그래서 &lt;strong&gt;총 2.5만 포인트를 걸고 펼쳐지는 글또 10기 최고의 글을 가려라!&lt;/strong&gt; 와 같은 후킹 문구를 처음에 배치하여 눈길을 끈 후, 글드컵 소개와 대결 진행 방식을 설명했습니다. 그 후 일정과 주의 사항, 참여 시 혜택 등의 정보를 덧붙였죠. 이모지와 슬랙의 포매팅 문법도 적극적으로 활용해 비주얼과 가독성도 높였습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/58bad879bf5f013dca9e31f12e6ef035/2c288/19.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 39.263803680981596%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABU0lEQVQoz42SW2+CQBCF+f//S+0DUi+oUKiiwMJyLWLkYvQ0Z4w+Nt1k2NmZycm3ZzHCMEQQHOF5HhzXxekUQusMjuPC930Mw4j/rsfjAWMYBuR5AaUUKJ6mKQ6HQM6sx3EseZIkspdliSzLUFU17vf7OyjGZfBDKtM0sV7bWCyWWK3W2Gy2sO0NlsuVhGnOpW9ZFuZzC5PJVGZnsw9MpzNY1ieu1+tTMFYKnudDa40wjOTKzEmV5zmSJEUcK6RaQ6lEelEUyQ3YJ3VVVRjHEQZxOeT73+IZhXc7B0EQYLvdCSnJbNuG4zhCzTPnmbvuF9JUI8ty0D4hpCAJmqbBT9OgrmvJGefzWUhJQFL6x2DO29DzKIoRHI/ouu4pyAbJSEOv+MKkIemrzp31/f6AvChE6PVIRVEK4VvwdruJoS+iruvRXi5o21aCNQbzvu///HV+AbqOUuQcAyYYAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;참여 유도&quot;
        title=&quot;참여 유도&quot;
        src=&quot;/static/58bad879bf5f013dca9e31f12e6ef035/a6d36/19.png&quot;
        srcset=&quot;/static/58bad879bf5f013dca9e31f12e6ef035/222b7/19.png 163w,
/static/58bad879bf5f013dca9e31f12e6ef035/ff46a/19.png 325w,
/static/58bad879bf5f013dca9e31f12e6ef035/a6d36/19.png 650w,
/static/58bad879bf5f013dca9e31f12e6ef035/2c288/19.png 684w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;고민하여 작성한 참여 유도 멘트&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;그리고 마지막에는 &lt;em&gt;‘내 글은 아직 부족한데…’&lt;/em&gt; 라고 생각하는 분들을 위한 참여 독려 메시지를 작성했습니다. 토너먼트의 특성상 대결이 필연적으로 발생하지만, 패배에 대한 부담이 참여에 대한 허들이 될 수 있다고 판단했거든요. 아무래도 자신이 작성한 글이 상대적으로 &lt;em&gt;‘더 못 쓴 글’&lt;/em&gt; 로 평가되는 것은 상처가 될 수도 있기도 하구요. 그래서 글드컵을 &lt;strong&gt;글또 10기를 마무리하는 축제&lt;/strong&gt; 라는 표현으로 나타내어 대결에 대한 부담을 덜어드리고자 했습니다.&lt;/p&gt;
&lt;p&gt;이렇게 작성한 홍보 문구를 Gemini에게도 다듬어 달라고 요청했고, 최종 공지 전에는 운영진 내부 채널에서 피드백을 한 번 더 거쳐 완성도를 높였습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9a873fead13a4f40d4a989f960d30c8d/3ceac/18.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 55.828220858895705%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAABaklEQVQoz42R6W6DMBCE8/7v1N89VKlpm4OENJSYcBgMBmObI8lUdktF0kiNpU9rab2jWc+kSBTGcKqw/yixnTN8LnN4C2bxnQK7FcfO4fAdDrLmuJw1TMq0wQCnGoJ1iAKG5XyDt+kS83fX3rcbAim6M8azAxMjMqbKOmRpDnfjgqYUZclRicrWuhZQWkFpib7vf02M+ePQ1LrSiKIISULBObeUZYmiKJDnBYQQ6Nr+bObX4aVl86Bvj/A8D+u1a4UJIQjDCEEQIAxDRHGMqhIos0FQXxe0TdpAyxZbz4PjrBDHMbTWUEpZzF1Kia7t/nc4NFXdWCHjMrZuKkue53Z18wVamf++ZeVE49Cd7OBsNofrutjtCBhjqKW07gyNbkcr3yBY8AIPj0/wfWITPRwOGJ/T8QSemmSb20KhlOJ1OgXxt0iSBIzlSNP0myz7Wbm9PWUpBZ5fFri7X4GQAPv93iY8UIv6quAXKZNBgvobouUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;설문지&quot;
        title=&quot;설문지&quot;
        src=&quot;/static/9a873fead13a4f40d4a989f960d30c8d/a6d36/18.png&quot;
        srcset=&quot;/static/9a873fead13a4f40d4a989f960d30c8d/222b7/18.png 163w,
/static/9a873fead13a4f40d4a989f960d30c8d/ff46a/18.png 325w,
/static/9a873fead13a4f40d4a989f960d30c8d/a6d36/18.png 650w,
/static/9a873fead13a4f40d4a989f960d30c8d/e548f/18.png 975w,
/static/9a873fead13a4f40d4a989f960d30c8d/3c492/18.png 1300w,
/static/9a873fead13a4f40d4a989f960d30c8d/3ceac/18.png 1456w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;글드컵 참여 설문지에도 소개 문구를 적었다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;참여자 모집은 당연하게도(?) 구글 폼을 이용했으며, 본인이 작성한 글 하나를 선정하여 기술 또는 비기술 토너먼트 중 한 분야를 골라 글또 10기 활동 기간 중 제출한 글을 하나 선정해서 링크로 제출하게 했습니다.&lt;/p&gt;
&lt;h3 id=&quot;평가-프롬프트-다듬기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%8F%89%EA%B0%80-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-%EB%8B%A4%EB%93%AC%EA%B8%B0&quot; aria-label=&quot;평가 프롬프트 다듬기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;평가 프롬프트 다듬기&lt;/h3&gt;
&lt;p&gt;글드컵의 핵심은 &lt;strong&gt;AI에게 글쓰기 대결의 심판 역할을 맡기는 것&lt;/strong&gt; 인 만큼, 평가 프롬프트 다듬기는 필수적인 과정이었습니다. AI가 글을 평가하는 데 있어 명확한 기준과 절차를 제공해야 했기 때문이죠.&lt;/p&gt;
&lt;p&gt;프롬프트는 크게 다음과 같은 요소들로 구성했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/17ec42668d5a7c95f85c4948dbdab178/c61d0/21.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 34.96932515337423%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAAAsTAAALEwEAmpwYAAABHElEQVQoz22RyW7DMAxE/f//VzTI7iWSrH2z5eQyBZk0QJfDAw8iRzNkZ4zCbeoxDVdMY49ZCQRvsbWFuW8r1iVDihHWKHinmVoS2lr5fduot+Lx2NApOWEczixK0GAMlkWIthYensYrxG3ArG6M0RIpuncfQeJd8AbOSTg3w1nNYiUHLC8x+nmpCVpNMFq8HBqu4VVJuBSH1go6ctRfTiCnehaMszNydKg5ICcST0hFI2WNUvwPV98sNXL0Toge+90Hzsc9RyGRWiJDzrh5CZjdEaVSxMTOf/OM3NBJOeJ4+MRwPbE7WgFFfsZOz8hLgHIH5GLfw//BO6TIp8MO03DhqHThFD1KjsgsHFGrh7Q7aH/my/91WLne7w1fBW8TJ9FNYxwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;프롬프트&quot;
        title=&quot;프롬프트&quot;
        src=&quot;/static/17ec42668d5a7c95f85c4948dbdab178/a6d36/21.png&quot;
        srcset=&quot;/static/17ec42668d5a7c95f85c4948dbdab178/222b7/21.png 163w,
/static/17ec42668d5a7c95f85c4948dbdab178/ff46a/21.png 325w,
/static/17ec42668d5a7c95f85c4948dbdab178/a6d36/21.png 650w,
/static/17ec42668d5a7c95f85c4948dbdab178/e548f/21.png 975w,
/static/17ec42668d5a7c95f85c4948dbdab178/c61d0/21.png 1145w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;대충 5,000자 정도의 프롬프트를 작성했다&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;역할 및 상황 설명:&lt;/strong&gt; AI에게 글드컵 대회를 소개하고 두 글을 비교 평가하는 상황을 상세히 설명, 심판으로서의 역할을 부여한 뒤 AI에게 기대하는 평가 태도와 목표를 설정&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;평가 항목 및 배점:&lt;/strong&gt; 큐레이션 팀에서 사용하던 평가 항목들을 제공
&lt;ul&gt;
&lt;li&gt;글의 구조적 완성도 (30점)&lt;/li&gt;
&lt;li&gt;내용의 독창성과 전문성 (30점)&lt;/li&gt;
&lt;li&gt;가독성과 표현력 (20점)&lt;/li&gt;
&lt;li&gt;독자 친화성 (20점)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;예외 상황 처리:&lt;/strong&gt; 기술/비기술 토너먼트 별 가중치 조정 및 동점자 발생 시 처리 방법 안내&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;포매팅 지침:&lt;/strong&gt; AI가 생성한 결과물을 노션에 바로 붙여 넣을 수 있도록 마크다운 포맷으로 정리해 달라고 요청&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;후속 프롬프트 안내&lt;/strong&gt;: AI가 다음 대결을 위해 어떤 정보를 제공해야 하는지 안내&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이렇게 작성한 프롬프트 그 자체도 AI에게 다시 다듬어달라고 재귀적으로 요청하며 완성도를 높였습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b254d27e4435bfccd5f41cdc107257e3/d7542/22.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 50.306748466257666%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABSklEQVQoz3VS2XLCQAzLX5Rcm4scmwTIRUJfylmG//8hdWTYlHbgQWPZ2dhaeS3X8/EKjuvN0fMV8kKjKCvkukRelHM+13QJFYSw+ANhO67A5M+NVRhhfzjh+3rD4XTB/njG1/6Iy/U21w7HM6I4geV7CkoFCKIYQRjJFCp6pfg/bOeO55qVBhF0kiLT92twysfCfouF7byFNOQ1XV+hXq1ndP2A1XqD9aZB07RoWqKTnCirGhVRr+QcIzF7SMImbdth07TC2aAftsJNjXnxMD+KY7kNET8irRKF9I6TCKOETaiWNcMZ264XNbRHl6VwfuOgMIp/GxpV4zQJH7YjxmmHfhikCfPtOGLafYrSZZohWaYC8jhZ/lXIw2YSp5PTK/IsL6DLSiDvT1NZPftnfJWG9NBXAdIsly1xWxxiNmfe53NuuNm6idzyD2XWH2Mop656AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;준비&quot;
        title=&quot;준비&quot;
        src=&quot;/static/b254d27e4435bfccd5f41cdc107257e3/a6d36/22.png&quot;
        srcset=&quot;/static/b254d27e4435bfccd5f41cdc107257e3/222b7/22.png 163w,
/static/b254d27e4435bfccd5f41cdc107257e3/ff46a/22.png 325w,
/static/b254d27e4435bfccd5f41cdc107257e3/a6d36/22.png 650w,
/static/b254d27e4435bfccd5f41cdc107257e3/d7542/22.png 810w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;훌륭한 글쓰기 대결 심판으로 조련(?)시켰다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이렇게 AI에게 심판 역할을 부여했다면, 그다음부터는 대결 진행에 필요한 정보만 제공하면 AI가 스스로 대결을 진행할 수 있도록 했습니다. 매칭 정보와 참여자, 글의 링크, 글 제목을 제공하면 AI가 해당 글을 읽고 평가를 진행하는 방식이었죠.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f4cb529fc83eb1d307bd14a642b37a51/59822/23.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.25766871165644%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAACI0lEQVQ4y02TC2vjMBCE8/9/28FBIUdpE9dvy5L8kizrYTdz7DopNQyLbPRpRru+AMDj8aCCmHZkRYOy7jEZj9kGjMbDusjf1LBgsR7L6uH8jnVLPzIuYvMRl9/AEBP+/L3i7d8NH1mNW96iFjPDUzrQ9SMaMUAOBnpafw4lTSbAhx0Xgv0Gvl0/8XEvUTQKedXjq5K8cd+/GZiXHapWoqgFq+4UhJzQ6wVbSKfD1+N9xPU9w/utRFYKZIXAvRAYl40dNp1G1Ui0/QA1mFOjwTA7dux8wuXYD9h1Q4g79uPAYlYY6+C2CLcFOB/ZXdoPhuVVxyqbHp2c+Ao6OaLtRxi7ncC6FagbAa013LoixogQAmII8N5jTwlp/+ZmvYAUt+U71RDqBC8EpKhaK+R5jrKsME0TpmnGOI6Y57M65xhIoM+s5EmoWsWwmuuAutOYzXoCaVPTNOj7Htu2wZGcY61PxxSZYn4VLW+me6TI5PIVfbHuBAohcLvdcM8ydloUBfK8QFVVvKYDySGBaLPUC3e11zPksPBaqBl29a/IGnVdM0ApxVFJFJ9g5DCmg90QRI+WQf0TTN2mal5AKSU7IacUW0rF72jddR32PTGQHNJGPdnncFseGxoZcm5dOIHDMPy4e7k6mzOxU+o4jdU9r7kx1FWazWWNmO0pOmDzz8G21kJpzdEJStLDwJUOo9GhplDcXk0MpP9ajwaSr8DwvxzSgf+x9Nok5bHIqgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;매칭 결과&quot;
        title=&quot;매칭 결과&quot;
        src=&quot;/static/f4cb529fc83eb1d307bd14a642b37a51/a6d36/23.png&quot;
        srcset=&quot;/static/f4cb529fc83eb1d307bd14a642b37a51/222b7/23.png 163w,
/static/f4cb529fc83eb1d307bd14a642b37a51/ff46a/23.png 325w,
/static/f4cb529fc83eb1d307bd14a642b37a51/a6d36/23.png 650w,
/static/f4cb529fc83eb1d307bd14a642b37a51/59822/23.png 916w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;매칭 정보를 제공하면 추론 과정을 통해 그 결과를 볼 수 있다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이렇게 출력 포매팅을 마크다운 방식으로 지정해 두어서, AI가 생성한 결과물을 노션에 바로 붙여 넣을 수 있도록 했습니다. 이 부분은 나중에 대시보드 제작 시에도 큰 도움이 되었죠.&lt;/p&gt;
&lt;h2 id=&quot;참가-접수&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B0%B8%EA%B0%80-%EC%A0%91%EC%88%98&quot; aria-label=&quot;참가 접수 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;참가 접수&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/69030d4a4f3f7bdc03d823ba559d058c/25c1c/17.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 58.282208588957054%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAACaUlEQVQozz2RC1OjMBSF+f8/SNcdtbqrVp2Krq31Ma2QBBISoC2UviC9Zyexmplvzk1u5uRwCWIhEMeCopgjkRkpXZDSJc2qhpp1S3WzpeVqS/Vqi2q5hlNPs8XSn21QNxvMqwazRYNgawnNbo/lpqN1a9HRHjvbYdu1vm73Ft3ektNNu/NnFvuDEtp994M7C85Phjj/PaLT4yFOj/7R9dkz9Xsjurt8oZvzoef67Bn93pD6FyP8OXlC7+gBvaPBQQ8cP+DyV4jgefCGYfhOj3cvGNwM6fH+le6vnun275Nn0B/5/fXFAFe9Ad1cPOKhP8bT/bsnvH39YRROESitoLQir5mk2bwkmaXEeEw8YaTzjExhSKQCUqWUqgQ616iWCyyqOWaLEpvtGt8rECKBEAlxLsAYJ6UycjqZTH9we8a47ydJCmNylOUMi6rGZrvDbtei6yx2bYfAGANjDGlj4MxcnSQJxTGjmH3xbRjFMQkh3D1IpTCbOdMK88UC6/UG1u4R1HWNqq6pqmrXoKIoSGUZpWlKUkrKi4KiKKLxeIy3t3eaTKeYHvj4+IBIEkipUJYlWpdQZRmcgXs1lZIyrYkLQZ9RRC6RNobcSCaTCaIoJsYYuBCeVEpkmfa4UazWawRpKi0XwjLOvWqtLWPcTqdTG0WRVSqzSZr6OopjK6W0Uimb54VdVJVn17a2s27trTOEmwvj3P0cN0+4FO6TPj8juH6Spi4dOOc+iZQSRVmiaVY+ldNm9VUHRVmGRVGGeVGEJnfkoUiSMGYsjGMWMsZDY/JDPw/zvAi1NmGW6TDT2tfaGH/Hef0H3IZvIAP3R9EAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;참여자 목록&quot;
        title=&quot;참여자 목록&quot;
        src=&quot;/static/69030d4a4f3f7bdc03d823ba559d058c/a6d36/17.png&quot;
        srcset=&quot;/static/69030d4a4f3f7bdc03d823ba559d058c/222b7/17.png 163w,
/static/69030d4a4f3f7bdc03d823ba559d058c/ff46a/17.png 325w,
/static/69030d4a4f3f7bdc03d823ba559d058c/a6d36/17.png 650w,
/static/69030d4a4f3f7bdc03d823ba559d058c/e548f/17.png 975w,
/static/69030d4a4f3f7bdc03d823ba559d058c/25c1c/17.png 1047w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;참여자 목록&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;프롬프트 다듬기 등 모든 준비를 마치고, 드디어 글드컵 참가자 모집글을 공개적으로 올렸습니다. 약 9일간의 모집 기간 동안 총 65명의 글또 멤버들이 글드컵에 참여 신청을 해주셨고, 기술 토너먼트에는 39명, 비기술 토너먼트에는 26명이 지원해 주셨습니다. 글또 10기 활동이 이미 종료된 시점임에도 불구하고 많은 분들이 참여해 주셔서 감사했습니다.&lt;/p&gt;
&lt;p&gt;한편으로는 글드컵 신청 마감 기한까지 작성된 글도 참여 대상으로 인정하기로 했는데, 이 글드컵 참여를 위해 새로 글을 작성해 주신 분들도 계셔서 감동이었습니다. 글드컵이 단순히 기존 글을 겨루는 대회를 넘어, 누군가에게는 글쓰기에 대한 동기 부여가 되었다는 점에서 의미 있게 느껴졌거든요.&lt;/p&gt;
&lt;p&gt;신청서에는 참여자들에게 자신의 글을 선택한 이유도 함께 물어봤는데, 그 이유가 다양해서 매우 흥미로웠습니다. 몇 가지를 꼽자면 다음과 같습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;가장 공들여 쓴 글이라서&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/2024/10/12/Geultto-Owl-Project.html&quot;&gt;글빼미(AI 피드백 봇)&lt;/a&gt;로부터 좋은 평가를 받은 글이라서&lt;/li&gt;
&lt;li&gt;오로지 글드컵을 위해 새로 작성한 글이라서&lt;/li&gt;
&lt;li&gt;본인의 철학을 담은 글이라서&lt;/li&gt;
&lt;li&gt;제목이 가장 눈길을 끄는 글이라서&lt;/li&gt;
&lt;li&gt;글을 쓰는 과정이 즐거웠던 글이라서&lt;/li&gt;
&lt;li&gt;큐레이션에 선정된 기록이 있어서&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이처럼 각자의 기준과 사연으로 선정된 글들이 모이면서, 저 역시도 글드컵에 대한 기대가 점점 커져갔습니다. 참여자들의 글이 어떤 대결을 펼칠지, 그리고 AI가 어떤 평가를 내릴지에 대한 호기심이 커져갔죠.&lt;/p&gt;
&lt;h3 id=&quot;대시보드와-대진표-제작&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C%EC%99%80-%EB%8C%80%EC%A7%84%ED%91%9C-%EC%A0%9C%EC%9E%91&quot; aria-label=&quot;대시보드와 대진표 제작 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;대시보드와 대진표 제작&lt;/h3&gt;
&lt;p&gt;대회 결과를 총 5일에 걸쳐 참가자들에게 배포해야 했기 때문에, 업데이트가 용이하면서도 추가적인 코딩 작업이 필요 없는 방법을 찾아야 했습니다. 그 결과, 앞서 이야기한 것처럼 노션을 활용해 대시보드를 제작하기로 결정했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d4a9f4b2930cd78c3044d870f086f69b/ea964/16.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 79.75460122699387%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAAsTAAALEwEAmpwYAAACXElEQVQ4y4WU32oUMRTG+66+gC+h4D+qLVgqSmvFFtQttIhUpOCVN0JB0AfwotJ2M5lkJpkkJ8n5JJndbXVbGjhkkkx++b5zMrPy7esx9rY2Mdndxvu9HexP3mH/4ACfPh/h148TfNzbxmR7E5Odl/h58h0MwBoD5gxmXoqVyevnuHf3DtYfP8D99U2svnqDZ1u72Hj7AYdHX7D25BE21p7ixepDHB/uIzNDygbRW3iKCCEgpXQJdL3E2elv/Dk9RSMlKCbElEAUYQcH6wkhM1JmxEjw3kNrdTOwAIy1sIMF54zbmnMOWs2BaRlYB5kXG8oTXw5nL479AqgVUhgQKILoP2Agqi/knMaoBySYXmMoqjkv5ufATusKjG5AJELO+Yrl4NGIC/RdC2c7DLaDdwaqlZDNFNbocd7oCp7nMPkCdKAQ/gWG4CGm5xVoelWBwVs0jajATss6V4LnwFkOabCIdB1wprAA3VAU2qqwldNqXasRWhQWy0q1yDEgUaiVXwJOp+d1Y7HXd6oqVErWg5RqlhT2nUaKBEp5LMh1wAK6CmyaKVopaj6N0TUtRU25Jl2nQd7BhViBN1hWNcaiWEgpFsUqc6VfWG7b24GdbserMiuKVm0tSgGVNTf01VoBtq0E+WEBvPpdFyCL6TmbXrF3hjvdctcpbmXDrRTc96quDbbjnBN771lrzeQde4qcUuKcM8/bmMOLs0Ulx0r3kM2l5TIu+Z0rLD8HckUhLVuOkUTXKeEGI6ztRfCDIPKCKIgQvEiRRIxBRAoCzCKEIIwxdRxiEilnwcyL+As3ecX5hQG/ZgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;대시보드&quot;
        title=&quot;대시보드&quot;
        src=&quot;/static/d4a9f4b2930cd78c3044d870f086f69b/a6d36/16.png&quot;
        srcset=&quot;/static/d4a9f4b2930cd78c3044d870f086f69b/222b7/16.png 163w,
/static/d4a9f4b2930cd78c3044d870f086f69b/ff46a/16.png 325w,
/static/d4a9f4b2930cd78c3044d870f086f69b/a6d36/16.png 650w,
/static/d4a9f4b2930cd78c3044d870f086f69b/e548f/16.png 975w,
/static/d4a9f4b2930cd78c3044d870f086f69b/3c492/16.png 1300w,
/static/d4a9f4b2930cd78c3044d870f086f69b/ea964/16.png 1312w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;제작한 대시보드. 상단에는 대진표, 하단에는 각 대결 별 상세 결과 페이지를 구성해 놓았다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;대시보드의 상단은 대진표를 한눈에 볼 수 있게 구성하고, 하단에는 각 경기에 대한 상세 결과를 표로 정리해서 별도의 추가 페이지에서 확인할 수 있도록 했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c6f51c84d0d6c5e900d1562d48240968/2c288/31.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 93.25153374233128%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAACXBIWXMAAAsTAAALEwEAmpwYAAACvUlEQVQ4y31SCZKjOBDs/z+vI3baBwYkQOIQl81hG7dyIgvDzGzMLhFJlaRSKuv4AIA8z9E0DZxzKIoCZVmicg7O1eJznzE8W5YF//d98GetRZZlSNMUWuvdEsZaWRtjZM1YEtv3Ph+kT7xer5WQB6fTSTappO97tG27q9ouVJVDWVZCwgcogjGM7boO39/fK6HWiQRUVSVk1+tVglgGWoIkwzBgmia5vJ05KY0T33uPD/6ocJpmjOMoF+Z59UlA0Ocj9/sdj8djP2fs7XYTME4IqZDFJ+p6BVNrml9rqqH6bU21m/KmafeU2TAhVErj8/MTx+MRh8MBh+MRUawQBBd8fX0hCAKcz2copSQb1o4liuNYyJ7Pp6jfa0jp27isL3coXYOm7aQ+VEcwXabFixvYWWIfGwZQdlGWa2rO7bNHEnZxIzTvKbB5vltjrJyRfJ/D63BH6Xr0wx3DvGCYBF7sLFYwzi8v59xbLcb5hfH+gilqLMt7Dpt+ROE6dLc7ruPzd/h+eOxr+v3w+GOPd4imn7As7xo23YBIW6g0R2orpKZCkpU+MSVs2XhT1F6nuTdF47PcyV5qK/Hfj6AbHlhe32sNKVmnBX4cLzicwg0+CDWCSPtLpP3XMfBhnHo+djxH/p9D4JOs/EPlTjhMT1F1iVNcogRBlNB6lVhEKvNRnPogVFx7qgtVhnOo6f8X4YLUOoRxikgZIQ5VJilHOvNhnLwJjS9cj1hbUctG/J1wXkTh+aJEIRXwgkpyxNr4SKV+XVvWEUGo/eEc+SQr/k54m57IyxZUxKbQZtb5LK85Dr6se0m1cJ1vrzNcO3jX3lB346+m/DtlnZU4XRRfp/X0I20kVTaF1uROGsF92vZ238mEcNm6PC8cBbAJKrXgiMSJAQlinb1TTnzV9N4WNXSWS7ptP63z+FZJhT8BJHabHNT+/coAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;대진표&quot;
        title=&quot;대진표&quot;
        src=&quot;/static/c6f51c84d0d6c5e900d1562d48240968/a6d36/31.png&quot;
        srcset=&quot;/static/c6f51c84d0d6c5e900d1562d48240968/222b7/31.png 163w,
/static/c6f51c84d0d6c5e900d1562d48240968/ff46a/31.png 325w,
/static/c6f51c84d0d6c5e900d1562d48240968/a6d36/31.png 650w,
/static/c6f51c84d0d6c5e900d1562d48240968/2c288/31.png 684w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;Gemini를 이용한 Mermaid 대진표 코드 생성&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;대진표 제작에는 &lt;strong&gt;Mermaid&lt;/strong&gt; 를 활용했고 이 부분에서 &lt;strong&gt;Gemini의 도움&lt;/strong&gt; 을 많이 받았습니다. 참여자들의 이름 목록과 원하는 대진표 형식을 Gemini에게 전달하자, 금세 Mermaid 문법으로 작성된 대진표 코드를 생성해 주었거든요. 이 코드를 노션에 붙여 넣으면 자동으로 대진표가 뚝딱 생성되었습니다. 만약 이걸 제가 한땀 한땀 수작업으로 작성했다면, 아마도 몇 시간은 걸렸을 것 같습니다.&lt;/p&gt;
&lt;p&gt;그런데 참가자 수가 정확히 &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2^n&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6644em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6644em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 형태가 아니었기 때문에 부전승 처리가 필요했습니다. 특히, 부전승의 숫자가 좌우 트리에 최대한 균등하게 배분되도록 배치하는 것이 중요했는데, AI는 이런 디테일한 부분까지는 제대로 처리하지 못했습니다. 결국 이런 점에서는 수동으로 조정하는 과정이 필요하더라구요.&lt;/p&gt;
&lt;p&gt;하지만 반복적이고 시간을 많이 소모할 수 있는 대진표 초기 스케치를 AI가 빠르게 생성해 준 덕분에, 전반적인 작업 효율을 크게 높일 수 있었습니다.&lt;/p&gt;
&lt;h3 id=&quot;대결-진행&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%8C%80%EA%B2%B0-%EC%A7%84%ED%96%89&quot; aria-label=&quot;대결 진행 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;대결 진행&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9526bb28738ab5974d97b4f70b12eaef/a0209/24.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 69.93865030674846%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB1UlEQVQ4y42S626cMBBG9/2fLf0RtVXSpNnAermDr/iCgW8qTHaVVpsmlo4GjDia+ezDJBgVRUHszKiqKmKMUdM0ZK2ldV2JCAR8nYMQgozWVBQl5aczdW1HMUaapom89xRCSO9b3dj2L8+3OFg7kvcBWZbj+Johy044MUZ5ntPpxIidC5JSkXPuSxy0MZhCoDzLqG564pyjbVtIqWGthTEG4zjCOY/tB+/3+qHQGEN1XaMsyyTSWlMIEy3LnEad5/kyMv7HFsXGgYi2Q8Hd3TeUZQWldGK0FuO4E4IHfbKwr10opcTv4wllI1F3KtWiljjXAqwSaHoFqR24cuByr2JDOwzSwvqIizQJt9weHn+h7znCFN+Yr/gQE3FeEOcVU1zS/hT37/Oy/i0UQiRhUdY7VYOm7VE3HeqmT/SDQAhTymtdV9waeatX4fPTE7quTXl57+Cdg3M2na51AcZ6mNFBGZs6e5cbLrJrhn3f48fPR9StAJcjBrFhwLkAFwJKKSzLglsd/buuh/JyzFFUHXquE92w14ErxBg/6gg3hcMw4P7+e8pMKvOGhjE6XWqtNbYL/V760fVJQq0Unl9yvLIW+blDxlo07YBh6CGkTB1eRv5M+AeZRznK6StIIAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;대결 진행을 위한 스크립트&quot;
        title=&quot;대결 진행을 위한 스크립트&quot;
        src=&quot;/static/9526bb28738ab5974d97b4f70b12eaef/a6d36/24.png&quot;
        srcset=&quot;/static/9526bb28738ab5974d97b4f70b12eaef/222b7/24.png 163w,
/static/9526bb28738ab5974d97b4f70b12eaef/ff46a/24.png 325w,
/static/9526bb28738ab5974d97b4f70b12eaef/a6d36/24.png 650w,
/static/9526bb28738ab5974d97b4f70b12eaef/a0209/24.png 725w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;대결 진행을 위한 스크립트&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;대진표가 최종 구성된 후에는, 결과 발표일 전까지 모든 대결을 미리 진행해 두는 작업이 필요했습니다. 희선님께서 정해진 대진표에 따라 AI에게 전달할 프롬프트를 뽑는 작업을 스크립트로 정리해 주신 덕분에 작업은 한결 수월했습니다. 그 후, AI가 평가한 대결 결과를 대시보드에 옮겨두는 작업을 진행했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2c9e54e743ae391ee748750b88db160d/25c1c/25.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 63.80368098159509%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB9UlEQVQ4y4VTaW/rMAzL//9zG7Y2aZukceLmvq+mNwcqc7EPD3gGBBuwRYmkbJ20hr3dIlQKjmPDdQ8IQ4XPzw8MQw+zbrcbTieNOD6h6zq56/s15Nx1uF6vsOZ5RhSGqOsKVVWhrmu5WJZFQMx6PB7wPBebzTf2ux3s7UbOQRBIfqgCnM9nWEzM0lSq9n2Hrmul2jxPuN/veL1eb0CySdNUCmdZJnlFkUvO5XLB8/mENU8T0iQRkGEYBLRtGgFkpwZw6Hvs93tUVYmqLFGWxTuKokCe5wJqsQq1i6JIKrHtcRjWGMe3NtM0QQUBtNbwfR/H41G0ZtfUVutIZLKYuN85cBwHu52D7eYbm68v0SWOY9GIwCzEwofDAUoFEnwj1LMMbduIRBa7cl0X7mF1d3UylkdlUQhV6scu23ZlsCxnoccgA+pvDLSappaufN+D57qiJwGjUAkN9dshq9MMnqdxFACCs6FpWu8FkJR1FCLPMiTxCdEvlVhr2UmNZhEgSRLRkm5ycTdnmsewSMO2bRlu3/NQ5CvVIs/FTY4JZ5W0SY+AHGbu4zhIh2YaBLBrWwGiy9StaRoZbsY66JUAcjHRaGeCzhq6AshvQ0B+KWrGL0j9SJcjopQSyv9bZl4tVqUx7Iw7JWjq+n2mg6T7V6d/henwB2wQ2EihkYV7AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;노션&quot;
        title=&quot;노션&quot;
        src=&quot;/static/2c9e54e743ae391ee748750b88db160d/a6d36/25.png&quot;
        srcset=&quot;/static/2c9e54e743ae391ee748750b88db160d/222b7/25.png 163w,
/static/2c9e54e743ae391ee748750b88db160d/ff46a/25.png 325w,
/static/2c9e54e743ae391ee748750b88db160d/a6d36/25.png 650w,
/static/2c9e54e743ae391ee748750b88db160d/e548f/25.png 975w,
/static/2c9e54e743ae391ee748750b88db160d/25c1c/25.png 1047w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;노션에 옮겨둔 대결 결과 상세 페이지&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;약간의 노가다(?)성 작업이 있었긴 하지만, AI가 제공한 결과물이 노션에 바로 붙여 넣을 수 있도록 마크다운 포맷으로 정리되어 있었기 때문에 생각보다 어렵지 않게 작업을 완료할 수 있었습니다.&lt;/p&gt;
&lt;h2 id=&quot;결과-공개&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B2%B0%EA%B3%BC-%EA%B3%B5%EA%B0%9C&quot; aria-label=&quot;결과 공개 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;결과 공개&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5d518030e8f2051889da7f6daaeed63c/95fa1/26.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 80.3680981595092%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB7klEQVQ4y5VU2W7bMBD0/39B0W/oW9GXtk99bVqgSNxIpg7KOq2LlERRhyVNQTo2qqaxkwVGWBLEcGZ3xc3HTx9w9+M7HMdBFEVgJcM0TViWBfM84xzLcs4XXItNlmVIDilcl8LzPI0kTuA6Lnzfx/2vb/C2n4F51FTqoquE6iNYhMh34FJPK1WXKJX90CNPTVQZfdK2vI6QMgvv796BPBBsf29h2zbqul4dVERn/L3+L2HGD/j68wviMEYQBNq2UvlSXFN5slyE8K0dzB2BYRjY7/daYVmWqKpK5wqMMUgpbyuUXQ/qeaCUwnVPzbBtBxYhIIToPcuyEIYh8jxf2f+3DBuV9rJGFFGQIAcJMgRxgE4UaFsJIQS6rsMwDFebcSbVCgN/D9N4hLmz8GiYME0DhOx0cxzbBqUeOGco84MuAedcQ5VElUFNxEWhShjniJMEZVHoQyXnSNNMN0ZZTNMcvEwxiBjH44xxHFdYWVZJzwoIVmA4jpiGDn1+wDAOmI7Xbb5oWfoueLRH0wq0LAczt6ibGk3NL7/hLawUysBDFQdoOwlZlagsA41oINsG8zw9G5ObcygDCh75kH0HyU+EohWQol4V/DVxIgxPCoVsL4S1aNCK+vLivI0w8sGTEEIKyIqBP1lum+rNhH8AJlvU4xD8kDQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;결과 공개&quot;
        title=&quot;결과 공개&quot;
        src=&quot;/static/5d518030e8f2051889da7f6daaeed63c/a6d36/26.png&quot;
        srcset=&quot;/static/5d518030e8f2051889da7f6daaeed63c/222b7/26.png 163w,
/static/5d518030e8f2051889da7f6daaeed63c/ff46a/26.png 325w,
/static/5d518030e8f2051889da7f6daaeed63c/a6d36/26.png 650w,
/static/5d518030e8f2051889da7f6daaeed63c/e548f/26.png 975w,
/static/5d518030e8f2051889da7f6daaeed63c/3c492/26.png 1300w,
/static/5d518030e8f2051889da7f6daaeed63c/95fa1/26.png 1816w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;하루하루 진행되는 대결 결과 배포를 매일 슬랙에 공유했다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이렇게 해서 8강까지는 모든 대결을 미리 진행하고, 결과를 정리하는 작업을 마쳤습니다. 이제 남은 건 대진 결과를 슬랙에 공개하는 것이었죠. 준비한 일정에 맞추어 대진 결과를 슬랙에 공개하기 시작했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/325a6d8929ed515676558bc2d534dc62/9937c/5.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 57.05521472392638%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAACZUlEQVQoz6WO20tUURjF5+/oJeohIntTzEtjicagDEKakFiYUmKGKSIS3QwrECJINKLsSoSaJZZNeZlRMzJRQXqJohKctHNmzHOZmXPmdsZfnFNOhY8t2LD3t9f6fcumBoJ8/rKAz+djxe/DJ4romkZY1wmFQsRiMUyFozEWBRFVVdE0DV3XiUSiaFrI8pmzRCKBLaSFWVUCGEacb4Ifr1fAu/ydJSscsGBBVWXJu8iqJFvhQCCAosjWvx78QSwaJqRpltfGbxlGAimgIasaq4qCGtKJRqNWI1mSUGTZukcikfUIkqoiyYrVzvSura1hM7eJgoCqKMlQUBYgEcWIJ1heXkFWVGsuCAKiKKIoigUQ/X4kScaIxzEM4xew7+kg5VUNnGhsoa7xNHVNrdSfuUZV3QXm33/gj9bw+0XiMXNRzHqbzcxjgiyHCWzvesKWtFJ2phfgcBaSll3I9jQnm7bZeTUyzsCgm+bzNzh76Tp3ewZ4/NxDd7+LR9196OFIErQOtXXe6SfFXkm2o4yi0gNk5h0kPa+ClN0VuF/PMj/TS9vlJpwlVezZX0NxeQ25BaVUVjcQCgaTwGTDjlu97EjNw77PgT0vn6wcO1mOI2SU3WRy9hNfF8dxv3tA65U2qo+3cKy2nuZzZ+jsuo0Rj/4DtBq23x9mc8ouMrLtZGZlkGXPJTXHydaCDtzTC7iGHlJ2spH8oqMcKq1lr7MYR8lhTl28iqbrG4HzH73c63Ex8GKU4SEXoxMzDLnf8GxkDq+g4PGMMfhyjPHJaTwTb3FPTOEamWRyao5YPL4RyH/qb5gJ/AnH9+RXROX+aQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;대회 시작&quot;
        title=&quot;대회 시작&quot;
        src=&quot;/static/325a6d8929ed515676558bc2d534dc62/a6d36/5.png&quot;
        srcset=&quot;/static/325a6d8929ed515676558bc2d534dc62/222b7/5.png 163w,
/static/325a6d8929ed515676558bc2d534dc62/ff46a/5.png 325w,
/static/325a6d8929ed515676558bc2d534dc62/a6d36/5.png 650w,
/static/325a6d8929ed515676558bc2d534dc62/e548f/5.png 975w,
/static/325a6d8929ed515676558bc2d534dc62/9937c/5.png 1156w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;사람들의 뜨거운 반응(?)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;대진표와 함께 생존자들의 명단(?)이 점점 줄어드는 것이 보이자 참여자들의 긴장감이 고조되는 게 느껴지더라고요. 저희는 &lt;em&gt;주접과 호들갑을 많이 떨어달라&lt;/em&gt; 고 부탁하며 축제 분위기를 더했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/19c03f6a8f029eb323682033d970a626/4fa52/8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 73.00613496932516%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAABv0lEQVQ4y6WTjY7aMBCEef8HrNqrjgMuBS6QxF7/23Gm2k1I4SR0amspCt7EX2Zml800Tai1Yprqcuf9iKkue7mP8nvdr+/WtS5npgkbLirVwdCAGC2Kt6DDFsYopBwRL2foZgfnLXL0cNZAnxt4R8g5gVQP+jjKvpSMDdO7rgXpDt4TijdQ2xdo1SNEj9AeMexfQZaQgoM1BNXsYPmDKUL3V+jTuwgoOc0KBy6qBegM9NsLtL4BTxhYsSPEYGFIYzgeBJjzAjw3M7CkReG1haEejm0wcPtDXgjJI3zMCq0ziDeFv/ZiMaUA1V1A7XE+KwprRd9fVoXZEdTrd5AeEFKYLR+2sN7OQEsYmp1k/sdyA2v1bPkhw2AEyAqJBvjoEdsTFFu2i2WjoRbLrJCGDnRvmTNkhcSZBYNkNdTPb1DclDQ3hYEkQCfAodmvGbJlUfw5QwZKU2KAv7bw3qLUImOj3t9kbFJ0qOOIMSfUscj8xeCl+2yXZ/EhQ2eVFO/XtA7tPMhfrTVDDpmB41iACTL1fH1et/qza5nDy9wUp8XKevAJ4Pb8ucLr0mW2fAf8l/X4Xw5GQv9P4N9Z+gr4GzyJjzsvSZJZAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;대진표 업데이트&quot;
        title=&quot;대진표 업데이트&quot;
        src=&quot;/static/19c03f6a8f029eb323682033d970a626/a6d36/8.png&quot;
        srcset=&quot;/static/19c03f6a8f029eb323682033d970a626/222b7/8.png 163w,
/static/19c03f6a8f029eb323682033d970a626/ff46a/8.png 325w,
/static/19c03f6a8f029eb323682033d970a626/a6d36/8.png 650w,
/static/19c03f6a8f029eb323682033d970a626/e548f/8.png 975w,
/static/19c03f6a8f029eb323682033d970a626/4fa52/8.png 1241w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;매일 업데이트된 대진표&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;64강, 32강, 16강이 진행되는 동안은 매일 대진표를 업데이트하고, AI가 제공한 결과를 노션에 옮겨두는 작업을 반복했습니다. 다행히 하루 5~10분 정도의 반복 작업으로 마칠 수 있었죠.&lt;/p&gt;
&lt;h3 id=&quot;승부-예측-이벤트&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%8A%B9%EB%B6%80-%EC%98%88%EC%B8%A1-%EC%9D%B4%EB%B2%A4%ED%8A%B8&quot; aria-label=&quot;승부 예측 이벤트 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;승부 예측 이벤트&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f3e3cfe66c9d95b259954b0b713ef983/5fe07/27.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 52.760736196319016%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAABOUlEQVQoz5WRX0vDMBTF8/0/jYLgnAhzPgkDK4Ivvqj9s2xt102XNrlpciTpMrvOKT5cfjn33N4eEpbEHK/vKd7iDHy5QlFusN4IiEZjKxS2NXUlFERNvra1gmgIq+oTRbnGshJ4XjQoPyRYa1vUSkJqgrYGDZE/kzHQ1oJM6/tSa8+gVat9OS2oRdUYCLJgNxczTEYPuLt+xG3gVYTpuNPTcbT3Jz3t/G9GGJ3PcHl2DzZPCmRJjnlaIo07ZnEO3tMdi6N+1mPOKzxFL2AAYGDgaTta2AMd/NAfMsxxnoMRaShFIK0hlfL81oS9f4q7OWMtkoSDad1CEcHRLfRa0SHpd7rvXNb9Qve3/sBQn+oH7RdaizRdgNEPSULS4yvY6cHiRnYL/51w6J9MOLw7qeiPhIe+Sxge5QuhvUwwULxDiwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;승부 예측 이벤트&quot;
        title=&quot;승부 예측 이벤트&quot;
        src=&quot;/static/f3e3cfe66c9d95b259954b0b713ef983/a6d36/27.png&quot;
        srcset=&quot;/static/f3e3cfe66c9d95b259954b0b713ef983/222b7/27.png 163w,
/static/f3e3cfe66c9d95b259954b0b713ef983/ff46a/27.png 325w,
/static/f3e3cfe66c9d95b259954b0b713ef983/a6d36/27.png 650w,
/static/f3e3cfe66c9d95b259954b0b713ef983/e548f/27.png 975w,
/static/f3e3cfe66c9d95b259954b0b713ef983/3c492/27.png 1300w,
/static/f3e3cfe66c9d95b259954b0b713ef983/5fe07/27.png 3422w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;승부 예측 이벤트&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;8강부터는 라이브 행사로 대결을 진행하기로 했기에 승부 예측 이벤트도 기획했습니다. 토너먼트에 직접 참여하지 않거나 일찍 탈락한 분들도 시간이 흐를수록 치열해지는 승부를 재미있게 관람했으면 하는 바람에서였습니다.&lt;/p&gt;
&lt;p&gt;승부 예측의 참여 대상과 방법에 대해서도 희선님과 많은 논의를 거쳤습니다. 최종적으로 8강 대진 승부 예측 및 우승자 예측을 사전에 미리 받아서 그 결과에 따라 점수를 준 뒤 순위를 매기기로 결정했습니다. 희선님께서 사전에 구글 폼으로 설문을 받고, 설문 결과를 바탕으로 승부 예측 점수를 계산하는 스프레드시트를 작성해 주셔서 이벤트를 쉽게 진행할 수 있었습니다.&lt;/p&gt;
&lt;h3 id=&quot;라이브-행사&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%9D%BC%EC%9D%B4%EB%B8%8C-%ED%96%89%EC%82%AC&quot; aria-label=&quot;라이브 행사 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;라이브 행사&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b1a389c49e0a80bc604d5c6f5d98df16/2f5f2/4.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 71.16564417177914%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEBf/EABQBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhADEAAAAaF5Lw2Egx//xAAbEAEAAgIDAAAAAAAAAAAAAAABAAIDEhETIf/aAAgBAQABBQKuavDm0O68VrA2ie//xAAWEQEBAQAAAAAAAAAAAAAAAAARECH/2gAIAQMBAT8BXJ//xAAWEQEBAQAAAAAAAAAAAAAAAAARARD/2gAIAQIBAT8BCuf/xAAaEAEAAgMBAAAAAAAAAAAAAAABABECEDEh/9oACAEBAAY/AkOzwu9GQy3mv//EABoQAQACAwEAAAAAAAAAAAAAAAEAESFxgUH/2gAIAQEAAT8huCcexncxSE0PWLKXMTEm6INtz//aAAwDAQACAAMAAAAQEO//xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QWJmX/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/EJIa/8QAHRABAAICAgMAAAAAAAAAAAAAAQARIUExUYHR4f/aAAgBAQABPxBpRdoU3a788VBYBECzeez7HFXFvFBNrd8eyOUCw0aSZerloJ//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;행사 직전&quot;
        title=&quot;행사 직전&quot;
        src=&quot;/static/b1a389c49e0a80bc604d5c6f5d98df16/6aca1/4.jpg&quot;
        srcset=&quot;/static/b1a389c49e0a80bc604d5c6f5d98df16/d2f63/4.jpg 163w,
/static/b1a389c49e0a80bc604d5c6f5d98df16/c989d/4.jpg 325w,
/static/b1a389c49e0a80bc604d5c6f5d98df16/6aca1/4.jpg 650w,
/static/b1a389c49e0a80bc604d5c6f5d98df16/2f5f2/4.jpg 797w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;행사 직전 희선님과&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;어느덧 16강 결과까지 발표가 된 후, 저는 희선님과 오프라인에서 만나 8강 라이브 이벤트를 준비했습니다. 행사 30분 전부터 게더타운으로 방송 세팅을 시작했고, 어떤 방식으로 진행할지 논의했죠.&lt;/p&gt;
&lt;p&gt;사실 금요일 밤이라 혹시나 관람자가 적을까 봐 걱정했지만, 시간이 흐르자 20명 가까이 되는 분들이 참석해 자리를 빛내주셨습니다. 사람들이 하나둘 들어오는 것을 보니 긴장되고 목이 타더라고요.&lt;/p&gt;
&lt;p&gt;방송 시작 후에는 행사 소개와 함께 프롬프트 공유를 마친 후 본격적으로 대결을 시작했습니다. 제가 화면 공유를 통해 실시간 대전 결과를 방송으로 공유하는 동안, 희선님이 옆에서 다음 대결에 필요한 프롬프트를 미리 만들어 주셔서 꽤나 수월하게 진행할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/cbef11219b732db349d399a496712e65/898f6/28.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 83.43558282208589%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAACdklEQVQ4y01UiZaCMAz0/39QWJRDsLSAnAq6wmTfRGDlvTFNS6Y5Bg/zPCPPcyGcc2KMkaIoZNsjuMezpmmkLEsCt7rFre5wa3o0bYeyLIRch3me5Xo1iOIYSZIgjmOkaQZjDC6XC+IkgXUO4zhiHCc8Hg9ChmGQ1+sl87zIsixKBkAOIiLP51OJCJK4ooIra7jiBusqtbkrYfICJnew1iHNMvT9gPf7DcY/n09SQQl5K8nKsgLLadsebTegaTrUTYem7RVt16vPs3547Ouu68B2KCHz/C6BNxHj+JBpGmWaJvVpeU5w/36/6x7f4zlLZukHvhBFEX5+fhAEATzPx9Hz4Pu+4nQ64Xw+63kYhgijCMfjEZ7nIQhOa4yH6/X6yZBDqesaxuRwzqGqKrXWWhRlqS0oikJ9gufb+vV6gSTLsuhA+CghZRHHsSRJIibPhbcxgJKhTOq6VtlUVUXoPqXF9zaZsWU7IQMYyADa399fvZET5HqzzIR9+rKbZNQqIXsYBCe5pKmkacpbkaap9mS1Wh7ltOpUwjDiWs7ns4RhqJaZ6lDe77emPI4jM2J2nCSz0gw5vTXDzdeMtp59P7uwb7ebhFGkPSSYXZZl+Kz/+0swU1bCGMplkxwlpCXzhw6DgiBQa62VruuoNUzThL7vcb8/MAwqYumHQYkY17atfuP0d0KKNIpj8X2fGUiaZWKt0yy26XJw9GlJ8u3T9n3/T8h+sTQ2luWyp8ySpbHMLMsU9Hn59uVsYP85XCUkGYNza5XQrtaYj9Z4O3vETOhTViyxrhvdI+iv3/JHhwwikRLn+b4uinL9i5p3BazT3v1tTZDwDzF3CX8UNaJFAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;오류&quot;
        title=&quot;오류&quot;
        src=&quot;/static/cbef11219b732db349d399a496712e65/a6d36/28.png&quot;
        srcset=&quot;/static/cbef11219b732db349d399a496712e65/222b7/28.png 163w,
/static/cbef11219b732db349d399a496712e65/ff46a/28.png 325w,
/static/cbef11219b732db349d399a496712e65/a6d36/28.png 650w,
/static/cbef11219b732db349d399a496712e65/898f6/28.png 798w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;?? 아니 원래 안 그랬잖아요&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;하지만 예상치 못한 변수가 발생했습니다. 라이브 행사 진행 도중 &lt;strong&gt;Gemini가 갑자기 크롤링을 하지 못하는 사태&lt;/strong&gt;가 벌어진 것입니다. 글 링크를 입력했는데도 내용을 읽어오지 못하고 대결을 진행할 수 없다는 메시지를 뱉어냈죠. 행사 처음부터 문제가 생겼다면 그러려니 했겠지만, 이전 대결에서는 아무 문제 없이 잘 진행되었거든요.&lt;/p&gt;
&lt;p&gt;그래서 처음에는 일시적인 오류라고 생각했지만, 몇 번을 시도해도 똑같은 문제가 발생하는 상황이 이어졌습니다. 결국 대회가 잠시 중단되는 사태가 발생했습니다. 정확한 원인은 알 수 없었지만, 짧은 시간 내에 크롤링 요청을 너무 많이 호출해서 문제가 생긴 것 같았습니다. 수십 명이 라이브로 지켜보는 상황에서 대회가 갑자기 중단되니 상당히(…) 곤혹스럽더라구요. 리허설은 물론 이전에는 전혀 없었던 일이었습니다.&lt;/p&gt;
&lt;p&gt;결국 대회가 중단된 상황을 설명하고, 남은 대결을 진행할 수 있는 다른 AI 모델을 찾아보기로 했습니다. 그렇게 ChatGPT를 이용해 나머지 대결을 진행하기로 결정했죠.&lt;/p&gt;
&lt;p&gt;아쉽게도 구독 중인 ChatGPT는 유료 모델이 아니어서 추론 과정을 볼 수는 없었고, 단순 결과물만 받아볼 수 있었습니다. 라이브가 끝날 때까지 Gemini는 여전히 외부 글을 읽어오지 못했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/afa811c2bdcc82937285fda9d7d83d1f/3e096/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 88.95705521472392%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEf0lEQVQ4y2XP20/TBxjG8f4ZS5aNWSEO6hYzA4oCU47iHIqAPVfOCIVSoEfo6fcrtKUHi7QICIiKKKDMwUSGhjlkBieiEV2G0+yK7N/4LsCFzl08F+/F+8nzSDKUSWQoUsiUy8hUyshUyMhSpZBRvIv0E1LS8r7gm+zd7M9PIqtMyhFVIkeUu/lWtYdM5d6dH+XWz15Sv0tCsmdfMjbbBYRAjO7wFTydYXyRGapMy9SaH6LvWOVgXgMpB4rRO59RZ3lIlekRVu8DgpFLeAMDiP6LhKJXSU8vRJIoS0SVmY3L0ISx5DSOhloailQ0ty7S2PYIo3WNk0V6CrKLaLWu0tDyK82WJ9QrPVjUZVgrK7ZjVitJ/uxLJAlJUiqy0+nRaxBUhXTXqvGUZTBmOc2Yq4przgqmHAruOEoYd51l1FHJpOcsYW0WovYU/ooSAlWleLUnSE5IQpKwW0pN7mEC6lxERR6iPJtO1TEmbXLuiUruehTMi2rmvBruenbuOVFFtPp7hDM5eBW52xHkOcikKUgSEqVU5xwmoD2GoMjHqyzAo8jnuqWMu4KaSYeciNtCuKuLMWclMy45Mx41wfLjeOR5eJX52xHkuch2JX8Aagq223nlObjLspmwlrDQqWLWVUbA60cIjjAp1vKzUMq8qCSoK0A4k41XsdUy72Pw0HZDj+Ykoq4Yh7qYXoOKy2YN8VYV9qY67E16Yi06YgYll0xahLMluDVFCNoiRNXxnck7YCLVR9Pw16gxh19gDjzDFljB2PU75zyLVBn6aWgMYWgfx2yLExmYpy2whi30lAbbTZqc8zhM3Yilh5FJZTtgzdFUfDVaHH1vuTL1ksmwj5GhGezdMzjco1y+MMSQL0AwMkgoMER8eIlrfj8xby9mz0Mc1hhiafp7sHoLrNVhjawzMP6U4KVlBief4w7M4e9dJHR5GYurB398AYtjGk/fDC2BQXpGlhAHXmNvPY9YeugD8EgqgTodrcFXGJ3LCO5bmBwLNIsvaBbWaHcvEPBcQW9/gN75hKaOeXz+UazO+7R0b+AwfwRuTe6q0eLuf8f0/DoTvd3cmpih59o7+m6+5YebtxgK+/DHJzCYo4xO/MJ4NMT0xB36bm9iM4bxlv0HTKOzRkOjuIAQ/hH7+Sd0DrzA4PoJq3eBzouvaO5eot7Yhd5yB//AOh29rxBiq9ijr+kwRf8/2Veno8G9SGVNiDbjeQy229jd01iFWYy263S09WJpiWH2Pcfguoe97SIO9yzO+N+0t0Xeg18kJVKXk0awvhxnfIOpuTVi3VF6g31cGF2n7/pLxob7uTo4zI3ZlwixP4gOT9FlrGNq+gH905t0tEXxyTP4KnEvkk8+lyI/sA+7Rk6N8zGt4hINwm/Utd+nyfMUg2sFo3uJls4VWsXH6J2rNNrmqDo3Qqu4zDnnCk31PkzHU9n16R4kxfn7qS0qwKQporTwFF8f1OEY28R14x8MoXUs4T8xR/7CHH6DKfQGc2QDU2gDR3yT4vIhDu7PoU0np/50AeWFWfwL9+ZN7ptY6F0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;라이브&quot;
        title=&quot;라이브&quot;
        src=&quot;/static/afa811c2bdcc82937285fda9d7d83d1f/a6d36/3.png&quot;
        srcset=&quot;/static/afa811c2bdcc82937285fda9d7d83d1f/222b7/3.png 163w,
/static/afa811c2bdcc82937285fda9d7d83d1f/ff46a/3.png 325w,
/static/afa811c2bdcc82937285fda9d7d83d1f/a6d36/3.png 650w,
/static/afa811c2bdcc82937285fda9d7d83d1f/e548f/3.png 975w,
/static/afa811c2bdcc82937285fda9d7d83d1f/3c492/3.png 1300w,
/static/afa811c2bdcc82937285fda9d7d83d1f/3e096/3.png 1718w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;라이브 행사를 마무리하며&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;예상치 못한 방송 사고(?)가 있었지만, 다행히 많은 분들의 응원 덕분에 무사히 라이브 행사를 마무리할 수 있었습니다. 특히 실시간으로 올라오는 댓글들을 확인하는 게 진행하는 입장에서 재미있는 포인트였습니다. 댓글들은 나중에도 다시 읽어보고 싶어서 모든 내용을 저장해 두었죠.&lt;/p&gt;
&lt;p&gt;1시간 반 정도에 걸친 라이브 방송을 마치고, 희선님과는 서로 &lt;em&gt;진짜 고생 많으셨다&lt;/em&gt; 며 응원과 감사의 인사를 나눴습니다. 몸과 정신은 힘들었지만, 많은 분들께 즐거움을 드릴 수 있었다는 점에서 뿌듯함이 느껴졌습니다. 라이브에 참여하셨던 성윤님께서도 나중에 고생 많았다며 따로 선물까지 챙겨주셔서 정말 감사했습니다.&lt;/p&gt;
&lt;h3 id=&quot;최종-우승자-공지&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B5%9C%EC%A2%85-%EC%9A%B0%EC%8A%B9%EC%9E%90-%EA%B3%B5%EC%A7%80&quot; aria-label=&quot;최종 우승자 공지 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;최종 우승자 공지&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/aded4645999d3c1dd93da7291ab6b65e/41d3b/29.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 46.62576687116564%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABgklEQVQoz42SzZKbMBCE/f6vk2POOecQb9a7gP6QQEZgsDESxt6elERh55BDpqprZnT41NLM7tv3H1QUjCpdwtojVN1Rf74geI8QArz3mKbpmaPmeQYRbUoBIGmHx404Zzhkgt4/C+IsB2MMSikqy5KUUrEnKSQVeZHqeO6co77vEfMwDBuXdvGSkytJaku6aihMZ/qf2BxhjRfwC4TBlcQFxz4TUKqEti1yZZMyacHKYzqz7gRzbOG6HuM4YlnuePG3JxOhKRkVTGCfKwghUNo2gWTlwHSDTEVgl4BV06Fu1hzmG56015MJ48mQMRpc6vQn4+QxXK7oz2PK3oc0oKg4kNs8Yw4Bj8fjCdyYuy8AzkhiQuJXYcA5xzsz+HlQeCs09rnG78Lgg1fIZI3q2CY17Qn3+/3fDrua0+fHAUqbdVXCjOhy8gHXqCms9bT2l6vHdfJYlmVjvRzGwjmHuApVZUgIQc+VkRLxK7SpoIyFMYakFGRtTcPQU9d19JfLBPwDdBasPJNtNiwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;최종 우승자 공지&quot;
        title=&quot;최종 우승자 공지&quot;
        src=&quot;/static/aded4645999d3c1dd93da7291ab6b65e/a6d36/29.png&quot;
        srcset=&quot;/static/aded4645999d3c1dd93da7291ab6b65e/222b7/29.png 163w,
/static/aded4645999d3c1dd93da7291ab6b65e/ff46a/29.png 325w,
/static/aded4645999d3c1dd93da7291ab6b65e/a6d36/29.png 650w,
/static/aded4645999d3c1dd93da7291ab6b65e/41d3b/29.png 774w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;치열한 경쟁을 뚫은 최종 우승자 공지&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;행사가 끝난 후에는 최종 대진표를 업데이트하고 각 토너먼트의 우승자를 공식적으로 발표했습니다. 그리고 축하의 인사와 함께 상품도 전달해 드렸습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/296dc1c10450ec5ae2357323a4dea103/3fe45/30.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 85.88957055214723%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAAC6klEQVQ4y11UaY+jMAzl//+u/bKXNGpnhqOc4QxQAiTQA5q3sqsZVVvJcvxCHPs9p866ruj7HkoptvP5zH5ZFoxqxDiOmOcZWpvv/Va2GIaB974wim+3G5yu6+B5Hnzfh+u6CMMQSZJYij8+PqwQwsZxZE/BCVEUWa01pmmCMQbGLHyxMZr9tm1wBqVwOp0QxzGSOIYQGbIsg+95Ns9ztLJGnnqoqtLWdQNKSFVRRVI2qGuJRnagwiipo4aBDiOKYoRRDM8P7CkI7K+fv1A0vW3Oo1VK2bZtqTVL7dHhvqckZ4ydgFE5tFnx2Hc4VdfhjxugyEN0skAvc5tluSXepuVqR3Oxxiz2yaPmlskonvWCyyxxNxKX6x30c+bFQDQS89hj0QqrUSzAvu92u9/Btm1kdt93wnG/39kTfr09cL1t2PcNj8cDzmVdkWcZ0jTDKYwQBCHSNLVJkiDLhA3D0HqexzGJRaIFQQDfDxAGn0hObxjHCcti+CKHxiZNU5RlibqqnuIkCWMkCuEk0qvlQiBJUogsQpH5UOo5PtZaOCS/57rIxfNwFEVcAc0Y7V0uF6zL+j0qFJOaxCGNzTRrjEphnvUzIWX2fB8iz1EUBdIk5SopMcWkLiWvqgpSStR1zeumadC1LWP0MAhnDudxRBaFEGGCKGT+OAkduF6vrBzdTB9/+VcjjIxE4gofpJTR0L2CniYs64LX39eB/9ev8SvmEBfEXVEW3Aq1ycTnORvFZEII/o48tUdeNpJbpm6qqmCOnb7r8P7hwg9CHI9HHA9HFuXz85PX7+/vjB8OB17TM6V3Tvue6zF+PB7w9vcH9DzBoSczVm/QzRsrSP8Y5NnWCyv5hVMFxCvF5GnkCJu1xrLeni0Pg4KIXeSJxy1Rm00jn+2XFapuQqsMmvOMup9RtiOvy25GUbd8pm0q1EWEbbs9x0aIAk3TfnNDyYhH8jRObdux0QVxnKCsarYn3zkGmWJpfmO/afwDsxj6hfaFAKMAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;우승자 소감&quot;
        title=&quot;우승자 소감&quot;
        src=&quot;/static/296dc1c10450ec5ae2357323a4dea103/a6d36/30.png&quot;
        srcset=&quot;/static/296dc1c10450ec5ae2357323a4dea103/222b7/30.png 163w,
/static/296dc1c10450ec5ae2357323a4dea103/ff46a/30.png 325w,
/static/296dc1c10450ec5ae2357323a4dea103/a6d36/30.png 650w,
/static/296dc1c10450ec5ae2357323a4dea103/3fe45/30.png 699w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;수상자 분들이 소감도 남겨주셨다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;우승자분들께는 축하의 인사와 함께 상품을 전달해 드렸고, 감사하게도 우승 소감도 남겨주셨습니다. 또한, 라이브 방송 시 진행했던 대결 결과물까지 대시보드에 모두 업데이트하면서 글드컵의 모든 일정을 성공적으로 마무리했습니다.&lt;/p&gt;
&lt;h2 id=&quot;후기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%9B%84%EA%B8%B0&quot; aria-label=&quot;후기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;후기&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b0f5298be3b09323091857d5c62b24f1/71c1d/1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.87116564417178%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAADBklEQVQozy2R6VMScQBA+eP6Uh+6L6sZM2MQtBW3kNVx2ZvlSGU8IBcXNZAQNEMQKCGVMLMCFBhIlvWY0kxLk8omBH6NTX/AmzfznqQismVBe5Sj95LkTpz4/E5TTOMHKWo/RW0toQcr+H6K+rZCHaaJwxT+LUkcZqgvcayYwauiVlIW6LJAPxmEug3yqVF4zNZs7WscMTfuxbFRXjnKQ1yvotPQ0NcpN5sUXD/E9SiGLdBuggRrjKQisscC8yNDJEKIg1PuJcmjLLX4HPeNawqBlgiv+JVjDtP0XhLfiLZmvE37KfpHhqgIdKXwz3ycZ8C2LuTGTDrka5oEn2ibo1vZ5fRqpCH56Rm78ihPgh39ynTbBHlj85UabOrLBbYs0JJjQQc26GkvXTfgQTmLMKf5k8OGHL3vF6ayyWD6pRPtHGik9NlX+EyfdAE+ZSahYl5fzZNlgZGU8jRYZyacqLmXGLGyCx71nBsyWc1L0afLryd3xPmt1Qike+SwtIzzWMAoDfAtpQ22Kv43a8GmLhm4P/u4fsjc6h1S+OzN3bxtNeGPRtzx2MTC3DOYfThmlaEk7BpoYCmp2waDAlU5gfN0VdQexJGHRM2pyzWvPXVv/CqL3b6eDmXf+8V0aDUzjxjYN57a87W3n1pqEuMqvgspnQRjJCVBCz7qloLIuZq68CgMNtHYc51zYmxx1uVyDcbCzkmvGzcZwBohRuBp2z31MIo6qe8pHBSYk9p/BGqWa4h0NISd9KIPC461mXiug9JBTfLSdnTS/8zYR4DP2re+FpPmGjvINPPYdoI4+QzW2d0klrKdC5K37T2tQfuDsEMR86tv9lPtRnR+5kmXfdLKo2DX8GGmKcRdZjuxq+3I7xxZFRlJtUAXM5RRK7tYL7tUf+fTi1vLL5C3I1doF9QxrHVzJMao3wURsKUXZpunuAvX4LYz8vafWQaIjASs6YsZatknDw9dNxulO3N3j7MdLov0zv3aszLY80gZc8riARXYNuRCqn78bivaqCJUuagGbDB/AZid/1kakSjJAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;포스터&quot;
        title=&quot;포스터&quot;
        src=&quot;/static/b0f5298be3b09323091857d5c62b24f1/a6d36/1.png&quot;
        srcset=&quot;/static/b0f5298be3b09323091857d5c62b24f1/222b7/1.png 163w,
/static/b0f5298be3b09323091857d5c62b24f1/ff46a/1.png 325w,
/static/b0f5298be3b09323091857d5c62b24f1/a6d36/1.png 650w,
/static/b0f5298be3b09323091857d5c62b24f1/e548f/1.png 975w,
/static/b0f5298be3b09323091857d5c62b24f1/3c492/1.png 1300w,
/static/b0f5298be3b09323091857d5c62b24f1/71c1d/1.png 1536w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;행사의 진행&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글드컵은 모든 과정이 온라인으로 이루어졌지만 준비 기간을 포함해 2명이서 약 한 달 동안 준비한 꽤나 큼지막한 행사였습니다. 그래서인지 준비 과정이 힘들기도 했지만 그만큼 느낀 점도 많았습니다.&lt;/p&gt;
&lt;p&gt;우선은 &lt;strong&gt;제가 떠올린 엉뚱한(?) 아이디어를 실제로 구체화하고 성공적으로 실행에 옮길 수 있었다는 점&lt;/strong&gt;에서 큰 뿌듯함을 느낍니다. 특히 제가 아끼고 애정하는 커뮤니티의 마무리를 기념하는 행사가 되었다는 점, 그리고 시간이 갈수록 경쟁이 치열해지면서 많은 분들이 흥미진진하게 지켜봐 주셨다는 점, 긴장감 넘치면서도 즐거운 대결 경험을 제공할 수 있었다는 점이 기억에 남습니다.&lt;/p&gt;
&lt;p&gt;다만, &lt;em&gt;‘한 번 쓰고 말 것’&lt;/em&gt; 이라는 생각으로 진행하다 보니 많은 작업들을 수동으로 처리하게 됐는데, 그것들이 생각보다 손이 많이 갔다는 점은 아쉬운 포인트로 남습니다. 물론 필요했다면 이런 작업들을 자동화할 수도 있었겠지만, 일회용 코드를 짜는 것도 귀찮아서 그렇게 하지 않았죠. 만약 &lt;strong&gt;대회 템플릿 자체를 자동화&lt;/strong&gt; 할 수 있었더라면, 이런 대회를 더 자주, 더 쉽게 열 수 있을 것이라는 생각이 듭니다. 예를 들자면 매 제출 회차마다 토너먼트 대결을 진행하는 식으로요.&lt;/p&gt;
&lt;p&gt;기술적으로는 &lt;strong&gt;AI를 이렇게까지 행사에 실용적으로 활용할 수 있다&lt;/strong&gt;는 것을 직접 경험하며 크게 느꼈습니다. 포스터 제작부터 홍보 문구 제작, 나아가 기획, 디자인, 개발 전반에 걸쳐 AI가 얼마나 큰 도움을 줄 수 있는지 확인하는 계기가 되었습니다. 이는 우리 일상과 업무에 AI가 어떻게 활용될 수 있는지에 대한 좋은 사례가 되었다고 생각합니다. 사실 애초에 AI가 없었다면 이 행사의 진행이 불가능하기도 했구요.&lt;/p&gt;
&lt;p&gt;이렇게 해서 AI와 함께한 글쓰기 토너먼트 대회, 글드컵의 준비 과정과 진행 후기를 마치고자 합니다. 이번 행사의 진행과 기획을 함께 도와주신 희선님께 특히나 더더욱 감사하다는 말씀을 전하면서 글을 마무리하겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[나의 청춘을 함께한 커뮤니티, 글또를 졸업합니다]]></title><description><![CDATA[2019년부터 함께한 글 쓰는 개발자 커뮤니티, 글또를 마무리하며 쓰는 회고입니다.]]></description><link>https://wormwlrm.github.io/2025/05/11/Adios-Geultto.html</link><guid isPermaLink="false">https://wormwlrm.github.io/2025/05/11/Adios-Geultto.html</guid><pubDate>Sun, 11 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a6a89055ca74a986208d414d86fa354d/bc3ae/1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 55.828220858895705%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAADGklEQVQozyXM7VPSBwDA8d8/sDdID+fmbXmXe/JW07y00GkBYmm5PKM8aTV2TlmmjglCjgjNBxKfUJ584MEsMbFERBiYJWt6ZdquaO32qhf7O77bbS8+bz/CZGwD/cwaTeMxVMNRjrQvUVpzHevFk5iqJWgqS+htPM8ZpY7cahviaj+i6hn2VE6RJR8ku6ybT4oNHDzewYGvLAjjkSd4YylaPXEqe1eQmsN8+M0Cn52zE+rvok15liM52YxeKudijQaxzE1OqZlciZ6io03kSIxklfawV2ZHLHchOCJP6FlYR+OJo7y9isy0zOcN8+Srpnkz5yJkaiazoJFs+SgfHzNQWlDP4cJmskqt7JO5EJdPIFJMkVE+gVjuRgjEU3QFH9HqTVLbt0KRdpFPvwty+IIP/00LqcAotzoHyc9Tk1uiI1dmIbPCjUjhRSR1IzrhZI/M9Z8MqROh8+4aGmeCSksExY1lKrqjlN2Mc0hhpfHqIOm3z3n31ybN5hnek06z/7Qfcfkk+yo8HFIFkDTd4/2qSTKkLkQnHQgaR4wWd4LT5giF7RHyWh6gVHXivXqZ3Y0Iuy+32N7+ld0XGxTWeRDLJ1CZH2KYesT3Y0mqLGG+aLiHWOr8P7T4VvEuxtA5VlBc6kd16ltsOiPbd8d4trlOh9mLf2aJv9+9oG9sgb2KCTpcK5htLn42GDFq9ZzS+vmgdpaME2MI3bftLNtu8Nhtw9umITx8i82FGXa8Q8yZjfT1e3n6W4q3b7ZIrCWo+nGWOmsU7TUdhopjnC/+kh/OyjnTMIBcH0Job7lOa109tcormPwJfKEoI44AhoE7PJ628+dOklfpLX5/+ZSd5+uoB5e43BUk5XPyR9DJkF5DfpGCkivjSNrmEHoH3JTo5pC2+1HaYlywrVI/kkA9nuCaNUj8lwTp9DNev94k/SpF03CYjqEga24bkR4DqTY1R2t6yawN8NHXDgR1/33y2h9QZlqmWB/iuPY+nfYAYx4Hs34X8fA8ydgiG+tRkvEw2pF5Gp2rqG0h3HkFRPeLOSf/iUyljwP/hv8AcKccO46uinIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;히로시의 회상&quot;
        title=&quot;히로시의 회상&quot;
        src=&quot;/static/a6a89055ca74a986208d414d86fa354d/a6d36/1.png&quot;
        srcset=&quot;/static/a6a89055ca74a986208d414d86fa354d/222b7/1.png 163w,
/static/a6a89055ca74a986208d414d86fa354d/ff46a/1.png 325w,
/static/a6a89055ca74a986208d414d86fa354d/a6d36/1.png 650w,
/static/a6a89055ca74a986208d414d86fa354d/e548f/1.png 975w,
/static/a6a89055ca74a986208d414d86fa354d/bc3ae/1.png 1268w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;글또와 함께 성장한 내가 주요 글감이 될 거라 &lt;a href=&quot;https://www.youtube.com/watch?v=nEh432koJH4&quot;&gt;히로시의 회상&lt;/a&gt;을 BGM으로…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;2019년부터 함께 했던 글 쓰는 개발자 커뮤니티 &lt;a href=&quot;https://geultto.github.io/&quot;&gt;글또&lt;/a&gt;가 올해 3월, 10기를 마지막으로 공식적인 활동을 마무리했습니다. 햇수로 7년이라는 시간, 제 개발 인생의 거의 90%를 함께했으니 &lt;em&gt;꽤 오랜 시간&lt;/em&gt; 이라는 말로는 부족할 만큼 깊은 인연이었죠.&lt;/p&gt;
&lt;p&gt;글또가 10기로 종료된다는 소식은 이미 공공연히 알려져 있었기에 막상 끝났을 때 감정의 동요가 크지는 않았습니다. 하지만 오랜 시간 정들었던 학교를 졸업하는 것처럼 시원섭섭한 마음이 드는 것은 어쩔 수 없더군요.&lt;/p&gt;
&lt;p&gt;돌이켜보면 처음 글또에 참여했을 때 남다른 마음가짐이 있었습니다. 나와 비슷한 관심사를 가진 사람들을 만난다는 호기심, 누군가 나의 글을 읽고 알아봐 줬으면 좋겠다는 기대감, 이직한 회사에서 인정받고 싶다는 욕심, 당장 한 사람의 몫을 해내고 싶다는 절박함…&lt;/p&gt;
&lt;p&gt;이런 노력이 반드시 성공적인 커리어로 이어질 것이라는 강한 믿음으로 자기소개를 했던 때가 엊그제 같은데, 시간이 흘러 이제는 사회에서 어느 정도 자리도 잡았고 한 분야의 엔지니어로 인정받게 된 지금, 그때의 간절함이 떠올라 감회가 새롭네요.&lt;/p&gt;
&lt;p&gt;글또를 한 마디로 정의하라면 정말 많은 생각들이 떠오릅니다. 나의 꿈, 나의 커리어, 나의 성장, 나의 열정, 나의 러닝 메이트, 나의 20대… 이것들을 한꺼번에 담을 수 있는 단어로 표현하자면 &lt;strong&gt;나의 청춘&lt;/strong&gt; 이라고 말할 수 있겠네요.&lt;/p&gt;
&lt;p&gt;지금의 저를 만드는 데 큰 영향을 준 글또의 마무리를 기념하고, 함께했던 소중한 추억을 발판 삼아 앞으로의 계획을 세우기 위해 이번 회고를 시작합니다. 이 글이 저처럼 &lt;strong&gt;글 쓰는 개발자 커뮤니티 글또를 궁금해하셨던 분&lt;/strong&gt; 들께 도움이 되기를 바랍니다.&lt;/p&gt;
&lt;h2 id=&quot;글또에-참여하게-된-계기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90%EC%97%90-%EC%B0%B8%EC%97%AC%ED%95%98%EA%B2%8C-%EB%90%9C-%EA%B3%84%EA%B8%B0&quot; aria-label=&quot;글또에 참여하게 된 계기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또에 참여하게 된 계기&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExbmg5dzJyeXlocWZmZHIxMGJibWQxazRyYzFxcDFpazRpMDkxMDFsZiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/LpQuxhwDhzLCEKVYFh/giphy.gif&apos; alt=&apos;혼자는 외로워&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;혼자는 외로워&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;저는 개발 블로그를 시작하면서부터 &lt;strong&gt;함께 글 쓰는 커뮤니티&lt;/strong&gt; 에 대한 막연한 갈증을 느끼고 있었습니다.&lt;/p&gt;
&lt;p&gt;2018년 7월, 처음 기술 블로그를 개설하고 1년간 16개의 글을 꾸준히 발행했습니다. 내용을 잘 정리한 덕분에 포트폴리오의 역할도 겸했고 이직 과정에서 도움을 받기도 했으니, 분명 블로그 활동은 저에게 긍정적인 경험이었죠.&lt;/p&gt;
&lt;p&gt;하지만 글을 쓰는 과정은 늘 외로웠습니다. 방구석이나 집 근처 카페에 틀어박혀 밤늦도록 씨름한 끝에 글 하나를 완성하고 발행 버튼을 눌러도, 마치 메아리 없는 외침처럼 아무런 반응이나 피드백이 없는 경우가 대부분이었죠. 내 경험과 시간을 담아 힘들게 쓴 글이 그저 인터넷 세상 어딘가에 떠다니는 데이터 쪼가리(?)처럼 느껴질 때가 많았습니다.&lt;/p&gt;
&lt;p&gt;그러다 보니 &lt;em&gt;‘나처럼 꾸준히 기술 블로그를 쓰는 사람이 또 있을까?’&lt;/em&gt;, &lt;em&gt;‘이런 사람들이 모여 서로 격려하고 피드백을 주고받으며 함께 성장하는 모임은 없을까?’&lt;/em&gt; 이런 고민들이 머릿속을 맴돌았습니다. 점점 지쳐가던 저는 자연스레 개발자들이 모여 글을 쓰는 커뮤니티를 찾아 나서기 시작했습니다.&lt;/p&gt;
&lt;p&gt;그러던 중 우연히 페이스북 그룹을 통해 글또라는 커뮤니티의 존재를 알게 되었습니다. 당시에는 이미 진행 중인 기수가 있어서 당장 참여할 수는 없었지만, 글또 그룹에 제가 쓴 글들을 공유하며 다음 기수가 열리기만을 손꼽아 기다렸습니다. 이것이 제가 글또와 인연을 맺게 된 첫걸음이었죠.&lt;/p&gt;
&lt;h2 id=&quot;글또-3기---첫-만남&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-3%EA%B8%B0---%EC%B2%AB-%EB%A7%8C%EB%82%A8&quot; aria-label=&quot;글또 3기   첫 만남 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 3기 - 첫 만남&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0cd5dbe3712ccd6d7043b14b12989723/6a068/2.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAQP/xAAVAQEBAAAAAAAAAAAAAAAAAAACAf/aAAwDAQACEAMQAAABWypwFUK4h//EABoQAAIDAQEAAAAAAAAAAAAAAAACAQMiExT/2gAIAQEAAQUCipRUQmlIJp6Hn1lT/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAESMf/aAAgBAwEBPwGlhZ//xAAXEQADAQAAAAAAAAAAAAAAAAAAARES/9oACAECAQE/AY5TB//EABkQAAIDAQAAAAAAAAAAAAAAAAABAhEhEv/aAAgBAQAGPwLZc4bJmyZ02xFUf//EABoQAQEBAAMBAAAAAAAAAAAAAAERACFBUWH/2gAIAQEAAT8hccyri+Z3rneRl/x16o9Vw5Uhy4Rx/9oADAMBAAIAAwAAABB4P//EABcRAQEBAQAAAAAAAAAAAAAAAAERADH/2gAIAQMBAT8Qg13JGb//xAAVEQEBAAAAAAAAAAAAAAAAAAABAP/aAAgBAgEBPxAaBpf/xAAdEAEAAwEAAgMAAAAAAAAAAAABABExIVFxgaHB/9oACAEBAAE/EBgsVS1VXzBjiQwaN/kQ+Y0p9DEt8ouB6CAwUj2q2iEKlNQ5P//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;역삼&quot;
        title=&quot;역삼&quot;
        src=&quot;/static/0cd5dbe3712ccd6d7043b14b12989723/6aca1/2.jpg&quot;
        srcset=&quot;/static/0cd5dbe3712ccd6d7043b14b12989723/d2f63/2.jpg 163w,
/static/0cd5dbe3712ccd6d7043b14b12989723/c989d/2.jpg 325w,
/static/0cd5dbe3712ccd6d7043b14b12989723/6aca1/2.jpg 650w,
/static/0cd5dbe3712ccd6d7043b14b12989723/6a068/2.jpg 960w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;2019년 9월, 역삼 자취방 근처의 북카페에서&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;그렇게 저는 2019년 7월부터 12월까지 글또 3기 멤버로 정식 활동을 시작했습니다. 글또 합류를 간절히 기다렸던 만큼 기대가 컸던 시기였죠.&lt;/p&gt;
&lt;p&gt;글또의 운영자이신 성윤님께서는 첫 제출 글은 다짐글을 권장하셨고, 이에 따라 저는 지난 1년간의 기술 블로그 활동을 돌아보는 &lt;a href=&quot;/2019/07/05/First-anniversary-from-starting-blog.html&quot;&gt;『개발 블로그 1년 째, 나는 어떻게 바뀌었을까』&lt;/a&gt; 글을 첫 글또 글로 제출했습니다. 그리고 6개월의 활동 기간 동안 저는 총 &lt;strong&gt;11개의 글&lt;/strong&gt;을 작성하며 꾸준히 기록을 이어나갔습니다.&lt;/p&gt;
&lt;p&gt;3기 때 썼던 글은 &lt;strong&gt;회사에서 새롭게 배운 지식&lt;/strong&gt; 과 &lt;strong&gt;사이드 프로젝트&lt;/strong&gt; 위주로 작성했습니다. IT 산업기능요원으로 두 번째 회사에 이직한 지 얼마 되지 않았을 때였거든요. 새로운 환경에서 배울 것들이 정말 많았고, 야근도 잦았지만 신기하게도 개발에 대한 열정과 체력이 넘쳐나던 시기였습니다. 그때의 저는 팔팔한 스물네 살이었거든요… 😇&lt;/p&gt;
&lt;p&gt;물론 힘들고 지친 날도 있었지만, 회사에서의 동료들이 기술 블로그를 운영하는 저를 많이 응원하고 격려해 주셔서 더욱 힘이 났던 것 같습니다. 그 덕분에 글을 쓰고 공유하는 것이 즐거웠던 기억이 나네요.&lt;/p&gt;
&lt;p&gt;3기 활동을 하면서 기억나는 에피소드들을 잠깐 소개해보자면요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;처음으로 오프라인 모임에 참여해 봤습니다. 내향적인 성격이었던 제가 큰 용기를 낸 것이었죠. 온라인으로만 소통하던 분들을 실제로 만나 함께 이야기 나누고 서로의 글에 대해 피드백했던 시간이 제게 큰 동기 부여가 되었습니다. 멋진 회사에 다니는 분들이 많아서 &lt;em&gt;‘나도 언젠가는 저런 회사에 갈 수 있을까?’&lt;/em&gt; 하고 내심 부러워했던 기억이 나네요.&lt;/li&gt;
&lt;li&gt;사이드 프로젝트를 2개 진행했습니다. 하나는 &lt;a href=&quot;/2019/07/21/Military-Service-Calculator-Development-Story.html&quot;&gt;Vue.js 기반의 크롬 확장 프로그램을 만든 것&lt;/a&gt;, 나머지는 &lt;a href=&quot;https://wormwlrm.github.io/2019/10/13/Kwakcheolyong-Image-Creator-Development-Story.html&quot;&gt;곽철용 짤 생성기&lt;/a&gt; 입니다. 곽철용 짤 생성기는 아직까지 제 &lt;a href=&quot;https://github.com/wormwlrm/kwakcheolyong&quot;&gt;깃허브의 리포지토리 스타 수 1위&lt;/a&gt;를 기록하고 있습니다. 😎&lt;/li&gt;
&lt;li&gt;기수 중간에 훈련소를 다녀왔습니다. &lt;a href=&quot;/2019/12/11/Review-of-Korean-Army-Traning-Center.html&quot;&gt;그 후기&lt;/a&gt;도 블로그에 올려두었죠. 성윤님께 미리 말씀드려 제출 패스를 예약하고 다녀왔지만, 훈련 후 돌아와서 다음 회차 글을 도저히 쓸 엄두가 나지 않아서 눈물을 머금고 미제출을 했던 쓰린 기억이 나네요.&lt;/li&gt;
&lt;li&gt;글또 활동 범위를 넘어선 &lt;a href=&quot;/2020/01/11/Review-of-hackathon-mentor.html&quot;&gt;외부 멘토링 경험&lt;/a&gt;을 처음 해보기도 했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;글또-4기---책-집필-도전&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-4%EA%B8%B0---%EC%B1%85-%EC%A7%91%ED%95%84-%EB%8F%84%EC%A0%84&quot; aria-label=&quot;글또 4기   책 집필 도전 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 4기 - 책 집필 도전&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/edc4e8335d69d156aa9bf363e5f72523/3e9cd/3.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.12883435582822%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQCAwUG/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAGx/nNcYLCOZ0knpZEzOv/EAB0QAAICAQUAAAAAAAAAAAAAAAECABESAxMhMkH/2gAIAQEAAQUCTssPLbrgrrDFapELEoFXBaBqLPP/xAAXEQADAQAAAAAAAAAAAAAAAAABAhBB/9oACAEDAQE/AYF2f//EABkRAAEFAAAAAAAAAAAAAAAAAAABAhARQf/aAAgBAgEBPwGFdhZ//8QAHBAAAgICAwAAAAAAAAAAAAAAAAEQIQIRMUGR/9oACAEBAAY/As4cLbucVvizv0oYj//EABwQAQACAgMBAAAAAAAAAAAAAAEAESExUWGBQf/aAAgBAQABPyFIfQwNGYfRBGtsA6CxUutrPMxyjtiDNLCoUNb4pEBarmJT6Sjwn//aAAwDAQACAAMAAAAQoCzB/8QAGBEAAwEBAAAAAAAAAAAAAAAAAAERITH/2gAIAQMBAT8Q6Qc1oiP/xAAYEQEBAAMAAAAAAAAAAAAAAAABABARIf/aAAgBAgEBPxB5ghm1/8QAHhABAAIBBQEBAAAAAAAAAAAAAQARITFBUWFxgZH/2gAIAQEAAT8QGe6PwjBwKN+oiTJhLSAFKXb1rKVEWGHx8lyqsndfcKKf0YhZZaj4EKnIpjrxLfLKajbzKWuV+xZUz37Z/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;역삼 스타벅스&quot;
        title=&quot;역삼 스타벅스&quot;
        src=&quot;/static/edc4e8335d69d156aa9bf363e5f72523/6aca1/3.jpg&quot;
        srcset=&quot;/static/edc4e8335d69d156aa9bf363e5f72523/d2f63/3.jpg 163w,
/static/edc4e8335d69d156aa9bf363e5f72523/c989d/3.jpg 325w,
/static/edc4e8335d69d156aa9bf363e5f72523/6aca1/3.jpg 650w,
/static/edc4e8335d69d156aa9bf363e5f72523/7c09c/3.jpg 975w,
/static/edc4e8335d69d156aa9bf363e5f72523/3e9cd/3.jpg 1058w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;2020년 4월, 역삼 자취방 근처의 스타벅스에서&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글또 3기를 성공적으로 마무리하며 글쓰기의 즐거움과 커뮤니티의 가치를 깊이 느꼈기에, 2020년 3월부터 8월까지 이어지는 글또 4기에도 참여를 결정했습니다.&lt;/p&gt;
&lt;p&gt;가장 큰 이유는 글또가 제가 찾던 &lt;strong&gt;글쓰기 자체에 온전히 집중할 수 있는 최적의 환경&lt;/strong&gt;이라고 판단했기 때문입니다. 글쓰기를 위한 기본적인 규칙은 제공하지만 적극적인 오프라인 모임 참여가 필수가 아닌 점이, 저에게는 부담 없이 몰입할 수 있는 환경으로 다가왔거든요.&lt;/p&gt;
&lt;p&gt;4기 동안 저는 총 &lt;strong&gt;10개의 글&lt;/strong&gt;을 작성했습니다. 하지만 3기 때와는 달리 글감을 미리 충분히 확보해두지 못해, 마감일이 다가올 때마다 소재를 짜내느라 유독 힘들었던 기억이 강하게 남아 있습니다. 때마침 코로나19로 인한 팬데믹이 시작되어 모두가 혼란스럽고 오프라인 활동이 어려워지면서 외부 경험을 통해 새로운 글감을 얻는 것도 쉽지 않았던 시기였죠.&lt;/p&gt;
&lt;p&gt;이때도 글쓰기 자체에 대한 열정은 있었지만, &lt;em&gt;무엇을 쓸까&lt;/em&gt; 가 큰 숙제였습니다. 이러한 어려움 속에서 창의적인 소재를 찾기 위해 여러 시도를 해보았고, 그래서인지 4기 때 작성한 글들은 &lt;strong&gt;적극적인 오픈소스 활동 경험, 새롭게 등장하는 기술 트렌드 분석, 그리고 독창적인 비유&lt;/strong&gt;를 활용하는 시도가 돋보이는 글들이 많았습니다. 가장 대표적인 글로 &lt;a href=&quot;/2020/08/12/History-of-JavaScript-Modules-and-Bundlers.html&quot;&gt;『JavaScript 번들러로 본 조선시대 붕당의 이해』&lt;/a&gt; 가 있죠.&lt;/p&gt;
&lt;p&gt;4기 활동을 하면서 기억나는 에피소드들을 잠깐 소개해보자면요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;2년 간의 &lt;a href=&quot;/2020/06/07/Review-of-Skilled-industrial-personnel.html&quot;&gt;IT 산업기능요원 복무를 성공적으로 마무리&lt;/a&gt;했습니다.&lt;/li&gt;
&lt;li&gt;글또를 함께한 &lt;a href=&quot;https://jay-ji.tistory.com/&quot;&gt;찬규&lt;/a&gt;님의 제안으로 개발자로서의 성장 과정을 에세이로 집필하는 프로젝트를 시작했습니다. 출판이라는 거대한 프로젝트는 혼자서는 엄두도 못 냈을 일이었지만 글또라는 커뮤니티의 다른 분들과 함께했기에 용기를 낼 수 있었습니다.&lt;/li&gt;
&lt;li&gt;당시 글또 4기를 함께 하고 있던 &lt;a href=&quot;https://soobing.github.io/&quot;&gt;수빈님&lt;/a&gt;과 같은 팀으로 일했던 경험이 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;글또-5기---이직과-복학&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-5%EA%B8%B0---%EC%9D%B4%EC%A7%81%EA%B3%BC-%EB%B3%B5%ED%95%99&quot; aria-label=&quot;글또 5기   이직과 복학 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 5기 - 이직과 복학&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/147d7732e9a8e89d04baceaf51a041bf/e2d85/4.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAUCAwQG/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQD/2gAMAwEAAhADEAAAAdNyWUOjngf/xAAaEAEAAwADAAAAAAAAAAAAAAACAQMRABIT/9oACAEBAAEFAleBJcI7yxBP16mb53//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwGI/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8Bqv/EABwQAAICAgMAAAAAAAAAAAAAAAABAhESMUFCkf/aAAgBAQAGPwLFuVlpyo7GVsSjo59P/8QAGhAAAwEBAQEAAAAAAAAAAAAAAAERMSFRkf/aAAgBAQABPyHnVK4I1kR79G3smEtCaLG3R3iR/9oADAMBAAIAAwAAABCPH//EABURAQEAAAAAAAAAAAAAAAAAAABx/9oACAEDAQE/ECn/xAAXEQADAQAAAAAAAAAAAAAAAAAAARFR/9oACAECAQE/EGxWH//EABwQAQEBAAEFAAAAAAAAAAAAAAERACExQVFxof/aAAgBAQABPxBJDCCuHJODRWcYn18XhILjGe8SunPDbaE76ih8Dfu//9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;역삼 스타벅스&quot;
        title=&quot;역삼 스타벅스&quot;
        src=&quot;/static/147d7732e9a8e89d04baceaf51a041bf/6aca1/4.jpg&quot;
        srcset=&quot;/static/147d7732e9a8e89d04baceaf51a041bf/d2f63/4.jpg 163w,
/static/147d7732e9a8e89d04baceaf51a041bf/c989d/4.jpg 325w,
/static/147d7732e9a8e89d04baceaf51a041bf/6aca1/4.jpg 650w,
/static/147d7732e9a8e89d04baceaf51a041bf/7c09c/4.jpg 975w,
/static/147d7732e9a8e89d04baceaf51a041bf/01ab0/4.jpg 1300w,
/static/147d7732e9a8e89d04baceaf51a041bf/e2d85/4.jpg 1411w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;2020년 11월, 해변이 보이는 강릉의 한 카페에서&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글또 5기는 2020년 11월부터 2021년 5월까지 활동했습니다. 이 시기는 제 인생에서 두 가지 큰 변화가 동시에 일어났던 때입니다. 바로 &lt;strong&gt;반려동물 모니터링 서비스를 개발하는 스타트업으로의 이직&lt;/strong&gt;과 &lt;strong&gt;대학교 복학&lt;/strong&gt;이었죠.&lt;/p&gt;
&lt;p&gt;저는 인원이 한 자리 수 규모인 작은 스타트업에 합류하게 되었고, 상대적으로 시니어(?) 개발자가 되었기에 할 수 있는 일들이 정말 많았고 그만큼 책임감도 컸습니다. 동시에 학교에서는 이전과는 다른 새로운 CS 지식들을 배우며 개발 역량을 넓혀갔습니다. 이렇게 새로운 회사와 학교를 병행하는 정신없이 바쁜 와중에도 글또 활동을 꾸준히 이어가며 총 &lt;strong&gt;11개의 글&lt;/strong&gt;을 작성했습니다.&lt;/p&gt;
&lt;p&gt;이때 쓴 글들은 주로 &lt;strong&gt;새로운 스타트업 환경에서의 경험과 도메인 지식&lt;/strong&gt;, 그리고 &lt;strong&gt;복학 후 학교에서 배운 CS 지식&lt;/strong&gt;을 다루는 내용이었습니다. 특히 &lt;a href=&quot;/2020/12/13/Building-a-Organization-Culture-at-Startup-Company.html&quot;&gt;『스타트업에서 조직 문화를 만들어나간다는 것』&lt;/a&gt; 이라는 글은 당시 제가 회사에서 느끼고 고민했던 바를 잘 담고 있어 기억에 남습니다. 이 시기는 코로나19가 여전히 극성이었고, 학교 복학으로 인해 다른 글또 멤버들과의 오프라인 커피챗 등은 이전보다 많이 하지 못했습니다.&lt;/p&gt;
&lt;p&gt;5기 활동 중 기억나는 에피소드들을 몇 가지 소개해보자면요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;친구와 함께 강릉으로 여행을 가기로 했는데 당일에 친구가 몸이 안 좋다는 이유로 홀로 여행을 떠나게 되었습니다. 혹시 몰라 노트북을 챙겨 온 덕분에 카페에서 글또 제출 글을 썼던 경험이 있습니다. 여행지에서 노트북을 펴고 글쓰기에 집중했던 특별한 추억입니다.&lt;/li&gt;
&lt;li&gt;복학 후에는 글또 마감일이 시험 기간과 겹칠 때가 있었습니다. 시험공부를 해야 하는 와중에 글까지 써야 해서 유독 힘들었던 기억이 나네요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;글또-6기---취준생&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-6%EA%B8%B0---%EC%B7%A8%EC%A4%80%EC%83%9D&quot; aria-label=&quot;글또 6기   취준생 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 6기 - 취준생&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f1d0a66e8922234e82e433e9a4f49c67/e2d85/5.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAgADBP/EABUBAQEAAAAAAAAAAAAAAAAAAAID/9oADAMBAAIQAxAAAAHnDQStKVf/xAAbEAACAgMBAAAAAAAAAAAAAAAAAgESAwQTFP/aAAgBAQABBQJF6FKv5IMDyg7tImxFf//EABYRAQEBAAAAAAAAAAAAAAAAAAARIv/aAAgBAwEBPwGsv//EABYRAQEBAAAAAAAAAAAAAAAAAAARIv/aAAgBAgEBPwGNv//EABwQAAEDBQAAAAAAAAAAAAAAAAABITECEBEiYf/aAAgBAQAGPwJhKcK5IvbbSf/EABkQAQEBAQEBAAAAAAAAAAAAAAERAEEQIf/aAAgBAQABPyGBml+LiyFUPADBcTqzABcdO7//2gAMAwEAAgADAAAAEH/P/8QAGBEBAQADAAAAAAAAAAAAAAAAAQARITH/2gAIAQMBAT8QFnfIJ//EABcRAQEBAQAAAAAAAAAAAAAAAAEAESH/2gAIAQIBAT8QTnJQ3//EAB0QAQEAAgIDAQAAAAAAAAAAAAERACFBUTFxkcH/2gAIAQEAAT8QTQaBAH3KDrZdXlHJL+XJJkEHh7wqWLJuXATeiHh37z//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;역삼 스타벅스&quot;
        title=&quot;역삼 스타벅스&quot;
        src=&quot;/static/f1d0a66e8922234e82e433e9a4f49c67/6aca1/5.jpg&quot;
        srcset=&quot;/static/f1d0a66e8922234e82e433e9a4f49c67/d2f63/5.jpg 163w,
/static/f1d0a66e8922234e82e433e9a4f49c67/c989d/5.jpg 325w,
/static/f1d0a66e8922234e82e433e9a4f49c67/6aca1/5.jpg 650w,
/static/f1d0a66e8922234e82e433e9a4f49c67/7c09c/5.jpg 975w,
/static/f1d0a66e8922234e82e433e9a4f49c67/01ab0/5.jpg 1300w,
/static/f1d0a66e8922234e82e433e9a4f49c67/e2d85/5.jpg 1411w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;2021년 9월, 부산 본가 근처의 한 카페에서&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글또 6기는 2021년 8월부터 2022년 1월까지 활동했습니다. 이 시기는 제 인생에서 &lt;em&gt;취준생&lt;/em&gt; 이라는 타이틀을 달고 모든 에너지를 한 곳에 쏟아부었던 때입니다. 6월부터는 일과 학업 병행의 어려움으로 퇴사를 결정하고, 오롯이 취업 준비에만 몰두하기 시작했기 때문입니다.&lt;/p&gt;
&lt;p&gt;취업이라는 명확한 목표가 생긴 만큼, 글쓰기의 방향도 자연스럽게 바뀌었습니다. 대부분의 시간을 &lt;strong&gt;CS 지식과 코딩 테스트 공부&lt;/strong&gt;에 할애하며 글또에도 이와 관련된 내용들을 많이 공유했습니다.&lt;/p&gt;
&lt;p&gt;이 시기 동안 총 &lt;strong&gt;10개의 글&lt;/strong&gt;을 작성했고, 그중 &lt;a href=&quot;/2021/10/04/OS-Restaurant.html&quot;&gt;『레스토랑에 비유해서 알아보는 운영체제』&lt;/a&gt; 와 같은 글들이 대표적입니다. 당시 저는 코로나19로 인한 팬데믹 상황이 여전했던 시기에 부산 본가에 머무르며 공부하고 있었기에, 글또 멤버들과의 오프라인 커피챗 등은 이전보다 더욱 활발하게 하지 못했던 것으로 기억합니다.&lt;/p&gt;
&lt;p&gt;6기 활동 중 기억나는 에피소드들을 몇 가지 소개해보자면요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;이전에 같은 회사를 다녔던 &lt;a href=&quot;https://medium.com/@zzanzu&quot;&gt;찬주&lt;/a&gt;님께 글또를 소개해드리고 초대했습니다.&lt;/li&gt;
&lt;li&gt;글또 4기 때부터 집필을 시작했던 &lt;a href=&quot;/2021/09/12/Review-of-Book-Publication.html&quot;&gt;책이 드디어 출간&lt;/a&gt;되었습니다! 책이 나왔다는 핑계로 오랜만에 많은 분들을 만나 인사를 드리고 직접 책을 선물하며 기쁨을 나눴습니다.&lt;/li&gt;
&lt;li&gt;오랫동안 준비했던 &lt;a href=&quot;/2021/12/19/Review-of-NAVER-recruitment.html&quot;&gt;네이버 공채에 최종 합격&lt;/a&gt;했다는 소식을 듣고 뛸 듯이 기뻤던 기억이 가장 강렬하게 남아 있습니다.&lt;/li&gt;
&lt;li&gt;글또 6기가 끝난 이후에는 &lt;a href=&quot;/2022/02/25/Migration-Journey-from-Jekyll-to-Gatsby.html&quot;&gt;블로그를 Jekyll에서 Gatsby로 마이그레이션 하는 프로젝트&lt;/a&gt;를 진행했습니다. 공부를 겸하며 진행한 프로젝트라 개발 과정에서 많이 헤맨 기억이 나네요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;글또-7기---운영진-시작&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-7%EA%B8%B0---%EC%9A%B4%EC%98%81%EC%A7%84-%EC%8B%9C%EC%9E%91&quot; aria-label=&quot;글또 7기   운영진 시작 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 7기 - 운영진 시작&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/fb784b11c02434595402bda426477cdb/e2d85/6.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEBf/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAABW3ObltIiP//EABgQAAMBAQAAAAAAAAAAAAAAAAACEQES/9oACAEBAAEFAoZ0WCtTvVVs2//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAECAQE/AVf/xAAaEAACAgMAAAAAAAAAAAAAAAAAEQExECFR/9oACAEBAAY/AsbQjkzZbP/EABsQAAMBAQADAAAAAAAAAAAAAAABESExQVFx/9oACAEBAAE/IU1uieGjbgJar9aY3xBJI2Otn//aAAwDAQACAAMAAAAQkB//xAAYEQADAQEAAAAAAAAAAAAAAAAAESEBUf/aAAgBAwEBPxCp4Xh//8QAFxEBAAMAAAAAAAAAAAAAAAAAARARIf/aAAgBAgEBPxAS9h//xAAbEAACAwEBAQAAAAAAAAAAAAABEQAhMUFhof/aAAgBAQABPxB4g9VwwVCa+QwAwoS2qpjy4rNFMivfsHDwCSN72f/Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;역삼 스타벅스&quot;
        title=&quot;역삼 스타벅스&quot;
        src=&quot;/static/fb784b11c02434595402bda426477cdb/6aca1/6.jpg&quot;
        srcset=&quot;/static/fb784b11c02434595402bda426477cdb/d2f63/6.jpg 163w,
/static/fb784b11c02434595402bda426477cdb/c989d/6.jpg 325w,
/static/fb784b11c02434595402bda426477cdb/6aca1/6.jpg 650w,
/static/fb784b11c02434595402bda426477cdb/7c09c/6.jpg 975w,
/static/fb784b11c02434595402bda426477cdb/01ab0/6.jpg 1300w,
/static/fb784b11c02434595402bda426477cdb/e2d85/6.jpg 1411w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;2022년 8월, 컬리 본사에서 글또콘 진행할 때&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글또 7기는 2022년 5월부터 10월까지 진행되었습니다. 이 시기는 제가 대학교 4학년 마지막 학기를 보내고, 곧이어 네이버에 입사하며 사회생활의 다음 단계를 준비하던 중요한 전환기였습니다.&lt;/p&gt;
&lt;p&gt;7기부터는 &lt;strong&gt;운영진에 참여&lt;/strong&gt;하게 되었습니다. 6기가 끝난 후 성윤님께서 직접 운영진 모집 글을 올리셨는데, 4년간 글또에 참여하며 글쓰기 습관과 기본기를 쌓아왔기에 이제는 커뮤니티에 본격적으로 기여하고 싶다는 마음이 들었습니다. 이 커뮤니티에 제가 받은 만큼 보답할 수 있는 가장 좋은 방법이 운영진이라고 생각했죠.&lt;/p&gt;
&lt;p&gt;7기 동안 저는 총 &lt;strong&gt;10개의 글&lt;/strong&gt;을 작성했습니다. 취업 준비 과정에서 시간 제약으로 인해 미처 깊이 다루지 못했던 &lt;strong&gt;CS 지식&lt;/strong&gt;들을 정리하거나, 새로운 소재를 찾기 위해 평소 &lt;strong&gt;당연하게 넘겼던 개념들에 대해 파고들어 글&lt;/strong&gt;을 쓰는 경우가 많았습니다. 글쓰기 자체에 대한 자신감이 있었던 시기였기에, 7기 활동 중에는 &lt;a href=&quot;/2022/08/20/Personal-Branding-from-Technical-Writing.html&quot;&gt;『기술 글쓰기를 통해 개인 브랜딩을 구축하는 나만의 방법』&lt;/a&gt;이라는 글을 쓰기도 했습니다.&lt;/p&gt;
&lt;p&gt;7기 활동 및 운영진으로서 기억나는 에피소드들을 소개합니다. 이 시기부터는 코로나로 인한 제한이 점점 풀리면서 모각코와 커피챗 등 오프라인 모임에 다시금 활발하게 참여했던 기억이 납니다. 성윤님께서는 이때부터를 &lt;em&gt;글또의 르네상스 시기&lt;/em&gt; 라고도 말씀해 주셨는데 그 시기를 운영진으로 함께 보내어서 기쁘네요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;운영진 참여를 고민하며 &lt;em&gt;‘어떤 것을 기여할 수 있을까’&lt;/em&gt; 생각하다, 마침 커뮤니티 내 익명 메시지 전송 봇에 대한 수요가 있어 직접 &lt;a href=&quot;/2022/05/07/Bamboo-Forest-Slack-App.html&quot;&gt;대나무숲 슬랙 봇을 제작&lt;/a&gt;했습니다. 온라인 OT에서 성윤님이 봇을 소개해주셨을 때, 많은 분들이 관심을 가져주셔서 부끄럽기도 하고 기뻤던 기억이 납니다.&lt;/li&gt;
&lt;li&gt;7기는 글또 커뮤니티의 비전을 새롭게 정의했던 시기이기도 합니다. 엄격한 기준을 세우려는 T 성향의 저와 따뜻한 마음을 강조하신 F 성향의 성윤님 사이에 의견 차이가 있었지만, 성윤님은 제 의견을 존중해 주셨습니다. 되돌아보면 성윤님의 부드러운 리더십과 따뜻한 마인드 덕분에 글또가 더 많은 멤버를 포용하며 성장할 수 있었다고 생각합니다. 한편으로 저는 리더보다는 리더를 서포트하는 역할이 더 잘 맞는다는 것을 배운 시기이기도 합니다.&lt;/li&gt;
&lt;li&gt;글또의 첫 공식 오프라인 컨퍼런스인 &lt;a href=&quot;https://github.com/geultto/geultto-conference&quot;&gt;글또콘&lt;/a&gt;이 열렸고, 당일에 행사 진행 스태프로 참여했습니다. 이때 &lt;em&gt;‘나도 언젠가 글또콘에서 발표해봐야지’&lt;/em&gt; 하고 막연히 생각했던 기억이 납니다.&lt;/li&gt;
&lt;li&gt;대학교 친구인 &lt;a href=&quot;https://velog.io/@juno7803/posts&quot;&gt;준호&lt;/a&gt;와 함께 글또 활동을 이어갔던 시기이기도 합니다.&lt;/li&gt;
&lt;li&gt;8명 규모의 운영진이 구의에 있는 성윤님 개인 작업실에 옹기종기 모여 운영 회의를 진행했던 기억이 생생합니다. 마지막 운영진 모임 때는 성윤님께서 포르투갈에서 사 온 잼을 나눠주셨던 기억이 나네요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;글또-8기---자동화-크루&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-8%EA%B8%B0---%EC%9E%90%EB%8F%99%ED%99%94-%ED%81%AC%EB%A3%A8&quot; aria-label=&quot;글또 8기   자동화 크루 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 8기 - 자동화 크루&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/4e0b13b190bdf007b9f9477bc339bdd4/e2d85/7.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.84662576687117%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAABAD/xAAVAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABMszZSVD/AP/EABsQAQEAAQUAAAAAAAAAAAAAAAECAwAREhMh/9oACAEBAAEFAuzg0Mz46AcrEo4Hf//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAEDAQE/AUf/xAAWEQEBAQAAAAAAAAAAAAAAAAAAERL/2gAIAQIBAT8BrT//xAAbEAEBAAEFAAAAAAAAAAAAAAARAAEDISIxUf/aAAgBAQAGPwIZLlqGZzsx1e3/xAAcEAABBAMBAAAAAAAAAAAAAAABABExQSFRYXH/2gAIAQEAAT8hGUcOyERstYdEZAamhBAWUFqcPFrUdlf/2gAMAwEAAgADAAAAEIwf/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8QCP/EABYRAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPxAwn//EAB0QAQEAAgIDAQAAAAAAAAAAAAERACExYVFxsdH/2gAIAQEAAT8Q26tIDsMGFxo5HfWKV3kp+sVYaK2l5X8yf7WVNjvAeXuQL7z/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;자동화&quot;
        title=&quot;자동화&quot;
        src=&quot;/static/4e0b13b190bdf007b9f9477bc339bdd4/6aca1/7.jpg&quot;
        srcset=&quot;/static/4e0b13b190bdf007b9f9477bc339bdd4/d2f63/7.jpg 163w,
/static/4e0b13b190bdf007b9f9477bc339bdd4/c989d/7.jpg 325w,
/static/4e0b13b190bdf007b9f9477bc339bdd4/6aca1/7.jpg 650w,
/static/4e0b13b190bdf007b9f9477bc339bdd4/7c09c/7.jpg 975w,
/static/4e0b13b190bdf007b9f9477bc339bdd4/01ab0/7.jpg 1300w,
/static/4e0b13b190bdf007b9f9477bc339bdd4/e2d85/7.jpg 1411w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;2023년 1월, 강남 트레바리 라운지에서 자동화 크루와 첫 만남&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글또 8기는 2023년 2월부터 7월까지 진행되었습니다. 이 시기는 네이버 지식iN 팀에 입사하여 새로운 환경에 적응해 가던 중, 예상치 못하게 신규 부서로 팀을 옮기며 혼란스러움을 느끼기도 했던 때입니다. 갑작스러운 전배였지만 다행히 회사 업무가 초반에는 비교적 여유가 있었고, 덕분에 글또 활동과 커뮤니티 운영에 더 많은 에너지를 쏟을 수 있었습니다.&lt;/p&gt;
&lt;p&gt;8기 동안 저는 총 &lt;strong&gt;10개의 글&lt;/strong&gt;을 작성했습니다. 지식iN 팀에서 동영상 DRM이라는 복잡하지만 흥미로운 도메인 지식을 접하게 되었고, 이를 깊이 파고들어 정리한 글이 이 시기의 대표적인 글로 자리매김했는데, 그 글이 바로 &lt;a href=&quot;/2023/03/05/DRM-Contents-on-Web.html&quot;&gt;『그 많은 OTT 콘텐츠는 어떻게 웹에서 재생될 수 있을까』&lt;/a&gt;입니다. 이 때는 새로운 업무 지식을 글또 제출 글로 작성하며 기록과 성장의 두 마리 토끼를 동시에 잡으려고 노력했던 기억이 나네요.&lt;/p&gt;
&lt;p&gt;8기 활동 및 운영진으로서 기억나는 에피소드들을 소개합니다. 이 시기는 코로나 제한이 더욱 완화되면서 오프라인 커피챗 참여율이 이전 기수들에 비해 더 높아졌던 시기여서 글쓰기 외에 사람들과의 교류에서도 활력을 얻었습니다. 또한 글또 커뮤니티 자체에 많은 변화와 새로운 시도가 있었던 때입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;글또의 내부 구조를 재정비하며 글또 세계관을 구축했습니다. 기존 조별 활동을 위한 코어 채널 외에 같은 직무끼리 모여 소통하는 빌리지 채널을 도입했고, 이를 바탕으로 직무별 오프라인 모임인 반상회가 탄생했습니다.&lt;/li&gt;
&lt;li&gt;글또 운영진 내에서도 역할 별로 크루를 나누게 되었고, 저는 대나무숲 슬랙 봇을 개발한 경험을 살려 자동화 크루를 이끌게 되었습니다. 이때부터 &lt;a href=&quot;https://daco2020.tistory.com/&quot;&gt;은찬&lt;/a&gt;님께서 &lt;a href=&quot;https://github.com/Daco2020/ttobot&quot;&gt;또봇&lt;/a&gt;이라는 자동화 봇을 개발해 주신 덕분에 그동안 수동으로 처리했던 많은 운영 작업들이 자동화 및 DB화 되었으며, 이를 통해 다양한 파생 작업들이 가능해져 운영 효율이 크게 향상되었습니다.&lt;/li&gt;
&lt;li&gt;대나무숲 서버를 호스팅 하고 있던 Heroku가 유료 플랜을 종료하면서 강제로 &lt;a href=&quot;/2023/02/12/Deploy-Slack-App-with-AWS-Lambda.html&quot;&gt;AWS Lambda로 마이그레이션&lt;/a&gt;하게 되었습니다. 이 경험은 글또 8기의 첫 제출 글의 주제로 잘 사용했죠.&lt;/li&gt;
&lt;li&gt;글또 내에서 처음으로 스터디를 기획하고 진행했습니다. &lt;a href=&quot;/2023/07/02/Resume-Renewal-Project.html&quot;&gt;『개발자를 위한 이력서 스터디 진행 후기』&lt;/a&gt; 글에도 남겼는데, 빡빡한 일정으로 힘들었지만 만족스러운 결과물을 얻을 수 있어서 개인적으로는 큰 보람을 느낄 수 있었습니다. 이 스터디 방식은 이후 글또 내에서 다양한 파생 스터디로 이어지기도 했습니다.&lt;/li&gt;
&lt;li&gt;저는 &lt;a href=&quot;/2023/09/18/Geultto-8th-Front-End-Conference.html&quot;&gt;8기의 프론트엔드 반상회 행사를 직접 기획하고 진행&lt;/a&gt;하면서 오프라인 행사 진행에 대한 경험치를 쌓을 수 있었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;글또-9기---글빼미&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-9%EA%B8%B0---%EA%B8%80%EB%B9%BC%EB%AF%B8&quot; aria-label=&quot;글또 9기   글빼미 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 9기 - 글빼미&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5dd429716fe2931c3e7a9ca4b9acbe90/3e9cd/8.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.12883435582822%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAIDBQT/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAgH/2gAMAwEAAhADEAAAAYXc3ZNZ4JX4rZ3Uzf/EABwQAQEAAgIDAAAAAAAAAAAAAAIBAAMEEhETIf/aAAgBAQABBQJSQheNWzkKId4HZB6gs7xEM501ZLZc4/3T/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEQIf/aAAgBAwEBPwFG3//EABYRAAMAAAAAAAAAAAAAAAAAAAAQIf/aAAgBAgEBPwEj/8QAHhABAAEEAgMAAAAAAAAAAAAAAQACESExAxASQWH/2gAIAQEABj8Cb+9JKkJogFGI06l3lz8IU8eCeA66udUrP//EABsQAAMBAQEBAQAAAAAAAAAAAAABESExQVGB/9oACAEBAAE/IbWq1oon2BK/RlSmvqJrJPejV4mRYLoTC9CjkXaVt1xKJC2/lLojQuoZ7hzp/9oADAMBAAIAAwAAABBUzM7/xAAYEQEBAQEBAAAAAAAAAAAAAAABABEhUf/aAAgBAwEBPxCYuktr7f/EABgRAAIDAAAAAAAAAAAAAAAAAAABECEx/9oACAECAQE/EHpQSj//xAAgEAEAAwABBAMBAAAAAAAAAAABABEhUTFBYaFxgcHR/9oACAEBAAE/EFYagtF+ZAPvhD+p0e0FVfcLiC82W73ZXkllQN3a5+5ytiqh41iIBHRabfB38wyDsNz4IOAHhg9QEvcJ2juzuxRLdLq7P//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;자동화&quot;
        title=&quot;자동화&quot;
        src=&quot;/static/5dd429716fe2931c3e7a9ca4b9acbe90/6aca1/8.jpg&quot;
        srcset=&quot;/static/5dd429716fe2931c3e7a9ca4b9acbe90/d2f63/8.jpg 163w,
/static/5dd429716fe2931c3e7a9ca4b9acbe90/c989d/8.jpg 325w,
/static/5dd429716fe2931c3e7a9ca4b9acbe90/6aca1/8.jpg 650w,
/static/5dd429716fe2931c3e7a9ca4b9acbe90/7c09c/8.jpg 975w,
/static/5dd429716fe2931c3e7a9ca4b9acbe90/3e9cd/8.jpg 1058w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;2023년 11월, 강남 돈룩업에서 자동화 크루 시작을 기념하며&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글또 9기는 2023년 11월부터 2024년 5월까지 이어졌습니다. 이 시기는 회사에서 진행하던 프로젝트가 다소 지지부진해서 개인적으로는 노잼 시기를 겪고 있었던 때입니다. 회사 업무는 기술 프로토타이핑 위주로 개발이 진행되다 보니 실제 완성된 결과물을 보지 못하는 것에 대한 아쉬움이 컸습니다.&lt;/p&gt;
&lt;p&gt;회사 업무에서는 직접적인 글감을 얻기 어려운 상황이었기에, 9기 동안 저는 총 &lt;strong&gt;8개의 글&lt;/strong&gt;을 작성했습니다. 글의 주제는 개발하면서 당연하게 여기고 놓치고 있던 &lt;strong&gt;기본적인 개념들을 다시 파고들어 정리&lt;/strong&gt;하거나, &lt;strong&gt;주변 동료들을 관찰하며 얻은 인사이트&lt;/strong&gt;를 바탕으로 삼는 경우가 많았습니다. 이 시기의 대표적인 글로 &lt;a href=&quot;/2024/02/25/3-Difficulties-when-you-solve-a-problem.html&quot;&gt;『개발자가 문제 해결 과정에서 마주치는 어려움의 유형 3가지』&lt;/a&gt;가 있습니다.&lt;/p&gt;
&lt;p&gt;9기 활동 및 운영진으로서 기억나는 에피소드들을 소개합니다. 운영진 활동은 8기에 이어 9기에도 자동화 크루에 속해 활동했습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;9기에는 운영진 규모가 기존 10명대에서 20명대로 크게 늘어났습니다. 저는 다소 보수적인 태도였는데, &lt;em&gt;‘많은 사람들이 온 만큼 끈끈한 유대가 잘 될까?’&lt;/em&gt; 하는 걱정이 앞섰지만 이는 기우였습니다. 운영진에 참여하신 분들 모두 열정이 넘치는 분이셨고 크루로 역할을 잘 분배한 덕분에 운영 역시 매끄럽게 진행되었습니다. 이 경험 덕분에 이후에는 운영진 규모가 커지는 것에 대한 부담은 없었습니다.&lt;/li&gt;
&lt;li&gt;이 과정에서 성윤님이 말씀해 주신 운영진을 참여하는 마음가짐(회사 일처럼 하지 말고 재밌게 하자 / 많은 것을 하기보다는 하나를 잘 끝내보자 / 힘들면 언제든 쉬고 돌아와도 괜찮다)을 다시금 배우며 성찰하는 계기가 되었습니다. T 성향의 제가 운영자였다면 결과 중심으로 업무를 할당했을 텐데, 성윤님의 마인드처럼 자발적인 활동은 열정 있는 사람들이 느슨하게 결합했을 때 모두가 즐겁게 참여할 수 있다는 것을 알게 되었습니다.&lt;/li&gt;
&lt;li&gt;9기에 참여하면서 제가 이룬 성과는 제출 글 검수 자동화 도구인 글빼미를 본격적으로 개발하고 외부에 공개한 것입니다. 기존에는 글또의 최소 글자수 1000자 검수를 성윤님께서 수동으로 하고 계셨는데, 이것이 너무 비효율적이라 느껴 자동화 아이디어를 떠올렸습니다. 마침 회사에서 E2E 테스트 도구인 Playwright를 써본 경험이 있어 이를 활용해 개발했고, 8기 운영진 내부 테스트를 거쳐 사용자들이 이 결과를 어떻게 받아들일지 궁금하여 외부에 제공하기 시작한 것이 글빼미의 탄생 배경입니다.&lt;/li&gt;
&lt;li&gt;사내 글또 멤버들을 위한 &lt;em&gt;네이버만나또&lt;/em&gt; 라는 소모임을 운영했습니다. 같은 회사에 다니면서 글또를 하는 분들과 회사 안에서 커피챗을 할 수 있지 않을까 하는 생각에서 시작했고, 덕분에 몇몇 분들과 오프라인으로 만나 교류했습니다.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;데일리 크리에이또&lt;/em&gt; 라는 소모임도 운영했습니다. &lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000200450030&quot;&gt;데일리 크리에이티브&lt;/a&gt; 라는 책을 매일 한 바닥씩 읽고 느낀 점을 공유하는 소모임을 시도했지만… 아쉽게도 꾸준히 진행하지 못하고 흐지부지되었습니다.&lt;/li&gt;
&lt;li&gt;9기 프론트엔드 반상회에서는 &lt;a href=&quot;/2023/05/07/SEO-for-Technical-Blog.html#%EB%B0%9C%ED%91%9C-%EC%9E%90%EB%A3%8C&quot;&gt;기술 블로그를 위한 SEO&lt;/a&gt; 라는 주제로 오프라인 발표를 했습니다. 이를 통해 발표자, 진행자, 참여자 포지션으로 한 번씩 컨퍼런스에 참석할 수 있었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;글또-10기---큐레이션-크루&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-10%EA%B8%B0---%ED%81%90%EB%A0%88%EC%9D%B4%EC%85%98-%ED%81%AC%EB%A3%A8&quot; aria-label=&quot;글또 10기   큐레이션 크루 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 10기 - 큐레이션 크루&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7117a66b24e8e26bbc320f655822c60e/565cc/9.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 49.69325153374233%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAAC30lEQVQozwXB209bBQDA4RMlvCgZiTESppTFicA6HBe39kC5rhza0vUCDCY9pVxa1pYWaMsK9HRnXQddl7VzUJxu4lwY4uZuouKyEBclMdFFH0xmFp+M/4QPPvz8PsF2Zgt7bAt7/B7WmZvYo5sMnnuCK/Mj7uwevqvP8Ob3qG87idmbI7j2GxO5n5i4tMtYZoeJpUfIyU1OJ9cZjRcQ2j0ZbImHDF98ykjiFt7sLr7VZ7jP3sWf+Yb0g38IxPMYDryCbDez9vVzPt5+zqc7Lyg8+oPCV7+Q3dgjt/GU8zceIwQ9MtMziyysfEfqym0Kd37mwtIKiaCf7PIqX/7wN6pfZtZYwWnL+3y2/SuPX/zHpVu7FLZ/Z+X7v0hv7JFcf0Jg6XOEnJLg8vwChfR58qrC/dt3uHJWIegZY17N8e2f/zLum6T6zZepq34LJbdOfnOHhrqD1FZr6G4x0Nqop1xTR2lpGUJ+dojL4UEyPj2p7iJScg8fxkMshgIshmdILyr4+47j7qjGotPg7LXjklpwNtdi1R3CJdZQX/EGJa/uo7ioGMEkHibi6uFi+ATp6BSezgbcOg1GrQbp0EEq95VgadTiNbYx3NLEpM3MnHySPsnEtD+GU2yi+KUiqir2U/9uJcKIcT/XFmws528yq26xeiaAz9rJYEsdA2IDsmQk3O/EoWtloOs4oQEnIe8UkekEwdFJwkN9xHwerqutPPykGSHm0HJvLUlEvYYommiqqmJQ6iIVDWDqkjghObC2dWI+pic+Pc9c8iohf5RmUY9RbMLS3krcbeGL5fcoKBqE0KiBZeUD+h0SJSVlVJSVIhklziXzlL/+Gke0WubVLOGZOB1HDbxzoBZzh5GqynIO17xNjaaMkV4DH6ntrCqNCP2yyNCIyOh4O0MDxxhz6YmEulHmeklETShzPVxQHaQUG7FQL5EpK7PhfibcBsY9BuRhHWPDR5l0NeA7dYT/Aeois/OROuZZAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;MT&quot;
        title=&quot;MT&quot;
        src=&quot;/static/7117a66b24e8e26bbc320f655822c60e/a6d36/9.png&quot;
        srcset=&quot;/static/7117a66b24e8e26bbc320f655822c60e/222b7/9.png 163w,
/static/7117a66b24e8e26bbc320f655822c60e/ff46a/9.png 325w,
/static/7117a66b24e8e26bbc320f655822c60e/a6d36/9.png 650w,
/static/7117a66b24e8e26bbc320f655822c60e/e548f/9.png 975w,
/static/7117a66b24e8e26bbc320f655822c60e/3c492/9.png 1300w,
/static/7117a66b24e8e26bbc320f655822c60e/565cc/9.png 1806w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;2024년 10월, 운영진 MT를 간 대성리에서&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글또의 마지막 공식 활동 기수인 10기는 2024년 9월부터 2025년 3월까지 진행되었습니다. 이 시기는 회사 업무에 아주 열정적으로 몰두하며 바쁘게 보냈던 때가 있었는가 하면, 갑작스러운 번아웃에 빠져 무기력함을 동시에 경험하기도 했던 격동의 시간이었습니다.&lt;/p&gt;
&lt;p&gt;이러한 개인적인 상황은 글또 활동에도 영향을 미쳤습니다. 10기 동안 &lt;strong&gt;총 9개의 글&lt;/strong&gt;을 작성했고, 이 시기에 작성한 글은 &lt;strong&gt;업무에서 얻은 지식과 감정을 정리&lt;/strong&gt;하거나, &lt;strong&gt;주변 사람들에게 조언과 도움을 경험&lt;/strong&gt;을 위주로 작성했습니다. 대표적인 글로는 제가 직접 겪었던 번아웃을 솔직하게 풀어낸 &lt;a href=&quot;/2025/02/16/Analyzing-the-Reasons-of-My-Burnout.html&quot;&gt;『어느 날, 무기력이 찾아왔다』&lt;/a&gt;가 있습니다. 힘든 시기가 찾아왔음에도 불구하고 글 제출을 놓지 않으며 스스로를 돌아보고 기록하려 노력했습니다.&lt;/p&gt;
&lt;p&gt;10기 활동 및 운영진으로서 기억나는 에피소드들을 소개합니다. 운영진의 규모는 30명대로 더욱 커졌고 이 덕분에 글또 내부에는 이전 기수에 없었던 수많은 시스템들이 새로 생겼던 시기입니다. 글또의 마지막을 장식하며 운영진의 일원으로서 중요한 변화와 성과를 만들어냈던 시기입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;운영진 조직 구조에 큰 변화가 있었습니다. 기존에는 기능 조직으로 움직였던 크루 대신 특정 목표 달성을 위한 목적 조직으로 전환을 시도했습니다. 이는 자동화 크루가 자동화 시스템 개발이라는 기능에는 충실했지만, 각자의 개발 목적이 달라 끈끈한 유대감이 부족하다는 판단 때문이었습니다.&lt;/li&gt;
&lt;li&gt;저는 새롭게 큐레이션 크루에 합류하였습니다. 기존에 개발했던 슬랙 봇의 개발 및 유지보수도 진행하면서 2주마다 40여 개의 글을 읽고 뛰어난 글을 선정하는 큐레이션 업무도 동시에 수행하는 등 여러 역할을 병행하며 바쁜 시간을 보냈습니다.&lt;/li&gt;
&lt;li&gt;큐레이션 크루에 합류한 이유는 9기 때 개발하고 있던 글빼미와 더 좋은 시너지를 낼 수 있는 크루라고 판단했기 때문입니다. 큐레이션은 좋은 글을 선정하는 것이 주목적이므로 좋은 글과 아쉬운 글에 대한 평가 기준을 세우는 것이 역할입니다. 이는 곧 좋지 않은 글을 판단하기 위한 글빼미의 목적과 잘 일치한다는 판단이 있었기 때문입니다.&lt;/li&gt;
&lt;li&gt;9기부터 개발했던 글빼미에 LLM을 이용한 피드백 제공 기능을 추가한 것은 10기의 가장 큰 성과 중 하나입니다. &lt;a href=&quot;https://heuristicwave.github.io/&quot;&gt;지훈&lt;/a&gt;님과 협력하여 이 기능을 구현했고, 글쓴이에게 더 풍부하고 개인화된 피드백을 제공할 수 있게 되면서 성윤님께서 오랫동안 이야기하셨던 꿈을 현실로 만들었다는 점에서 큰 보람을 느꼈습니다. 또한 LLM 피드백 강도를 설정하는 기능도 추가하며 사용자 경험을 개선하려 노력했습니다.&lt;/li&gt;
&lt;li&gt;회사 내 글또 멤버들과의 교류가 즐거워 &lt;em&gt;네이버만나또&lt;/em&gt; 소모임을 더욱 주도적으로 진행했습니다. 한 달에 한 번씩 정기적인 모임을 주최했고, 사내에서만 5번 이상 커피챗을 가지며 동료들과의 끈끈함을 다졌습니다.&lt;/li&gt;
&lt;li&gt;10기 프론트엔드 반상회에는 일반 참여자로 참석하여 글또 멤버들과 교류를 이어갔습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;글또가-나에게-미친-영향&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90%EA%B0%80-%EB%82%98%EC%97%90%EA%B2%8C-%EB%AF%B8%EC%B9%9C-%EC%98%81%ED%96%A5&quot; aria-label=&quot;글또가 나에게 미친 영향 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또가 나에게 미친 영향&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExbWxpOXM0ZXJkMGpjNTI0ZTB3aWtvMjJicGNvZjBzYndiYXVxaXB5MSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/EaMTsoYxfPpuw/giphy.gif&apos; alt=&apos;러닝메이트&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;성공적인 커리어를 위해 어디로 가야할지 방황하던 나를 이끌어준 커뮤니티&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;햇수로 7년, 제 개발 인생의 대부분을 함께한 글또는 저에게 정말 많은 의미와 소중한 가치를 남겼습니다.&lt;/p&gt;
&lt;p&gt;가장 먼저 꾸준히 &lt;strong&gt;글을 쓰게 만드는 강력한 동기 부여&lt;/strong&gt;가 되어주었습니다. 보증금이라는 제도와 다른 사람과 함께 글을 쓴다는 경험이 저의 글쓰기 여정을 더 이상 외롭지 않게 만들어줬거든요. 사실 언젠가부터는 글 쓰는 행위가 익숙해지면서 글쓰기가 관성적으로 느껴지던 순간도 있었고, 제가 글을 쓰는 근본적인 태도나 마음가짐에 대해 깊이 성찰하지 못했던 점은 개인적으로 아쉬운 부분으로 남지만, 그럼에도 불구하고 글또라는 시스템 덕분에 멈추지 않고 계속 쓸 수 있었다는 것은 자명한 사실입니다.&lt;/p&gt;
&lt;p&gt;글또는 또한 제 &lt;strong&gt;커리어를 한 단계 더 발전시키는 중요한 발판&lt;/strong&gt;이 되어주었습니다. IT 산업기능요원으로 처음 복무를 시작하고 지금의 이 자리에 오기까지 글또가 제공한 함께 글쓰는 환경과 그 안에서의 경험들이 큰 도움이 되었거든요.&lt;/p&gt;
&lt;p&gt;글또라는 환경 속에서는 저는 &lt;strong&gt;혼자였다면 경험하지 못했을 다양하고 값진 경험&lt;/strong&gt;을 쌓을 수 있었습니다. 글또는 글을 제출하는 것은 물론, 다양한 사람들과의 커피챗을 통해 교류할 수 있고, 다양한 스터디와 모임이 열리고, 성장을 장려하는 여러 이벤트가 열리는 공간이었습니다. 또한 운영진으로 참여하면서 슬랙 봇 개발로 아이디어를 현실로 만들고, 반상회와 글또콘 등 여러 행사를 운영진으로서 준비하고 진행했고, 다른 멤버들의 글을 읽고 피드백하는 큐레이션 업무를 맡고, 회사 동료들과 사내 모임을 만드는 등 개발 외적으로도 정말 다양하고 의미 있는 경험을 할 수 있었죠.&lt;/p&gt;
&lt;p&gt;무엇보다 글또를 통해 &lt;strong&gt;좋은 사람들을 많이 만날 수 있었습니다&lt;/strong&gt;. 때로는 얕고 넓게, 때로는 깊고 좁게 형성된 인맥들은 제 삶의 큰 자산이 되었습니다. 모두 자신의 일과 글쓰기에 열정 넘치는 분들이었기에 그분들과 함께하는 것만으로도 저 역시 긍정적인 자극을 많이 받고 동기 부여를 이어갈 수 있었습니다.&lt;/p&gt;
&lt;p&gt;마지막으로, 글또의 운영자이신 &lt;strong&gt;성윤님의 따뜻한 마음씨와 리더십에 대한 존경&lt;/strong&gt; 입니다. 성윤님은 글또의 목적이 따뜻한 커뮤니티임을 늘 강조하셨고, 결국 사람이라는 본질을 잊지 않으셨습니다. 냉철하고 딱딱한 규칙 기반보다는 따뜻한 마음으로 사람들을 대하고, 개개인의 의사와 자율성을 존중하면서도 필요할 때는 명확한 결단력을 보여주시는 모습에서 커뮤니티 리더로서의 진정한 가치를 배울 수 있었습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;종종 &lt;em&gt;‘내가 성윤님의 나이였을 때 나는 어떤 생각을 하며 살고 있었는가?&lt;/em&gt; 라는 생각을 하곤 합니다. 사실 그때로 돌아간다고 하더라도 성윤님의 결정처럼 생각하고 행동하지 못할 것 같아서 더 존경스럽더라구요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;성윤님이 계셨기에 글또가 10기까지 이어지며 수많은 개발자들에게 긍정적인 영향을 줄 수 있었다고 생각합니다.&lt;/p&gt;
&lt;p&gt;글또 활동을 통해 얻은 가장 큰 깨달음 중 하나는 &lt;strong&gt;따뜻하고 열정 있는 마음을 가진 사람들이 함께 모이면 정말 어떤 일이라도 즐겁게 해낼 수 있다&lt;/strong&gt;는 값진 자신감입니다. 서로에게 긍정적인 영향을 주는 사람들과의 관계는 앞으로도 제 삶에 중요한 자산이 될 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;글또-이후의-나&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%80%EB%98%90-%EC%9D%B4%ED%9B%84%EC%9D%98-%EB%82%98&quot; aria-label=&quot;글또 이후의 나 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;글또 이후의 나&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExaGRlOGJyaHA2YzRqcWRmY28zaHZ0OXlmYms4aWk3anVoZmlqZHNnOSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/l1J9BYe5eZccC4Nck/giphy.gif&apos; alt=&apos;노을&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;초심을 잃지 말자&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;사실 7년이라는 시간 동안 꾸준히 글을 써왔지만, 아직까지도 &lt;strong&gt;글쓰기는 여전히 어렵다&lt;/strong&gt; 고 느끼곤 합니다. 기술적으로 내용을 풀어내는 능력은 분명 늘었지만, &lt;em&gt;써야겠다&lt;/em&gt; 는 마음을 먹고 책상에 앉기는 여전히 어렵더라구요. 😓&lt;/p&gt;
&lt;p&gt;그 원인으로는 나이가 들고 개발 외에도 신경 써야 할 일들이 많아지면서 예전만큼 글쓰기에 집중하기 어렵게 된 점도 있을 것입니다. 그럼에도 글또라는 &lt;em&gt;함께 쓰는 환경&lt;/em&gt; 이 있었기에 그 어려움을 조금이나마 이겨내고 꾸준함을 유지할 수 있었습니다. 그리고 &lt;em&gt;어렵다, 어렵다&lt;/em&gt; 말은 하지만 또 막상 책상에 앉으면 깊게 몰입하여 글을 쓰곤 합니다. 이는 무언가에 진정으로 몰두해서 성공을 이뤄낸 경험이 있었기 때문이겠죠.&lt;/p&gt;
&lt;p&gt;글또의 공식 활동은 마무리되었지만, 글쓰기 습관까지 놓치는 것은 아닙니다. 앞으로는 글또의 비활동 시즌처럼 &lt;strong&gt;한 달에 하나 정도의 포스트를 쓰는 것을 목표&lt;/strong&gt;로 삼으려 합니다. 회사 업무가 바쁘다는 핑계로, 7년이라는 시간 동안 저를 성장시키고 지금의 저를 있게 만든 소중한 글쓰기 습관을 소홀히 하지 않겠다는 다짐입니다.&lt;/p&gt;
&lt;p&gt;지금은 글또 내에서 공식 활동 마무리를 기념하는 행사를 기획하여 진행 중입니다. 이 마무리 행사와 관련된 후기 글도 작성해 볼 예정이구요. 시간적 여유에 쫓겨 작성하지 못했던 몇 가지 기술 주제들도 올해가 가기 전까지는 작성할 예정입니다. 또한, 글또를 통해 만난 소중한 인연들, 특히 마지막 10기를 함께 했던 분들과는 앞으로도 꾸준히 교류를 이어갈 계획입니다.&lt;/p&gt;
&lt;h2 id=&quot;마무리&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%A7%88%EB%AC%B4%EB%A6%AC&quot; aria-label=&quot;마무리 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;마무리&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExN3JydTJ2em5jMjkyYmhudWw0cXpudjdlNDIxdnl1b21uMGJrdDNmeCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/dxCSx7uOPQjVtpw4P5/giphy.gif&apos; alt=&apos;졸업&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;저 글또에서 졸업합니다!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;글또를 함께한 &lt;a href=&quot;https://daco2020.tistory.com/&quot;&gt;은찬&lt;/a&gt;님께서는 글또를 &lt;a href=&quot;https://daco2020.tistory.com/891&quot;&gt;1단 로켓에 비유한 회고글&lt;/a&gt;을 작성해주셨습니다. 이 비유를 보자마자 참 멋있는 말이라는 생각이 들었는데요. 1단 로켓은 비록 제 역할을 다한 후 분리되지만 그 덕분에 2단, 3단 로켓이 더 높이 날아갈 수 있는 것처럼 글또는 많은 사람들이 더 넓은 세상으로 나아갈 발판이 되는 커뮤니티라고 생각이 들었기 때문입니다. 이것보다 더 찰떡같은 비유는 없는 듯 해서 한 번 인용해보고 싶었어요.&lt;/p&gt;
&lt;p&gt;저는 이제 글또로부터 &lt;strong&gt;졸업&lt;/strong&gt;한다고 생각합니다. 마치 학교를 졸업하는 학생처럼 아쉬운 마음이 들기도 하지만, 어둡고 불확실했던 나의 커리어를 비추어주고 혼자서도 잘 나아갈 수 있을 만큼 나를 성장시켜 준 것에 대해 고맙고 후련한 마음도 듭니다. 7년이라는 시간 동안 제 성장의 가장 든든한 동반자였던 글또와, 그 안에서 함께했던 모든 분들께 진심으로 감사드립니다.&lt;/p&gt;
&lt;p&gt;글또는 이제 공식적인 활동을 마무리하지만, 글또를 통해 얻은 수많은 경험과 소중한 인연들은 제 개발 인생과 삶 속에 계속 남아 빛을 발할 것입니다. 저의 20대 청춘과도 같았던 글또에게 다시 한번 감사하다는 말을 전하며 글을 마무리합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;오래 준비한 완성을 축하하고, 오늘의 새로운 시작을 축하합니다. 서로에게, 그리고 자신에게 친절하시길. 그리고 그 친절을 먼 미래의 우리에게 잘 전달해주시길 바랍니다. 응원합니다. 축하합니다.&lt;/p&gt;
&lt;p&gt;- &lt;a href=&quot;https://brunch.co.kr/@bwbwpark/6&quot;&gt;허준이 교수의 졸업식 축사&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;참고-자료&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C&quot; aria-label=&quot;참고 자료 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;참고 자료&lt;/h2&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://zzsza.github.io/diary/2025/03/30/geultto-operation-retrospective/&quot;&gt;글또 1~10기. 7년의 커뮤니티 운영 회고&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://daco2020.tistory.com/891&quot;&gt;1단 로켓을 분리합니다. 굿바이 글또!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[안드로이드 크롬에서 CSS vh 단위가 이상하게 동작했던 이유]]></title><description><![CDATA[안드로이드 크롬 108 버전부터 레이아웃 표시 영역의 동작이 달라졌기 때문입니다.]]></description><link>https://wormwlrm.github.io/2025/03/02/Viewport-Resize-Behavior.html</link><guid isPermaLink="false">https://wormwlrm.github.io/2025/03/02/Viewport-Resize-Behavior.html</guid><pubDate>Sun, 02 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;작년에 회사에서 QA를 진행하다가 이상한 버그를 발견했습니다. 구형 안드로이드 기기에서 가상 키보드가 올라오면 CSS 단위인 &lt;code class=&quot;language-text&quot;&gt;vh&lt;/code&gt; 값이 예상과 다르게 동작하고 있었던 것이죠. 그런데 비교적 최신 기기였던 제 스마트폰에서는 정상적으로 동작하더군요.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://github.com/user-attachments/assets/15914661-720d-4713-a1c0-fc83d3e6ebd7&quot; autoplay control loop muted playsinline&gt;&lt;/video&gt;
&lt;em&gt;두 스마트폰에서 다른 부분이 보이시나요?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이상하다 싶어서 원인을 찾아보니, 안드로이드 크롬 108 버전부터 브라우저가 레이아웃 표시 영역을 계산하는 방식이 바뀌었기 때문이었습니다. 제 스마트폰은 크롬 108 이상이었기 때문에 정상 동작했던 것이었죠.&lt;/p&gt;
&lt;p&gt;솔직히 이런 변경 사항이 있었던 걸 몰랐다는 점이 꽤 충격(?)이었는데요. 그래서 이번 기회에 레이아웃 표시 영역이란 무엇인지, 그리고 크롬 108부터 기본 동작이 왜 변경되었는지 정리해 보려고 합니다.&lt;/p&gt;
&lt;p&gt;이번 포스트를 통해 &lt;strong&gt;안드로이드 크롬에서 뷰포트 관련 문제를 겪고 있는 개발자&lt;/strong&gt; 분들에게 도움이 되었으면 좋겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;문제-상황-살펴보기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%AC%B8%EC%A0%9C-%EC%83%81%ED%99%A9-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0&quot; aria-label=&quot;문제 상황 살펴보기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;문제 상황 살펴보기&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c02b50a9e82f4d59bb82a7d258729140/169e3/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 69.32515337423312%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAADa0lEQVQ4yy3Sa0/bBhTGcX/AfYVJnSpt2rRb2V6g7cWkatLEqlbA1K1QCi0rgy2lKbQUygolISGEy3IhxrlfbSe2EychFyexk39FuiM9745+j3R0hEcLj3D97RrH/dzN1NSvzM89xP38BStPV1h6vMzExHf8+fgp/+7sjePzHvHXyhoP5xbwHvjZfbPPpvsV664XCJVqnR7Q6I9oOSCrBkajTceBAR/GtbpGVEwxcECrWtSaNrJsksuWGdgfdtrdEUNAuPR4qMQSpEMxiqEYATFJTMqQiYgUxCRmNMLi3XsEX+5QE5MkD0/J+M+JBC84Po5REZPoyTylUIxy+BLh3for4vEMoWswIvFxVGQ2dEGz2sJMpNE8e8zcvsPeyiq5bBFJSqPFs0xLSW5KScysTNUCzeclubWF8GzpCe59H6sv3+DzBfksHOWu/5jzkEg+nsBSFJZn7rO+uIRra5fVzW0O3nr5KXDKR/sHePcOiRQqNM0mFSmFcLTrISXrRKU0SjLH10WZJ0WFfCpPTjNp2LB87w+8G1uIikG0pKMqNab1BjfLOrnLDOFChatCCfW/CIJ44KUcCiF6PDRPTvk+FmXNcui1HbTukDaw+MsdzvY8aDGR8+1tDJ+P+WCAb/QqNVlDbvWpSZeoZ2GEs519dLlMXkrQSaS5ZRg8s8G5vkvHGYMLt6cIvt6mkUyRDgTohcMsx0VuWQOcVp9ys4s+ACWVR4i8O+SyUscfjaMWND7pDnDZYHdHY9ACfpv8kbcrq5TaNsFkAbVkMN3u8/kQRt0RendEfQhqInv9NgGK9S4nFwmMks6nzTau/gi7O0Rr22NwZmKSoxcb6B0bf1jEVKrMmld84VyDQ7SugzkERUojiP4g2UYPT0hELerc6PRYG4IzAK3HGJyd/AG/e2Nc4AuJ5KQs940GX/YdRhbonf9BMYUQWXejinGk4xOuYnF+Tmd4nSvRzhZQcyVams70V99y+I9rDB6cRajKOtNXXW7YI+gO0a0hDaAcSyCc+Y5plg3q5SqmolGXdUzVoKoaaLJOp95i/sECx9ubDC2TRk3FNitE62W2mhp2TcGoFDEqeZSLc4TFcJ6sXqdYlFEqOvmSQlEuU5RV6s0W9Wab3+ceEI3FwQGr1cdq2wzbA+jYWB2bmtZALVZQZJ33nVfSuipmBo4AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;다른 그림 찾기&quot;
        title=&quot;다른 그림 찾기&quot;
        src=&quot;/static/c02b50a9e82f4d59bb82a7d258729140/a6d36/3.png&quot;
        srcset=&quot;/static/c02b50a9e82f4d59bb82a7d258729140/222b7/3.png 163w,
/static/c02b50a9e82f4d59bb82a7d258729140/ff46a/3.png 325w,
/static/c02b50a9e82f4d59bb82a7d258729140/a6d36/3.png 650w,
/static/c02b50a9e82f4d59bb82a7d258729140/e548f/3.png 975w,
/static/c02b50a9e82f4d59bb82a7d258729140/3c492/3.png 1300w,
/static/c02b50a9e82f4d59bb82a7d258729140/169e3/3.png 1682w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;좌측은 크롬 버전 103, 우측은 크롬 버전 123&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;처음에 나온 영상을 자세히 살펴보면 두 스마트폰에서 다른 부분을 찾을 수 있습니다.&lt;/p&gt;
&lt;p&gt;첫 번째는 바로 &lt;code class=&quot;language-text&quot;&gt;document&lt;/code&gt; 의 높이입니다. 좌측은 가상 키보드가 올라오면 높이가 줄어드는 반면, 우측은 가상 키보드가 올라와도 높이가 그대로 유지되고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b7113ebe0a278379f5cc20c3cdd19bc5/c1b63/2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 50.920245398773%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAACVUlEQVQoz22RW0tUURhAz6+IytFx7nMunuucM+fMjI4aXpKEMiTqof5Ab/2HngoiIijoNdLH8loRmdGDhSFW5nibcdQQNc1SsR5WnLHCqA3rZbP3Yn17C+NPRpl+PcHNNxP0vH3H7ucdhnt7aXclOhsUWtIiLU6C9nSCFjvOmbzMpQ6D7maF860aF9oMTjckONei05WXEMZejTE9Ncf14hJ3p2bY3YeXz0ZwlSS5lImrK6TEWmwxRCoZJKNFaM1IZIwwnhoko9biqBEcNYZnJhHK80sslT5xb67IUGmZ/a09Rh8NkDU1sp5Lo63iWQppS8NSRTpzKl0nm+nMuzS4BhlbrdDomZyotxFKhSIry+s8nCowXirD2hYvHvRgyBKebZM3EpiKSF2ihljoGBcbZK50n+Jya46OJo/Wpgxtf8giLM4sMjX5kWt+4dYO/nreN4CWTJL1cpz138+zsFIuUiyIURfFdi0cWyNr12HKEQw5gqMlqHdUhOXZEvOFIrdW1xne+fFL2I+lqNhOhiY1jKdLpEwLOV6LJobQLJ2ULlZkUjSAEq9Bl8IVhIXJAptr29z5usfgzveKcKRvCDUaQo4HkaOByiUfMVKFKYfx0jqWFiclBdETAbS4T1UFYWm6SLm4wo3lVQa39w4K+4eRao4gxaqRD+FL6/yfzjrkXR0pchwlFvgLYeHDLBurW9ze+ELf5reDwqHHyLVH/xH6tWK0GtNNk0vrJMJVlTP+3m+ExdkyhfczXC3McX++fFA49BTpP0IxEsCQQuQcFVsJVUb0Rz7MT0JOrF/EUW5EAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;정답&quot;
        title=&quot;정답&quot;
        src=&quot;/static/b7113ebe0a278379f5cc20c3cdd19bc5/a6d36/2.png&quot;
        srcset=&quot;/static/b7113ebe0a278379f5cc20c3cdd19bc5/222b7/2.png 163w,
/static/b7113ebe0a278379f5cc20c3cdd19bc5/ff46a/2.png 325w,
/static/b7113ebe0a278379f5cc20c3cdd19bc5/a6d36/2.png 650w,
/static/b7113ebe0a278379f5cc20c3cdd19bc5/e548f/2.png 975w,
/static/b7113ebe0a278379f5cc20c3cdd19bc5/c1b63/2.png 1200w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;두 문제의 정답은&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;두 번째는 바로 &lt;code class=&quot;language-text&quot;&gt;input&lt;/code&gt; 의 위치입니다. 이 인풋은 &lt;code class=&quot;language-text&quot;&gt;top: 20vh&lt;/code&gt; 스타일을 갖고 있는데요. 좌측은 가상 키보드가 올라오면 인풋의 위치가 올라가는 반면, 우측은 가상 키보드가 올라와도 인풋 위치가 그대로 유지됩니다. 이를 통해 &lt;code class=&quot;language-text&quot;&gt;vh&lt;/code&gt; 단위가 두 스마트폰에서 다르게 동작하고 있다는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;이러한 차이점이 왜 발생하는지 이해하기 위해서는, 먼저 &lt;strong&gt;레이아웃 뷰포트&lt;/strong&gt;와 &lt;strong&gt;시각적 뷰포트&lt;/strong&gt;의 개념을 알아야 합니다.&lt;/p&gt;
&lt;h2 id=&quot;레이아웃-뷰포트와-시각적-뷰포트&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EB%B7%B0%ED%8F%AC%ED%8A%B8%EC%99%80-%EC%8B%9C%EA%B0%81%EC%A0%81-%EB%B7%B0%ED%8F%AC%ED%8A%B8&quot; aria-label=&quot;레이아웃 뷰포트와 시각적 뷰포트 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;레이아웃 뷰포트와 시각적 뷰포트&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8664126ddf3b2492b4bf18ef593fc26f/5bf79/7.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.23312883435584%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAABYlAAAWJQFJUiTwAAACuUlEQVQ4y02T227jNhCG9f4v0Bdou71cdFMUKLoXRY9I0thJrBMlkrLktZxsHNk627LzFaSs3V784Mzw5/CfIcd50gFi/gee7+N5HomKyRJFJAT39/fEoU8U+Lieh+951hfGdz1C30eGPmHg8/i4YJVlOLezOd+9v+JmPmeTp/jJJ+ZyxXqzZrVacicS5iIhX2css4ybIMGVS57yFVGSch1oZJqR6JiF7+N887vPD9czknXIuVX8HQVcPbgUhaRvNL+4Pr+FAX2l2bxIrh487nTIW6uRecT7mYvKY/oq5sM/dzh/xRp6zanVNKWCg7Zo9pKuUnbP+qWkM/vHxMbaSnFuNXTj2Xof8afr4nDIacrYHjYwxHovbXLj942iLseY8au9pC2VRV8ry6t2irdewbDBifOUroo5NHpMUI+Y7KHTXy6bcGjGhNa+cIdOsnrJcL69Dim2EfVuJBmyKdckm5RMcbPWO2mrML61S8W51wy94t2twHFXS7pacmy0hVFkyEOrbdJj+9UfLrbBqdf0l8SnTnM+KGbLZOxhWUS2F81+7FW1k1bl//tUFtIqsj0r5Je4iZm9Zh/DeYNzqxP6RlplFhcVRpm52WBSebzEp95Oe/ZMK3lIE5zvbwTVLmaoxhJ2W8nQaE6NtkqMymOlONZjBYbTm/WinnMCLG3J7/4VOJttxvNWINaCYic5tYrV54hoLeyXMapkLkieBEOrqCuJ+BSSv0S89ZptERPlgl0ZkX5Oxx4utMuH+SNxFtCbDxq4/HT/SFEI9q+CX90FHxcLyteI9VPIj3cPzLRnuV7i8/NiQfrsw2mDczpsODWxnQbzp4yiaTqmVzTTwPHywvXXaTq2yqo003NuY87HZ5yhf6EsllT7jHKX0lQZdZnR1pmNNaWJj6uJW95+tLsLp9im1OWSt+GV/wAdM1i0spsH8AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;레이아웃 뷰포트&quot;
        title=&quot;레이아웃 뷰포트&quot;
        src=&quot;/static/8664126ddf3b2492b4bf18ef593fc26f/a6d36/7.png&quot;
        srcset=&quot;/static/8664126ddf3b2492b4bf18ef593fc26f/222b7/7.png 163w,
/static/8664126ddf3b2492b4bf18ef593fc26f/ff46a/7.png 325w,
/static/8664126ddf3b2492b4bf18ef593fc26f/a6d36/7.png 650w,
/static/8664126ddf3b2492b4bf18ef593fc26f/5bf79/7.png 966w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;레이아웃 뷰포트를 파란 영역으로 나타냈다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;레이아웃 뷰포트(layout viewport)&lt;/strong&gt; 란 브라우저에 화면이 나타내는 영역을 의미합니다. 만약 우리가 접속한 웹 페이지에 스크롤이 있다면, 우리는 레이아웃 뷰포트 영역만큼을 화면에서 볼 수 있게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2864b87c0a0abde29ef13b6b3af94452/f53a0/6.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 68.71165644171779%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAADLklEQVQ4yy2RSW8UVxSF699ln12kbLJBiqIssiN/gEgoICUSbEKQUQwokQWOia32EIMAD+CA42676aGGV1XdNbwaeqyuobvri7qc1Xu6956j756rAGRpihAmrXYH07LIs2xVZjQcEIUBwzhkEIWEgWQ8HjEvCqTrMoslxVASSx/XcSiKAsX3JTu1Gj/evsV339zg3s932N3fJ45jXr054vmLLf7Y/JOtWo3Nv7Y5OX2H3vdY39nl+yeHfHG/xvrBW57XtnGlRDHsHpu7L7i9echnd3e4+WSP3dcH2I7H/tkZW8dv+PzeDl893GPv/Vsa7UviQUjfb/JO77DdaNKLdBzZxI8HKG4gkUGLaGTS7HXxB4LRWEM4PsPYYJmZTKcmk7GAQtC1Nbp9H6N3CQsLMgPmFqLXwA5iFOH5dMUFZIJlolci2/tEx/a40FrMJhrZRCef6hSJim6rhHFAKK9Ip4LpSGM+E0h5RTQcoMhQ4jgNikSQjDWKxCCK2vQ8nzBQmY010onObKyTTVU6porq+KjWJcv0WlNmJqrVwJIxiuH6dES9Kl43BabTomV5/Ku1SFeE05WZQTFTUS2VIFoRNiuy2USvVo/CK+IVYRBJXLdBlghGQ41lLhgO2vT/J1yZrQjzxKDMtcpQc2WVYZ4IxkMNcrOCEjK6JtSsBixtWJhAD0d2aJoedb1VrTwd6RVJMu7SFl3kijBowsKGpVlpo+CK4WiI4kqPrv6RZx8bfLtxwq/H51j9SxzPIwz16srkVnVJFgLR1zBcWWX29H2dW7Uz6lYb3a6jexGK6ztsbD7it2fr/LC2xk+PfmFnfwPXl5w1LzhtfuDLtZd8/fQ1R80zmnoLVRj8vvGAm/cfcuPuA+48Xudgb504kigsM2T/A47xjrj3D4F1yiS6Akp07Zzz8wMOT//m5ekh9foBw0Ajm41QP73C0Y4IxTGOfoytn5BnCUpZZhQzQZ6YFKlZ/Zn3KkMWAYtUXGdV2DBfZTwGCpb5at4iT61KR9kHFijlMidLLNKJRTq1q3dZOJXhPA/IpmbVn00s5qlJuRix0qRTs6rlic0ytymLPmU55z8FVPPyD1bF7QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;레이아웃 뷰포트&quot;
        title=&quot;레이아웃 뷰포트&quot;
        src=&quot;/static/2864b87c0a0abde29ef13b6b3af94452/a6d36/6.png&quot;
        srcset=&quot;/static/2864b87c0a0abde29ef13b6b3af94452/222b7/6.png 163w,
/static/2864b87c0a0abde29ef13b6b3af94452/ff46a/6.png 325w,
/static/2864b87c0a0abde29ef13b6b3af94452/a6d36/6.png 650w,
/static/2864b87c0a0abde29ef13b6b3af94452/e548f/6.png 975w,
/static/2864b87c0a0abde29ef13b6b3af94452/f53a0/6.png 1062w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;레이아웃 뷰포트는 &lt;code class=&quot;language-text&quot;&gt;position: fixed&lt;/code&gt; 스타일을 갖는 요소에 영향을 줍니다. 화면에 고정된 위치를 지정하는 &lt;code class=&quot;language-text&quot;&gt;fixed&lt;/code&gt; 스타일은 레이아웃 뷰포트를 기준으로 계산되기 때문에, 레이아웃 뷰포트의 크기가 변하면 &lt;code class=&quot;language-text&quot;&gt;fixed&lt;/code&gt; 스타일을 갖는 요소의 위치도 변하게 되죠.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://github.com/user-attachments/assets/763478d1-5fce-474f-bc68-511a351a6656&quot; autoplay control loop muted playsinline&gt;&lt;/video&gt;
&lt;em&gt;브라우저 주소창, 가상 키보드, 핀치 줌을 이용해 레이아웃 뷰포트의 크기를 변경시켜 보았다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;반면 &lt;strong&gt;시각적 뷰포트(visual viewport)&lt;/strong&gt; 란 사용자가 지금 실제로 보고 있는 화면의 영역을 의미합니다. 브라우저의 주소창, 가상 키보드의 영역, 핀치 줌을 이용한 화면 확대 등 다양한 요소로 인해 레이아웃 뷰포트와 눈에 보이는 영역이 서로 다를 수 있기 때문입니다.&lt;/p&gt;
&lt;p&gt;위 영상을 보시면 이해가 빠르실 것 같은데요, 화면에 나타나는 &lt;code class=&quot;language-text&quot;&gt;Visual Viewport&lt;/code&gt; 영역의 값 변화를 살펴보시면 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;os와-브라우저에-따라-달라지는-동작&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#os%EC%99%80-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%97%90-%EB%94%B0%EB%9D%BC-%EB%8B%AC%EB%9D%BC%EC%A7%80%EB%8A%94-%EB%8F%99%EC%9E%91&quot; aria-label=&quot;os와 브라우저에 따라 달라지는 동작 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;OS와 브라우저에 따라 달라지는 동작&lt;/h2&gt;
&lt;p&gt;이렇게 해서 레이아웃 뷰포트와 시각적 뷰포트의 차이점을 알아봤습니다. 그리고 모바일 브라우저에서 가상 키보드가 올라오는 것이 시각적 뷰포트의 크기를 변경시킨다는 것도 알게 되었죠.&lt;/p&gt;
&lt;p&gt;여기서 모바일 브라우저는 가상 키보드가 올라올 때 세 가지의 방법으로 레이아웃 뷰포트와 시각적 뷰포트를 계산할 수 있습니다. 여기서 문제가 발생하죠. 바로 &lt;strong&gt;OS와 브라우저의 조합에 따라 동작이 서로 달라진다는 것&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2c7f1ea363bb37953fc8d030309893bf/1c1a4/11.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 63.190184049079754%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABYlAAAWJQFJUiTwAAAC20lEQVQ4y12SXW/bZBiG+wN3xik/giFNCHEKnCFtbAeANpC2roMOQdVVojtIR2mTtEnsfPgr/nbixE7StGmbpLHjJBeyXYmPW3qeV/b73tdj+b23DL2NaxkErknPtWk2mwwGQ24mV6iKQtc2sz3PtpBaLaa3t3Q8D1Nv03dM+p5FW1UxDINUW9u/vOXxTz/z6NtXPN3Z483uLpqmIio6P77a5usfdvjs2Wte7O6xf3BA1/c5ODzk+etdPn/6ki9fvGXn198pHB3lQL3T4Z064tMDnZdCn+H4gp7v4PYDOmHI9+c+D9/pFIwR44sQ23VQLQMpvOGLQ5Ovjhzs0QTP1dlsNmzNp9fkSrK+TBJUy2Y4DInj6H5vlfXh1QTTsZlcjv7jSSWbJqv1mq1gdEGSJFxOrllEMVG0YND38IOA6WzKKo5YLuaw2XA3nWC5DpYfZJDUczubZ6Cg57BOgbPbCf9WnCQotsPlxYAoXuBeJ9TDGZN4w/j6JgNOxgP+L9my8y8sVyv4loylNXF1CbVVxXFsJMOkUinxyfYxD5685/H+KbpUw3BcKvV6dtOWbWPfV6Mh5pdSrlRRZJlWq4UsS5xXa5xpLkHPp1qtYrVVnLaCpuRngn6XpnhOS5Ky57TSqB2XyzmwUK5htDVkWUZVVQSxjmJ59HwfQRBQFJWWJCMrSjbY7XQ5rVTQVDXzKIqCJEkIwlkOrIl10nDrmoqlazSaTUTdI+j1EMU6mqZlg9JKzf1eF6kpoGl65tHbWhbscvU8B74/LvLNfpkHzwo83Dnhjz9LCJqd/aNisUij0UAURer1OoJQw+n4nBRP2Ds65aPvPvDx8w/8VjihVPorB/aCkKZuU5ItzhQbzXJZLWPmd3e4rovneVmZpkkYhiSrNf2gT9vQKUpm5mkoGjdX4xyYtmhxxzpesIoXJMv4nwjFMfP5nCiKmM1mWc5SpWv6Lkl9y4hosWBz7/kb3xWh+/sZF1MAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;브라우저&quot;
        title=&quot;브라우저&quot;
        src=&quot;/static/2c7f1ea363bb37953fc8d030309893bf/a6d36/11.png&quot;
        srcset=&quot;/static/2c7f1ea363bb37953fc8d030309893bf/222b7/11.png 163w,
/static/2c7f1ea363bb37953fc8d030309893bf/ff46a/11.png 325w,
/static/2c7f1ea363bb37953fc8d030309893bf/a6d36/11.png 650w,
/static/2c7f1ea363bb37953fc8d030309893bf/e548f/11.png 975w,
/static/2c7f1ea363bb37953fc8d030309893bf/1c1a4/11.png 1046w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;브라우저 별 레이아웃 뷰포트와 시각적 뷰포트의 변경&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;resize-visual&lt;/strong&gt; 방식
&lt;ul&gt;
&lt;li&gt;레이아웃 뷰포트는 변경되지 않고 시각적 뷰포트만 변경&lt;/li&gt;
&lt;li&gt;iOS 크롬, iOS 사파리, iOS 엣지, iPad 크롬, iPad 사파리, iPad 엣지, ChromeOS 크롬&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;resizes-content&lt;/strong&gt; 방식
&lt;ul&gt;
&lt;li&gt;레이아웃 뷰포트와 시각적 뷰포트 모두 변경&lt;/li&gt;
&lt;li&gt;안드로이드 크롬 (108 버전 이전까지), 안드로이드 파이어폭스, 안드로이드 엣지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;overlays-content&lt;/strong&gt; 방식
&lt;ul&gt;
&lt;li&gt;레이아웃 뷰포트와 시각적 뷰포트 모두 변경하지 않음&lt;/li&gt;
&lt;li&gt;해당 방식으로 동작하는 브라우저 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이런 차이로 인해 가상 키보드가 올라올 때 안드로이드 크롬과 iOS 크롬에서 서로 다른 동작을 하는 문제가 발생합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;iOS 크롬에서는 vh 단위가 유지되는 반면 안드로이드 크롬에서는 &lt;code class=&quot;language-text&quot;&gt;vh&lt;/code&gt; 단위가 변경됨&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;position: fixed&lt;/code&gt; 스타일을 갖는 요소의 위치가 iOS 크롬에서는 유지되는 반면, 안드로이드 크롬에서는 변경됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이를 올바르게 해결하기 위해서는 사용자 에이전트를 읽어와서 JavaScript로 레이아웃 뷰포트와 시각적 뷰포트의 크기를 직접 계산해야 하는데, 개발자 입장에서는 여간 번거로운 일이 아니었죠.&lt;/p&gt;
&lt;h2 id=&quot;안드로이드-크롬-108-버전부터-기본-동작-변경&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%ED%81%AC%EB%A1%AC-108-%EB%B2%84%EC%A0%84%EB%B6%80%ED%84%B0-%EA%B8%B0%EB%B3%B8-%EB%8F%99%EC%9E%91-%EB%B3%80%EA%B2%BD&quot; aria-label=&quot;안드로이드 크롬 108 버전부터 기본 동작 변경 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;안드로이드 크롬 108 버전부터 기본 동작 변경&lt;/h2&gt;
&lt;p&gt;이처럼 동일한 코드가 OS에 따라 서로 다르게 동작하는 문제가 있었기 때문에, &lt;a href=&quot;https://developer.chrome.com/blog/new-in-chrome-108?hl=ko&quot;&gt;안드로이드 크롬 108 버전&lt;/a&gt;부터는 iOS의 동작 형태를 그대로 따라가도록 수정되었습니다. 즉 눈에 보이는 화면 크기가 줄더라도 레이아웃 영역 계산에 영향을 주지 않게 되었습니다. 이로 인해 다른 브라우저와의 동작 차이를 줄이고, &lt;code class=&quot;language-text&quot;&gt;vh&lt;/code&gt; 와 같은 뷰포트 단위의 동작을 일관되게 사용할 수 있게 되었죠.&lt;/p&gt;
&lt;p&gt;만약 108 버전 이후의 안드로이드 크롬에서 기존의 동작을 유지하고 싶다면 다음과 같은 메타 태그를 사용하면 됩니다. &lt;code class=&quot;language-text&quot;&gt;interactive-widget&lt;/code&gt; 속성에 원하는 동작을 지정해주면 되죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width, initial-scale=1.0, interactive-widget=resizes-content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;새로운-뷰포트-단위의-탄생&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%83%88%EB%A1%9C%EC%9A%B4-%EB%B7%B0%ED%8F%AC%ED%8A%B8-%EB%8B%A8%EC%9C%84%EC%9D%98-%ED%83%84%EC%83%9D&quot; aria-label=&quot;새로운 뷰포트 단위의 탄생 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;새로운 뷰포트 단위의 탄생&lt;/h2&gt;
&lt;p&gt;이렇게 해서 안드로이드 크롬 108 버전부터 레이아웃 표시 영역의 기본 동작이 변경되었다는 소식을 전해드렸는데요. 마침 해당 버전에 &lt;a href=&quot;https://web.dev/blog/viewport-units?hl=ko&quot;&gt;뷰포트와 관련된 새로운 기능&lt;/a&gt;이 추가되어서 이를 함께 소개해 드리려고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8c8aa1f91864ae396ae223b17fd3fc4f/f8836/5.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 61.34969325153374%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAACp0lEQVQoz12QSW8TWRSF88tY0GLDhk0nbQfikJbsCkgIJKSIVqsbEIMi9QIkNmxYMSOCM0Ac4piUE6dsGmJChsLGCfMQ2/FQrvJY9d7XKtuEhsV5Vzr3ve/e83oAbMdhO5cjndlk681bSmXDtanVapimiWVZbRmGgWlZ2M0GjUqRRqVE0yy3a9UoIaSkR0qJvrrC+L1b/P3HCJf/GSUSekghn+P5cpKx4Hhbj0IzBCemWHmR5FnmIxemlrkUXufS7Dqj0y+5NvscpKDHPa6E1zgV2uSvmQynZ7cYmUqxuvmBu6tZ/I/zHJ/LciKSIxAuMq1nibzO06vCUByGNPAuwblEGYTtAh3OaiU8sU5zUANPFJbf7XBdt/htCfyJjnpjMJYyUF9nOajaDMcliiY4HIOL8UIXKGwuaDttU1kSKJpkMGqTfJfn5kaF/oVvvsC7AMFUmWgmR78qCCQgEAffkgss4i7XBRbaptv0uxcWnF2gdxGUeEeeLlB1gZEGAbVKYN7Epza5mCiC093wvFZg8EmdQMTA/8TEN9/sAHUL71wdJVxAmSvhiTQJpo3vwHnzR6D4H9A335nojzYY2AWaeKMCZbGJErPxRCXBlNGO7FWdnyIXupGl06YPJWD4KQz/C4djkuT7PDe6kd1HitaJ/OBV5w8HFgRHn8LRBPyuwejuhtLhtPqFvnANX8RiIFKld6bCs61tbuoVDsXgSLyj/kUYT5WZ1b+yf7pK31yDvnCdA+EWf6rZLhDBmcU8e25/Zv/9L+y7+4m9dz6jb1tcWymyb8Lg15BBb8jglwmDOxslkpmPHBtbY2Ryg1NTOicnU1yNpgHpAuFrDfSCTbosSJUc0mVJU0KuarOWb/Kq0GprfafFTl2A00LUTUTdQjYspFtbdYQQ/Ae0+SZXoE1ZGwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;모바일&quot;
        title=&quot;모바일&quot;
        src=&quot;/static/8c8aa1f91864ae396ae223b17fd3fc4f/a6d36/5.png&quot;
        srcset=&quot;/static/8c8aa1f91864ae396ae223b17fd3fc4f/222b7/5.png 163w,
/static/8c8aa1f91864ae396ae223b17fd3fc4f/ff46a/5.png 325w,
/static/8c8aa1f91864ae396ae223b17fd3fc4f/a6d36/5.png 650w,
/static/8c8aa1f91864ae396ae223b17fd3fc4f/e548f/5.png 975w,
/static/8c8aa1f91864ae396ae223b17fd3fc4f/f8836/5.png 1214w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;모바일 브라우저의 주소창과 탭 바의 유무에 따라 &lt;code class=&quot;language-text&quot;&gt;100vh&lt;/code&gt; 의 크기는 정확히 화면과 일치하지 않는다&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;모바일 브라우저에서는 주소창과 탭 바 등의 요소가 화면의 일부를 차지하게 되는데요. 이러한 요소들이 화면의 일부를 차지하게 되면 &lt;code class=&quot;language-text&quot;&gt;100vh&lt;/code&gt; 단위로 높이를 지정했을 때, 화면의 높이와 일치하지 않는 문제가 발생합니다.&lt;/p&gt;
&lt;p&gt;특히 모바일 크롬을 예시로 들면… 화면을 아래로 스크롤하면 주소창이 사라지고, 가상 키보드가 올라오면 주소창이 다시 나타나는 것이 기본 동작입니다. 이러한 동작으로 인해 &lt;code class=&quot;language-text&quot;&gt;vh&lt;/code&gt; 단위로 스타일을 지정한 요소가 원하는 위치에 나타나지 않는 문제가 발생하는데, 이걸 고쳐 달라는 요청을 들으면 참 난감했거든요.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7968b38bce7c86161e675dd5d3dd7040/d4b10/10.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 81.59509202453987%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAAC4ElEQVQ4y3WTXW/cRBiF9+eBihA0af8B8AdQAy2FFJrSqk1aUbXQhHbhkkq0XETKHdxUhBI1RVGTbRu83qzt/fBmP+z1x9bjmQfNOGs2QYw1nvHxzJkz533fShiGfPDhR7z3/hxzc2fNOD9/llqtxk8PH7LwyadcOP8ZF85f5NzCAtvbz/n50SNOvfMup+fPcHruDG+9fYpvbt9Gt0q/3+fy0tdcu7HM9Y+XufzVVS5+scjm5h90Oh0Oh3182+fwoEen16XZdHj8+Be+XLrC1aUbXFq8wueLl6hWf0QpRSWKInIhDDttyuY4DtE4Kj5SYFJMPc9jOBhyso3HY5IkoaInPb+HQpHV3qAminAcUq/XCUaBWSyDHBVK9NNsNmm1WuRIxCAjCzKzRmMl4aA/KI55JSGHOImxbZsgKAiJii5ROE2HTrtT4CEQKzPV9vyHcPQ6Rk4gjiIsyyIMwuI6fsJkpIxHjUajJEwPU6KBKBXGxwgVDPdjRApJfFxh6MckIwVS0XQc2u3C7OQwJeiL/1dYXjmNadiN0sPZK7uOWxLOXrnb7ZKmaUGoU8eY/yoHMePhNCihRI2VCYozo1AFEhnJUmFJOE0D9To3CpM0MV5NPdRkWqHOBNd1zeZCoUKdVKgrxe/6RdrsvkFOJME4NEHRVmhcDDPykSCTGQeNAzzXIydH9DNEkGn7aXlHaRPHMaura9y5e5fqnR+4992qKSOdb+vr69y8dYsHa1VWv/2elZsr7Ozs8PTpnyyvrHD/3gPur1XNmo2NjaL0dCoIIej5XZ48+Y2GbZnvKR7HEc+3t6hb+2RZhpTS9DRNeFl7wc5fz0iSGCHyfwlN1Q1Sft2ysLxR4dsRLiT8/sLlZXNwDNfvrT2Xzd02E6HKfxWToElMbb9hNtUsh17PL8hERt0+YNfusWe18Fy3rF3Xa7FXb7Nn+/xt2cj8SGF5qtLhL3qpQunqmOJqBj+x5wjX4z8rZZfg168J/gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;동적 뷰포트 단위&quot;
        title=&quot;동적 뷰포트 단위&quot;
        src=&quot;/static/7968b38bce7c86161e675dd5d3dd7040/a6d36/10.png&quot;
        srcset=&quot;/static/7968b38bce7c86161e675dd5d3dd7040/222b7/10.png 163w,
/static/7968b38bce7c86161e675dd5d3dd7040/ff46a/10.png 325w,
/static/7968b38bce7c86161e675dd5d3dd7040/a6d36/10.png 650w,
/static/7968b38bce7c86161e675dd5d3dd7040/e548f/10.png 975w,
/static/7968b38bce7c86161e675dd5d3dd7040/3c492/10.png 1300w,
/static/7968b38bce7c86161e675dd5d3dd7040/d4b10/10.png 1394w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;이로 인해 등장한 단위, dvh lvh svh&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;이러한 문제를 해결하기 위해 새로운 뷰포트 단위가 등장했습니다. 바로 &lt;code class=&quot;language-text&quot;&gt;dv*&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;lv*&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;sv*&lt;/code&gt; 단위인데요. 이 단위들은 뷰포트의 크기를 기준으로 계산되는데, 각각 다음과 같은 특징을 갖고 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;dv*&lt;/code&gt;: 현재 레이아웃 뷰포트의 크기를 기준으로 계산&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;lv*&lt;/code&gt;: 가장 큰 레이아웃 뷰포트의 크기를 기준으로 계산&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;sv*&lt;/code&gt;: 가장 작은 레이아웃 뷰포트의 크기를 기준으로 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이러한 접두어는 &lt;code class=&quot;language-text&quot;&gt;vw&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;vh&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;vmin&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;vmax&lt;/code&gt; 와 같은 뷰포트 단위와 함께 조합하여 사용할 수 있으며, 레이아웃 뷰포트의 크기에 따라 동적으로 변하는 뷰포트 단위를 사용할 수 있게 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/52b8386b9dc3bcb31e26ce5c0da1aebc/81501/12.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 39.263803680981596%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAABm0lEQVQoz42Q227aQBRF/Q8BOwTbc/HgscdXGAOBoJCSFFW5qKry2peq/f9fWBWQVupbH5b2OS9b56xgVUxxVtM5TVMI2lLi8oSmkHTuhKI0U7J0TJaGf9HJmCK7wc1iGpviO40WY4J9N+F5r5jXKXUpqGxK52IWbkquJlg9wagInY7IRPhRfMGIkJmM0MkII0NkMiLQyRW3LqbLYtosoc1iFllMkV3jTuW5YG4EvtA0NqE+XdMa6kLQl5K2EOdPWivOlwe5uub50PLl4Hh5sLztDa+fZhxbhXeG3cby7XPD47bCmynH3rD1JU+DwTcpyz5nNbfceU+ZSQLhImY/c/SbIPuRY35Z4nfJ1zZm3VyTvivUd0V+Lxm8ZdhJfG8Z7gV6O6WbW4bOcbfxVIUi0CrE9clZcNkn2D6mtgmZiM7OtI3Qs4hZEmJkhPrwdsqTt9N8RoTI+IrAV5rX/ZLHbctx2/N027JbWJa1YnCSZXlhqORld//mH1a1ojZTgtW84OWwYedL9uuah3XDUCl8meKd+D9KwbKSVOaG3/8z7CIpWA4vAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;동적 뷰포트 단위&quot;
        title=&quot;동적 뷰포트 단위&quot;
        src=&quot;/static/52b8386b9dc3bcb31e26ce5c0da1aebc/a6d36/12.png&quot;
        srcset=&quot;/static/52b8386b9dc3bcb31e26ce5c0da1aebc/222b7/12.png 163w,
/static/52b8386b9dc3bcb31e26ce5c0da1aebc/ff46a/12.png 325w,
/static/52b8386b9dc3bcb31e26ce5c0da1aebc/a6d36/12.png 650w,
/static/52b8386b9dc3bcb31e26ce5c0da1aebc/e548f/12.png 975w,
/static/52b8386b9dc3bcb31e26ce5c0da1aebc/3c492/12.png 1300w,
/static/52b8386b9dc3bcb31e26ce5c0da1aebc/81501/12.png 2886w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;브라우저 지원 범위&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;브라우저 지원 범위가 94%로 높긴 하지만 구형 브라우저에서는 지원이 되지 않기 때문에 조심해야 한다는 점을 강조하면서 이번 내용을 정리할 수 있을 것 같네요.&lt;/p&gt;
&lt;h2 id=&quot;마무리&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%A7%88%EB%AC%B4%EB%A6%AC&quot; aria-label=&quot;마무리 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;마무리&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExOGtyd2RtN3AzdHQxY2pwbjN6Z295YXN4MnQ4cWZvN29kcGozZWg5ZSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/JPgbfjx4d2sAAkQabX/giphy.gif&apos; alt=&apos;chrome&apos; loading=&apos;lazy&apos; /&gt;
          &lt;/p&gt;
&lt;p&gt;이렇게 해서 이번 포스트에서는 레이아웃 표시 영역이란 무엇인지, 그리고 크롬 108부터 기본 동작이 왜 변경되었는지를 정리해 보았습니다.&lt;/p&gt;
&lt;p&gt;저는 위 내용을 팀에 공유했고, 안드로이드 크롬의 버전이 108 이상인지 미만인지에 따라 로직을 분리하는 방식으로 QA에 제보된 문제를 해결할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;혹시라도 여러분이 웹 개발 도중 구형 안드로이드 기기의 크롬에서만 뷰포트 관련 문제가 발생한다면, 이를 근거로 문제의 원인을 찾아보세요.&lt;/p&gt;
&lt;h2 id=&quot;참고-링크&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B0%B8%EA%B3%A0-%EB%A7%81%ED%81%AC&quot; aria-label=&quot;참고 링크 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;참고 링크&lt;/h2&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/web-platform-tests/interop-2022-viewport/blob/main/explainers/layout-viewport.md&quot;&gt;Interop 2022 Viewport - Layout Viewport&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/viewport-resize-behavior&quot;&gt;Android용 Chrome에 적용될 표시 영역 크기 조절 동작 변경사항에 대비하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://viewport-resize-behavior.netlify.app/&quot;&gt;Viewport Resize Behavior&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[어느 날, 무기력이 찾아왔다]]></title><description><![CDATA[번아웃의 원인 분석을 통해 스스로를 돌아보고 이를 극복하는 과정을 정리해 보았습니다.]]></description><link>https://wormwlrm.github.io/2025/02/16/Analyzing-the-Reasons-of-My-Burnout.html</link><guid isPermaLink="false">https://wormwlrm.github.io/2025/02/16/Analyzing-the-Reasons-of-My-Burnout.html</guid><pubDate>Sun, 16 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;1월 중순, 저는 새로운 기능을 구현하기 위해 팀원들과 스펙 회의를 진행했습니다. 그런데… 회의를 진행할수록 의욕이 떨어진다는 느낌을 받았습니다. 마치 넘어야 할 산이 끊임없이 나타난다는 느낌을 받았습니다. 가슴이 답답했고 무기력감이 몰려왔습니다.&lt;/p&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExdGk1cjN3M2RwbzhuZHRqeDRsdnJkZDZoeGRwM2cyN2JqbHUwYm1rbSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/3oD3YGIVrRGbe5YGNa/giphy.gif&apos; alt=&apos;시지프스&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;마치 시지프스가 된 기분&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;작년까지만 해도 어렵고 도전적인 업무를 도맡아 했던 저였기에 이런 감정이 낯설고 당황스럽게 느껴졌습니다. 흔히 말하는 &lt;em&gt;번아웃&lt;/em&gt; 이 온 건가 싶더라구요. 그리고 작년 동료 평가에서 ”&lt;em&gt;번아웃이 걱정 된다&lt;/em&gt;” 는 피드백을 들었던 것도 생각이 났습니다.&lt;/p&gt;
&lt;p&gt;지금은 2월 중순이 되었고 당시의 감정은 어느 정도 추스렀습니다만, 이런 감정이 생긴 이유를 분석하고 싶었습니다. 그래서 오늘은 당시의 경험을 돌아보고 번아웃을 맞이한 이유와 해결책을 고민하는 과정을 정리해보려 합니다.&lt;/p&gt;
&lt;p&gt;이번 포스트를 통해 &lt;strong&gt;번아웃을 맞이하는 저만의 이유 분석과 해결책을 고민하는 과정&lt;/strong&gt; 이 궁금하신 분들에게 도움이 되었으면 좋겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;요약&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%9A%94%EC%95%BD&quot; aria-label=&quot;요약 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;요약&lt;/h2&gt;
&lt;p&gt;세 가지의 키워드로 그 이유를 정리할 수 있을 것 같습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1월의 우울&lt;/strong&gt;: 환경적 요인&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;깊은 몰입과 잦은 상황 변화&lt;/strong&gt;: 개인 성향적 요인&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;보물섬 찾기와 배 만들기&lt;/strong&gt;: 조직적 요인&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;1월의-우울&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1%EC%9B%94%EC%9D%98-%EC%9A%B0%EC%9A%B8&quot; aria-label=&quot;1월의 우울 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1월의 우울&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExMXp2eWNuYzJzbG1ibnlmNzI4bWNxaWc2ODU5YW0waG5qYXYzeGpuaiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/116kbTYYxHDDoY/giphy.gif&apos; alt=&apos;1월의 우울&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;기쁨이기도 하지만 걱정이기도 한 새해&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;첫 번째는 환경적 요인, &lt;a href=&quot;https://www.elle.co.kr/article/19949&quot;&gt;1월의 우울증&lt;/a&gt;입니다. 작년 1월에도 비슷한 감정을 느꼈는데, 올해도 같은 감정이 찾아와 이를 하나의 원인으로 생각했습니다. 검색해 보니 이는 저만의 문제가 아니라, 많은 사람들이 겪는 자연스러운 현상이더군요.&lt;/p&gt;
&lt;p&gt;이와 관련하여 자료를 찾아보니, 1월에 유독 상실감과 무기력감을 느끼는 이유로는 다음과 같은 것들이 있다고 합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;일조량 감소&lt;/strong&gt;: 1월은 일조량이 가장 적은 달로, 햇빛을 받을 시간이 적어지면서 우울감이 증가할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;연말연시의 스트레스&lt;/strong&gt;: 한 해를 결산하고 새로운 목표를 세우는 과정에서 부담감을 느낌&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;휴가 종료&lt;/strong&gt;: 연말 휴가 후 다시 일상으로 복귀하는 과정에서 무기력감을 경험&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;저 역시 여기에 해당하는 부분이 많았습니다. 연말에는 긴 휴가를 다녀왔고, 연말까지 끝내야 할 업무를 마무리하느라 막판 스퍼트(?)를 내기도 했죠. 그러다 보니 1월이 되면서 모든 걸 새롭게 시작해야 한다는 부담감이 더 크게 다가온 것 같습니다.&lt;/p&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExams5MTJ1OXBxZ2I0MGJ6YmZyMDNmdno1a3JscGVlaHIwY3UxcnQxNiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/QLj1DlO0Qe2Ws/giphy.gif&apos; alt=&apos;그림&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;완성된 2024년, 이제 2025년의 도화지에 첫 스케치를 할 시간&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;새해라는 환경적 변화가 모든 것을 새로 시작한다는 느낌을 주는데요. 그것이 저에게는 마치 &lt;em&gt;그리던 그림을 서둘러 마무리하고 숨을 돌렸더니, 흰 도화지를 새로 받아 스케치부터 시작하려는 느낌&lt;/em&gt; 같았습니다. 막상 다시 그리기 시작하면 금방 익숙해지겠지만, 처음엔 막막하고 부담스러울 수밖에 없겠죠.&lt;/p&gt;
&lt;p&gt;다행히 1월의 우울감은 시간이 지나면 자연스럽게 사라진다고 합니다. 그리고 설 연휴를 맞이하면서 충분히 휴식하는 시간도 가졌습니다. 덕분에 저 역시 지금은 한결 나아졌고, 다시 평상시의 리듬을 찾아가고 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;깊은-몰입과-잦은-상황-변화&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B9%8A%EC%9D%80-%EB%AA%B0%EC%9E%85%EA%B3%BC-%EC%9E%A6%EC%9D%80-%EC%83%81%ED%99%A9-%EB%B3%80%ED%99%94&quot; aria-label=&quot;깊은 몰입과 잦은 상황 변화 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;깊은 몰입과 잦은 상황 변화&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExNGZ4aWg5MTJ5enYxMjhqZTd3cXRydTJ0MWVtMjc1a3l1bzZoNmxqYiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/SVgCHJ2n35EA6XFPpO/giphy.gif&apos; alt=&apos;몰입&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;둘 사이의 밸런스를 찾는 과정&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;두 번째 이유는 개인 성향적 요인인&lt;strong&gt;업무에 대한 깊은 몰입과 잦은 상황 변화의 충돌&lt;/strong&gt;이었습니다.&lt;/p&gt;
&lt;p&gt;저는 &lt;strong&gt;하나의 어려운 문제를 깊이 파고들어 해결하는 것&lt;/strong&gt;을 좋아합니다. 또한 결과의 &lt;strong&gt;디테일과 완성도&lt;/strong&gt; 역시 중요하게 생각하는 편이기 때문에, 이런 업무들을 맡으면 끝까지 완벽하게 완성하고 싶은 욕구가 생기곤 했습니다. 이것은 저의 열정과 동기 부여를 만드는 요소 중 하나였죠. 그래서인지 실제로 작년에 회사에서 제가 맡은 업무들도 대부분 그런 성향을 반영한 것들이었습니다.&lt;/p&gt;
&lt;p&gt;이런 방식의 업무 스타일은 &lt;strong&gt;인내심과 끈기&lt;/strong&gt;를 요구하는데요, 저는 이 분야에서 매우 재능(?)이 뛰어난 편입니다.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 480px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3bb9f9d6e0bd9f2add7e7789f9b5e489/7cc5e/1.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.12883435582822%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABAAFA//EABYBAQEBAAAAAAAAAAAAAAAAAAECAP/aAAwDAQACEAMQAAABWvKebrVRjLK6GlTP/8QAGxAAAgIDAQAAAAAAAAAAAAAAAAIQEgERIQP/2gAIAQEAAQUC82iiiZ0K/LGNi2Owkf/EABcRAQEBAQAAAAAAAAAAAAAAAAEAEBH/2gAIAQMBAT8BcS5f/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEQ/9oACAECAQE/AVyP/8QAFxAAAwEAAAAAAAAAAAAAAAAAACAxEP/aAAgBAQAGPwLIsIn/xAAdEAACAgEFAAAAAAAAAAAAAAAAARExIRBBUWFx/9oACAEBAAE/IZEJJqjqFjjSIpDAkB7m4+BUf//aAAwDAQACAAMAAAAQ+8Gz/8QAGBEAAgMAAAAAAAAAAAAAAAAAABEBECH/2gAIAQMBAT8QSDB1f//EABgRAQADAQAAAAAAAAAAAAAAAAEAEBFR/9oACAECAQE/EBmuwNp//8QAHRABAAMBAAIDAAAAAAAAAAAAAQARIUExYVGBkf/aAAgBAQABPxAQNPRDdhPcWbfqyG23EoAJgdgNr8wKKKp2dQyj5/BhgrIzpmo//9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;인내심&quot;
        title=&quot;인내심&quot;
        src=&quot;/static/3bb9f9d6e0bd9f2add7e7789f9b5e489/7cc5e/1.jpg&quot;
        srcset=&quot;/static/3bb9f9d6e0bd9f2add7e7789f9b5e489/d2f63/1.jpg 163w,
/static/3bb9f9d6e0bd9f2add7e7789f9b5e489/c989d/1.jpg 325w,
/static/3bb9f9d6e0bd9f2add7e7789f9b5e489/7cc5e/1.jpg 480w&quot;
        sizes=&quot;(max-width: 480px) 100vw, 480px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;em&gt;어릴 적부터 인내심 하나는 기가 막혔다!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;위 사진은 제가 고등학생 때 진행했던 행동 발달 항목 테스트 결과지인데요. 인내심이 평균적인 다른 사람과 비교했을 때 상당히 높은 편으로 나온 것을 볼 수 있습니다. 상당히 아웃라이어(?)라고 볼 수 있죠. 이러한 성향은 개발자로서 어려운 문제를 인내심을 가지고 끈기 있게 해결해 나가는 데 있어서 큰 장점으로 작용했습니다.&lt;/p&gt;
&lt;p&gt;하지만 반대로, &lt;strong&gt;불확실한 환경과 잦은 변경 사항&lt;/strong&gt;은 저에게 스트레스로 다가왔습니다. 빠르게 프로토타이핑을 하거나 개념 증명(Proof of Concept) 중심의 업무는 흥미를 끌지 못했죠. 그런데 제가 속한 팀은 &lt;strong&gt;해외향 신규 서비스 런칭&lt;/strong&gt; 을 목표로 하는 팀이기 때문에 서비스 방향을 탐색하는 과정에서 기획 변경(피보팅, Pivoting)이 빈번히 발생했습니다.&lt;/p&gt;
&lt;p&gt;이 과정에서 지금까지 공들여 만든 작업물들이 사용되지 않고 폐기되는 경우도 많았고, 그런 상황이 반복될수록 심리적인 저항감이 커졌습니다.&lt;/p&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExZjQzNmhmNGVwY3dodjYzN3I0ZXA5a2pwZ2thMGcxanAzZzV5cGJjZyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/XBpUGMmoGM4DVHoRMZ/giphy.gif&apos; alt=&apos;방향&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;이 방향이 아닌가? 다른 길로 가보자!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;물론 저는 변화 자체를 거부하는 사람은 아닙니다. 하지만 회사의 서비스 방향이 계속 바뀌고, 동의할 수 없는 결정이 내려질 때면 감정적으로 소모되는 느낌이 들었습니다.&lt;/p&gt;
&lt;p&gt;결과물에 주인 의식을 갖고 일하는 것이 중요하다는 제 가치관이 흔들리기 시작했죠. &lt;em&gt;‘코드가 버려질 수도 있다는 걸 의식하고 덜 열정적으로 일하는 것이 맞는 걸까?’&lt;/em&gt; 라는 고민이 들었거든요.&lt;/p&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExMTVlOGNnYm1pOGZub3Z5NjV0czY4bGxtMWtucWxtbG0yeXE1MW01aCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/3orieVZUfsWliRDxmg/giphy.gif&apos; alt=&apos;주인의식&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;우리가 코드의 주인은 아닐지라도, 그 탐색 과정은 가치 있다.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;여기에 대한 해답은 팀원들에게 저의 고민을 솔직하게 공유하면서 얻을 수 있었습니다. 우리가 돈을 받고 일하는 이상, 코드의 주인은 결국 &lt;strong&gt;회사&lt;/strong&gt;입니다. 그러므로 결과물에 과몰입하는 것이 꼭 좋은 방향은 아닐 수도 있다는 것이죠.&lt;/p&gt;
&lt;p&gt;몰입과 상황 변화를 대처하는 방법으로는 &lt;strong&gt;결과를 탐색하는 과정 또한 가치 있다&lt;/strong&gt; 는 마음가짐을 갖는 것이었습니다. 코드의 가치는 단순히 배포된 결과물에서 끝나지 않습니다. 과정에서 얻은 경험과 지식이 팀에 축적되고, 팀원들에게 공유되면서 무형 자산이 됩니다.&lt;/p&gt;
&lt;p&gt;팀원들과 함께 우리가 하고 있는 업무를 스스로 평가해 보았을 때 우리는 일반적인 웹 서비스에서는 경험할 수 없는 흥미롭고 도전적인 업무를 하고 있고, 이 과정에서 저의 경험은 팀에 자산으로 남아서 다른 팀원들에게도 많은 도움이 되고 있다고 평가해 주셨습니다.&lt;/p&gt;
&lt;p&gt;실제로 제가 개발한 기능이 폐기된 적이 있지만, 그 과정에서 배운 것들이 이후 프로젝트에서 더 나은 코드를 작성하는 데 큰 도움이 되었습니다. 또한 제 경험을 팀원들에게 전수하면서 팀 전체의 역량을 높이는 계기가 되기도 했죠.&lt;/p&gt;
&lt;p&gt;이러한 관점의 변화를 통해 결과물이 사용되지 않는다고 해서 그것이 모두의 시간과 노력이 허사로 느껴지는 것은 아니라는 것을 깨달았습니다. 우리의 노력은 결국 어디선가 다시 쓰일 것이고, 그 과정에서 배우는 것들이야말로 가장 값진 자산이니까요.&lt;/p&gt;
&lt;h2 id=&quot;보물섬-찾기와-배-만들기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EB%B3%B4%EB%AC%BC%EC%84%AC-%EC%B0%BE%EA%B8%B0%EC%99%80-%EB%B0%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0&quot; aria-label=&quot;보물섬 찾기와 배 만들기 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;보물섬 찾기와 배 만들기&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExcjR4amVxZzRobjhpeWNtZHhienhwcDJjMzNqcGFrajV2OHlsY3A1dyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/sTg66zDF6KicjY6wp5/giphy.gif&apos; alt=&apos;보물섬&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;보물섬을 향한 항해&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;세 번째 이유는 조직적 요인, &lt;strong&gt;일의 목표와 방향, 의미가 명확하지 않다는 점&lt;/strong&gt;이었습니다.&lt;/p&gt;
&lt;p&gt;저는 일의 목표와 방향에 공감할 수 있는지의 여부가 동기 부여에 큰 영향을 미치는 편입니다. 그런데 시간이 흐를수록 우리 서비스의 목표와 방향이 여러 번의 피보팅을 거치며 정확하게 무슨 문제를 해결하고 싶은 것인지가 명확하지 않다는 생각이 들었습니다.&lt;/p&gt;
&lt;p&gt;팀원들에게 이 내용을 공유할 때 저는 &lt;em&gt;보물섬과 배&lt;/em&gt; 를 비유로 들어 설명했습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;일반적인 목표 지향적인 회사에서는 이렇게 일을 하는 것 같아요. 바다 너머에 보물섬이 있다고 해보죠. 육지에 있는 사람들은 그 보물섬을 찾기 위해 배를 만들고 노를 젓습니다. 이 과정이 물론 힘들고 어렵겠지만, 목표가 명확하고 향하는 방향이 명확하다면 그 노력이 가치 있게 느껴질 거예요.&lt;/p&gt;
&lt;p&gt;그런데 저희 조직은 좀 반대인 것 같아요. &lt;em&gt;“일단 배를 만들어. 그리고 노를 저어봐. 그러다 보면 보물섬을 만날지도 몰라.”&lt;/em&gt; 라는 느낌이 들어요. 열심히 노를 저어야 하는 실무자 입장에서는 시간이 흐를수록 동기 부여가 점점 옅어질 수밖에 없는 것 같아요.&lt;/p&gt;
&lt;p&gt;보물섬을 찾는 것이 우리가 풀어야 할 문제이자 목표고, 어떤 방향으로 가야할 지 정하는 것이 선장의 역할일 거예요. 그리고 실무자는 선장의 명령에 따라 열심히 노를 저어야 합니다. 이것이 각자의 역할이니까요.&lt;/p&gt;
&lt;p&gt;열심히 노를 젓기 위해서는 보물섬을 찾는 것이 왜 중요한지를 이해하고 있어야 하는데, 그게 명확하지 않다면 노를 젓는 것이 힘들어질 수밖에 없는 것 같아요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이런 이야기를 바탕으로 여러 이야기를 나누었는데요. 이를 통해 저는 조직 관점에서 탑다운 의사 결정을 내릴 때 충분한 설명과 근거가 뒷받침되지 않았다는 점, 그리고 실무자가 리더에게 편하게 의견을 전달할 수 있는 커뮤니케이션 창구가 필요하다는 것을 느꼈습니다.&lt;/p&gt;
&lt;p&gt;우리 조직의 이런 부분이 사기에 영향을 미치고 있다는 점에 대해서는 공감했지만, 매우 큰 조직에 속해 있는 실무자의 입장으로써 여기에 대해 뚜렷한 해결책을 제시하기는 어려웠습니다. 사람들이 모인 곳에서는 결국 정치적인 요소가 들어가기 마련이라는 점을 감안해야 한다는 의견도 있었구요.&lt;/p&gt;
&lt;p&gt;하지만 팀원들과 이런 이야기를 나누면서 서로의 생각을 공유하고 공감하는 것만으로도 감정 해소에 많은 도움이 되었습니다.&lt;/p&gt;
&lt;h2 id=&quot;결론&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B2%B0%EB%A1%A0&quot; aria-label=&quot;결론 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;결론&lt;/h2&gt;
&lt;p&gt;
            &lt;img src=&apos;https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExMHU3NGJvOTcwcTg1Mm0ybGlwdWdzZDUzOXE0ZGtvcjE5aXduN3JmNSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/SsHZjFZTqLLqTedLw9/giphy.gif&apos; alt=&apos;결론&apos; loading=&apos;lazy&apos; /&gt;
          
&lt;em&gt;모든 직장인들 화이팅!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;초반에는 번아웃이 왔다는 사실을 인정하고 싶지 않았지만 이를 받아들이고 원인을 분석하며 해결책을 찾아가는 과정에서, 저는 멘탈적으로 한층 성장할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;특히, 제 노력과 가치를 인정해 주는 팀원들에게 감사함을 느꼈고, 솔직한 대화를 통해 신뢰가 더욱 깊어졌습니다. 무엇보다도 &lt;strong&gt;충분한 휴식과 팀원들과의 소통이 가장 중요하다&lt;/strong&gt;는 것을 깨달았습니다. 서로의 고민을 공유하고 공감하는 과정에서 감정적으로도 큰 위안을 얻을 수 있었죠.&lt;/p&gt;
&lt;p&gt;이렇게 해서 번아웃의 이유를 분석해 보았는데요, 이러한 경험을 통해 저는 &lt;strong&gt;상황 변화에 더 유연하게 대응할 수 있는 개발자로 성장하고 있다&lt;/strong&gt;는 확신이 들었습니다. 물론 퇴사나 이직 같은 극단적(?) 선택지도 있겠지만, 저처럼 본인을 둘러싼 상황과 성향, 감정을 분석해 보고 글로 정리해 보는 것도 좋은 방법이 될 수 있을 것 같아요.&lt;/p&gt;</content:encoded></item></channel></rss>