<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>치즈덕처럼 개발하기</title>
        <link>https://velog.io/</link>
        <description>열심히 아자아자</description>
        <lastBuildDate>Wed, 11 Dec 2024 02:28:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>치즈덕처럼 개발하기</title>
            <url>https://velog.velcdn.com/images/jun_o_o/profile/cf10d684-d45f-46c7-9a40-db69e1dd6fc2/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 치즈덕처럼 개발하기. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jun_o_o" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[ bundle-analyzer로 최적화하기 🥳(feat. dynamic import)]]></title>
            <link>https://velog.io/@jun_o_o/bundle-analyzer%EB%A1%9C-%EC%B5%9C%EC%A0%81%ED%99%94%ED%95%98%EA%B8%B0-feat.-dynamic-import</link>
            <guid>https://velog.io/@jun_o_o/bundle-analyzer%EB%A1%9C-%EC%B5%9C%EC%A0%81%ED%99%94%ED%95%98%EA%B8%B0-feat.-dynamic-import</guid>
            <pubDate>Wed, 11 Dec 2024 02:28:31 GMT</pubDate>
            <description><![CDATA[<h2 id="시작하며">시작하며!</h2>
<p>프론트엔드에서 개발을 진행하다 보면, 최적화를 위해 여러 가지를 알아볼 때가 분명 존재한다. 나의 경우에는 이번 프로젝트에서 여러 최적화를 진행하기로 하였고, 그 중 하나는 <code>bundle size</code>를 줄여보자는 것이었다.</p>
<p><code>bundle size</code>가 커질수록 초기 로딩 시간이 늘어나고, 결국 사용자 경험에 좋지 않은 영향을 주므로 이번 기회에 해보자고 생각했다!</p>
<h2 id="bundle-analyzer">bundle-analyzer</h2>
<p>최적화를 하기 전에, 프로젝트의 번들 파일이 어떻게 구성되었는지 확인해야 한다. 나는 <code>bundle-analyzer</code>를 사용하였다.</p>
<pre><code>pnpm install @next/bundle-analyzer</code></pre><p><img src="https://velog.velcdn.com/images/jun_o_o/post/b50c7f24-6a2d-470f-9c14-cd1972a3c71a/image.png" alt=""></p>
<p>프로젝트에서 next를 사용하므로, <code>next.config.ts</code>에 <code>bundle-analyzer</code>를 적용시켜준다.</p>
<pre><code class="language-typescript">
import { NextConfig } from &quot;next&quot;;
const withBundleAnalyzer = require(&#39;@next/bundle-analyzer&#39;)({
  enabled: process.env.ANALYZE === &#39;true&#39;,
});

...

export default withBundleAnalyzer(nextConfig);</code></pre>
<p>해당 코드는, env 파일의 <strong>ANALYZE</strong> 스크립트 설정을 통해 언제 <code>bundle-analyzer</code>이 실행될 지 적용할 수 있다. </p>
<p>나의 경우 build 할 시 실행되도록 작성하였다.</p>
<pre><code>ANALYZE=true pnpm run build</code></pre><h2 id="실행">실행</h2>
<p>build시, 프로젝트의 현재 번들 크기가 나타나게 된다.</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/a037fa8a-dd64-436a-bf73-200cd65837fb/image.png" alt=""></p>
<p><strong>client.html</strong>, <strong>edge.html</strong>, <strong>nodejs.html</strong> 총 3개의 번들링 결과를 시각적으로 분석해준다.</p>
<p>위의 충격적인 사진의 경우 <strong>client.html</strong>이다...</p>
<pre><code class="language-typescript">const Lottie = dynamic(() =&gt; import(&#39;lottie-react&#39;), { ssr: false });</code></pre>
<p>해당 lottie를 <code>dynamic import</code> 처리를 한 후 살펴보자!</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/de1d53b1-c63a-4faf-8166-cc687b37c577/image.png" alt="">
크기가 많이 줄었다...</p>
<h2 id="dynamic-import">Dynamic import</h2>
<p>Dynamic import를 사용하면 크게 3가지 장점을 얻을 수 있다.</p>
<p><strong>1. 초기 로딩 시간 단축</strong></p>
<blockquote>
<p>초기 렌더에 꼭 필요한 코드만 번들링하고, 나머지는 사용 시점에 불러올 수 있다.</p>
</blockquote>
<p><strong>2. 코드 스플리팅</strong></p>
<blockquote>
<p>불필요한 코드가 최초 번들에 포함되지 않도록 분리할 수 있고, 사용자 상호작용에 따라 필요한 부분만 점진적으로 로드하여 전체적인 성능을 개선할 수 있다.</p>
</blockquote>
<p><strong>3. UX 개선</strong></p>
<blockquote>
<p>필요 없는 리소스를 나중에 불러오므로 더 빠른 첫 화면 렌더링을 경험할 수 있다.</p>
</blockquote>
<h2 id="마무리">마무리</h2>
<p>현재는 간단하게 다른 지표를 확인하지 않고 <code>bundle-analyzer</code>만 활용하여 최적화를 진행해봤는데, 추후에는 <strong>lighthouse</strong>도 적용해서 전/후 결과를 비교해봐야겠다!</p>
<h2 id="참고">참고</h2>
<p><a href="https://github.com/webpack-contrib/webpack-bundle-analyzer">GitHub-Webpack Bundle Analyzer</a>
<a href="https://velog.io/@pds0309/nextjs-bundle-analyzer%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%B5%9C%EC%A0%81%ED%99%94-%EC%9D%BC%EA%B8%B0">[nextjs] bundle-analyzer를 사용한 최적화 일기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Storybook 배포하기(Chromatic, Git Action) 👻 ]]></title>
            <link>https://velog.io/@jun_o_o/Storybook-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0Chromatic-Git-Action</link>
            <guid>https://velog.io/@jun_o_o/Storybook-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0Chromatic-Git-Action</guid>
            <pubDate>Wed, 04 Dec 2024 02:30:32 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jun_o_o/post/ed90e5de-e29d-46c8-8f10-f807b43bd8b6/image.png" alt=""></p>
<p>이번 협업 프로젝트에서 <code>Storybook</code>을 사용하게 되었는데, 멘토님께서 사용하는 것을 넘어서 <code>Chromatic</code>으로 배포하면 협업 간의 효율성을 향상할 수 있고, 디자인 시스템을 관리하는 부분에서 유용하다고 하셔서 배포를 고민하게 되었다.</p>
<p>그리고 PR 시 자동으로 <code>Chromatic</code>도 배포하도록 설정해보았다. Git Action을 사용하여 배포 주소를 보여주도록 하였다.</p>
<h2 id="chromatic-사용">Chromatic 사용</h2>
<p><strong>Chromatic 이란?</strong></p>
<blockquote>
<p>스토리북 관리자가 만든 무료 배포 서비스이다. 스토리북을 클라우드에 안전하게 배포하고 호스팅할 수 있다.</p>
</blockquote>
<p>Chromatic에 가입 후, 배포할 프로젝트를 선택한다. 해당 프로젝트에서 명령어를 통해 설치가 가능하다. 현재 pnpm을 사용하고 있으므로, pnpm으로 설치를 진행하였다.</p>
<pre><code>pnpm install --save-dev chromatic</code></pre><p>그리고, 다시 터미널에서 chromatic에 배포하면 된다.</p>
<pre><code>npx chromatic --project-token=chpt_ ---</code></pre><p><img src="https://velog.velcdn.com/images/jun_o_o/post/8756f41f-d713-4182-935a-cf74e186edad/image.png" alt="">
굉장히 쉽게 배포가 끝났다! 현재 프로젝트에 있는 storybook이 정상적으로 보이는 것을 확인할 수 있다.</p>
<h2 id="git-action을-통한-자동-배포">Git Action을 통한 자동 배포</h2>
<p>위의 <code>chpt_ ---</code>의 토큰을 깃허브에 등록할 수 있다.</p>
<p>해당 레포지토리의 <strong>Secrets and variables</strong>의 <strong>Actions</strong>에서 토큰을 등록할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/b096a3c2-69d1-4229-9c01-53baae1d4b62/image.PNG" alt=""></p>
<p>등록 후, <code>.github/workflows</code> 폴더 안에 yml 파일을 생성한다. 공식 문서에서는 <code>chromatic.yml</code>파일로 생성하라고 하였지만, 이름은 크게 문제가 되지 않기에 나는 <code>storybook.yml</code>으로 생성하였다.</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/95013932-b194-482f-b1cf-f9cc2b45e781/image.png" alt=""></p>
<p>코드의 경우 <a href="https://jjang-j.tistory.com/138">짱잼이의 FE 개발 공부 저장소
</a> 블로그를 참고하였다. 해당 블로그의 프로젝트는 yarn을 사용하고 있어서 yml이 yarn 기준으로 되어있는데, 내가 진행하는 프로젝트의 경우 pnpm을 사용하므로 Corepack을 활성화하고, pnpm 명령어로 변경하여 진행하였다.</p>
<pre><code>name: Preview

on:
  pull_request:
    branches: [&#39;main&#39;, &#39;develop&#39;]

permissions:
  contents: write
  pages: write
  deployments: write
  id-token: write
  issues: write
  pull-requests: write

jobs:
  storybook-preview:
    runs-on: ubuntu-20.04

    steps:
      - name: 저장소 체크아웃
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Corepack 활성화
        run: corepack enable

      - name: pnpm 설치
        run: corepack prepare pnpm@latest --activate

      - name: 캐시 종속성
        id: cache
        uses: actions/cache@v3
        with:
          path: &#39;**/node_modules&#39;
          key: ${{ runner.os }}-node-${{ hashFiles(&#39;**/pnpm-lock.yaml&#39;) }}-storybook

      - name: 종속성 설치
        if: steps.cache.outputs.cache-hit != &#39;true&#39;
        run: pnpm install

      - name: Chromatic에 게시
        id: chromatic
        uses: chromaui/action@v1
        with:
          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
          token: ${{ secrets.GITHUB_TOKEN }}
          onlyChanged: true
          autoAcceptChanges: true

      - name: 현재 시간 가져오기
        uses: josStorer/get-current-time@v2
        id: current-time
        with:
          format: &#39;YYYY년 MM월 DD일 HH시 mm분 ss초&#39;
          utcOffset: &#39;+09:00&#39;

    outputs:
      storybook_url: ${{ steps.chromatic.outputs.storybookUrl }}
      current_time: ${{ steps.current-time.outputs.formattedTime }}

  github-bot-storybook:
    runs-on: ubuntu-latest
    needs: [storybook-preview]

    steps:
      - name: PR 코멘트 남기기
        uses: thollander/actions-comment-pull-request@v2
        with:
          comment_tag: ${{ github.event.number }}-storybook
          message: |
            💄 Storybook: ${{ needs.storybook-preview.outputs.storybook_url }}
            🕖 Update: ${{ needs.storybook-preview.outputs.current_time }}
</code></pre><p><img src="https://velog.velcdn.com/images/jun_o_o/post/6f74d593-fbba-40f4-bb8a-b89ab7c1cc01/image.png" alt="">
<img src="https://velog.velcdn.com/images/jun_o_o/post/0e8523ef-5c3f-421e-92ce-8b5fcb40dbde/image.png" alt=""></p>
<p>PR 시 배포가 정상적으로 이루어지는 모습을 확인할 수 있다!</p>
<h2 id="참고">참고</h2>
<p><a href="https://jjang-j.tistory.com/138">짱잼이의 FE 개발 공부 저장소 - [GitHub Action / Chromatic] 스토리북 PR 미리보기 배포 (feat. yarn)
</a>
<a href="https://storybook.js.org/tutorials/intro-to-storybook/react/ko/deploy/">스토리북(Storybook) 배포하기 공식문서</a>
<a href="https://velog.io/@93minki/Storybook-Chromatic-%EC%9C%BC%EB%A1%9C-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0">Storybook Chromatic 으로 배포하기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 프로젝트에 폰트 적용하기(Pretandard, tailwind)📃]]></title>
            <link>https://velog.io/@jun_o_o/%ED%8F%B0%ED%8A%B8-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0pretendard</link>
            <guid>https://velog.io/@jun_o_o/%ED%8F%B0%ED%8A%B8-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0pretendard</guid>
            <pubDate>Wed, 27 Nov 2024 13:16:11 GMT</pubDate>
            <description><![CDATA[<p>이번에 새로운 프로젝트 초기 세팅을 진행하면서, 전역으로 <code>Font</code>를 적용해야 하는 일이 생겼다. 원래의 나는 <code>googlefont</code>로 항상 바로 적용했었는데, <code>Pretandard</code>는 슬프게도 <code>googlefont</code>에 없는 이유로 인해 <code>localFont</code> 기능을 사용하게 되었다.</p>
<h2 id="nextfont">next/font</h2>
<p><a href="https://nextjs.org/docs/app/building-your-application/optimizing/fonts">Next.js Font Optimization</a></p>
<blockquote>
<p><code>next/font</code>는 사용자 정의 글꼴을 포함한 글꼴을 자동으로 최적화, 외부 네트워크 요청을 제거하여 적용시켜준다. </p>
</blockquote>
<p>나는 이번 프로젝트에서 <code>next/font/local</code>을 사용하였는데, local에서 불러온 글꼴 또한 자동으로 최적화를 해주어 사용하게 되었다. </p>
<h2 id="pretendard-설치-✨">Pretendard 설치 ✨</h2>
<p><a href="https://github.com/orioncactus/pretendard">Pretendard github</a>
<img src="https://velog.velcdn.com/images/jun_o_o/post/a41e5fa3-7f01-4dd7-ad09-743ee1c09f1d/image.png" alt=""></p>
<p>9가지 굵기가 지원되고, 가변 글꼴 또한 지원되는 글꼴이다. 많은 프로젝트에서 사용되고 있는 system ui 대체 글꼴이다.</p>
<p><code>PretendardVariable.woff2</code> 파일을 프로젝트에 넣어 주자. 나의 경우, <code>src/fonts</code> 폴더 안에 넣었다(next, app router)</p>
<h2 id="적용해보자">적용해보자!</h2>
<pre><code>import localFont from &#39;next/font/local&#39;;

...

const pretendard = localFont({
  src: &#39;../../fonts/PretendardVariable.woff2&#39;,
  display: &#39;swap&#39;,
  weight: &#39;45 920&#39;,
  variable: &#39;--font-pretendard&#39;,
});</code></pre><p><code>layout.tsx</code> 파일에 적용해준다.</p>
<p>src 경로의 경우, 파일이 위치한 알맞은 경로로 해줘야 한다.</p>
<p>이렇게 작성한 경우, 밑의 body에 전체적으로 적용해주면 된다!</p>
<pre><code>      &lt;body className={`${pretendard.variable} font-pretendard`}&gt;
        &lt;QueryProvider&gt;{children}&lt;/QueryProvider&gt;
      &lt;/body&gt;</code></pre><p>현재 <code>tanstack query</code>, <code>tailwind</code>를 사용하고 있기에 className과 QueryProvider가 존재한다.</p>
<h2 id="tailwind-설정">Tailwind 설정</h2>
<pre><code>export default {
    theme: {
        extend: { 
              fontFamily: {
                pretendard: [&#39;var(--font-pretendard)&#39;],
      ...</code></pre><p><code>tailwind.config.ts</code> 파일에 해당 font를 extend로 설정해준다.</p>
<h2 id="실제-사용-화면-💻">실제 사용 화면 💻</h2>
<p>tailwind에 추가로 fontSize 관련 확장도 하였기에, 밑의 코드처럼 작성해보았다!
<img src="https://velog.velcdn.com/images/jun_o_o/post/17557a8e-0d4e-4607-8964-c4504de116d4/image.png" alt="">
<img src="https://velog.velcdn.com/images/jun_o_o/post/737bf772-ce26-46c5-8915-09894cae9f90/image.png" alt=""></p>
<p>적용이 매우 잘 된 모습을 확인할 수 있다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Tailwind에 대하여🎐]]></title>
            <link>https://velog.io/@jun_o_o/Tailwind%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</link>
            <guid>https://velog.io/@jun_o_o/Tailwind%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</guid>
            <pubDate>Mon, 18 Nov 2024 10:57:36 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jun_o_o/post/41164b92-bb0d-475c-afb7-15003588b50e/image.png" alt=""></p>
<h2 id="tailwind가-뭔가요">Tailwind가 뭔가요?</h2>
<p>엄청나게 많은 유틸리티 클래스를 가지고, 해당 유틸리티를 통해서 조합하여 쉽게 css를 작성할 수 있는 CSS 프레임워크다.</p>
<p>테일윈드의 공식 문서를 살펴보면, 정말 많은 양의(진짜 다 못센다) 클래스들이 세팅되어 있는데, 심지어 간단하고 원래 CSS 작성법을 알면 유추가 가능한 수준이라 러닝커브가 높지 않다.</p>
<blockquote>
<p><code>&lt;h3 className=&quot;mb-8 text-lg font-semibold&quot; /&gt;</code></p>
</blockquote>
<h2 id="bootstrap이-좋나요-tailwind가-좋나요">bootstrap이 좋나요, Tailwind가 좋나요?</h2>
<p>몇 년 전까지만 해도 bootstrap이 tailwind보다 더 널리 사용되었지만, 현재 2024년을 기준으로 tailwind가 시장에서 더 널리 사용되고 있다.</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/19165ca3-e08f-47fe-b232-1ec58b80cba3/image.png" alt=""></p>
<p><a href="https://npmtrends.com/bootstrap-vs-tailwindcss">bootstrap vs tailwindCSS</a></p>
<p>npm trends에서도 확실히 알 수 있을 정도의 차이이다.</p>
<p>사실 둘의 차이를 구분하는 것은 꽤나 어려운게, bootstrap의 경우 디자인 되어 있는 클래스를 사용하는 것이고, tailwind는 css를 빠르고 간단하게 인라인으로 작성하기 위해 사용된다.</p>
<p>하지만 가장 유명한 CSS 프레임워크이니 만큼, 현재 사용 척도를 알기에는 충분하다고 생각된다.</p>
<h2 id="tailwind를-왜-사용하나요">Tailwind를 왜 사용하나요?</h2>
<p>공식문서에 따르면 반응형 디자인을 지원하고, <code>hover</code>와 <code>focus</code> 등을 지원하며, 다크 모드 또한 쉽게 적용할 수 있고, 스타일 재사용이 가능하며, <code>tailwind.config</code>의 extend를 통해 사용자가 원하는 디자인을 편리하게 추가할 수 있다는 점을 기존 CSS와 차별화되는 핵심적인 기능으로 알려주고 있다.</p>
<p>개인적으로, 클래스의 네이밍 등에 사용하는 시간이 단축되고 정해진 값을 끼워맞추는 작성방식이기에 개발 속도가 비약적으로 빨라졌다.</p>
<p>또한, 일관적인 디자인을 지원하므로 웹페이지에서 통일성을 주기 쉬우며, 이는 좋은 사용자 경험으로 이어진다고 생각한다.</p>
<h2 id="그럼-단점은-없나요-👀">그럼 단점은 없나요? 👀</h2>
<p>세상에 단점 없는 사람이 없듯이, 테일윈드도 단점이 존재한다. </p>
<p>일단, 위의 장점과 상충되는 문제로 못생긴 코드를 꼽는다.</p>
<blockquote>
<pre><code>&lt;div className=&quot;absolute bottom-full left-1/2 mb-14 hidden w-max -translate-x-1/2 transform group-hover:block&quot;&gt;
  &lt;div className=&quot;text-sm-medium bg-gray-90 relative z-10 rounded-lg px-8 py-4 text-sm text-white/90&quot;&gt;
    {children}
    &lt;div className=&quot;border-t-gray-90 absolute left-20 top-full h-0 w-0 -translate-x-1/2 border-x-8 border-t-8 border-x-transparent&quot; /&gt;
  &lt;/div&gt;
&lt;/div&gt;</code></pre></blockquote>
<p> _ 으아악_</p>
<p> 직관적이면서도 못생긴 코드여서, 해당 단점은 아무래도 영원히 고쳐지지 않을 듯 싶다.</p>
<p> 또한, JS 코드가 사용할 수 없다. 설정을 열심히 만지면 구현이 가능하긴 하지만 굉장히 번거롭고 까다로운 길을 택해야 한다.</p>
<h2 id="설치하는-방법">설치하는 방법</h2>
<pre><code>npm install -D tailwindcss
npx tailwindcss init</code></pre><p><a href="https://tailwindcss.com/docs/installation/framework-guides">tailwind 공식 문서</a></p>
<p>next를 사용하는 경우, next를 설치할 때 tailwind를 사용하는지 물어본다!</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/20380e1e-53f4-434b-be6b-338a2a6cbc87/image.png" alt=""></p>
<h2 id="tailwind를-능숙하게-사용하는-방법">tailwind를 능숙하게 사용하는 방법</h2>
<p>tailwind의 불편한 점을 보완하기 위한 라이브러리가 많이 나와있는데, 그 중 유명한 3가지를 뽑자면 <code>clsx</code>, <code>cva</code>, <code>tailwind-merge</code>이다.</p>
<p>또한, tailwind CSS의 클래스를 권장 클래스 순서에 따라 정렬해주는 prettier 플러그인도 존재한다.
<code>prettier-plugin-tailwindcss</code></p>
<p>해당 라이브러리와 플러그인에 관해서는 다음에 정리하도록 하자!</p>
<h3 id="참고">참고</h3>
<p><a href="https://tailwindcss.com/">Tailwind CSS 공식문서</a>
<a href="https://wonny.space/writing/dev/hello-tailwind-css">Hello Tailwind CSS! | 장점, 단점, 사용법</a>
<a href="https://npmtrends.com/bootstrap-vs-tailwindcss">bootstrap VS tailwindcss</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드잇 일경험 인턴 회고 😎]]></title>
            <link>https://velog.io/@jun_o_o/%EC%BD%94%EB%93%9C%EC%9E%87-%EC%9D%BC%EA%B2%BD%ED%97%98-%EC%9D%B8%ED%84%B4-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@jun_o_o/%EC%BD%94%EB%93%9C%EC%9E%87-%EC%9D%BC%EA%B2%BD%ED%97%98-%EC%9D%B8%ED%84%B4-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Thu, 14 Nov 2024 12:57:52 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jun_o_o/post/def97e08-5372-46b3-9514-9576c3d8b88a/image.png" alt=""></p>
<p>10월 7일부터, 11월 1일까지 코드잇에서 약 4주간의 인턴 생활을 진행하였다. </p>
<p>스프린트를 마무리하고, 앞으로 뭘 해야 하나 하던 나에게 코드잇 인턴십 공고는 정말 가뭄의 단비와도 같았다. 한 치의 망설임도 없이 바로 신청하였고, 정말 다행스럽게도 인턴십에 합격하게 되었다! 엄청 많은 사람들 중에서 합격했다는 게 기분이 되게 좋으면서도 싱숭생숭했다. 못 하면 어떡하지...</p>
<p>부트캠프에서도 스스로 성장하였다고 생각하였고, 인턴 기간동안에도 1달 동안 회의하고 코딩하고, 정말 많은 것을 배웠다고 생각한다. </p>
<h2 id="팀-분배-및-프로젝트">팀 분배 및 프로젝트</h2>
<p>총 10명의 인원들로 인턴 생활을 시작하였고, 5명씩 나눠지게 되었다. 하나의 프로젝트를 팀마다 각자의 방식으로 풀어나가게 되었다.</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/9ae6083e-65c4-41d2-887a-cfe5554fdaa8/image.png" alt=""></p>
<p>진행하게 된 프로젝트는 <code>Codeit Resources</code>라는 프로젝트였다. 코드잇 사내에서 사용할 회의실 예약, 좌석 예약 및 관리 프로그램을 제작하는 것이었다.</p>
<p>또한, 인턴에 합격된 인원은 전부 다 프론트엔드였는데, 5명으로 나누고 그 중 2명은 FE, 2명은 BE, 1명은 PM으로 진행하게 되었다. 나는 아직은 프론트엔드 기술을 더 갈고 닦고 싶어서 FE로 진행하게 되었다.</p>
<h2 id="진행-과정-및-어려움">진행 과정 및 어려움</h2>
<p>프로젝트 처음부터 살짝 난항이 있었는데, 나는 살면서 처음 보는 Turborepo를 사용하게 되었다. 여러 개의 저장소가 하나의 큰 저장소에서 관리되는 방식이었다. 꽤나 낯설기도 하고, 하나의 큰 config에서 참조하여 각자 레포의 eslint나 tsconfig, tailiwnd config를 설정하는 것이 꽤나 낯설면서도 재미있었다! 새로운 기술을 접하다 보니 의욕도 생기는 느낌이었다.</p>
<p>하지만 재미와 어려움은 별개의 문제이기에, 저장소의 구조를 이해하는 것에도 시간이 꽤 소요되었다. 심지어, 우리는 <code>vercel stylelint</code> 를 웹에서 적용하여 개발하였는데, 정말... 까다로운 lint 규칙이 많아서 당황했다.</p>
<p>그리고 패키지 버전 관리도 꽤나 어려움을 겪었지만, 그 문제는 어찌저찌 해결하였기에 처음에는 순탄하지 않았지만 그래도 개발 속도에 진척이 있었다.</p>
<p>가장 큰 문제는, 개발 기간이 4주도 채 되지 않았다는 것이다. 총 인턴 기간 4주 중에서 일주일은 서로 프로젝트 관련 회의, 기본 레포지토리 세팅, 기술 스택 선정 및 일정 관리... 예상 외로 촉박한 기간에 부담을 느꼈다. 지금 생각하면 조금 내려놓고 해도 되었을 듯 하다.</p>
<br>

<p>우리 팀은 맨 처음 회의를 진행하면서, 이번 인턴십의 목표를 &#39;도전&#39;으로 잡았다. 그 목표에 맞게 진행하면서, 정말 많이 배웠다. 사실 백엔드와 이렇게 직접적으로 협업해본 적이 아주 예전이라 걱정이 많았었는데, 스스로 API를 이해하고 Model 등을 보면서 연결해보니 백엔드 코드도 명세서 없이 이해할 수 있게 될 정도로 성장한 것 같다.</p>
<h2 id="아쉬웠던-점">아쉬웠던 점</h2>
<p>기간이 촉박함에 따라, 스스로 도전을 칭했음에도 여러 공통 컴포넌트를 빠르게 쳐버리는 선택을 하면서(...) 완성도가 떨어지는 결과를 가져오게 되었다.</p>
<p>또한 컴포넌트가 지나치게 무겁고 두꺼워지는 문제가 발생하였는데, 이 문제는 추후 리팩토링으로 해결하고 있으나 리팩토링에 걸리는 시간을 생각하면 이상적인 개발 방향은 아니었던 것 같다.</p>
<p>개인적으로, 해야 하는 양이 많아지면서 저절로 퇴근한 후에 집에서도 코딩을 계속 진행하였는데, 밤에 코딩하니까 배가 고프고... 무언가를 먹고 싶고... 먹으면 졸려서 코딩을 잘 못하는 식곤증의 무한루프에 빠진 적도 있다. 사실 이게 가장 힘들었다... 한 번 깨진 수면패턴은 쉽게 돌아오지 않는다는 사실이 너무 뼈아팠다😂</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/8696d1f9-1b8c-4fec-8e48-93e654afd9f7/image.png" alt=""></p>
<h2 id="다시-하면-정말-잘-할-수-있는데-시켜주시면-안-되나요">다시 하면 정말 잘 할 수 있는데 시켜주시면 안 되나요</h2>
<p>위의 말만 보면 정말 너무 힘들어요... 자고 싶어요... 과 같은 경험이었던 것 같지만, 사실 스스로 정말 재미있고 신나게 인턴생활을 즐겼다고 생각한다! </p>
<p>마지막에, 엄청난 실력의 소유자이신 에이든 님의 지도를 따라 각자 프로젝트 동안 느꼈던 것들을 정리하면서 이야기를 나누었던 시간이 있었다. 모두 1달이라는 짧은 시간동안 열심히 달려오고, 그만큼 생각나는 것도 많았을건데 이 기회에 서로 더 이해하면서 각자 힘들었던 점과 생각을 공유해서 더 기억에 남는 것 같다.</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/75a804ab-46cf-4f80-904b-d807aef34af5/image.png" alt="">
<em>우리 팀 최고 ㅠ.ㅠ</em></p>
<p>너무너무 아쉽지만, 그만큼 열심히 달렸다고 생각한다. 그리고 열심히 달렸음에도, 아직 부족한 점을 절실히 깨달았다.</p>
<p>긍정적인 조직문화와, 밝은 에너지를 한껏 받고 마무리한 인턴이었다. 앞으로도 더 열심히, 꾸준하게 준비해서 꼭 취업에 성공하자...!!!</p>
<br>

<p><img src="https://velog.velcdn.com/images/jun_o_o/post/97ca8a62-f548-4109-8ccc-15c0011bc3f2/image.png" alt="">
같이 인턴을 진행했던 분들 정말 감사하고, 언제나 친절하게 인턴분들을 세심하게 신경써주신 이유정 매니저님과 기술적으로도, 멘탈적으로도 많은 도움을 주신 에이든 님 정말 감사했습니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드잇 스프린트 6기 마무리 회고🔥 ]]></title>
            <link>https://velog.io/@jun_o_o/%EC%BD%94%EB%93%9C%EC%9E%87-%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8-6%EA%B8%B0-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@jun_o_o/%EC%BD%94%EB%93%9C%EC%9E%87-%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8-6%EA%B8%B0-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 11 Nov 2024 12:19:12 GMT</pubDate>
            <description><![CDATA[<p>소프트웨어 관련 전공으로 대학을 졸업한 나는, 바로 취업해서 열심히 살아가야겠다는 마음을 가진 채 취업전선에 뛰어들었다. 취업하고 싶은 마음은 굴뚝같았지만 변변찮은 이력서와, 정리되지 않은 포트폴리오를 가진 나에게는 너무 냉정한 구인시장이었다.</p>
<p>너무 막연하게 생각한 것이 아닐까 생각했다. 대학교를 졸업하면 바로 취업할 수 있을 것으로 생각한 나로서는, 사회는 내 생각 이상으로 차갑고 냉정하게 신입을 골라내었다. 심지어, 요즘은 수없이 많은 사람이 개발자의 꿈을 안고 도전하는 시대가 아닌가. 취업을 위해서는 열망으로는 부족했다. 나를 어필할 수 있는 포트폴리오, 다듬어진 이력서, 그리고 무엇보다 지금보다 몇 배는 뛰어난 개발 실력이 필요했다.</p>
<p>이 생각을 하게 된 이후로, 나는 수많은 부트캠프를 찾아보기 시작했다. 그 중 가장 마음에 드는 커리큘럼과(react, ts, next, tailwind, 심지어 jest와 storybook까지!) 강의 사이트로 유명한 코드잇의 부트캠프를 선택하게 되었다.</p>
<h2 id="👀-성장했을까">👀 성장했을까...?</h2>
<p>사실 개발 실력으로는 과거의 나에 비해서 많은 성장을 이루었다고 생각한다.</p>
<p>예전에 모르는 라이브러리를 보면 지레 겁을 먹고, 간단한 css도 기억이 가물가물해서 여러 군데를 돌아다니다 해결했던 나로서는, 지금의 성장이 정말 피부로 느껴졌다. 일단 모르는 라이브러리를 봐도 겁이 나지 않는다...! 공식문서의 소중함을 절절히 깨달았다.</p>
<p>하지만, 과거의 내가 너무 부족했다는 사실에 근거하였을 때, 지금도 정말 부족한 부분이 많은 개발자라는 것은 변함없는 사실이라고 생각한다. 세상사 완벽한 사람이 어디 있을까 하지만... 스스로 지식의 깊이를 더하고 싶다는 생각을 자주 한다.</p>
<p>스프린트의 기간 동안 총 3개의 프로젝트를 하였다. 기초, 중급, 심화 프로젝트로 구성되어 있다. 기초 시절의 나는 정말로... 정말로 심각한 사람이었지만 점점 팀원들의 격려와 주강사님의 친절하면서도 자세한 설명을 들으며 성장해갔다.</p>
<p>사실 수료한 것만으로도 잘했다고 생각한다. 6개월 동안 마음을 다잡고, 꾸준히 한 것만으로도 대단하다! 그렇지만, 열심히 해서 많은 것을 얻어갔다고 생각한다.</p>
<h2 id="🕶️-앞으로-어떻게-해야-할까">🕶️ 앞으로 어떻게 해야 할까</h2>
<p>스프린트는 분명 나에게 커다란 성장의 발판이 되어주었다. 하지만 현재의 나로 만족할 수 있는가?</p>
<p>모르고 있을 때는 조금만 하면 넘을 수 있을 거 같은데, 막상 조금이라도 발을 담가보면 치열하게 노력해야 넘어갈 수 있는 곳이 개발이라고 생각한다. 앞으로 더 꾸준히 커리어를 쌓아가며 열심히 노력하자. 나중에 나 스스로 당당하게 한 명의 개발자라고 할 수 있게끔 자신감을 얻는 것을 목표로 할 것이다.</p>
<h3 id="여담">여담</h3>
<p>스프린트 회고록을 작성하면서, 사실 프로젝트에서 기술적으로 성장한 부분과, 어려웠던 부분을 초점으로 두고 작성해야 할까 많이 고민하였다.</p>
<p>그런 부분은 나중에 또 작성하면 되는 거 아닐까 하며 글을 작성한다.</p>
<p>6개월이라는 시간 동안 꾸준히 수강생들을 독려해주고 응원해준 스프린트 매니저님들과, 주강사님과, 멘토님에게 정말 감사하다고 전하고 싶다. 나중에라도 꼭 만날 수 있는 기회가 있으면 좋겠다!</p>
<p>그리고 열심히 동고동락하며 긴 기간 동안 달려온 스프린터들에게도 감사하다. 다들 너무 좋은 성격과 밝은 에너지의 소유자여서 즐겁게 코딩할 수 있었다!</p>
<br>

<hr>
<h3 id="진짜-여담">진짜 여담</h3>
<p>사실 이 글은 2개월 전에 올려야지 올려야지 하다가 마음에 안 들어서 안 올리고, 이렇게 소감을 쓰는 게 맞나 싶어서 안 올린... 화석화가 진행 중인 글이다.</p>
<p>나중에 꼭 만나고 싶었던 매니저님들은 엄청나게 좋은 기회로 코드잇 인턴으로 뽑혀서 만나게 되었다! 정말 행복했다😊</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드잇 스프린트 중급 프로젝트 회고 🍀Wiki viki🍀]]></title>
            <link>https://velog.io/@jun_o_o/%EC%BD%94%EB%93%9C%EC%9E%87-%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8-%EC%A4%91%EA%B8%89-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0-Wiki-viki</link>
            <guid>https://velog.io/@jun_o_o/%EC%BD%94%EB%93%9C%EC%9E%87-%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8-%EC%A4%91%EA%B8%89-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0-Wiki-viki</guid>
            <pubDate>Fri, 26 Jul 2024 15:41:16 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jun_o_o/post/fc5cf4c0-dca4-4625-8f4f-84f0ae33bb2e/image.png" alt="">
코드잇 스프린트를 진행하면서 정말 기분 좋게 개발했던 중급 프로젝트가 성공적으로 마무리되었다!</p>
<p>짧다면 짧은 시간 동안 열심히 개발했고, 팀원들이랑 꾸준히 의논해가며 부족한 점을 채워가며 발전하는 시간이여서 더 뜻깊었던 시간이었다.</p>
<p>기초 프로젝트에서 스스로 만족하지 못했던 부분과, 부족하다고 생각되던 부분을 여러모로 채워나갈 수 있어서 정말... 만족스럽게 마무리한 프로젝트였다🤩</p>
<p><a href="https://github.com/wiki-viki/wiki-viki">Wiki-viki 깃허브 링크</a></p>
<h2 id="중급-프로젝트-wikid">중급 프로젝트 Wikid</h2>
<h3 id="프로젝트-선정-이유">프로젝트 선정 이유</h3>
<p><strong>Wikid</strong>라는 프로젝트는, 지인들의 위키를 작성하고 공유하는 서비스이다.</p>
<p>기초 프로젝트와 비슷하게 4개의 프로젝트 주제 중 선택할 수 있었는데, 타인의 위키를 작성한다는 점, 마크다운 에디터 등을 사용할 수 있다는 점, 스프린트에서 매주 진행하던 스프린트 미션과 다른 부분이 많다는 점 등... 팀원들과의 회의를 통해 프로젝트를 선정하게 되었다.</p>
<p>또한, 난이도가 가장 높다는 부분이 선정 이유 중 하나였다. 다들 너무 잘해서 난이도 높은 프로젝트를 해도 무리가 없을 듯 했다.</p>
<br>

<h2 id="🍀-완전-위키비키자나">🍀 완전 위키비키자나~</h2>
<p>프로젝트를 정한 후, 프로젝트에 특별함을 더하기 위해(같은 시안으로 진행하는 팀이 많다 보니, 특별한 네이밍과 로고 등은 개발 능률을 향상시켜준다고 생각한다...) 프로젝트 이름을 정하던 도중 위키비키라는 이름이 선정되었다.</p>
<p>긍정적(낙관적) 사고를 기반으로, 타인이 나에 대한 위키를 써준다니 완전 럭키비키잖아~ 라는 생각으로 네이밍을 진행했는데, 찰떡같은 이름이라고 생각한다. 개발하는 내내 프로젝트에 애정을 가지고 임할 수 있었다.</p>
<br>

<h2 id="기술-스택">기술 스택</h2>
<p><code>Next. js</code>, <code>TypeScript</code>, <code>Tailwind Css</code>, <code>Zustand</code> 등을 사용하였다.
<br></p>
<h3 id="nextjs">Next.js</h3>
<p>Next.js의 경우 페이지 라우터를 사용하였다. 앱 라우터의 경우 페이지 라우터에 비해 높은 러닝커브와, 비교적 안정적이지 않다는 점, 현재 개발하는 프로젝트가 소규모 프로젝트라는 점 등으로 인해 제외되었다.
<br></p>
<h3 id="typescript">TypeScript</h3>
<p><strong>TypeScript</strong>의 경우, 자바스크립트의 여러가지 단점을 보완해주기 때문에(타입 지정으로 인해) 필수라고 생각되어 사용하였다. API에서 받는 데이터 등의 타입을 미리 지정해두고 사용하니 쉽게 개발할 수 있었다.
<br></p>
<h3 id="tailwind-css">Tailwind CSS</h3>
<p><strong>Tailwind CSS</strong>의 경우, 팀 내에서 여러 의견이 나왔던 기술이다. Tailwind를 아예 사용해보지 않은 사람이 있었고, 이미 styled components, module.css 등으로 css를 작성하는 경우가 많았기 때문이다.</p>
<p>이에 대해서 해결하기 위해 <strong>팀적으로 기술적인 스터디를 진행</strong>해서, 어떤 기술 스택을 도입하기 전에 <strong>현재 우리가 진행할 프로젝트에 어울릴지, 장점과 단점</strong>은 무엇인지 매일 의견을 나누었다.</p>
<p>결론적으로, Tailwind의 <strong>획기적으로 감소되는 css 코드 작성 시간</strong>(처음에는 러닝커브가 존재하지만, 조금 익숙해지면 정말 빠르게 작성할 수 있다), <strong>next에서 추천하는 방식(빌드 타임에 스타일시트를 가져오는 방식이다)</strong>, 클래스 네이밍 고민 시간 절약... 등으로 인해 Tailwind를 사용하게 되었고, 지금은 매우 만족하면서 사용하고 있다. 다음 프로젝트에서도 Tailwind를 계속 사용할 예정이다.</p>
<p>extend로 미리 피그마 시안의 color와 font style을 지정해두고 사용하니 정말 편리했다.
<img src="https://velog.velcdn.com/images/jun_o_o/post/f39adb67-5821-4a5b-bbe9-338d5cbcf5f4/image.png" alt=""></p>
<br>

<h3 id="zustand">Zustand</h3>
<p>Zustand는 사실 공부의 목적으로 사용하였다. 전역 상태관리 라이브러리를 사용해보고 싶었는데, 현재 zustand가 가장 많이 사용되는 상태관리 라이브러리고, 비교적 러닝커브가 낮고(프로젝트 기간이 짧은 나에게는 정말 큰 이점이었다), 번들 사이즈가 정말 작다는 점 등으로 인해 선택하게 되었다.</p>
<p>물론 React의 Context API를 사용하여 상태 관리가 가능하지만, 학습적인 측면이 더 컸다고 생각한다.</p>
<br>


<h2 id="회고">회고</h2>
<p>KPT 방식으로 진행하였다.</p>
<h3 id="👏-keep">👏 Keep</h3>
<p>서로를 배려하여 트러블 없이 즐겁게 프로젝트를 완수했다.
매일 데일리 스크럼을 통해 각자의 작업 상황을 파악했다.
리뷰 속도가 빠르며, 팀원들끼리 아낌없이 칭찬하고 부족한 부분에 대해서는 꼼꼼하게 피드백했다.
본인이 맡은 일에 대해 책임을 가지고 마감 기한보다 빠르게 작업했다.
사용자 경험 측면을 고려하고, 기능 및 성능 개선과 리팩토링 등 부가 요소에도 신경쓰며 작업했다.</p>
<h3 id="😢-problem">😢 Problem</h3>
<p>마감 기한이 다가올수록 본인이 구현해야 할 작업에 집중하다 보니 코드 리뷰가 늦어졌다.
다들 개발을 쉬지 않고 너무 열심히 하다 보니 컨디션이 좋지 않을 때가 있었다.
이슈 트래킹과 일정 관리 도구를 활용하지 않아 프로젝트의 전체 진행 상황 파악이 어려웠다.
디스코드에 잡담이 많아 중요한 메시지를 놓치거나 찾기 어려웠다.</p>
<h3 id="💪-try">💪 Try</h3>
<p>시간 분배에 신경을 쓰며 코드 리뷰에 시간을 투자해 봐야겠다..
건강을 잘 챙기고 쉴 때는 쉬면서 작업해 봐야겠다.
다음 프로젝트에서는 일정이 길기 때문에 노션, 깃허브 프로젝트, 지라 등 다양한 도구들을 사용하여 관리를 해 봐야겠다.
잡담은 새로 스레드를 만들어 사용하거나 새로운 채널을 파서 소통해 봐야겠다.</p>
<br>

<h2 id="개인적인-문제점">개인적인 문제점</h2>
<h3 id="컴파운드-패턴-미사용">컴파운드 패턴 미사용</h3>
<p>컴파운드 패턴에 대해 자세히 알지 못했고, 시간적으로 여유가 없어 Prop Drilling이 일부분 일어나는 컴포넌트를 작성하였다. 나중에 리팩토링을 진행하면서 어느 정도 해결하였지만, 처음부터 컴파운드 패턴을 사용하여 컴포넌트를 더 구조화하였으면 어떨까 하는 아쉬움이 존재한다.</p>
<h3 id="이슈-트래킹-방식의-문제점">이슈 트래킹 방식의 문제점</h3>
<p>깃허브 이슈를 브랜치를 생성하는 용도로 사용한 것 같다. 정말 긴급한 버그나, 바로 수정해야 할 핫픽스, 기능적 에러 등을 이슈에다가 보관하였으면 좋았을 것 같다.</p>
<h3 id="pr-세분화">PR 세분화</h3>
<p>중간에 게시글 상세 페이지를 구현할 때, 아무 생각 없이 페이지 전체를 구현한 후 PR을 올렸었다. 하지만 그 때 기능적으로 추가된 부분이 정말 많았어서(게시글 삭제, 댓글 작성, 댓글 수정, 댓글 삭제, 게시글 좋아요 표시, 댓글 무한스크롤 등...) 전체적으로 file change가 많아서 PR도 오래 걸렸고, 코드 리뷰도 오래 걸렸고, merge도 뒤늦게 되었다.</p>
<p>PR을 세분화하고, 이슈의 하위 이슈를 만들어서 관리하도록 하자!</p>
<br>

<h2 id="개인-kpt-회고">개인 KPT 회고</h2>
<p>이제 KPT로 회고해보도록 하자.</p>
<h3 id="👏-keep-1">👏 Keep</h3>
<p>기능 구현을 깔끔하게 완료하였다.
사용자 경험 측면을 고려하여, 애니메이션과 framer motion 등을 사용하여 부드럽게 만들었다.
데일리 스크럼, 팀 미팅 등에 꾸준히 참여하였고, PR 또한 꾸준히 작성하였다.</p>
<h3 id="😢-problem-1">😢 Problem</h3>
<p>코어타임을 지정해두었지만, 개발을 코어타임이 아닌 밤에 했던 적이 꽤나 존재하였다...
너무 늦게 자서 기상 시간이 점점 늦어져 몸상태가 말이 아니었다...</p>
<h3 id="💪-try-1">💪 Try</h3>
<p>이슈트래킹 방식에 대해 더 생각해보자!
일찍 자고 일찍 일어나자!
다른 팀원의 장점을 열심히 흡수해보도록 하자!</p>
<br>

<p>맡은 부분에 대해 회고를 남길까 헀지만, 전체적으로 작성하는 회고를 남기기로 하였다.
중급 프로젝트를 너무 만족스럽게 마무리해서 정말 좋다! 다음 프로젝트도 열심히 해서 유종의 미를 거둬보도록 하자!😎</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TanStack Query에 대해 알아보자!]]></title>
            <link>https://velog.io/@jun_o_o/TanStack-Query%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@jun_o_o/TanStack-Query%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sat, 20 Jul 2024 03:59:12 GMT</pubDate>
            <description><![CDATA[<p>스프린트 과정을 열심히 달려가다 보니, 리액트 쿼리에 대한 정보를 접하게 되었다. 
점점 상태관리와 서버 상태, 데이터 관리에 대한 중요성을 알게 되었지만 어떻게 해야 할 지 막막할 때, <strong>리액트 쿼리</strong>(지금은 TansStack이다)의 기능을 통해 효과적으로 처리할 수 있다는 것을 알게 되었다.</p>
<p>TanStack Query란 무엇인지, 왜 사용하는지 한 번 알아보도록 하자!</p>
<br>

<h2 id="✨-tanstack-query란">✨ TanStack Query란?</h2>
<p><a href="https://tanstack.com/query/latest">TanStack Query 공식사이트</a></p>
<blockquote>
<p><strong>서버 상태 가져오기, 캐싱, 동기화 및 업데이트를 보다 쉽게 다룰 수 있도록 도와주는 라이브러리</strong>이다. 클라이언트 상태와 서버 상태를 명확히 구분하기 위해 만들어졌다.</p>
</blockquote>
<p>데이터를 불러오다 보면 코드가 복잡해지는 경우가 많은데, 그런 방식과 달리 간단하고 직관적으로 사용할 수 있다. </p>
<h3 id="기능">기능</h3>
<ul>
<li>캐싱</li>
<li>동일한 데이터에 대한 중복 요청을 단일 요청으로 통합</li>
<li>백그라운드에서 오래된 데이터 업데이트</li>
<li>데이터가 얼마나 오래되었는지 알 수 있다.</li>
<li>데이터 업데이트를 가능한 빠르게 반영</li>
<li>페이지네이션 및 데이터 지연 로드와 같은 성능 최적화</li>
<li>서버 상태의 메모리 및 가비지 수집 관리</li>
<li>구조 공유를 사용하여 쿼리 결과를 메모화</li>
</ul>
<br>

<h2 id="사용하는-방법">사용하는 방법</h2>
<pre><code>npm install @tanstack/react-query
</code></pre><p>해당 라이브러리를 설치한 후, QueryClient를 import해서 새로운 쿼리 클라이언트를 만들어야 한다. 그리고 그것을 QueryClientProvider를 통해 App 컴포넌트의 자손 컴포넌트에 전달해야 한다.</p>
<pre><code>import { QueryClient, QueryClientProvider } from &#39;@tanstack/react-query&#39;;
import HomePage from &#39;./HomePage&#39;;

const queryClient = new QueryClient();

function App() {
  return (
    &lt;QueryClientProvider client={queryClient}&gt;
      &lt;HomePage /&gt;
    &lt;/QueryClientProvider&gt;
  );
}

export default App;</code></pre><br>

<h2 id="💡-usequery">💡 useQuery</h2>
<p><a href="https://tanstack.com/query/v5/docs/framework/react/reference/useQuery">useQuery 공식문서</a>
TanStack Query에 존재하는 다양한 API중 하나로, GET 요청에 대한 데이터를 관리한다.</p>
<pre><code>useQuery({
  queryKey: [&#39;posts&#39;, username],
  queryFn: () =&gt; getPostsByUsername(username),
  staleTime: 60 * 1000,
});
</code></pre><p><strong>queryKey</strong>
필수 값이고, 해당 쿼리에 사용할 쿼리 키이다.</p>
<p><strong>queryFn</strong>
백엔드에서부터 데이터를 받아오는 함수를 지정해주자.</p>
<p><strong>staleTime</strong>
데이터가 언제까지 fresh 상태를 유지할 것인지 정할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/8a1d340e-9ecf-4eac-b6dd-c2174a032c09/image.png" alt=""></p>
<p><code>isPending</code>, <code>isError</code>를 통해 로딩 처리와 에러 처리 또한 가능하다.</p>
<p>정말 너무너무 많으므로 다른 것이 궁금하면 공식문서를 참고하도록 하자!</p>
<br>

<h2 id="🤔-usemutation">🤔 useMutation</h2>
<p><a href="https://tanstack.com/query/v5/docs/framework/react/reference/useMutation">useMutation 공식문서</a></p>
<p>데이터베이스에 값을 추가하거나 변경, 삭제하는 경우 사용한다. <code>POST</code>, <code>PATCH</code>, <code>PUT</code>, <code>DELETE</code> 요청에 대한 데이터를 관리한다.</p>
<pre><code>const mutation = useMutation({
  mutationFn: PatchByUsername(name),
  onMutate() {
    /* ... */
  },
  onSuccess(data) {
    console.log(data);
  },
  onError(err) {
    console.log(err);
  },
  onSettled() {
    /* ... */
  },
});</code></pre><p><code>onSuccess</code>, <code>onError</code> 메서드를 통해 성공했을 시, 실패했을 시 response 데이터를 핸들링할 수 있다.</p>
<p><code>onMutate</code>는 mutation 함수가 실행되기 전에 실행되고, mutation 함수가 받을 동일한 변수가 전달된다.</p>
<p><code>onSettled</code>는 try...catch...finally 구문의 finally처럼 요청이 성공하든 에러가 발생하든 상관없이 마지막에 실행된다.</p>
<br>

<h2 id="참고">참고</h2>
<p><a href="https://tanstack.com/query/latest">TanStack Query</a>
<a href="https://github.com/ssi02014/react-query-tutorial?tab=readme-ov-file#usemutation">react-query-tutorial</a>
<a href="https://tech.kakaopay.com/post/react-query-1/#react-query-%EC%86%8C%EA%B0%9C">카카오페이 프론트엔드 개발자들이 React Query를 선택한 이유</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[쉽고 간단하게 이쁜 애니메이션을 적용하는 방법!]]></title>
            <link>https://velog.io/@jun_o_o/%EC%89%BD%EA%B3%A0-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%9D%B4%EC%81%9C-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98%EC%9D%84-%EC%A0%81%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@jun_o_o/%EC%89%BD%EA%B3%A0-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%9D%B4%EC%81%9C-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98%EC%9D%84-%EC%A0%81%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 23 Jun 2024 10:58:07 GMT</pubDate>
            <description><![CDATA[<p>프로젝트를 하던 도중, 디자인 시안으로 나와있는 아이콘이 너무 심심해 보여서 어떻게 해야 시선을 사로잡을 수 있을까 고민하다가 애니메이션을 사용하게 되었다.</p>
<p>그런데, 너무 단순한 동작만 반복하는 느낌이 들어서... 아직 css 고수가 아닌 나는 좀 더 쉬운 방법이 없을까 찾아보게 되었다.</p>
<p>그래서 찾은 것이 <strong>lottie</strong>!!!</p>
<br>

<h2 id="💡-lottie">💡 Lottie</h2>
<blockquote>
<p>에어비엔비에서 개발한 오픈소스 모바일 라이브러리이다.
Json 기반 애니메이션 파일을 사용하여 애니메이션을 렌더링한다.</p>
</blockquote>
<p>벡터 기반의 애니메이션이므로, 아무리 확대해도 깨지지 않는다는 장점이 있다!</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/22b800f4-0bd5-4e35-b292-82c3a707a9b8/image.png" alt="">
png와 gif에 비해, 정말 획기적인 용량을 보여주는 lottie! 한 번 사용해봐야 할 것 같지 않은가...</p>
<br>

<h2 id="어떻게-적용하나요">어떻게 적용하나요?</h2>
<p>일단 lottiefiles에 접속하여, 원하는 애니메이션을 검색한다.
<img src="https://velog.velcdn.com/images/jun_o_o/post/d49dbe27-8f51-45d3-9aa1-582ce464880a/image.png" alt=""></p>
<p>원하는 애니메이션을 찾았다면, json 파일 형식으로 다운로드를 하면 된다.</p>
<p>그 후에, npm에서 lottie-react를 install해주도록 하자.</p>
<pre><code>npm i lottie-react</code></pre><p>이제 컴포넌트에 lottie를 import 후 적용하면 된다!</p>
<pre><code>import Lottie from &#39;lottie-react&#39;;
import CheckLottie from &#39;@/../public/lottie/check.json&#39;;

...

&lt;Lottie animationData={CheckLottie} /&gt;</code></pre><br>

<h2 id="후기">후기</h2>
<p>프로젝트를 여러모로 이쁘게 만들어준다. 아이콘이 밋밋하거나, 움직여서 사용자의 시선을 끌게 할 때 등, 여러 상황에서 사용할 수 있을 것 같다!</p>
<br>


]]></description>
        </item>
        <item>
            <title><![CDATA[세션 기반 인증과 토큰 기반 인증]]></title>
            <link>https://velog.io/@jun_o_o/%EC%84%B8%EC%85%98-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D%EA%B3%BC-%ED%86%A0%ED%81%B0-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D</link>
            <guid>https://velog.io/@jun_o_o/%EC%84%B8%EC%85%98-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D%EA%B3%BC-%ED%86%A0%ED%81%B0-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D</guid>
            <pubDate>Sun, 23 Jun 2024 10:40:02 GMT</pubDate>
            <description><![CDATA[<p>세션 기반 인증과, 토큰 기반 인증에 대해 알아보자!</p>
<p>자세히 알기 위해서는, 우선 인증이 무엇인지에 대해 알아야 한다.
<br></p>
<h2 id="인증">인증</h2>
<blockquote>
<p>어떤 사용자 또는 장치의 신원을 확인하는 과정</p>
</blockquote>
<p>예시로, 신원을 확인하기 위해 신분증을 제출하는 경우 등을 인증절차라고 할 수 있다.
<br></p>
<h2 id="인가">인가</h2>
<blockquote>
<p>어떤 개체가 어떤 리소스에 접근할 수 있는지, 어떤 동작을 수행할 수 있는지 검증하는 것</p>
</blockquote>
<p>접근 권한을 얻는 일을 말한다.</p>
<p>예시로, 신원을 확인하여 회원가입을 진행한 A와 B가 존재한다고 하자. A가 게시글을 작성하였을 때, B는 A가 작성한 게시글에 대해 수정과 삭제의 권한을 가지고 있지 않다. 타인의 리소스에 대해 인가되어 있지 않기 때문이다.</p>
<p><strong>✨ 인증은 인가로 이어지지만, 인가는 인증으로 이어지지 않는다.</strong>
<br></p>
<h2 id="세션-기반-인증">세션 기반 인증</h2>
<h3 id="세션이란">세션이란?</h3>
<p>서버가 저장하는 사이트 방문자들에 대한 기록이다.
id, ip 주소, 마지막 방문 시기, 사용한 브라우저 등의 정보가 담겨 있다.</p>
<h3 id="세션-기반-인증-1">세션 기반 인증</h3>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/cdf6461d-5697-4dbd-bd6e-694655378c59/image.png" alt="">
세션을 사용한 인증 방식이다.
유저가 로그인 할 시, 서버는 세션 정보를 기록한 뒤 세션을 식별하는 id를 Set-Cookie로 클라이언트에 응답하게 된다.
클라이언트가 서버에 요청할 때, 서버에서 응답한 쿠키를 자동으로 포함하게 된다.</p>
<p><strong>서버는 클라이언트의 쿠키에 담긴 세션 id만 확인해서 방문자의 신원을 파악할 수 있다!</strong></p>
<p>일정한 기간이 지나거나, 클라이언트에서 로그아웃 요청을 보낼 경우 해당 세션이나 로그인 유저를 만료 처리한다.</p>
<br>

<h2 id="토큰-기반-인증">토큰 기반 인증</h2>
<h3 id="인증-토큰">인증 토큰</h3>
<p>유저에 대한 정보를 암호화한 문자열이다.
특정 콘텐츠에 대해 접근할 수 있게 해주기 때문에 Access Token이라고도 한다.
<code>JWT (JSON Web Token)</code> 형식을 가장 많이 사용하고 있다.</p>
<h3 id="토큰-기반-인증-1">토큰 기반 인증</h3>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/b017e6b0-05ae-41c9-a1eb-575eb6750340/image.png" alt="">
유저의 로그인 상태를 저장하고, 요청이 올 때마다 저장 및 확인하지 않고도 유저를 식별할 수 있다.
대신, 토큰 자체를 해석해서 사용하게 된다.</p>
<p>유저가 로그인 할 시, 유저를 식별할 수 있는 id, 만료일 등의 내용이 담긴 토큰을 만들어 클라이언트에게 응답한다.
JWT의 경우 디지털 서명이 존재해 토큰의 내용이 위변조 되었는지 서버측에서 확인이 가능하다.
이후 클라이언트는 응답으로 받은 토큰을 서버에 요청할 때 Authorization 헤더에 담아 전송한다.
<strong>서버는 클라이언트의 토큰을 비밀키를 사용해 해석, 유효성 검증 및 유저를 특정한다.</strong></p>
<p>만료 시간이 지나지 않고, 토큰을 가지고 있는 경우에는 항상 로그인 상태를 유지할 수 있다. 로그아웃을 하고 싶으면 클라이언트에서 저장한 토큰을 삭제하면 된다.</p>
<br>

<h2 id="세션과-토큰-인증의-차이">세션과 토큰 인증의 차이</h2>
<h3 id="사이즈">사이즈</h3>
<p><strong>세션</strong>의 경우 Cookie 헤더에 세션 id만 보내면 되므로 <strong>트래픽을 적게 사용</strong>한다.
<strong>토큰</strong>의 경우(JWT) 사용자 인증 정보, 토큰의 발급 시각, 만료 시각, 토큰의 id 등의 정보를 담으므로 세션 id에 비해 정보가 방대하여 <strong>더 많은 네트워크 트래픽을 사용</strong>한다.</p>
<h3 id="효율성">효율성</h3>
<p>토큰 기반 인증의 장점이다.</p>
<p>세션 기반 인증의 경우, 서버는 항상 로그인 세션을 저장하고 매 리퀘스트가 일어날 때 유저가 누구인지 비교해야 한다.</p>
<p>토큰 기반 인증의 경우 토큰 자체 내용을 해석하면 되기에 효율적으로 작동이 가능하다.</p>
<h3 id="유연성">유연성</h3>
<p>토큰 기반 인증의 경우, 토큰을 발행하는 방법이 똑같고, 시크릿 키만 존재한다면 발행을 한 곳과 확인을 하는 곳이 달라도 유연하게 인증이 가능하다.</p>
<h3 id="restful-api">RESTful API</h3>
<p>세션 정보와 같이 서버가 상태 정보를, 예를 들어 유저가 로그인을 했는지 안 했는지를 저장하고 있는 걸 <strong>stateful</strong>하다고 표현한다.</p>
<p>REST에 부합하기 위해서는, 서버가 상태 정보를 저장하지 않는 특성(<strong>stateless</strong>)이 있어야 한다. </p>
<p>서버는 클라이언트에서 보내는 정보만으로 충분히 상태를 파악할 수 있어야 한다!</p>
<p>이 기준으로 보았을 때, 토큰 기반 인증이 더 어울린다고 할 수 있다.</p>
<h3 id="무효화">무효화</h3>
<p>세션 기반 인증의 장점 중 하나이다.
서버에서 세션 데이터를 따로 관리하므로 특정 세션을 손쉽게 무효화가 가능하다.</p>
<p>안전장치를 더 쉽게 사용할 수 있다는 점으로 이해하도록 하자.</p>
<br>

<h2 id="참고">참고</h2>
<p><a href="https://hackernoon.com/using-session-cookies-vs-jwt-for-authentication-sd2v3vci">Using Session Cookies Vs. JWT for Authentication</a>
<a href="https://www.codeit.kr/topics/user-system-theory/lessons/5513">코드잇-세션vs토큰 기반 인증</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TS] 🐸JavaScript에서 TypeScript로 마이그레이션  해보자!]]></title>
            <link>https://velog.io/@jun_o_o/TS-JavaScript%EC%97%90%EC%84%9C-TypeScript%EB%A1%9C-%EB%A7%88%EC%9D%B4%EA%B7%B8%EB%A0%88%EC%9D%B4%EC%85%98-%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@jun_o_o/TS-JavaScript%EC%97%90%EC%84%9C-TypeScript%EB%A1%9C-%EB%A7%88%EC%9D%B4%EA%B7%B8%EB%A0%88%EC%9D%B4%EC%85%98-%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sun, 02 Jun 2024 17:17:04 GMT</pubDate>
            <description><![CDATA[<h1 id="어쩌다가-하게-되었나">어쩌다가 하게 되었나</h1>
<p>스프린트 미션을 하다가, <code>React + JavaScript</code>로 이루어진 프로젝트를 <strong>타입스크립트로 마이그레이션</strong> 하는 미션을 받게 되었다.</p>
<p>마침 타입스크립트를 배우고 있던 도중이라 정말 잘 해봐야지...! 하면서 열심히 하였으나, 처음이다 보니 너무 삽질을 많이 했다.</p>
<p>적용이 생각보다 어렵다. 그냥 확장자 바꾸고 뭐 하면 끝 아니냐~ 하지만 정말 생각보다 오류가 많았다.
<br></p>
<h1 id="적용-순서">적용 순서</h1>
<h2 id="1-typescript-설치">1. TypeScript 설치</h2>
<pre><code>npm install --save typescript</code></pre><p>만약, <strong>사용하고 있는 라이브러리가 있다면 설치</strong>해주도록 하자.
<strong>Node</strong>의 경우, ts를 해석하지 못하므로 <strong>꼭 <code>ts-node</code>를 설치</strong>해주도록 하자!</p>
<pre><code>npm install --save @types/node @types/react @types/react-dom</code></pre><p>style-components를 사용하고 있다면 @types를 설치하도록 하자.</p>
<pre><code>npm install @types/styled-components --save-dev</code></pre><br>

<h2 id="2-tsconfigjson-생성하기">2. tsconfig.json 생성하기</h2>
<pre><code>tsc --init</code></pre><p><strong>tsconfig란, 타입스크립트를 자바스크립트로 변환할 때의 설정을 정의해 놓은 파일</strong>이다.</p>
<pre><code>{

  &quot;compilerOptions&quot;: {

    &quot;baseUrl&quot;: &quot;src&quot;,

    &quot;target&quot;: &quot;es5&quot;,

    &quot;lib&quot;: [&quot;dom&quot;, &quot;es2015&quot;],

    &quot;allowJs&quot;: true,

    &quot;checkJs&quot;: false,

    &quot;skipLibCheck&quot;: true,

    &quot;strict&quot;: true,

    &quot;esModuleInterop&quot;: true,

    &quot;allowSyntheticDefaultImports&quot;: true,

    &quot;module&quot;: &quot;esnext&quot;,

    &quot;moduleResolution&quot;: &quot;node&quot;,

    &quot;resolveJsonModule&quot;: true,

    &quot;isolatedModules&quot;: true,

    &quot;noEmit&quot;: true,

    &quot;jsx&quot;: &quot;react&quot;, // or &quot;react-jsx&quot; for React 17+

    &quot;forceConsistentCasingInFileNames&quot;: true,

  },

  &quot;include&quot;: [&quot;src&quot;]

}</code></pre><br>

<h2 id="3-customdts-파일-추가">3. custom.d.ts 파일 추가</h2>
<p><strong>d.ts 파일이란 타입만 저장할 수 있는 파일 형식</strong>이다.</p>
<p>나중에 js, jsx 파일을 tsx로 확장자 변경을 하게 된다면, 분명 <strong>import 시 svg, png 등을 인식하지 못하는 문제가 일어난다.</strong></p>
<p>타입스크립트의 타입 시스템 범위 밖에 있으므로 오류가 일어나기에, 우리는 <code>custom.d.ts</code>라는 파일을 만들고 여기 안에 <strong>커스텀 타입을 선언하여 오류가 나지 않도록 할 것</strong>이다!</p>
<pre><code>declare module &#39;*.svg&#39; {
  const content: any;
  export default content;
}

declare module &#39;*.png&#39; {
  const content: any;
  export default content;
}

declare module &#39;*.jpg&#39; {
  const content: any;
  export default content;
}

declare module &#39;*.jpeg&#39; {
  const content: any;
  export default content;
}</code></pre><br>

<h2 id="4-😤-대망의-확장자명-변경-tsx">4. 😤 대망의 확장자명 변경 (tsx)</h2>
<p>이제 드디어 확장자명 변경을 할 시간이 왔다!
여기서 중요한 것은, js, jsx를 <strong>전부 tsx로 변경</strong>해야 한다는 점이다.</p>
<p>이 글은 <strong>React+Typescript를 사용한다는 것을 전제로 작성하였으므로, 꼭 tsx로 변경해주길 바란다.</strong>
<br></p>
<h3 id="41-슬픈-오류의-시간">4.1 슬픈 오류의 시간</h3>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/475b6e89-8c9a-4253-8286-6aadd667b95b/image.png" alt="">
나는 처음에 ts와 tsx가 헷갈렸기에 아무 생각 없이 &quot;js로 작성되어 있는건 ts로, jsx인 거는 tsx로 바꾸면 되겠지~&quot; 라고 생각했지만, 정말 큰 오산이였다.</p>
<blockquote>
<p>~은 값을 참조하지만, 여기서는 형식으로 사용되고 있습니다...</p>
</blockquote>
<p>이 오류는 <strong>타입스크립트가 값과 타입을 제대로 구분하지 못할 때 생기는 문제</strong>인데, ts는 기본적으로 jsx 문법을 인식하지 못한다. 
<strong>tsx는 React 컴포넌트의 타입을 자동으로 추론하고 처리할 수 있어서(JSX 구문을 인식) 오류가 일어나지 않는 것이다.</strong></p>
<p><del>이런 오류를 겪기 싫으면 tsx로 해두자</del></p>
<p>빨간 줄 천지인 프로젝트를 볼 수 있는데, HTML 타입과 Props 타입 등을 천천히 정해가면서 오류를 없애보자!</p>
<p><code>interface</code>를 적재적소에 활용하는 것이 많은 도움이 된다.</p>
<p>결론적으로, TypeScript가 우리가 작성했던 <strong>코드, 컴포넌트의 타입을 올바르게 추론하고 검사</strong>할 수 있도록 하나하나 지정해두자.</p>
<br>

<h3 id="42-다-지정해야-하나요">4.2 다 지정해야 하나요?</h3>
<p> <img src="https://velog.velcdn.com/images/jun_o_o/post/9b5d99c7-ca5a-4835-8e0b-05ccc0833889/image.png" alt=""></p>
<p>article useState의 경우, 초깃값으로 []가 지정이 되어 있기에 정확한 타입 추론이 어렵다. 이런 경우에는 </p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/225a83dc-49ed-4329-9efb-e3f2ebc47a06/image.png" alt="">
위와 같이 정확하게 타입을 지정해주는 것이 좋다.</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/3e38e938-98b5-4bcd-94b0-8f1ed382b0bf/image.png" alt="">
keyword useState의 경우, 초깃값으로 &quot;&quot;이 지정되어 있다. 이런 경우 <strong>TypeScript는 type 추론을 정확하게 할 수 있으므로 굳이 지정해줄 필요가 없다!</strong></p>
<p>처음부터 너무 엄격하게 적용하지 말고, 점진적으로 strict 레벨을 증가시키도록 하자.</p>
<br>

<h1 id="마치며">마치며</h1>
<p>JavaScript에서 TypeScript로 마이그레이션 하는 것은 예상 외로 시간이 많이 걸리니 넉넉하게 잡아두고 해보자!
<br></p>
<h2 id="참고-자료">참고 자료</h2>
<p><a href="https://velog.io/@day_1226/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EB%B0%94%EA%BE%B8%EA%B8%B0">타입스크립트로 바꾸기(벨로그)</a>
<a href="https://velog.io/@jihwooon/TypeScript-%ED%99%98%EA%B2%BD%EC%9C%BC%EB%A1%9C-%EB%A7%88%EC%9D%B4%EA%B7%B8%EB%A0%88%EC%9D%B4%EC%85%98%ED%95%98%EA%B8%B0">타입스크립트 환경으로 마이그레이션하기(벨로그)</a>
<a href="https://joshua1988.github.io/ts/etc/convert-js-to-ts.html#%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%BD%94%EB%93%9C%EC%97%90-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A5%BC-%EC%A0%81%EC%9A%A9%ED%95%A0-%EB%95%8C-%EC%A3%BC%EC%9D%98%ED%95%B4%EC%95%BC-%ED%95%A0-%EC%A0%90">자바스크립트 코드에 타입스크립트를 적용할 때 주의해야 할 점(핸드북)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TS] 💡JavaScript가 아닌 TypeScript를 쓰는 이유 ]]></title>
            <link>https://velog.io/@jun_o_o/TS-JavaScript%EA%B0%80-%EC%95%84%EB%8B%8C-TypeScript%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@jun_o_o/TS-JavaScript%EA%B0%80-%EC%95%84%EB%8B%8C-TypeScript%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Wed, 29 May 2024 17:59:59 GMT</pubDate>
            <description><![CDATA[<h2 id="타입스크립트란">타입스크립트란?</h2>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/9f8e538b-2238-46bf-9cd6-52c9cdae8300/image.png" alt=""></p>
<p><strong>자바스크립트에 타입을 부여한 언어입니다.
자바스크립트의 확장된 언어라고 볼 수 있습니다!</strong></p>
<p>자바스크립트 기반으로 작동되기에, 브라우저에서 실행하기 위해서는 <strong><code>ts</code> 파일을 <code>js</code> 파일로 변환</strong>해주는 과정이 필요합니다. 이를 <strong>&#39;컴파일 과정&#39;</strong>이라고 합니다.
<br></p>
<h3 id="자바스크립트에-어떤-한계가-있나요">자바스크립트에 어떤 한계가 있나요?</h3>
<p>일단, 자바스크립트는 <strong>동적 타입 언어</strong>입니다.
런타임 환경에서 타입을 결정하는 언어입니다.
배우기 쉬우며, 타입을 따로 지정하지 않아도 된다는 장점이 존재합니다.</p>
<p>하지만 실행 도중 제가 생각한 타입과 다른 타입이 결과값으로 나온다면... 자바스크립트는 바로 타입 에러를 띄워버립니다.
<img src="https://velog.velcdn.com/images/jun_o_o/post/8ff35aaa-7417-4a4f-83f9-12716851dd13/image.png" alt=""><em>정말 무서운 에러들입니다</em></p>
<br>

<h3 id="타입스크립트는-어떤-이점이-있나요">타입스크립트는 어떤 이점이 있나요?</h3>
<p>타입스크립트는 <strong>점진적 타입 언어</strong>입니다.</p>
<p>동적 타입 시스템과, 정적 타입 시스템을 혼합한 것 같은 타입 시스템을 사용합니다.</p>
<p>정적 타입 시스템처럼 변수의 타입을 코드 실행 전에 결정하고, 타입 오류가 없는지 프로그램 실행 전에 코드를 검사합니다.</p>
<p>동적 타입 시스템처럼 모든 변수에 일일히 타입을 명시하지 않아도, 변수에 담기는 초기값을 기준으로 자동으로 타입을 알아서 추론하기도 합니다.</p>
<p>이런 특징을 통해, <strong>컴파일 단계에서 오류를 포착할 수 있고</strong>, <strong>어떤 타입의 값이 필요한지 바로 파악이 가능합니다</strong>.</p>
<br>

<h3 id="🤔-타입스크립트는-항상-좋나요">🤔 타입스크립트는 항상 좋나요?</h3>
<p>타입스크립트는 위와 같이 정말 좋은 점을 많이 가지고 있지만, 결국 자바스크립트의 장점인 유연성이 사라진 형태입니다.
<code>any</code> 등으로 보완할 수 있지만, 사용하는 시점에서 타입스크립트의 장점이 많이 퇴색된다고 생각합니다.</p>
<p>또한, <strong>처음에 입문하기에 어려우며</strong> 코드 작성을 할 때 자잘한 타입을 전부 지정해야 하므로 <strong>시간이 오래 걸린다</strong>는 단점이 있습니다.</p>
<br>

<h2 id="그래도-사용하면-확실히-좋다">그래도, 사용하면 확실히 좋다!</h2>
<p><strong>컴파일 단계에서 오류를 포착</strong>할 수 있으므로, 에러를 예방하는 효과가 정말 크다고 생각합니다. 또한, 코드를 통해 <strong>어떤 타입의 값이 필요한지 쉽게 파악</strong>이 가능하여 <strong>흐름을 이해</strong>하기 쉽고, <strong>협업에 도움</strong>이 됩니다.
<br></p>
<h2 id="참고">참고</h2>
<p><a href="https://joshua1988.github.io/ts/why-ts.html">타입스크립트 핸드북</a>
<a href="https://ts.winterlood.com/7250edd7-a3fd-4662-b756-f11f927c73f2">한 입 크기로 잘라먹는 타입스크립트</a>
<a href="https://www.typescriptlang.org/ko/docs/handbook/2/basic-types.html">타입스크립트 공식문서</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 비동기 실행 동작 순서 이해하기(예제)]]></title>
            <link>https://velog.io/@jun_o_o/JS-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%8B%A4%ED%96%89-%EB%8F%99%EC%9E%91-%EC%88%9C%EC%84%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0%EC%98%88%EC%A0%9C</link>
            <guid>https://velog.io/@jun_o_o/JS-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%8B%A4%ED%96%89-%EB%8F%99%EC%9E%91-%EC%88%9C%EC%84%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0%EC%98%88%EC%A0%9C</guid>
            <pubDate>Thu, 18 Apr 2024 01:54:37 GMT</pubDate>
            <description><![CDATA[<p>코드잇 스프린트를 열심히 달려나가던 도중, 어떤 코드에 대해 출력값과 이유를 서술하라는 위클리 페이퍼를 받게 되었다.</p>
<pre><code>// 1번
let num = 1;

// 2번
setTimeout(() =&gt; {
  num = 2;
}, 0);

// 3번
num = 3;

// 4번
console.log(num);</code></pre><p>다행히도 비동기 실행에 대한 공부를 어느 정도 했던 상태인지라, 간단하게 답을 유추할 수 있었다. 이 코드를 이해하기 위해선 일단 비동기 실행에 대해 알아봐야 한다!</p>
<h1 id="비동기-실행이-뭔데">비동기 실행이 뭔데?</h1>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/08bb20f6-034c-4050-b067-01949c919051/image.png" alt=""></p>
<p>특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고, 다음 코드를 먼저 실행하는 자바스크립트의 특성을 의미한다.</p>
<pre><code>// #1
console.log(&#39;Hello&#39;);
// #2
setTimeout(function() {
    console.log(&#39;Bye&#39;);
}, 3000);
// #3
console.log(&#39;Hello Again&#39;);</code></pre><p>위의 예제 코드를 보았을 때, 비동기 실행에 대한 이해가 없다면 실행 순서를 다음과 같은 결과값으로 생각할 것이다.</p>
<blockquote>
<ol>
<li>Hello 출력</li>
<li>3초 뒤 Bye 출력</li>
<li>Hello Again 출력</li>
</ol>
</blockquote>
<p>하지만 실제 실행시켜보면 순서가 다른 걸 알 수 있다.</p>
<blockquote>
<ol>
<li>Hello 출력</li>
<li>Hello Again 출력</li>
<li>3초 뒤 Bye 출력</li>
</ol>
</blockquote>
<p>위의 <code>setTimeout</code> 함수의 콜백은 비동기적으로 실행되기에, 실행 흐름이 다음 코드로 바로 넘어가서 나중에 콜백이 실행되는 것이다.</p>
<h2 id="비동기-실행을-하는-함수들">비동기 실행을 하는 함수들</h2>
<ol>
<li><code>fetch</code></li>
<li><code>setTimeout</code>
특정 함수의 실행을 원하는 시간만큼 뒤로 미루기 위해 사용</li>
<li><code>setInterval</code>
특정 콜백을 일정한 시간 간격으로 실행하도록 등록</li>
<li><code>addEventListener</code>
클릭과 같은 특정 이벤트가 발생 시, 실행할 콜백을 등록하는 메소드.</li>
</ol>
<h1 id="예제-답">예제 답</h1>
<p>결론적으로, 맨 위의 예제에 대한 답은 3이다. <code>console.log</code>가 실행될 당시의 <code>num</code>의 값은 3이기 때문이다.</p>
<h1 id="참고">참고</h1>
<p><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Asynchronous/Introducing">MDN_ 비동기 프로그래밍(JS)</a>
<a href="https://velog.io/@kde9889/JS-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%8B%A4%ED%96%89%EC%9D%98-%EA%B0%84%EB%8B%A8%ED%95%9C-%EB%8F%99%EC%9E%91-%EC%88%9C%EC%84%9C">비동기 실행의 간단한 동작 순서</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[HTTP] HTTP 요청 메서드]]></title>
            <link>https://velog.io/@jun_o_o/HTTP-HTTP-%EC%9A%94%EC%B2%AD-%EB%A9%94%EC%84%9C%EB%93%9C</link>
            <guid>https://velog.io/@jun_o_o/HTTP-HTTP-%EC%9A%94%EC%B2%AD-%EB%A9%94%EC%84%9C%EB%93%9C</guid>
            <pubDate>Sun, 07 Apr 2024 14:51:21 GMT</pubDate>
            <description><![CDATA[<h1 id="http-메서드란">HTTP 메서드란?</h1>
<p>클라이언트가 웹 서버에서 사용자 리퀘스트의 목적 혹은 종류를 알리는 수단이다.</p>
<br>

<h2 id="주요-메소드">주요 메소드</h2>
<br>

<p>💡 <strong><code>GET</code></strong> : 리소스 조회</p>
<p>서버에서 클라이언트가 요청하는 경우, URL 입력, 링크 클릭의 경우에도 <code>GET</code>에 해당한다.
<code>GET</code> 요청은 <strong>멱등성</strong>을 가져, 여러 번 조회를 하여도 리소스는 변하지 않는다.
<code>GET</code> 요청에서 서버에 데이터를 전달하는 경우, <strong>쿼리스트링</strong>을 통해 전달한다.</p>
<br>

<p>💡 <strong><code>POST</code></strong> : 리소스 생성, 수정</p>
<p>새로운 리소스를 생성, 기존 리소스를 수정하기 위해 <strong>서버에 데이터를 보내는 메서드</strong>이다.
리퀘스트 바디를 사용하고, 일반적으로 캐시되지 않는다.
서버의 데이터 변경이 일어날 수 있다.
<strong>멱등성</strong>을 가지지 않아, 여러 번 리퀘스트를 반복할 겨우 동일한 응답을 보장할 수 없다.</p>
<br>

<p>💡 <strong><code>PUT</code></strong> : 리소스 대체, 수정, 없을 경우 생성</p>
<p>새로운 리소스를 생성하거나 기존 리소스를 수정하기 위해 <strong>서버에 데이터를 보내는 메서드</strong>이다.
서버에 리소스가 <strong>없을 경우 생성</strong>, <strong>있을 경우 클라이언트가 보낸 데이터로 대체</strong>한다.
<strong>멱등성</strong>을 가진다.</p>
<br>

<p>💡 <strong><code>DELETE</code></strong> : 리소스 삭제</p>
<p>지정한 리소스를 삭제하는 메서드이다.
<strong>서버의 데이터를 삭제</strong>하는 변경을 하며, <strong>멱등성</strong>을 가진다.</p>
<br>

<p>💡 <strong><code>PATCH</code></strong> : 리소스 부분 변경(수정)</p>
<p>기존 리소스의 부분적 수정을 위한 메서드이다.
<code>PUT</code>은 데이터의 완전 대체이고, <code>PATCH</code>는 부분 수정을 한다.
<strong>멱등성</strong>을 가지지 않는다.</p>
<br>

<p><strong><code>HEAD</code></strong></p>
<p>특정 리소스를 <code>GET</code> 메서드로 요청 시, 돌아올 헤더를 받기 위한 메서드이다.</p>
<br>

<p><strong><code>OPTION</code></strong></p>
<p>서버와 브라우저가 통신하기 위한 통신 옵션을 확인하기 위한 메서드이다.
어떤 <code>method</code>, <code>header</code>, <code>content-type</code>을 제공하는지 확인할 수 있다.</p>
<br>

<p><strong><code>CONNECT</code></strong></p>
<p>대상 자원으로 식별되는 서버에 대한 연결 요청을 하는 메서드이다.</p>
<br>

<h1 id="참고">참고</h1>
<p><a href="https://youwjune.tistory.com/42">HTTP 메서드란?</a>
<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Methods">MDN HTTP 요청 메서드</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 이벤트 버블링, 캡처링, 위임]]></title>
            <link>https://velog.io/@jun_o_o/JavaScript-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81-%EC%BA%A1%EC%B2%98%EB%A7%81-%EC%9C%84%EC%9E%84</link>
            <guid>https://velog.io/@jun_o_o/JavaScript-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81-%EC%BA%A1%EC%B2%98%EB%A7%81-%EC%9C%84%EC%9E%84</guid>
            <pubDate>Sun, 07 Apr 2024 14:15:02 GMT</pubDate>
            <description><![CDATA[<h1 id="이벤트-버블링">이벤트 버블링</h1>
<blockquote>
<p><strong>자식 요소에서 부모 요소</strong>로 이벤트가 전파되는 것</p>
</blockquote>
<p>기본적으로 이벤트 버블링이 일어난다.
<code>event.stopPropagation()</code> 메서드로 전파를 막을 수 있다.
<img src="https://velog.velcdn.com/images/jun_o_o/post/2012ff84-bfed-44ea-b8dd-77fdbffa2f2c/image.png" alt=""></p>
<h1 id="이벤트-캡처링">이벤트 캡처링</h1>
<blockquote>
<p><strong>부모 요소에서 자식 요소</strong>로 이벤트가 전파되는 것</p>
</blockquote>
<p>캡처링에서 이벤트 핸들러를 동작시키려면,<code>addEventListener</code>의 세번째 프로퍼티에 <code>true</code> 혹은 <code>{capture: true}</code>를 전달하면 된다.
<img src="https://velog.velcdn.com/images/jun_o_o/post/45c4fb48-3f45-46d6-b873-2943f3298b3c/image.png" alt=""></p>
<h1 id="이벤트-위임">이벤트 위임</h1>
<p>비슷한 방식으로 여러 요소를 다뤄야 할 때 사용한다.
요소의 공통 조상에 이벤트 핸들러를 하나만 할당해도, 여러 요소를 다룰 수 있기에 편리하다.</p>
<h1 id="버블링을-꼭-써야하는가">버블링을 꼭 써야하는가?</h1>
<p>버블링은 꼭 멈춰야 하는 상황이 아닌 이상 사용하는 것이 좋다.
버블링을 막아야 해결되는 문제는 커스텀 이벤트를 통해 해결할 수 있고, 이벤트 위임이라는 효율적인 방식을 사용하여 코딩할 수 있기 때문이다.</p>
<h1 id="참고">참고</h1>
<p><a href="https://ko.javascript.info/event-delegation">이벤트 위임</a>
<a href="https://ingg.dev/event-delegation/">이벤트 전파와 이벤트 위임 이해하기</a>
<a href="https://velog.io/@tlatjdgh3778/%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81%EA%B3%BC-%EC%BA%A1%EC%B2%98%EB%A7%81%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%A6%AC">이벤트 버블링과 캡처링에 대한 정리</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] var, let, const에 대하여]]></title>
            <link>https://velog.io/@jun_o_o/JavaScript-var-let-const%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</link>
            <guid>https://velog.io/@jun_o_o/JavaScript-var-let-const%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</guid>
            <pubDate>Sun, 31 Mar 2024 12:58:31 GMT</pubDate>
            <description><![CDATA[<h1 id="차이점의-기준">차이점의 기준?</h1>
<p><strong>중복 선언 허용</strong>, <strong>스코프</strong>, <strong>호이스팅</strong>을 기준으로 살펴볼 것이다.</p>
<h1 id="변수-선언-방식">변수 선언 방식</h1>
<p>💡<code>var</code></p>
<ul>
<li>선언과 초기화가 동시에 진행된다.</li>
<li>재선언, 재할당이 가능하다.</li>
</ul>
<pre><code class="language-jsx">var ex1;
console.log(ex1); //undefined

// 아무것도 할당하지 않을 시 undefined 값이 암묵적으로 할당된다.

/*
1. 선언 단계 : 변수 이름을 등록
2. 초기화 단계 : 값을 저장하기 위해 메모리 공간을 확보, undefined 할당해 초기화
이전에 다른 애플리케이션이 사용했던 값(쓰레기 값)이 남아 있을 수 있다.
*/</code></pre>
<p>💡<code>let</code> (ES6)</p>
<ul>
<li>선언만 이루어진다.</li>
<li>재선언이 불가능하고, 재할당이 가능하다.</li>
</ul>
<pre><code class="language-jsx">let ex1;
console.log(ex1); //undefined
ex1 = 1;
console.log(ex1); // 1</code></pre>
<p>💡<code>const</code> (상수, ES6)</p>
<ul>
<li>선언만 이루어진다. 선언과 동시에 초기화를 해야 한다.</li>
<li>재선언, 재할당이 불가능하다.</li>
</ul>
<pre><code class="language-jsx">const ex1 = 0;
ex1 = 1; //TypeError</code></pre>
<h2 id="중복-선언-허용">중복 선언 허용</h2>
<blockquote>
<p><code>var</code>의 경우 허용하지만, <code>let</code>과 <code>const</code>는 허용하지 않는다.</p>
</blockquote>
<pre><code class="language-jsx">var user = &quot;Bae&quot;;
var user = &quot;Jun&quot;; //에러는 발생하지 않는다.

alert(user); // Jun

let myName;
let myName; // SyntaxError</code></pre>
<h1 id="스코프">스코프</h1>
<p>💡<strong>스코프란?</strong></p>
<ul>
<li>식별자(변수명, 함수명, 클래스명…)의 유효범위를 뜻한다.</li>
<li>전역에 선언된 전역변수는 전역 스코프를 가져 모든 곳에서 참조가 가능하다.</li>
<li>지역에 선언된 지역변수는 지역 스코프를 가져 해당 지역, 하위 지역에서만 참조된다.</li>
</ul>
<blockquote>
<p><code>var</code>의 경우 함수 스코프를 지원하고, <code>let</code>과 <code>const</code>의 경우 블록 스코프를 지원한다.</p>
</blockquote>
<pre><code class="language-jsx">var foo = 123; // 전역 변수

console.log(foo); // 123

{
var foo = 456; // 전역 변수
}

console.log(foo); // 456</code></pre>
<pre><code class="language-jsx">let foo = 123; // 전역 변수

{
  let foo = 456; // 지역 변수
  let bar = 456; // 지역 변수
}

console.log(foo); // 123
console.log(bar); // ReferenceError: bar is not defined
</code></pre>
<h1 id="호이스팅">호이스팅</h1>
<p>💡<strong>호이스팅이란?</strong></p>
<ul>
<li><strong>변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징</strong></li>
</ul>
<blockquote>
<p><code>let</code>, <code>const</code>로 선언한 변수는 선언되기 이전에 사용할 수 없다.
<code>var</code> 로 선언한 변수는 함수 스코프를 기준으로 선언되기 이전에도 변수에 접근이 가능하다.</p>
</blockquote>
<pre><code class="language-jsx">console.log(myVariable);
let myVariable; // Uncaught ReferenceError

console.log(myVariable);
var myVariable; //undefined</code></pre>
<h1 id="참조">참조</h1>
<p><a href="https://poiemaweb.com/es6-block-scope">PoiemaWeb</a></p>
<p><a href="https://ko.javascript.info/var">오래된 var</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 얕은 복사, 깊은 복사]]></title>
            <link>https://velog.io/@jun_o_o/JavaScript-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC-31hsqixg</link>
            <guid>https://velog.io/@jun_o_o/JavaScript-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC-31hsqixg</guid>
            <pubDate>Sun, 31 Mar 2024 12:56:18 GMT</pubDate>
            <description><![CDATA[<h1 id="자료형에-따라-달라지는-복사값">자료형에 따라 달라지는 복사값</h1>
<p>자바스크립트에서는 <strong>원시값</strong>과 <strong>참조값</strong> 두 가지 데이터 타입이 존재한다.</p>
<p>💡<strong>원시값</strong></p>
<ul>
<li>기본 자료형(단순한 데이터)를 의미한다.</li>
<li><code>Number</code>, <code>String</code>, <code>Boolean</code>, <code>Null</code>, <code>Undefined</code> , <code>Symbol</code> , <code>BigInt</code></li>
<li>변수에 원시값을 저장 시, 변수의 메모리 공간에 실제 데이터 값이 저장된다.</li>
</ul>
<pre><code class="language-jsx">let a = 1; 
let b = a;

a = 123;

console.log(a); // 123
console.log(b); // 1

//변수에 기본형을 할당 시, 새로운 메모리 공간에 독립적인 실제값이 복사된다.</code></pre>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/832899a2-2a1f-4455-9de8-b4610d2c7d06/image.png" alt=""></p>
<p>💡<strong>참조값</strong></p>
<ul>
<li><p>여러 자료형으로 구성되는 <strong>메모리에 저장된 객체</strong>를 의미한다.</p>
</li>
<li><p><code>Object</code> , <code>Functio</code> , <code>Array</code> …</p>
</li>
<li><p>변수에 객체를 저장 시, 독립적인 메모리 공간에 값을 저장하고 변수에 저장된 메모리 공간의 참조를 저장하게 된다.</p>
<p>  → <strong>할당된 변수를 조작하는 것은, 객체가 아닌 해당 객체의 참조를 조작하는 것</strong>이다.</p>
</li>
</ul>
<pre><code class="language-jsx">let obj1 = {num:1};
let obj2 = obj1;

obj1.num = 123;

console.log(obj1); // num:123
console.log(obj2); // num:123

//변수에 참조형을 할당 시, 해당 객체의 메모리 주소값이 복사된다.</code></pre>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/cef62281-9263-4513-a4ff-e0f6cf7503a4/image.png" alt=""></p>
<h2 id="얕은-복사">얕은 복사</h2>
<blockquote>
<p>객체의 메모리 주소 값을 복사하는 것!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/5430279a-d407-46bd-9a1c-b75013ba86d6/image.png" alt=""></p>
<p>💡<strong>방법</strong></p>
<pre><code class="language-jsx">1. Array.prototype.slice()
/* start ~ end 인덱스까지 기존 배열에서 추출하여 새로운 배열을 리턴.
    start, end를 설정하지 않을 시 기존 배열을 전체 얕은 복사
    slice() 메소드의 경우 기본적으로 얕은 복사 수행 */

2. Object.assign(생성할 객체, 복사할 객체);

3. Spread 연산자(전개 연산자)</code></pre>
<h2 id="깊은-복사">깊은 복사</h2>
<blockquote>
<p>실제 값을 복사하는 것!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/62ce3332-592a-428f-b5cc-605040045cde/image.png" alt=""></p>
<p>💡<strong>방법</strong></p>
<pre><code class="language-jsx">1. JSON.parse(JSON.stringfy(obj))
/* stringfy의 경우 객체를 json 문자열로 변환
    이 과정에서 객체의 참조가 모두 끊어짐
    객체를 json 문자열로 변환 후 
    다시 parse를 통해 원래 객체로 만든다. */

    - 가장 간편하다.
    - function이 있는 경우, undefined도 처리한다
    - 다른 방법에 비해 느리다는 단점이 있다.

2. 커스텀 재귀 함수
    - 객체의 함수도 제대로 표현할 수 있다.
    - 복잡하다.

3. Lodash와 같은 외부 라이브러리
    - 사용에 제약이 없다면 가장 효과적이다.</code></pre>
<h1 id="참조">참조</h1>
<p><a href="https://bbangson.tistory.com/78">[JavaScript] 깊은 복사, 얕은 복사</a></p>
<p><a href="https://choar816.tistory.com/154">[JS] 얕은 복사, 깊은 복사 차이 쉽게 이해하기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] Git Flow]]></title>
            <link>https://velog.io/@jun_o_o/Git-Git-Flow</link>
            <guid>https://velog.io/@jun_o_o/Git-Git-Flow</guid>
            <pubDate>Mon, 25 Mar 2024 05:12:35 GMT</pubDate>
            <description><![CDATA[<h1 id="git-flow란">Git Flow란?</h1>
<p>브랜치를 나누는 전략 중 하나이다.</p>
<ul>
<li><strong>main</strong>: 정식 배포의 기준이 되는 브랜치이다. 언제나 배포 가능한 상태로 유지되어야 하는 브랜치이다.</li>
<li><strong>develop</strong>: 개발 중인 코드를 관리하는 브랜치이다. 새로운 기능 개발, 개발된 변화를 담은 버전 배포작업이 시작될 수 있다.</li>
<li><strong>feature</strong>: 개발할 기능을 위한 브랜치이다. 기능 개발이 완료될 시, develop으로 병합되고 feature는 제거된다.</li>
<li><strong>release</strong>: 배포를 위한 브랜치이다. 배포 전 마무리 작업, 버그 수정이 이루어진다. 완료 시 main, develop으로 병합되고 제거된다.</li>
<li><strong>hotfix</strong>: 긴급한 버그 수정을 위한 브랜치이다. master 브랜치를 기준으로 생성하게 된다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/1c7cfa88-0852-4010-9a94-66bfe8ff02cb/image.png" alt=""></p>
<h2 id="왜-branch를-분류하나요">왜 branch를 분류하나요?</h2>
<blockquote>
<p>협업 중 수정된 코드의 충돌을 방지하기 위해서</p>
</blockquote>
<h2 id="장점">장점</h2>
<ul>
<li>안정적인 배포를 위한 구조</li>
<li>긴 개발 주기에 적합, 복잡한 기능 개발 버그 수정에 유용</li>
</ul>
<h2 id="단점">단점</h2>
<ul>
<li>브랜치가 많아지고, 관리해야 할 작업 증가</li>
<li>작은 규모의 프로젝트에는 비효율적</li>
</ul>
<h1 id="참고">참고</h1>
<p><a href="https://github.com/nvie/gitflow">git-flow 도구</a>
<a href="https://puleugo.tistory.com/165">github Convention 정리, 모음</a>
<a href="https://puleugo.tistory.com/107">git flow란</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] branch merge란?]]></title>
            <link>https://velog.io/@jun_o_o/Git-branch-merge%EB%9E%80</link>
            <guid>https://velog.io/@jun_o_o/Git-branch-merge%EB%9E%80</guid>
            <pubDate>Mon, 25 Mar 2024 05:00:48 GMT</pubDate>
            <description><![CDATA[<h1 id="branch">branch</h1>
<p>여러 개발자들이 동시에 다양한 작업을 할 수 있게 만들어 주는 기능이다.</p>
<blockquote>
<p>독립적으로 어떤 작업을 진행하기 위한 개념</p>
</blockquote>
<p>브랜치를 나누지 않으면, 여러 사람이 commit할 경우 충돌이 일어날 확률이 높다. 또한, 서로 작업한 commit 내역을 내 로컬 repo에 계속 반영해야 한다!
<img src="https://velog.velcdn.com/images/jun_o_o/post/6cb1df2a-8347-4328-a0bc-62ff2bc011cf/image.png" alt=""></p>
<h2 id="branch-merge">branch merge</h2>
<p>현재 branch에서 다른 branch를 합칠 때 사용한다.</p>
<p><img src="https://velog.velcdn.com/images/jun_o_o/post/47f451b1-6ec4-428b-84b6-b3508180a54f/image.png" alt=""></p>
<h3 id="create-a-merge-commit">Create a merge commit</h3>
<p><strong>각각의 branch에 남은 commit을 히스토리에 그대로 남긴다.</strong></p>
<blockquote>
<p>commit 이력을 모두 남겨야 할 때 사용한다.</p>
</blockquote>
<pre><code>git merge {머지할 브랜치}</code></pre><p><img src="https://velog.velcdn.com/images/jun_o_o/post/d9808352-1845-4e61-8814-997169ca85f9/image.png" alt=""></p>
<h3 id="squach-and-merge">Squach and merge</h3>
<p>개발용 branch에 있던 내용을 하나로 합쳐서 중앙 branch에 <strong>하나의 commit</strong>으로 저장하는 전략</p>
<blockquote>
<p>기존 변경사항들의 상세내용보다, merge 자체에 목적을 두고 사용한다.</p>
</blockquote>
<p>다만, <strong>개발용 branch에서 어떤 코드를 언제 바꿨는지</strong>에 대해 헷갈릴 수 있으므로 주의!</p>
<pre><code>git merge --squash</code></pre><p>![]
(<a href="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBNK1m%2FbtrVo5r9pF5%2F9qrwyTxP3XGHwk7jpBQd8K%2Fimg.png">https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBNK1m%2FbtrVo5r9pF5%2F9qrwyTxP3XGHwk7jpBQd8K%2Fimg.png</a>)</p>
<h3 id="rebase-and-merge">Rebase and merge</h3>
<p>Rebase라는 기능을 이용한다.</p>
<blockquote>
<p>히스토리의 Base를 직접 옮겨서 처리하는 방식이므로, 개발용 branch에서 변경한 내용을 중앙 branch에서 변경한 것처럼 바꿔버릴 수 있다!</p>
</blockquote>
<p>Merge commit이 없으므로, <strong>어느 시점에 Merge가 되었는지 나중에 판단하기 어렵다.</strong></p>
<pre><code>git merge -ff</code></pre><h2 id="그래서-뭐가-더-좋나요">그래서, 뭐가 더 좋나요?</h2>
<blockquote>
<p>특정 기능 개발 후 develop branch에 머지하려고 하면, Squash and Merge가 유용하다.</p>
</blockquote>
<blockquote>
<p>develop branch를 production branch로 merge하고자 할 때는 develop branch에 분기가 남아있다면, production branch는 간결하게 유지하고자 Rebase and Merge가 유용하다.</p>
</blockquote>
<h1 id="참고">참고</h1>
<p><a href="https://ssocoit.tistory.com/273">https://ssocoit.tistory.com/273</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CSS] Position]]></title>
            <link>https://velog.io/@jun_o_o/CSS-Position</link>
            <guid>https://velog.io/@jun_o_o/CSS-Position</guid>
            <pubDate>Mon, 18 Mar 2024 05:55:12 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jun_o_o/post/5361b768-7fc3-4bc3-993b-18b82f00c62e/image.png" alt=""></p>
<h1 id="position">Position</h1>
<blockquote>
<p>글의 흐름에서 벗어나서, <strong>요소를 자유롭게 배치할 때 사용</strong>하는 속성이다.</p>
</blockquote>
<ul>
<li><code>static</code>, <code>relative</code>, <code>absolute</code>, <code>fixed</code>, <code>sticky</code> 가 있다.</li>
<li><code>top</code>, <code>bottom</code>, <code>left</code>, <code>right</code> 속성으로 위치를 변경한다.</li>
</ul>
<h2 id="static">static</h2>
<p>요소를 일반적인 문서 흐름에 따라 배치한다. 기본값으로 지정된다.</p>
<h2 id="relative">relative</h2>
<p>요소를 일반적인 문서 흐름에 따라 배치한다. <code>top</code> 등의 값에 따라 위치가 변경된다.<img src="https://velog.velcdn.com/images/jun_o_o/post/20724e60-d2d9-4c03-93d2-96d6b30047ae/image.png" alt=""></p>
<h2 id="absolute">absolute</h2>
<p>요소를 <strong>일반적인 문서 흐름에서 제거</strong>한다. 페이지 레이아웃에 공간도 배정하지 않는다.
가장 가까운 위치 지정 조상 요소에 대해 상대적으로 배치된다.
<strong>조상 중 위치 지정 요소가 없을 시 초기 컨테이닝 블록을 기준으로 삼아 배치된다.
<img src="https://velog.velcdn.com/images/jun_o_o/post/560fe04c-d8bc-4397-b7d4-d9d7fa1b5592/image.png" alt="">
.</strong></p>
<h2 id="fixed">fixed</h2>
<p>요소를 <strong>일반적인 문서 흐름에서 제거</strong>하고, 페이지 레이아웃에 공간도 배정하지 않는다.
뷰포트의 초기 컨테이닝 블록을 기준 삼아 배치된다. 마우스 스크롤로 화면을 바꾸어도 움직이지 않는다!
<strong>네비게이션</strong>을 만들 때 많이 사용된다.
<img src="https://velog.velcdn.com/images/jun_o_o/post/d35178fa-da2e-4394-a8cd-5566fe104dae/image.png" alt=""></p>
<h2 id="sticky">sticky</h2>
<p><code>static</code>처럼 원래 위치에 있따가, 정해진 위치에 브라우저가 스크롤되면 <code>fixed</code>처럼 고정되어 배치된다.</p>
<hr>
<h1 id="참고">참고</h1>
<p><a href="https://developer.mozilla.org/ko/docs/Web/CSS/position">MDN-Position</a></p>
]]></description>
        </item>
    </channel>
</rss>