<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>y_cow.log</title>
        <link>https://velog.io/</link>
        <description>프론트엔드 Jr</description>
        <lastBuildDate>Tue, 11 Jul 2023 16:33:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>y_cow.log</title>
            <url>https://velog.velcdn.com/images/y_cow/profile/a3827df8-18bb-4606-9b77-490e85bb9fba/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. y_cow.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/y_cow" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[ github GPG란? (OSSCA ArgoWorkflows)]]></title>
            <link>https://velog.io/@y_cow/github-GPG%EB%9E%80-OSSCA-ArgoWorkflows</link>
            <guid>https://velog.io/@y_cow/github-GPG%EB%9E%80-OSSCA-ArgoWorkflows</guid>
            <pubDate>Tue, 11 Jul 2023 16:33:24 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>오픈소스 컨트리뷰션에 멘티로 참여했습니다. 제 목표 오픈소스는 ArgoWorkflows.
멘티로 첫번째 활동에 대한 기록입니다.</p>
</blockquote>
<p>멘티로 첫번째 활동에 대해 지령을 받았습니다. 오픈소스 기여에 필요한 내용들을 연습하기 위해 멘토님이 레포지토리를 하나 만들어 주셨는데 해당 레포지토리를 fork해서 주어진 이슈 템플릿을 골라 생성하고 목표를 이뤄야 했는데 목표는 간단했습니다.</p>
<ol>
<li>docs/users/[이름].md 문서 추가하기</li>
<li>docs/users/users.md 에 내 md문서 링크 걸기</li>
</ol>
<p><strong>단! PR컨벤션 지키기,커밋 메시지 컨벤션 적용해보기(optional), DCO 봇의 체크 통과하기, GPG를 이용해 서명된 커밋 작성하기</strong>
다른건 몰라도 GPG, DCO봇은 처음 들어보는거였는데 친절하게 참고링크도 다 걸어주셔서 금방 이해했습니다👍</p>
<h3 id="gpg란-gnu-privacy-guard">GPG란? (GNU Privacy Guard)</h3>
<p><img src="https://velog.velcdn.com/images/y_cow/post/4584eb50-69a9-41b3-b28b-d62da210eb60/image.png" alt="">
GPG란 PGP 라는 전자우편 암호화 도구를 기반으로 만든 소프트웨어로 여러가지의 암호화를 지원하며 디폴트로 RSA 알고리즘을 사용합니다.</p>
<h3 id="사용-이유">사용 이유</h3>
<p><img src="https://velog.velcdn.com/images/y_cow/post/1d93f748-1b33-4d1c-9922-de2eab8262a9/image.png" alt=""></p>
<p>깃허브에서 이 GPG 키를 등록하면 커밋, 태그에 로컬로 서명하여 사람들에게 <strong>변경 내용에 출처에 대한 신뢰</strong>를 줄 수 있습니다. 검증된 커밋이라고 위에 보이는 사진처럼 Verified 태그도 달아주죠! 무엇보다 ArgoWorkflows 프로젝트에는 검증된 커밋을 사용해 커밋을 올리라는 조건이 존재했습니다.</p>
<h3 id="gpg-설치-및-설정">GPG 설치 및 설정</h3>
<p>저는 맥os 사용자이기에 brew를 이용했습니다.</p>
<pre><code>brew install gpg //gpg 설치

gpg --gen-key</code></pre><p><code>gpg --gen-key</code>를 입력하면 이름, 이메일을 입력하라고 나오는데 사용하실 이름과 이메일을 입력하시면 됩니다. (이메일은 깃허브에 등록해야하니 깃허브에 등록된 이메일과 통일하시면 편해요!) 그리고 다 입력했다면 O 를 입력해주면 프롬프트가 나오는데 앞으로 커밋을 보낼 때 등등 사용할 암호를 설정해주시면 됩니다. 계속 사용하니 잊지않는걸로 설정하세요!</p>
<pre><code>We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key E15D651143742DAD marked as ultimately trusted
gpg: directory &#39;/Users/jeyraof/.gnupg/openpgp-revocs.d&#39; created
gpg: revocation certificate stored as &#39;/Users/jeyraof/.gnupg/openpgp-revocs.d/85B5FA0A8A67AA1A20FA7D4BE15D651143742DAD.rev&#39;
public and secret key created and signed.

pub   rsa3072 2021-02-08 [SC] [expires: 2023-02-08]
      85B5FA0A8A67AA1A20FA7D4BE15D651143742DAD //여기가 key
uid                      Test RealName &lt;test@email.com&gt;
sub   rsa3072 2021-02-08 [E] [expires: 2023-02-08]</code></pre><p>완료되면 해당 메세지가 보일텐데 여기 보이는 key는 나중에 필요하니 따로 메모장같은곳에 적어두시는걸 추천합니다! RSA3072 암호화 알고리즘을 적용했다고 합니다.</p>
<pre><code>$ git config --global user.email test@email.com
$ git config --global user.name &quot;Test RealName&quot;
$ git config --global user.signingkey 85B5FA0A8A67AA1A20FA7D4BE15D651143742DAD
$ git config --global commit.gpgsign true
$ git config --global gpg.program gpg</code></pre><p>그리고 위처럼 깃 설정을 변경 해주시면 됩니다! email, name, signingkey에는 위에서 입력한 이메일과 이름 그리고 키를 입력하시면 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/y_cow/post/c2e5fd6a-9e32-4049-a44c-018f0b3eff07/image.png" alt=""></p>
<p>그리고 다른 프로젝트에서 커밋 메세지를 작성해 보시면 비밀번호 입력하는 창이 나올겁니다! 커밋을 추가하시고 <code>git log</code>를 확인하면 gpg 서명이 되어있는걸 확인하실 수 있습니다.
암호를 묻는 창이 나오지 않고 에러가 나온다면 <code>export GPG_TTY=$(tty)</code> 을 입력후에 다시 시도해보세요.</p>
<p>저는 IDE를 껐다가 프로젝트 킬때마다 에러가 생겨서 고정했는데 만약 고정하고 싶으시다면 맥os에 root폴더에서 숨김파일을 해제하신 후 .zshrc 파일에 하단에 저 코드를 입력해두시면 다시 입력해주지 않아도 괜찮습니다👍</p>
<h3 id="깃허브에-gpg키-등록해주기">깃허브에 GPG키 등록해주기</h3>
<p>아까 말씀드린것처럼 이메일을 등록해줘야 하는데 이미 등록되어 있으시다면 이메일 등록은 넘어가시면 됩니다.
GPG키를 이제 github에 등록해줘야하는데 프로필을 눌러 Settings에 들어가신 후 SSH and GPG Keys 를 클릭하시면 new GPG key를 눌러 등록하시면 됩니다.</p>
<pre><code>-----BEGIN PGP PUBLIC KEY BLOCK-----

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
gCrQ7YWLfhewIewqujWAeWR/9j7gbg==
=Lu+o
-----END PGP PUBLIC KEY BLOCK-----</code></pre><p>넣어줘야할 내용은 터미널로 돌아가셔서 <code>gpg --armor --export [아까 등록할때 받은 키]</code>를 입력하시면 이런 내용을 받을 수 있는데 절취선까지 모두 복사해서 깃허브에 넣어주시면 됩니다. 그럼 키까지 등록 완료! 이후에 커밋을 올려보시면 Verified 태그가 달린걸 확인할 수 있습니다.</p>
<h3 id="github-dcodeveloper-certificate-of-origin-통과하기">github DCO(Developer Certificate of Origin) 통과하기</h3>
<p><img src="https://velog.velcdn.com/images/y_cow/post/f8cecc3b-7aca-4fbb-afc3-53dc21715b8a/image.png" alt="">
DCO는 오픈소스 프로젝트에 컨트리뷰터가 PR 등 코드에 자신의 기여를 인증하는 방법입니다. 모든 커밋 메시지에 작성자와 일치하는 이메일 주소가 포함되어야 합니다.
DCO봇 체크를 하는 방법은 간단합니다!</p>
<pre><code>git commit -s -m &#39;feat: DCO봇 넘어가기&#39;</code></pre><p>이런식으로 -s 옵션을 걸어주면 커밋 하단에 이미지 처럼 자동으로 Signed-off-by: [이름] [이메일]이 들어가게 되고 DCO봇의 체크를 넘어가게 됩니다.</p>
<h3 id="후기">후기</h3>
<blockquote>
<p><a href="https://github.com/ssi02014/react-query-tutorial">리액트쿼리 튜토리얼</a>에 기여하며 그냥 fork 후에 PR을 올리면 끝인 줄 알았는데 이런 절차들이 있는 줄 꿈에도 몰랐습니다.. 아직 오픈소스에 기여하기 위한 준비단계 이지만 이름있는 프로젝트에 기여할 생각하니 벌써부터 재밌는거 같아요 남은 활동도 열심히 해보겠습니다🔥</p>
</blockquote>
<h3 id="참고-자료">참고 자료</h3>
<p>해당 자료들은 저희 멘토님이 참고하라고 주신 레퍼런스 사이트들입니다.🙇‍♂️</p>
<ul>
<li><a href="https://docs.github.com/ko/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword">키워드를 활용한 issue 연결</a></li>
<li><a href="https://flank.github.io/flank/pr_titles/">PR 네이밍 컨벤션</a></li>
<li><a href="https://github.com/apps/dco">DCO</a></li>
<li><a href="https://www.44bits.io/ko/post/add-signing-key-to-git-commit-by-gpg">GPG</a></li>
<li><a href="https://www.conventionalcommits.org/en/v1.0.0/">커밋 컨벤션</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[뒤로가기 이벤트 막고 원하는 이벤트 실행하기(React)]]></title>
            <link>https://velog.io/@y_cow/%EB%92%A4%EB%A1%9C%EA%B0%80%EA%B8%B0-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A7%89%EA%B3%A0-%EC%9B%90%ED%95%98%EB%8A%94-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0React</link>
            <guid>https://velog.io/@y_cow/%EB%92%A4%EB%A1%9C%EA%B0%80%EA%B8%B0-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A7%89%EA%B3%A0-%EC%9B%90%ED%95%98%EB%8A%94-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0React</guid>
            <pubDate>Sun, 09 Jul 2023 20:05:14 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/y_cow/post/70ce3a1f-7cf0-454c-aaba-b72f08edd74d/image.png" alt=""></p>
<blockquote>
<p>구현 과제 진행 중 페이지 이동은 하지않고 상태들만 뒤로 돌려야하는 이벤트가 필요했는데 제출할때는 결국 버그를 잡아내지 못했지만,, 이후에 정상작동하는 방법을 찾았습니다!</p>
</blockquote>
<h3 id="히스토리-객체">히스토리 객체</h3>
<p>히스토리 객체는 브라우저의 히스토리에 대한 정보를 document, documentState 리스트로 저장하는 객체입니다. 자바스크립트에서 개인정보 보호를 위해 객체에 접근하여 상세한 정보를 알 수는 없습니다.</p>
<blockquote>
<ul>
<li>history.length : 브라우저 히스토리 목록의 <strong>개수를 반환</strong>합니다.</li>
</ul>
</blockquote>
<ul>
<li>history.go() : 인수로 전달받은 정수만큼 히스토리 이동     ex:) history.go(-2) 2개의 이전페이지로 이동</li>
<li>history.back() : 히스토리 목록의 이전 URL로 이동, 브라우저의 뒤로가기와 동일</li>
<li>history.forward() : 히스토리 목록의 다음 URL로 이동, 브라우저의 앞으로가기와 동일</li>
</ul>
<p>위에서 얘기했듯 히스토리는 객체지만 히스토리 리스트는 내부에 자료구조 Stack 형태의 리스트로 구성되어 있습니다. 뒤로가기 버튼을 누르면 window객체에 설정된 popstate 이벤트가 실행되고 기본 이벤트로 설정된 뒤로 또는 앞으로가기가 실행됩니다. (history의 앞뒤는 모두 &quot;POP&quot; 이벤트로 처리되어 구분할 수 없습니다.)</p>
<h3 id="뒤로가기-이벤트-막기">뒤로가기 이벤트 막기</h3>
<p>뒤로가기 이벤트를 막는 방법은 꽤 여러가지 방법이 있습니다! react-router v5의 경우에는 useHistory 훅을 이용했지만 저는 v6를 사용하기에 전역 history객체를 사용했습니다. (v6에서는 useHistory 훅이 없어졌습니다. 페이지 이동 시 useNavigate 사용)</p>
<pre><code class="language-js">history.pushState(null,&quot;&quot;,&quot;&quot;);</code></pre>
<p>router 이동 시 발생하는 popstate의 기본 이벤트를 막을 수는 없습니다. <code>history.pushState</code>를 이용해 페이지 이동없이 현재 히스토리 스택을 추가하고 뒤로가기 버튼으로 인해 뒤로 이동해서 현재의 페이지를 유지시키는 방법입니다. 만약 홈 -&gt; 로그인 -&gt; 게시판으로 이동했고 게시판에서 뒤로가기 이벤트를 막아준다면 이런형태가 됩니다. (pushState와 replaceState 는 popstate 이벤트를 발생시키지 않습니다.)
<img src="https://velog.velcdn.com/images/y_cow/post/9b19a321-1774-4f82-8a4f-8d5cb21c7a16/image.png" alt=""></p>
<p>사실 히스토리 리스트에서 최상단 요소가 pop()되는지는 확실하지 않습니다.. 제가 적용했을 때 그림과 같은 형태로 useEffect를 실행하면 앞으로가기 버튼이 잠깐 활성화 했다가 사라지는 모습을 보고 유추했습니다. 동작은 원하는 대로 진행되었으니까요! 아쉽게도 브라우저는 앞으로가기 이벤트와 뒤로가기 이벤트를 별도로 구분해놓지 않아 두 이벤트 모두 &quot;POP&quot; 이벤트로 처리되므로 저처럼 앞으로 갈 경우 상태의 처리가 곤란하다면 앞으로 가기를 막는것도 하나의 방법인거 같습니다 👍 (gif라 프레임이 잘려 잘 보이지 않네요😅)
<img src="https://velog.velcdn.com/images/y_cow/post/96badb82-d63d-4446-95f2-ccbdc6119eeb/image.gif" alt=""></p>
<h3 id="react-적용버그-존재-❗️">React 적용(버그 존재 ❗️)</h3>
<p>진행한 사전과제로 예시를 들수는 없으므로 cra로 간단하게 프로젝트를 만든 후 홈, 로그인, 게시판 페이지를 router로 연결해 줍니다! 문제만 보여주기 위해 useEffect의 로직만 보여드리겠습니다.</p>
<pre><code class="language-js">// notice.tsx
  useEffect(() =&gt; {
    history.pushState(null, &quot;&quot;, window.location.href);

    const handleClickBrowserBackBtn = () =&gt; {
      if (progress &gt;= 1) {
        setProgress((prev) =&gt; prev - 1);
      } else {
        navigate(&quot;/login&quot;);
      }
    };

    window.addEventListener(&quot;popstate&quot;, handleClickBrowserBackBtn);

    return () =&gt; {
      window.removeEventListener(&quot;popstate&quot;, handleClickBrowserBackBtn);
    };
  }, [progress, navigate]);</code></pre>
<p><img src="https://velog.velcdn.com/images/y_cow/post/eff5c5bb-5a7d-4302-860e-f2b515b947f4/image.gif" alt=""> 페이지를 유지하고 뒤로가기를 막는것까지는 문제없이 진행이 되지만, <code>pushState</code>시에 현재의 주소가 들어가게 되니, 게시판 페이지에서 마지막 뒤로가기를 눌러 login으로 이동 하고 나서 다시 뒤로가기를 누르면 마운트 시에 들어간 pushState인 게시판 페이지가 나오고, 다시 뒤로가기를 누르면 조건문의 navagate(&quot;/login&quot;)이 실행되고, 무한반복이 되어버렸습니다.
이유는 이제서야 알게되었는데 천천히 되짚어 보면 <code>navagate(&#39;/login&#39;)</code>을 통해 로그인 페이지로 이동을 했지만 history.back() 즉 스택을 뒤로간게 아니라 로그인 페이지로 이동한 히스토리 스택을 추가한 형태가 되고 그럼 당연히 이전페이지는 notice페이지가 되는 거였습니다.</p>
<h3 id="react-적용버그-해결">React 적용(버그 해결)</h3>
<p>이걸 어떻게 해결해야할지 이것저것 많은 시도를 해보았더니 첫번째로 알게된건 세번째 인자에 빈 문자열을 넣어주면 됩니다! <a href="https://developer.mozilla.org/ko/docs/Web/API/History/pushState">mdn</a> 문서에 따르면 빈 문자열을 넣게되면 알아서 현재 document의 url로 설정이 됩니다. 굳이 적어주지 않아도 된다는거죠. 그리고 내가 원하는건 뒤로가기니까 <code>navigate(-1)</code> 형태로 주었어요.</p>
<pre><code class="language-js">  useEffect(() =&gt; {
    history.pushState(null, &quot;&quot;, &quot;&quot;);
    console.log(&quot;스택쌓음&quot;);

    const handleClickBrowserBackBtn = () =&gt; {
      console.log(&quot;popstate 실행&quot;);
      if (progress &gt;= 1) {
        setProgress((prev) =&gt; prev - 1);
      } else {
        console.log(&quot;쌓인 스택만큼 제거 루프 실행&quot;);
        navigate(-1);
      }
    };

    window.addEventListener(&quot;popstate&quot;, handleClickBrowserBackBtn);

    return () =&gt; {
      window.removeEventListener(&quot;popstate&quot;, handleClickBrowserBackBtn);
    };
  }, [progress, navigate]);</code></pre>
<p><img src="https://velog.velcdn.com/images/y_cow/post/b96dcc1c-0ca1-46ad-a59a-697b1573d39a/image.gif" alt=""> 이 코드는 뒤로가고 난 후에는 문제가 없습니다. 하지만 흘러가는 형태를 보게되면 이벤트가 반복실행 되는게 보이죠.</p>
<ul>
<li>notice 페이지 진입 (pushState 2번 실행)</li>
<li>클릭이벤트 4번 진행 -&gt; (pushState 4번 실행)</li>
<li>popstate 이벤트(뒤로가기) 진행 -&gt; navigate(-1) 로 인해 뒤로 이동 -&gt; 뒤로이동 했으므로 다시 popstate 진행 -&gt; 쌓인 notice페이지(6번) 만큼 실행 후 페이지이동</li>
</ul>
<p>만약 20가지 선택을 하는 페이지였다면 뒤로가기위해 저 루프를 20번이상을 반복해야 하는거죠.. 하지만 앞으로가기 버튼을 비활성화 시키기 위해서 pushState는 필수였고 그냥 이 루틴으로 픽스하였습니다.
sessionStorage와 쿼리스트링을 이용한 방법도 가능하겠다는 생각이 드네요. sessionStorage는 동일하게 뒤로가기 이벤트를 막는 pushState가 필요할 것 같고 쿼리스트링을 이용하면 가장 깔끔하게 될거 같습니다! </p>
<blockquote>
<p>브라우저의 기본적인 이벤트를 막고 진행을 해야한다는 점이 어떤 에러를 일으킬지 몰라 사실 historyAPI는 지양하는게 좋다지만.. 2일을 붙잡아도 다른 방법이 떠오르지 않네요 😅 추후 기회가 된다면 쿼리스트링으로 업데이트 해보겠습니다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Tree Shaking(lodash)]]></title>
            <link>https://velog.io/@y_cow/Tree-Shakinglodash</link>
            <guid>https://velog.io/@y_cow/Tree-Shakinglodash</guid>
            <pubDate>Mon, 03 Jul 2023 12:41:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/y_cow/post/19d16a07-9294-413d-86c0-7a26afa212f0/image.png" alt=""></p>
<blockquote>
<p>테오의 스프린트가 끝나고 코드 리팩토링 PR을 올렸는데 PL분의 코멘트를 받고 충격먹어 기록해두는 lodash의 tree shaking 🦊</p>
</blockquote>
<h3 id="tree-shaking">tree shaking</h3>
<p>트리 쉐이킹은 <strong>사용하지 않는 코드를 제거</strong>하는 방법입니다. 번들링 사이즈를 줄이기 위해 사용하는 방법으로 webpack 등에서 번들러에 포함이 되어 있는 기능입니다.</p>
<p>평소에 라이브러리를 불러와 사용할 때 다른 곳에서 사용할 때 두개의 방법을 사용하게 되는데</p>
<pre><code class="language-js">import ${name} from &#39;경로&#39;
const name = require(&#39;경로&#39;)</code></pre>
<p><code>import</code>는 ES6에 새롭게 추가된 방식이고 <code>require</code>는 주로 node에서 사용하는 방법 이였습니다. (현재는 node에서도 ES모듈 사용 가능)</p>
<h3 id="lodash">lodash</h3>
<pre><code class="language-js">import { debounce } from &#39;lodash&#39;
import { WheelEvent, useRef } from &#39;react&#39;

const useHorizontalWheel = () =&gt; {
  const wheelRef = useRef&lt;null | HTMLDivElement&gt;(null)
  const onWheelHandler = debounce((e: WheelEvent&lt;HTMLDivElement&gt;) =&gt; {
    if (wheelRef.current) {
      wheelRef.current.scrollLeft +=
        e.deltaY &gt; 0 ? wheelRef.current.clientWidth + 10 : -wheelRef.current.clientWidth + -10
    }
  }, 100)

  return { wheelRef, onWheelHandler }
}

export default useHorizontalWheel
</code></pre>
<p><img src="https://velog.velcdn.com/images/y_cow/post/79202249-44c6-4a93-b7a5-397302ea694e/image.png" alt=""></p>
<p>스프린트 프로젝트 진행 중 마우스 휠을 이용한 가로 슬라이드를 만드는 구간에 debounce 기술을 적용하기 위해 lodash 라이브러리를 설치했고 평소와 똑같이 사용했습니다. 해당 훅은 업로드 페이지에서 사용했고 PL분께 코멘트를 듣고 빌드하여 확인해보니 다른페이지 보다 확실히 큰 사이즈.. 관련된 내용을 찾아보니 이미 많이 이슈가 됐던 사항인지 많은 레퍼런스가 나왔고 결과는 이렇습니다.</p>
<blockquote>
<p>lodash 라이브러리는 <strong>CommonJS 형식으로 (module.exports 방식의 내보내기)</strong> 작성되어 있어 해당 코드는 트리 쉐이킹을 할 수 없다. Webpack은 ES6 모듈 형식으로 의존성을 관리하는 모듈만 Tree-Shaking을 진행한다. <a href="https://webpack.kr/guides/tree-shaking/">웹팩 Tree Shaking</a></p>
</blockquote>
<h3 id="해결-방법">해결 방법</h3>
<p>관련 내용을 찾아보고 플러그인을 설치하는 방법도 있었지만 간단하게 import 내용을 변경하는 방법을 사용했다. 2가지의 방법 중 하나를 채택하여 사용하면 될거 같다.</p>
<pre><code class="language-js">import debounce from &#39;lodash/debounce&#39; // 또는
import { debounce } from &#39;lodash-es&#39; // npm i lodash-es 설치 필요
</code></pre>
<h3 id="적용-후">적용 후</h3>
<p><img src="https://velog.velcdn.com/images/y_cow/post/9fb17320-f4b9-427e-a803-53e68db6787e/image.png" alt=""> 무려 24kB나 줄어 드는걸 볼 수 있다. 번들 크기를 더 줄일 방법이  있는지 빨리 더 찾아봐야겠다. (성능 관련 최적화 작업은 성공 시 성취감이 너무 좋다..)
해당 내용을 몰랐다면 lodash 사용 페이지마다 번들 사이즈를 줄이지 못했을지도 몰랐는데 앞으로 라이브러리 사용 시 해당 라이브러리의 export 방식이 ES 모듈이 맞는지 체크 해야겠다! 완전 좋은 정보 공유 감사합니다 PL,,👍</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[테오의 스프린트 15기 (회고 겸 후기)]]></title>
            <link>https://velog.io/@y_cow/%ED%85%8C%EC%98%A4%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8-15%EA%B8%B0-%ED%9A%8C%EA%B3%A0-%EA%B2%B8-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@y_cow/%ED%85%8C%EC%98%A4%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8-15%EA%B8%B0-%ED%9A%8C%EA%B3%A0-%EA%B2%B8-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Fri, 30 Jun 2023 19:50:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/y_cow/post/99e8e563-8ed3-415a-8169-5e176434c76f/image.png" alt=""></p>
<h3 id="참여-계기">참여 계기</h3>
<blockquote>
<p>길어지는 취준 생활에 지쳐가고 있던 중💀 (<del>신입 좀 뽑아주세요..흑흑</del>) 진행중이던 해커톤도 탈락하고..!
주로 혼자서 개발을 진행하다 보니 제가 어디에 있는지 어느 순간 알수가 없더라구요..? 뭘 더 해야할지 나한테 부족한 부분이 무엇일지 고민하고 있었는데 테오의 스프린트 소식을 지인분께 듣게 되었고 찾아보니 구글 스프린트를 기반으로 5일간 기획설계 -&gt; 개발 -&gt; 배포 로 이어진다는걸 보았는데 처음 든 생각은 가능한가...? 싶었는데 역시 안되는건 없다!! 그래서 다른분들과 협업을 통해 의견을 나누고, 더 체계적인 방법으로 개발을 해보고 싶어 테오의 스프린트에 참여하게 되었습니다. 정말 좋은분들과 개발에 진심이신 분들이 많으니 기회가 된다면 꼭! 참여해보세요 :)</p>
</blockquote>
<h3 id="1일차">1일차</h3>
<p>가장 신기했던 것중에 하나가 바로 님 금지문화!! 처음에는 어색했지만 사용해보니 이유를 알겠더라구요 금방 친근감이 들고 의견을 주고받는 과정이 더 자유로워 지는게 느껴졌어요. 아 그리고 모두 부캐(닉네임)을 정하고 사용하는데 이것도 정말 좋은거 같았습니다 다른 &quot;나&quot;가 되어보는건 더 자신감을 주게 되는거 같아요 👍
<img src="https://velog.velcdn.com/images/y_cow/post/d895e8e2-13c4-4640-9e54-db1362691999/image.png" alt=""> </p>
<p>첫날에는 각자 준비해온 아이디어를 발표하고,아이디어를 설명하는 시간을 가졌습니다. 재밌어 보이는 아이디어가 굉장히 많았지만 저는 <a href="https://namu.wiki/w/%EA%B8%B0%EC%96%B5%EC%9D%98%20%EA%B6%81%EC%A0%84">기억의 궁전</a>이라는 셜록홈즈에도 나온 암기법에서 나온 아이디어로 추억을 시각화 하여 그때의 감정을 다양한 방법(이미지, 음악 등)으로 저장하는 프로젝트에 참여하게 되었습니다!
<img src="https://velog.velcdn.com/images/y_cow/post/cd0be337-4c69-4f08-a464-332f1c47ff89/image.png" alt=""> </p>
<p><img src="https://velog.velcdn.com/images/y_cow/post/7491b935-11e2-4208-bb14-d5b858f2350e/image.png" alt=""> 1. 닉네임에 대한 설명과 역할, 짧은소개
2. 스프린트에서 다같이 해냈으면 하는 목표
3. 개인의 목표 (커리어 관련)
4. 만들 서비스의 궁극적인 목표
5. 스프린트(서비스)에서 제일 중요하게 생각했으면 하는 가치
6. 나의 강점 &amp; 기술스택
7. 나의 약점 &amp; 팀원에게 미리 전하는 Risk
8. 팀에게 바라는 것
9. 명언(개똥철학처럼) 😎</p>
<p>팀이 정해지고 나서 각자의 조 피그잼으로 이동해서 위 리스트 처럼 템플릿을 따라 작성하며 한명씩 작성한 부분에 대해 얘기해 보는 시간을 가지는데(큰 리액션 필수) 자연스럽게 서로가 바라는것과 양해해줬으면 하는것, 서비스에 중요하게 생각하는 부분까지 알아가며 바로 친해지게 되었습니다. 중간중간에 테오와 스탭분들이 와서 진행체크하며 노하우를 알려주는게 너무 도움이 되었고, 무엇보다 팀원분들이 너무 좋은 분들이였어요(리액션 짱..ㅋㅋㅋ) 다음 날 숙제로는 서비스에 필요한 레퍼런스를 찾아와 다시 얘기하기로 했습니다.</p>
<h3 id="2일차">2일차</h3>
<p>2일차에는 레퍼런스를 토대로 팀원들의 생각을 합치고 서비스의 목적, 타겟층, 비슷한 서비스의 사용자의 불편함을 얘기하고 우리 서비스에서는 어떠한 차별점을 둘것인지 의견을 나눴어요. 이때 서비스의 세부적인 사항들이 어느정도 정해지기 시작했죠! 만약 이때 얘기를 나누지 않았다면 서로 다른 방향을 보고 있었을 지도 모른다는 생각이 들어요. 같은 기능이라고 생각했던 부분이 얘기를 나눴을 때 서로 다른 방향을 보고있었거든요ㅎㅎ.. 의사소통이 얼마나 중요한지 다시 한번 깨달았습니다.
<img src="https://velog.velcdn.com/images/y_cow/post/17e31836-79fc-4292-9ebf-2cb1cd7b6ff6/image.png" alt=""> <img src="https://velog.velcdn.com/images/y_cow/post/8390602c-38d4-431e-84a6-f26979bab899/image.png" alt=""> 그렇게 정해진 기능과 페이지에 대해 스토리보드를 작성해보고 내일 이 스토리 보드를 기준으로 각자의 스케치를 어느정도 해오기로 약속했습니다! 뭔가 체계적으로 흘러가는 이 경험이 아주 좋았어요!! 서비스 자체의 이해도가 다른 기분이였습니다. 저희는 인스타 처럼 보여주기 위한 SNS보다는 개인적인 추억 저장소가 될 수 있게 방향성을 잡았고 보여주고 싶은 추억은 보여줄 수 있는 기능도 생각했지만 후 순위로 미뤄두었습니다. (이후에 개발기간이 2일 인걸 다시금 깨닫고 아차 싶어서 기능다이어트를 진행하게 됩니다^^.. 이거 안했으면 큰일날 뻔 했어요)</p>
<h3 id="3일차">3일차</h3>
<p>세부적인 디자인은 디자이너 분이 해주시겠지만 어느정도 각자 생각하는 페이지별 스케치를 보고 한 화면씩 본인의 스케치에 대해 설명하고 해당 화면 설명이 모두 끝난 후 마음에 들었던 &quot;요소&quot;에 투표를 진행했죠!! 그리고 UI 결정권자와 PL을 정해 확실하게 기능과 컨셉을 픽스했습니다. 이후 해야할 태스크를 BDD(Behavior Driven Development)와 SDD(Schema Driven Development)를 통해 태스크를 정리했습니다. BDD와 SDD가 궁금하시면 <a href="https://velog.io/@teo/behavior-driven-development-schema-driven-development">테오의 글</a>을 보시는 걸 추천드릴게요👍
<img src="https://velog.velcdn.com/images/y_cow/post/95cdeb97-2bee-4b7f-a5f8-c7ab8d6f2054/image.png" alt=""><img src="https://velog.velcdn.com/images/y_cow/post/c3380c68-e614-45d7-8ff6-bf224e70f5a6/image.png" alt=""> <img src="https://velog.velcdn.com/images/y_cow/post/7bc4379f-92c7-4822-8323-2b66e04f6462/image.png" alt="">
아 정말 너무 좋았습니다. 해야할 태스크가 딱딱 정리되고 코드는 작성하지도 않았는데 이미 뭘 만들어야 하는지 머릿속에 구상이 되는 느낌이였어요!! 저는 이렇게 개발해본게 처음이였거든요. 이후에는 <strong>임팩트</strong> 와 <strong>이펙트</strong>를 기준으로 기능에 대해 마지막으로 정리하며 기능다이어트 까지 마무리하고 간단하게 사용할 기술스택을 정리 후 내일부터 디자인과 개발에 들어가기로 했습니다.</p>
<h3 id="4-5일차-개발기간">4-5일차 (개발기간)</h3>
<p>레포지토리는 깃허브 오거니제이션 만들어 사용하기로 했고 컨벤션은 깃플로우 방식을 사용하기로 했습니다! 현직자이신 PL분이 프로젝트 셋업과 린트설정을 너무 잘해주셔서 커밋린트로 알게되고 체계적으로 진행할 수 있었어요! 각각 진행중인 태스크는 이슈를 만들고 해당 이슈번호로 브랜치를 생성해서 PR을 통해 2명이상의 어프로브를 받으면 머지가 가능하도록 했습니다. 커밋은 마지막에 이슈번호를 붙여서 해당 이슈에 대한 작업사항을 남기구요!</p>
<ul>
<li>issue <img src="https://velog.velcdn.com/images/y_cow/post/d55c1597-003d-4da0-9073-2502761ca7a9/image.png" alt=""></li>
<li>PR <img src="https://velog.velcdn.com/images/y_cow/post/5c1610be-d262-45e7-8587-40bf94b919f6/image.png" alt=""></li>
</ul>
<p>프로젝트는 Next.js, TypeScript,react-query, emotion 으로 시작하고 추후 전역상태가 필요하면 추가하기로 했고
저는 emotion/styled 설정, 키워드 기반 AI 이미지 생성 기능, Loader 컴포넌트를 담당했습니다! 팀은 9명이지만 프론트가 6명이라 세세하게 나누었습니다ㅎㅎ..</p>
<p>카카오의 Karlo와 유명한 openAI에 DALL・E 모델을 고민했는데 저는 가난한 취준생이기에 팀원들과 협의 후 달에 500장 무료인 Karlo로 채택하여 사용했습니다.
하나의 이슈가 있었는데,, Karlo는 영어로만 사용할 수 있었기에 사용자의 입력이 한글일 경우를 고려했어야 해서 PAPAGO API로 사용자의 입력을 보내 번역한 후 다시 Karlo로 보내 이미지를 받아오는 방법이였습니다.</p>
<p>두번이나 외부 API를 거쳐야 하기에 속도면에서 조금 느릴 수 있지만,, 현재의 방법에서는 최선이라 생각해서 진행했습니다. 또 API KEY를 프라이빗 하게 관리하기 해야 했는데 굳이 백서버를 통할 필요 없이 .env에 NEXT_PUBLIC이 아닌 환경변수를 구성해 Next에서 제공하는 api router를 사용해 서버를 통해 받아오도록 구성했습니다. 혹시 저처럼 사용하실 분들이 계실 수 있으니 도움이 되길 바라며 창피하지만 코드 남겨봅니다😎 (더 좋은 방법이 있다면 알려주세요!!)</p>
<ul>
<li><strong>커스텀 훅</strong>
<img src="https://velog.velcdn.com/images/y_cow/post/5028ff52-3ede-43ba-b94c-3bf058788411/image.png" alt=""></li>
<li><strong>api router</strong>
<img src="https://velog.velcdn.com/images/y_cow/post/b71c26c6-c8e7-470e-bae9-ec861db2b74b/image.png" alt=""> 생각보다 제 파트를 빠르게 끝내게 되어 어려움을 겪고 계신 팀원 분들과 페어프로그래밍도 진행하며 알차게 개발했습니다. 👍 (완성하고 팀원분들과 이미지 생성 테스트하며 논건 비밀 500장 다 써서 아이디 교체한건 더 비밀) 개인적으로 개발하다가 코어 타임에는 ZEP에 모여 소통하며 개발했는데 회사를 다니게 되면 동료분들이 의견을 나누는데 거리낌이 없으면 좋겠다는 생각이 들었습니다. 개발이 아주 착착 진행되었어요.</li>
</ul>
<h3 id="6일차">6일차</h3>
<p>이제 10시에 다른분들에게 서비스를 배포하여 선보일 차례가 되었습니다! 저희 팀은 나름 기능 다이어트를 한다고 했지만,, 2일이란 시간이 정말 빠르더라구요 다들 빠르면 새벽 3시 늦으면 6시까지 달렸지만 10시 이전에 배포까지는 문제 없이 되었지만 테스트를 미리 해보지 않아 작은 문제들이 생겼었지만! 모든 팀원들이 초인이 되어 정말 빠르게 문제를 찾아 HOT-FIX를 진행했고 MVP 기능은 작동가능하여 선보일 수 있었습니다! 테스터 분들이 좋은 반응을 보여주셨고 나중에 써보고 싶다고 테스트 아이디를 따로 물어보시는 분도 계셔서 정말 기분 좋았어요(개발하길 잘했다) <img src="https://velog.velcdn.com/images/y_cow/post/1f9d417e-60dc-400a-bf34-11db229b6604/image.gif" alt=""> 아직 완벽하지 않아서 속도가 조금(많이) 느리지만 개선할 수 있습니다!! 이미지를 생성해야 해서 조금 느린거 같아요.. 흑 <img src="https://velog.velcdn.com/images/y_cow/post/673a2206-ce4d-4c90-9927-57aa065a6ec7/image.png" alt=""> 저장한 리스트에서 추억을 클릭하면 이미지 다운로드도 가능하고 사용자가 넣어둔 음악(youtube링크)도 자동으로 재생돼요!! 저장 기능도 있어서 폴라로이드 처럼 이쁜 사진도 저장이 됩니다👍
테스트 인터뷰 시간이 끝나고 팀원분들과 회고를 진행했습니다</p>
<p><img src="https://velog.velcdn.com/images/y_cow/post/5ccee4b7-ddf2-45ba-8173-65ae51568145/image.png" alt=""> 1. 프로젝트 결과물에 대한 회고
2. 협업과 팀에대한 회고
3. 스프린트, 그리고 나에 대한 회고
각각 Liked, Learned, Lacked, Longed for을 작성하고 발표했는데 정말 팀원분들 모두 늦게까지 고생했는데 힘들었다가 아니라 <strong>시간이 짧아서 아쉬웠다</strong>가 대부분이였고 저도 너무 아쉬운 마음과 함께 어떤 프로젝트보다 몰입해서 진행할 수 있었던 것 같습니다.</p>
<h3 id="마무리">마무리</h3>
<blockquote>
<p>사람적으로도 너무 좋고 프로젝트에 열정적인 팀원분들을 만나서 너무너무 좋았고 (너무 늦은시간까지 진행해 테오가 GG치고 자러간 유일한 팀⭐️) 앞으로도 오래오래 좋은 관계를 유지하면 좋겠습니다 😄 이번 스프린트 처럼 무리하게는 아니지만 프로젝트에서 부족했던 부분들을 하나하나 디벨롭 하기로 했고 언젠간 포트폴리오에 올려도 손색없을 정도의 프로젝트가 될 날을 기다리며.. 13조 파이팅!!!🔥
좋은 기회를 경험을 선사해준 테오와 고생하신 스탭분들에게 감사하다는 말을 드리며 언젠간 성장해서 저도 테오처럼 좋은 영향을 줄 수 있는 개발자가 될게요!!!! 🙇‍♂️🫡</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>