<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>felog</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 10 Jul 2024 13:48:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>felog</title>
            <url>https://velog.velcdn.com/images/jiin-seok/profile/3eadfa4d-bd4d-4c53-b2bc-4bd976c76b51/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. felog. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jiin-seok" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Next.js, 어떻게 편할까?]]></title>
            <link>https://velog.io/@jiin-seok/Next.js-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%8E%B8%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@jiin-seok/Next.js-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%8E%B8%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Wed, 10 Jul 2024 13:48:32 GMT</pubDate>
            <description><![CDATA[<h3 id="nextjs란">Next.js란</h3>
<ul>
<li>React 기반의 프레임워크이다.</li>
<li>웹 애플리케이션을 쉽게 구축할 수 있다. 별도 설정 없이도 가능한 게 많다.</li>
</ul>
<h2 id="다른-프레임워크-라이브러리보다-편리한-점">다른 프레임워크, 라이브러리보다 편리한 점</h2>
<ol>
<li><p><strong>(설정 불필요) 추가 설정을 안 해도 된다.</strong></p>
<ul>
<li>따로 설정할 것이 많으면 정하고 지켜야 할 규칙도 많다.</li>
<li>프레임워크가 지정한 방법이 있으면 그 자체로 컨벤션이 된다.</li>
</ul>
</li>
<li><p><strong>(특징적 기능) 추가 설정으로도 불가능한 것이 가능하다.</strong></p>
<ul>
<li>다른 자바스크립트 환경에서는 불가능한 것이 가능하다.</li>
</ul>
</li>
</ol>
<h2 id="특징적-기능">특징적 기능</h2>
<h3 id="관리-용이-파일-기반-라우팅">(관리 용이) 파일 기반 라우팅</h3>
<p><strong>Next.js</strong></p>
<ul>
<li>파일 시스템을 라우팅 시스템으로 사용한다.
<code>pages</code> 디렉토리에 파일을 생성하면 해당 파일이 자동으로 URL 경로와 매핑한다.</li>
<li>파일명을 <code>[param]</code> 형태로 하여 동적 라우팅도 가능하다.</li>
</ul>
<p><strong>다른 프레임워크에서 하려면</strong></p>
<ul>
<li>예를 들어 React Router는 라우팅 설정을 별도로 구성해야 하는데 방법이 다양하다.</li>
<li>경로 = 파일명이 아니어서 파일명을 짓는 수고가 든다.</li>
</ul>
<h2 id="설정-불필요">설정 불필요</h2>
<h3 id="관리-용이-api-라우팅">(관리 용이) API 라우팅</h3>
<p><strong>Next.js</strong></p>
<ul>
<li><code>pages/api</code> 디렉토리에 파일을 생성해 <strong>API 엔드포인트</strong>를 만든다.</li>
<li>프론트엔드와 백엔드 코드를 하나의 프로젝트에서 관리할 수 있다.</li>
</ul>
<pre><code class="language-js">// pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ message: &#39;Hello, world!&#39; });
}</code></pre>
<blockquote>
<p><strong>엔드포인트 예</strong>
GET /users - 모든 사용자 목록을 가져오는 요청
POST /users - 새로운 사용자를 생성하는 요청
GET /users/{id} - 특정 ID를 가진 사용자의 정보를 가져오는 요청
PUT /users/{id} - 특정 ID를 가진 사용자의 정보를 업데이트하는 요청
DELETE /users/{id} - 특정 ID를 가진 사용자를 삭제하는 요청</p>
</blockquote>
<p><strong>다른 프레임워크에서 하려면</strong></p>
<ul>
<li>전통적인 웹 개발에서는 <strong>별도의 백엔드 서버(예: Express.js, Django 등)</strong>를 설정하고, <strong>API 통신으로 프론트엔드와 통합</strong>한다.</li>
</ul>
<pre><code class="language-js">// pages/index.js
export async function getServerSideProps() {
  const res = await fetch(&#39;https://api.example.com/data&#39;);
  const data = await res.json();
  return { props: { data } };
}

export default function Home({ data }) {
  return &lt;div&gt;{data.message}&lt;/div&gt;;
}</code></pre>
<h3 id="최적화-지원-서버-사이드-렌더링-ssr-및-정적-사이트-생성-ssg">(최적화 지원) 서버 사이드 렌더링 (SSR) 및 정적 사이트 생성 (SSG)</h3>
<p><strong>Next.js</strong></p>
<ul>
<li><strong>서버 측에서 페이지를 렌더링하는 SSR, 빌드 시점에 정적 페이지를 생성하는 SSG</strong>를 기본적으로 지원한다. SEO, 초기 로드 성능을 향상할 수 있다.</li>
</ul>
<p><strong>다른 프레임워크에서 하려면</strong></p>
<ul>
<li>React와 같은 라이브러리는 기본적으로 클라이언트 사이드 렌더링(CSR)만을 지원한다.</li>
<li><strong>예: Gatsby, Nuxt.js</strong> 등 추가적인 설정과 라이브러리가 필요하다.</li>
</ul>
<h3 id="최적화-지원-이미지-최적화">(최적화 지원) 이미지 최적화</h3>
<p><strong>Next.js</strong></p>
<ul>
<li>성능을 향상시킬 수 있는 이미지 최적화 기능이 내장되어 있다.</li>
<li>이미지 크기 조정, 포맷 변환, 지연 로딩 등</li>
</ul>
<p><strong>다른 프레임워크에서 하려면</strong></p>
<ul>
<li><strong>Cloudinary, Imgix 등</strong> 별도의 라이브러리나 서비스를 사용한다.</li>
</ul>
<h3 id="최적화-지원-자동-코드-분할">(최적화 지원) 자동 코드 분할</h3>
<p><strong>Next.js</strong></p>
<ul>
<li>빌드 시점에 페이지 단위로 자동 코드 분할이 이루어진다.</li>
<li><strong>사용자가 특정 페이지에 접근할 때 그 페이지에 필요한 코드만 다운로드</strong>된다.</li>
<li><strong>초기 로드 성능이 향상된다.</strong></li>
</ul>
<pre><code class="language-jsx">// 프로젝트 구조

my-next-app/
├── pages/
│   ├── index.js
│   ├── about.js
│   └── contact.js</code></pre>
<pre><code class="language-jsx">// 빌드 후 파일 구조 (Next.js 애플리케이션)
// Next.js는 각 페이지를 별도의 JavaScript 청크로 분할

.next/
├── static/
│   ├── chunks/
│   │   ├── pages/
│   │   │   ├── index.js
│   │   │   ├── about.js
│   │   │   └── contact.js</code></pre>
<p><strong>다른 프레임워크에서 하려면</strong></p>
<ul>
<li>Webpack 등의 번들러를 직접 설정한다.</li>
</ul>
<h3 id="보안-미들웨어">(보안) 미들웨어</h3>
<p><strong>Next.js</strong></p>
<ul>
<li>Next.js 12부터 미들웨어 기능을 지원한다.</li>
<li><strong>요청을 가로채고, 라우팅 전후에</strong> <strong>인증, 로깅, 리다이렉션</strong> 등을 수행할 수 있다. </li>
</ul>
<pre><code class="language-jsx">// middleware.js
// 토큰이 없으면 로그인 페이지로 리다이렉트

export function middleware(req, ev) {
    if (req.nextUrl.pathname.startsWith(&#39;/admin&#39;)) {
        const **token = req.cookies.token;**
        **if (!token) {**
            return Response.**redirect(new URL(&#39;/login&#39;, req.url))**;
        }
    }
    return Response.next();
}</code></pre>
<p><strong>다른 프레임워크에서 하려면</strong></p>
<ul>
<li><strong>Express.js와 같은 백엔드 프레임워크에서</strong>, 별도의 설정과 코드를 추가해 사용한다.</li>
</ul>
<h3 id="코드-호환성-css-및-스타일링">(코드 호환성) CSS 및 스타일링</h3>
<p><strong>Next.js</strong></p>
<ul>
<li>CSS 및 <strong>Sass</strong>(!= SCSS)를 기본적으로 지원한다.</li>
<li><strong>설정 없이 다양한 CSS-in-JS 라이브러리와 호환</strong>된다(styled-components, Emotion 등).</li>
</ul>
<p><strong>다른 프레임워크에서 하려면</strong></p>
<ul>
<li>스타일링을 위한 설정이 필요하다.</li>
</ul>
<h3 id="코드-호환성-typescript-지원">(코드 호환성) TypeScript 지원</h3>
<p><strong>Next.js</strong></p>
<ul>
<li>TypeScript를 기본적으로 지원한다.</li>
<li><strong>프로젝트에 TypeScript를 도입하는 과정이 매우 간단</strong>하다.</li>
</ul>
<pre><code class="language-bash">touch tsconfig.json // tsconfig.json 파일을 생성
npm run dev // 개발 서버 실행, 패키지와 설정 파일들이 자동으로 설치되고 구성됨</code></pre>
<pre><code class="language-bash">npm install --save-dev typescript @types/react @types/node // TypeScript 설치
npm run dev // 개발 서버 실행, 패키지와 설정 파일들이 자동으로 설치되고 구성됨</code></pre>
<p><strong>다른 프레임워크</strong></p>
<ul>
<li><strong>설정 파일과 추가 패키지를 직접 구성</strong>한다.</li>
</ul>
<h3 id="관리-용이-배포-및-호스팅">(관리 용이) 배포 및 호스팅</h3>
<p><strong>Next.js</strong></p>
<ul>
<li>Next.js 앱은 CI/CD 파이프라인을 내장한 Vercel로 쉽고 빠르게 배포, 호스팅할 수 있다.<ul>
<li>GitHub, GitLab, Bitbucket 등과 통합하여 코드 푸시 시 자동으로 배포할 수 있다.</li>
</ul>
</li>
</ul>
<p><strong>다른 프레임워크</strong></p>
<ul>
<li>배포를 위한 별도의 CI/CD 설정이나 호스팅 서비스를 구성해야 한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 사이트 꾸미기 - 파비콘 & 썸네일 넣기 (Public 폴더 활용)]]></title>
            <link>https://velog.io/@jiin-seok/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%BE%B8%EB%AF%B8%EA%B8%B0-%ED%8C%8C%EB%B9%84%EC%BD%98-%EC%8D%B8%EB%84%A4%EC%9D%BC-%EB%84%A3%EA%B8%B0-Public-%ED%8F%B4%EB%8D%94-%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@jiin-seok/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%82%AC%EC%9D%B4%ED%8A%B8-%EA%BE%B8%EB%AF%B8%EA%B8%B0-%ED%8C%8C%EB%B9%84%EC%BD%98-%EC%8D%B8%EB%84%A4%EC%9D%BC-%EB%84%A3%EA%B8%B0-Public-%ED%8F%B4%EB%8D%94-%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Wed, 26 Jun 2024 02:44:19 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.w3schools.com/html/html_favicon.asp">https://www.w3schools.com/html/html_favicon.asp</a></p>
<p><a href="https://create-react-app.dev/docs/using-the-public-folder/">https://create-react-app.dev/docs/using-the-public-folder/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트 툴 & 컨벤션 세팅하기]]></title>
            <link>https://velog.io/@jiin-seok/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8C%8C%EC%9D%BC-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0-.gitignore%EB%B6%80%ED%84%B0-axios-package.json%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@jiin-seok/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8C%8C%EC%9D%BC-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0-.gitignore%EB%B6%80%ED%84%B0-axios-package.json%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Wed, 12 Jun 2024 11:27:50 GMT</pubDate>
            <description><![CDATA[<p>처음으로 협업 프로젝트를 설정해 보았다.
초기에 빠르게 진행해 참여자 모두가 작업할 공간을 마련해야 하는 부분이므로 
프로젝트 세팅 전 과정을 다시 해보면서 이번 경험을 기록하고자 한다.</p>
<h1 id="github-세팅">Github 세팅</h1>
<h3 id="organization-생성">Organization 생성</h3>
<ol>
<li><p>깃허브 상단 네비게이터의 프로필 이미지 클릭!
<img src="https://velog.velcdn.com/images/jiin-seok/post/1c15888f-d7ef-464b-9b25-06bae565542c/image.png" alt=""></p>
</li>
<li><p>Your organizations
<img src="https://velog.velcdn.com/images/jiin-seok/post/b9d4e00b-a891-4e29-88b0-4df3df7a2f14/image.png" alt=""></p>
</li>
<li><p>New organization
<img src="https://velog.velcdn.com/images/jiin-seok/post/f84409c1-36a9-4fc0-bff9-fffef4311c84/image.png" alt=""></p>
</li>
<li><p>플랜 선택, 보통 Create a free organization
<img src="https://velog.velcdn.com/images/jiin-seok/post/27a6a38e-f25e-4921-b56c-bdb610b14571/image.png" alt=""></p>
</li>
<li><p>Set up your organization</p>
</li>
</ol>
<ul>
<li><strong>Organization Name</strong>은 이렇게 주소에 들어간다.
<a href="https://github.com/organizations/watermelon-project/">https://github.com/organizations/watermelon-project/</a></li>
<li>이때 <strong>Contact email이 필요</strong>해서 장기 프로젝트는 공용 이메일주소를 마련해도 좋겠다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/5112e468-2c95-44d3-b86d-780a3af32829/image.png" alt=""></li>
</ul>
<ol start="6">
<li>Add organization members</li>
</ol>
<ul>
<li>팀원 깃허브 계정 정보를 미리 조사하면 좋다. 
(username, full name or email address)</li>
<li>skip this step 하고 나중에 초대할 수도 있다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/279fc649-284c-4edd-87e6-980a3ca53742/image.png" alt="">
<img src="https://velog.velcdn.com/images/jiin-seok/post/23cc84c4-9469-494f-9941-2a8769e4d9d6/image.png" alt=""></li>
</ul>
<ol start="7">
<li>인증하면 생성된다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/03d604a3-f401-46d4-86f1-26d2ef8ff7ee/image.png" alt=""></li>
</ol>
<h3 id="repository-생성">Repository 생성</h3>
<ol start="8">
<li><p>oranization &gt; Repositories &gt; New repository 
<img src="https://velog.velcdn.com/images/jiin-seok/post/cb258da4-8897-4f98-90cb-d375736a585f/image.png" alt=""></p>
</li>
<li><p>Create new repository</p>
</li>
</ol>
<ul>
<li><strong>Organization Name</strong>도, <strong>Repository name</strong>으로 사용할 프로젝트 이름도 미리 정하는 것 추천! 주소로 쓰이니 다른 팀원들 마음에도 들도록 ㅎㅎ</li>
<li>나는 학습용으로 사용하기 위해 Public을 선택했다.</li>
<li>Add a README file &amp; Add .gitignore 굳이 하지 않는다. 프로젝트 파일에 react를 설치하면 생기는 예시 파일을 편집해서 사용하면 된다. 
<img src="https://velog.velcdn.com/images/jiin-seok/post/3b599ce5-5eae-4ecb-916f-fa91f2fa2e84/image.png" alt=""></li>
</ul>
<h3 id="프로젝트-디렉토리-생성--연결">프로젝트 디렉토리 생성 &amp; 연결</h3>
<ol start="10">
<li>이제 로컬에 프로젝트를 만들고 깃허브에 만든 레포지토리와 연결한다.</li>
</ol>
<ul>
<li><p>create a new repository: 그냥 로컬에서 디렉토리 만들어서 열고 명령어로 레포지토리 만들고 깃허브랑 연결하는 것이다.</p>
</li>
<li><p>push an existing repository: 이건 명령어로 깃허브랑 연결만 하는 것. 주로 쓰던 방법이다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/07222521-a1e9-478b-a38b-f609cf47fe1f/image.png" alt=""></p>
</li>
<li><p>Qick setup: 난 이걸 추천한다. </p>
<ul>
<li><p>set up in desktop 하면 GitHub Desktop이라는 프로그램 설치가 안내된다. 이게 뭐냐면 그냥 Git을 GUI로 하는 프로그램이다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/a4c38181-b956-4c24-a61e-53d0888e9b60/image.png" alt=""></p>
</li>
<li><p>이미 설치한 사람은 이렇게 프로그램이 열린다. clone만 누르면 프로젝트 디렉토리 생성부터 remote 연결까지 한방에 된다. 굿 (clone 하는 것이므로)</p>
</li>
<li><p>나중에 인증 문제가 있을 수 있으니 URL만 HTTPS에서 아까의 안내 페이지에 있던 SSH로 바꿔준다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/928b0298-713a-4d06-8405-fa30f4de52b7/image.png" alt="">
<img src="https://velog.velcdn.com/images/jiin-seok/post/74b176c2-aee9-49d0-ad48-a1023e3956ce/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<h1 id="github-컨벤션-공지">GitHub 컨벤션 공지</h1>
<h2 id="이슈-pr-템플릿-등록">이슈, PR 템플릿 등록</h2>
<p>PR이 머지되면 이슈 Close 되게 하는 방법</p>
<h2 id="브랜치-룰-설정">브랜치 룰 설정</h2>
<p>브랜치 머지 조건 설정 (PR 강제)</p>
<h2 id="이슈---커밋---pr---코드리뷰---머지-방법">이슈 - 커밋 - PR - 코드리뷰 - 머지 방법</h2>
<h3 id="이슈">이슈</h3>
<p>이슈는 무엇을 어떻게 써야 할까?</p>
<h3 id="커밋">커밋</h3>
<h3 id="브랜치">브랜치</h3>
<h3 id="머지">머지</h3>
<p>추천 템플릿과 이유
이슈, 커밋, PR의 크기는?
코드 리뷰 쉽게 하기 
머지 커밋 방지
깃 그래프 보기
빌드 확인하기
배포 미리보기, 체커, 자동배포</p>
<h1 id="도구-사용---설정-파일-추가">도구 사용 - 설정 파일 추가</h1>
<h3 id="gitignore-추가">gitignore 추가</h3>
<ol start="11">
<li>gitignore.io
아까 깃허브에서 굳이 수고하지 않은 이유... 이런 좋은 사이트가 있기 때문이다 ㅎㅎ
<a href="https://www.toptal.com/developers/gitignore">https://www.toptal.com/developers/gitignore</a></li>
</ol>
<ul>
<li>검색창에 팀의 개발 환경 정보를 모두 넣고(OS, IDE, 언어/프레임워크) 생성 버튼을 클릭하면 gitignore의 내용이 생성된다.</li>
<li>위의 검색창에서 어떤 정보를 골라서 생성한 건지도 주석으로 기록된다. 그대로 붙여넣는다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/17f10be9-8ae7-4a22-b96a-40a3aeef03dc/image.png" alt="">
<img src="https://velog.velcdn.com/images/jiin-seok/post/8f0b4329-d8a9-46f0-b812-14375fbdec2e/image.png" alt="">
<img src="https://velog.velcdn.com/images/jiin-seok/post/00eaf54c-ff45-42a3-bfe1-e38f4b328a99/image.png" alt=""></li>
</ul>
<ol start="12">
<li>첫 커밋을 하고 푸시하면 로컬과 원격이 잘 연결되어 있다는 걸 확인할 수 있다.</li>
</ol>
<p><strong>가능하면 설정 파일은 프로젝트에 필요한 만큼만 레포에 푸시하는 게 좋다.</strong> (예시 파일/코드 삭제, gitignore 설정)
그러지 않으면 설정한 사람만 추가한 코드가 엄청 많아져서 깃허브 Insight를 볼 때 진짜(?) 기여도를 알기 어렵다.
게다가 언젠가 누군가는 예시 코드/파일을 삭제해야 하니 index 파일 정리와 라우터, 페이지 컴포넌트, 그 안에 페이지 이름 넣기 정도는 세팅하는 사람이 미리 해두는 게 깔끔하다! 
<img src="https://velog.velcdn.com/images/jiin-seok/post/44283553-9ed0-43e1-b6a1-6cd610e9c52c/image.png" alt=""></p>
<h3 id="react-app-설치">React App 설치</h3>
<ol start="11">
<li>무사히 생성됐으니 IDE에서 프로젝트 디렉토리를 열고 터미널에서 명령어로 React를 설치한다.</li>
</ol>
<ul>
<li><p><code>npm init react-app .</code>
<code>npm init react-app &lt;폴더 이름&gt;</code> 으로도 된다는데 나는 설치 과정에서 파일이 추가되는 게 보이는 것도 좋고 명령어가 늘 똑같아서 위 방법을 쓴다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/9493c895-2df3-41c1-b259-0a7754678e43/image.png" alt=""></p>
</li>
<li><p>컴퓨터 사양만큼 기다린다. 난 맥미니 써서 좀 기다렸다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/3782feb4-202b-4cdc-9339-2a4641cc79e7/image.png" alt=""></p>
</li>
<li><p>Happy hacking! 예시 파일로 프로젝트 뼈대가 생겼으니, 설정 파일을 본격적으로 추가한다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/10cfddab-ee35-4327-9f6c-4c9f0049f493/image.png" alt=""></p>
</li>
</ul>
<h3 id="editor-config">Editor Config</h3>
<p>에디터마다 GUI로 설정해야 하는 부분을 파일로 전달하는 셈이라 프로젝트 루트에 두고 레포지토리에 올리면 공통된 설정을 사용할 수 있다고 한다.
<code>.editorconfig</code></p>
<pre><code>root = true

[*]
indent_style = space          # 들여쓰기에 스페이스 사용
indent_size = 2               # 들여쓰기 크기는 스페이스 2개로 쓰기
charset = utf-8               # 파일 인코딩은 utf-8
insert_final_newline = true   # 파일 맨 마지막에 빈 줄 추가하기</code></pre><h1 id="패키지-설치--설정">패키지 설치 &amp; 설정</h1>
<h3 id="packagejson">package.json</h3>
<p>패키지 명령어 설정 파일
나만의 명령어 저장, 패키지 적용 범위 설정, 버전 정보 확인 등 가능</p>
<h3 id="prettier">prettier</h3>
<p><a href="https://prettier.io/docs/en/install">https://prettier.io/docs/en/install</a></p>
<p>간단히 써보면,</p>
<ol>
<li><p>패키지 설치 </p>
<pre><code>npm install --save-dev --save-exact prettier</code></pre></li>
<li><p><code>.prittierrrc.json</code> 생성</p>
</li>
<li><p><code>.prettierignore</code> 생성</p>
</li>
<li><p>기본 명령어로 실행</p>
<pre><code>npx prettier . --write</code></pre></li>
</ol>
<p>--write는 자동수정(포매팅)</p>
<ol start="5">
<li>체크
<img src="https://velog.velcdn.com/images/jiin-seok/post/10ebd6f2-2994-4c52-b21b-a754c55d6526/image.png" alt=""></li>
</ol>
<p>실행할 때 자동수정까지 되도록  추가
6. </p>
<h3 id="eslint">eslint</h3>
<p>내장
prettier와 충돌 피하는 방법
eslintrc.json (js 말고 json이 좋음)
eslintignore
eslint.config.mjs</p>
<h3 id="stylelint">stylelint</h3>
<p>stylelintrc.json</p>
<h3 id="husky">husky</h3>
<p>포매터, 린터 실행 강제</p>
<h1 id="스켈레톤">스켈레톤</h1>
<p>있어야 할 폴더들 - 폴더의 이해 
네이밍 규칙 예시</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hook과 함수는 무엇이 다를까]]></title>
            <link>https://velog.io/@jiin-seok/Hook%EA%B3%BC-%ED%95%A8%EC%88%98%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%BC%EA%B9%8C</link>
            <guid>https://velog.io/@jiin-seok/Hook%EA%B3%BC-%ED%95%A8%EC%88%98%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%BC%EA%B9%8C</guid>
            <pubDate>Thu, 30 May 2024 07:10:03 GMT</pubDate>
            <description><![CDATA[<p>Hook은 기본적으로 Javascript <strong>함수</strong>이다.</p>
<p>리액트에서 제공하는 useState, useEffect와 같은 기본 Hook과
직접 만드는 커스텀 Hook <strong>모두 함수</strong>로 정의된다.</p>
<p>Hook은 일반 함수와 같이 <code>useFunction()</code> 형태로 사용한다.</p>
<p>다만,</p>
<ol>
<li>함수 밖에서 사용할 수는 없다.</li>
<li>Hook을 사용한 함수는 곧 Custom Hook이 된다.</li>
<li>함수형 컴포넌트 역시 함수이므로, 내부에 Hook을 사용하면 컴포넌트인 동시에 Custom Hook이기도 하다. (use로 시작하는 네이밍 규칙은 이름만 보고도 함수의 성질을 알 수 있는 이름을 짓기 위함이고, Custom Hook의 기술적 조건은 아니다.)</li>
<li>하지만 컴포넌트는 꼭 이름이 대문자로 시작해야 하기 때문에, 네이밍 규칙을 따른 Custom Hook은 컴포넌트가 될 수 없다.</li>
</ol>
<pre><code class="language-js">function useUser(id) { // Custom Hook
  const [user, setUser] = useState(null);
  const login = (username, password) =&gt; {
    // ...
    if(로그인 성공) {
      setUser(userData);
  }
  const logout = () =&gt; {
    // ...
    setUser(null);
  }
  return [user, login, logout];
}

function Nav() { // 함수형 컴포넌트에서 일반 함수처럼 Custom Hook 사용
  const [user, login, logout] = useUser();
  // ...
}</code></pre>
<ul>
<li>useUser(id), setUser, Nav 모두 함수이다.</li>
<li>setUser는 리액트 Hook이다.</li>
<li>useUser는 커스텀 Hook이지만 컴포넌트는 아니다.</li>
<li>Nav는 컴포넌트이자 커스텀 Hook이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트에서 비동기로 상태값을 업데이트할 때 콜백함수를 써야 하는 이유]]></title>
            <link>https://velog.io/@jiin-seok/%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%97%90%EC%84%9C-%EB%B9%84%EB%8F%99%EA%B8%B0%EB%A1%9C-%EC%83%81%ED%83%9C%EA%B0%92%EC%9D%84-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8%ED%95%A0-%EB%95%8C-%EC%BD%9C%EB%B0%B1%ED%95%A8%EC%88%98%EB%A5%BC-%EC%8D%A8%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@jiin-seok/%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%97%90%EC%84%9C-%EB%B9%84%EB%8F%99%EA%B8%B0%EB%A1%9C-%EC%83%81%ED%83%9C%EA%B0%92%EC%9D%84-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8%ED%95%A0-%EB%95%8C-%EC%BD%9C%EB%B0%B1%ED%95%A8%EC%88%98%EB%A5%BC-%EC%8D%A8%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Wed, 29 May 2024 11:18:18 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jiin-seok/post/37969f57-a4d1-4e59-afa9-32954fe9f14d/image.png" alt=""></p>
<h2 id="리액트에서-비동기로-상태를-참조할-때-콜백함수를-써야-한다는-건-무슨-뜻일까">리액트에서 비동기로 상태를 참조할 때 콜백함수를 써야 한다는 건 무슨 뜻일까?</h2>
<h3 id="리액트에서-상태-값을-업데이트할-때-비동기-처리가-필요한-경우">리액트에서 상태 값을 업데이트할 때 비동기 처리가 필요한 경우</h3>
<p>예) setTimeout이나 <strong>API 요청</strong>과 같은 비동기 작업을 하고 나서 상태를 업데이트해야 할 때</p>
<pre><code class="language-jsx">setTimeout(() =&gt; {
  setCount(count + 1); 
}, 1000);</code></pre>
<p>위처럼 비동기 처리 직후에 상태를 업데이트하면 문제가 발생한다. </p>
<p><strong>비동기 처리 후의 값이 아닌 전의 값을 참조하여 의도치 않은 결과</strong>가 나올 수 있다.
<strong>리액트는 비동기 처리가 끝나기 전 이미 UI를 업데이트했을 수 있기 때문이다.</strong></p>
<ol>
<li>리액트는 상태 업데이트 함수 (예: setState)가 호출되면, 상태가 바뀌었다고 판단한다. (비동기 처리를 기다리지 않음)</li>
<li>리액트는 컴포넌트의 UI를 새로운 상태에 맞춰 업데이트한다. </li>
<li>비동기 처리 결과에 따라, 처리 후 나중에 실제 상태가 변경된다.</li>
</ol>
<p>즉 상태 업데이트 함수가 호출된 이후에 비동기 작업이 끝나는 경우
리액트는 이미 UI를 업데이트한 뒤이므로 비동기 처리 결과를 상태 업데이트에 반영할 수 없는 것이다.</p>
<p>비동기 처리 후 이를 반영해 상태를 업데이트하려면, <strong>비동기 처리 후의 값을 아규먼트로 받아 실행되는 콜백 함수 안에서</strong> 상태를 업데이트한다.</p>
<pre><code class="language-jsx">setTimeout(() =&gt; {
  setCount(prevCount =&gt; prevCount + 1);
}, 1000);</code></pre>
<p><code>prevCount =&gt; prevCount + 1</code>과 같이 <strong>함수 형태로 값을 업데이트</strong>하면 리액트가 의도대로 작동한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트 리액트 - 객체, 클래스, 인스턴스, ref, useRef, current]]></title>
            <link>https://velog.io/@jiin-seok/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EA%B0%9D%EC%B2%B4-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-ref-useRef-current</link>
            <guid>https://velog.io/@jiin-seok/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EA%B0%9D%EC%B2%B4-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-ref-useRef-current</guid>
            <pubDate>Mon, 27 May 2024 13:51:38 GMT</pubDate>
            <description><![CDATA[<h2 id="객체-object">객체 (Object)</h2>
<p>자바스크립트에서 다양한 타입의 데이터와 함수를 하나의 변수에 저장할 수 있는 데이터 타입.</p>
<pre><code class="language-js">const person = {
  name: &#39;John&#39;,
  age: 20,
  sayHello: function() {
    console.log(&#39;Hello!&#39;);
  } 
}</code></pre>
<p>key와 value의 집합체이다. 위와 같이 프로퍼티(name, age)와 메소드(sayHello)로 구성할 수 있다.</p>
<ul>
<li>키-값 쌍의 자료 구조</li>
<li>값으로 다양한 데이터 타입이 가능</li>
<li>메소드도 값으로 가질 수 있음</li>
<li>동적 추가와 삭제 가능</li>
</ul>
<p>자바스크립트에서 함수와 배열도 실제로는 객체이다.
객체는 복합적인 자료를 효과적으로 관리할 수 있어 프로그래밍에서 매우 중요하며, 객체 지향 프로그래밍 패러다임의 기초가 된다.</p>
<h2 id="객체-지향-프로그래밍oop">객체 지향 프로그래밍(OOP)</h2>
<p>프로그래밍 패러다임의 한 종류로, 실세계의 객체와 그 객체들 간의 관계를 프로그래밍하는 방식이다.</p>
<h3 id="객체-지향의-핵심-원리">객체 지향의 핵심 원리</h3>
<ul>
<li>추상화 - 현실 세계를 프로그램 설계에 반영</li>
<li>캡슐화 - 객체의 속성과 기능을 하나로 묶음</li>
<li>상속 - 다른 객체의 속성과 기능을 물려받을 수 있음</li>
<li>다형성 - 객체들이 같은 메시지에 대해 다르게 응답할 수 있음</li>
</ul>
<p>이를 바탕으로 객체간 유기적인 협력 관계를 구축한다.</p>
<h3 id="장점">장점</h3>
<ul>
<li>복잡한 문제를 객체 단위로 쪼개어 해결</li>
<li>코드 재사용성 증가</li>
<li>유지보수 용이</li>
</ul>
<h3 id="단점">단점</h3>
<p>설계의 중요성이 높고 배우기 어렵다는 단점도 있다.</p>
<p>대표적인 OOP 언어로는 자바, 파이썬, C++ 등이 있으며 자바스크립트도 프로토타입 기반의 객체지향을 지원한다.</p>
<h2 id="프로토타입">프로토타입</h2>
<p>객체지향 프로그래밍의 상속을 구현하는 방법 중 하나.
자바스크립트는 프로토타입 기반의 객체지향 언어로, 다른 객체의 프로퍼티와 메소드를 상속받을 수 있다.</p>
<pre><code class="language-js">// 프로토타입 객체 
const car = {
  wheels: 4,
  drive() {
    console.log(&quot;drive..&quot;);
  }
}

// car를 프로토타입으로 하는 객체  
const bmw = Object.create(car); 

bmw.drive(); // drive..
console.log(bmw.wheels); // 4</code></pre>
<p>여기서 bmw는 car 객체를 프로토타입으로 상속받았다.
car 객체의 프로퍼티와 메소드를 사용할 수 있다.
리액트에서도 컴포넌트의 프로토타입 체인을 통해 상속 기능을 제공한다.</p>
<h2 id="프로토타입-체인">프로토타입 체인</h2>
<p>자바스크립트에서 객체지향 상속을 구현하는 방법 중 하나.</p>
<p>자바스크립트의 모든 객체는 자신의 부모 역할을 하는 프로토타입 객체를 가리키고 있다. 그리고 부모 객체도 부모를 가리키고 있어, 이들이 프로토타입 체인을 형성하고 있다.</p>
<pre><code class="language-js">const parent = {
  name: &#39;Parent&#39;,
  printName() {
    console.log(this.name);
  }  
};

const child = Object.create(parent);
child.printName(); // &#39;Parent&#39;</code></pre>
<p>여기서 <code>child</code> 객체는 <code>parent</code> 객체를 프로토타입으로 상속받았다.
이때 <code>child</code> 객체에 <code>printName</code> 메서드가 없다면, 자바스크립트 엔진은 프로토타입 체인을 따라 올라가 <code>parent</code>의 <code>printName</code>을 찾아서 사용한다.
즉, 연쇄적으로 프로토타입 객체들을 탐색한다는 의미이다.</p>
<h2 id="클래스">클래스</h2>
<p>클래스는 객체 지향 프로그래밍의 한 원리인데, 객체들의 분류와 <strong>설계도</strong>이다. 자바스크립트 ES6 문법을 통해 도입되었다.
클래스를 사용하면, 객체 인스턴스(즉, 클래스로 정의한 객체)를 생성하고, 공통된 특성과 기능을 구현할 수 있다.</p>
<pre><code class="language-js">class Cat {
  constructor(name) {
    this.name = name;
  }

  meow() {
    console.log(`${this.name}야 옹옹!`);
  }
}

const myCat = new Cat(&quot;나비&quot;);
myCat.meow();// 나비야 옹옹!</code></pre>
<p>이렇게 <code>Cat</code> 클래스로부터 나비라는 <code>Cat</code> 인스턴스를 생성하고 기능을 사용할 수 있다.
리액트에서는 컴포넌트를 클래스 형태로 정의할 수 있다.</p>
<pre><code class="language-js">class MyComponent extends React.Component {
  render() {
    return &lt;div&gt;Hello&lt;/div&gt;;
  }
}</code></pre>
<p>컴포넌트를 클래스로 정의하면 해당 컴포넌트 자체가 인스턴스가 되고 메소드 및 상태를 가질 수 있게 된다.</p>
<h2 id="인스턴스">인스턴스</h2>
<p>리액트에서 해당 컴포넌트를 가리킨다.
리액트 컴포넌트를 클래스 형태로 정의하면 이 컴포넌트 자체가 하나의 인스턴스이다.</p>
<pre><code class="language-jsx">class MyComponent extends React.Component {
  render() {
    return &lt;div&gt;Hello&lt;/div&gt;;
  }
}

const myComponent = new MyComponent();</code></pre>
<p>여기서 <code>myComponent</code>가 바로 <code>MyComponent</code>의 인스턴스이다.
클래스 컴포넌트 내부에서는 this 키워드를 통해 자신의 인스턴스에 접근할 수 있다.</p>
<pre><code class="language-js">this.state// 인스턴스의 state
this.props// 인스턴스의 props</code></pre>
<p>함수 컴포넌트의 경우 별도의 인스턴스 개념이 없지만,
ref를 통해 해당 컴포넌트 자체를 참조할 수 있다.</p>
<pre><code class="language-jsx">const myComponent = useRef(null);

&lt;MyComponent ref={myComponent}/&gt;</code></pre>
<p>여기서 <code>myComponent.current</code>가 바로 이 함수형 컴포넌트의 인스턴스가 된다.</p>
<h2 id="ref">ref</h2>
<p>특정 DOM 노드나 리액트 컴포넌트 인스턴스에 대한 참조(reference)를 만들어주는 것.</p>
<pre><code class="language-js">const myElement = useRef(null);

&lt;div ref={myElement}&gt;
  Hello!
&lt;/div&gt;</code></pre>
<p>여기서 <code>myElement</code>는 해당 div 엘리먼트의 참조가 저장되어 있다.
<code>myElement.current</code>를 통해 이 div 엘리먼트에 직접적으로 접근할 수 있다.</p>
<p>ref의 주요 사용처</p>
<ul>
<li>특정 DOM에 직접 접근해야 할 때 (스크롤, 포커스 등)</li>
<li>컴포넌트 내부에서 특정 자식 컴포넌트에 접근할 때</li>
<li>컴포넌트와 관련된 값을 저장할 때</li>
</ul>
<p>이처럼 DOM이나 컴포넌트 접근 시 reference로 사용된다.</p>
<h2 id="useref">useRef</h2>
<p>리액트 훅(Hook) 중 하나로, 함수형 컴포넌트에서 ref를 쉽게 사용할 수 있도록 해준다.</p>
<pre><code class="language-jsx">const ref = useRef(initialValue);</code></pre>
<p><code>useRef</code>가 하는 일</p>
<ul>
<li><p>DOM의 참조 - 특정 DOM에 대한 참조(reference)를 만들어준다.
예를 들어 특정 엘리먼트에 focus를 주고 싶은 경우, 이 엘리먼트를 참조할 수 있도록 useRef를 사용한다.</p>
<pre><code class="language-jsx">const inputEl = useRef(null);

&lt;input ref={inputEl} /&gt;

inputEl.current.focus();</code></pre>
</li>
<li><p>렌더링 비참조 값의 유지 - 렌더링과 관계 없이 바뀔 수 있는 값을 관리한다.
<code>useRef</code>로 관리하는 값은 렌더링에 영향을 주지 않으면서 컴포넌트의 생명주기를 벗어나지 않고 유지할 수 있다.
이를 활용하여 이전 값을 저장하는 용도 등으로 사용할 수 있다.</p>
<pre><code class="language-jsx">const id = useRef(1);
id.current++; // 렌더링과 무관하게 current 값 1 증가 (값 유지 및 변경 가능)</code></pre>
</li>
</ul>
<h2 id="current-프로퍼티">current 프로퍼티</h2>
<p><code>useRef</code>가 반환하는 객체가 기본적으로 가지고 있는 특별한 프로퍼티</p>
<pre><code class="language-js">const id = useRef(1); 

return &lt;div&gt;ID: {id.current}&lt;/div&gt; </code></pre>
<p>이때 <code>id.current</code>를 통해 현재 가리키고 있는 값에 접근할 수 있다.
이 값은 컴포넌트의 리렌더링에 영향을 받지 않기 때문에, 부수 효과 없이 변수를 관리할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[구글 폰트에서 Variable 폰트에 굵기 font-weight 적용하기]]></title>
            <link>https://velog.io/@jiin-seok/%EA%B5%AC%EA%B8%80-%ED%8F%B0%ED%8A%B8%EC%97%90%EC%84%9C-Variable-%ED%8F%B0%ED%8A%B8%EC%97%90-font-weight-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jiin-seok/%EA%B5%AC%EA%B8%80-%ED%8F%B0%ED%8A%B8%EC%97%90%EC%84%9C-Variable-%ED%8F%B0%ED%8A%B8%EC%97%90-font-weight-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 07 May 2024 08:13:07 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>구글 폰트를 적용할 때, Variable 폰트에 어떻게 굵기 400, 700을 적용해야 할까?</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/a07d4c6e-2235-47ef-9b10-b8434bf3b91d/image.png" alt="">
구글 폰트를 가져와서 폰트마다 두 가지 굵기를 적용하는 실습이다.</p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/ec9c97a8-4e4e-40eb-b83a-0d489c0e2914/image.png" alt="">
여러 폰트 중 실습 문제에 나온 Noto Sans Korean은 1 axis짜리 Variable 폰트이다.</p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/b71bc4ff-5b06-4b7e-aa37-dca08f43aee3/image.png" alt="">
Get Font를 누른다.</p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/1b46838b-e5a0-42c8-8792-e8d32bfea8ff/image.png" alt="">
Get embed code를 눌러 코드를 얻는다.</p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/0814c78d-5cb9-438e-bd14-7df0151ced32/image.png" alt=""></p>
<pre><code>&lt;head&gt;
  &lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.googleapis.com&quot;&gt;
  &lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.gstatic.com&quot; crossorigin&gt;
  &lt;link href=&quot;https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&amp;family=Poppins:wght@400;600&amp;display=swap&quot; rel=&quot;stylesheet&quot;&gt;
&lt;/head&gt;</code></pre><p>첫 번째 옵션처럼 HTML &lt;head&gt; 태그 내에 삽입한다.</p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/72d27fb9-2a21-4b75-9d9d-0fb5f873be62/image.png" alt="">
Poppins 글꼴은 예시 이미지처럼 h1 태그가 굵게 표시되었지만,
Noto Sans Korean 글꼴은 예시 이미지와 다르게 h2 태그가 굵게 표시되지 않는다.</p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/51badec0-81a6-4146-b568-029c11267a5f/image.png" alt="">
Poppins 글꼴과 Noto Sans Korean 글꼴의 차이점은 코드에 있다.</p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/131d0f7a-88dd-4d30-908e-c1956b643466/image.png" alt="">
Poppins는 굵기별 폰트를 토글로 선택할 수 있어서 실습 문제에 나온 400, 600을 선택했다.
Noto Sans Korean은 Full axis 또는 One value로만 폰트 굵기를 선택할 수 있었고, Full axis의 경우 임베드 코드가 이렇게 생성되었다.
<img src="https://velog.velcdn.com/images/jiin-seok/post/51badec0-81a6-4146-b568-029c11267a5f/image.png" alt=""></p>
<pre><code>family=Noto+Sans+KR:wght@100..900</code></pre><p>Static 굵기인 Poppins처럼 코드를 바꿔준다.</p>
<pre><code>family=Noto+Sans+KR:wght@400;700</code></pre><p><img src="https://velog.velcdn.com/images/jiin-seok/post/0794fe99-026a-4007-b706-5c087e2dbd5e/image.png" alt="">
Noto Sans Korean이 적용된 한국어 문장도 h2 태그가 무사히 Bold 처리 되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[QA 커뮤니케이션]]></title>
            <link>https://velog.io/@jiin-seok/QA-%EC%BB%A4%EB%AE%A4%EB%8B%88%EC%BC%80%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@jiin-seok/QA-%EC%BB%A4%EB%AE%A4%EB%8B%88%EC%BC%80%EC%9D%B4%EC%85%98</guid>
            <pubDate>Fri, 26 Apr 2024 04:45:20 GMT</pubDate>
            <description><![CDATA[<p>모든 IT 조직엔 &#39;일명 QA&#39; 업무가 있지만, 그것이 말뜻대로의 QA는 아니다. 테스터의 경험과 직관에 기반한 무작위 테스트에 의존하는 경우도 상당하고, 조직 구성상 PM/기획자가 겸업하기도 한다.</p>
<p><em><strong>이런 상황에 놓인 &#39;일명 QA&#39;가 자신의 정체성을 지키는 가장 중요한 도구는 기술적 커뮤니케이션이다.</strong></em></p>
<p>코딩을 하지 않더라도, API 문서를 읽고 이해하는 것만으로도 전문 테스터 나아가 QA는 겸업 테스터와 구별될 수 있다.</p>
<ol>
<li><p><strong>버그의 속성과 담당자</strong>를 알 수 있다.</p>
<p><em>&#39;아 그건 백에서 해줘야 해요.&#39;</em>
라는 말을 듣지 않게 된다. 정말 단순하게 이 메시지를 어디서 띄우는지만 매번 정확히 알고 있어도 개발자는 테스터를 소통 가능한 존재로 느끼게 될 것이고, 버그 리포트는 신뢰성을 가지게 된다. (QA는 양치기 소년이 되어선 안 된다.)</p>
</li>
<li><p>코드 리뷰는 하지 않아도 <strong>&#39;API 명세 리뷰&#39;는 할 수 있다.</strong></p>
<p>QA라면 기획안을 리뷰해야 한다. 여기까지는 기획자의 테스트와 유사하다.</p>
<p>또 할 수 있는 것이 API 문서 리뷰이다. 사람이 하는 일이기 때문에 &#39;누락 결함&#39;이 있다.
예를 들면 스웨거를 보고 필수값 여부를 알 수 있다. 기획안에서는 조회 필수값이었는데 조회하는 API에서는 필수 파라미터가 아니라면 누락 결함이다. UI가 모두 개발된 뒤에 하나씩 경우를 달리해 눌러보며 필수값 적용 여부를 아는 것보다 API 문서를 읽고 판단하는 것이 빠르고 정확하다. &#39;프론트엔드 테스트를 위한 준비 과정&#39;이기도 하다. 이 과정을 거치고 나면 이후는 대개 프론트엔드 문제이므로.</p>
<p>API 호출과 작성된 오류 메시지 확인도 가능하다. 특히 GET의 경우는 API 테스트 도구 안에서 과정이 끝나기 때문에(프론트엔드 개발 전일 경우) 간략하다. 오류 메시지는 QA의 중요한 대상 중 하나이다. 개발자는 오류 메시지가 고객에게 직접 노출된다는 점을 간과할 수 있다. 어떤 메시지든 고객이 볼 수 있다고 전제하고 &#39;지금 무슨 상황이며, 나는 무엇을 해야 하는지&#39; 알려주는 메시지여야 한다. 오류를 만들어서 직접 불러오지 않고도 작성된 것을 읽고 리뷰할 수 있다니 얼마나 좋은가?</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[mySQL 쿼리로 만든 그리드와, 개발된 그리드 비교하여 데이터 출력 테스트]]></title>
            <link>https://velog.io/@jiin-seok/mySQL-%EC%BF%BC%EB%A6%AC%EB%A1%9C-%EB%A7%8C%EB%93%A0-%EA%B7%B8%EB%A6%AC%EB%93%9C%EC%99%80-%EA%B0%9C%EB%B0%9C%EB%90%9C-%EA%B7%B8%EB%A6%AC%EB%93%9C-%EB%B9%84%EA%B5%90%ED%95%98%EC%97%AC-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B6%9C%EB%A0%A5-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@jiin-seok/mySQL-%EC%BF%BC%EB%A6%AC%EB%A1%9C-%EB%A7%8C%EB%93%A0-%EA%B7%B8%EB%A6%AC%EB%93%9C%EC%99%80-%EA%B0%9C%EB%B0%9C%EB%90%9C-%EA%B7%B8%EB%A6%AC%EB%93%9C-%EB%B9%84%EA%B5%90%ED%95%98%EC%97%AC-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B6%9C%EB%A0%A5-%ED%85%8C%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Mon, 31 Jul 2023 12:35:51 GMT</pubDate>
            <description><![CDATA[<p>내가 QA하는 제품은 업무 시스템으로, 데이터 그리드가 페이지 UI의 대부분을 차지하는 경우가 많다.</p>
<p>따라서 테스트할 때 AQueryTool을 자주 활용하는데, 어느 날 그런 생각이 들었다. 
&#39;이거 최종 결과물이랑 똑같이 DB에서 추출해서 둘을 비교할 수는 <del>없나?</del> <em><strong>아니 있지!</strong></em> 💡&#39;</p>
<p>나는 고객사에 &#39;실사용 Raw Data&#39; 추출을 지원하며 SQL이 뭔지 체감하게 되었던 것이다.
이번엔 내가 그걸 직접 해보기로 했다.</p>
<p>신규 개발하는 페이지의 UI 기획안이 나오고, 그 순서대로 쿼리를 짰다. 일단 그걸 짜기 위해 파라미터명은 다 찾아놔야 했고, 특정 날짜 등 몇 가지 조건으로 <strong>테스트페이지에 만들어진 그리드와 Worbench Result Grid를 일치시킬 수 있었다.</strong> </p>
<p>일치하지 않는 몇몇 값을 자세히 보기 위해 F12 &gt; 네트워크를 찍어 보니 아예 해당 값이 페이지 조회 시 오지 않는다는 걸 알게 되었다. </p>
<p>또는 <strong>조회 결과</strong>가 너무 달라서 재확인해 보니, 오해가 있어 기획과 다르게 <strong>조회 API</strong>가 (and를 or로 만드는 등) 만들어져 있었다.</p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/14b0ef42-4174-47fe-a379-2d10b3bd0b1e/image.png" alt=""></p>
<p>아직 능숙하진 않지만, <em>들여다 보면서도 확인하기 어려웠던 데이터를 직접 DB에서 뽑아 봄으로써 QA의 완성도를 높일 수 있었다.</em></p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/052f4e5c-3fa2-472c-9a5a-4dff4eae5b78/image.png" alt=""></p>
<p><em>이런 것도 실수하며 뚝딱거렸지만 포기하지 않았다!</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Asana Workflow를 이용한 Bug Report 반자동화]]></title>
            <link>https://velog.io/@jiin-seok/Asana-Workflow%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Bug-Report-%EB%B0%98%EC%9E%90%EB%8F%99%ED%99%94</link>
            <guid>https://velog.io/@jiin-seok/Asana-Workflow%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Bug-Report-%EB%B0%98%EC%9E%90%EB%8F%99%ED%99%94</guid>
            <pubDate>Mon, 31 Jul 2023 12:00:02 GMT</pubDate>
            <description><![CDATA[<p>리포트는 <strong>데이터 고유번호</strong>를 제목으로 하고, <strong>생성일, 버그확인결과, 이슈분류, 증상, 원인</strong> 총 5개 칼럼을 덧붙였다. 워크플로우로 Slack에 연동함으로써 <em>Asana 프로젝트를 버그 트래커로 활용했다.</em></p>
<p>예) 123 / 2023.07.31. / 수정배포 / 엣지케이스 / 고유 데이터 중복 생성 / 더블클릭 방지하지 않아 같은 요청을 여러 번 보냄</p>
<p>QA가 이슈 작성 
➡️ 백엔드, 프론트엔드로 분류(Opend) 
➡️ Slack 버그 채널에서 각 담당자 멘션 
➡️ 개발자는 링크 타고 들어와 Asana에서 버그확인결과 작성 
➡️ 이슈는 답변완료로 이동(Resolved) 
➡️ QA가 직접 체크하여 &#39;배포 후 확인&#39;으로 이동(Closed)</p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/6b597261-e043-4b33-9560-542c5f029263/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiin-seok/post/13264190-b791-450e-a7d6-9d86d6866708/image.png" alt=""></p>
<p><em>현재는 우리회사가 Asana를 사용하지 않기에 자세한 내용과 워크플로우 설정을 조회할 수 없다.</em></p>
<p>이렇게 이슈를 증상과 원인까지 모아 봄으로써 개발자와 QA가 근래의 다발 이슈를 쉽게 확인하고, 수정배포 시 집중 점검의 대상으로 삼을 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2nd QA Korea Conference 후기]]></title>
            <link>https://velog.io/@jiin-seok/2nd-QA-Korea-Conference-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@jiin-seok/2nd-QA-Korea-Conference-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Mon, 31 Jul 2023 11:58:09 GMT</pubDate>
            <description><![CDATA[<p>2023.07.29~30. 이번 주말 2일간 열리는 QA 컨퍼런스에 참석했다. </p>
<p>혼자 근무해온 내게는 소중한 경험이 될 것 같아서, 컨퍼런스의 존재를 알게 되고 곧장 참가 신청했다. </p>
<p>컨퍼런스는 세션 구성이 주니어부터 시니어까지, 스타트업부터 대기업, 외국계까지, 그리고 무엇보다 연사분들이 다루고 이야기하는 테스트의 종류까지 (게임테스트, UI테스트, API테스트, 매뉴얼테스트, 테스트프로세스, 전력소모량성능테스트, 디바이스팜 구축기...!) 너무나 다양해서 더욱 알찬 시간이었다. 유료 행사여서 자료를 추후 공유해주신다고 하는데 진심으로 기대 중이다.</p>
<p>공감되는 이야기를 들을 때마다 이랬다. <em>&#39;나도 똑같은 생각을 했는데! 이상한 일이 아니었구나! <strong>그냥 해결하면 되는 거군!</strong>&#39;</em></p>
<ol>
<li><p><strong>무작위 테스트를 수행하다 QA기간 막바지에 중대한 엣지 케이스를 발견해 배포 일정을 연기</strong>했다.
나도 무작위 테스트를 장려하는 회사에서 일을 배웠지만 <em>엣지 케이스로 배포가 거듭 연기되는 것을 보고 테스트케이스를 작성했다.</em> 매번 작성하기는 쉽지 않았지만 체크리스트 형태로 간략히 대체하거나, 이미 수행한 테스트를 버그가 없었더라도 기록하여 다른 테스터가 &#39;무엇을 이미 테스트했는지&#39;을 알 수 있게 하는 등 다양한 노력을 해왔다.</p>
</li>
<li><p><strong>버그 1건도 노트북을 들고 가 대면 전달</strong> 했다.
같은 일을 할 거면 집중해서 산출물을 내는 게 조직에 유익하다고 생각한다. 내가 대면 소통을 하는 건 &#39;이미 적어 보낸 것을 함께 보면서 이야기&#39;하기 위해서다. <strong>내가 3분동안 적으면 무제한의 독자가 두고두고 10초에 이해한다</strong>. 하지만 내가 3분을 쓰기 싫어하면 둘이 모여 2번 이야기하고도 기억이 안 나서, 말하고 적어 일을 2번 하기도 한다. 테스트 기록은 버그 추적 및 회귀 테스트를 위한 자원이기에 남기지 않으면 안 된다.</p>
</li>
<li><p><strong>테스트 환경의 잦은 변동으로 테스트를 중단시키는 에러(500)가 빈번히 발생</strong>해 API 테스트를 자동화했다.
철저히 분리된 QA서버에서 코드 프리즈 하지 않기에 나 또한 자주 겪은 상황이었다. 주요 API 테스트를 자동화하여서 수시로 수행했다면 고객 불만을 확연히 줄일 수 있지 않았을까 테스트 자동화에 가진 늦은 관심이 아쉽기도 했다. </p>
</li>
</ol>
<p>배터리를 분해해 전력소모량으로 성능 테스트 하는 시니어 QA, 사내 데이터 조직과 협업하여 QA 이슈를 데이터 분석으로 선별하고, QA 성과를 데이터 대시보드로 표현한 게임 QA, 디바이스 팜을 전문적으로 구성한 테스트 대행 스타트업 등 공감보다는 존경에 가까운 업무 경험도 있었다.</p>
]]></description>
        </item>
    </channel>
</rss>