<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Geon's 블로그</title>
        <link>https://velog.io/</link>
        <description>사회 공헌적인 Data Engineer를 꿈꾸는 이건입니다.</description>
        <lastBuildDate>Sat, 11 Jan 2025 09:53:41 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Geon's 블로그</title>
            <url>https://velog.velcdn.com/images/geon-2/profile/142ef651-876c-4ae7-ac97-db21e46731ec/image.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Geon's 블로그. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/geon-2" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Spring] @ResponseBody의 역할]]></title>
            <link>https://velog.io/@geon-2/Spring-ResponseBody%EC%9D%98-%EC%97%AD%ED%95%A0</link>
            <guid>https://velog.io/@geon-2/Spring-ResponseBody%EC%9D%98-%EC%97%AD%ED%95%A0</guid>
            <pubDate>Sat, 11 Jan 2025 09:53:41 GMT</pubDate>
            <description><![CDATA[<p>스프링에서 api 통신 구현을 위해 @ResponseBody이라는 Annotation을 사용하는데, 정확하게 어떤 역할을 하는 것일까?</p>
<details>
  <summary><strong>Annotation의 정의</strong></summary>
  <div markdown="1">
  해석하면 '주석'이지만, spring에서의 annotation은 우리가 아는 '주석'에 더해 더 많은걸 지원해준다.
'@'가 prefix로 붙어서 정의되어 있으며, 객체나 메소드에 더 많은 의미와 기능을 추가해주는 기술이다.

<ul>
<li>컴파일러에게 코드 작성 문법 에러를 체크하도록 정보를 제공</li>
<li>소프트웨어 개발 툴이 빌드나 배치시 코드를 자동으로 생성할 수 있도록 정보를 제공</li>
<li>실행시(런타임시) 특정 기능을 실행하도록 정보를 제공</li>
</ul>
<p><a href="https://velog.io/@rara_kim/Spring-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98Annotation">참고: [Spring] 어노테이션(Annotation)</a></p>
</div>
</details>

<h2 id="responsebody">@ResponseBody</h2>
<p>@ResponseBody를 명시하면 api 통신을 위해 MessageConverter에 데이터가 전송된다. 정확하게 알아보기 위해 명시하지 않았을 때와 비교해보자.</p>
<h3 id="viewresolver">viewResolver</h3>
<p>명시하지 않았을 때는 아래처럼 Controller가 리턴 값을 반환했을 때 viewResolver가 받아 처리한다.
<img src="https://velog.velcdn.com/images/geon-2/post/283df36e-b04c-4ae2-82d4-82bf27283ad9/image.png" alt="">
viewResolver는 클라이언트에게 반환해줄 View를 결정하는 역할을 한다.</p>
<ol>
<li>Controller가 뷰 이름(예: &quot;home&quot;)을 반환</li>
<li>ViewResolver는 설정에 따라 해당 뷰 이름을 물리적 뷰 경로(예: /WEB-INF/views/home.jsp)로 매핑</li>
<li>매핑된 물리적 경로를 기반으로 View 객체를 생성</li>
<li>생성된 View 객체는 클라이언트에게 적절한 HTML이나 템플릿을 렌더링</li>
</ol>
<p>viewResolver는 View를 반환하기 때문에 MVC를 사용하는 템플릿 기반 웹 어플리케이션을 구현할 때 사용된다.</p>
<h3 id="httpmessageconverter">HttpMessageConverter</h3>
<p>명시할 때는 아래처럼 HttpMessageConverter가 리턴 값을 받는다.
<img src="https://velog.velcdn.com/images/geon-2/post/01b6ea34-ae6a-4340-b6a5-2858a694969c/image.png" alt="">
HttpMessageConverter는 이름에서 알 수 있듯이 Http 통신 간의 메시지를 변환해주는 역할을 한다.</p>
<ol>
<li>컨트롤러가 반환하는 객체(예: List<User>)를 HTTP 응답 메시지(예: JSON, String)로 변환</li>
<li>클라이언트로부터 들어온 HTTP 요청 데이터를 Java 객체로 변환</li>
<li>변환 작업은 Content-Type과 Accept 헤더를 기반으로 수행</li>
</ol>
<p>역할에서 알 수 있듯이 데이터 교환이 주 목적으로, api 기반 서비스 구현에 사용된다.</p>
<blockquote>
</blockquote>
<h3 id="reference">Reference</h3>
<p><a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8">스프링 입문 - 김영한</a></p>
<blockquote>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flux 패턴 (before Redux)]]></title>
            <link>https://velog.io/@geon-2/Flux-%ED%8C%A8%ED%84%B4-before-Redux</link>
            <guid>https://velog.io/@geon-2/Flux-%ED%8C%A8%ED%84%B4-before-Redux</guid>
            <pubDate>Sun, 07 Jul 2024 13:04:29 GMT</pubDate>
            <description><![CDATA[<p>제목에서 언급하였듯이 Redux를 공부하기 전에 알아두어야 할 개념이다. 그 이유는 Redux와 Flux의 관계가 다음과 같기 때문이다.</p>
<blockquote>
<p><strong>“Redux implements Flux”</strong></p>
</blockquote>
<p>Redux가 Flux라는 디자인 패턴을 실제로 구현한 구현체라는 것이다.</p>
<p>그래서 Flux 패턴을 공부하는 것이 추후 Redux를 빠르게 이해하는데 용이할 것이다.</p>
<h1 id="flux">Flux</h1>
<p><strong><code>Flux</code></strong>란 Meta에서 클라이언트 사이드 웹 어플리케이션을 위해 고안한 아키텍쳐이다.</p>
<p>Flux의 공식 Github 레포지토리에서는 <code>Flux</code>를 다음과 같이 정의하고 있다.</p>
<blockquote>
<p><em>An application architecture for React utilizing a unidirectional data flow.</em></p>
</blockquote>
<p>출처: <a href="https://github.com/facebookarchive/flux?tab=readme-ov-file">https://github.com/facebookarchive/flux?tab=readme-ov-file</a></p>
<blockquote>
</blockquote>
<p>해석하면, ‘<strong>*단방향 데이터 흐름</strong>을 활용한 React용 어플리케이션 <strong>아키텍쳐*’</strong>이다.</p>
<p>여기서 제일 중요한 부분은 ‘단방향 데이터 흐름’이라는 키워드이다. </p>
<p>왜냐하면 당시의 Facebook이 <code>MVC</code>의 단점이라고 판단한 <strong>양방향 데이터 흐름</strong>을 해결하기 위해 <code>Flux</code>를 고안한 것이기 때문이다.</p>
<h2 id="mvc란">MVC란?</h2>
<p><code>MVC</code>란 <strong>Model-View-Controller</strong>의 약자로 데이터 및 논리 제어를 구현하기 위한 디자인 패턴이다.</p>
<p>MVC의 구조는 다음과 같다.</p>
<ul>
<li>Model: 데이터와 비즈니스 로직을 관리한다.</li>
<li>View: 레이아웃과 화면을 처리한다.</li>
<li>Controller: Model과 View로 명령을 전달한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/geon-2/post/e7296745-6583-46e5-ae0b-cb94e076aa99/image.png" alt=""></p>
<p><code>Controller</code>가 요청한 Data를 <code>Model</code>이 DB에서 불러와 요청에 응답하면, <code>Controller</code>가 해당 데이터를 <code>View</code>에 전송에 보여주는 형태이다. </p>
<p>중요한 것은 요청과 응답이 발생하여 데이터가 업데이트되면 <code>View</code>와 <code>Model</code>이 업데이트된다. 즉, <code>View</code>가 <code>Model</code>을 업데이트할 수도 있고, <code>Model</code>이 <code>View</code>를 업데이트할 수도 있다. 이를 다른 말로 <strong>양방향 데이터 흐름</strong>이라고 한다.</p>
<h3 id="mvc의-문제점">MVC의 문제점</h3>
<p>Facebook이 단점으로 생각한 양방향 데이터 흐름이 문제가 되는 이유는 복잡도가 증가될 때 있다.</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/edf15b0e-3d39-4b7f-bb0f-520b21c91256/image.png" alt=""></p>
<p>위 사진이 <code>MVC</code>의 문제점을 직관적으로 보여주고 있다.</p>
<p>양방향 데이터 흐름의 단점은 다음과 같다.</p>
<ul>
<li>복잡도가 높아질 수록 업데이트 비용도 높아짐</li>
<li>복잡도가 높아질 수록 버그의 추적이 어려워 예측하기 어려운 코드가 됨</li>
</ul>
<p>이러한 문제가 생기는 결정적인 이유는 요소 간의 의존도가 높기 때문이다. 위 사진과 같이 <code>View</code>와 <code>Model</code>은 상호의존적이기 때문에 한 요소의 복잡도가 올라가면 다른 요소의 복잡도도 올라간다. 그래서 어플리케이션이 복잡해지면 복잡해질수록 <code>MVC</code>의 구조가 무의미해진다.</p>
<p><code>FE</code>(Front-end)에서 <code>MVC</code>를 적용하기 힘든 가장 큰 이유는 <code>View</code>가 메인이 되기 때문이다. <code>MVC</code>에서 <code>View</code>는 단순하게 요청한 데이터를 보여주는 결과에 불과하지만, <code>FE</code>에서는 <code>View</code>에서 발생하는 이벤트를 통제하는 것이 메인이기 때문에 <code>MVC</code>의 목적과는 모순된다. 그래서 실제로 <code>FE</code>에서 <code>MVC</code>를 구현해보면 <code>View</code>와 <code>Model</code>의 갯수가 증가함에 따라 <code>Controller</code>의 규모가 무지막지하게 커진다. </p>
<h2 id="flux의-구조">Flux의 구조</h2>
<p><img src="https://velog.velcdn.com/images/geon-2/post/75876445-4674-4275-bcba-495a57812aa8/image.png" alt=""></p>
<p><code>Flux</code>는 <code>MVC</code>의 단점을 해결해기 위해 <strong>단방향 데이터 흐름</strong>으로 설계되었다.</p>
<ul>
<li><p><code>Action</code>: 상태 변경 요청을 담은 JS 객체</p>
<pre><code class="language-jsx">  {
      type: &#39;새로운 메시지 도착&#39;,
      payload: {
          id: ...,
          message: &#39;오늘 점심 메뉴 뭐 먹을까?&#39;,
          threadId: ...,        
      }
  }</code></pre>
<ul>
<li><code>type</code>: 액션 이름</li>
<li><code>payload</code>: 데이터</li>
</ul>
</li>
<li><p><code>Dispatcher</code>: 모든 데이터 변경 요청이 경유하는 중앙 허브</p>
<ul>
<li><code>View</code>로부터 <code>Action</code>을 받아 모든 <code>Store</code>들에게 전송</li>
<li>내부에 상태 변경 로직이 존재하지 않음</li>
<li><code>Store</code> 간 의존성 관리<ul>
<li><code>Store</code> A의 상태 변경 순서를 <code>Store</code> B 다음으로 미룰 수 있음</li>
</ul>
</li>
</ul>
</li>
<li><p><code>Store</code>: 어플리케이션 상태 및 로직 컨테이너</p>
<ul>
<li><code>Dispatcher</code>에서 전달된 <code>Action</code>을 통해서만 상태 변경</li>
<li>상태가 변경되면 <code>View</code>에게 통지</li>
</ul>
</li>
<li><p><code>View</code>: 상태에 따라 화면을 출력</p>
<ul>
<li>Controller-View (React)<ul>
<li><code>View</code>와 <code>Controller</code>의 역할을 동시에 함</li>
<li><code>Store</code>가 통지하는 상태 변경을 수신 받은 상태에 따라 <code>View</code>를 새로 렌더링</li>
</ul>
</li>
<li>Dispatcher에게 <code>Action</code> 전달</li>
</ul>
</li>
</ul>
<h3 id="flux의-장점">Flux의 장점</h3>
<ul>
<li>단방향 데이터 흐름으로 구성하여 복잡성을 해결하였음</li>
<li>컴포넌트 간의 의존성을 줄여서 유지보수가 용이함</li>
<li>그로 인해 예측 가능성이 높아져 대규모 프로젝트에도 적합함</li>
</ul>
<hr>
<h2 id="reference">Reference</h2>
<blockquote>
<p>Meta Archive, flux, <a href="https://github.com/facebookarchive/flux?tab=readme-ov-file">https://github.com/facebookarchive/flux?tab=readme-ov-file</a>
Facebook, Flux, <a href="https://haruair.github.io/flux/">https://haruair.github.io/flux/</a>
mdn web docs, MVC, <a href="https://developer.mozilla.org/ko/docs/Glossary/MVC">https://developer.mozilla.org/ko/docs/Glossary/MVC</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[JWT]]></title>
            <link>https://velog.io/@geon-2/JWT</link>
            <guid>https://velog.io/@geon-2/JWT</guid>
            <pubDate>Wed, 03 Jul 2024 13:47:55 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/geon-2/post/014e9773-1573-41a3-bdda-561c1fd5c8ef/image.png" alt=""></p>
<h1 id="jwt">JWT</h1>
<p><strong><code>JWT</code></strong>는 <strong>JSON Web Token</strong>의 약자로 Web 환경에서의 안전한 정보 전송을 위한 개방형 표준으로 JSON 객체 형태로 정의된다. </p>
<p>개발자가 정의한 JWT가 사용되는 경우는 다음과 같다.</p>
<ul>
<li>권한 부여<ul>
<li>가장 일반적인 경우로 사용자가 로그인할 때 권한을 부여하는 목적으로 사용된다.</li>
<li>로그인 이후 각 요청에 JWT가 포함되어 해당 토큰으로 허용된 경로, 서비스 및 리소스에 접근할 수 있다.</li>
</ul>
</li>
<li>정보 교환<ul>
<li>JWT는 당사자 간에 안전한 정보 전달을 위해서도 사용된다.</li>
<li>JWT는 서명된 키로 사용되기 때문에 사용자 인증에 용이하다.</li>
<li>Header와 Payload를 사용하여 변조 여부도 확인 가능하다.</li>
</ul>
</li>
</ul>
<h2 id="cookie-vs-sessioncookie-vs-jwt">Cookie vs Session/Cookie vs JWT</h2>
<p><code>JWT</code> 는 특히 사용자 인증 기능에 가장 많이 사용된다. 그래서 가장 많이 사용되는 인증 방식들을 한번 비교 해보았다.</p>
<h3 id="cookie">Cookie</h3>
<ul>
<li>장점<ul>
<li>인증 테스트를 할 경우 및 간단한 앱을 만들때 빠르게 설계할 수 있음</li>
</ul>
</li>
<li>단점<ul>
<li>보안에 매우 취약하여 해킹을 당하는 일이 빈번함</li>
<li>용량 제한이 있어 많은 정보를 담을 수 없다. (용량이 커질수록 네트워크 부하가 심해져 성능 저하 문제가 발생할 수 있음)</li>
</ul>
</li>
</ul>
<h3 id="sessioncookie">Session/Cookie</h3>
<ul>
<li>장점<ul>
<li>매개가 되는 <code>Cookie</code>는 유의미한 값을 갖지 않음<ul>
<li><code>Cookie</code>는 <strong>Session Storage</strong>에서 가져온 <strong>Session ID</strong>를 담는 역할</li>
<li>따라서, 계정정보를 담아 인증을 거치는 것보다 안전함</li>
</ul>
</li>
<li>각 사용자마다 고유한 <strong>Session ID</strong>가 발급되기 때문에 요청이 들어올 때마다 회원정보를 확인할 필요가 없음</li>
</ul>
</li>
<li>단점<ul>
<li>세션 하이재킹 공격이 발생할 수 있음<ol>
<li>A 사용자의 <strong>HTTP 요청</strong>을 B 사용자(해커)가 가로챔</li>
<li>B 사용자는 가로챈 <strong>HTTP 요청</strong>을 이용해 내부의 <code>Cookie</code>를 탈취함</li>
<li>B 사용자가 탈취한 <code>Cookie</code>를 이용해 서버에 <strong>HTTP 요청</strong>을 보냄</li>
<li>서버는 B 사용자를 A 사용자로 오인하여 정보를 잘못 보냄</li>
</ol>
</li>
<li><strong>Session Storage</strong>를 서버에 구축해야 하기 때문에 사용자가 많아지는 경우 서버 부하가 발생할 수 있음</li>
</ul>
</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>Cookie</th>
<th>Session/Cookie</th>
<th>JWT</th>
</tr>
</thead>
<tbody><tr>
<td>보안</td>
<td>취약</td>
<td>강함</td>
<td>강함</td>
</tr>
<tr>
<td>서버 부하</td>
<td>낮음</td>
<td>높음</td>
<td>낮음</td>
</tr>
<tr>
<td>네트워크 부하</td>
<td>높음</td>
<td>낮음</td>
<td>높음</td>
</tr>
</tbody></table>
<h2 id="구조">구조</h2>
<p><strong><code>JWT</code></strong>는 JSON 정보가 <code>Base64Url</code>로 인코딩된 형태가 점(.)으로 구분된 세 부분으로 구성되며, 각 부분은 다음과 같다.</p>
<ul>
<li>Header</li>
<li>Payload</li>
<li>Signature</li>
</ul>
<p>세 부분이 각각 인코딩되어서 다음과 같은 형태를 띤다.</p>
<p><code>xxxxx.yyyyy.zzzzz</code></p>
<h3 id="header">Header</h3>
<p><strong><code>Header</code></strong>는 일반적으로 해시 알고리즘(HMAC SHA256 또는 RSA 등)과 토큰 유형을 정의한다.</p>
<pre><code class="language-json">{
    &quot;alg&quot;: &quot;HS256&quot;,
    &quot;typ&quot;: &quot;JWT&quot;
}</code></pre>
<h3 id="payload">Payload</h3>
<p><code>Payload</code>는 전달하고자 하는 데이터에 관한 내용이 포함된다.</p>
<p>데이터의 Key를 <code>claim</code>이라고 하며 세 가지 종류로 나뉜다.</p>
<ul>
<li>Registered claims (등록된 클레임)<ul>
<li>필수는 아니지만 사용이 권장되는 <code>claim</code>으로 압축을 위해 세 글자로만 구성된다.</li>
<li><code>iss</code> (issuer), <code>exp</code> (expiration time), <code>sub</code> (subject), <code>aud</code> (audience) 등</li>
<li>그 외의 claim: <a href="https://datatracker.ietf.org/doc/html/rfc7519#section-4.1">https://datatracker.ietf.org/doc/html/rfc7519#section-4.1</a></li>
</ul>
</li>
<li>Public claims (공개 클레임)<ul>
<li>사용자가 자유롭게 정의할 수 있는 <code>claim</code>이다.</li>
<li>하지만 충돌을 피하기 위해 다음 두 가지 방식으로 정의해야 한다.<ul>
<li><a href="https://www.iana.org/assignments/jwt/jwt.xhtml">IANA JSON 웹 토큰 레지스트리</a> 에서</li>
<li>충돌 방지 네임스페이스를 포함하는 URI</li>
</ul>
</li>
</ul>
</li>
<li>Private claims (비공개 클레임)<ul>
<li>당사자 간 정보 공유를 위한 맞춤형 <code>claim</code></li>
<li>사용을 동의한 당사자 간에 정보 공유를 위해 작성된다.</li>
</ul>
</li>
</ul>
<pre><code class="language-json">{
    &quot;sub&quot;: &quot;1234567890&quot;,
    &quot;name&quot;: &quot;John Doe&quot;,
    &quot;admin&quot;: true
}</code></pre>
<h3 id="signature">Signature</h3>
<p><code>Signature</code>는 인코딩된 <code>Header</code>, <code>Payload</code>와 <code>Secret Key</code>가 합쳐진 형태로 생성된다.</p>
<p>예를 들어, HMAC SHA256 알고리즘을 사용하는 경우 다음과 같은 방식으로 생성된다.</p>
<pre><code class="language-json">HMACSHA256(
    base64UrlEncode(header) + &quot;.&quot; +
    base64UrlEncode(payload),
    secret)</code></pre>
<p>세 부분이 각각 Base64Url로 인코딩되어 다음과 같은 형태로 보여진다.</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/6134fc73-19d1-49d4-bcd8-67c8ba5705fa/image.png" alt=""></p>
<p><a href="https://jwt.io/#debugger-io">jwt.io debugger</a>를 사용해서 실제로 생성해볼 수 있다.</p>
<h2 id="jwt의-문제">JWT의 문제</h2>
<p>위에서 언급하였듯이 JWT는 만능이 아니다. 다른 인증 방식에 비하여 서버 부하가 적고, 보안에 강하기 때문에 많이 사용되고, 권장하는 방식이지만 무턱대고 사용하는 경우 큰 보안 이슈가 발생한다.</p>
<h3 id="1-알고리즘-지정">1. 알고리즘 지정</h3>
<pre><code class="language-json">{
    &quot;alg&quot;: &quot;none&quot;,
    &quot;typ&quot;: &quot;JWT&quot;
}</code></pre>
<p>위와 같이 Header의 해시 알고리즘 부분을 “none”으로 해두는 경우이다.</p>
<p>어떤 멍청한 개발자가 이렇게 하냐 싶겠지만 생각보다 많은 사람들이 실수하는 부분이기 때문에 한번 더 확인하는 것을 추천드린다.</p>
<p>실제로 “none”을 집어넣고 해킹을 시도하는 경우도 존재하기 때문에 이를 방지하기 위해서 “none”인 경우를 걸러주는 로직도 구현할 필요가 있어보인다.</p>
<h3 id="2-유저-정보">2. 유저 정보</h3>
<p>JWT는 인코딩된 문자열이기는 하지만 디코딩이 매우 쉽다. </p>
<p>그렇기 때문에 JWT에는 절대로 민감한 유저 정보를 넣어서는 안되고, 해당 유저임을 확인할 수 있는 최소한의 정보만 넣어야 한다.</p>
<h3 id="3-secret-key-문제">3. Secret Key 문제</h3>
<p>Secret Key는 당연하게도 어렵게 만들어야 한다. </p>
<p>로그인에 필요한 비밀번호와 같은 것이기 때문에 유추가 쉬운 문자는 당연히 배제해야 하고, 최대한 길게 생성하고, 생성된 키는 철저하게 관리해야 한다.</p>
<p>이게 조금 불안하다 싶으면 많은 사람들이 사용하는 방법이 존재한다.</p>
<h4 id="privatepublic-key-pair">Private/Public Key Pair</h4>
<p>생성과 검증에 필요한 공개 키와 비밀 키를 생성하는 것이다. 좀 더 쉽게 설명하자면 매우 풀기 어려운 수학적 문제(공개 키)와 출제자만 알고 있는 특정한 종류의 정보(비밀 키)를 생성한다. 문제(공개 키)를 풀면 원래의 메시지(비밀 키)를 해독할 수 있다.</p>
<p>이 방법을 사용하면 하나의 키를 사용할 때보다 키의 유출 위험이 줄어들고, 통신의 비밀성을 보장할 수 있다. 또한, 네트워크 규모가 커질수록 관리가 훨씬 용이해진다.</p>
<h3 id="4-jwt-탈취">4. JWT 탈취</h3>
<p>Session/Cookie 방식과 비슷하게 토큰을 탈취하는 경우가 발생할 수 있다. JWT는 클라이언트에서 관리되기 때문에 서버에서 이 문제를 해결할 수 있는 방법은 없다. 이를 방지하기 위해 유효기간이 존재하지만, 만료될 때까지 기다려야 한다는 문제가 있다. 그래서 이를 해결하기 위한 좋은 방법이 존재한다.</p>
<h4 id="access-token과-refresh-token">Access Token과 Refresh Token</h4>
<p>기본적인 개념은 다음과 같다</p>
<ul>
<li>Access Token<ul>
<li>유효기간이 짧은 토큰(ex. 60일, 1시간)</li>
<li>API 통신에 사용됨</li>
</ul>
</li>
<li>Refresh Token<ul>
<li>유효기간이 긴 토큰(ex. 1년)</li>
<li>Access Token 갱신 시 사용됨</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/geon-2/post/c787c341-5010-4cb4-9c12-806b97b9b26d/image.png" alt=""></p>
<p>해당 방법을 사용한 통신 과정은 다음과 같다.</p>
<ol>
<li>로그인 인증에 성공한 클라이언트는 <code>Refresh Token</code>과 <code>Access Token</code> 두 개를 <strong>서버로부터 받는다</strong>.</li>
<li>클라이언트는 <code>Refresh Token</code>과 <code>Access Token</code>을 <strong>로컬</strong>에 저장해놓는다.</li>
<li>클라이언트는 <strong>헤더</strong>에 Access Token을 넣고 API 통신을 한다. <strong>(Authorization)</strong></li>
<li>일정 기간이 지나 <code>Access Token</code>의 <strong>유효기간이 만료</strong>되었다.<ol>
<li>Access Token은 이제 유효하지 않으므로 <strong>권한이 없는 사용자</strong>가 된다.</li>
<li>클라이언트로부터 유효기간이 지난 Access Token을 받은 서버는 <a href="https://www.rfc-editor.org/rfc/rfc6750#section-6.2.2">401 (Unauthorized)</a> 에러 코드로 응답한다.</li>
<li><code>401</code>를 통해 클라이언트는 <code>invalid_token</code> (유효기간이 만료되었음)을 알 수 있다.</li>
</ol>
</li>
<li><strong>헤더</strong>에 Access Token 대신 <code>Refresh Token</code>을 넣어 <strong>API를 재요청</strong>한다.</li>
<li>Refresh Token으로 사용자의 권한을 확인한 서버는 <strong>응답쿼리 헤더</strong>에 <strong>새로운 Access Token</strong>을 넣어 응답한다.</li>
<li>만약 <code>Refresh Token</code>도 <strong>만료</strong>되었다면 서버는 동일하게 <strong>401 error code</strong>를 보내고, 클라이언트는 <strong>재로그인</strong>해야한다.</li>
</ol>
<h4 id="refresh-token-탈취">Refresh Token 탈취?</h4>
<p>해당 방법은 Access Token 탈취 문제를 해결하고자 만든 것이기 때문에 Refresh Token에 탈취 문제를 해결한 것은 아니다. OAuth는 이를 해결하기 위해 <strong>Refresh Token Rotation</strong>을 제시한다.</p>
<p>클라이언트가 Access Token을 재요청할 때 Refresh Token도 새로 발급받는 것이다. 이렇게 하면 탈취된 Refresh Token은 더 이상 해당 사용자의 Token이 아니게 되는 것이기 때문에 탈취 위험에서 벗어날 수 있게 된다.</p>
<hr>
<h2 id="reference">Reference</h2>
<blockquote>
<p>JWT, Introduction, <a href="https://jwt.io/introduction">https://jwt.io/introduction</a>
코딩애플, JWT 대충 쓰면 님들 인생 끝남, <a href="https://www.youtube.com/watch?v=XXseiON9CV0">https://www.youtube.com/watch?v=XXseiON9CV0</a>
Wikipedia, 공개 키 암호 방식, <a href="https://ko.wikipedia.org/wiki/%EA%B3%B5%EA%B0%9C_%ED%82%A4_%EC%95%94%ED%98%B8_%EB%B0%A9%EC%8B%9D">https://ko.wikipedia.org/wiki/공개<em>키</em>암호_방식</a>
OAuth, What Are Refresh Tokens and How to Use Them Securely<strong>,</strong> <a href="https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/">https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hooks]]></title>
            <link>https://velog.io/@geon-2/Hooks</link>
            <guid>https://velog.io/@geon-2/Hooks</guid>
            <pubDate>Tue, 02 Jul 2024 14:58:25 GMT</pubDate>
            <description><![CDATA[<p>이 파트에는 React의 LifeCycle(생명주기)에 관한 내용이 포함되어있으니 먼저 공부하고 보면 이해하기 쉬울 것이다.</p>
<h1 id="hooks">Hooks</h1>
<p>Hook은 버전 16.8부터 새로 추가된 요소로, 기존 Class 바탕의 코드 없이 상태 값과 여러 React의 기능을 사용할 수 있는 요소이다.</p>
<p>Hook이라는 개념이 고안된 이유는 사용자들이 직면한 다음과 같은 문제들 때문이다.</p>
<ol>
<li>컴포넌트 사이에서 상태 로직을 재사용하기 어렵다.<ul>
<li>React는 컴포넌트 간에 재사용 가능한 로직을 붙이는 방법을 제공하지 않았다.</li>
<li>이전에는 <a href="https://ko.legacy.reactjs.org/docs/hooks-intro.html">render props</a>, <a href="https://ko.legacy.reactjs.org/docs/hooks-intro.html">고차 컴포넌트</a>와 같은 패턴으로 해결하였지만, 이러한 패턴은 컴포넌트의 재구성을 강요하여, 코드의 추적을 어렵게 만들었다.</li>
<li>Hook은 계층의 변화 없이 상태 관련 로직을 재사용할 수 있도록 도와준다.</li>
</ul>
</li>
<li>복잡한 컴포넌트들은 이해하기 어렵다.<ul>
<li>각 생명주기 메서드에는 자주 관련 없는 로직이 섞여들어간다.</li>
<li>Hook을 통해 서로 비슷한 것을 수행하는 작은 함수의 묶음으로 컴포넌트를 나누는 방법을 사용할 수 있다.</li>
</ul>
</li>
<li>Class의 this 키워드<ul>
<li>React에서 Class를 사용하기 위해서는 Javascript의 this 키워드가 어떻게 작동하는지 알아야 한다.<ul>
<li>다른 언어와는 다르게 작동하기 때문에 코드의 재사용성과 구성을 매우 어렵게 만들었다.</li>
</ul>
</li>
<li>Hook은 Class 없이 React 기능들을 사용하는 방법을 제시한다.</li>
</ul>
</li>
</ol>
<h2 id="hooks의-종류">Hooks의 종류</h2>
<h3 id="1-usestate">1. useState</h3>
<p><code>useState</code>는 가장 기본적인 Hook으로 가변적인 상태를 지니고 있을 수 있게 해준다</p>
<h4 id="usestate의-구조">useState의 구조</h4>
<pre><code class="language-jsx">// const [state, 업데이트 함수] = useState(초기값);
const [count, setCount] = useState(0);</code></pre>
<ul>
<li>parameter<ul>
<li><code>state</code>의 초기값을 인수로 가짐</li>
</ul>
</li>
<li>return<ul>
<li><code>state</code>와 <code>함수</code>를 포함한 배열을 반환함</li>
<li>반환된 함수를 통해 <code>state</code>를 업데이트 할 수 있음</li>
</ul>
</li>
</ul>
<h4 id="example">Example</h4>
<pre><code class="language-jsx">import { useState } from &quot;react&quot;;

function Counter() {
  const [count, setCount] = useState(0);

  return (
    &lt;div&gt;
      &lt;p&gt;Number: {count}&lt;/p&gt;
      &lt;button type=&quot;button&quot; onClick={() =&gt; setCount(count + 1)}&gt;
        +
      &lt;/button&gt;
      &lt;button type=&quot;button&quot; onClick={() =&gt; setCount(count - 1)}&gt;
        -
      &lt;/button&gt;
    &lt;/div&gt;
  );
}

export default Counter;</code></pre>
<p>버튼을 통해 count의 값이 변경되는 기능이 구현되어있다. </p>
<p><code>useState</code>는 parameter로 <code>state</code>의 초기값을 받아 저장한다. 따라서 해당 코드에서는 count의 초기값이 0으로 주어지고, <code>setCount</code> 함수를 통해 <code>count</code>의 값을 변경 가능하다.</p>
<p><code>state</code>는 당연하게도 컴포넌트의 <code>state</code>로 작용하기 때문에 값이 변경되면 실시간으로 <code>리렌더링</code>된다.</p>
<h3 id="2-useeffect">2. useEffect</h3>
<p><code>useEffect</code>는 컴포넌트가 렌더링 될 때마다 특정 작업을 설정할 수 있는 Hook이다. </p>
<p>“Effect”는 <code>Side-Effect</code>의 의미로 <code>useEffect</code>를 통해 부작용을 관리할 수 있다. </p>
<h4 id="useeffect의-구조">useEffect의 구조</h4>
<pre><code class="language-jsx">// useEffect(callback 함수, dependency array)
useEffect(() =&gt; {
    console.log(&#39;useEffect 호출&#39;)

    // return () =&gt; {}
}, [key])</code></pre>
<ul>
<li>parameter<ul>
<li>callback 함수: 컴포넌트의 생명주기에 따라 실행되는 함수<ul>
<li>함수를 <code>return</code> 값으로 가질 수 있음</li>
<li>마운트 될 때 (componentDidMount)<ul>
<li><code>callback</code> 함수가 return 이전까지 실행됨</li>
</ul>
</li>
<li>업데이트 될 때 (componentDidUpdate)<ul>
<li><code>dependency array</code>에 값이 포함되어 있으면, 해당되는 값이 업데이트 될 때 <code>callback</code> 함수가 return 이전까지 실행됨</li>
<li><code>dependency array</code>가 빈 배열이면 실행되지 않음</li>
</ul>
</li>
<li>언마운트 될 때 (componentWillUnmount)<ul>
<li><code>callback</code>가 return하는 함수가 실행됨</li>
</ul>
</li>
</ul>
</li>
<li>dependency array(의존성 배열): <code>callback</code> 함수가 의존하는 값들이 포함되어 있음<ul>
<li>빈 배열일 경우에는 컴포넌트가 마운트 될 때, 즉, 처음 렌더링될 때만 함수가 실행됨</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="example-1">Example</h4>
<pre><code class="language-jsx">import { useState, useEffect } from &#39;react&#39;;

function Welcome () {
    const [name, setName] = useState(&#39;&#39;);

    useEffect(() =&gt; {
        if (name == &#39;&#39;) {
            alert(&#39;Welcome&#39;);
        } else {
            alert(`${name}님 환영합니다!`);
        }

        return () =&gt; { // optional
            alert(&#39;안녕히가세요!&#39;);
        }
    }, [name]);

    return (
        &lt;&gt;
            &lt;input type=&quot;text&quot; name=&quot;name&quot; value={name} onChange{() =&gt; setName(name)} /&gt;
        &lt;/&gt;
    )
}

export default Welcome;</code></pre>
<p>input을 통해 입력한 이름을 alert 메시지로 출력하는 예제를 구현해보았다.</p>
<p>예제에서 <code>useEffect</code>가 실행되는 조건은 다음과 같다.</p>
<ul>
<li>첫 마운트 시: ‘당신의 이름을 입력하세요’ 메시지가 alert됨</li>
<li>name의 값이 변경될 때: ‘${name}님 환영합니다!’ 메시지가 alert됨</li>
<li>언마운트 시: ‘안녕히가세요!’ 메시지가 alert됨</li>
</ul>
<h3 id="3-usecontext">3. useContext</h3>
<p><code>useContext</code>는 함수형 컴포넌트에서 <code>Context</code>를 보다 쉽게 사용할 수 있는 Hook이다.</p>
<p><code>Context</code>는 React 내에서 전역 상태를 관리할 수 있는 방법 중에 하나이다. 전역 상태 관리란 말 그대로 <code>state</code>를 전역에서 관리하기 때문에 <code>Props Drilling</code> 문제를 해결할 수 있다.</p>
<pre><code class="language-jsx">import { createContext, useContext } from &quot;react&quot;;

const ThemeContext = createContext(&quot;black&quot;);

function ContextSample() {
  const theme = useContext(ThemeContext);
  const style = {
    width: &quot;24px&quot;,
    height: &quot;24px&quot;,
    background: theme,
  };
  return &lt;div style={style} /&gt;;
}

export default ContextSample;</code></pre>
<h3 id="4-usereducer">4. useReducer</h3>
<p><code>useReducer</code>는 <code>useState</code>와 같이 <code>state</code>를 관리할 수 있는 Hook이다. <code>useState</code>와 다른 점은 <code>state</code>를 업데이트 하는 로직을 컴포넌트로부터 분리시키는 것이 가능하다는 것이다.</p>
<p><strong>Redux</strong>를 알고 있다면 생각나는 그 reducer를 생각하면 편하다. 조금 다른 점은 Redux 에서는 액션 객체에 어떤 액션인지 알려주는 type 필드가 꼭 있어야 하지만, useReducer 에서 사용하는 액션 객체에서는 꼭 지니고 있을 필요가 없다.</p>
<h4 id="usereducer의-구조">useReducer의 구조</h4>
<pre><code class="language-jsx">const reducer = (state, action) =&gt; { 
    // ...
}

// const [state, dispatch] = useReducer(reducer 함수, object)
const [state, dispatch] = useReducer(reducer, { value: 0 });</code></pre>
<ul>
<li>parameter<ul>
<li>reducer 함수: action이 정의된 함수<ul>
<li>parameter로 <code>state</code>와 <code>action</code>을 가짐</li>
<li><code>state</code>들이 어떻게 업데이트되는지에 대한 로직이 정의되어 있음</li>
</ul>
</li>
<li>object: <code>state</code>들의 초기값이 저장된 object</li>
</ul>
</li>
<li>return<ul>
<li><code>state</code>와 <code>dispatch</code>가 포함된 배열이 반환됨</li>
<li><code>dispatch</code>를 통해 <code>state</code>를 업데이트 할 수 있음</li>
</ul>
</li>
</ul>
<h4 id="example-2">Example</h4>
<pre><code class="language-jsx">import { useReducer } from &quot;react&quot;;

function reducer(state, action) {
  switch (action.type) {
    case &quot;INCREMENT&quot;:
      return { value: state.value + 1 };
    case &quot;DECREMENT&quot;:
      return { value: state.value - 1 };
    default:
      return { value };
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { value: 0 });

  return (
    &lt;div&gt;
      &lt;p&gt;Number: {state.value}&lt;/p&gt;
      &lt;button type=&quot;button&quot; onClick={() =&gt; dispatch({ type: &quot;INCREMENT&quot; })}&gt;
        +
      &lt;/button&gt;
      &lt;button type=&quot;button&quot; onClick={() =&gt; dispatch({ type: &quot;DECREMENT&quot; })}&gt;
        -
      &lt;/button&gt;
    &lt;/div&gt;
  );
}

export default Counter;</code></pre>
<p>카운터 예제를 useReducer로 구현해보았다.</p>
<p>dispatch는 action을 인수로 가지며, action의 type 값을 통해서 로직을 선택할 수 있다. type이 달라질 때마다 카운터 값을 변경하는 방식이 달라지고 있다.</p>
<h4 id="usereducer-vs-usestate">useReducer vs useState</h4>
<ul>
<li><strong>useState</strong><ul>
<li>관리해야 할 <code>state</code>가 1개일 경우</li>
<li>그 <code>state</code>가 단순한 숫자, 문자열 또는 <code>boolean</code> 값일 경우</li>
</ul>
</li>
<li><strong>useReducer</strong><ul>
<li>관리해야 할 <code>state</code>가 1개 이상, 복수일 경우</li>
<li>혹은 현재는 단일 <code>state</code> 값만 관리하지만, 추후 유동적일 가능성이 있는 경우</li>
<li>스케일이 큰 프로젝트의 경우</li>
<li><code>state</code>의 구조가 복잡해질 것으로 보이는 경우</li>
</ul>
</li>
</ul>
<p>해당 Hook과 관련해서 더 자세하게 알고 싶다면, React의 상태 관리와 Redux에 대해 공부해보기를 권장한다.</p>
<h3 id="5-usememo">5. useMemo</h3>
<p>useMemo는 컴포넌트의 성능을 최적화 하는데 사용되는 Hook이다.</p>
<p>“Memo”는 <code>memorization</code>, 즉, ‘메모리에 넣기’를 의미한다. 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 반복 수행을 제거하여 프로그램 실행 속도를 빠르게하는 기술이다.</p>
<h4 id="usememo의-구조">useMemo의 구조</h4>
<pre><code class="language-jsx">// const value = useMemo(callback 함수, dependency array)
const value = useMemo(() =&gt; {
    return calculate();
}, [item])</code></pre>
<ul>
<li><code>useEffect</code>의 구조와 비슷하게 생각하면 됨</li>
<li>parameter<ul>
<li>callback 함수: 렌더링될 때 실행되는 함수<ul>
<li><code>useEffect</code>와 동일하게 처음 렌더링될 때와 dependency array의 값이 업데이트될 때 실행됨</li>
<li>다른 값에 의해 렌더링될 경우 메모리에 저장된 값을 재사용한다.</li>
</ul>
</li>
<li>dependency array(의존성 배열): <code>callback</code> 함수가 의존하는 값들이 포함되어 있음<ul>
<li><code>useEffect</code>와 동일하게 빈 배열인 경우 처음 렌더링될 때 이후엔 callback 함수가 실행되지 않고 저장된 값을 재사용함</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="example-3">Example</h4>
<pre><code class="language-jsx">import { useState } from &quot;react&quot;;

function hardCalculate(number) {
  console.log(&quot;어려운 계산!&quot;);
  for (let i = 0; i &lt; 99999999; i++) {} //생각하는 시간
  return number + 10000;
}

function easyCalculate(number) {
  console.log(&quot;쉬운 계산!&quot;);
  return number + 1;
}

function App() {
  const [hardNumber, setHardNumber] = useState(1);
  const [easyNumber, setEasyNumber] = useState(1);

  const hardSum = hardCalculate(hardNumber);
  const easySum = easyCalculate(hardNumber);

  return (
    &lt;div&gt;
      &lt;h3&gt;어려운 계산기&lt;/h3&gt;
      &lt;input
        type=&quot;number&quot;
        value={hardNumber}
        onChange={(e) =&gt; setHardNumber(parseInt(e.target.value))}
      /&gt;
      &lt;span&gt; + 10000 = {hardSum}&lt;/span&gt;

      &lt;h3&gt;쉬운 계산기&lt;/h3&gt;
      &lt;input
        type=&quot;number&quot;
        value={easyNumber}
        onChange={(e) =&gt; setEasyNumber(parseInt(e.target.value))}
      /&gt;
      &lt;span&gt; + 1 = {easySum}&lt;/span&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<p>어떤 블로그의 예제를 들고와 봤다.</p>
<p>어려운 계산기와 쉬운 계산기를 구현한 예제이다.</p>
<p>어려운 계산기는 반복문을 99999999번 돌리고 값을 반환하기 때문에 숫자를 변경하면 1초 정도의 딜레이를 거친 후 값이 변경된다.</p>
<p>심지어 쉬운 계산기의 값을 변경해도 1초 정도의 딜레이를 거친 후 값이 변경된다.</p>
<p>그 이유는 쉬운 계산기의 input값을 변경하면 컴포넌트가 리렌더링되는데 이 때 내부의 변수들이 초기화되기 때문에 hardCalculate가 다시 실행되기 때문이다.</p>
<p>그렇다면 이제 <code>useMemo</code>를 통해 이를 방지해보자.</p>
<pre><code class="language-jsx">const hardSum = useMemo(() =&gt; {
    return hardCalculate(hardNumber)**;**
}, [hardNumber]);</code></pre>
<p>이렇게 하면 처음 렌더링될 때 hardCalculate로 계산된 값이 메모리에 저장되기 때문에 hardNumber가 업데이트되지 않는 경우에는 딜레이를 거치지 않아도 된다.</p>
<h3 id="6-usecallback">6. useCallback</h3>
<p><code>useCallback</code>은 <code>useMemo</code>와 동일하게 <code>memorization</code> 기법으로 컴포넌트 성능을 최적화 시켜주는 Hook이다.</p>
<p><code>useMemo</code>가 값을 저장하는 거라면 <code>useCallback</code>은 함수를 자체를 저장하는 거라고 이해하면 된다.</p>
<h4 id="usecallback의-구조">useCallback의 구조</h4>
<pre><code class="language-jsx">// useCallback(callback 함수, dependency array)
useCallback(() =&gt; {
    return value;
}, [item]);</code></pre>
<ul>
<li>parameter<ul>
<li>callback 함수: 렌더링될 때 실행되는 함수<ul>
<li><code>useMemo</code>와 동일하게 실행됨</li>
</ul>
</li>
<li>dependency array(의존성 배열): <code>callback</code> 함수가 의존하는 값들이 포함되어 있음<ul>
<li>이것도 <code>useMemo</code>의 dependency array와 동일함</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="example-4">Example</h4>
<pre><code class="language-jsx">import { useEffect, useState, useCallback } from &#39;react&#39;;

function App() {
    const [number, setNumber] = useState(0);

    const someFunction = useCallback(() =&gt; {
        console.log(`someFunc: number: ${number}`);
        return;
    }, []);

    useEffect(() =&gt; {
        console.log(&quot;someFunction 이 변경되었습니다.&quot;);
    }, [someFunction]);

    return (
        &lt;div&gt;
            &lt;input
                type=&quot;number&quot;
                value={number}
                onChange={e =&gt; setNumber(e.target.value)}
            /&gt;
            &lt;br /&gt;
            &lt;button onClick={someFunction}&gt;Call someFunc&lt;/button&gt;
        &lt;/div&gt;
    );
}

export default App;</code></pre>
<p>위 코드도 어떤 블로그의 예제를 빌려왔다. <code>useEffect</code>를 이용해 callback 함수가 <code>memorization</code>된 것을 확인하는 예제이다. </p>
<p><code>useCallback</code>의 callback 함수는 처음 렌더링될 때 실행되고 메모리에 저장된다. <code>useCallback</code>의 <code>denpendency array</code>가 빈 배열이기 때문에 이후에는 메모리에 저장된 callback 함수를 재사용하게 된다. 따라서, <code>useEffect</code>의 callback 함수는 마운트될 때 이후에는 실행되지 않는다.</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/9d3f2722-ccc1-4b7e-8bbf-8b95f54b52ce/image.gif" alt=""></p>
<h3 id="7-useref">7. useRef</h3>
<p><code>useRef</code>는 저장공간 도는 DOM요소에 접근하기 위해 사용되는 Hook이다.</p>
<h4 id="example1---변수-관리">Example1 - 변수 관리</h4>
<p>!codesandbox[fpp7l2?view=editor+%2B+preview&amp;module=%2Fsrc%2FApp.js]</p>
<p>위 코드도 특정 블로그의 예제를 들고 온 것이다.</p>
<p>useState, useRef 그리고 let 키워드를 사용해서 세 가지 형태의 변수를 정의한 것이다. 그리고 각각 세 가지 버튼으로 해당 변수들의 값을 증가시킬 수 있다.</p>
<p>직접 실행해보면 각각의 특징이 다음과 같다.</p>
<ul>
<li>stateCount: useState로 선언된 변수로 값이 증가될 때 실시간으로 렌더링된다.</li>
<li>refCount: useRef로 선언된 변수로 증가될 때 렌더링되지 않고, 렌더링되도 값이 유지된다.</li>
<li>varCount: 일반적인 javascript 변수로 렌더링될 때 값이 초기화된다.</li>
</ul>
<p>여기서 알 수 있는 것은 <code>useRef</code>의 값은 유지되지만 업데이트 시 렌더링되지 않아서 변수를 관리하는데 용이하다.</p>
<h4 id="example-2---dom-지정">Example 2 - DOM 지정</h4>
<pre><code class="language-jsx">import { useRef } from &#39;react&#39;;

function App() {
    const inputRef = useRef();

    function focus() {
        inputRef.current.focus();
        console.log(inputRef.current);
    }

    return (
        &lt;div&gt;
            &lt;input ref={inputRef} type=&quot;text&quot; /&gt;
            &lt;button&gt;Login&lt;/button&gt;
            &lt;button onClick={focus}&gt;focus&lt;/button&gt;
        &lt;/div&gt;
    )
}</code></pre>
<p><code>useRef</code>로 선언된 변수는 DOM 요소를 지정할 수 있다.</p>
<p>React에서는 javascript의 querySelector 대신 <code>useRef</code>를 사용해서 DOM 요소를 지정하는 것이 가능하다.</p>
<hr>
<h2 id="reference">Reference</h2>
<blockquote>
<p>React, Hook의 개요, <a href="https://ko.legacy.reactjs.org/docs/hooks-intro.html">https://ko.legacy.reactjs.org/docs/hooks-intro.html</a>
Hayoung, React Hook :: useReducer에 대해 알아보기, <a href="https://velog.io/@iamhayoung/React-Hooks-useReducer%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0">https://velog.io/@iamhayoung/React-Hooks-useReducer에-대해-알아보기</a>
김진영, [React] useMemo란?, <a href="https://velog.io/@jinyoung985/React-useMemo%EB%9E%80">https://velog.io/@jinyoung985/React-useMemo란</a>
sohyeon kim, [React] 다시 한번 useCallback을 파헤쳐보자, <a href="https://velog.io/@hjthgus777/React-%EB%8B%A4%EC%8B%9C-%ED%95%9C%EB%B2%88-useCallback%EC%9D%84-%ED%8C%8C%ED%97%A4%EC%B3%90%EB%B3%B4%EC%9E%90">https://velog.io/@hjthgus777/React-다시-한번-useCallback을-파헤쳐보자</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[React의 Lifecycle]]></title>
            <link>https://velog.io/@geon-2/React%EC%9D%98-Lifecycle</link>
            <guid>https://velog.io/@geon-2/React%EC%9D%98-Lifecycle</guid>
            <pubDate>Fri, 21 Jun 2024 09:00:09 GMT</pubDate>
            <description><![CDATA[<pre><code>함수형 컴포넌트 사용 증가로 lifecycle에 대해 깊게 다루지 않았습니다.
이 글의 목적은 Hook을 보다 쉽게 이해하기 위함이기 때문에 더 많은 공부를 위해서는 공식 문서를 직접 찾아보시기 바랍니다. </code></pre><h1 id="lifecycle">Lifecycle</h1>
<p>React에는 Lifecycle 즉 생명주기가 존재한다. 정확하게는 <strong>컴포넌트의 생명주기</strong>가 존재한다고 해야한다. React 내에서 컴포넌트는 생성, 수정, 제거의 과정을 거치도록 설계되었다.</p>
<p>우리가 Lifecycle에 대해 다루는 이유는 당연히 컴포넌트을 명확하게 통제할 수 있기 때문이다. 또한, React를 하면서 반드시 사용하는 Hook에 대한 이해도 더 직관적으로 할 수 있다.</p>
<h2 id="lifecycle의-분류">Lifecycle의 분류</h2>
<p><img src="https://velog.velcdn.com/images/geon-2/post/133371e8-578e-4bc8-b6d4-db288c2932c7/image.png" alt=""></p>
<p>Lifecycle은 크게 세 가지로 나눌 수 있다.</p>
<ul>
<li>생성될 때 (마운팅)</li>
<li>업데이트 할 때 (업데이팅)</li>
<li>제거 할 때 (언마운팅)</li>
</ul>
<h3 id="마운트">마운트</h3>
<p>컴포넌트가 DOM에 생성되기 전까지의 Lifecycle 이벤트 들이다.</p>
<h4 id="consturctorprops">consturctor(props)</h4>
<p><strong>class의 생성자</strong>를 의미한다. class가 생성될 때 한 번 호출되며, 컴포넌트의 state 설정이 필요한 경우 constructor에서 진행한다.</p>
<pre><code class="language-jsx">class MyComponent extends React.Component {
    constructor(props) {
        super(props) // 상속 받을 경우 가장 먼저 와야함

        /* 1. state 초기화 */
        this.state = {
            // ...
        }

        /* 2. 인스턴스에 이벤트 메서드 바인딩 */
        this.onClick = this.onClick(this)
    }

    onClick() {
        console.log(this)
    }
}

export default MyComponent</code></pre>
<h4 id="static-getderivedstatefrompropsprops-state">static getDerivedStateFromProps(props, state)</h4>
<p><strong>최초 생성 시와 업데이트 시</strong> 사용되는 메서드이며, static 이기 때문에 this를 사용할 수 없다.</p>
<p>렌더링될 때 매번 실행되므로 유의하여 컴포넌트를 작성해야 한다.</p>
<p>이 메서드는 props에 의해 state가 변경되어야 할 경우인데, 드물게 사용한다고 한다. 이 Lifecycle 이벤트를 사용하는 경우라면 다음과 같은 경우인지 확인하고, 다른 대안으로 작성하는 것을 권장한다.</p>
<h4 id="render">render()</h4>
<p>모든 컴포넌트가 반드시 구현해야하는 메서드로 return 값으로 다음 중 하나를 반환해야 한다.</p>
<ul>
<li>React element: JSX 문법으로 작성된 메서드</li>
<li>배열과 Fragment: 여러개의 React element를 반환</li>
<li>Portal: 루트 노드 외 별도의 DOM 트리에 자식 element를 렌더링</li>
<li>문자열 및 숫자: 텍스트 노드로서 렌더링</li>
<li>Boolean 또는 null</li>
</ul>
<h4 id="componentdidmount">componentDidMount()</h4>
<p>컴포넌트가 DOM 트리에 <strong>마운트 된 이후</strong> 실행된다. 외부에서 데이터를 불러오기 적절한 위치이며, 데이터에 대한 구독도 설정하기 적절한 위치이다.</p>
<h3 id="업데이트">업데이트</h3>
<p>컴포넌트가 생성되고, props 또는 state가 업데이트될 때 발생한다.</p>
<h4 id="shouldcomponentupdatenextprops-nextstate">shouldComponentUpdate(nextProps, nextState)</h4>
<p>React는 props 및 state가 변경될 때마다 render 함수를 실행하는 것을 기본으로 하고 있다. 이 메서드는 boolean을 return하는데 값에 따라 결과가 나뉜다.</p>
<ul>
<li>true일 때: 리렌더링</li>
<li>false일 때: 리렌더링되지 않음 (render(), componentDidUpdate() 함수가 호출되지 않음)</li>
</ul>
<p>값에 따라 리렌더링되지 않는 경우도 있기 때문에 성능최적화가 필요한 경우에 사용한다.</p>
<h4 id="getsnapshotbeforeupdateprevprops-prevstate">getSnapshotBeforeUpdate(prevProps, prevState)</h4>
<p>가장 마지막으로 <strong>렌더링 된 결과가 DOM에 반영되었을 때</strong> 호출된다. 채팅화면의 Scroll 위치 조정할 때처럼 DOM 업데이트 이후 결정된 화면에 대한 조작이 필요할 때 사용한다. 여기서 return 되는 값은 componentDidUpdate의 세번째 인자로 전달된다.</p>
<h4 id="componentdidupdateprevprops-prevstate-snapshot">componentDidUpdate(prevProps, prevState, snapshot)</h4>
<p>최초 렌더링시에는 호출되지 않고, <strong>업데이트가 일어난 직후에 발생</strong>하는 이벤트이다. DOM 조작이나 이전 props와 비교하여 네트워크 요청을 보낼지 결정하기에 좋은 위치이다.</p>
<h3 id="언마운트">언마운트</h3>
<p>컴포넌트가 DOM에서 제거(UnMounting) 될 때 발생한다.</p>
<h4 id="componentwillmount">componentWillMount</h4>
<p>컴포넌트가 <strong>DOM에서 제거되기 직전에 호출</strong>되는 이벤트이다. 여기서는 구독해제, 네트워크 요청 취소 등 메모리 누수 방지에 대한 처리를 진행한다.</p>
<hr>
<h2 id="reference">Reference</h2>
<blockquote>
<p>React, State and Lifecycle, <a href="https://ko.legacy.reactjs.org/docs/state-and-lifecycle.html">https://ko.legacy.reactjs.org/docs/state-and-lifecycle.html</a>
veloport, LifeCycle Method, <a href="https://react.vlpt.us/basic/25-lifecycle.html">https://react.vlpt.us/basic/25-lifecycle.html</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[RESTful API]]></title>
            <link>https://velog.io/@geon-2/RESTful-API</link>
            <guid>https://velog.io/@geon-2/RESTful-API</guid>
            <pubDate>Wed, 19 Jun 2024 06:53:56 GMT</pubDate>
            <description><![CDATA[<h1 id="restful-api">RESTful API</h1>
<p>개발을 하다보면 한번쯤은 듣는 개념이다. 그때마다 매번 의미를 찾아보고 이해해보려하지만, 항상 잊어리는 녀석이라 이번에 제대로 정리해보려고 한다.</p>
<p>깊게 알아보기 전에 우선 단어로 접근해보자.</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/eeb4b50a-1fb9-4eda-9d42-a061445d0078/image.png" alt=""></p>
<p>‘<strong>REST</strong>’라는 단어에 “~가득한, 아주 ~하는” 등의 의미를 나타내는 ‘<strong>ful</strong>’이라는 접미사가 붙은 형태이다.</p>
<p>해석하면 ‘아주 REST한 API’가 된다. 좀 더 알기 쉽게 의역하자면, <strong>REST의 원칙을 잘 따르는 API</strong>라는 의미이다.</p>
<p>결론적으로 REST를 이해하면 RESTful API를 이해할 수 있다.</p>
<h2 id="rest">REST</h2>
<blockquote>
<p><em><strong>REST</strong>(Representational State Transfer)란 월드 와이드 웹(WWW)과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식이다.
…
엄격한 의미로 REST는 네트워크 아키텍처 원리의 모음이다.</em></p>
<p>출처: <a href="https://ko.wikipedia.org/wiki/REST">https://ko.wikipedia.org/wiki/REST</a></p>
</blockquote>
<p>단순하게 말하자면 네트워크 아키텍처의 한 종류이다.</p>
<p>“Representational State Transfer”의 약자로 자원을 이름(자원의 표현)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미한다.</p>
<p>즉, <strong>자원</strong>의 <strong>표현</strong>에 의한 상태를 송수신하는 모든 행위들을 정의하는 것이다. 여기에서 “자원”, “표현”, “행위”는 REST를 구성하는 요소들을 의미한다.</p>
<h3 id="rest의-구성-요소">REST의 구성 요소</h3>
<ol>
<li>자원(Resource): URI<ul>
<li>모든 자원에는 고유한 ID가 존재하고, 이 자원은 Server에 존재한다.</li>
<li>자원을 구별하는 ID는 ‘/groups/:group_id’와 같은 HTTP URI 이다.</li>
<li>Client는 URI를 이용해서 자원을 지정하고 해당 자원의 상태(정보)에 대한 조작을 Server에 요청한다.</li>
</ul>
</li>
<li>행위(Verb): HTTP Method<ul>
<li>HTTP 프로토콜의 Method를 사용한다.</li>
<li>HTTP 프로토콜은 GET, POST, PUT, DELETE와 같은 Method를 제공한다.</li>
</ul>
</li>
<li>표현(Representation of Resource)<ul>
<li>Client가 자원의 상태(정보)에 대한 조작을 요청하면 Server는 이에 적절한 응답(Representation)을 보낸다.</li>
<li>REST에서 하나의 자원은 JSON, XML, TEXT, RSS 등 여러 형태의 Representation으로 나타내어 질 수 있다.</li>
<li>JSON 혹은 XML을 통해 데이터를 주고 받는 것이 일반적이다.</li>
</ul>
</li>
</ol>
<p>위 세 가지 요소로 REST를 구체적으로 정의하면 다음과 같다.</p>
<p><em>HTTP URI(Uniform Resource Identifier)를 통해 자원(Resource)을 명시하고, HTTP Method(POST, GET, PUT, DELETE)를 통해 해당 자원에 대한 CRUD Operation을 적용하는 것을 의미한다.</em></p>
<p>JSON, XML 등의 표현으로 서버에 저장된 자원은 HTTP URI를 통해 조작할 수 있고, 해당 자원을 조작하는 행위는 HTTP Method로 정의된다는 것이다.</p>
<h3 id="rest의-원칙">REST의 원칙</h3>
<p>RESTful API를 이해하는데 구성 요소만큼 중요한 것이 원칙이다. </p>
<ul>
<li>Server-Client(클라이언트/서버 구조)<ul>
<li>자원이 있는 쪽이 서버, 자원을 요청하는 쪽이 클라이언트가 된다.<ul>
<li>REST 서버: API를 제공하고, 비즈니스 로직 처리 및 저장을 책임진다.</li>
<li>클라이언트: 사용자 인증이나 콘텍스트 등을 직접 관리하고 책임진다.</li>
</ul>
</li>
</ul>
</li>
<li>Uniform Interface(인터페이스 일관성)<ul>
<li>URI로 지정한 Resource에 대한 조작을 통일되고 한정적인 인터페이스로 수행한다.</li>
<li>HTTP 표준 프로토콜에 따르는 모든 플랫폼에서 사용이 가능하다.</li>
</ul>
</li>
<li>Stateless(무상태)<ul>
<li>각 요청 간 클라이언트의 콘텍스트가 서버에 저장되어서는 안 된다.</li>
<li>서버는 각각의 요청을 완전히 별개의 것으로 인식하고 처리한다.</li>
</ul>
</li>
<li>Cacheable(캐시 처리 가능)<ul>
<li>WWW에서와 같이 클라이언트는 응답을 <a href="https://www.cloudflare.com/ko-kr/learning/cdn/what-is-caching/">캐싱</a>할 수 있어야 한다.</li>
</ul>
</li>
<li>Layered Syste(계층화)<ul>
<li>클라이언트는 REST API 서버만 호출한다.<ul>
<li>클라이언트는 대상 서버에 직접 연결되었는지, 또는 중간 서버를 통해 연결되었는지를 알 수 없다.</li>
</ul>
</li>
<li>REST 서버는 다중 계층으로 구성될 수 있다.<ul>
<li>API Server는 순수 비즈니스 로직을 수행하고 그 앞단에 보안, 로드밸런싱, 암호화, 사용자 인증 등을 추가하여 구조상의 유연성을 줄 수 있다.</li>
</ul>
</li>
</ul>
</li>
<li>Code on demaned (optional)<ul>
<li>서버로부터 스크립트를 받아서 클라이언트에서 실행한다.</li>
</ul>
</li>
</ul>
<p>REST API, RESTful API는 “자원, 표현, 행위”들이 포함되고, 해당 원칙들을 충족하는 API인 것이다.</p>
<p>그럼, REST는 어떤 이유로 고안 되었을까?</p>
<p>그 이유는 다양한 클라이언트들의 등장으로 인한 애플리케이션 분리 및 통합을 위해서 였다.</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/6771d147-3d89-4475-8d3f-aa8e148c5eda/image.png" alt=""></p>
<p>서버 프로그램은 크롬, 엣지, 사파리 등 여러 종류의 브라우저에 더해 각기 다른 아키텍쳐로 구성된 모바일 디바이스를 대응할 필요가 있어졌다.</p>
<p>이러한 멀티 플롯폼에 대한 대응을 위해서 클라이언트/서버 간 사이에 설계된 아키텍쳐가 필요했고, REST에 수요가 증가한 것이다.</p>
<p>그럼 이러한 REST를 기반으로 고안된 REST API란 어떤 것일까?</p>
<h2 id="rest-api">REST API</h2>
<p><img src="https://velog.velcdn.com/images/geon-2/post/6a35a28f-5aae-4401-b3f8-48d8226d832c/image.png" alt=""></p>
<p>API란 뭘까?</p>
<blockquote>
<p><em>API는 정의 및 프로토콜 집합을 사용하여 두 소프트웨어 구성 요소가 서로 통신할 수 있게 하는 메커니즘입니다.
…
Application Programming Interface의 줄임말로, API의 맥락에서 애플리케이션이라는 단어는 고유한 기능을 가진 모든 소프트웨어를 나타내며, 인터페이스는 두 애플리게이션 간의 서비스 계약이라고 할 수 있습니다. 이 계약은 요청과 응답을 사용하여 두 애플리케이션이 서로 통신하는 방법을 정의합니다.</em></p>
</blockquote>
<p>출처: <a href="https://aws.amazon.com/ko/what-is/api/">https://aws.amazon.com/ko/what-is/api/</a></p>
<blockquote>
</blockquote>
<p>REST API는 <strong>REST 기반으로 구현된 서비스 API</strong>라는 의미이며, API의 정의에 의하면 클라이언트와 서버가 REST의 원칙이 따라 서로 통신하는 방법을 정의한 것이라고 할 수 있다.</p>
<h3 id="rest-api-기본-설계-규칙">REST API 기본 설계 규칙</h3>
<p>REST API 설계 시 가장 중요한 항목은 다음 2가지로 요약할 수 있다.</p>
<ol>
<li>URI는 정보의 자원을 표현해야 한다.</li>
<li>자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현한다.</li>
</ol>
<p>이것만으로는 어려우니 구체적으로 알아보자.</p>
<h4 id="uuri는-정보의-자원을-표현해야-한다u-리소스명은-동사보다-명사를-사용"><U>URI는 정보의 자원을 표현해야 한다.</U> (리소스명은 동사보다 명사를 사용)</h4>
<pre><code class="language-bash">GET /members/delete/1</code></pre>
<p>위와 같은 방식은 REST를 제대로 적용하지 않은 URI이다. URI는 자원을 표현하는데 중점을 두어야 하며, delete와 같은 행위에 대한 표현이 들어가서는 안된다.</p>
<h4 id="u자원에-대한-행위는-http-methodget-post-put-delete-등으로-표현u"><U>자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE 등)으로 표현</U></h4>
<p>위의 잘못된 URI를 HTTP Method를 통해 수정해 보면</p>
<pre><code class="language-bash">DELETE /members/1</code></pre>
<p>다음과 같이 된다.</p>
<p>회원정보를 가져올 때는 GET, 회원 추가 할 때는 POST를 사용한다.</p>
<p><strong>회원 정보 조회</strong></p>
<pre><code class="language-bash">GET /members/show/1 (x)
GET /members/1 (o)</code></pre>
<p><strong>회원 추가</strong></p>
<pre><code class="language-bash">GET /members/insert/2 (x) - GET 메서드는 리소스 생성에 맞지 않는다.
POST /members/2 (o)</code></pre>
<p>[참고] HTTP Method는 다음과 같은 역할을 수행한다.</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td>POST</td>
<td>해당 URI을 요청하면 리소스를 생성한다</td>
</tr>
<tr>
<td>GET</td>
<td>해당 리소스를 조회한다. 리소스를 조회하고 해당 document에 대한 자세한 정보를 가져온다.</td>
</tr>
<tr>
<td>PUT</td>
<td>해당 리소스를 수정한다.</td>
</tr>
<tr>
<td>DELETE</td>
<td>해당 리소스를 삭제한다.</td>
</tr>
</tbody></table>
<p>위와 같은 방식으로 URI은 자원, HTTP Method는 행위만을 정의하는 것이 REST API의 기본 규칙이다.</p>
<h3 id="rest-api-설계-규칙">REST API 설계 규칙</h3>
<ol>
<li><p>슬래시 구분자(/)는 계층 관계를 나타내는데 사용한다.</p>
<pre><code class="language-bash"> http://restapi.example.com/houses/apartments</code></pre>
</li>
<li><p>URI 마지막 문자로 슬래시(/)를 포함하지 않는다.</p>
<ul>
<li><p>URI에 포함하는 모든 글자는 리소스의 유일한 식별자로 사용되어야 한다. (URI가 다르면 리소스도 달라져야 함)</p>
</li>
<li><p>혼동 방지를 위해 경로 마지막에는 슬래시(/)를 사용하지 않는다.</p>
<pre><code class="language-bash">http://restapi.example.com/houses/apartments/ (x)
http://restapi.example.com/houses/apartments (o)</code></pre>
</li>
</ul>
</li>
<li><p>하이픈(-)은 URI 가독성을 높이는데 사용한다.</p>
</li>
<li><p>밑줄(_)은 URI에 사용하지 않는다.</p>
</li>
<li><p>URI 경로에는 소문자가 적합하다.</p>
<ul>
<li>RFC 3986(URI 문법 형식)은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하기 때문이다.</li>
</ul>
</li>
<li><p>파일확장자는 URI에 포함하지 않는다.</p>
<ul>
<li><p>REST API에서는 메시지 바디 내용의 포맷을 나타내기 위한 파일 확장자를 URI 안에 포함시키지 않는다.</p>
</li>
<li><p>대신 Accept header를 사용한다.</p>
<pre><code class="language-bash">http://restapi.example.com/members/soccer/345/photo.jpg (x)

GET /member/soccer/345/photo HTTP/1.1 Host:restapi.example.com Accpet: image/jpg (o)</code></pre>
</li>
</ul>
</li>
<li><p>리소스 간에는 연관 관계가 있는 경우</p>
<ul>
<li><p>/리소스명/리소스ID/관계가 있는 다른 리소스명</p>
<pre><code class="language-bash">GET : /users/{userid}/devices # (일반적으로 소유 &#39;has&#39;의 관계를 표현할 때)</code></pre>
</li>
</ul>
</li>
</ol>
<p>[참고] 응답상태코드</p>
<blockquote>
<ul>
<li>1xx: 전송 프로토콜 수준의 정보 교환</li>
</ul>
</blockquote>
<ul>
<li>2xx: 클라이언트 요청이 성공적으로 수행됨</li>
<li>3xx: 클라이언트는 요청을 완료하기 위해 추가적인 행동을 취해야 함</li>
<li>4xx: 클라이언트의 잘못된 요청</li>
<li>5xx: 서버쪽 오류로 인한 상태코드<blockquote>
</blockquote>
</li>
</ul>
<h2 id="restful-api-1">RESTful API</h2>
<p>그럼 RESTful API란 뭘까?</p>
<p><strong>‘RESTful’</strong>은 아까 처음에 정의하였듯이 <strong>‘아주 REST한’</strong>이라는 의미이다.</p>
<p>REST API에 확장된 개념으로 보다 REST를 REST 답게 쓰기 위한 개념이다.</p>
<h3 id="restful-api의-목적">RESTful API의 목적</h3>
<p>‘이해하기 쉽고 사용하기 쉬운 REST API를 만드는 것’</p>
<p>RESTful한 API를 구현하는 근본적인 목적은 성능이 아닌 이해도 및 호환성을 높이는 것이다. 따라서, 성능이 중요한 상황에서는 굳이 RESTful한 API를 구현할 필요는 없다.</p>
<h3 id="restful-하지-못한-경우">RESTful 하지 못한 경우</h3>
<ul>
<li>Ex1) CRUD 기능을 모두 POST로만 처리하는 API</li>
<li>Ex2) route에 resource, id 외의 정보가 들어가는 경우(/students/updateName)</li>
</ul>
<h2 id="글을-마치며">글을 마치며</h2>
<p>정작 중요한 RESTful API는 많이 다루지 않았는데, 그것은 본질적으로 REST API와 다르지 않기 때문이다. 그럼에도 RESTful한 것이 중요한 이유는 직관적인 소통을 위함에 있다. REST는 결국 좋은 소통을 위해 고안된 개념이다. REST를 RESTful하지 못하게 사용하는 것, 즉, 어렵게 REST를 사용하는 것은 복잡하게 소통하는 것이므로 REST를 사용하지 않는 것이나 다름없다. 그렇기 때문에 RESTful을 개념자체를 알고 이해하는 것이 중요하다. RESTful API이야말로 서버에서 쉽게 데이터에 액세스할 수 있는 웹 애플리케이션을 구축하는 가장 좋은 방법이기 때문이다.</p>
<hr>
<h2 id="reference">Reference</h2>
<blockquote>
<p>Wikipedia, REST, <a href="https://ko.wikipedia.org/wiki/REST">https://ko.wikipedia.org/wiki/REST</a>
heejeong Kwon, [Network] REST란, REST API란, RESTful이란?, <a href="https://gmlwjd9405.github.io/2018/09/21/rest-and-restful.html">https://gmlwjd9405.github.io/2018/09/21/rest-and-restful.html</a>
팬도라, Jersey를 활용한 RESTful 이해하기, <a href="https://judo0179.tistory.com/13">https://judo0179.tistory.com/13</a>
The Postman Team, ‘What Is a REST API? Examples, Uses, and Challenges’, <a href="https://blog.postman.com/rest-api-examples/">https://blog.postman.com/rest-api-examples/</a>
aws, 애플리케이션 프로그래밍 인터페이스(API)란 무엇인가요?, <a href="https://aws.amazon.com/ko/what-is/api/">https://aws.amazon.com/ko/what-is/api/</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Functional Programming]]></title>
            <link>https://velog.io/@geon-2/Functional-Programming</link>
            <guid>https://velog.io/@geon-2/Functional-Programming</guid>
            <pubDate>Tue, 04 Jun 2024 12:55:53 GMT</pubDate>
            <description><![CDATA[<h2 id="programming-paradigm">Programming Paradigm</h2>
<blockquote>
<p>패러다임이란 한 시대의 사람들의 견해나 사고를 근본적으로 규정하고 있는 테두리로서의 인식의 체계, 또는 사물에 대한 이론적인 틀이나 체계를 의미하는 개념이다. </p>
</blockquote>
<p>출처: <a href="https://ko.wikipedia.org/wiki/%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84">https://ko.wikipedia.org/wiki/패러다임</a></p>
<blockquote>
</blockquote>
<p>프로그래밍 패러다임이란 말 그대로 프로그래밍의 패러다임 형태를 정의하는 것이다. 이것은 프로그래머에게 프로그래밍의 관점을 갖게 해 주고, 결정하는 역할을 한다. 각각의 프로그래밍 언어들은 서로 다른 프로그래밍 패러다임을 지원하며, 다수의 패러다임을 지원하는 경우도 존재한다.</p>
<p>프로그래밍 패러다임은 크게 두가지 종류로 나뉜다.</p>
<ul>
<li>절차형 프로그래밍(Imperative programming)<ul>
<li>절차적 프로그래밍(Procedural programming)</li>
<li>객체지향적 프로그래밍(Object-oriented programming)객체 기반의 패러다임</li>
</ul>
</li>
<li>선언형 프로그래밍(Declarative programming)<ul>
<li>함수형 프로그래밍(Functional programming)</li>
<li>논리형 프로그래밍(Logic programming)</li>
<li>리액티브 프로그래밍(Reactive programming)</li>
</ul>
</li>
</ul>
<h2 id="functional-programming">Functional Programming</h2>
<blockquote>
<p>함수형 프로그래밍은 자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임의 하나이다. 함수의 응용을 강조하며, 계산가능성, 결정문제, 함수정의, 함수응용과 재귀를 연구하기 위해 개발된 형식체계인 <a href="https://ko.wikipedia.org/wiki/%EB%9E%8C%EB%8B%A4_%EB%8C%80%EC%88%98">람다 대수</a>에 근간을 두고 있다.</p>
</blockquote>
<p>출처: <a href="https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98%ED%98%95_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D">https://ko.wikipedia.org/wiki/함수형_프로그래밍</a></p>
<blockquote>
</blockquote>
<p>함수형 프로그래밍이란 <strong>순수 함수(pure function)</strong>를 조합하고 <strong>공유 상태(shared state)</strong>, <strong>변경 가능한 데이터(mutable data)</strong> 및 <strong>부작용(side-effects)</strong>을 피하여 소프트웨어를 만드는 프로세스다.</p>
<p>개념이 좀 어려워 보이는데 하나씩 풀어서 해석해보자.</p>
<h3 id="순수-함수pure-functions">순수 함수(Pure functions)</h3>
<p>순수 함수는 다음과 같다</p>
<ul>
<li>같은 입력이 주어지면, 항상 같은 출력을 반환</li>
<li>Side Effect가 없음. (외부 상태를 변경하지 않음)</li>
</ul>
<p>입력에만 의존하고 외부의 상태를 변경하지 않으며, 동일한 입력에 대해 항상 동일한 출력을 반환한다.</p>
<p>즉, 이름 그대로 정해진 값만 순수하게 반환할 뿐 그 이외의 어떤 것도 변경하지 않는 함수를 말한다.</p>
<pre><code class="language-jsx">function add(a, b) {
    return a + b;
}

// 동일한 input에 해당되는 동일한 output을 반환
console.log(add(3, 5)); // output: 8
console.log(add(3, 5)); // output: 8</code></pre>
<h3 id="공유-상태shared-state와-불변성immutability">공유 상태(Shared state)와 불변성(Immutability)</h3>
<p>함수형 프로그래밍에서는 공유 상태를 피하고, 데이터의 불변성을 유지한다. 이는 한 번 생성된 데이터는 변경되지 않으며, 새로운 데이터를 생성할 때 기존 데이터를 변경하는 대신 새로운 데이터를 반환한다.</p>
<p>이렇게 말해도 어려우니까 좀 더 쉽게 설명해보겠다.</p>
<h4 id="값에-의한-호출call-by-value-vs-참조에-의한-호출call-by-reference">값에 의한 호출(Call by value) vs 참조에 의한 호출(Call by reference)</h4>
<p>프로그램이 메모리에 저장된 값을 호출하는 방식은 두 가지가 있다.</p>
<ul>
<li>값에 의한 호출: 메모리에 저장된 값만을 호출하는 방식</li>
<li>참조에 의한 호출: 메모리에 할당된 공간 즉, 주소를 참조하는 방식</li>
</ul>
<p>‘값에 의한 호출’은 저장된 값을 복사하여 가져오기 때문에 실제 값에는 영향이 가지 않지만, ‘참조에 의한 호출’은 값이 저장된 메모리 주소를 가져와 실제 값에 영향을 미친다.</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/14d0c5bb-e7c9-46aa-85f5-89e8f546728a/image.gif" alt=""></p>
<p>함수형 프로그래밍에서는 두 가지 방식 중 <strong>‘값에 의한 호출’</strong>을 사용한다.</p>
<p>한가지 예를 들어 보겠다.</p>
<pre><code class="language-jsx">function foo(str) {
    return str.substring(0, 2);
}</code></pre>
<p> <strong>foo</strong>  함수는 문자열의 2번째 글자까지 반환해주는 함수이다. 즉, 문자열을 수정하여 반환해준다.</p>
<pre><code class="language-jsx">const str = &quot;Hello, World&quot;;

foo(str); // output: He</code></pre>
<p> <strong>foo</strong>  함수는 ‘<strong>str’</strong> 변수를 수정하여 ‘He’라는 값을 반환하였다. 이제, 기존의 str을 출력해보자.</p>
<pre><code class="language-jsx">console.log(foo(str)); // output: He
console.log(str); // output: Hello, World</code></pre>
<p>처음 할당한 값이 그대로 반환된 것을 볼 수 있다.</p>
<p>함수형 프로그래밍에서는 값에 의한 호출을 사용하기 때문에 기존에 값이 그대로 저장된 것을 볼 수 있다. 만약, 참조에 의한 호출을 사용하였다면 값이 ‘He’로 변경되었겠지만, 그렇지 않기 때문에 변경되지 않았다.</p>
<p>이제 아까했던 말을 다시 보자.</p>
<p>함수형 프로그래밍에서는 공유 상태를 피하고, 불변성을 유지한다고 했었다.</p>
<ul>
<li>공유 상태를 피하다 → 공유하지 않는다 → 함수와 값을 공유하지 않는다</li>
<li>불변성을 유지한다 → 값의 변경이 없다</li>
</ul>
<p>함수는 값을 공유하지 않기 때문에 실제 값에 영향을 미치지 않고, 이것은 값을 변경하지 않는다는 말과 같다. 즉, 한번 생성된 데이터는 변경되지 않으며, 새로운 데이터가 생성될 때는 기존의 데이터를 유지한 채 새로운 데이터를 반환한다.</p>
<h3 id="부작용side-effects">부작용(Side Effects)</h3>
<p>흔히 아는 그 말과 비슷하다. 말 그대로 어떤 것이 기대하는 효과 외에 나타나는 부수적인 효과를 의미한다. 보다 프로그래밍적으로 이야기하자면 부작용은 함수가 외부의 상태를 변경하거나 다른 부수 효과를 발생시키는 것을 말한다.</p>
<p>순수 함수에 특징에서 말했던 부작용이 없다는 의미는 외부의 상태를 변경하는 등의 다른 부수 효과를 발생시키지 않아 예측된 결과만을 반환한다는 의미이다.
함수형 프로그래밍에서는 이러한 부작용을 최소화하여 코드를 예측 가능하고 안정적으로 유지한다.</p>
<p>이를 보다 깊게 이해하기 위해서는 클로저라는 개념을 알아야 한다.</p>
<h4 id="클로저closure">클로저(Closure)</h4>
<blockquote>
<p>“A closure is the combination of a function and the lexical environment within which that function was declared.”</p>
<p>클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)과의 조합이다.</p>
<p>출처: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures</a></p>
</blockquote>
<p>위에서 이야기 하는 렉시컬 환경은 함수가 정의된 스코프에서 사용할 수 있는 변수들의 집합을 나타낸다.</p>
<p>말이 좀 어려운데 쉽게 이야기 하자면 함수를 정의할 때 그 함수 내에서 사용할 수 있는 변수들의 집합을 말하는 것이다. </p>
<p>흔히 이야기 하는 전역 변수, 지역 변수가 위에서 이야기 하는 내용과 이어진다.</p>
<pre><code class="language-jsx">let globalNum = 1;

function scope1 () {
    let num = 2;

    console.log(num, globalNum);
}

function scope2 () {
    let num = 3;

    console.log(num, globalNum);

    num++;
    globalNum++;
}

scope1(); // output: 2, 1
scope2(); // output: 3, 1
scope1(); // output: 2, 2</code></pre>
<p>scope1과 scope2는 사용할 수 있는 변수가 각각 정해져 있다.</p>
<ul>
<li>globalNum은 함수 밖에서 선언되어 모든 함수가 사용할 수 있다. 흔히 이것을 <strong>전역 변수</strong>라고 한다.</li>
<li>num은 각각의 함수 내에서 선언되었기 때문에 선언된 함수 내에서만 사용할 수 있다. 흔히 이것을 <strong>지역 변수</strong>라고 한다.</li>
</ul>
<p>지역 변수인 num들은 해당 함수 안에서만 영향을 미치지만, 전역 변수인 globalNum은 함수 외부적으로 영향을 미치는 것을 볼 수 있다.</p>
<p>함수들이 해당 변수들을 사용할 수 있는 이유는 클로저가 해당 변수들을 사용할 수 있는 범위를 지정하고 기억하였기 때문이다.
<br>
그렇다면 클로저와 부작용이 어떤 관계가 있는 것일까?</p>
<p>클로저는 함수형 프로그래밍에서 부작용을 줄일 수 있는 도구로 작용한다. 클로저가 함수가 영향을 미칠 수 있는 범위를 지정하여 외부로의 주는 영향을 차단하기 때문이다. 또한, 클로저가 생성됨을 알고 있기 때문에 우리는 함수가 미치는 영향을 예측할 수 있다.</p>
<p>즉, 클로저를 통해 부작용을 예측할 수 있고, 최소화할 수 있는 것이다.</p>
<br>
다음과 같은 특징들로 인한 함수형 프로그래밍의 장점은 다음과 같다.

<ul>
<li>함수의 테스트가 쉽고 가독성이 좋음</li>
<li>함수들 간의 결합, 조합이 간결해지며, 익명 함수를 사용할 수 있음</li>
<li>코드 재사용성이 높음</li>
<li>깔끔하고 유지보수가 용이함</li>
</ul>
<hr>
<h3 id="reference">Reference</h3>
<blockquote>
<p>Wikipedia, Programming paradigm, <a href="https://en.wikipedia.org/wiki/Programming_paradigm">https://en.wikipedia.org/wiki/Programming_paradigm</a></p>
</blockquote>
<p>Wikipedia, 함수형 프로그래밍, <a href="https://ko.wikipedia.org/wiki/%ED%95%A8%EC%88%98%ED%98%95_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D">https://ko.wikipedia.org/wiki/함수형_프로그래밍</a></p>
<blockquote>
</blockquote>
<p>MDN Web docs, Closure, <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures">https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures</a></p>
<blockquote>
</blockquote>
<p>Dico’s_footPrint.log, [Javascript] Functional Programming(함수형 프로그래밍), <a href="https://velog.io/@grinding_hannah/JavaScript-Functional-Programming%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D">https://velog.io/@grinding_hannah/JavaScript-Functional-Programming함수형-프로그래밍</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git WorkFlow]]></title>
            <link>https://velog.io/@geon-2/Git-WorkFlow</link>
            <guid>https://velog.io/@geon-2/Git-WorkFlow</guid>
            <pubDate>Tue, 04 Jun 2024 12:46:14 GMT</pubDate>
            <description><![CDATA[<h2 id="workflow의-중요성">Workflow의 중요성</h2>
<p>지난 시간에 공부했듯이 Git으로 프로젝트를 관리할 때는 브랜치로 관리한다. 브랜치를 활용하여 손쉽게 백업하고 분할 작업이 가능하도록 하여, 보다 안전하고 효율적으로 작업할 수 있다. </p>
<p>그렇다고 무턱대고 브랜치를 생성하다보면 각 브랜치의 역할을 구분하기가 불가능해지면서 작업이 난잡해지기 때문에 결국에는 대참사로 이어질 가능성이 있다.</p>
<p>우리는 이것을 방지하기 위해 생성할 브랜치의 역할을 미리 명시할 필요가 있다.</p>
<h2 id="git-workflow">Git Workflow</h2>
<p>Git Workflow는 브랜치를 사용하는 규칙들을 명시해둔 개념이며, 대표적으로 <strong>Git Flow</strong>, <strong>Github Flow</strong>, <strong>Gitlab Flow</strong> 가 있다.</p>
<h3 id="git-flow">Git Flow</h3>
<p><img src="https://velog.velcdn.com/images/geon-2/post/8f4cf5b2-4019-416c-92d3-3ec947c18b73/image.png" alt=""></p>
<p>가장 대표적인 브랜치 전략로 대규모 프로젝트에 적합하다.</p>
<p>5가지 종류의 브랜치로 관리된다.</p>
<ul>
<li>master(main): 제품으로 출시될 수 있는 브랜치</li>
<li>develop: 다음 출시 버전을 개발하는 브랜치</li>
<li>feature: 기능을 개발하는 브랜치</li>
<li>release: 이번 출시 버전을 준비하는 브랜치</li>
<li>hotfix: 출시 버전에서 발생한 버그를 수정하는 브랜치</li>
</ul>
<p><strong>master</strong>는 배포된 상태의 버전이 포함되어 있기 때문에 프로젝트의 원본이 저장된 브랜치라고 할 수 있다.</p>
<p><strong>develop</strong>은 원본 파일을 수정하는 것은 위험하기 때문에 만들어진 복사본으로 실질적인 메인 브랜치 역할을 한다.</p>
<p><strong>feature</strong>는 말그대로 기능을 개발하는 브랜치이다. 예를 들어, 로그인 기능을 추가하고 싶다고 한다면 ‘feature/login’ 이라고 생성하여 기능을 개발한다.</p>
<p><strong>release</strong>는 develop에서 개발된 기능들을 출시하기 전에 테스트를 위해 사용되는 브랜치이다. QA 등을 release 브랜치에서 진행하고, 정상적으로 완료되면 master 브랜치에 merge된다.</p>
<p><strong>hotfix</strong>는 치명적인 버그가 발생한 경우 빠르게 대응하기 위해 master 브랜치에서 생성하여 사용한다.</p>
<p>Git Flow는 Vincent Driessen이 2010년 블로그에 올린 <a href="https://nvie.com/posts/a-successful-git-branching-model/">A successful Git branching</a> 이라는 글이 인기를 끌며 현재까지 가장 대중적으로 사용하고 있는 전략이다. <strong>안정성과 신뢰성</strong>을 바탕으로 설계된 <strong>프로세스의 명확성</strong> 때문에 많은 프로젝트에서 사용 되었다. 하지만, 장점이 명확한 만큼 한계점도 명확하다.</p>
<h4 id="git-flow의-한계">Git Flow의 한계</h4>
<p>Vincent Driessen이 해당 글을 올린지 10년이 지난 2020년에 포스팅 위에 반성의 글(Note of Reflection)을 적는다. 누군가가 블로그에 잘 요약해두어서 가져와 봤다. </p>
<blockquote>
<p><em>Git-Flow는 등장하고 10년 넘게 표준처럼 자리잡고, 더 나아가 마치 만병통치약처럼 사용되었다. 현재는 <strong>Git으로 관리되는 인기있는 유형의 소프트웨어가 웹 어플리케이션으로 이동</strong>하고 있다. <strong>웹 어플리케이션은 일반적으로 롤백되지 않고, 지속적으로 제공(Continuous Delivery)</strong>되므로 <strong>여러 버전의 소프트웨어를 지원할 필요가 없다</strong>.</em></p>
<p><em>웹 어플리케이션은 내가(Vincent Driessen) 10년전 블로그 글을 쓸때에는 염두해둔 소프트웨어 유형이 아니다. <strong>팀이 소프트웨어를 지속적으로 제공</strong>한다면, Git Flow 대신 <strong>Github Flow와 같은 더 단순한 워크플로우</strong>를 채택할 것을 제안한다.</em></p>
<p><em>그러나 명시적으로 버전을 관리해야하는 소프트웨어를 개발한다면, 여전히 Git Flow가 적합할 수 있다.</em></p>
</blockquote>
<p>간단하게 말해서 CI/CD 파이프라인에는 적합하지 않다는 의미이다. 명시적으로 버전을 관리해야 하는 오픈소스 라이브러리/프레임워크, 스마트폰 어플리케이션 등의 프로젝트에는 적합하지만, 웹 같이 단일 버전이 지속적으로 제공되어야 하는 프로젝트의 경우에는 병렬적으로 버전을 지원할 필요가 없기 때문에 비 효율적이라는 것이다. 그래서 그 경우에는 보다 단순한 workflow를 사용할 필요가 있다.</p>
<h3 id="github-flow">Github flow</h3>
<p><img src="https://velog.velcdn.com/images/geon-2/post/195d6e29-eed5-41f9-b75b-3ed2aacab7b1/image.png" alt=""></p>
<p>Vincent Driessen이 언급한 Github Flow는 이름 그대로 Github 환경에서 사용하기 적합한 브랜치 전략이다.</p>
<p>2가지 종류의 브랜치로 운영되기 때문에 상당히 단순하다</p>
<ul>
<li>Master: 메인 브랜치로 모든 커밋이 빌드되어 있음</li>
<li>Topic: 새로운 기능 개발과 버그 수정을 위한 브랜치</li>
</ul>
<p>Git Flow 기준으로 develop, release는 없애고, feature, hotfix를 <strong>topic</strong>이라는 하나의 브랜치로 묶었다.</p>
<h4 id="master-브랜치">Master 브랜치</h4>
<p>가장 큰 특징이자 Github Flow가 강제하는 유일한 사항은 <strong>Master 브랜치</strong>는 항상 <strong>Stable</strong>해야 한다는 것이다. Master의 모든 커밋은 언제 배포하든 문제 없어야 하고, 언제든 브랜치를 새로 만들어도 문제가 없어야 한다. 따라서, Master 브랜치의 모든 커밋은 빌드가 되고, 테스트를 통과해야한다.</p>
<h4 id="topic-브랜치">Topic 브랜치</h4>
<p>Topic 브랜치의 이름은 기능을 설명하는 명확한 이름으로 네이밍한다. 예를들어, <strong>user-content-cache-key</strong>, <strong>submodules-init-task</strong> 등과 같이 말이다.</p>
<p>또 다른 특징은 Topic 브랜치의 모든 커밋은 기능이 완성되지 않았더라도 꾸준히 Push 한다는 것이다. 이것은 곧 구성원끼리의 <strong>끊임없는 커뮤니케이션</strong>을 가능하게 해준다. 또한, 이것은 Github의 PR과 이어진다.</p>
<h4 id="pull-request">Pull Request</h4>
<p>Github에는 PR(Pull Request)라는 기능이 존재한다. 브랜치끼리 비교하여 변경내역을 보여주는 기능이다. 개발자들은 개설된 PR에서 코드리뷰를 주고 받고, Merge여부를 결정한다. PR을 통해 자연스로운 코드 리뷰가 가능해진다.</p>
<h3 id="gitlab-flow">GitLab Flow</h3>
<p><img src="https://velog.velcdn.com/images/geon-2/post/beed0f10-d9b9-4b81-a5db-51712f13b4ac/image.png" alt=""></p>
<p>단순하여 출동에 대처하기 힘든 Github Flow의 단점을 보완하기 위해 나온 전략이다.</p>
<p>4가지 종류의 브랜치로 운영된다.</p>
<ul>
<li>master: Git Flow의 develop와 동일한 역할로 개발 단계의 코드가 포함된 브랜치이다.</li>
<li>feature: 특정한 기능을 구현하는 브랜치로, 구현이 완료되면, master 브랜치로 PR을 날린다.</li>
<li>production: Git Flow의 master 브랜치와 동일한 역할로 배포될 코드가 포함된 브랜치이다.</li>
<li>pre-production: 배포 전에 테스트를 위한 브랜치로, 정상적으로 완료되면 production과 master 브랜치로 PR을 날린다.</li>
</ul>
<p>가장 큰 장점은 pre-production 브랜치로 테스트함으로써 안정성을 확보함과 동시에 내장된 CI/CD 파이프라인을 제공하여 배포를 자동화할 수 있다는 점이다.</p>
<p>안정성이 확보된 프로젝트에서는 Github Flow가 더 효율적이지만, 더 복잡하거나 큰 규모의 프로젝트에서 Github Flow보다 더 효율적이다.</p>
<hr>
<h3 id="reference">Reference</h3>
<blockquote>
</blockquote>
<p>나동호, 2017.08.30, 우린 Git-flow를 사용하고 있어요, <a href="https://techblog.woowahan.com/2553/">https://techblog.woowahan.com/2553/</a></p>
<blockquote>
<p>Vincent Driessen, 2020.03.05, A successful Git branching model, <a href="https://nvie.com/posts/a-successful-git-branching-model/">https://nvie.com/posts/a-successful-git-branching-model/</a></p>
<p>Hudi, 2022.08.03, Git 브랜치 전략 (feat. Git Flow, Github Flow), <a href="https://hudi.blog/git-branch-strategy/">https://hudi.blog/git-branch-strategy/</a></p>
<p>Github, <a href="https://githubflow.github.io/">https://githubflow.github.io/</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git branch]]></title>
            <link>https://velog.io/@geon-2/Git-branch</link>
            <guid>https://velog.io/@geon-2/Git-branch</guid>
            <pubDate>Tue, 04 Jun 2024 12:39:26 GMT</pubDate>
            <description><![CDATA[<h2 id="git-branch">Git branch</h2>
<p>이전 장에서 언급하였듯이 이번 장에서는 <strong>branch</strong>라는 것을 다루어볼 것이다.</p>
<p>개발을 하다보면 코드를 여러 개로 복사하여 작업하여야 하는 경우가 생긴다. 예를 들어, 현재 배포된 서비스에서 새로운 기능을 추가하고 싶을 때, 원본 코드 위에서 작업을 하면 손상될 가능성이 있기 때문에 안전하게 복사본 위에서 작업을 한다. 이러한 경우가 많기 때문에 대부분의 DVCS는 이러한 기능을 제공하는데, Git의 branch 모델은 특히 강력한 기능을 제공한다.</p>
<h3 id="branch-생성">branch 생성</h3>
<pre><code class="language-bash">$ git branch 브랜치명</code></pre>
<p>새로운 branch를 생성하기 위해서는 branch라는 옵션 뒤에 브랜치명을 입력하면 된다.</p>
<p>테스트를 위해 파일을 하나 만들었다.<img src="https://velog.velcdn.com/images/geon-2/post/7843fbad-8a0d-4fd3-b2cd-3f163045be7e/image.png" alt=""><img src="https://velog.velcdn.com/images/geon-2/post/e5268307-ee08-479e-9613-7ce955153df6/image.png" alt="">
잘 작동하고 있는 웹페이지에 이쁜 스타일을 적용하고 싶다. 하지만 원본 파일 위에 수정하면 불안하기 때문에 branch를 하나 만들어서 작업할 것이다.
<img src="https://velog.velcdn.com/images/geon-2/post/e876995f-d6db-4772-b9d8-0768c13490b0/image.png" alt=""></p>
<p>생성한 branch로 변경하고 싶으면 <strong>switch</strong> 옵션을 사용하면 된다.</p>
<pre><code class="language-bash">$ git switch 브랜치명</code></pre>
<p><img src="https://velog.velcdn.com/images/geon-2/post/cd252b9b-0e59-4173-8fd6-ff98c6439577/image.png" alt=""></p>
<p>현재 branch가 master에서 style로 잘 변경되었다. 이제 안전하게 작업할 수 있을 것 같다!
<img src="https://velog.velcdn.com/images/geon-2/post/2a6697f2-68f5-4d98-ae65-193bf0a5c7d0/image.png" alt=""></p>
<p>‘style’ branch에서 style.css 파일을 하나 만들고 커밋까지 해보았다.</p>
<p>이 상태에서 다시 ‘master’ branch로 이동하면 어떻게 될까?
<img src="https://velog.velcdn.com/images/geon-2/post/ddf8048e-f3b7-4c7b-94cd-aaa232933138/image.png" alt=""></p>
<p>놀랍게도 style.css 파일이 존재하지 않는다는 표시가 뜬다. 이렇게 branch는 작업 공간 자체를 분할 해주어서 쉽게 백업이 가능하도록 한다.
<img src="https://velog.velcdn.com/images/geon-2/post/c2eb2820-437e-49e9-9ada-0bca9849cbba/image.png" alt=""></p>
<p>이쁘게 잘 수정된 것 같으니 이제 원본 프로젝트에 적용해보고 싶다. 그러기 위해선 원본 branch로 이동해야 한다.</p>
<pre><code class="language-bash">$ git switch master

$ git merge 브랜치명</code></pre>
<p><strong>merge</strong> 옵션 뒤에 병합된 브랜치명을 입력하면 현재 브랜치에 병합된다.
<img src="https://velog.velcdn.com/images/geon-2/post/dcb85fb7-1fac-4efd-9412-224fa5167a7f/image.png" alt=""></p>
<p>master branch에도 style.css가 정상적으로 추가 되었다.</p>
<h3 id="conflict">Conflict</h3>
<p>merge할 때는 주의할 점이 있다. 바로 같은 부분을 편집하는 경우이다. 위의 경우 style.css라는 새로운 파일을 작업한 것이기 때문에 상관없지만, 같은 파일의 같은 라인을 편집한 경우 <strong>conflict</strong>가 발생한다.</p>
<p>직접 확인해보기 위해 index.html의 h1 안의 텍스트를 수정해보겠다.
<img src="https://velog.velcdn.com/images/geon-2/post/ab553b8f-a547-4248-9717-49c118dce990/image.png" alt="">
<img src="https://velog.velcdn.com/images/geon-2/post/c4fa6ba8-fa6a-4dda-b32d-76dd450347f7/image.png" alt=""></p>
<p>이 상태에서 merge를 해보자</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/bd597704-7c28-4b01-992b-6d3b37df3c57/image.png" alt=""></p>
<p>그러면 다음과 같이 h1부분에서 충돌이 일어났다고 표시가 된다. 컴퓨터는 어떤 것을 기준으로 merge 할지 판단할 수 없기 때문에 conflict에는 수동으로 수정을 해주어야 한다.</p>
<p>수정 이후에는 동일하게 git에 add, commit, push 해주면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 시작하기]]></title>
            <link>https://velog.io/@geon-2/Git-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@geon-2/Git-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 04 Jun 2024 12:21:32 GMT</pubDate>
            <description><![CDATA[<h2 id="git-이란">Git 이란?</h2>
<p>Git은 가장 많이 사용되는 DVCS(분산 버전 관리 시스템)이다. 기존의 델타 방식 시스템과 다른 점은 데이터를 스냅샷의 스트림처럼 취급한다는 점이다. 변경 사항이 생길 경우 변경된 부분만 저장하는 것이 아닌 파일 시스템 전체를 저장한다. 이러한 스냅샷들이 모여서 시간의 흐름에 따라 변경된 내용을 추적하는 방식으로 데이터를 관리 한다.</p>
<p>Git의 장점은 다음과 같다.</p>
<h3 id="로컬-명령">로컬 명령</h3>
<p>거의 모든 명령이 로컬 파일과 데이터만 사용하기 때문에 네트워크가 없는 환경에서도 작업이 가능하다. 히스토리 조회나 커밋을 할 때도 로컬 파일 내에서 할 수 있기 때문에 네트워크가 없는 환경에서도 순조롭게 작업이 가능하다.</p>
<h3 id="병렬-개발">병렬 개발</h3>
<p>위의 장점에서 이어지는 항목인데, 네트워크 환경이 없는 곳에서 개발이 가능한 이유는 병렬 개발이 가능하기 때문이다. Git에는 브랜치라는 기능이 존재하는데, 이를 활용하면 각각의 독립적인 개발 라인을 하나의 프로그램으로 병합하는 것이 가능하다.</p>
<h2 id="시작하기">시작하기</h2>
<hr>
<h3 id="github">Github</h3>
<p>Git을 사용하기 위해서는 로컬 파일을 저장하는 저장소가 필요하다. 이는 ‘<strong>Github’</strong>이라는 서비스가 수행하는데, 이를 사용하기 위해서는 Github.com에 먼저 가입하여야 한다.</p>
<p><a href="https://github.com/">GitHub: Let’s build from here</a></p>
<p>위 링크를 통해 Github에 가입하면 다음과 같은 화면이 나온다.</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/5733f79a-d069-499c-9724-02d3ee18c3c6/image.png" alt=""></p>
<p>Github을 통해 프로젝트를 관리하기 위해서는 우선 각 프로젝트를 관리할 repository(저장소)가 필요하다. 좌측의 <strong>New</strong> 버튼을 누르면 새로운 repository를 만들 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/c362bd0f-fa4a-4792-bd5e-11f791cf803c/image.png" alt=""></p>
<p>그러면 이러한 화면이 나오는데, 여기서는 이름과 공개 여부만 설정해주면 된다. 그 아래 나머지는 추후에 설정이 가능하기 때문에 지금은 신경쓰지말자</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/0e47b94e-0917-4692-bcb3-a84ab5c047dd/image.png" alt=""></p>
<p>repository를 생성하면 다음과 같은 화면이 나온다.</p>
<p>우리는 여기서 가장 위에 ‘.git’으로 끝나는 주소만 잘 기억하고 있으면 된다.</p>
<h3 id="git-설치">Git 설치</h3>
<p><a href="https://git-scm.com/downloads">Git - Downloads</a></p>
<p>위 링크로 들어가면 Git을 다운로드 할 수 있게 안내해준다.</p>
<p><strong>Windows</strong></p>
<p><a href="https://git-scm.com/downloads">Download for Windows</a></p>
<p><strong>MacOS</strong></p>
<p><a href="https://git-scm.com/download/mac">Download for Mac</a></p>
<pre><code class="language-bash">$ brew install git</code></pre>
<p>Mac은 homebrew로 설치하면 된다.</p>
<p><strong>Linux/Unix</strong></p>
<p><a href="https://git-scm.com/download/linux">Download for Linux/Unix</a></p>
<p>Linux/Unix는 버전에 맞는 명령어를 입력하여 설치한다.</p>
<h2 id="git-config">Git config</h2>
<p>본격적으로 Git을 사용하기 이전에 가장 먼저해야 될 것이다. 설치한 Git에 Github Account 정보를 등록하여야 서버 저장소와 연동이 가능하다. 최초 한번만 설정하면 이후 Git을 사용할 때 매번 지정하지 않아도 된다.</p>
<pre><code class="language-bash">$ git config --global user.name &quot;User Name&quot;
$ git config --global user.email &quot;Example@example.com&quot;</code></pre>
<p>이후 아래 명령어로 잘 등록되었는지 확인할 수 있다.</p>
<pre><code class="language-bash">$ git config --list</code></pre>
<h3 id="git-init">Git init</h3>
<p>config가 완료되었다면 아까 만들어둔 repository에 파일을 업로드할 준비를 할 순서이다.</p>
<p>먼저, 이용할 로컬 저장소로 이동한다. 아까 만든 repository에 업로드 될 파일들이 존재하는 곳이다.</p>
<p>이동하였다면 다음 명령어를 입력해준다.</p>
<pre><code class="language-bash">$ git init</code></pre>
<p>git init은 해당 디렉토리를 로컬 저장소로 지정해주는 명령어다. Git이 해당 디렉토리를 지켜보면서, 내부 파일들의 추가, 수정, 삭제 등을 감지할 수 있게 된다.</p>
<p>다음은 리모트 저장소를 연결하여야 한다.</p>
<pre><code class="language-bash">$ git remote add origin repository-address</code></pre>
<p>repository-address부분에 아까 기억하라고 했던 그 주소(~.git)를 입력하면 된다.</p>
<h3 id="git-add">Git add</h3>
<p>다음은 로컬 저장소 안의 파일들을 <strong>스테이지</strong> 위에 올릴 차례이다.</p>
<p>여기서 스테이지라는 용어가 나오는데, 이를 알기 위해서는 Git에서의 <strong>세 가지 상태</strong>를 먼저 알아야 한다.</p>
<h4 id="git의-세-가지-상태">Git의 세 가지 상태</h4>
<blockquote>
<p>💡 Git의 세 가지 상태 (출처: <a href="https://git-scm.com/book/ko/v2/%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-Git-%EA%B8%B0%EC%B4%88">https://git-scm.com/book/ko/v2/시작하기-Git-기초</a>)</p>
<p>Git은 파일을 <strong>Commited</strong>, <strong>Modified</strong>, <strong>Staged</strong> 이렇게 세 가지 상태로 관리한다.</p>
<ul>
<li>Committed란 데이터가 로컬 데이터베이스에 안전하게 저장됐다는 것을 의미한다.</li>
<li>Modified는 수정한 파일을 아직 로컬 데이터베이스에 커밋하지 않는 것을 의미한다.</li>
<li>Staged란 현재 수정한 파일을 곧 커밋할 것이라고 표시한 상태를 의미한다.
<img src="https://velog.velcdn.com/images/geon-2/post/97b46b5c-634b-4c96-98e5-f83c1414bcb3/image.png" alt=""></li>
</ul>
</blockquote>
<p>Git의 공식 사이트에서는 세 가지만 언급하고 있지만, 좀 더 명확하게 이해하기 위해서는 <strong>unmodified</strong> 상태를 추가하여 네 가지 상태로 이해하는 것이 좋다. 로컬 저장소에서 파일이 관리되는 순서는 다음과 같다.</p>
<ol>
<li>Working Directory에 존재하는 파일을 수정 (unmodified → modified)</li>
<li>수정된 파일을 스테이징하여 Staging Area에 올림 (modified → staged)</li>
<li>스테이징한 파일들을 커밋하여 Repository에 기록함 (staged → commited)</li>
</ol>
<p>위에서 스테이지 위에 올린다는 의미는 수정된 파일 즉, modified 상태인 파일을 Staging Area에 올린다는 의미이다. 우리는 이것을 <strong>스테이징</strong>(staging)이라고 한다.</p>
<pre><code class="language-bash">$ git add .

# or

$ git add 파일명</code></pre>
<p>add 다음의 ‘.’은 모든 파일을 의미한다. 특정 파일만 스테이지 위에 올리고 싶으면 ‘.’ 위치에 해당 파일명을 적으면 된다.</p>
<h3 id="git-commit">Git Commit</h3>
<p>드디어 커밋을 해볼 차례이다!</p>
<p>커밋이란 수정되기 전 파일로부터 수정된 후 파일이 되기까지의 변경 이력을 기록해 놓는 것이라고 할 수 있다. </p>
<p>위에서 언급했듯이 staged 상태인 파일들을 커밋하면 commited 상태로 변경되며, repository에 기록된다.</p>
<p>-m 이라는 옵션을 사용하면 커밋 메시지를 적을 수 있는데, 여기에 자신이 어떤 파일을 어떻게 수정했는지 기록할 수 있다.</p>
<pre><code class="language-bash">$ git commit -m &quot;커밋 메시지&quot;</code></pre>
<p>로컬에서 그동안의 커밋 내역들을 보고 싶으면 다음 명령어로 확인하면된다.</p>
<pre><code class="language-bash">$ git log</code></pre>
<h3 id="git-push">Git Push</h3>
<p>커밋된 파일들은 리모트 저장소에 업로드할 수 있다.</p>
<pre><code class="language-bash"># git push (리모트 저장소 별칭) (브랜치명)
$ git push origin master</code></pre>
<p>마지막에 <strong>브랜치명</strong>은 다음 파트에 좀 더 자세하게 설명하겠지만, 일반적으로 처음 생성하면 <strong>master</strong> 또는 <strong>main</strong> 이라는 이름으로 생성된다.</p>
<p><img src="https://velog.velcdn.com/images/geon-2/post/35c005f0-e3fc-4422-b888-61a786704051/image.png" alt=""></p>
<p>결과적으로 잘 업로드 된 것을 볼 수 있다.</p>
<hr>
<h3 id="reference">Reference</h3>
<blockquote>
<p>Git, 1.3 시작하기 - Git 기초, <a href="https://git-scm.com/book/ko/v2/%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-Git-%EA%B8%B0%EC%B4%88">https://git-scm.com/book/ko/v2/시작하기-Git-기초</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[버전 관리란?]]></title>
            <link>https://velog.io/@geon-2/%EB%B2%84%EC%A0%84-%EA%B4%80%EB%A6%AC%EB%9E%80</link>
            <guid>https://velog.io/@geon-2/%EB%B2%84%EC%A0%84-%EA%B4%80%EB%A6%AC%EB%9E%80</guid>
            <pubDate>Tue, 04 Jun 2024 12:15:46 GMT</pubDate>
            <description><![CDATA[<h3 id="버전-관리란">버전 관리란?</h3>
<p><strong>‘버전 관리(Version Control)’</strong>는 파일 변경 사항을 시간에 따라 기록하고, 필요할 때 특정 버전을 다시 호출할 수 있는 시스템을 일컫는 말이다.</p>
<p>간단하게 설명하자면 동일한 정보에 대해 여러 버전을 정의하고 관리하는 것을 의미한다.</p>
<p>소프트웨어 엔지니어링 내에서는 소프트웨어의 소스 코드의 변경 사항을 추적한 내역을 ‘버전 관리’라고 칭한다.</p>
<blockquote>
<p>✏️ <strong>형상 관리와 버전 관리</strong></p>
<ul>
<li><strong>버전 관리</strong>(Version Control): 동일한 정보에 대한 여러 버전을 관리</li>
<li><strong>형상 관리</strong>(Configuration Management): 소프트웨어의 변경사항을 체계적으로 관리</li>
</ul>
<p>형상 관리는 버전 관리를 포함한 소프트웨어 프로젝트와 관련된 모든 변경 사항을 관리한다는 개념이다.
실무에서는 명확하게 구분되어 있지 않고 대체로 비슷한 의미로 사용된다고 한다.</p>
</blockquote>
<br>

<h3 id="버전-관리는-왜-필요한가">버전 관리는 왜 필요한가?</h3>
<p>버전 관리를 하는 이유는 다음과 같다.</p>
<ol>
<li><p><U><strong>히스토리 추적 및 관리</strong></U>
소프트웨어의 이전 버전(이력)을 흔히 히스토리라고 한다. 버전 관리 시스템은 필요한 경우 특정 버전으로 쉽게 롤백할 수 있는 기능을 제공한다. 이를 통해 추가, 수정, 삭제 과정에서 <span style="color:red">발생할 수 있는 예측 불가능한 위험을 줄일 수 있어</span> 대규모 개발 과정을 보다 안전하게 이끌어나갈 수 있다.</p>
</li>
<li><p><U><strong>백업 및 복구</strong></U>
히스토리 추적이 쉽다는 것은 곧 <span style="color:red">백업 및 복구가 쉽다</span>는 말과 동일하다. 예상치 못한 이슈가 발생하였을 때 되돌릴 수 없는 경우 이미 검증된 버전으로의 롤백을 통해 안전하게 상태를 복구할 수 있다.</p>
</li>
<li><p><U><strong>협업에 필수적</strong></U>
프로젝트에서 버전 관리가 사용되는 가장 큰 이유이다.
대부분의 프로젝트는 여러 명의 개발자가 협업하는 형태로 진행된다. 각각의 개발자들은 할당된 일부 기능들을 따로따로 개발하고 하나의 버전으로 합치는 과정으로 이어진다.
버전 관리 시스템은 이러한 작업 환경을 보다 안전하고 효율적으로 만들어준다.
협업 시 흔히 발생하는 충돌을 방지할 수 있고, 이 충돌을 쉽게 해소할 수 있으며 다른 개발자의 작업 내역을 쉽게 확인할 수도 있다.</p>
</li>
</ol>
<br>

<h3 id="버전-관리-시스템">버전 관리 시스템</h3>
<ol>
<li><p><U>로컬 버전 관리</U>
로컬에서 버전을 관리하기 위해 많은 사람이 디렉토리로 파일을 복사하는 방법을 사용한다. 매우 간단하기 때문에 자주 사용하지만, 실수로 작업하던 디렉토리를 삭제하거나 잘못 수정, 복사할 수 있는 리스크가 있다.
이러한 이유로 오래전에 로컬 VCS라는 것을 만들었다. 이 VCS는 간단한 데이터베이스를 사용해서 파일의 변경 정보를 관리했다.</p>
</li>
<li><p><U>중앙집중식 버전 관리(CVCS)</U>
로컬 VCS는 1인 개발 시엔 용이하지만 다른 개발자와 함께 작업할 때 사용하기엔 한계가 있다. 그래서 이를 위해 개발된 것이 CVCS(중앙집중식 VCS)이다. CVS, Subversion, Perforce 같은 시스템은 파일을 관리하는 서버가 별도로 있고, 클라이언트가 중앙 서버에서 파일을 받아서 사용(Checkout)하는 방식으로 이루어진다.
이러한 방식은 누가 무엇을 하고 있는지 알 수 있기 때문에 관리자가 프로젝트를 꼼꼼하게 관리할 수 있다는 장점이 있다. 하지만, 중앙 서버에서 문제가 발생하는 경우에는 프로젝트 전체가 중단되고, 백업할 수 있는 방법이 없기 때문에 최악의 경우 모든 히스토리를 잃게 되는 치명적인 단점이 존재한다.</p>
</li>
<li><p><U>분산 버전 관리 시스템</U>
이런 치명적인 단점을 보완하기 위해 고안된 시스템이 DVCS(분산 버전 관리 시스템)이다. Git, Mecurial, Bazaar, Darcs가 대표적인데, 이들은 저장소를 히스토리와 더불어 전부 복제한다. clone이라고 불리우는 복제물로 백업이 가능하다. 또한, 대부분의 DVCS 환경에서는 리모트 저장소가 존재하기 때문에 사람들은 동시에 다양한 그룹과 다양한 방법으로 협업할 수 있다.</p>
<br>
</li>
</ol>
<hr>
<h3 id="reference">Reference</h3>
<blockquote>
<p>Git, 1.1 시작하기 - 버전 관리란?, <a href="https://git-scm.com/book/ko/v2/%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-%EB%B2%84%EC%A0%84-%EA%B4%80%EB%A6%AC%EB%9E%80%3F">https://git-scm.com/book/ko/v2/%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-%EB%B2%84%EC%A0%84-%EA%B4%80%EB%A6%AC%EB%9E%80%3F</a></p>
<p>Configuration Management, <a href="https://en.wikipedia.org/wiki/Configuration_management">https://en.wikipedia.org/wiki/Configuration_management</a></p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>