<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ashd_89.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 29 May 2025 03:09:55 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>ashd_89.log</title>
            <url>https://velog.velcdn.com/images/ashd_89/profile/9b0578ca-82ac-4d6a-860b-41fe5d21aa82/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ashd_89.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ashd_89" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[CS-network 3. HTTP]]></title>
            <link>https://velog.io/@ashd_89/CS-network-3.-HTTP</link>
            <guid>https://velog.io/@ashd_89/CS-network-3.-HTTP</guid>
            <pubDate>Thu, 29 May 2025 03:09:55 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ashd_89/post/5544bcc3-f246-4375-93fa-9ce0e8f0aefa/image.png" alt=""></p>
<h2 id="📌-hyper-text-transfer-protocol">📌 HYPER TEXT TRANSFER PROTOCOL</h2>
<h3 id="📖-hypertext란">📖 Hypertext란?</h3>
<p>참조링크를 통해, 독자가 다른 문서로 즉각적으로 이동할 수 있는 문서로 순차적 나열적 구조가 아닌, 사용자가 임의로 나열하는 구조를 가진다.</p>
<h3 id="📖-http란">📖 HTTP란?</h3>
<p><strong>인터넷 상에서 데이터를 주고 받기 위한 프로토콜</strong></p>
<ul>
<li>클라이언트와 서버 간의 통신 (웹사이트를 로드 하는데 필요한 정보를 요청하는 방법)</li>
<li>World Wide Web의 통신 방법</li>
<li>요청 &amp; 응답 방식의 애플리케이션 계층의 통신</li>
<li>단방향성 (하나의 요청에 하나의 응답)</li>
</ul>
<h3 id="📖-http의-단점">📖 HTTP의 단점</h3>
<p><strong>데이터를 평문으로 보낸다</strong></p>
<ul>
<li>도청 및 데이터 변조 + 패킷 가로채기 가능 =&gt; HTTPS (Secure)</li>
</ul>
<h3 id="📖-http-method">📖 HTTP method</h3>
<p><strong>1. GET</strong>
주로 조회에 사용되며, 서버의 데이터를 수정하는데에 사용해서는 안됨
<strong>=&gt; 따라서 GET 요청은 멱등성을 가진다. (다 회 시도에 따른 서버의 변경 및 리턴이 바뀌지 않음)</strong></p>
<ul>
<li>조회 정보를 URL의 쿼리 파라미터로 전달</li>
<li>요청시 본문(Body) 및 ContextType이 없음</li>
<li>캐싱 가능 (캐싱 2번 @Cacheable활용 부분은 후에 추가적으로 redis를 사용하는 부분과 묶어서 글 작성!)</li>
</ul>
<ol>
<li><p>클라이언트 캐싱 (백엔드에서는 유도만)</p>
<pre><code> @GetMapping(&quot;/items/{id}&quot;)
 fun getItemWithETag(
     @PathVariable id: Long,
     request: HttpServletRequest
 ): ResponseEntity&lt;ItemDto&gt; {
     val item = itemService.getItem(id)
     val etag = &quot;\&quot;&quot; + item.hashCode().toString() + &quot;\&quot;&quot;  

     // 클라이언트가 보내온 ETag와 비교
     val clientETag = request.getHeader(&quot;If-None-Match&quot;)
     if (clientETag != null &amp;&amp; clientETag == etag) {
         return ResponseEntity.status(HttpStatus.NOT_MODIFIED).eTag(etag).build()
     }

     return ResponseEntity.ok()
         .eTag(etag)
         .cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS).cachePublic())
         .body(item)
 }</code></pre></li>
</ol>
<h3 id="클라이언트-캐싱-상세-과정">클라이언트 캐싱 상세 과정</h3>
<ol>
<li>서버는 ETag를 응답 헤더에 넣어서 보냄<pre><code>ETag: &quot;123456&quot;
Cache-Control: public, max-age=60</code></pre></li>
<li>클라이언트(브라우저 또는 프록시)가 이 응답을 저장하고
이후 다시 같은 URL 요청 시, 클라이언트는 If-None-Match: 부분을 추가</li>
</ol>
<pre><code>GET /items/1
If-None-Match: &quot;123456&quot;</code></pre><ol start="3">
<li>서버는 현재 데이터로부터 ETag 생성 (hashCode, 또는 content 기반 hash 등)</li>
</ol>
<p><strong>[ 예시에서는 단순히 item을 hash처리해서 ETag 생성 ]</strong></p>
<pre><code>  val etag = &quot;\&quot;&quot; + item.hashCode().toString() + &quot;\&quot;&quot;  </code></pre><p><strong>[ 클라이언트가 보낸 ETag와 동일한지 확인 하는 코드 ]</strong></p>
<pre><code>if (clientETag == etag) {
    return ResponseEntity.status(HttpStatus.NOT_MODIFIED).eTag(etag).build()
}</code></pre><p>서버는 본문(body)을 전혀 보내지 않고,
HTTP 304 Not Modified 응답만 내려줌.
→ 즉, 클라이언트가 기존에 저장한 데이터를 그대로 사용함!</p>
<ol start="2">
<li>@Cacheable을 활용한 서버 측 캐싱 (이후에!!!)<br>

</li>
</ol>
<p><strong>2. POST</strong>
주로 새로운 데이터 생성에 사용되며, 부모 리소스의 하위 리소스를 생성하는데 사용
<strong>=&gt; 따라서 POST 요청은 멱등성을 가지지 못한다. (동일한 요청이라도, 리소스를 중복으로 만들어 다른 리소스가 생성)</strong></p>
<ul>
<li>body를 반드시 포함 (Context-Type도 필수)</li>
<li>정상적으로 리소스가 생성될 시 201(Created)로 응답</li>
</ul>
<p><strong>3. PUT</strong><br>주로 기존 데이터 수정에 사용
<strong>=&gt; 중요!!! PUT 요청은 멱등성을 가진다. (수정은 하나의 리소스를 대상으로 하기 때문에 덮어씌워짐 = 멱등성 보장)</strong></p>
<ul>
<li>body에 변경된 데이터 내용을 반드시 포함 (Context-Type도 필수)</li>
<li>URL을 통해 어떤 리소스 수정할지를 지정해야함 (PUT /member/1)</li>
</ul>
<p><strong>4. DELETE</strong></p>
<p><strong>기타</strong></p>
<ul>
<li><p>HEAD (vs GET) : GET과 유사하지만, 헤더만 조회하기 때문에, body데이터가 없어 더 빠른 조회 가능
예시, HEAD /my-profile/image.png 형식이면, GET 방식에 비해 이미지가 존재하는지, 크기가 얼마인지의 정보를 빠르게 얻을 수 있다.</p>
</li>
<li><p>PATCH (vs PUT) RESTful하게 사용한다면, PUT은 id를 제외 모든 데이터를 덮어씌우고, return을 전체 데이터 / 그에반해 patch는 원하는 속성만 수정하고, return을 수정된 값만 보낸다. </p>
</li>
<li><p><em>=&gt; 즉 PUT은 이론상 해당 리소스의 모든 데이터가 DTO에 포함되어야 하는게 맞음*</em></p>
</li>
<li><p>OPTIONS : 서버에서 지원하는 메서드 목록 확인 </p>
</li>
<li><p>CONNECT : 프록시 동작의 터널 접속 변경 (프록시 서버 역할)</p>
</li>
</ul>
<h3 id="📖-http-응답-코드">📖 HTTP 응답 코드</h3>
<p><img src="https://velog.velcdn.com/images/ashd_89/post/f4b17047-e3fb-4116-ab84-cc48a39b5e59/image.png" alt=""></p>
<h2 id="📌-http10">📌 HTTP/1.0</h2>
<p><strong>하나의 연결에 하나의 요청을 처리(즉 모든 요청마다 3-HANDSHAKE)</strong>
RTT(Round-Trip Time)
클라이언트의 요청에 따라 서버로 응답을 받을 때까지 걸리는 시간 (즉, 왕복 시간)</p>
<ul>
<li>기본적으로 3-HANDSHAKE의 RTT를 1.5</li>
<li>요청 또는 응답 1번의 RTT를 1로 보는데
HTTP/1.0에서는 최소 2.5RTT 연결 및 첫 요청까지 매 요청마다 소비 (비효율적)</li>
</ul>
<p>따라서 이미지를 처리할 때 서버와의 연결을 또 열고, 받는 방식이 매우 부담이 되기 때문에 아래와 같은 방법을 통해 요청을 최소화 함</p>
<ul>
<li>이미지 스플리팅 (하나의 큰 이미지로 받고, 좌표값(css의 postion)으로 나눠서 이미지를 사용)</li>
<li>이미지 Base64 인코딩 (이미지를 64진법의 문자열로 인코딩)
=&gt; 현재 사용 중인 url 방식은 이미지 자체를 보내지 않고, 주소값으로 필요할때 재요청 하는 방식 / Base64는 이미지 자체를 인코딩해서 문자열로 통신에 사용하고, 이를 클라이언트가 직접 디코딩하면 이미지 파일로 만들어지는 방식 (미리보기에 많이 사용됨)</li>
</ul>
<h2 id="📌-http11">📌 HTTP/1.1</h2>
<p><strong>keep-alive 옵션을 통해 한번 연결됬을 때 여러 개의 파일 처리(최초 한번의 요청에서 3-HANDSHAKE 이후 통로를 keep-alive로 열어두는 방식)</strong>
단점 : Head-of-Line Blocking</p>
<h3 id="📖-hol-blocking">📖 HOL Blocking</h3>
<p>HTTP/1.1 처리 흐름 (단일 연결) [HTML-CSS-JS...]
HTML 요청
HTML 응답이 완전히 끝나야
CSS 요청 시작
CSS 응답 끝나야
JS 요청 시작
...</p>
<p>리소스 수가 많을수록 요청이 직렬로 병목 발생
=&gt; CSS 전달 과정이 느리게 받아지게 되면, 후에 받는 JS, JPG 등도 다운로드가 지연됨  </p>
<h2 id="📌-http2">📌 HTTP/2</h2>
<h3 id="📖-spdy란">📖 SPDY란?</h3>
<p>2012년쯤 웹페이지들이 더 많은 리소스로 동적으로 구성되며, 다수의 도메인을 가짐과 동시에, 보안이 중요한 이슈가 되었다. 이에, latency와 보안 측면에서 HTTP를 보완한 SPDY 프로토콜을 GOOGLE에서 발표했다.
-Multiplexing, HTTP 헤더 압축, 바이너리 프로토콜, TLS(Transport Layer Security) 위에서 동작 등의 특징을 가지고 있었지만 HTTP/2로 버전이 업데이트 되며, 현재는 지원이 중단되었다.</p>
<h3 id="📖-multiplexing">📖 Multiplexing</h3>
<p><strong>스트림을 여러개 사용한다.</strong>
특정 스트림에서 병목 현상, 패킷 손실이 발생하더라도, 다른 스트림에는 영향을 주지 않게
=&gt; 데이터를 프레임으로 쪼개서 병렬적으로 처리!
=&gt; 단 하나의 데이터를 쪼갠 프레임은 하나의 스트림에서만!
=&gt; 애플리케이션 단계에서의 HOL Blocking은 해결 가능 (TCP 단계에서는 X)</p>
<blockquote>
<p> *<em>질문 1 : /index.html 파일이 A,B,C 프레임으로 쪼개져서 각 스트림에서 전달된다? =&gt; HTTP/2.0단계에서 이 질문의 잘못된 점과 B프레임이 손실 되었을 때 어떻게 처리 될지를 설명하시오!
*</em></p>
</blockquote>
<h3 id="📖-헤더-압축">📖 헤더 압축</h3>
<p>HTTP/1.1 문제점
요청마다 중복된 헤더가 계속 전송됨 (예: User-Agent, Cookie, Authorization 등) 
리소스가 많은 웹 페이지에서는 → 수십 번 같은 헤더가 반복됨</p>
<p>HPACK(Header Compression for HTTP/2)
클라이언트와 서버가 서로 동일한 헤더 테이블을 가지고 테이블에 이미 존재하는 헤더를 인덱스 번호로 전송하는 방법</p>
<p>허프만 트리 
트리 방식을 참고해서 가장 빈도수 많은 문자를 root = 0으로 해서 빈도수가 적은 값을 위로 위치하게 하는 방식</p>
<ul>
<li>Prefix-Free Code (접두어가 겹칠 수 없게 = 알아보기 쉬움)
0 01 011 이런식이라면 디코딩 과정에서 어디서 끊어야할지 알 수 없음
따라서 상위 비트가 이전 비트와 겹치지 않게 설계
<img src="https://velog.velcdn.com/images/ashd_89/post/b574ed44-befc-48c7-95b1-e558e8bcbb49/image.png" alt="">
결국 특정 문자의 빈도수 현재 표에서는 F의 빈도수가 높으면 높을 수록 압축률이 높다.</li>
</ul>
<p>=&gt; HPACK의 index는 이와 같은 방법으로 생성되어 빈도수가 높을 수록 낮은 비트(적은 용량)를 할당하고, 만약 헤더 테이블에 없으면, 현재 테이블에 허프만 트리 방식으로 index를 설계해서, 추가한다. </p>
<h3 id="📖-서버-푸시">📖 서버 푸시</h3>
<p>기존 HTTP/1.1에서는 HTML -&gt; CSS -&gt; JS -&gt; JPG 순으로 요청이 올때까지 기다려야 했다면, HTML을 요청했을 때, 서버에서 요청을 받기 전에, HTML내에 필요한 CSS, JS, JPG 먼저 전송 가능</p>
<h2 id="📌-http3-https--quic">📌 HTTP/3 (HTTPS + QUIC)</h2>
<p><strong>기존 TCP 사용하던 HTTP/2의 단점을 해결하고자, UDP 방식을 사용하는 HTTP 신규 프로토콜</strong></p>
<h3 id="📖-quicquick-udp-internet-connections">📖 QUIC(Quick UDP Internet Connections)</h3>
<p>이전에 UDP는 TCP에 비해 안정성이 떨어지기 때문에 활용도가 낮다라고 공부한적이 있다. 이를 최신 기술을 통해, UDP의 안정성을 Internet 환경에서 TCP 수준 또는 그 이상으로 만든 것을 QUIC라고 한다.</p>
<p>아래는 기존 UDP 방식에서 QUIC가 되며 바뀐점들 + HTTP/2와 비교한 것</p>
<ol>
<li>안정성 
TCP처럼 패킷 번호를 부여 손실을 확인하고 재전송 요청</li>
</ol>
<ul>
<li>vs TCP : TCP는 손실된 데이터를 ACK를 통해 확인 즉 뭐가 빠진지는 정확히 판단하지 못하는 반면, QUIC 방식은 송신자 측은 RTO(타이머)방식으로 패킷 재전송 시도 및 빠진 패킷 번호를 수신사측에서 확인하고 재요청</li>
</ul>
<ol start="2">
<li>흐름제어
수신자는 네트워크 혼잡도를 확인해 TCP처럼 처리 가능량을 송신자에게 전달 (패킷 유실 방지)
like “한 번에 100KB까지만 보내줘”라고 통지</li>
</ol>
<ul>
<li>vs TCP : 연결 전체 단위 뿐만 아니라 스트림 단위까지 두 가지 레벨의 흐름제어</li>
</ul>
<ol start="3">
<li>복구</li>
</ol>
<p><strong>TCP 단계의 HOL BLOCKING이 없는 복구</strong></p>
<p>스트림 1: [A][B][C]
스트림 2: [X][Y][Z]</p>
<p>[TCP]
→ 만약 [B] 패킷 손실 → TCP는 전체 순서를 멈추고 B 재전송까지 기다림
<strong>→ 스트림 2의 [X], [Y], [Z]도 도착해도 처리 못 함 (HOL 블로킹)</strong></p>
<p>[QUIC]
→ [B] 손실 → QUIC이 [B]만 재요청
<strong>→ [X], [Y], [Z]는 스트림 2로 독립 전송 및 처리 가능</strong>
→ 전체 처리 지연 없음
<br></p>
<p><strong>결론 QUIC는 UDP로 TCP의 거의 모든 장점을 기술로 구현해낸 방식 (동일한 처리 + 속도 우수)</strong></p>
<h3 id="📖-zero-round-trip-time-0-rtt">📖 Zero round-trip time (0-RTT)</h3>
<p>한 번 HTTP 연결이 이루어지고 나면, 클라이언트는 더 이상 handshake를 통해 통신 방법을 확인하려 서로를 확인하는 프로세스를 진행하지 않는다 (간결한 통신)</p>
<h3 id="📖-https가-선택이-아닌-필수">📖 HTTPS가 선택이 아닌 필수</h3>
<ul>
<li>HTTP/2까지는 선택 사항</li>
<li>HTTP/3부터는 TLS 1.3을 내장시켰기 때문에 필수</li>
</ul>
<h2 id="📌-https">📌 HTTPS</h2>
<p><strong>애플리케이션 계층과 전송 계층 사이에 [신뢰 계층] 추가</strong></p>
<h3 id="📖-ssltls">📖 SSL/TLS</h3>
<p><strong>SSL/TLS(신뢰 계층) = 전송 계층에서 보안을 제공하는 프로토콜</strong></p>
<ol>
<li>보안 세션을 위한 키교환 진행 (handshake의 마지막 부분)</li>
<li>보안 세션동안 cyper suites라는 암호화 알고리즘 리스트를 클라이언트와 서버가 통신
(후에 어떤 알고리즘을 써서 암호화해서 보내고, 풀지를 결정)</li>
<li>CA에서 발급한 인증서 기반으로 인증 메커니즘 진행</li>
<li>해싱 등으로 알고리즘 </li>
</ol>
<h3 id="📖-디피-헬만-키-교환-알고리즘">📖 디피-헬만 키 교환 알고리즘</h3>
<p>y = g^x * (mod p) =&gt; 공개 값을 공유해서 각자 비밀 값과 연산하여, 혼합 값을 공유하면 공통의 암호키를 생성할 수 있는 원리</p>
<ul>
<li>예시) ECDHE (쉽고 안전한 디피-헬만 알고리즘 변형)
클라이언트    서버
개인키: a    개인키: b
공개키: A = a·G    공개키: B = b·G
수신 공개키: B    수신 공개키: A
공통 키: K = a·B    공통 키: K = b·A
=&gt; 중간에서 A, B를 모두 알아도 a나 b를 모르면 K를 연산하기 힘듬</li>
</ul>
<h3 id="📖-sha-256">📖 SHA-256</h3>
<p><strong>어떤 길이의 값을 입력해도 256비트의 고정된 결과값을 출력하는 알고리즘</strong>
내부 과정은 매우 복잡하지만 간단히 설명하면 </p>
<ul>
<li>전처리 과정에서 어떠한 데이터든지 확장해서 512비트로 만들고</li>
<li>이를 32bit의 8조각으로 쪼개서, 복잡한 연산(비트수는 바뀌지 않음)을 진행</li>
</ul>
<p>[Merkl–Damgård Algorithm &amp; RoundFunction =복잡한 연산]
=&gt; [입력 블록 512비트] + [현재 상태 256비트] → 새로운 상태 256비트
=&gt; 이 복잡한 연산은 이전 조각을 매개변수로 이용 A,B,C 면 B를 만들 때는 A가 사용되고, B의 값이 업데이트가 된 후에는 C를 만들 때 사용됨  </p>
<ul>
<li>이를 다시 이어 붙임 = 256bit 유지</li>
</ul>
<blockquote>
<p> *<em>질문 2 : 문자가 512bit를 넘어가면?
*</em></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[CS-network 2. IP 주소]]></title>
            <link>https://velog.io/@ashd_89/CS-network-2.-IP-%EC%A3%BC%EC%86%8C</link>
            <guid>https://velog.io/@ashd_89/CS-network-2.-IP-%EC%A3%BC%EC%86%8C</guid>
            <pubDate>Thu, 01 May 2025 01:34:45 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ashd_89/post/e21a96e9-d576-4b41-bd8d-b128e18d9ea7/image.png" alt=""></p>
<h2 id="📌-네트워크-기기">📌 네트워크 기기</h2>
<h3 id="📖-처리-범위">📖 처리 범위</h3>
<p><strong>계층 별로 처리하되, 상위 계층은 하위 계층을 처리할 수 있다.</strong></p>
<p>즉 애플리케이션 계층의 L7 스위치는 인터넷 계층에서, IP에 따른 분배도 가능하고, 데이터 링크 계층에서 MAC 주소에 따른 패킷 분배도 가능하다</p>
<h3 id="📖-대표-기기하드-웨어">📖 대표 기기(하드 웨어)</h3>
<p><strong>애플리케이션 계층 : L7 스위치(로드 밸런서)</strong></p>
<p><strong>인터넷 계층 : L3 스위치(라우터)</strong></p>
<p><img src="https://velog.velcdn.com/images/ashd_89/post/720f2047-1a05-456e-9345-e5b68648d9f7/image.png" alt=""></p>
<p>*<em>데이터 링크 계층 : L2 스위치 &amp; 브릿지(LAN to LAN) *</em></p>
<p><strong>물리 계층 : NIC(LAN 카드)</strong></p>
<ul>
<li>각 LAN 카드가 가지는 고유 식별 번호가 : MAC 주소! <br>

</li>
</ul>
<h2 id="📌-ip-주소">📌 IP 주소</h2>
<h3 id="📖-주소-매핑">📖 주소 매핑</h3>
<p>통신을 한다는 것은 어떤 PC와 PC가 연결된다는 것이기 때문에, 서로가 MAC 주소를 알아야한다!</p>
<p>결국 IP와 DNS 같은 것은 특정 컴퓨터 그룹에 접근을 쉽게하기 위한, 뼈대 주소이지 노드와 노드를 연결해 주지는 않음!!!</p>
<p><strong>택배를 보낼때, &quot;서울시 동대문구&quot;만 보내서 찾아갈 수 없는 것과 같은 이치!</strong></p>
<p>단순하게, <strong>정적 테이블</strong>을 가지고 있으면 해결이 되나, IP는 DHCP등 여러 요인에 의해 지속적으로 변경되므로, <strong>통신 프로토콜을 이용해서</strong>, IP라는 큰 범위의 주소를 통해서 빠르게 찾아가고, 이후 MAC이라는 다른 방법(전화?)으로 상세주소를 알아내어 통신!</p>
<h3 id="📖-arp-rarp">📖 ARP, RARP</h3>
<ul>
<li><p><strong>ARP는 주소 결정 프로토콜(Address Resolution Protocol, ARP)</strong>로 IP주소를 MAC주소로 대응시키는 프로토콜</p>
</li>
<li><p><strong>RARP는 역순 주소 결정 프로토콜(Reverse Address Resolution Protocol, RARP)</strong>로 MAC 주소에 맞는 IP값을 알아오는 프로토콜</p>
</li>
</ul>
<p>RARP의 한계: RARP는 IP 주소만 알려줄 수 있기 때문에 통신을 위해 subnetMask, 라우터의 등 다른 정보가 필요한 현대 통신에서는 DHCP 등으로 대체</p>
<p>중요 ARP와 RARP는 
<strong>같은 그룹 내 = 동일한 라우터에 연결 = 동일한 서브넷 IP를 가지는</strong>
경우에만 이용 가능
<img src="https://velog.velcdn.com/images/ashd_89/post/b9d51127-6194-4597-a236-700e2557c348/image.png" alt=""></p>
<p>먼저 Request broadcast(1:N)는 L2 스위치에 &quot;나 이 IP 주소의 MAC주소 알고 싶어&quot;라고 하는거고 이는 L2 스위치가 가진, MAC주소 테이블에 의해 연결된 모든 노드에 브로드캐스팅 된다.</p>
<p>이후에 해당 IP를 가진 노드가 Reply unicast(1:1)를 L2 스위치에 보내 &quot;이 IP는 내 주소야, 나 여기있어&quot;라고 인식시키고, 이를 스위치가 다시 reqeust 요청을 보낸 노드에게 보내는 방식</p>
<h2 id="📌-라우팅">📌 라우팅</h2>
<h3 id="📖-어떻게-찾아갈까">📖 어떻게 찾아갈까?</h3>
<p>통신 장치는 각각 자신의 범위를 지정하고 있다. 즉 자신의 범위 밖까지는 연결해 줄 수 없다. 각 통신장치는 라우팅 테이블을 가진다. 목적지 IP를 확인하고, 라우팅 테이블 내 다음 통신장치로 연결</p>
<p>즉 서울특별시 이면, 서울 택배 허브로, 충북이면 충북 택배허브로 보내는 방식
<br></p>
<h3 id="📖-라우팅-테이블">📖 라우팅 테이블</h3>
<p><img src="https://velog.velcdn.com/images/ashd_89/post/bb9dcb7f-5f46-495e-ad58-428beecb6482/image.png" alt=""></p>
<ul>
<li>네트워크 대상(Network Destination) : 목적지 네트워크의 IP 주소</li>
<li>서브넷 마스크(Netmask) : 대상 주소를 설명할 때 쓰이는 값</li>
<li>게이트웨이(Gateway) : 이 장치와 연결되어있패킷이 전달되는 다음 IP 주소(외부 네트워크와 연결된 장치) 만약 목적지가 로컬 네트워크라면 “연결됨(connected)”라고 표기 되며 다른 네트워크라면 해당 네트워크의 게이트웨이를 가리킴<br>

</li>
</ul>
<h3 id="gateway">GATEWAY</h3>
<p><img src="https://velog.velcdn.com/images/ashd_89/post/1c2f455a-3406-4827-81a7-3c79dc02ae27/image.png" alt="">
서로 다른 네트워크간의 통신을 위해서는 반드시 필요한 일종의 &quot;대문&quot; 역할로 따로 지정한 Host IP의 일종</p>
<br>

<h3 id="📖-클래스-기반-ip-할당과-서브넷-마스크">📖 클래스 기반 IP 할당과 서브넷 마스크</h3>
<p><img src="https://velog.velcdn.com/images/ashd_89/post/2ba9a304-4b09-45f5-9512-5f920f106156/image.png" alt=""></p>
<p>IP는 Byte 단위 즉 8개의 0,1로 표현된 범위를 나뉘어서 네트워크 주소와 호스트 주소를 구분한다.</p>
<p>이를 구분하는 키를 subnetMask 라고 하고, 이는 <strong>1이 연속되어 나오다, 0으로 바뀌는 지점</strong>이 생기도록 디자인하며, 1의 개수를 이용하여 /24 와 같은 형태로 작성한다.</p>
<p>예시) 255.255.255.0
1111 1111 . 1111 1111 . 1111 1111 . 0000 0000</p>
<blockquote>
<p> *<em>질문 1 : 192.168.0.0/20의 네트워크 범위, 호스트 범위, 네트워크 주소, 브로드 캐스트 주소?
*</em></p>
</blockquote>
<h3 id="📖-dhcp">📖 DHCP</h3>
<p><img src="https://velog.velcdn.com/images/ashd_89/post/c784f2bb-24cb-4278-affa-dd6affc6ae84/image.png" alt="">
DHCP(Dynamic Host Configuration Protocol)는 <strong>네트워크의 장치가 IP 주소를 요청하고 할당받을 수 있도록 하는 네트워크 프로토콜</strong></p>
<ul>
<li>서브넷 마스크 및 게이트웨이와 같은 다른 매개변수를 네트워크의 장치에 자동 할당</li>
</ul>
<p>DHCP Ack에서 임대 기간과, IP를 받음</p>
<ul>
<li>장치가 네트워크에서 제거되거나 임대가 만료되면 사용 중이던 주소를 사용 가능한 주소 풀로 반환하고 다른 장치에 재할당</li>
</ul>
<blockquote>
<p> ** 질문 2? : DHCP 서버와 클라이언트가 서로 다른 서브넷을 가질때?**</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[CI/CD 전체적인 구조 (1. Build)]]></title>
            <link>https://velog.io/@ashd_89/CICD-%EC%A0%84%EC%B2%B4%EC%A0%81%EC%9D%B8-%EA%B5%AC%EC%A1%B0-1.-Build</link>
            <guid>https://velog.io/@ashd_89/CICD-%EC%A0%84%EC%B2%B4%EC%A0%81%EC%9D%B8-%EA%B5%AC%EC%A1%B0-1.-Build</guid>
            <pubDate>Sun, 27 Apr 2025 09:32:58 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ashd_89/post/48c1402d-85c2-4d03-9f14-73f6020ceaff/image.png" alt=""></p>
<h2 id="📌-cicd-구조-1build">📌 CI/CD 구조 (1.Build)</h2>
<p>시험 하나 남았는데 회로 공부하다가 잠깐 쉬어가는 겸 블로그 글 업로드 시작!</p>
<h3 id="📖-무슨-내용인가-요약">📖 무슨 내용인가? (요약)</h3>
<p>앞으로 &quot;CI/CD의 구조&quot;라는 주제로 적을 내용은 서버 이전 프로젝트를 진행하기전에, 강의 형식으로 CI/CD의 과정이 어떻게 되는지 현업자  대! 준수님이 설명해준 내용을 내 맘대로 정리한 내용이다. 이전에는 기본적인 형태만 잡고 있었다면, 각 과정을 순차적으로 잘 설명해줘서, 해당 내용과 추가적인 공부 + 알고 있던 지식을 함께 정리해 보려한다.</p>
<p>일단 설명하기 전에, 준수님은 뭐든지 <strong>주체와 도구</strong>의 구분이 중요하다고 했기 때문에 이 부분을 중점으로 다뤄보겠다! </p>
<h3 id="📖-1-build">📖 1. Build</h3>
<p><strong>Build (도구 : gradle)</strong></p>
<p>소프트웨어 빌드(software build)의 정의는 소스 코드 파일을 실행할 수 있는 독립(standalone) 소프트웨어 가공물로 변환하는 과정이다.</p>
<blockquote>
<p>빌드는 코드를 ,패키징 해서, 어떠한 배포가능한 형태로 만드는 과정</p>
</blockquote>
<p>자바 환경에서 설명해보면</p>
<ul>
<li>먼저 코드는 .java형태로 작성</li>
<li>이후 컴파일러에서 .java를 바이트 코드인 .class로 변환하고 (문법 오류 체크 포함!)</li>
<li>JVM에서 .class파일을 메모리에 할당하고, 바이트코드를 해석 및 실행 (여기 부터를 Runtime이라고 부름!)</li>
<li>사실상 이 과정이 build의 끝</li>
</ul>
<h3 id="class-build의-문제점">[.class] build의 문제점</h3>
<p>여러 클래스의 상호작용을 위해 &quot;java -cp&quot;와 같은 명령어로 class-path를 지정해주어야 하고, 파일이 하나라도 없으면 실행 자체가 안되는 문제가 발생!</p>
<h3 id="jar-패키징">[.jar] 패키징</h3>
<ul>
<li>각 클래스 파일들</li>
<li>class-path연결</li>
<li>리소스 파일 (.yml, .xml)</li>
<li>메타데이터</li>
<li>fat jar를 통한 라이브러리 연결
등을 묶어서 zip 형식으로 묶어서 한번에 build가 되게!</li>
</ul>
<blockquote>
<p>이 과정을 진행해 주는 것이 바로 Gradle</p>
</blockquote>
<h3 id="gradle">Gradle</h3>
<h3 id="1-기본-구조">1) 기본 구조</h3>
<pre><code>plugins {
    id &#39;java&#39;
}

group = &#39;com.example&#39;
version = &#39;1.0.0&#39;

repositories {
    mavenCentral()
}

dependencies {
    testImplementation &#39;org.junit.jupiter:junit-jupiter:5.8.2&#39;
}

test {
    useJUnitPlatform()
}
</code></pre><p>build.gradle
 ├── plugins: &quot;나는 Java 프로젝트야!&quot; 
 ├── group / version: 프로젝트 식별자 설정
 ├── repositories: &quot;라이브러리 어디서 받을까?&quot; 
 ├── dependencies: &quot;어떤 라이브러리 쓸까?&quot; 
 └── test: &quot;JUnit5 기준으로 테스트할게!&quot;</p>
<p>기본적으로 gradle은 plugin과 dependecy 그리고, dependency를 어디서 가져올지를 결정하는 repository로 결정된다. (mavenCentral은 세계 최대 오픈 소스 저장소!)</p>
<h3 id="plugin과-dependecy의-차이가-무엇인가">plugin과 dependecy의 차이가 무엇인가?</h3>
<p>Plugin은 gradle에게 이 프로젝트에 대해서 설명하고, 해야할 작업을 알려주는 것!
Dependecy는 내 소스 코드를 실행할 때 필요한 라이브러리 </p>
<blockquote>
<p>Plugin : &quot;빌드 툴을 업그레이드&quot; (Gradle 자체 upgrade)
Dependency : &quot;내 소스 코드를 업그레이드&quot; (코드 자체에 기능 추가)</p>
</blockquote>
<p>🔨 플러그인은 빌드 공장에서 일하는 로봇을 추가하는 거고,
📦 의존성은 내 제품(앱) 안에 들어가는 부품을 추가하는 것!
<br></p>
<h3 id="2-각-과정">2) 각 과정</h3>
<ol start="0">
<li>clean : 이전 빌드 결과물 초기화</li>
<li>compileJava : javac(컴파일러)를 호출 해서 .class로!</li>
<li>prcessResources : 리소스 파일을 .class와 함께 복사</li>
<li>jar : 복사한 .class와 resource를 묶어서 jar파일 만들기</li>
<li>test : Junit과 같은 테스트 프레임워크를 활용한 테스트 진행</li>
</ol>
<p><strong>- 1+2 : gradle classes</strong>
<strong>- 1+2+3 : gradle assemble</strong>
<strong>- 1+2+3+4 : gradle build (assemble + test)</strong></p>
<blockquote>
<h3 id="결과--class-파일을-적당히-묶고-리소스-같은-것들도-추가해서-jar파일로-만들어냄">결과 : .class 파일을 적당히 묶고 리소스 같은 것들도 추가해서 .jar파일로 만들어냄!</h3>
</blockquote>
<h3 id="📖-0단계--build-이전-과정-for-자동-배포">📖 0단계 : Build 이전 과정 (for 자동 배포)</h3>
<p>결국 jar 파일을 서버 컴퓨터로 옮겨서 jvm으로 실행하는게 최종 목적인데, 이걸 내가 </p>
<ul>
<li>변경 사항이 있을 때 마다</li>
<li>직접 .jar로 만들고(build)</li>
<li>서버 컴퓨터로 파일을 옮겨서 실행하면,</li>
</ul>
<p><strong>CI/CD의 의미가 없다!</strong></p>
<h3 id="📖-자동화">📖 자동화</h3>
<p>보통은 github repository에 특정 조건(브랜치나, 태그) 등을 활용해서 push 했을 때, 원하는 주소로 webhook을 보내 변경사항을 감지한다!</p>
<p>이후에는 변경된 코드를 자동으로 build하고, 2번 과정인 도커 이미지로 만드는 과정까지 진행
=&gt; 이전 프로젝트에서는 이 과정을 jenkins라는 툴의 pipeline을 이용!!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CS-network 1. TCP/IP]]></title>
            <link>https://velog.io/@ashd_89/CS-network-1.-TCPIP</link>
            <guid>https://velog.io/@ashd_89/CS-network-1.-TCPIP</guid>
            <pubDate>Mon, 14 Apr 2025 00:56:46 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ashd_89/post/18fd8a40-c5f7-478f-abdf-757e12818561/image.png" alt=""></p>
<h2 id="📌-네트워크-기초">📌 네트워크 기초</h2>
<h3 id="📖-노드와-링크">📖 노드와 링크</h3>
<p>노드는 네트워크 장치 링크는 무선 또는 유선으로 연결된 상태를 의미한다.</p>
<h3 id="📖-처리량과-대역폭">📖 처리량과 대역폭</h3>
<p><img src="https://velog.velcdn.com/images/ashd_89/post/36bf0763-fa0f-410b-a4b2-a95d6e40192a/image.png" alt="">
네트워크에 트래픽(데이터)이 전달되면 이는 디지털 신호이기 때문에 0 또는 1즉 bit 데이터로 전달된다. 
이때 처리량(throughtput)은 1초에 수신되는 bit의 수(bps)를 의미하고,
이 처리량을 단위 시간 당 max값으로 설정한 것을 대역폭이라고 한다. 따라서 대역폭과 처리량의 단위가 동일하다!
<br></p>
<h2 id="📌-네트워크-토폴로지">📌 네트워크 토폴로지</h2>
<h3 id="📖-토폴로지">📖 토폴로지</h3>
<p>토폴로지는 노드와 링크가 어떻게 배치되어 있는 지를 의미한다. 
종류는 Tree, 회선에 여러개의 노드가 연결된 Bus, 노드끼리 1대다 관계의 스타, 노드끼리 1-1-1 관계의 링, 노드끼리 다대다 관계를 가지는 메시 구조가 있다.</p>
<h3 id="📖-스푸핑-in-lanbus">📖 스푸핑 in Lan(Bus)</h3>
<p>Bus 방식에서는 중앙 통신 회선하나에 여러개가 연결되어, 해당 노선을 따라 순차적으로 데이터가 전달된다. 따라서 중앙 통신 회선에 접속만 하면, 데이터를 송신부에서 수신부로 가기전에 가로 챌 수 있는 단점이 잇는데 이를 스푸핑 이라고한다.</p>
<ul>
<li>주의 : 병목 현상이 발생했을 때, 회선 추가 및 대역폭 개선 등의 다양한 문제 해결방법이 있지만, 네트워크 토폴로지에 따른 올바른 방법을 적용해야 해결할 수 있다.   <br>

</li>
</ul>
<h2 id="📌-네트워크-종류">📌 네트워크 종류</h2>
<ul>
<li>기본적으로 규모가 클수록 혼잡하고 속도가 느리다.<h3 id="📖-wan--man">📖 WAN &amp; MAN</h3>
</li>
<li>WAN은 국가 및 대륙 범위의 통신망을 의미하고, 인터넷이 WAN에 속한다. MAN은 동일 국가 내 통신망으로 지역을 이어주는 통신망이다.  <h3 id="📖-lan">📖 LAN</h3>
</li>
<li>LAN은 근거리 통신망을 의미하고, 보통 라우터나, 공유기를 통해 연결된다. <br>

</li>
</ul>
<h2 id="📌-명령어">📌 명령어</h2>
<h3 id="📖-ping">📖 Ping</h3>
<p>가장 많이 쓰이는 Ping은 원하는 노드를 대상을 패킷을 보내 수신 상태 및 도달시간을 확인할 수 있는 명령어이다. ICMP 프로토콜을 기반으로 통신한다.</p>
<h4 id="패킷의-헤더에는-송신-ip--프로토콜--패킷-번호를-가진다">패킷의 헤더에는 송신 IP + 프로토콜 + 패킷 번호를 가진다.</h4>
<p><img src="https://velog.velcdn.com/images/ashd_89/post/deaf86ee-a97a-42c4-bf12-52eeb260c642/image.png" alt=""></p>
<h4 id="icmp는-tcpip전송계층에서-패킷을-처리할-때-발생되는-문제나-정상-응답을-받을-수-있는-프로토콜이다">ICMP는 TCP/IP(전송계층)에서 패킷을 처리할 때 발생되는 문제나 정상 응답을 받을 수 있는 프로토콜이다.</h4>
<ul>
<li>Echo request는 ICMP에서 수신자에게 보내는 응답 요청 메시지를 담고 있으며</li>
<li>Echo reply는 수신자가 보내주는 응답이 기록된다.</li>
<li>Destination Unreachable는 전송실패 했을 때 즉, Echo reply와 반대의 상황에서 메시지가 저장되고</li>
<li>마지막으로 Time Exceeded는 ICMP데이터의 생명을 의미하는 TTL이 0이 되었을 때 메시지를 송신자에게 메시지를 반환한다.</li>
</ul>
<h4 id="ttl을-1씩-증가시켜가면선-모든-노드를-기록하는-방법--traceroute">TTL을 1씩 증가시켜가면선 모든 노드를 기록하는 방법 = Traceroute</h4>
<ul>
<li>TTL을 1로 설정해서 패킷을 보내면  </li>
<li>다음 노드로 가면 TTL이 0이 되고, TimeExceeded 메시지 전송</li>
<li>이후 다시 TTL을 1 증가 시키고, 다시 다음노드로 전달 반복 
=&gt; 결과적으로 겨쳐간 모든 노드에서 TTL이 0이 한번씩 되기 때문에, 송신한 노드에서는 목적지까지의 모든 노드에서 반환한 메시지를 확인 가능! </li>
</ul>
<blockquote>
<p> <strong>질문 1 : NAT(외부에서는 포트번호로 접근) 즉 라우터를 사용하게 되면 traceroute방식에서 해당 목적지를 어떻게 찾아갈까</strong></p>
</blockquote>
<br>

<h3 id="📖-nslookup">📖 nslookup</h3>
<p>DNS(인터넷 상의 전화번호부)를 확인하는 명령어</p>
<h4 id="내부-dns-서버에-어떻게-외부에서의-접근을-막나">내부 DNS 서버에 어떻게 외부에서의 접근을 막나?</h4>
<p>DNS 즉 외부에서 확인할 수 있는 도메인 정보가 아니라, 외부에는 공개 되지 않는 도메인 주소를 형성하여 만드는 내부 네트워크 도메인이다. 
 보통은 bind라는 프로그램을 메인 서버에 설치!, 원하는 도메인과 내부 ip를 연결하여, 파일로 저장해서, 도메인 이 형성되는 방식</p>
<p> 즉 어떤 도메인이 입력되면, 외부 DNS 확인하기전에, 내부 DNS를 확인해서 있다면 해당 ip랑 연결 해주고, 없다면 외부 ip를 탐색!</p>
<blockquote>
<p> *<em>질문 2 : 내가 만든 서버의 DNS가 A.com-&gt;B.com으로 바뀌었다. 다른 PC에서 내 서버ip로 DNS 테이블을 조회하면 A로 보일까 B로 보일까? 또 내 컴퓨터에서 nslookup을 하면 어떻게 보일까? *</em> </p>
</blockquote>
<br>


<h2 id="📌-tcpip-계층-구조">📌 TCP/IP 계층 구조</h2>
<h3 id="📖-애플리케이션-계층--프로토콜-계층">📖 애플리케이션 계층 = 프로토콜 계층</h3>
<ul>
<li>FTP는 파일전송, SSH 원격(암호화), HTTP(www. 인터넷), SMTP 메일전송 등이 있다.<h3 id="📖-전송-계층">📖 전송 계층</h3>
TCP와 UDP는 데이터 전송을 위한 프로토콜이다. TCP는 각 패킷을 순서대로 전달하고, 연결을 매 순간 확인하며 전달하는 방식이다. 즉 출발지에서 목적지까지 1차차로 연결이 성공하는 경로를 확인하고 그 경로로만 패킷을 전달한다. 그에 반해 UDP는 수신 여부를 확인하지 않고 데이터만 전달한다. 심지어 경로도 자유분방하다.  </li>
</ul>
<h4 id="tcp연결-과정-및-해제-과정에서는-handshake를-한다">TCP연결 과정 및 해제 과정에서는 HANDSHAKE를 한다!</h4>
<ul>
<li>3handshake -&gt; data -&gt; 4handshake</li>
</ul>
<p>[3handshake]
TCP의 통신 노드는 ISN이라는 32-bit 시퀀스 번호(노드의 주민번호?)를 송신자가 보내고, 수신자가 받아서 자신의 ISN과 승인 응답으로 송신자의 ISN+1을 보낸 후, 다시 송신자가 받아서 승인 응답으로수신자의 ISN+1을 보내서 양방향으로 체크한 경우 통신을 시작한다.
이때 자신의 시퀀스 번호를 보는 과정을 SYN 승인 응답을 보내는 과정을 ACK라고 한다. </p>
<p>[data]
이후 인증된 TCP 통신 경로로 각 데이터를 교환하고</p>
<p>[4handshake]
통신을 종료하기 위해 FIN(종료 코드)을 송신자 측에서 전달하고 (1차 종료 상태), 수신자 측은 승인 응답인 ACK를 보낸다. 이 경우 ACK를 받은 송신자 측은 무응답 (2차 종료 상태)
이후 수신자 측은 응답이 없는 것을 확인하고 응답이 아닌 FIN을 처음으로 보낸다 (수신자 측의 마지막 통신). 이후 이를 받은 송신자는 2차 종료 상태에서 대기 상태로 전환되고, 승인 응답 전송한다. 이는 수신자가 받는 최종적으로 양뱡향으로 확인한 종료이기 때문에 수신자는 최종 CLOSED되고, 응답을 받을 수 없는 송신자는 대기하다가 time out되어서 CLOSED된다.<br><img src="https://velog.velcdn.com/images/ashd_89/post/dec78a63-a37a-4634-915e-01f37a6cc6d1/image.png" alt=""></p>
<h4 id="tcp-중간에-유실-되면">TCP 중간에 유실 되면</h4>
<p>송신자는 데이터를 보냄과 동시에 이전에 통신한 기록을 기반으로 timeout을 설정한다. timeout이내로 데이터+ACK를 받지 못하면 해당 패킷을 재전송한다.
<img src="https://velog.velcdn.com/images/ashd_89/post/f107bd45-a09f-492e-8eaa-e417689685c8/image.png" alt=""></p>
<blockquote>
<p> *<em>질문 3? timeout을 송신자 쪽에서 스스로 계산한다면 똑같은 데이터를 중복으로 보낼 수 있지 않나? TCP는 연결성을 보장하고 중복 데이터는 없다 그랬는데? *</em> </p>
</blockquote>
<br>


<h3 id="📖-인터넷-계층--원하는-ip-주소로-전송하기-위한-규칙">📖 인터넷 계층 : 원하는 IP 주소로 전송하기 위한 규칙</h3>
<ul>
<li>연결을 보장하지 않는다!<h3 id="📖-링크-계층">📖 링크 계층</h3>
광섬유 등을 이용하여 물리적을 데이터를 보내는 계층 + 이더넷 계층인데 주로 맥주소를 교환한다.</li>
</ul>
<h2 id="📌-계층-간-통신">📌 계층 간 통신</h2>
<p>결국 최종적으로 통신을 할때에는 여러 계층을 통과해야하고, 결국 각 과정에서 필요한 프로토콜들이 모두 전달되어야한다. 즉 PDU(계층에서 계층으로 전달되는 데이터)는 반드시 이전 단계의 프로토콜을 가진다.
<img src="https://velog.velcdn.com/images/ashd_89/post/38e5cdf0-cdc5-4ff4-8688-bbc8ce0da1af/image.png" alt=""></p>
<p>캡슐화 즉 애플리케이션 계층에서 데이터는 전송 계층으로 넘어가면서 TCP나 UDP 프로토콜이 추가되고 (L4), 다시 인터넷 계층으로 전달되면서 IP 프로토콜 등이 추가(L3), 이후에 링크 계층으로 넘어가면서 MAC 주소 등이 추가 되서, 물리적으로 이동 된다
이후에 다시 위 과정의 역과정인 비캡슐화 과정을 통해 애플리케이션 계층의 데이터만 뽑아서 전달 된다.</p>
<h3 id="📖-vpn">📖 VPN</h3>
<p>VPN은 외부 접근 불가 + 연결되어야만 확인할 수 있는 일종의 보안통로로 통신하는 방식이다. </p>
<blockquote>
<p> <strong>VPN도 결국 계층간 통신 과정을 거칠텐데, 왜 중간 노드에서 확인할 수 없는 보안통로를 만들 수 있는 것일까? 똑같이 비캡슐화 과정을 하면 보이는게 아닌가?</strong>
VPN에는 여러 방법이 있지만, 계층 간 통신과 연결을 하려면 IP 프로토콜 즉 L3단계에서의 로직을 봐야한다. VPN은 받은 캡슐화된 데이터(L3니까 IP+TCP+데이터)를 암호화한다. = 이전에 키교환 과정 필요
 암호화한 캡슐화 데이터를 다시 L3까지의 프로토콜을 다시 붙인다.(IP+TCP+암호화:[IP+TCP+데이터]) 즉, 2중 캡슐화를 통해, 프로토콜을 통해 정상적인 통신 과정을 진행할 수 있게 하고(암호화하면 패킷의 프로토콜이 인식이 안됨), 중간에서 열어봤자 암호화 되서 볼 수 없게 하는 것이 VPN!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[향후 블로그 방향성]]></title>
            <link>https://velog.io/@ashd_89/%ED%96%A5%ED%9B%84-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%B0%A9%ED%96%A5%EC%84%B1</link>
            <guid>https://velog.io/@ashd_89/%ED%96%A5%ED%9B%84-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%B0%A9%ED%96%A5%EC%84%B1</guid>
            <pubDate>Sun, 13 Apr 2025 07:14:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ashd_89/post/631aa4e9-f922-40f0-a287-f098bf50aaaa/image.png" alt=""></p>
<h2 id="📌-근황">📌 근황</h2>
<p>일단 지금은 시험기간이다. 4월 3째주...
시대생으로 들어온지 2개월 만에, 팀 협업으로 1차 프로젝트는 마무리 했다. 이 글을 차피 비공개 처리할 것이기 때문에 솔직하게 풀어볼 예정이다!
또 시대생 TF에 참여할 수 있게 되었고, 잘만 된다면, 내가 원하던 로직적으로 복잡한 프로젝트가 되지 않을까 싶다. 채팅 서비스에 관심 있던 MSA까지 할 수 있었으면 배우는게 많아서 너무 좋을 것 같다. 수아 및 용현이랑 CS 스터디를 결성했고, 시대생에서 서버 이전 프로젝트에 참여하게 되었다</p>
<h2 id="📌-향후-블로그-방향성-및-계획">📌 향후 블로그 방향성 및 계획</h2>
<p>CS 스터디를 시작하면서 배울 내용들을 노션에 정리하기 보다는 블로그에 정리하는게 조금 나중에 더 유용하지 않을까 생각했다. 블로그를 공개해야하기 때문에 ssul 태그 글들을 비공개 처리하는 것과 동시에, 내가 이전에 공부하면서 적었던 글들을 읽어 보았다. 내용정리가 끝인 느낌.. 읽어봐도, 크게 도움되는 느낌을 글이 아니었다. (결국 ssul만 열심히 적고, 잘 읽히고 ㅋㅋㅋㅋ, 기술 내용은 이전에 정리 한번 해서 많이 없기도 한 듯)
때문에 그냥 내용 정리보다는 내 언어로 다시 적는 느낌으로 대화체를 사용해서 적어보고자 한다. 임시글로 저장해 놓은 TF 진행하면서 배운 내용들도 최대한 빠르게 올려볼 생각이고! 내가 다시 읽었을 때, 까먹었어도 다시 이해를 할 수 있는 수준이 되는 것을 목표로 정리해볼 것이다. 설치나, 기본 이론 같은 부분은 어쩔 수 없이 줄글이 되겠지만, 배운 내용들과 고민했던 것들 위주로 정리해 보겠다.</p>
<h3 id="📖-리팩토링-프로젝트-refactor">📖 리팩토링 프로젝트 (refactor)</h3>
<ul>
<li>일단 진행하지 않을 것이다.</li>
</ul>
<p>애초에 코틀린으로 구조를 생각하면서 짜게 되는 법을 배우면 의미가 없어지기도 했고, tiggle을 수정하는 것이 매우 큰 투자가 필요함이 당연한데, 그 정도의 결과가 나오는지 의문점이 들고, 시대생 프로젝트(TF 뿐 아니라, 서버이전 등)를 하면서 동시에 진행하는 것은 무리다. 결국 서버이전 자체가 리팩토링 프로젝트의 핵심이었던 CI/CD쪽을 해볼 수 있어 일단 멈추고, 이후에 다시 진행하는게 맞지 않을까?</p>
<h3 id="📖-tf-과정-중-에러나-사용-기술-관련-t-shoot">📖 TF 과정 중 에러나 사용 기술 관련 (t-shoot)</h3>
<ul>
<li>최대한 대화체를 사용해서 이해하기 쉽도록</li>
</ul>
<p>처음 봐도 이해가 쉽도록, 내가 이해한 내용들을 풀어서 설명해 보려한다. 솔직히 막막한 부분들도 있긴 한데, 일단 써보고! 너무 답이 없다 싶으면 어쩌겠냐.. 그냥 정리해봐야지</p>
<h3 id="📖-cs-study-cs-network">📖 CS-study (cs-network)</h3>
<ul>
<li>일단 네트워크로 시작 다른 친구들이 어떻게 정리할지는 모르겠으나, 나는 대화체로 적어볼 예정 안된다 그럼 바꾸지 뭐</li>
</ul>
<h3 id="📖-cicd-관련-cicd">📖 CI/CD 관련 (cicd)</h3>
<ul>
<li>시대생 서버 이전 하면서, 공부한 내용들 정리해보기</li>
</ul>
<p>일단 자유롭게 쓸 수있는 초고성능 컴퓨터 생겼으니까, 이전에 생각했던 것들 여러 노드 가지고 이것 저것 해보다 보면 뭐라도 늘지 않을까 ㅋㅋㅋ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Entity 관련 사소한 팁]]></title>
            <link>https://velog.io/@ashd_89/Entity-%EA%B4%80%EB%A0%A8-%EC%82%AC%EC%86%8C%ED%95%9C-%ED%8C%81</link>
            <guid>https://velog.io/@ashd_89/Entity-%EA%B4%80%EB%A0%A8-%EC%82%AC%EC%86%8C%ED%95%9C-%ED%8C%81</guid>
            <pubDate>Tue, 21 Jan 2025 10:12:59 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-intellij에서-사용처-확인-tip">📌 intellij에서 사용처 확인 tip</h2>
<h3 id="📖-entity">📖 Entity</h3>
<p>Constructors는 생략이 가능하지만,
*<em>찾고자하는 entity에 작성하고, ctrl 클릭을 하게 되면 *</em></p>
<ul>
<li><p>기존에는 모든 User 관련 모든 사용처가 뜨지만
<img src="https://velog.velcdn.com/images/ashd_89/post/d6545c51-de6a-4135-9ca0-bb2053bf8a62/image.png" alt=""></p>
<br>
</li>
<li><p>Entity를 사용한 곳만 찾아낼 수 있다.
<img src="https://velog.velcdn.com/images/ashd_89/post/488e21b7-f650-4392-8b19-0e38faff1a32/image.png" alt=""></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Trouble : kotlin-reflect와 annotation의 관계]]></title>
            <link>https://velog.io/@ashd_89/Trouble-kotlin-reflect%EC%99%80-annotation%EC%9D%98-%EA%B4%80%EA%B3%84</link>
            <guid>https://velog.io/@ashd_89/Trouble-kotlin-reflect%EC%99%80-annotation%EC%9D%98-%EA%B4%80%EA%B3%84</guid>
            <pubDate>Tue, 21 Jan 2025 07:55:06 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ashd_89/post/b784dd6a-53a2-4eb1-9ebe-9aa0175a4813/image.png" alt=""></p>
<h2 id="📌-이해를-위해-알아야-할-기본-개념">📌 이해를 위해 알아야 할 기본 개념</h2>
<h3 id="📖-1-레퍼런스-객체">📖 1. 레퍼런스 객체</h3>
<p><strong>- 클래스의 객체를 가리키는 값 (변수?와 유사) =&gt; 아래 코드의 person1</strong></p>
<pre><code class="language-kotlin">class Person(val name: String, val age: Int)

val person1 = Person(&quot;Alice&quot;, 30)</code></pre>
<h3 id="📖-2-참조리플렉션-연산자-">📖 2. 참조(리플렉션) 연산자 (::)</h3>
<p><strong>- class, method, property 등을 참조해오는 연산자</strong></p>
<ul>
<li>JAVA는 .을 통해서 </li>
</ul>
<ol>
<li>어떠한 클래스의 객체를 생성</li>
<li>그 객체의 속성이나 메소드를 <strong>참조가 아닌 직접 접근</strong><br>
</li>
</ol>
<ul>
<li>kotlin에서는 .을 통해서 객체 본연의 값을 가져오는 것도 가능하지만
::을 통해서</li>
</ul>
<ol>
<li>참조를 통한 각 개별 값 접근을 반복문을 통한 수정이 아닌 전체 데이터 변경<pre><code class="language-kotlin">fun main() {
 val names = listOf(&quot;Alice&quot;, &quot;Bob&quot;, &quot;Charlie&quot;)
 val upperCaseNames = names.map(String::toUpperCase) // 메서드 참조 사용
 println(upperCaseNames) // [ALICE, BOB, CHARLIE]
}</code></pre>
</li>
<li>정확한 속성이나 메소드 이름을 모를 때도 가능 =&gt; 이것이 핵심<br>

</li>
</ol>
<h2 id="📌-문제-상황">📌 문제 상황</h2>
<h3 id="📖-java에서-kotlin으로-entity를-수정-하던-중-jpa-repository의-annotation을-사용하는-과정에서-에러가-발생">📖 Java에서 Kotlin으로 Entity를 수정 하던 중 JPA repository의 annotation을 사용하는 과정에서 에러가 발생</h3>
<ul>
<li>intellij에서는 추가 construcor와 getter/setter의 추가 생성 요청 (but  해결 X)<blockquote>
<p>Caused by: java.lang.ClassNotFoundException: kotlin.reflect.full.KClasses</p>
</blockquote>
</li>
</ul>
<br>


<h2 id="📌-해결-방안">📌 해결 방안</h2>
<h3 id="📖-리플렉션-관련-라이브러리-추가">📖 리플렉션 관련 라이브러리 추가</h3>
<pre><code class="language-kotlin">implementation &quot;org.jetbrains.kotlin:kotlin-reflect:{kotlin_version}&quot;</code></pre>
<br>

<h2 id="📌-원리">📌 원리</h2>
<h3 id="📖-1-jvm">📖 1. JVM</h3>
<p>*<em>중요 !!! : JVM의 클래스 로더는 클래스 실행 시키기 전에 클래스가 필요로 하는 메모리 및 자원을 할당 *</em></p>
<ul>
<li>그럼 어떻게? 클래스가 실행 되지도 않았는데 어떤 필드, 메서드 등이 있을 지 알고 할당
=&gt; <strong>Reflection : 런타임에 프로그램의 클래스를 조사하기 위해 사용되는 기술</strong>
=&gt; Reflection을 이용하기 위해서 사용하는 객체 = 레퍼런스 객체</li>
</ul>
<pre><code class="language-java">Class&lt;?&gt; aClass = Class.forName(&quot;클래스 파일 위치&quot;)
aClass.getDeclaredFields()
aClass.getDeclaredAnnotations()</code></pre>
<p><strong>이처럼 declared를 이용해서 class 파일명만 알아도, 내부를 분석할 수 있도록 작동</strong>
<br></p>
<h3 id="📖-2-jpa-repository와-같은-라이브러리">📖 2. JPA repository와 같은 라이브러리</h3>
<p><strong>동일하게 어떤 클래스든 간에 작동해야 하기 때문에</strong></p>
<p>*<em>- @Entity라던가, 어떤 속성이 @Id가 붙어 있는지 확인해야하는데 내부 클래스나, 속성 정보 없이 해야하기 때문에 Reflect이용 *</em>
<br></p>
<h3 id="📖-3-java는-reflect가-기본-라이브러리--kotlin에서는-x">📖 3. java는 reflect가 기본 라이브러리 / kotlin에서는 X</h3>
<ul>
<li>아마 이러한 부분을 해결하기 위해, 가상 객체를 생성하여, reflect를 사용하지 않는 복잡한 방법이 있어, intellij에서는 생성자를 추가로 생성해보라고 하지 않았을까?</li>
<li>이 부분은 정확하지 않음<br>

</li>
</ul>
<h2 id="📌-이후에-할-추가-공부">📌 이후에 할 추가 공부</h2>
<p><a href="https://everyday-develop-myself.tistory.com/319">https://everyday-develop-myself.tistory.com/319</a></p>
<ul>
<li>reflection은 generic과 변성</li>
<li>in out과 kClass 등...</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[참고]]></title>
            <link>https://velog.io/@ashd_89/%EC%B0%B8%EA%B3%A0</link>
            <guid>https://velog.io/@ashd_89/%EC%B0%B8%EA%B3%A0</guid>
            <pubDate>Tue, 21 Jan 2025 06:53:27 GMT</pubDate>
            <description><![CDATA[<p>kotlin 관련 지식 정리 (난이도가 높아 보임...) 
<a href="https://everyday-develop-myself.tistory.com/category/Android/Kotlin?page=4">https://everyday-develop-myself.tistory.com/category/Android/Kotlin?page=4</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin TestCode : Junit5]]></title>
            <link>https://velog.io/@ashd_89/Kotlin-TestCode-Junit5</link>
            <guid>https://velog.io/@ashd_89/Kotlin-TestCode-Junit5</guid>
            <pubDate>Wed, 08 Jan 2025 13:09:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ashd_89/post/2ceaba9d-7c9e-42c8-a317-b28a38d693b9/image.png" alt=""></p>
<h2 id="📌-junit5-in-kopring">📌 Junit5 in Kopring</h2>
<h3 id="📖-1-annotation">📖 1. Annotation</h3>
<p><img src="https://velog.velcdn.com/images/ashd_89/post/87c69fd0-0eca-4afa-9f9c-91518ad26c96/image.png" alt=""></p>
<ul>
<li>@Test : 테스트 메소드 지정</li>
<li>@BeforeEach : 각 테스트가 수행되기 전 실행</li>
<li>@AfterEach : 각 테스트가 수행된 후 실행</li>
<li>@BeforeAll : 테스트를 실행하기 전 최초 한번만 실행</li>
<li>@AfterAll : 테스트를 실행한 후 최초 한번만 실행</li>
</ul>
<p>=&gt; @BeforeAll과 @AfterAll은 전체에 영향을 주므로 
Java에서는 static설정 Kotlin에서는 conpanion object로 선언된 곳에 사용 (@JvmStatic 필수)</p>
<pre><code class="language-kotlin">class JunitTest {
    companion object {
        @JvmStatic
        @BeforeAll
        fun beforeAll(): Unit {

        }
    }

    @BeforeEach
    fun beforeEach() {}

    @Test
    fun test1(){

    }

    @Test
    fun test2(){

    }

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

<h3 id="📖-2-assertthat--단언문">📖 2. AssertThat : 단언문</h3>
<ul>
<li>import시 AssertProvider로
<img src="https://velog.velcdn.com/images/ashd_89/post/9fe7e088-65a5-4167-82c9-da6d044afced/image.png" alt=""></li>
</ul>
<p>@Test가 적힌 메소드 (given / when / then) 중 then에 사용하며, 잘못된 값이 들어왔을 때, 예상 값과 실제 값을 비교 가능</p>
<pre><code class="language-kotlin">//then
        assertThat(calculator.number).isEqualTo(7)</code></pre>
<p><img src="https://velog.velcdn.com/images/ashd_89/post/9333b3e6-c95a-421f-bf5e-273f5a0a240a/image.png" alt=""></p>
<ul>
<li><p>assertThat(A) A는 대상 값</p>
<h4 id="assertthrows에러명으로-에러-검출-및-메세지-확인-가능">assertThrows&lt;에러명&gt;으로 에러 검출 및 메세지 확인 가능</h4>
<pre><code class="language-kotlin">val message = assertThrows&lt;IllegalArgumentException&gt; { 
function1() }.message 
  assertThat(message).isEqualTo(&quot;잘못된 값이 들어왔습니다&quot;)

//context Object 활용 =&gt; 기억안나면 Kotlin 기본 문법
assertThrows&lt;IllegalArgumentException&gt; { function1() }.apply {
   assertThat(message).isEqualTo(&quot;잘못된 값이 들어왔습니다&quot;)
}</code></pre>
<br>
</li>
<li><p>isEqualTo(B) B는 기대 값</p>
<blockquote>
<ul>
<li>.isEqualTo</li>
<li>.isTrue/ isFalse</li>
<li>.hasSize</li>
<li>.extracting(&quot;name&quot;).containsExactlyInAnyOrder(&quot;LEE&quot;, &quot;Park&quot;)
리스트 값의 name이라는 파라미터 값이 맞는지 (순서 상관 X)</li>
<li>.extracting(&quot;name&quot;).containsExactly(&quot;LEE&quot;, &quot;Park&quot;)
리스트 값의 name이라는 파라미터 값이 맞는지 (순서 상관 O)</li>
</ul>
</blockquote>
</li>
</ul>
<br>

<h3 id="📖-3-spring에서의-각-계층-테스트">📖 3. Spring에서의 각 계층 테스트</h3>
<ul>
<li>Controller : 응답받는 <strong>JSON 및 Http 위주</strong>의 검증 (@SpringBootTest)</li>
<li>Domain(순수한 자바 객체) : 기존의 class 테스트</li>
<li>Service, Repository : 스프링 빈을 활용한 <strong>데이터 위주</strong>의 테스트 (@SpringBootTest)</li>
</ul>
<p>0) Java Code -&gt; test Kotlin (Java코드 베이스로 kotlin 테스트를 구현할 경우)</p>
<ul>
<li><p>@Autowired를 통해 Service와 Repository를 의존성 주입</p>
</li>
<li><p>각 테스트에 @DisplayName을 통해서 이름 지정 가능</p>
</li>
<li><p>UserCreateRequest(&quot;lee&quot;, null)를 사용하기 위해서는 생성자 필수</p>
<pre><code class="language-kotlin">@SpringBootTest
class UserServiceTest @Autowired constructor(
  private val userService: UserService,
  private val userRepository: UserRepository,
  )
{
  @Test
  @DisplayName(&quot;유저 등록이 정상 작동 한다.&quot;)
  fun saveUserTest(){
      //given
      val request = UserCreateRequest(&quot;lee&quot;, null)

      //when
      userService.saveUser(request)

      //then
      val result = userRepository.findAll()
      assertThat(result).hasSize(1)
      assertThat(result[0].name).isEqualTo(&quot;lee&quot;)
      assertThat(result[0].age).isNull()
  }
</code></pre>
</li>
</ul>
<p>}</p>
<pre><code>- null일 경우 kotlin에서는 null이 가능한지 확인이 안되므로, Java 엔티티의 getter에 @Nullable, @NotNull 필요
```java
@Entity
public class User {

  @Id
  @GeneratedValue(strategy = IDENTITY)
  private Long id;

  @Column(nullable = false)
  private String name;

  private Integer age;

  @NotNull
  public String getName() {
    return name;
  }

  @Nullable
  public Integer getAge() {
    return age;
  }</code></pre><h4 id="중요-동일한-스프링-컨텍스트h2-database를-공유하기-때문에-연속된-테스트-과정에서-각-테스트가-정상적이어도-문제가-발생할-수-있다">중요! 동일한 스프링 컨텍스트(H2 database)를 공유하기 때문에 연속된 테스트 과정에서 각 테스트가 정상적이어도 문제가 발생할 수 있다</h4>
<p><strong>따라서 각 테스트 후에 AfterEach로 db초기화 필요</strong></p>
<pre><code class="language-kotlin">@AfterEach
    fun clean() {
        userRepository.deleteAll()
    }</code></pre>
<br>

<h3 id="📖-4-전체-테스트-진행">📖 4. 전체 테스트 진행</h3>
<p>Intellij에서 gradle -&gt; verification -&gt; test</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin 기본 문법]]></title>
            <link>https://velog.io/@ashd_89/Kotlin-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@ashd_89/Kotlin-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Fri, 03 Jan 2025 15:23:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ashd_89/post/1ac55405-9e57-4921-b2dd-eb272f593dca/image.png" alt=""></p>
<h2 id="📌-기존-자바-코드가-어떤식으로-바뀌는-지">📌 기존 자바 코드가 어떤식으로 바뀌는 지!</h2>
<p>참고 : <a href="https://jinjinyang.tistory.com/66">https://jinjinyang.tistory.com/66</a></p>
<h3 id="📖-1-함수">📖 1. 함수</h3>
<h4 id="1-선언-방식--fun-함수명-매개변수명--타입--반환타입">1. 선언 방식 =&gt; fun 함수명 (매개변수명 : 타입) : 반환타입</h4>
<p>기본 선언</p>
<pre><code class="language-kotlin">fun sum(a: Int, b: Int):Int = a+b { }</code></pre>
<ul>
<li>return을 따로 지정할 필요가 없음 (return a+b와 동일)</li>
</ul>
<p>반환 값이 void</p>
<pre><code class="language-kotlin">fun sum2(a: Int, b: Int):Unit { }</code></pre>
<blockquote>
<p>** 코틀린 함수의 장점 =&gt; 매개값이 다른 동일한 함수를 계속 만들 필요 X**</p>
</blockquote>
<ul>
<li>디폴트 파라미터 선언</li>
<li>파라미터 지정 </li>
<li>특정 인자만 값 세팅 가능</li>
</ul>
<h3 id="📖-2-변수와-상수">📖 2. 변수와 상수</h3>
<h4 id="1-선언-방식--varval-변수명--타입대문자---값">1. 선언 방식 =&gt; var/val 변수명 : 타입(대문자)  = 값</h4>
<p>var : 변수(가변값) </p>
<pre><code class="language-kotlin">val myName : String = &quot;ashd&quot;</code></pre>
<p>val : 상수(불변값) </p>
<pre><code class="language-kotlin">var myAge : Int = 20</code></pre>
<h4 id="2-출력--활용">2. 출력 =&gt; $활용</h4>
<p>$변수</p>
<pre><code class="language-kotlin">val number = 20
println(&quot;Please give me $number dollors&quot;)</code></pre>
<p>${수식}</p>
<pre><code class="language-kotlin">val number = 20
println(&quot;I only have ${if (number &lt;10 ) number else 10} dollor&quot;)</code></pre>
<br>

<h3 id="📖-3-클래스">📖 3. 클래스</h3>
<h4 id="0-기본-형태-생성자가-필요치-않음">0. 기본 형태 (생성자가 필요치 않음)</h4>
<p>Java</p>
<pre><code class="language-java">@Getter
@Setter
@AllArgsConstructor
public class Person {
    private String name;
    private int age;
    private boolean isMarred;
}</code></pre>
<p>Kotlin</p>
<pre><code class="language-kotlin">class Person(val name: String, val age: Int, val isMarried: Boolean)</code></pre>
<h4 id="1-자바와-달리-field-선언만-하고-getter-setter를-사용하지-않음">1. 자바와 달리 field 선언만 하고 Getter, Setter를 사용하지 않음</h4>
<ul>
<li>간결한 선언 </li>
<li>명칭을 통한 getter/setter<pre><code class="language-kotlin">fun main (args: Array&lt;String&gt;) {
  val person = Person(&quot;ashd&quot;, 20, false)
  println(person.isMarried());
}</code></pre>
<blockquote>
<p><strong>### decompile(자바로 어떻게 되는지) =&gt; shiftX2(info창) - Bytecode Viewer</strong></p>
</blockquote>
</li>
</ul>
<pre><code class="language-java">public final class PersonKt {
    public static final void main() {
      Person person = new Person(&quot;ashd&quot;, 20, false);
      String var1 = person.getName();
      System.out.println(var1);
      int var2 = person.getAge();
      System.out.println(var2);
      boolean var3 = person.isMarried();
      System.out.println(var3);
   }</code></pre>
<h4 id="2-custom-gettersetter">2. Custom Getter/Setter</h4>
<ul>
<li>get() / set()</li>
<li>변수 선언 후 getter/setter의 결정 방법을 선언<pre><code class="language-kotlin">class Rectangle (val height: Int, val width: Int) {
  val isSquare:Boolean
      get(){
          return height == width
      }
}</code></pre>
<blockquote>
<p><strong>하나의 파일에 여러 클래스와 함수, 최상위 변수를 선언 가능 + 장점</strong></p>
</blockquote>
</li>
</ul>
<p>코틀린에서 편리해서 자주 활용되는 부분임
결합도가 높은 클래스, 유사한 클래스, enum 클래스 등 한곳에 모아 놓으면 관리와 사용이 편리해짐
<br></p>
<h3 id="📖-4-when조건문--enum">📖 4. when(조건문) + enum</h3>
<h4 id="0-enum-public-enum---enum-class">0. Enum (public enum -&gt; enum class)</h4>
<pre><code class="language-kotlin">enum class Color(val r: Int, val g: Int, val b: Int){
    RED(255, 0, 0),
    ORANGE(255, 166, 0),
    YELLOW(255, 255, 0),
    GREEN(0, 255, 0);// 아래 함수와 구분을 위해서 세미콜론 추가

    fun rgb() = (r * 256 + g) *256 + b
}</code></pre>
<h4 id="1-when은-swtich문을-대체한다-enum활용이-필수">1. When은 Swtich문을 대체한다 (Enum활용이 필수)</h4>
<ul>
<li>화살표 사용 </li>
<li>다중 대체가 가능 </li>
<li>else는 사용할 수 있지만, when은 case를 지정하지 않았을 때, 컴파일 단계에서 에러를 찾을 수 있어 수정이 편리 <pre><code class="language-kotlin">fun getKoreanColor(color: Color): String =
  when(color) {
      RED, ORANGE -&gt; &quot;빨강 혹은 오렌지&quot;
      YELLOW -&gt; &quot;노랑&quot;
      GREEN -&gt; &quot;녹색&quot;
  }
}</code></pre>
<h4 id="2-인자가-없는-when-else처리-필수">2. 인자가 없는 When (Else처리 필수)</h4>
<pre><code class="language-kotlin">fun mix(c1: Color, c2: Color) =
  //인자가 없는 when의 경우 반드시 else을 정의해야 됨
  when {
      c1 == RED &amp;&amp; c2 == YELLOW -&gt; ORANGE
      c1 == YELLOW &amp;&amp; c2 == BLUE -&gt; GREEN
      else -&gt; throw RuntimeException()
  }</code></pre>
<h4 id="3-when을-활용한-typecast">3. When을 활용한 TypeCast</h4>
<pre><code class="language-kotlin">fun printObject(obj: Any): Unit = when(obj){
  is String -&gt; println(obj.lowercase())
  is Duration -&gt; println(obj.nano)
  is LocalDateTime -&gt; println(obj.month)
  else -&gt; println(&quot;Unknown type&quot;)
}</code></pre>
<br>

</li>
</ul>
<h3 id="📖-5-반복문">📖 5. 반복문</h3>
<h4 id="0-while-java와-동일">0. while (java와 동일)</h4>
<ul>
<li>do-while 사용 가능</li>
</ul>
<h4 id="1-for-python과-유사">1. for (python과 유사)</h4>
<ul>
<li>a..b는 a&lt;=x&lt;=b와 동일 (첫과 끝을 반드시 포함)</li>
<li>until을 써도 되지만 쓸모 없음<pre><code class="language-kotlin">fun main(){
  for (i in 1..10){
      println(evenOrOdd(i))
  }
  // 마지막 10 미포함 -&gt; until활용
  // for (i in 1&lt;= until &lt; 100)</code></pre>
</li>
</ul>
<h4 id="2-map">2. map</h4>
<ul>
<li>컬렉션 함수 존재 mutableMapOf, listOf, mapOf, setOf 사용 가능</li>
<li>순환 및 구조 분해 이용 가능 
순환 (s.key &amp; s.value) =&gt; for (s in students)
구조분해 (num,name) =&gt; for ((num, name) in students) <pre><code class="language-kotlin">val students = mutableMapOf&lt;Int, String&gt;()
  students[1] = &quot;lee&quot;
  students[2] = &quot;kim&quot;
  students[3] = &quot;park&quot;</code></pre>
</li>
</ul>
<blockquote>
<p>*<em>일반 mapOf는 to를 통해 key, value 선언 (가장 많이 사용)  *</em></p>
</blockquote>
<pre><code class="language-kotlin">val st = mapOf(
        1 to &quot;Jock&quot;,
        2 to &quot;Diana&quot;,
        3 to &quot;Frost&quot;
    )</code></pre>
<br>

<h3 id="📖-6-예외-처리">📖 6. 예외 처리</h3>
<h4 id="1-try-catch-new를-사용하지-않음">1. try catch (new를 사용하지 않음)</h4>
<ul>
<li><p>when처럼 반환의 값으로 취급</p>
<pre><code class="language-kotlin">fun parse(numberStr: String): Int = try {
  Integer.parseInt(numberStr)

  throw IOException(&quot;일부로 발생시키는 checked exception&quot;)
} catch (e: IOException) {
  throw RuntimeException(&quot;UnChecked exception으로 변환&quot;) // 후에 설명할 checked  Exception 처리 방식
} finally {
  println(&quot;무조건 실행되는 코드블록&quot;)
}</code></pre>
</li>
</ul>
<blockquote>
<p><strong>중요 @Transactional과 checked Exception</strong></p>
</blockquote>
<ul>
<li><p>Checked Exception: 컴파일 타임에 체크되는 예외 = 처리를 해야 코드가 돌아감
Ex) IOException, SQLException, ClassNotFoundException 등</p>
</li>
<li><p>Unchecked Exception: NullPointerException 같은 작동 중에 발생하는 에러 </p>
</li>
</ul>
<p>*<em>Java에서는 @Transcational을 사용하면 unchecked exception이 발생할 경우에만 트랜잭션을 롤백한다. *</em></p>
<p>= 컴파일 과정에서, reader로 읽을 파일이 존재하는지, 읽기 권한은 있는지 등의 checked Exception이 발생할 수 있는 에러는 찾아서 실행을 막음(이미 걸러짐) =&gt; Unchecked Exception이 발생했을 때만 롤백해도 정상적으로 작동</p>
<p><strong>Kotiln에서는 Checked Exception이 없음 즉, @Transcational을 사용하면 checked exception이 발생한 경우 롤백하지 않는다.</strong></p>
<p>= IO Exception과 같은 checked Exception이 발생했을 경우 강제로 unchecked Exception을 던져주거나, 롤백하는 코드가 필요
pstmt1이 실행하는 sql문이 name으로 찾아서 update라면, update가 실패할 가능성 존재</p>
<pre><code class="language-java">try (PreparedStatement pstmt1 = connection.prepareStatement(sql1);

                // 쿼리 실행 (예외 발생 가능성)
                pstmt1.setString(1,&quot;Bob&quot;);
                pstmt1.executeUpdate();

                // 모든 쿼리가 성공적으로 실행되면 커밋
                connection.commit();
            } catch (SQLException e) {
                // 예외 발생 시 롤백
                System.out.println(&quot;예외 발생: &quot; + e.getMessage());
                if (connection != null) {
                    try {
                        connection.rollback();
                        System.out.println(&quot;트랜잭션 롤백 완료&quot;);
                    } catch (SQLException rollbackEx) {
                        System.out.println(&quot;롤백 중 오류 발생: &quot; + rollbackEx.getMessage());
                    }
                }
            }</code></pre>
<br>

<h3 id="📖-7-확장-함수-및-확장-프로퍼티">📖 7. 확장 함수 및 확장 프로퍼티</h3>
<h4 id="1-확장-함수-kotlin은-기본적으로-final">1. 확장 함수 (kotlin은 기본적으로 final)</h4>
<ul>
<li>kotlin의 함수들은 강제로 Open을 달아주지 않는 이상 상속할 수 없다. (List와 같은 라이브러리 함수의 경우 상속이 불가능)</li>
<li>오버라이딩은 불가능 / 오버로딩은 가능</li>
<li>기본 형태는 fun 피확장함수명.새확장함수명  ( )</li>
</ul>
<h4 id="이-코드는-list를-상속받아-generic-데이터를-기준-값으로-정하는-확장-함수">이 코드는 List를 상속받아 generic 데이터를 기준 값으로 정하는 확장 함수</h4>
<ul>
<li>참고 : generic은 함수를 선언할 때, 이게 generic함수라는 것을 알려줘야함 <pre><code class="language-kotlin">fun &lt;E&gt; List&lt;E&gt;.getHigherThan(num: E): List&lt;E&gt; {
  // 구현....
  return arrayListOf&lt;E&gt;()
}</code></pre>
</li>
</ul>
<blockquote>
<p><strong>중요 :  확장 함수는 정적 바인딩된다!</strong></p>
</blockquote>
<pre><code class="language-kotlin">open class Idol {
    open fun sing() = println(&quot;아이돌이 노래를 불러요&quot;)
}

class BTS: Idol() {
    override fun sing() = println(&quot;BTS가 노래를 불러요&quot;)
}

fun Idol.dance() = println(&quot;아이돌이 춤을 춰요&quot;)
fun BTS.dance() = println(&quot;BTS가 춤을 춰요&quot;)

fun main() {
    // 부모 타입으로 자식 객체 생성
    val bts: Idol = BTS()
    bts.sing() // BTS가 노래를 불러요
    bts.dance() // 아이돌이 춤을 춰요
}</code></pre>
<p>타입과 객체 : Idol 타입의 변수인 bts는 Idol 클래스 또는 그 자식 클래스인 BTS의 객체를 참조</p>
<ul>
<li>sing은 일반 함수이기 때문에 동적바인딩 즉 bts가 처음에는 부모 클래스인 <strong>Idol타입</strong>이지만 default값으로 자식 클래스인 <strong>BTS 객체</strong>로 선언될 때를 인식하고 =&gt; BTS</li>
<li>dance는 확장 함수이기 때문에 정적바인딩 되어서, 처음 부모 클래스인 <strong>Idol타입</strong>으로 인식 =&gt; Idol</li>
</ul>
<h4 id="2-확장-프로퍼티">2. 확장 프로퍼티</h4>
<ul>
<li>확장 함수와 유사한 형태로</li>
<li>단 일회성</li>
<li>getter는 필수 / setter는 선택</li>
</ul>
<pre><code class="language-kotlin">var StringBuilder.lastChar: Char
    get() = get(length - 1)
    set(value: Char) {
        this.setCharAt(length - 1, value)
    }

fun main() {
    val sb = StringBuilder(&quot;Gold&quot;)
    sb.lastChar = &#39;f&#39;
    println(sb) // golf
}</code></pre>
<br>

<h3 id="📖-8-인터페이스와-상속">📖 8. 인터페이스와 상속</h3>
<h4 id="1-인터페이스-반드시-overrride">1. 인터페이스 (반드시 overrride)</h4>
<ul>
<li>implements나 extends로 구현하지 않고 코틀린에서는 : 으로</li>
<li>다중 상속도 동일하게 가능 </li>
</ul>
<h4 id="2-상속-반드시-open으로-선언-필수">2. 상속 (반드시 Open으로 선언 필수)</h4>
<ul>
<li>메소드도 open으로 선언해야 상속 가능 </li>
<li>상속받은 메소드(override)는 재상속 가능</li>
<li>다중 상속도 동일하게 가능 </li>
</ul>
<blockquote>
<p><strong>상속 생성자 선언 방법</strong></p>
</blockquote>
<ul>
<li><p>주 생성자(All args)는 선언부에서 기본으로 생성</p>
</li>
<li><p>부 생성자는 construct를 통해 생성하고 :뒤에 this - 다른 생성자, super - 상속 클래스 생성자를 호출</p>
<pre><code class="language-kotlin">class Child : Parent{
  private val subName:String

  constructor(subName: String):this(subName, &quot;&quot;)

  constructor(subName:String, firstName: String):super(firstName){
      this.subName = subName
  }
}</code></pre>
</li>
</ul>
<p><strong>위 코드의 간소화</strong></p>
<ul>
<li>subName만 있을 때는 firstName을 &quot;&quot;으로 받으므로 =&gt; Default 값으로 변경</li>
<li>firstName이 존재할 경우 부모 클래스의 생성자 호출<pre><code class="language-kotlin">class Child(val subName:String, firstName: String = &quot;&quot;) : Parent(firstName)</code></pre>
</li>
</ul>
<h3 id="📖-9-sealed봉인된-class">📖 9. Sealed(봉인된) class</h3>
<ul>
<li>인터페이스와 달리, 클래스로 인식되어서 클래스명()로<h4 id="1-인터페이스를-사용-중에-추가된-클래스가-있을-때">1. 인터페이스를 사용 중에 추가된 클래스가 있을 때</h4>
</li>
<li>추가 클래스가 있을 때, getMessage 함수에서 컴파일 단계에서 에러로 처리되지 않음 =&gt; else처리</li>
</ul>
<pre><code class="language-kotlin">interface Error

class FileError(val filename:String) : Error

class DatabaseError(val database:Database) : Error

class RedisError(val host:String): Error

enum class Database{
    ORACLE, MYSQL, MARIADB;
}

fun getMassage(error: Error) = when(error){
    is FileError -&gt; &quot;error is fileError ${error.filename}&quot;
    is DatabaseError -&gt; &quot;error is databaseError ${error.database.name}&quot;
    else -&gt; throw IllegalArgumentException(&quot;error is unknown&quot;)
}</code></pre>
<h4 id="2-sealed-class를-사용-중에-추가된-클래스가-있을-때">2. sealed class를 사용 중에 추가된 클래스가 있을 때</h4>
<ul>
<li>RedisError를 추가하면, getMessage2에 RedisError에 대한 처리가 안되어있기 때문에 처리 편리 =&gt; enum에서 -&gt; 이용하는 방식과 동일한 원리<pre><code class="language-kotlin">sealed class Error2{
  class FileError(val filename:String) : Error2()
  class DatabaseError(val database:Database) : Error2()
  class RedisError(val host:String): Error2()
}
</code></pre>
</li>
</ul>
<p>enum class Database2{
    ORACLE, MYSQL, MARIADB;
}</p>
<p>fun getMassage2(error: Error2) = when(error){
    is Error2.DatabaseError -&gt; &quot;error is databaseError ${error.database.name}&quot;
    is Error2.FileError -&gt; &quot;error is fileError ${error.filename}&quot;
    is Error2.RedisError -&gt; &quot;error is redisError ${error.host}&quot;
}</p>
<pre><code>&lt;br&gt;

### 📖 10. 활용 (private set / data class / object class)
#### 1. set 제한 (private set)
```kotlin
class Account {
    var balance: long = 0
    private set
}</code></pre><h4 id="2-data-class-java의-record와-유사">2. data class (java의 record와 유사)</h4>
<blockquote>
<p><strong>toString을 쓴 것 처럼 객체 안의 내용을 확인 가능 =&gt; 객체 조회시 이름@주소가 아니라, 주 생성자의 값들이 출력됨</strong></p>
</blockquote>
<ul>
<li>DTO 생성 시 유용</li>
<li>toString()/equals()/hashCode() 사용 가능<pre><code class="language-kotlin">data class User(val name: String, val age: Int)</code></pre>
</li>
</ul>
<h4 id="3-object-키워드-싱글톤-패턴">3. object 키워드 (싱글톤 패턴)</h4>
<ul>
<li>object라고만 써야함 (class x )</li>
<li>유일 인스턴스가 자동으로 생성<pre><code class="language-kotlin">object NumberUtil {
  fun sum(a:Int, b:Int) = a+b
  fun multiply(a:Int, b:Int) = a*b
}
</code></pre>
</li>
</ul>
<p>fun main() {
    println(NumberUtil.multiply(10 ,2))
}</p>
<pre><code>&lt;br&gt;
- 익명 클래스로 사용 가능

&gt; **참고 : companion Object**

- static 대용으로 사용 가능 (클래스 생성 시 팩토리 생성자 기능)
=&gt; 상수 선언
=&gt; 처음 생성되는 데이터의 나이를 0으로 고정하는 팩토리 생성자
```kotlin
data class Child (val name:String, val age:Int){
    companion object {
        const val MAX_CHILDREN = 4

        fun ofDefaultAge(subName:String):Child{
            return Child(subName, 0)
        }
    }
}</code></pre><h3 id="intellij-kotlin-프로젝트-tip">intellij kotlin 프로젝트 Tip</h3>
<ul>
<li>생성한 kotlin 폴더가 특수 폴더로 지정되지 않을 때
<img src="https://velog.velcdn.com/images/ashd_89/post/0bcbd6a4-2afe-4e16-9b2f-2a4242412815/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[리팩토링 기술 정리]]></title>
            <link>https://velog.io/@ashd_89/%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-%EA%B8%B0%EC%88%A0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@ashd_89/%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-%EA%B8%B0%EC%88%A0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 14 Dec 2024 15:01:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ashd_89/post/b2a9aa06-532c-4e3e-8d93-4a21047cceb3/image.png" alt=""></p>
<h2 id="📌-코딩으로-학습하는-리팩토링">📌 코딩으로 학습하는 리팩토링</h2>
<blockquote>
<p><strong>강의를 들으면서 유용한 단축키나 정보를 정리한다!!!</strong></p>
</blockquote>
<h3 id="📖-냄새-0-기초-환경-설정">📖 냄새 0. 기초 환경 설정</h3>
<h4 id="1-환경-변수-텍스트-파일로-지정">1. 환경 변수 텍스트 파일로 지정</h4>
<p>기초 환경 설정 중 githubBuilder를 이용해 필요한 oauth 정보를 home에서 텍스트 파일로 만들어서 넘겨주도록 구현한 부분이 있는데 file 클래스를 활용하여, 경로를 지정해서 oauth값을 받을 수 있다면, 다른 yml파일의 변수들도 같은 방식으로 사용 가능하지 않을까? 
<strong>=&gt; 시간 남을때 조금 더 공부해보자</strong></p>
<pre><code class="language-java">public static GitHubBuilder fromPropertyFile() throws IOException {
        File homeDir = new File(System.getProperty(&quot;user.home&quot;));
        File propertyFile = new File(homeDir, &quot;.github&quot;);
        return fromPropertyFile(propertyFile.getPath());
    }

    public static GitHubBuilder fromPropertyFile(String propertyFileName) throws IOException {
        Properties props = new Properties();
        FileInputStream in = null;

        try {
            in = new FileInputStream(propertyFileName);
            props.load(in);
        } finally {
            IOUtils.closeQuietly(in);
        }

        return fromProperties(props);
    }</code></pre>
<h4 id="2-ctrl-----ctrl--shift---">2. ctrl + -&gt; / ctrl + shift + -&gt;</h4>
<ul>
<li>ctrl + -&gt;는 단어 단위 이동</li>
<li>ctrl + shift + -&gt;는 끝과 끝으로 (원래는 END/HOME이지만 keymap에서 편의상 변경)
<img src="https://velog.velcdn.com/images/ashd_89/post/5b93ee9d-7303-4a68-baf9-389b438b671e/image.png" alt=""></li>
</ul>
<br>

<h3 id="📖-냄새-1-이름">📖 냄새 1. 이름</h3>
<ul>
<li>shift + F6 (전체 범위 이름 변경)</li>
<li>ctrl + F6 (이름 뿐 아니라, 보내는 type, 매개변수 등도) - <strong>선언부만 바뀜</strong></li>
</ul>
<hr>
<ul>
<li>Method Reference = 람다식을 : : 으로 간략하게<pre><code class="language-java">.forEach(name -&gt; System.out.println(name)); -&gt; .forEach(System.out::println);</code></pre>
</li>
</ul>
<hr>
<ul>
<li><p>최신기술 Record (유사 딕셔너리) = Dto를 만들어주면서 자동으로 getter, setter, hashcode(), equals()가 생성  </p>
<ul>
<li>hashcode( ) : 객체마다 고유 값</li>
<li>equals( ) : 값이 같은지</li>
</ul>
<pre><code class="language-java">public record StudyReview(String reviewer, String review){ }
</code></pre>
</li>
</ul>
<hr>
<br>

<h3 id="📖-냄새-2-중복">📖 냄새 2. 중복</h3>
<ul>
<li>shift + F6 (전체 범위 이름 변경)</li>
<li>ctrl + F6 (이름 뿐 아니라, 보내는 type, 매개변수 등도) - <strong>선언부만 바뀜</strong></li>
</ul>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[리팩토링 계획]]></title>
            <link>https://velog.io/@ashd_89/Refactoring-%EA%B3%84%ED%9A%8D</link>
            <guid>https://velog.io/@ashd_89/Refactoring-%EA%B3%84%ED%9A%8D</guid>
            <pubDate>Sat, 14 Dec 2024 14:46:50 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ashd_89/post/db92f25b-eff1-4a0d-ad35-44d026772992/image.png" alt=""></p>
<h2 id="📌-tiggle-리팩토링">📌 Tiggle 리팩토링</h2>
<h3 id="지금-생각하는-과정은-다음과-같다-계속-수정-예정">지금 생각하는 과정은 다음과 같다. (계속 수정 예정)</h3>
<p>2024년 말 목표</p>
<blockquote>
<ol>
<li>자동 배포환경 구성</li>
<li>리팩토링에 관한 공부</li>
<li>스프링 시큐리티에 대한 심화 학습</li>
</ol>
</blockquote>
<h3 id="📖-1-cicd-자동-배포를-먼저-구성하고-서버의-가용율을-확인하면서-리팩토링을-진행하고자-한다">📖 1. CI/CD 자동 배포를 먼저 구성하고, 서버의 가용율을 확인하면서, 리팩토링을 진행하고자 한다.</h3>
<p>jenkins와 argoCD를 활용하고, 백과 프론트를 각각 Blue-Green과 Canary방식을 생각 중이다. </p>
<ul>
<li><input disabled="" type="checkbox"> <strong>VM ware로 가상 PC 4대</strong>를 만들고 (백엔드 만해도 4대인데, 컴퓨터에서 감당이 될지 모르겠다...  AWS는 실수하면 돈이 많이 나갈 위험이 있어서 일단 고려 사항에는 두는게 맞는 것 같다.)</li>
<li><input disabled="" type="checkbox"> <strong>Master-worker에 쿠버네티스 설치</strong>하고 연결까지</li>
<li><input disabled="" type="checkbox"> <strong>Jenkins랑 ArgoCD설치</strong>하고,</li>
<li><input disabled="" type="checkbox"> <strong>mariadb 설치는 worker에</strong> </li>
<li><input disabled="" type="checkbox"> <strong>Repo하나 파서 Webhook 연결하고</strong></li>
<li><input disabled="" type="checkbox"> <strong>depolyment.ymal 및 Jenkins pipeline 작성하고</strong></li>
<li><input disabled="" type="checkbox"> 결과적으로 <strong>Backend를 자동 배포 되게해서 디스코드 알람오게 만드는 것</strong> 까지가 1차 목표</li>
</ul>
<h3 id="📖-2-리팩토링의-방법에-대한-공부는-조금씩-진행한다">📖 2. 리팩토링의 방법에 대한 공부는 조금씩 진행한다.</h3>
<p>리팩토링이 말 그대로 더 나은 방향으로 바꾸는 것이지만, 어떤 부분을 어떤 식으로 바꾸는게 맞는지에 대한 명확한 지식이 없다. 아는 것은 중복 코드나, 알아보기 쉬운 변수명 수정 정도? 
<strong>인프런 강의 : 코딩으로 학습하는 리팩토링 - 백기선</strong>
<a href="https://www.inflearn.com/course/%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81">https://www.inflearn.com/course/%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81</a>
이 강의 영상을 매일 조금씩 공부하면서 기본적인 리팩토링의 구조를 알고, 적용해 나가는 방향으로 Tiggle 프로젝트 리팩토링을 진행할 것이다.</p>
]]></description>
        </item>
    </channel>
</rss>