<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ji-ha.log</title>
        <link>https://velog.io/</link>
        <description>기초가 단단한 프로그래머 -ing</description>
        <lastBuildDate>Wed, 26 Oct 2022 08:11:03 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>ji-ha.log</title>
            <url>https://images.velog.io/images/ji-ha/profile/7d271155-6bbc-4df4-b025-a2cea9b614a3/face.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ji-ha.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ji-ha" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Message Driven vs Event Driven]]></title>
            <link>https://velog.io/@ji-ha/Message-Driven-vs-Event-Driven</link>
            <guid>https://velog.io/@ji-ha/Message-Driven-vs-Event-Driven</guid>
            <pubDate>Wed, 26 Oct 2022 08:11:03 GMT</pubDate>
            <description><![CDATA[<h2 id="개념의-혼돈">개념의 혼돈</h2>
<p>리액티브 프로그래밍을 접해보고, 아키텍쳐에 대해서 배우다보니 <strong>무슨무슨 드리븐</strong>에 대해서 엄청나게 많이 듣는다. 그 중에서도 헷갈리던 개념인 <strong>Message Driven, Event Driven</strong>에 대해서 정리되어 있는 글이 있길래 번역하여 이해해보고 어떻게 사용하는 게 올바른 것인지 이해해보자.</p>
<h2 id="reactive-system">Reactive System?</h2>
<p>일단, 배우게 된 리액티브 프로그래밍에 대해서 잠깐 봐보자.</p>
<blockquote>
<p>Reactive Systems rely on <strong><em>asynchronous message-passing</em></strong> to establish a boundary between components that ensures <em><strong>loose coupling</strong></em>, <em><strong>isolation and location transparency</strong></em>.</p>
</blockquote>
<p>리액티브 시스템은 비동기적인 메시지 패싱에 의존한다고 되어있다.
의존하는 이유는 세가지이다.</p>
<ul>
<li><strong>loose coupling</strong> -&gt; 느슨한 결합</li>
<li><strong>isolation</strong> -&gt; 아이솔레이션</li>
<li><strong>location transparency</strong> -&gt; 위치 투명성</li>
</ul>
<p>이랬을 때의 장점으로는
부하관리가 가장 큰 것 같고 탄력성, message queue를 통한 모니터링 및 흐름 제어가 존재한다.</p>
<h2 id="message-vs-event">Message vs Event</h2>
<p>Message는 특정한 주소로 data를 보내는 것이다.
Message Driven은 각각의 컴포넌트가 특정한 주소를 가지고, 다른 컴포넌트도 메세지를 보낼 수 있는 구조라고 한다.
<em>이해하기로는 그냥 현재의 RESTful API들이다.</em></p>
<p>반면에 Event는
컴포넌트에서 데이터를 던진다. 아무나에게! <em>시간 괜찮은 사람이 처리해달라고.</em></p>
<h3 id="sending-messages-vs-emitting-events">Sending Messages vs Emitting Events</h3>
<p><strong>전통적인 프로그래밍 모델</strong>들은 컴포넌트 A가 컴포넌트 B의 메소드를 호출하는 식으로 동작하였다.</p>
<ul>
<li>만약에 B가 현재 바쁘거나, 애초에 느렸다면 A는 기다려준다. <del>로맨티스트</del></li>
</ul>
<p><strong>Message Driven System</strong>에서는 컴포넌트 A는 메세지를 만들고 컴포넌트 B의 주소로 배달되어야한다.</p>
<ul>
<li>컴포넌트 A는 메세지를 전송하고, control을 다시 받는다.<em>(전통적인 방식과 다르게 컴포넌트 B에게 하라고 시킨 후에 A는 자기 할일을 하는 것이다)</em></li>
<li>Message Driven에서의 컴포넌트는 주로 Queue를 가진다. 이러한 Queue는 들어오는 메세지들에 대해서 load spike(부하 지점)_(제일 많이 신경써야하는 부분)_가 되는 부분이기도 하다.</li>
</ul>
<p><strong>Event Driven</strong>에서 컴포넌트들은 이벤트를 expose하는 위치만을 알려준다.</p>
<ul>
<li>컴포넌트 A는 이벤트를 던지지만(emit), 누가 이 이벤트를 처리하는지는 알지 못한다.</li>
<li>위치는 ordered queue를 사용한다.</li>
<li>consumer(일을 처리할 사람들)들은 이미 소비된 이벤트와 보류중인 이벤트를 추적할 수 있도록 Queue를 인덱싱하는 경우도 있다.</li>
</ul>
<h3 id="difference">Difference?</h3>
<blockquote>
<p>그래서 둘의 차이는 뭘까?</p>
</blockquote>
<p><strong>Message Driven</strong>은 누가 메세지를 받아서 처리하는지 <strong>정해져(fixed) 있다</strong>.
<em>(아는 사람 -&gt; 아는 사람)</em></p>
<p><strong>Event Driven</strong>은 <strong>일단 이벤트를 던져</strong>버린다. <em>&#39;누군가 처리해주겠지&#39;라는 생각으로.</em> 그리고 consumer들은 이를 받아서 처리한다.
<em>(아는 사람 -&gt; 모르는 사람)</em></p>
<h2 id="잘못이해하지마">잘못이해하지마!</h2>
<p>하지만 여전히 혼동하기 쉬운 개념들이다. 마지막으로 정리를 해본다면,
Message Driven -&gt; <strong>시스템의 building block</strong>을 나타내고
Event Driven -&gt; <strong>시스템의 상위 수준 속성</strong>(higher level property)<em>(==architecture)</em></p>
<p>따라서, Message Driven tool들을 사용하여 Event Driven System을 만들 수 있다는 뜻이다. <em>== kafka를 사용하여 Event Driven을 만든다고 생각한다.</em></p>
<h3 id="내가-이해한-것">내가 이해한 것</h3>
<p>Message Driven은 도구이고, Event Driven은 구조이다.
-&gt; 이벤트 드리븐 아키텍쳐에서 채택할 수 있는 도구 중 하나가 메세지 드리븐이라고 생각하게 되었다. 다른 도구는 무엇이 있는데? 라고한다면 아직... 모르겠다. 어떤 게 더 있는지는 좀 더 찾아봐야할 것 같다.</p>
<p><a href="https://developer.lightbend.com/docs/akka-platform-guide/concepts/message-driven-event-driven.html">참고자료</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Race Condition & Critical Section & Semaphore, Mutex]]></title>
            <link>https://velog.io/@ji-ha/Race-Condition-Critical-Section-Semaphore-Mutex</link>
            <guid>https://velog.io/@ji-ha/Race-Condition-Critical-Section-Semaphore-Mutex</guid>
            <pubDate>Tue, 29 Mar 2022 03:34:09 GMT</pubDate>
            <description><![CDATA[<h3 id="항상-deadlock을-따라다니는-세-친구들">항상 deadlock을 따라다니는 세 친구들</h3>
<p>자료들을 읽다보면, Race Condition부터 시작하여 Critical Section이 무엇인지 그리고 이를 해결하기 위한 Semaphore와 mutex가 무엇인지 설명하고 시작하는 경우가 많다.
이번 기회에 어떤 친구들인지 알아보기로 하자.</p>
<h3 id="race-condition">Race Condition</h3>
<p>동시에 여러개의 프로세스가 동일한 자료를 접근하여 조작하고,</p>
<p>그 실행 결과가 특정 순서에 의존하는 상황</p>
<p>ex</p>
<p><img src="https://images.velog.io/images/ji-ha/post/cfd9f6b2-83cf-491a-8313-fa6224035b48/raceCondition.png" alt=""></p>
<p>이렇게 되어버리면 사용자가 원하는 결과를 얻지 못하고, 이상한 값들을 가지게 된다.</p>
<p>그래서 이러한 문제를 해결하기 위한 접근 방법이 <strong>Critical Section Problem</strong> 이다.</p>
<h3 id="critical-section임계영역">Critical Section(임계영역)</h3>
<p>동일한 자원을 동시 접근하는 작업을 실행하는 코드 영역</p>
<h4 id="critical-section-problem임계영역-문제">Critical Section Problem(임계영역 문제)</h4>
<p>프로세스들이 Critical Section을 함께 사용할 수 있는 프로토콜을 설계하는 것</p>
<p>이를 해결하려면 3가지 조건들이 <strong>모두 만족</strong>해야한다.</p>
<blockquote>
</blockquote>
<ul>
<li>Mutual Exclusion(상호 배제)<ul>
<li>프로세스 P1이 Critical Section에서 실행 중이라면, <strong>다른 프로세스들은 그들이 가진 Critical Section에서 진행될 수 없다.</strong></li>
</ul>
</li>
<li>Progress(진행)<ul>
<li>Critical Section에서 실행중인 프로세스가 없고, 별도의 동작이 없는 프로세스들만 Critical Section 진입 후보로서 참여될 수 있다.</li>
</ul>
</li>
<li>Bounded Waiting(한정된 대기)<ul>
<li>P1가 Critical Section에 진입 신청 후부터 받아들여질 때까지, 다른 프로세스들이 Critical Section에 진입하는 횟수는 제한이 있어야 한다.</li>
</ul>
</li>
</ul>
<h3 id="semaphore--mutex">Semaphore &amp; Mutex</h3>
<h4 id="semaphore">Semaphore</h4>
<p>임계구역을 설정하여 그 동안에는 <strong>다른 프로세스가 접근하지 못하도록 하는 방법</strong></p>
<p>가용한 개수를 가진 자원에 대한 접근 제어용으로 사용. semaphore는 가용한 자원의 개수로 초기화 한다.</p>
<p>자원을 사용하면 세마포가 감소하고, 방출하면 세마포가 증가한다.</p>
<ul>
<li>P와 V라는 동작이 있다고 가정함.<ul>
<li>P: 임계 구역 들어가기 전에 수행 ( 프로세스 진입 여부를 자원의 개수(S)를 통해 결정)</li>
<li>V: 임계 구역에서 나올 때 수행 (자원 반납 알림, 대기 중인 프로세스를 깨우는 신호)</li>
</ul>
</li>
</ul>
<h4 id="mutex">Mutex</h4>
<ul>
<li>프로세스가 임계구역에 들어가기 전에 lock을 획득하고, 나올 때 lock을 반환한다.</li>
<li>상태가 0, 1인 <strong>이진 세마포어</strong>라고 부르기도 한다.</li>
</ul>
<h4 id="문제점">문제점</h4>
<p>busy waiting 
→ 자원을 얻을 때까지 계속 확인하는 것을 의미
→ CPU 자원을 쓸데 없이 낭비하기 때문에 좋지 않은 쓰레드 동기화 방식</p>
<h4 id="해결방법">해결방법</h4>
<p>wait하는 함수에 block()이라는 함수 추가 → list에 자기 자신을 등록하고 sleep()하는 함수</p>
<p>wakeup(): signal()함수 내부에서 실행. 대기하고 있는 프로세스 중 하나를 깨워줌</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DeadLock]]></title>
            <link>https://velog.io/@ji-ha/DeadLock</link>
            <guid>https://velog.io/@ji-ha/DeadLock</guid>
            <pubDate>Tue, 29 Mar 2022 03:23:32 GMT</pubDate>
            <description><![CDATA[<h3 id="들어가기-전에">들어가기 전에</h3>
<p><a href="https://velog.io/@ji-ha/Race-Condition-Critical-Section-Semaphore-Mutex">데드락을 알기위한 사전 지식들</a>
위의 링크를 한번 읽고 오는 게 좋겠다. 데드락이 왜 발생할 수 밖에 없었는지에 대한 개념 설명 글이다.</p>
<h3 id="무엇">무엇</h3>
<p>프로세스가 <strong>자원을 얻지 못해서 다음 처리를 하지 못하는 상태</strong></p>
<p>→ 교착 상태 라고도 부른다.</p>
<p>→ 시스템적으로 <strong>한정된 자원</strong>을 여러 곳에서 사용하려고할 때 발생.</p>
<h3 id="왜발생">왜(발생?)</h3>
<p>프로세스 1과 2가 자원 1, 2를 모두 얻어야할 때, p1이 자원 1을 가지고, p2가 자원 2를 가지고 있는 상태라면,</p>
<p>서로 원하는 자원이 상대방에 할당되어 두 프로세스는 무한정 wait 상태에 빠진다.</p>
<p>→ 멀티 프로그래밍 환경에서 한정된 자원을 얻기 위해 서로 경쟁하는 상황 발생</p>
<p>→ 한 프로세스가 자원을 요청했을 때, 동시에 그 자원을 사용할 수 없는 상황이 발생할 수 있다. 이때 프로세스는 대기 상태로 들어간다.</p>
<p>→ 대기 상태로 들어간 프로세스들이 실행 상태로 변경될 수 없을 때 <strong>교착상태</strong> 발생</p>
<h3 id="데드락-발생-조건">데드락 발생 조건</h3>
<p>데드락이 일어나는 조건 4가지가 있음.</p>
<p>이 4가지를 모두 만족해야 데드락이 발생함!</p>
<ul>
<li>Mutual exclusion(상호 배제): 자원은 한번에 한 프로세스만 사용할 수 있음.</li>
<li>Hold and Wait(점유 대기): 최소한 하나의 자원을 점유하고 있으면서 다른 프로세스에 할당되어 사용하고 있는 자원을 추가로 점유하기 위하여 대기하는 프로세스가 존재해야 한다.</li>
<li>No Preemtion(비선점): 다른 프로세스에 할당된 자원은 사용이 끝날 때까지 강제로 뺏을 수 없다.</li>
<li>Circular Wait(순환 대기): 프로세스의 집합에서 순환 형태로 자원을 대기하고 있어야한다.</li>
</ul>
<h3 id="어떻게해결">어떻게(해결?)</h3>
<h4 id="데드락-예방--회피">데드락 예방 &amp; 회피</h4>
<ul>
<li>예방: 교착 상태 발생 조건 중에 하나를 제거하여 해결한다(자원 낭비가 심하다)<ul>
<li>상호배제 부정: 여러 프로세스가 공유 자원 사용</li>
<li>점유대기 부정: 프로세스 실행 전에 모든 자원을 할당</li>
<li>비선점 부정: 자원 점유 중인 프로세스가 다른 자원을 요구할 때 가진 자원 반납</li>
<li>순환대기 부정: 자원에 고유번호 할당 후 순서대로 자원 요구</li>
</ul>
</li>
<li>회피: 교착 상태 발생 시 피해나가는 법<ul>
<li>Banker’s Algorithm(은행원 알고리즘)<ul>
<li>은행에서 모든 고객의 요구가 충족되도록 현금을 할당하는데서 유래</li>
<li>프로세스가 자원을 요구할 때, 시스템은 자원을 할당한 후에도 안정 상태로 남아있게 되는지 사전에 검사하여 교착상태 회피</li>
<li>안정 상태면 자원 할당, 아니면 다른 프로세스들이 자원 해지까지 대기</li>
</ul>
</li>
<li>단점
  -<strong>시스템 과부하가 증가</strong><ul>
<li>일정하게 남아있는 자원 수 파악 힘듦</li>
<li>다중 프로그래밍 시스템에서는 사용자 수가 항상 변함</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="데드락-탐지--회복">데드락 탐지 &amp; 회복</h4>
<p>→ 교착 상태가 되는 것은 허용하고, 그 후에 회복시키는 방법
-&gt; (걍 다시 돌아갈 수 있을 때 까지 프로그램을 강제 종료하는 것!)</p>
<ul>
<li>탐지<ul>
<li>자원 할당 그래프를 통해 교착 상태를 탐지</li>
<li>자원 요청 시, 탐지 알고리즘을 실행시켜서 그에 대한 오버헤드 발생함</li>
</ul>
</li>
<li>회복: 교착 상태 일으킨 프로세스를 종료하거나, 할당된 자원을 해제시켜 회복시키는 방법<ul>
<li>프로세스 종료 방법<ul>
<li>교착 상태의 프로세스를 모두 중지</li>
<li>교착 상태가 제거될 때까지 하나씩 프로세스 중지</li>
</ul>
</li>
<li>자원 선점 방법<ul>
<li>교착 상태의 프로세스가 점유하고 있는 자원을 선점해 다른 프로세스에게 할당(뺏긴 프로세스들은 일시정지 상태)</li>
<li>우선 순위가 낮은 프로세스나 수행 횟수 적은 프로세스 위주로 프로세스 자원 선점</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[IPC(InterProcess Communication)]]></title>
            <link>https://velog.io/@ji-ha/IPCInterProcess-Communication</link>
            <guid>https://velog.io/@ji-ha/IPCInterProcess-Communication</guid>
            <pubDate>Fri, 11 Feb 2022 09:07:00 GMT</pubDate>
            <description><![CDATA[<h1 id="ipcinterprocess-communication">IPC(InterProcess Communication)</h1>
<h2 id="사용하는-이유">사용하는 이유?</h2>
<p>Q) process간의 통신을 위해서! → (왜 통신해야하는데?)</p>
<p>A)</p>
<p>Information sharing(정보를 공유해야해서!)</p>
<p>Computation speedup(계산 속도가 빨라져서!)</p>
<p>modularity(모듈성?)</p>
<p>Convenience(편리해요!)</p>
<p>+전체적으로 보면, 멀티코어나 멀티CPU에서 멀티 프로세싱을 하기 위해서이다. 그 와중에 프로세스끼리 소통을 하려면 필요하기 때문이다</p>
<h2 id="ipc의-종류">IPC의 종류</h2>
<p><img src="https://images.velog.io/images/ji-ha/post/c8aed165-a11e-4c63-a3fe-859f67f196b7/IPC.png" alt=""></p>
<ul>
<li><p>Shared memory(오른쪽)</p>
<p>  특정공간(한 프로세스가 가지고 있는 부분)을 다른 프로세스가 접근할 수 있게 해준다!</p>
</li>
<li><p>Message passing(왼쪽)</p>
<p>  process A와 process B가 소통할 수 없기 때문에 kernetl을 통하여 데이터가 전송된다.</p>
</li>
</ul>
<p>추가적으로,</p>
<ul>
<li>Message Queue</li>
<li>Socket</li>
<li>ordinary&amp;named pipe</li>
</ul>
<p>이 있다. 추가적인 방식들은 <strong>client/server architecture에서 사용하는 communication 방법</strong>이다.</p>
<h2 id="shared-memory">Shared Memory</h2>
<p>shared memory를 구현하는 모델이 있다.</p>
<h3 id="producer-consumer-model">Producer-Consumer Model</h3>
<p>두 프로세스가 통신할 때, 한쪽은 데이터 생산자(Producer) 역할, 다른 한쪽은 데이터를 소비(Consumer)하는 역할만 한다.</p>
<p>생산자와 소비자가 데이터를 주고받을 때, <strong>shared memory가 버퍼 역할</strong>을 한다.</p>
<p>버퍼는 circular buffer를 사용한다.</p>
<h2 id="message-passing">Message Passing</h2>
<p>message passing은 shared memory를 사용하지 않기 때문에 시작하기위해서는 절차가 필요하다.</p>
<ol>
<li><p>communication link를 만든다.(이미 존재한다면, 다시 만들 필요는 없다!)</p>
</li>
<li><p>basic primitive를 이용하여 메시지를 교환한다.</p>
<p> 두가지 basic primitive가 존재한다.</p>
<p> <strong>send</strong>(message, dstination) or <strong>send</strong>(message)</p>
<p> <strong>receive</strong>(message, host) or <strong>receive</strong>(message)</p>
</li>
</ol>
<p>또한, message passing을 하는 방식에는 4가지가 있는데,</p>
<p><strong>Direct / Indirect Communication</strong></p>
<p><strong>Synchronous / Asynchronous Communication</strong></p>
<p>기본적인 메시지의 구조는 <strong>header와 body,</strong> 2부분으로 나뉜다.</p>
<h3 id="direct-communication">Direct Communication</h3>
<p>두개의 프로세스가 직접적으로 연결되는 것.</p>
<p>direct Communication에서 communication link의 특징</p>
<ul>
<li>link는 자동적으로 생성된다</li>
<li><strong>one pair processes에 링크되어 생성</strong>된다.(다른 프로세스가 껴들지 못한다!)</li>
<li>한 링크에는 한 쌍의 프로세스만 가능하다.</li>
<li>link는 unidirectional(단방향)일 수 있지만, 대부분은 bi-directional(양방향)이다.</li>
</ul>
<h3 id="indirect-communication">Indirect Communication</h3>
<p>mailbox라는 중간 매개체를 통하여 메시지를 주고받는 것.</p>
<p>indirect Communication에서 communication link의 특징</p>
<ul>
<li>프로세스들이 common mailbox를 공유한다 했을 때만 link가 생긴다.</li>
<li>하나의 link는 많은 process와 연결되어있다.</li>
<li>프로세스 각각의 쌍들(each pair of processes)은 여러 communication link를 공유할 수 있다.</li>
<li>unidirectional 또는 bi-directional link가 가능합니다!</li>
</ul>
<h3 id="synchronization">Synchronization</h3>
<p>보내고 받는 process가 동기화 되어 있다는 것 → sender와 receiver가 동시에 통신을 위한 행동을 해야한다.</p>
<p>동기화 하는 방법에는 Blocking과 Non-blocking 두가지가 있다.</p>
<p><del><strong>Blocking</strong>이 <strong>synchronous</strong>된 방법이고,</del></p>
<p><del><strong>Non-blocking</strong>이 <strong>nonsynchronous</strong>된 방법이다.</del></p>
<p><del><strong>Blocking</strong></del></p>
<p><del>Blocking send: sender block이 메시지를 받을 때까지 <strong>기다린다</strong>(block).</del></p>
<p><del>Blocking receive: receiver가 메시지를 사용할 수 있을 때까지 <strong>기다린다</strong>(block).</del></p>
<p><del>(non-blocking의 receive를 보면 좀 더 이해가 간다!)</del></p>
<p><del><strong>Non-Blocking</strong></del></p>
<p><del>Non-blocking send: sender가 메시지를 보내고 <strong>다른 할 일 한다.</strong></del></p>
<p><del>Non-blocking receive: <strong>valid</strong>하거나 <strong>null</strong>이거나 메시지를 받는다.</del>
<a href="https://musma.github.io/2019/04/17/blocking-and-synchronous.html">여기서 공부를 해봅시다</a></p>
<h2 id="참고">참고</h2>
<p><a href="https://www.geeksforgeeks.org/inter-process-communication-ipc/">https://www.geeksforgeeks.org/inter-process-communication-ipc/</a></p>
<p>대학교 운영체제 수업자료</p>
<h3 id="추가적으로">추가적으로..</h3>
<p>Sync, Async, blocking, non-blocking에 대한 설명이 추가되면 좋을 거 같아서 자료를 첨부한다. (스스로도 헷갈릴 때 와서보자!)
<a href="https://velog.io/@nittre/%EB%B8%94%EB%A1%9C%ED%82%B9-Vs.-%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-%EB%8F%99%EA%B8%B0-Vs.-%EB%B9%84%EB%8F%99%EA%B8%B0#2-sync-nonblocking">첨부1</a>
<a href="https://siyoon210.tistory.com/147#comment14503291">첨부2</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[abstract class와 inteface]]></title>
            <link>https://velog.io/@ji-ha/abstract-class%EC%99%80-inteface</link>
            <guid>https://velog.io/@ji-ha/abstract-class%EC%99%80-inteface</guid>
            <pubDate>Thu, 10 Feb 2022 09:24:43 GMT</pubDate>
            <description><![CDATA[<h2 id="abstract-classis-a">abstract class(is-a)</h2>
<ul>
<li>앞으로 구현될 클래스(상속받을)들의 방향성을 제시하는 역할</li>
<li>직접 객체를 만들 수 없습니다!</li>
<li>이 클래스는 무조건 하나의 abstarct method가 있어야합니다.</li>
<li>클래스 <strong>계층구조를 만들기 위해서</strong> base class를 define할 때 주로 사용합니다!</li>
<li>뼈대</li>
</ul>
<h2 id="interfacehas-a">Interface(has-a)</h2>
<ul>
<li>interface에 정의된 메소드를 각 클래스 목적에 맞게 구현하는 것</li>
<li>methods, properties, events, indexers(특정 클래스나 구조체의 인스턴스가 배열과 같이 인덱싱되게 해주는 것)들을 가질 수 있습니다.</li>
<li>interface는 <strong>선언만</strong>할 수 있습니다!!!!</li>
<li>그렇다면 interface 멤버들의 구현은?<ul>
<li>implicitly, explicitly(암시적, 또는 명시적으로) interface를 구현하는 클래스에서 제공해야합니다!</li>
</ul>
</li>
<li>기능</li>
</ul>
<h2 id="abstract-class와-interface의-차이">abstract class와 interface의 차이</h2>
<p><img src="https://images.velog.io/images/ji-ha/post/95cee36a-82ff-49fd-b5eb-5983657be50e/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-10%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%206.23.51.png" alt=""></p>
<p>비교 중에서 abstract class가 interface보다 빠르다!라고 하는 부분이 있다.</p>
<p>왜 빠른지, 이유가 확실하게 나온 것 같지는 않아서 찾아보던 중에 <a href="https://stackoverflow.com/questions/51112973/are-abstract-classes-faster-than-interfaces-in-java">스택오버플로우</a>를 찾았다!</p>
<h3 id="간략하게-설명해보면">간략하게? 설명해보면,</h3>
<p>class에는 재정의가 가능한 method table이 존재한다.</p>
<p>이 테이블은 상속이 가능하며, 새 메서드를 추가하거나 재정의한 메서드에 대해서 테이블 항목을 대체할 수 있다.</p>
<p>그래서 abstract class같은 경우는 그냥 재정의된 메서드를 테이블에서 찾기만하면 되니까 빠르다할 수 있다.</p>
<p>반면에, interface는 상속관계가 없는 다른 인터페이스에서도 구현할 수 있기 때문에, 구현 메서드는 해당하는 클래스에 속해있는 테이블까지 찾아가야한다. 이를 해결하는 방법이 ‘<strong>double-dispatch</strong>’라는 방법인데, 인터페이스의 테이블에서 실제 클래스의 테이블로 매핑을 하는 방법이다! 이 double-dispatch를 진행함으로써 interface의 속도는 일반 클래스보다는 느릴 수 있다.</p>
<p>하지만 java에서도 HotSpot JVM과 같은 JVM은 double-dispatch를 사용하지 않습니다. 다른 virtual method invocation과 마찬가지로 실제 수신기 클래스에 대해서 인터페이스 메서드 호출을 해결합니다. 이렇게 사용하면, 동일한 클래스 계층이라면 추가 단계가 필요 없습니다!</p>
<p>라고 되어 있다. 밑에 더 설명하는 내용을 보면, interface가 일반 클래스보다 느려지는 시나리오가 있지만, 추상 클래스로 이러한 시나리오를 만들 수 없기 때문에, i<strong>nterface와 abstrac class간 속도의 차이를 이야기하는건 의미가 없다고 한다.(적어도 자바에서는! 다른 언어에서는 어떻게 변할지는 모른다.)</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데코레이터 패턴]]></title>
            <link>https://velog.io/@ji-ha/%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@ji-ha/%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 08 Feb 2022 05:02:35 GMT</pubDate>
            <description><![CDATA[<p>객체에 <strong>추가적인 요건</strong>을 <strong>동적</strong>으로 첨가한다.</p>
<p>데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.</p>
<h3 id="들어가기-전에">들어가기 전에,</h3>
<p>상속은 <strong>is-a</strong></p>
<p>구성은 <strong>has-a</strong></p>
<h2 id="클래스-다이어그램">클래스 다이어그램</h2>
<p><img src="https://images.velog.io/images/ji-ha/post/d4090a1b-01fd-4c6b-aa37-9234e5da8537/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.28.19.png" alt=""></p>
<h3 id="component">Component</h3>
<ul>
<li>구성요소를 나타내주는 클래스 or 인터페이스</li>
</ul>
<h3 id="decorator">Decorator</h3>
<ul>
<li>자신기 장식할 <strong>구성요소가 같은</strong> 인터페이스 또는 추상 클래스를 구현.</li>
</ul>
<h3 id="concretecomponent">ConcreteComponent</h3>
<ul>
<li>새로운 행동을 동적으로 추가합니다.</li>
</ul>
<h3 id="concretedecorators">ConcreteDecorators</h3>
<ul>
<li>구상클래스 입니다!(== <strong>has-a</strong>)</li>
<li>Component 객체가 들어있습니다.(== <strong>구성요소에 대한 레퍼런스</strong>가 들어있는 인스턴스 변수가 있는 것)</li>
<li>이 객체를 통하여 <strong>추가적인 장식</strong>을 할 수 있습니다.</li>
</ul>
<h2 id="상속을-대신하기-위해-사용하는-패턴">상속을 대신하기 위해 사용하는 패턴?</h2>
<p>상속을 대체할 수는 없습니다.</p>
<p>다만 상속을 통해 <strong>하고자하는 일이 다릅니다!</strong></p>
<p>데코레이터에서의 상속은</p>
<p>오버라이딩을 통하여 <strong>메소드의 행동</strong>을 변경하고 <strong>올바른(필요한) 형식</strong>을  맞추기 위해서 하는 것입니다!</p>
<p>객체의 <strong>구성</strong>(인스턴스 변수로 다른 객체를 저장하는 방식)을 통하여 유연성을 보장합니다!</p>
<h2 id="데코레이터-패턴이-적용된-코드">데코레이터 패턴이 적용된 코드</h2>
<h3 id="component-class">Component Class</h3>
<pre><code class="language-kotlin">package decorator

abstract class Beverage(
    var description: String = &quot;제목 없음&quot;
) {
    open fun getDes() = description

    abstract fun cost(): Double
}</code></pre>
<p>추상클래스 or 인터페이스 모두 가능.</p>
<h3 id="concretecomponent-1">ConcreteComponent</h3>
<pre><code class="language-kotlin">package decorator

class Espresso: Beverage() {

    init {
        description = &quot;에스프레소&quot;
    }

    override fun cost(): Double {
        return 1.99
    }
}</code></pre>
<p>모든 첨가물 데코레이터에서 getDes()를 통하여 표현할 수 있습니다!</p>
<h3 id="decorator-1">Decorator</h3>
<pre><code class="language-kotlin">package decorator

abstract class CondimentDecorator: Beverage() {
    abstract override fun getDes(): String
}</code></pre>
<h3 id="concretedecorator">ConcreteDecorator</h3>
<pre><code class="language-kotlin">package decorator

class Mocha(
    private var beverage: Beverage
    ): CondimentDecorator() {

    override fun cost(): Double {
        return beverage.cost() + .20
    }

    override fun getDes(): String {
        return beverage.getDes() + &quot;, 모카&quot; // 재귀는 아님
    }
}</code></pre>
<pre><code class="language-kotlin">package decorator

class Whip(
    private var beverage: Beverage
    ) : CondimentDecorator() {

    override fun cost(): Double {
        return beverage.cost() + .59
    }

    override fun getDes(): String {
        return beverage.getDes() + &quot;, 휘핑 크림&quot;
    }
}</code></pre>
<h3 id="실행결과">실행결과</h3>
<pre><code class="language-kotlin">package decorator

fun main() {
    val beverage = Espresso()
    println(beverage.description)

    var beverage2: Beverage = HouseBlend()
    beverage2 = Mocha(beverage2)
    beverage2 = Mocha(beverage2)
    beverage2 = Whip(beverage2)
    println(beverage2.getDes())
}

// 결과
// 에스프레소
// 하우스 블렌드 커피, 모카, 모카, 휘핑 크림
// 하우스 블렌드 커피, 모카, 휘핑 크림, 모카</code></pre>
<h2 id="패턴이-가진-단점">패턴이 가진 단점</h2>
<p>구상 구성요소(모카, 휘핑...)의 형식을 알아내서 <strong>결과를 바탕으로 어떤 작업을 처리하는 코드</strong>에는 적합하지 않습니다!</p>
<p><strong>특정 형식에 의존하는 코드</strong>에 데코레이터를 그냥 적용해버리면 코드가 엉망이 됩니다!</p>
<p>그러다보니, <strong>구성요소를 초기화</strong>하는 데 필요한 코드가 훨씬 복잡해집니다.</p>
<h4 id="-특정-형식에-의존하는-코드">! 특정 형식에 의존하는 코드</h4>
<p>→ 특정 데코레이터 내부에서 인스턴스 변수(Component component)가 참조하고 있는 구상 컴포넌트의 구현체를 알 수 없습니다.(Whip 클래스의 구성 클래스가 어떤 데코레이터로 감싸져 있는지 모른다는 뜻) 따라서, 데코레이터 수행 과정 중 구상 컴포넌트에 특정 작업을 할 수 없습니다!</p>
<h2 id="단점을-극복하기-위한-패턴-사용">단점을 극복하기 위한 패턴 사용</h2>
<p>구성요소를 초기화하는데 필요한 코드가 훨씬 복잡해집니다.</p>
<p>→ 이러한 문제는 <strong>팩토리</strong> 패턴이나 <strong>빌더</strong> 패턴을 사용함으로써 해결이 가능합니다!</p>
<h3 id="팩토리-메서드-패턴을-통한-코드-단순화">팩토리 메서드 패턴을 통한 코드 단순화</h3>
<p><img src="https://images.velog.io/images/ji-ha/post/082f13e3-0a4f-4434-8365-82e50d3f83c4/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-03%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.54.44.png" alt=""></p>
<p>데코레이터 패턴의 Component가 Product로 들어가면서, 팩토리 메서드 패턴을 사용하였습니다!</p>
<p>코드로 작성해보면,</p>
<h3 id="creator">Creator</h3>
<pre><code class="language-kotlin">package decorator

abstract class BeverageStore {
    abstract fun createBeverage(type: String): Beverage
}</code></pre>
<h3 id="concretecreator">ConcreteCreator</h3>
<pre><code class="language-kotlin">package decorator

class StarbuzzStore: BeverageStore() {
    override fun createBeverage(type: String): Beverage {
        var targetBeverage: Beverage = Espresso()
        if(type == &quot;HouseBlend&quot;) targetBeverage = HouseBlend()
        return targetBeverage
    }
}</code></pre>
<h3 id="결과">결과</h3>
<pre><code class="language-kotlin">package decorator

fun main() {
    val starbuzzStore = StarbuzzStore()
    val beverage = starbuzzStore.createBeverage(&quot;Espresso&quot;)
    println(beverage.description)

    var beverage2 = starbuzzStore.createBeverage(&quot;HouseBlend&quot;)
    beverage2 = Mocha(beverage2)
    beverage2 = Mocha(beverage2)
    beverage2 = Whip(beverage2)
    println(beverage2.getDes())
}

// 결과
// 에스프레소
// 하우스 블렌드 커피, 모카, 모카, 휘핑 크림</code></pre>
<p>이런식으로 사용이 가능할 것 같습니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[팩토리 패턴]]></title>
            <link>https://velog.io/@ji-ha/%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@ji-ha/%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 08 Feb 2022 04:45:42 GMT</pubDate>
            <description><![CDATA[<p>우리는 <strong>객체를 생성함</strong>으로써 코드를 만들어 나갑니다.</p>
<p>하지만, 문제가 있습니다.</p>
<p>→ new를 통해 만들어진 객체를 변경하거나 확장해야할 때, 우리는 코드를 다시 확인하고 추가/제거 해야합니다.</p>
<p>→ 이런 식으로 코드를 만들면 <strong>관리 및 갱신</strong>이 어려워지고 <strong>오류</strong>가 생길 가능성이 높아집니다..!</p>
<h2 id="어떻게-해야할까요">어떻게 해야할까요?</h2>
<p><strong>바뀔 수 있는 부분</strong>을 찾아내서 <strong>바뀌지 않는 부분</strong>하고 분리시킵시다!</p>
<h3 id="아무런-패턴이-적용되지-않은-지금까지의-코드">아무런 패턴이 적용되지 않은, 지금까지의 코드</h3>
<pre><code class="language-kotlin">fun orderPizza(type: String): Pizza {
    lateinit var pizza : Pizza

    // 이 부분은 맨날 바뀌어야 하는 부분. 새로운 메뉴가 나오거나 메뉴가 삭제된다면 해당 코드는 매일 변합니다.
    if(type == &quot;cheese&quot;) {
        pizza = CheesePizza()
    } else if(type == &quot;greek&quot;) {
        pizza = GreekPizza()
    } else if(type == &quot;pepperoni&quot;) {
        pizza = PepperoniPizza()
    }

    /* 추가될 수도 있습니다!
    else if(type == &quot;clam&quot;) {
        pizza = new ClamPizza()
    }
    */

    // 여기는 무슨 짓을 하더라도 피자가 준비되고, 배달되기 위해서는 필요한 부분.
    pizza.prepare()
    pizza.bake()
    pizza.cut()
    pizza.box()

    return pizza
}</code></pre>
<h3 id="간단한-팩토리가-적용된-코드">간단한 팩토리가 적용된 코드</h3>
<pre><code class="language-kotlin">class PizzaStore(val factory: SimplePizzaFactory) {
    fun orderPizza(type: String): Pizza {
        pizza = factory.createPizza(type)
        pizza.prepare()
        pizza.bake()
        pizza.cut()
        pizza.box()
    }
}</code></pre>
<pre><code class="language-kotlin">class SimplePizzaFactory {
    fun createPizza(type: String): Pizza {
        lateinit var pizza: Pizza

        if(type == &quot;cheese&quot;) {
            pizza = CheesePizza()
        }
        } else if(type == &quot;greek&quot;) {
            pizza = GreekPizza()
        }
        } else if(type == &quot;pepperoni&quot;) {
            pizza = PepperoniPizza()
        }
        return pizza
    }
}</code></pre>
<h3 id="장점">장점</h3>
<ul>
<li>구현을 변경해야 하는 경우에 여기저기 다 들어가서 고칠 필요가 없습니다! → 위에 보이는 Factory 클래스만 고치면 됩니다.</li>
</ul>
<h3 id="뭔가-부족한데">뭔가 부족한데...?</h3>
<ul>
<li>Factory와 Store가 따로 있다보니, 새로운 Store가 만들어질 때마다 변하면 안되는 부분들이 개발자에 따라 바뀔 수도 있는 위험이 있습니다.</li>
<li>Store와 Factory를 <strong>유연성</strong>이 있으면서도 <strong>하나로 묶을 수 있는</strong> 방법은 없을까요?</li>
</ul>
<h3 id="알아가기">알아가기</h3>
<p>모든 팩토리 패턴에서는 <strong>객체 생성을 캡슐화</strong>합니다!</p>
<hr>
<h2 id="팩토리-메서드-패턴">팩토리 메서드 패턴</h2>
<p><strong>서브클래스(의 메서드)</strong>에서 <strong>어떤 클래스를 만들지 결정</strong>하게 함으로써(== 맡기는 것) 객체 생성을 캡슐화합니다!</p>
<p>→ 객체를 생성하기 위한 <strong>인터페이스를 정의</strong>하는 것!</p>
<p>→ 어떠한 클래스의 인스턴스를 만들지는 <strong>서브클래스에서 결정</strong>하게 만듭니다.</p>
<p>이 패턴에서 등장하는 클래스의 종류는 두가지로 나눌 수 있습니다.</p>
<h3 id="생산자creator-클래스">생산자(Creator) 클래스</h3>
<p><img src="https://images.velog.io/images/ji-ha/post/1ffa596d-d1cf-4d61-9116-1cfc0aaeeedb/1.png" alt=""></p>
<p>PizzaStore: <strong>추상 생산자</strong> 클래스</p>
<ul>
<li>상속받은 서브 클래스들에서 객체를 생산하기 위해 구현할 <strong>팩토리 메서드를 정의</strong>합니다.</li>
<li>생산자 자체에서 어떤 제품 클래스가 만들어질지 미리 알 수 없습니다!</li>
</ul>
<p>ChicagoPizzaStore &amp; NYPizzaStore: 구상 생산자(<strong>Concrete creator)</strong> 클래스</p>
<ul>
<li>createPizza() 메서드가 팩토리 메서드입니다! 이 <strong>메서드에서 객체를 생산</strong>합니다.</li>
</ul>
<hr>
<h3 id="제품product-클래스">제품(Product) 클래스</h3>
<p><img src="https://images.velog.io/images/ji-ha/post/3510ea06-3675-41eb-b2f7-557f46b26daf/2.png" alt=""></p>
<p>Pizza: 팩토리에서 생산하는 모든 <strong>제품(product)</strong></p>
<p>~~pizza: <strong>구상</strong> 클래스</p>
<h3 id="팩토리-메서드-패턴의-설계도">팩토리 메서드 패턴의 설계도</h3>
<p><img src="https://images.velog.io/images/ji-ha/post/f07cf39e-8fb5-44f0-9c92-1b3aef825d8f/3.png" alt=""></p>
<blockquote>
<p>화살표의 모양은 알고 계신 것과 다를 겁니다...! 양해부탁.</p>
</blockquote>
<p><strong>구상 클래스 인스턴스를 만드는 일은 Concrete</strong> 친구들이 책임집니다.</p>
<p>실제로 제품을 만드는 클래스는 <strong>ConcreteCreator</strong>밖에 없습니다!</p>
<hr>
<h2 id="추상-팩토리-패턴">추상 팩토리 패턴</h2>
<p><strong>제품군</strong>을 <strong>만들 때</strong> 사용하는 패턴(== product class를 만들 때 사용하는 팩토리 패턴!)</p>
<p>인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 <strong>구상 클래스를 지정하지 않고도 생성</strong>이 가능하다!!</p>
<h3 id="설계도">설계도</h3>
<p><img src="https://images.velog.io/images/ji-ha/post/848c20a6-b072-479c-8346-9c2da3028ff5/4.svg" alt=""></p>
<p>설계도에서 보면, product 구상클래스들이 <strong>factory interface를 받아서 객체를 구성</strong>하는 것을 알 수 있다!</p>
<p>자, 코드로 살펴봅시다.</p>
<h4 id="abstract-product-class">abstract product class</h4>
<pre><code class="language-kotlin">package factory

abstract class Pizza {
    abstract var name: String
    abstract var dough: String
    abstract var sauce: String
    abstract var toppings: ArrayList&lt;String&gt;

    abstract fun prepare() // 상속받을 구상클래스에서 객체를 구성하기 위해 필요한 메서드

    open fun bake() {
        println(&quot;bake 25분 걸려요.&quot;)
    }

    open fun cut() {
        println(&quot;pizza를 잘라서 드릴게요~&quot;)
    }

    open fun box() {
        println(&quot;박스 포장을 합니다.&quot;)
    }
}</code></pre>
<h4 id="product-class">product class</h4>
<pre><code class="language-kotlin">package factory

class NYCheesePizza(
    private val pizzaIngredientFactory: PizzaIngredientFactory // factory 클래스를 주입받는다.
    ): Pizza() {

    override var name: String = &quot;1KG 치즈 피자&quot;
    override lateinit var dough: String
    override lateinit var sauce: String
    override lateinit var toppings: ArrayList&lt;String&gt;

    override fun prepare() { // 주입받은 factory 클래스를 통하여 객체를 구성한다.
        println(&quot;맛있는 &quot; + name + &quot; 준비 중&quot;)
        dough = pizzaIngredientFactory.createDough()
        sauce = pizzaIngredientFactory.createSauce()
        toppings = pizzaIngredientFactory.createVeggies()
    }

    override fun cut() {
        println(&quot;치즈 피자 맛있겠다.&quot;)
    }
}</code></pre>
<ul>
<li>factory를 주입받을 때, interface 클래스를 작성해놓으면 우리가 필요한 구상클래스가 무엇인지 모르고 사용할 수 있다!</li>
</ul>
<h4 id="factory-interface">factory interface</h4>
<pre><code class="language-kotlin">package factory

interface PizzaIngredientFactory {

    fun createDough(): String
    fun createSauce(): String
    fun createCheese(): String
    fun createVeggies(): ArrayList&lt;String&gt;
    fun createPepperoni(): String
    fun createClam(): String
}</code></pre>
<h4 id="factory-class">factory class</h4>
<pre><code class="language-kotlin">package factory

class NYPizzaIngredientFactory: PizzaIngredientFactory {
    override fun createDough(): String {
        return &quot;ThinCrustDough&quot;
    }

    override fun createSauce(): String {
        return &quot;MarinaraSauce&quot;
    }

    override fun createCheese(): String {
        return &quot;ReggianoCheese&quot;
    }

    override fun createVeggies(): ArrayList&lt;String&gt; {
        return mutableListOf(&quot;Garlic&quot;, &quot;Onion&quot;) as ArrayList&lt;String&gt;
    }

    override fun createPepperoni(): String {
        return &quot;SlicedPepperoni&quot;
    }

    override fun createClam(): String {
        return &quot;FreshClam&quot;
    }
}</code></pre>
<h3 id="트레이드오프">트레이드오프</h3>
<p>Q) 신메뉴로 피자에 민초를 엄청 넣고 싶은데... 그러면 어떡하죠?</p>
<p>A) 어쩔 수 없어요. interface가 수정되어야합니다..!</p>
<p>Q) 엥 그러면 모든 서브클래스가 수정되어야하는 거 아닌가요?</p>
<p>A) 제품군을 생성하는 추상 팩토리 패턴은 인터페이스도 매우 큰편(==인터페이스 내부에 있는 것들이 다양하다!)이기 때문에 감수해야합니다.</p>
<h3 id="추상-팩토리-패턴은-팩토리-메서드-패턴을-사용한다">추상 팩토리 패턴은 팩토리 메서드 패턴을 사용한다?</h3>
<p><img src="https://images.velog.io/images/ji-ha/post/4744fed1-9563-4821-8acd-d3b49e7ba216/5.png" alt=""></p>
<p>???) 이거 완전 팩토리 메서드 패턴의 생산자 클래스잖아!</p>
<p> 종종 사용되는 경우가 있습니다. 추상 팩토리 패턴 안에도 제품을 생산하기 위한 메서드가 있기 때문에, 생산자 클래스가 사용되는 것은 자연스러운 일입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Scope Function]]></title>
            <link>https://velog.io/@ji-ha/Scope-Function</link>
            <guid>https://velog.io/@ji-ha/Scope-Function</guid>
            <pubDate>Wed, 26 Jan 2022 05:13:55 GMT</pubDate>
            <description><![CDATA[<p>Scope Function에는 5가지 함수들이 존재합니다!</p>
<ul>
<li>let, run, with</li>
<li>apply, also</li>
</ul>
<p>Scope Function에 해당하는 함수들을 람다식을 이용하여 호출하면 <strong>일시적인 Scope</strong>(범위)가 생기고</p>
<p>이 범위 안에서는 전달된 객체에 대해 “<strong>it</strong>” 또는 “<strong>this</strong>”라는 <strong>Context Object</strong>를 통하여 접근할 수 있습니다.</p>
<h2 id="scope-function-간-차이점">scope function 간 차이점</h2>
<p>이 함수들에는 두가지 차이점이 있습니다.</p>
<ul>
<li>Context Object를 참조하는 방법(it, this)</li>
<li>Return value</li>
</ul>
<hr>
<h2 id="context-object">Context Object?</h2>
<p>Scope Function 람다식 안에서 Context Object는 실제 객체명을 대신하여, this나 it을 통해 객체에 접근합니다.</p>
<pre><code class="language-kotlin">class Person(var name: String, var age: Int)

fun main() {
    val person = Person(&quot;노지환&quot;, 25)

    person.run {
        println(&quot;이름: ${this.name}&quot;) // this를 사용하여 진행할 수 있습니다.
        println(&quot;나이: $age&quot;) // this를 생략해도 됩니다!
        age = 26
    }
    println(person.age)

    person.let {
        println(&quot;이름: ${it.name}&quot;) //it은 생략할 수 없습니다!
        println(&quot;나이: ${it.age}&quot;)
        it.age = 25
    }
}</code></pre>
<h3 id="this">this</h3>
<p><strong>run, with, apply</strong>는 Context Object를 “<strong>this</strong>”로 참조합니다!</p>
<pre><code class="language-kotlin">class Person(var name: String, var age: Int)

fun main() {
    val person = Person(&quot;노지환&quot;, 25)

    person.run {
        println(&quot;이름: ${this.name}&quot;)
        println(&quot;나이: $age&quot;)
    }

    with(person) {
        println(&quot;이름: ${this.name}&quot;)
        println(&quot;나이: $age&quot;)
    }

    person.apply {
        println(&quot;이름: ${this.name}&quot;)
        println(&quot;나이: $age&quot;)
    }
}</code></pre>
<h3 id="it">it</h3>
<p>let, also는 Context Object를 “it”으로 참조합니다.</p>
<pre><code class="language-kotlin">        person.let { want -&gt; // 이런식으로 전달 인자명을 설정할 수도 있습니다!
        println(&quot;이름: ${want.name}&quot;)
        want.name = &quot;지환노&quot;
    }

    person.also {
        println(&quot;이름: ${it.name}&quot;)
    }</code></pre>
<hr>
<h2 id="return-value">Return Value</h2>
<ul>
<li>apply, also는 <strong>Context Object</strong>를 반환하고,</li>
<li>let, run, with는 <strong>람다식 결과</strong>를 반환합니다!</li>
</ul>
<h3 id="context-object-1">Context Object</h3>
<p>apply, also의 반환값은 <strong>Context Object 객체 자체</strong>입니다.</p>
<p>따라서, <strong>체인</strong> <strong>형식으로</strong> 계속 호출이 가능합니다!</p>
<pre><code class="language-kotlin">        val numberList: MutableList&lt;Double&gt; = mutableListOf()
    numberList.also { println(&quot;Populating the list&quot;) } // 이런식으로
        .apply { // 연속적으로 사용하더라도, 반환값이 객체이기 때문에 사용이 가능하다!
            add(2.71)
            add(2.3)
            add(4.5)
            for (i in this) println(i)
        }
        .also { println(&quot;sorting&quot;) }
        .sort() // 하지만 sort후에는
        .run { // 반환값이 true, false이기 때문에 run을 사용할 때 this를 사용할 수 없다
            for(i in numberList) println(i)
        }
                //.run 이 친구도 사용이 불가능하다! run의 return 값은 람다식 결과를 반환하기 때문에 객체를 가져올 수 없다.</code></pre>
<p>게다가 Context Object를 <strong>반환하는 함수의 return</strong> 문에도 사용이 가능합니다!</p>
<pre><code class="language-kotlin">fun getNumber(): Int {
    return Random.nextInt(100).also {
            println(&quot;return random number&quot;)
    }
}</code></pre>
<h3 id="lambda-result">Lambda Result</h3>
<ul>
<li>let, run, with는 람다식 결과를 반환합니다.</li>
<li>결과를 변수에 할당하거나, 결과에 대해서 추가적인 작업을 수행할 때 사용합니다!</li>
</ul>
<pre><code class="language-kotlin">        person.let {
        println(&quot;-------------------------------&quot;)
        println(it.name)
        it.name = &quot;지환노&quot;
        println(it.name)
        it // -&gt; 이런식으로 scope function이 종료될 때 객체를 넘길 수도 있다!!
    }
    println(person.name) // scope function 안에서 값을 변경하면 적용된다!</code></pre>
<hr>
<h2 id="적절한-때-적절한-사용법">적절한 때, 적절한 사용법</h2>
<p>여러가지 Scope Function들의 권장 사용법을 알아봅시다!</p>
<h3 id="let">let</h3>
<ul>
<li>context Object: it</li>
<li>Return Value: Lambda result</li>
<li>객체 결과값에 <strong>하나 이상의 함수를 호출</strong>하는 경우 사용합니다.</li>
</ul>
<pre><code class="language-kotlin">val str: String? = &quot;Hello&quot;   
val length = str?.let { 
    println(&quot;let() called on $it&quot;)        
    processNonNullString(it)      // OK: &#39;it&#39; is not null inside &#39;?.let { }&#39;
    it.length
}</code></pre>
<h3 id="with">with</h3>
<ul>
<li>Context Object: this</li>
<li>Return Value: Lambda Result</li>
<li>이미 생성된 Context Object <strong>객체를 인자로 받아서 사용</strong>하는 것이 효율적일 때 사용합니다.</li>
<li>with는 “이 객체를 사용하여 다음을 수행합니다”라고 읽을 수 있습니다!</li>
</ul>
<pre><code class="language-kotlin">val numbers = mutableListOf(&quot;one&quot;, &quot;two&quot;, &quot;three&quot;)
with(numbers) {
    println(&quot;&#39;with&#39; is called with argument $this&quot;)
    println(&quot;It contains $size elements&quot;)
}</code></pre>
<h3 id="run">run</h3>
<ul>
<li>Context Object: this</li>
<li>Return Value: Lambda Result</li>
<li>with과 비슷하지만, <strong>Context Object의 확장 기능으로 let</strong>을 호출합니다!</li>
<li><strong>개체 초기화와 반환 값 계산이 모두 포함되어 있을 때 유용</strong>합니다!</li>
</ul>
<pre><code class="language-kotlin">val service = MultiportService(&quot;https://example.kotlinlang.org&quot;, 80)

val result = service.run { // 요기에 null check도 가능하기 때문에 유용하다! service?.run
    port = 8080
    query(prepareRequest() + &quot; to port $port&quot;)
}</code></pre>
<h3 id="apply">apply</h3>
<ul>
<li>Context Object: this</li>
<li>Return Value: Context Object</li>
<li>주로 receiver object의 개체 구성을 위해 사용합니다!</li>
</ul>
<pre><code class="language-kotlin">val adam = Person(&quot;Adam&quot;).apply {
    age = 32
    city = &quot;London&quot;        
}
println(adam)</code></pre>
<h3 id="also">also</h3>
<ul>
<li>Context Object: it</li>
<li>Return Value: Context Object</li>
<li>속성이나 기능이 아닌 object의 참조가 필요한 작업이나 외부 범위에서 이 참조를 숨기고 싶지 않은경우 사용합니다!</li>
</ul>
<pre><code class="language-kotlin">val numbers = mutableListOf(&quot;one&quot;, &quot;two&quot;, &quot;three&quot;)
numbers
    .also { println(&quot;The list elements before adding new one: $it&quot;) } // 이렇게 log 찍기 같이 하면 좋다!
    .add(&quot;four&quot;)</code></pre>
<hr>
<h2 id="총정리">총정리</h2>
<table>
<thead>
<tr>
<th>Fuction</th>
<th>Context Object</th>
<th>Return Value</th>
</tr>
</thead>
<tbody><tr>
<td>let</td>
<td>it</td>
<td>Lambda Result</td>
</tr>
<tr>
<td>run</td>
<td>this</td>
<td>Lambda Result</td>
</tr>
<tr>
<td>with</td>
<td>this</td>
<td>Lambda Result</td>
</tr>
<tr>
<td>apply</td>
<td>this</td>
<td>Context Object</td>
</tr>
<tr>
<td>also</td>
<td>it</td>
<td>Context Object</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[쓰레드(thread)]]></title>
            <link>https://velog.io/@ji-ha/%EC%93%B0%EB%A0%88%EB%93%9Cthread</link>
            <guid>https://velog.io/@ji-ha/%EC%93%B0%EB%A0%88%EB%93%9Cthread</guid>
            <pubDate>Tue, 25 Jan 2022 12:40:06 GMT</pubDate>
            <description><![CDATA[<p>프로세스 안에서 실행되는 여러 흐름 단위</p>
<h2 id="motivation">motivation</h2>
<p>thread는 어플리케이션 내에서 실행됩니다.</p>
<p>여러 개의 task로 이루어진 애플리케이션은 separate threads로 분리됩니다.</p>
<p>== 하나의 <strong>task</strong>마다 하나의 <strong>tread</strong>를 만듭니다.</p>
<p>???: thread가 아니라 process를 여러개 만들어서 진행해도 되지 않을까요??</p>
<p>→ process를 만드는 것은 비용이 매우 많이 든다. <strong>OS가 할일도 많고, overhead도 많아서 하지 않습니다!!</strong></p>
<h2 id="한-프로세스에서-쓰레드가-공유하는-것들">한 프로세스에서 쓰레드가 공유하는 것들</h2>
<p><img src="https://images.velog.io/images/ji-ha/post/edb0d8e7-5710-4402-9a5a-66cd3ba5aafa/4.png" alt=""></p>
<p><strong>code, data, file</strong>은 쓰레드끼리 공유합니다.</p>
<p><strong>registers와 stack</strong>은 쓰레드마다 가집니다.</p>
<h3 id="쓰레드와-프로세스의-결정적인-차이">쓰레드와 프로세스의 결정적인 차이?</h3>
<p>code, data, files는 공유하고, registers와 stack은 각자 가지고 있다는 것을 알고 있어야합니다.
→ <strong>프로세스가 달라지면 공유되는 부분도 달라지지만, 쓰레드가 달라진다고 공유되는 부분이 바뀌진 않습니다.</strong></p>
<h2 id="장점">장점</h2>
<p>반응이 빨라집니다.</p>
<p>리소스 쉐어가 더 편리하고 경제적입니다. == code, data, file을 공유하기 때문입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로세스(process)]]></title>
            <link>https://velog.io/@ji-ha/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4process</link>
            <guid>https://velog.io/@ji-ha/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4process</guid>
            <pubDate>Tue, 25 Jan 2022 12:19:27 GMT</pubDate>
            <description><![CDATA[<h2 id="process란">process란?</h2>
<ul>
<li>프로그램을 메모리 상에서 실행중인 작업</li>
<li>디스크에 있을 때는 program이라고 부르지만, 메모리에 올라가면 <strong>process</strong>가 됩니다.</li>
</ul>
<h2 id="process의-구성feat-메모리">process의 구성(.feat 메모리)</h2>
<p><img src="https://images.velog.io/images/ji-ha/post/8c03b13f-9bac-41a6-ace2-76c3b8f4e31f/1.png" alt=""></p>
<p>address space: 프로세스의 주소 공간</p>
<p>stack: function의 데이터(지역변수들을 저장할 때는 <strong>위에서 아래로 저장</strong>이 됩니다.)</p>
<p>data: 전역변수와 상수가 저장되는 구역입니다.</p>
<p>text: program의 코드 일부가 메모리에 올라가는데 이를 text라고 합니다.</p>
<h2 id="context-switch">Context switch</h2>
<p>dispatcher가 지금 일하고 있는 process를 바꿔야할 때,</p>
<ol>
<li>이전 프로세스의 대한 정보를 <strong>PCB</strong>(Process Control Block)에 저장합니다.</li>
<li>다음으로 돌릴 프로세스를 정한 후에 정한 프로세스를 진행합니다.</li>
<li>이 프로세스가 끝나면, 전 프로세스로 돌아가서 저장한 PCB를 가져와서 다시 진행합니다.</li>
</ol>
<p>이 변경하는 과정 자체를 <strong>context switch</strong>라고 합니다.</p>
<p>→ 프로세스의 <strong>상태 정보를 저장하고 복원</strong>하는 일련의 과정!</p>
<h2 id="context-switch가-일어날-때-pcb에-저장하는-것들">Context Switch가 일어날 때, <strong>PCB</strong>에 저장하는 것들?</h2>
<ul>
<li>PC(Program Counter)</li>
<li>Scheduling Information</li>
<li>Base and limit register value(기준 및 제한 레지스터 값)</li>
<li>Currently used register(현재 사용중인 레지스터)</li>
<li>Changed State</li>
<li>I/O State Information</li>
<li>Accounting Information</li>
</ul>
<h3 id="팁">팁</h3>
<p>context switch는 멀티테스킹에서 중요한 역할을 합니다.</p>
<p>context switch하는 시간은 매우 아까운 시간입니다. == 퍼포먼스를 높이려면 이러한 오버헤드가 짧으면 짧을수록 좋습니다.</p>
<h2 id="context-switch를-줄이기-위해서는-어떻게-해야할까">context switch를 줄이기 위해서는 어떻게 해야할까?</h2>
<ol>
<li><strong>high</strong> memory speed</li>
<li><strong>smal</strong> number of registers</li>
<li><strong>more</strong> special instruction for context switch<ul>
<li>special instruction? : 새로운 명령어를 만들었다는 것</li>
<li>cpu 명령(==software적)으로 하는 게 더 빠르고 효율적입니다. == 많을수록 좋습니다.</li>
</ul>
</li>
<li><strong>more</strong> register<ul>
<li>돈이 많다면 register를 많이 사용하자!</li>
</ul>
</li>
</ol>
<h2 id="five-state-process-model">Five-state Process Model</h2>
<p><img src="https://images.velog.io/images/ji-ha/post/de36f3d8-9ff3-471d-90a0-7b7d394c1a18/2.png" alt="">
New: 프로세스가 새롭게 만들어지는 것.</p>
<p>Running: 모든 process는 이 상태에 존재하기 위한 여정입니다. <strong>process가 queue에서 가져</strong>와지는 과정.</p>
<p>Ready: running으로 가려면 이 상태를 거쳐야합니다. queue에 들어오는 것이 ready 상태, time-out은 running으로 간 프로세스가 시간이 다 되었는데도 끝내지못한다면 queue로 다시 들어오는 것을 말합니다.</p>
<p>Waiting:  timeout은 <strong>비자발적</strong>으로 일어나는 것. 다른 일이 생겼을 때는 waiting으로 온다. 일이 다 끝나면 ready로 갑니다!</p>
<p>terminated: 프로세스가 종료되는 과정. <strong>할당한 자원을 모두 회수</strong>합니다.</p>
<h2 id="process-scheduling">process scheduling</h2>
<p>→ <strong>CPU 사용량을 최대</strong>로 올리기 위하여 스케줄링을 한다.</p>
<p>scheduler는 ready에 존재하는 프로세스를 running으로 보내는 역할을 합니다.</p>
<p>ready에 존재하는 queue는 Priority Queue입니다.</p>
<p><img src="https://images.velog.io/images/ji-ha/post/ebc06b97-f7ea-4015-ac75-a4e89400adc0/3.png" alt="">
long term: 어떤 친구를 <strong>메모리에 올려</strong>줄 것인지 정하는 스케줄러</p>
<p>short term: 메모리에 올려져 있는 친구들 중 <strong>CPU에 올려줄 친구</strong>를 정하는 스케줄러</p>
<h3 id="헷갈리는-개념">헷갈리는 개념</h3>
<p>멀티 프로그래밍(Multi Programming)</p>
<ul>
<li>여러개의 프로그램이 <strong>시간을 공유하면서 돌아가는 것</strong></li>
<li>각각의 <strong>프로그램이 순서</strong>대로 돌아갑니다.</li>
</ul>
<p>멀티 태스킹(Multi Tasking)</p>
<ul>
<li>task == process. 멀티 프로그래밍보다 context switching이 더 자주 발생합니다.</li>
<li>자주 스위칭한다면? : 사람이 보기에는 <strong>동시에 발생하는 것처럼 보입니다.</strong></li>
<li><strong>CPU Scheduling</strong>이 어떻게 <strong>프로세스를 스위칭할지 관리</strong>합니다!</li>
</ul>
<p>멀티 쓰레딩(Multi Threading)</p>
<ul>
<li><strong>하나의</strong> 프로세서가 <strong>여러개의</strong> 일을 하는 것을 뜻합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[N+1]]></title>
            <link>https://velog.io/@ji-ha/N1</link>
            <guid>https://velog.io/@ji-ha/N1</guid>
            <pubDate>Fri, 21 Jan 2022 06:32:36 GMT</pubDate>
            <description><![CDATA[<p>조회할 때, 1개의 쿼리만 날릴 것으로 생각했으나, 나올 필요가 없는 조회 쿼리가 N개 더 발생하는 문제</p>
<h2 id="왜-일어날까">왜 일어날까?</h2>
<ul>
<li>JPA같은 자동화 쿼리문이 생겨나면서 발생하는 문제입니다.<ul>
<li>JPA: 객체에 대해서 조회할 때 다양한 연관관계 매핑에 의해서 관계가 맺어진 <strong>다른 객체가 함께 조회</strong>되는 경우에 N+1 발생.</li>
</ul>
</li>
</ul>
<h2 id="test-entity">Test Entity</h2>
<pre><code class="language-kotlin">@Entity
class Account(
    var name: String,

//    @BatchSize(size = 2)
//    @OneToMany(mappedBy = &quot;account&quot;, fetch = FetchType.LAZY)
        @OneToMany(mappedBy = &quot;account&quot;, fetch = FetchType.EAGER)
    var folderList: List&lt;Folder&gt; = mutableListOf(),

//    @BatchSize(size = 2)
//    @OneToMany(mappedBy = &quot;account&quot;, fetch = FetchType.LAZY)
//    var articleList: List&lt;Article&gt; = mutableListOf(),
// 2개 이상의 Collection Join을 테스트할 때 사용할 객체관계!
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0L
)</code></pre>
<pre><code class="language-kotlin">@Entity
class Folder(name: String, account: Account) {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long = 0L
    var name: String = name

    @ManyToOne(fetch = FetchType.EAGER)
    var account: Account = account
}</code></pre>
<pre><code class="language-kotlin">@Entity
class Article(name: String, account: Account) {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long = 0L
    var name: String = name

    @ManyToOne(fetch = FetchType.EAGER)
    var account: Account = account
}</code></pre>
<p>Account가 Folder와 Article을 @OneToMany로 가지고 있는 것을 확인할 수 있습니다!</p>
<h2 id="n1이-일어날-부분들-총정리">N+1이 일어날 부분들 총정리</h2>
<h3 id="즉시로딩eager">즉시로딩(EAGER)</h3>
<p> 조회할 때부터 연관관계가 매핑된 객체들을 싹다 긁어모아옵니다.</p>
<pre><code class="language-kotlin">    @Test
    fun accountFindTestWithEager() {
        println(&quot;------------------------------start&quot;)
        val findAll = accountRepository.findAll()
        val account = findAll
        println(&quot;------------------------------end&quot;)
        for(a in account) {
            val folderList = a.folderList
            for(b in folderList)
                println(b.name)
        }
    }</code></pre>
<h4 id="참고사항">참고사항</h4>
<ul>
<li>데이터베이스에 저장된 Account의 개수는 3개</li>
</ul>
<h4 id="테스트-결과">테스트 결과</h4>
<p><img src="https://images.velog.io/images/ji-ha/post/57aec50a-bb0b-480a-8d2e-659ce29e925d/1.png" alt=""></p>
<blockquote>
<p>우리가 원하는 쿼리는 단 하나</p>
</blockquote>
<p><img src="https://images.velog.io/images/ji-ha/post/8d07cccf-19d6-429e-848f-7fe8df59ed5c/2.png" alt=""></p>
<blockquote>
<p>추가적으로 날아가는, 조회 쿼리문</p>
</blockquote>
<p>우리가 JPA에게 원하는 결과는 findAll()이라는 쿼리 하나만 날아가는 것을 원하지만, 결과는 그렇지 않습니다.</p>
<p>데이터베이스에 존재하는 account의 개수(현재 테스트에서는 3 == N)만큼 추가로 쿼리가 날아갑니다...!</p>
<h3 id="지연로딩lazy">지연로딩(LAZY)</h3>
<p>즉시로딩에서 문제가 되는 <strong>조회에서의 N+1</strong>을 해결하기 위한 방법입니다.</p>
<p>→ 하지만,  <strong>첫 조회때는 1개의 쿼리</strong>만 날려서 괜찮아보이나, 연관관계 매핑된 <strong>객체를 사용</strong>할 때 따로 쿼리가 날아가서 <strong>N+1</strong> 문제는 여전히 발생합니다!</p>
<pre><code class="language-kotlin">@Test
    fun accountFindTestWithLazy() {
        println(&quot;------------------------------start&quot;)
        val accountList = accountRepository.findAll()
        println(&quot;------------------------------end&quot;)

        for(a in accountList)
            println(a.folderList.size)
    }</code></pre>
<h4 id="참고사항-1">참고사항</h4>
<pre><code class="language-kotlin">@Entity
class Account(
...
        @OneToMany(mappedBy = &quot;account&quot;, fetch = FetchType.LAZY)
            var folderList: List&lt;Folder&gt; = mutableListOf(),
...
)</code></pre>
<p>FetchType을 LAZY로 변경해야합니다!</p>
<h4 id="테스트-결과-1">테스트 결과</h4>
<p><img src="https://images.velog.io/images/ji-ha/post/b1a51010-fcdf-4bf1-a60e-887f4df46b91/3.png" alt=""></p>
<blockquote>
<p>조회 자체는 하나의 쿼리문으로 잘 간 것 같지만...?</p>
</blockquote>
<p><img src="https://images.velog.io/images/ji-ha/post/ead24189-9606-4860-9efa-150f8e5b85e3/4.png" alt=""></p>
<blockquote>
<p>조회 후 for문을 통해 객체들을 사용할 때, N+1 발생..!</p>
</blockquote>
<p>조회 자체는 우리가 바라는대로 쿼리문이 하나로 날아가지만,</p>
<p>가져온 데이터에 접근하여 연관관계가 매핑된 객체를 사용할 때마다 쿼리문이 날아가는 것을 확인할 수 있습니다!</p>
<h3 id="fetch-join">fetch join</h3>
<p>지연로딩을 통해 해결이 될 줄 알았지만, 우리가 원하는 결과는 아니었습니다!</p>
<p>그래서 나온 방법이 fetch join!</p>
<p>fetch join을 적용하는 방법에는 두가지가 존재합니다.</p>
<pre><code class="language-kotlin">interface AccountRepository: JpaRepository&lt;Account, Long&gt; {

        // Query문 하나만을 사용한 fetch join
    @Query(&quot;select distinct a from Account a left join fetch a.folderList&quot;)
    fun findAllJPQLFetch(): List&lt;Account&gt;

        // @EntityGraph를 통해 사용하는 fetch join
    @EntityGraph(attributePaths = [&quot;folderList&quot;], type = EntityGraph.EntityGraphType.FETCH)
    @Query(&quot;select distinct a from Account a left join a.folderList&quot;)
    fun findAllEntityGraph(): List&lt;Account&gt;

        ...
}</code></pre>
<h4 id="차이점">차이점?</h4>
<ul>
<li>쿼리문을 통한 fetch join을 사용한다면, 쿼리문에 하드코딩해야한다는 단점이 존재합니다!</li>
<li>쿼리문에 fetch를 사용하는대신, @EntityGraph를 통하여 하드코딩을 줄이는 방식으로 진행이 가능합니다.</li>
</ul>
<h4 id="테스트-결과-2">테스트 결과</h4>
<p><img src="https://images.velog.io/images/ji-ha/post/5239acfc-bf47-4eac-bafb-3d8910183663/5.png" alt=""></p>
<blockquote>
<p>하나의 쿼리문으로 필요한 것들을 모두 가져오는 모습..!</p>
</blockquote>
<p>그러나, 이렇게 fetch join만으로도 해결할 수 없는 부분들이 있는데요..!</p>
<ul>
<li>pagination</li>
<li>collection join</li>
</ul>
<p>두 부분에서는 여전히 문제가 발생합니다!</p>
<h2 id="fetch-join-problem">fetch join problem</h2>
<h3 id="pagination">pagination</h3>
<pre><code class="language-kotlin">@Test
    fun pagingFetchJoinTest() {
        println(&quot;------------------------------start&quot;)
        val pageRequest = PageRequest.of(0, 2)
        val findAllPage = accountRepository.findAllPage(pageRequest)
        println(&quot;------------------------------end&quot;)
        for(a in findAllPage) println(a.folderList.size)
    }</code></pre>
<h4 id="참고사항-2">참고사항</h4>
<pre><code class="language-kotlin">interface AccountRepository: JpaRepository&lt;Account, Long&gt; {
        ...
        @EntityGraph(attributePaths = [&quot;folderList&quot;], type = EntityGraph.EntityGraphType.FETCH)
            @Query(&quot;select distinct a from Account a left join a.folderList&quot;)
            fun findAllPage(pageable: Pageable): Page&lt;Account&gt;
        ...
}</code></pre>
<h4 id="테스트-결과-3">테스트 결과</h4>
<p><img src="https://images.velog.io/images/ji-ha/post/14efa867-c438-4564-9f5f-c3acc30c2759/6.png" alt=""></p>
<blockquote>
<p>잘... 된 거 같은데?</p>
</blockquote>
<h4 id="문제점">문제점</h4>
<pre><code class="language-kotlin">2022-01-21 11:41:54.315  WARN 67141 --- [           main] o.h.h.internal.ast.QueryTranslatorImpl   : HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!</code></pre>
<p>아주아주 유심히 보셨다면 봤을 수도 있고 warning이니까~ 하고 넘기기 쉽지만, 생각보다 큰 문제로 다가올 수 있습니다!</p>
<p>해석을 해보면</p>
<p>→ 데이터베이스에서 필요한 <strong>모든 데이터</strong>들을 일단 다 가져와서 <strong>인메모리에 저장</strong>했어!</p>
<p>→ limit와 offset에 맞게 인메모리에서 작업한 후에 준거야!</p>
<p>라고 합니다.</p>
<p>지금 같은 경우는 데이터가 얼마 없기 때문에 인메모리에 가져와서 하는 경우여도 괜찮지만, 데이터가 많아질수록 <strong>OOM(Out Of Memory)</strong>이 발생할 문제가 있습니다!</p>
<h4 id="언제-일어나는-걸까">언제 일어나는 걸까?</h4>
<p><strong>~ToMany인 객체</strong>를 가져올 때</p>
<p>→ 다르게 말하면, <strong>~ToOne</strong>인 객체가 포함된 Entity는 <strong>그냥 pagination해도 된다</strong>는 것!</p>
<h4 id="해결책">해결책</h4>
<p>batchSize로 날릴 쿼리문의 정도를 제한하기!</p>
<h4 id="테스트-코드">테스트 코드</h4>
<pre><code class="language-kotlin">@Test
    fun pagingBatchSizeTest() {
        println(&quot;------------------------------start&quot;)
        val page = accountRepository.findAll(PageRequest.of(0, 2))
        println(&quot;------------------------------end&quot;)
        for(a in page) println(a.folderList.size)

    }</code></pre>
<h4 id="테스트결과">테스트결과</h4>
<p><img src="https://images.velog.io/images/ji-ha/post/e86078b8-a152-4b86-9931-99078d44eea8/7.png" alt=""></p>
<blockquote>
<p>됐다!</p>
</blockquote>
<p>정상적인 pagination을 위한 쿼리문이 날아간 후에 <strong>지정한 batch size만큼의 객체를 받아올 수 있게</strong> 쿼리를 하나 날립니다!
그러면 지정해 놓은 100개의 객체를 가지고 와서 2개 이상 필요할 때 저장된 객체를 사용하면 됩니다.
물론 쿼리가 한번 날아가고 끝이 나는것은 아니지만, N+1보다는 적은 개수의 쿼리가 날아감으로써 해결할 수 있습니다.</p>
<h4 id="tip">tip</h4>
<p>batch size는 코드 기준으로 folder가 아닌 account의 갯수를 의미한다.</p>
<p>→ 연관관계를 <strong>가지고 있는 객체</strong>를 기준으로 카운트된다고 이해하면 될 거 같음!</p>
<h3 id="2개-이상의-collection-join">2개 이상의 collection join</h3>
<h4 id="언제-일어나는걸까">언제 일어나는걸까?</h4>
<h4 id="사전조건">사전조건</h4>
<pre><code class="language-kotlin">@Entity
class Account(
    var name: String,

//    @BatchSize(size = 100)
    @OneToMany(mappedBy = &quot;account&quot;, fetch = FetchType.LAZY)
    var folderList: List&lt;Folder&gt; = mutableListOf(),

//    @BatchSize(size = 100)
    @OneToMany(mappedBy = &quot;account&quot;, fetch = FetchType.LAZY)
    var articleList: List&lt;Article&gt; = mutableListOf(),

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0L
)</code></pre>
<pre><code class="language-kotlin">interface AccountRepository: JpaRepository&lt;Account, Long&gt; {
        ...
    @EntityGraph(attributePaths = [&quot;folderList&quot;, &quot;articleList&quot;], type = EntityGraph.EntityGraphType.FETCH)
    @Query(&quot;select distinct a from Account a left join a.folderList&quot;)
    fun findAllEntityGraph2(): List&lt;Account&gt;
        ...
}</code></pre>
<p>테스트를 위해서 주석처리해놨던 articleList를 다시 살려줍니다.</p>
<p>또한, @EntityGraph를 통한 fetch join을 해준다면 일어나는 문제를 확인할 수 있습니다!</p>
<pre><code class="language-kotlin">@Test
    fun collectionFetchJoinTest() {
        println(&quot;------------------------------start&quot;)
        accountRepository.findAllEntityGraph2()
        println(&quot;------------------------------end&quot;)
        // Batch size를 작성함으로써 해결하는 방법에서는 fetch join을 사용해서는 안된다.
        // fetch join이 batch size보다 먼저 적용되기 때문에 batch size는 무시되고 exception이 발생한다.
    }</code></pre>
<h4 id="결과">결과</h4>
<pre><code class="language-kotlin">Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [com.example.n1.entity.Account.folderList, com.example.n1.entity.Account.articleList]</code></pre>
<p><strong>MutipleBagFetchException</strong>이 발생하는 것을 확인할 수 있습니다!</p>
<p><strong>~ToMany인 연관관계가 두개 이상</strong>이라면 exception을 던짐으로써 막는 것을 확인할 수 있습니다.</p>
<h4 id="해결방법">해결방법</h4>
<ul>
<li><p>set 자료구조를 사용하면 exception이 던져지지는 않습니다!</p>
<p>  → 하지만, ~ToMany pagination의 고질적인 문제인 OOM을 해결할 수는 없습니다.</p>
</li>
</ul>
<p>따라서, <strong>BatchSize를 통한 해결</strong>이 필요합니다.</p>
<h4 id="사전-조건">사전 조건</h4>
<pre><code class="language-kotlin">@Entity
class Account(
        ...
    @BatchSize(size = 2) // 데이터가 얼마 없기 때문에 batch size가 어떻게 적용되는지 보기 위하여 size를 2로 하였음.
    @OneToMany(mappedBy = &quot;account&quot;, fetch = FetchType.LAZY)
    var folderList: List&lt;Folder&gt; = mutableListOf(),

    @BatchSize(size = 2)
    @OneToMany(mappedBy = &quot;account&quot;, fetch = FetchType.LAZY)
    var articleList: List&lt;Article&gt; = mutableListOf(),
        ...
)</code></pre>
<pre><code class="language-kotlin">//    @EntityGraph(attributePaths = [&quot;folderList&quot;, &quot;articleList&quot;], type = EntityGraph.EntityGraphType.FETCH)
    @Query(&quot;select distinct a from Account a left join a.folderList&quot;)
    fun findAllEntityGraph2(): List&lt;Account&gt;</code></pre>
<p>Entity에 존재하는 연관관계들에게 @BatchSize를 걸고, <strong>fetch join은 사용하지 않으면</strong> 정상적으로 동작이 가능합니다!</p>
<h4 id="왜-fetch-join은-사용하지-않는거야">왜? fetch join은 사용하지 않는거야?</h4>
<p>batch size를 사용한다면, fetch join을 걸면 안됩니다!</p>
<p>이유는 <strong>fetch join</strong>이 <strong>batch size보다 우선적으로 적용</strong>되기 때문에, 설정했던 batch size가 무시되기 때문입니다!</p>
<h4 id="결과-1">결과</h4>
<p>다시 test 코드를 실행해보면,</p>
<p><img src="https://images.velog.io/images/ji-ha/post/8526b69f-039e-42f5-84f8-d4c68d9c1b37/8.png" alt=""></p>
<blockquote>
<p>batchsize인 2 만큼 불러와서 진행하는 모습을 확인할 수 있다.</p>
</blockquote>
<p>test 데이터가 부족하여, @BatchSize를 2로 진행했지만, 원하는 결과가 나온 것을 확인할 수 있습니다!</p>
<h2 id="n1-총정리">N+1 총정리</h2>
<p>즉시로딩 → N+1 문제 발생</p>
<p>지연로딩 → <strong>조회</strong>할 때는 <strong>쿼리가 하나</strong>만 날아가지만, <strong>객체 접근</strong>시 N+1발생</p>
<p>fetch join → <strong>한 쿼리에 원하는 데이터</strong>를 가져오지만, pagination과 2개 이상의 collection join에서 예상치 못한 문제 발생</p>
<p>pagination → <strong>@BatchSize</strong> 설정을 통한 OOM 문제 해결</p>
<p>2개 이상의 collection join → <strong>@BatchSize</strong> 설정을 통한 MutipleBagFetchException 해결 &amp; OOM 문제 해결!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[트리(tree)]]></title>
            <link>https://velog.io/@ji-ha/%ED%8A%B8%EB%A6%ACtree</link>
            <guid>https://velog.io/@ji-ha/%ED%8A%B8%EB%A6%ACtree</guid>
            <pubDate>Tue, 18 Jan 2022 15:36:01 GMT</pubDate>
            <description><![CDATA[<h2 id="트리의-정의">트리의 정의</h2>
<ul>
<li>트리는 노드로 이루어진 <strong>비선형</strong> 자료구조</li>
</ul>
<h2 id="트리의-특징">트리의 특징</h2>
<ul>
<li>하나의 <strong>루트</strong> 노드를 갖는다.</li>
<li>방향 그래프이다.</li>
<li>그래프의 한 종류이다. <strong>최소 연결 트리</strong>라고도 불린다.</li>
<li><strong>트리에는 사이클이 존재할 수 없다.(사이클이 존재한다면 트리가 아니고 “그래프”이다!)</strong></li>
<li>루트에서 한 노드로 가는 경로는 유일한 경로 뿐이다.</li>
</ul>
<h2 id="트리의-순회-방식">트리의 순회 방식</h2>
<p><img src="https://images.velog.io/images/ji-ha/post/f6b266be-b359-47dd-83c6-a91d78a3daf9/%E1%84%90%E1%85%B3%E1%84%85%E1%85%B5.png" alt=""></p>
<ul>
<li><p>전위 순회(pre-order)</p>
<p>  <strong>각 루트</strong>를 우선적, 순차적으로 방문하는 방식</p>
<p>  1→2→4→8→9→5→10→11→3→6→13→7→14</p>
</li>
</ul>
<ul>
<li><p>중위 순회(in-order)</p>
<p>  <strong>왼쪽의 하위 트리</strong> 우선 방문 후 → <strong>루트</strong> → <strong>오른쪽 하위 트리</strong> 방문하는 방식</p>
<p>  8→4→9→2→10→5→11→1→13→6→3→14→7</p>
</li>
</ul>
<ul>
<li><p>후위 순회(post-order)</p>
<p>  <strong>왼쪽 하위 트리의 하위</strong>를 모두 방문 후 → <strong>오른쪽 하위 트리의 하위</strong>를 우선 방문 후 → <strong>루트</strong>를 방문하는 방식</p>
<p>  8→9→4→10→11→5→2→13→6→14→7→3→1</p>
</li>
</ul>
<ul>
<li><p>레벨 순회(level-order)</p>
<p>  계층에 존재하는 루트별로 방문하는 방식</p>
<p>  1→2→3→4→5→6→7→8→9→10→11→12→13→14</p>
</li>
</ul>
<p>트리의 종류</p>
<ul>
<li>이진트리<ul>
<li>이진 탐색 트리<ul>
<li><strong>red-black tree</strong></li>
</ul>
</li>
<li>포화 이진 트리</li>
<li>완전 이진 트리</li>
</ul>
</li>
<li><strong>트라이(trie)</strong></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[그래프(graph)]]></title>
            <link>https://velog.io/@ji-ha/%EA%B7%B8%EB%9E%98%ED%94%84graph</link>
            <guid>https://velog.io/@ji-ha/%EA%B7%B8%EB%9E%98%ED%94%84graph</guid>
            <pubDate>Tue, 18 Jan 2022 15:34:40 GMT</pubDate>
            <description><![CDATA[<h3 id="그래프의-정의">그래프의 정의</h3>
<p>노드와 그 노드를 연결하는 간선을 하나로 모아놓은 자료구조</p>
<h3 id="그래프의-특징">그래프의 특징</h3>
<p>그래프는 <strong>네트워크 모델</strong>이다.</p>
<p>부모-자식 관계라는 개념이 없다.</p>
<p>→ 루트 노드라는 개념이 없다.</p>
<p>순회는 DFS나 BFS로 이루어진다.</p>
<p>그래프는 순환 혹은 비순환이다.</p>
<p>그래프는 크게 방향 그래프와 무방향 그래프가 있다.</p>
<h3 id="무방향-그래프-방향-그래프">무방향 그래프? 방향 그래프?</h3>
<p>무방향: 간선을 통해서 양방향으로 갈 수 있다.</p>
<p>A-B와 B-A가 같다.</p>
<p>방향: 간선에 방향성이 존재하는 그래프</p>
<p>A→B와 B→A가 다르다</p>
<h3 id="가중치-그래프">가중치 그래프?</h3>
<p>간선에 비용이나 가중치가 할당된 그래프</p>
<ul>
<li>네트워크라고도 한다</li>
</ul>
<h3 id="연결-그래프-비연결-그래프">연결 그래프? 비연결 그래프?</h3>
<p>연결 그래프: 무방향 그래프에 있는 모든 정점쌍에 대해서 항상 경로가 존재하는 경우</p>
<p>비연결 그래프: 무방향 그래프에서 특정 정점쌍 사이에 경로가 존재하지 않는 경우</p>
<h3 id="사이클-비순환-그래프">사이클? 비순환 그래프?</h3>
<p>사이클: 단순 경로의 시작 정점과 종료 정점이 동일한 경우</p>
<ul>
<li>단순 경로? 경로 중에서 반복되는 정점이 없는 경우</li>
</ul>
<p>비순환 그래프</p>
<ul>
<li>사이클이 없는 그래프</li>
</ul>
<h3 id="완전-그래프">완전 그래프?</h3>
<ul>
<li>그래프에 속해 있는 모든 정점이 서로 연결되어 있는 그래프</li>
<li>무방향 완전 그래프</li>
</ul>
<h3 id="그래프-구현-방법">그래프 구현 방법?</h3>
<ol>
<li>인접 <strong>행렬</strong><ol>
<li>사용하면 좋을 때 : 그래프에 간선이 많이 존재하는 <strong>밀집(Dense) 그래프</strong>인 경우</li>
<li>장점<ol>
<li>2차원 배열에 있는 위치만 확인하면 되기 때문에 조회 시간이 <strong>O(1)</strong>입니다.</li>
</ol>
</li>
<li>단점<ol>
<li>모든 정점에 대한 간선정보를 대입해야해서 입력시에는 O(n^2)의 시간복잡도를 가진다.</li>
<li>무조건 2차원 배열이 필요해서 <strong>공간의 낭비가 있다</strong></li>
</ol>
</li>
</ol>
</li>
<li>인접 <strong>리스트</strong><ol>
<li>사용하면 좋을 때 : 그래프에 간선이 적은 <strong>희소(Sparse)</strong> 그래프인 경우</li>
<li>장점<ol>
<li>인접한 노드를 쉽게 찾을 수 있다.</li>
<li>그래프에 <strong>존재하는 간선의 수</strong>를 O(N+E)안에 알 수 있다.</li>
<li>필요한 만큼의 공간만 사용하여 <strong>공간의 낭비가 적다</strong></li>
</ol>
</li>
<li>단점<ol>
<li>특정 두 점이 연결되었는지 확인하려면 인접행렬에 비해 시간이 오래 걸린다.</li>
</ol>
</li>
</ol>
</li>
</ol>
<h3 id="그래프의-탐색-방법">그래프의 탐색 방법</h3>
<ol>
<li>DFS<ol>
<li>넓게 탐색하기 전에 깊게 탐색하는 것</li>
<li><strong>모든 노드를 방문</strong>하고자 할 때 이 방법 선택하는 게 좋음</li>
</ol>
</li>
<li>BFS<ol>
<li>깊게 탐색하기 전에 넓게 탐색하는 것</li>
<li>두 노드 사이의 <strong>최단 경로</strong> 혹은 <strong>임의의 경로</strong>를 찾고 싶을 때 이 방법을 선택하는 게 좋음</li>
</ol>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[리스트(List)]]></title>
            <link>https://velog.io/@ji-ha/%EB%A6%AC%EC%8A%A4%ED%8A%B8List-gnlczkoh</link>
            <guid>https://velog.io/@ji-ha/%EB%A6%AC%EC%8A%A4%ED%8A%B8List-gnlczkoh</guid>
            <pubDate>Wed, 05 Jan 2022 08:04:16 GMT</pubDate>
            <description><![CDATA[<h2 id="리스트의-정의">리스트의 정의</h2>
<p>배열이 가지고 있는 인덱스라는 장점 대신, <strong>빈틈없는 데이터의 적재</strong>라는 장점을 취한 <strong>선형</strong>자료구조</p>
<p>→ 하지만, 메모리에서 <strong>순차성을 보장하지는 못하기</strong> 때문에 locality는 보장되지 않는다. 따라서 <strong>cash hit가 어렵다.</strong></p>
<h2 id="java에서의-list">java에서의 list</h2>
<p>java에서 List를 구현하여 사용할 수 있는 방법은 두가지로 나뉜다.</p>
<h3 id="링크드리스트linkedlist">링크드리스트(LinkedList)</h3>
<p><strong>연결</strong>로 구현한 리스트</p>
<p><strong>시간복잡도</strong></p>
<p>추가/삭제: O(1)</p>
<p>접근: O(n)</p>
<h3 id="어레이리스트arraylist">어레이리스트(ArrayList)</h3>
<p><strong>배열</strong>을 이용하여 리스트를 구현한 것</p>
<h4 id="시간복잡도">시간복잡도</h4>
<p>추가/삭제: O(n)</p>
<p>접근: O(1)</p>
<h4 id="array배열와-arraylist의-차이점">array(배열)와 arrayList의 차이점</h4>
<p>array는 사이즈를 고정으로 사용하기 때문에, 사이즈 변경이 필요하다면 새로 선언해야한다.</p>
<p>arrayList는 리스트가 꽉차면, 사이즈를 <strong>동적으로 늘려준다.</strong></p>
<h4 id="java가-arraylist를-동적으로-늘리는-방법">java가 arrayList를 동적으로 늘리는 방법?</h4>
<p>동적으로 늘리는 방식을 흐름대로 살펴보자면,</p>
<p><img src="https://images.velog.io/images/ji-ha/post/bc829b39-de41-4b43-93ba-28567c3bdba9/list1.png" alt=""></p>
<p>add()를 통해 새로 들어오는 값을 list에 추가한다. 그때 들어가는 위치가 마지막이라면 grow()를 호출한다.</p>
<p><img src="https://images.velog.io/images/ji-ha/post/900a1d13-d47c-4009-b9be-643d8b646154/list2.png" alt=""></p>
<p>grow는 list 사이즈가 java에서 정해놓은 최소값보다 작다면 최소값으로 만들어주고, 그 이상의 값이라면 1.5배만큼 list size를 증가시킨다.</p>
<p><img src="https://images.velog.io/images/ji-ha/post/040f69c1-00a1-47c5-b13f-1e4712d15ebe/list3.png" alt=""></p>
<p>만약 사이즈를 증가시킬 때, java에서 정해놓은 MAX size보다 크다면 에러를 띄운다.</p>
<h3 id="arraylist와-linkedlist-비교">arrayList와 linkedList 비교</h3>
<p>삽입과 삭제는 linkedList가 훨씬 빠르지만, 조회를 할 때는 arrayList가 훨 낫다.</p>
<p>만약 <strong>조회가</strong> 많은 서비스라면 <strong>arrayList</strong>가, <strong>삽입과 삭제가</strong> 많은 <strong>linkedList</strong>가 더 적합하다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배열(array)]]></title>
            <link>https://velog.io/@ji-ha/%EB%B0%B0%EC%97%B4array</link>
            <guid>https://velog.io/@ji-ha/%EB%B0%B0%EC%97%B4array</guid>
            <pubDate>Wed, 05 Jan 2022 07:16:34 GMT</pubDate>
            <description><![CDATA[<h2 id="배열의-정의">배열의 정의</h2>
<p><strong>고정된</strong> 크기를 갖는 <strong>같은 자료형</strong>의 원소들이 연속적인 형태로 구성된 <strong>선형자료구조</strong></p>
<p>→크기를 변경하려면 새로 배열을 선언하는 수밖에 없다.</p>
<h2 id="배열-특징">배열 특징</h2>
<p>cache hit 가능성이 커져서 성능에 큰 도움이 된다?</p>
<p>→ 연속된 메모리 공간에 저장되기 때문에 캐시 <strong>지역성(locality)</strong>이 증가하여 캐시 적중률이 증가하는 것</p>
<p>overhead가 적다</p>
<p>→ 장점이자 단점인 고정된 크기를 갖는다는 특성은 <strong>추가적인 메모리가 필요하지 않다</strong>는 것을 의미하고, 이는 overhead가 적다는 것으로 이어진다</p>
<p>메모리 낭비가 발생할 수 있다</p>
<p>→ <strong>크기가 고정</strong>되어 있어서, 사용하지 않는 부분이 많을 경우에는 <strong>저장 공간의 낭비가 발생</strong>할 수 있다</p>
<h2 id="시간복잡도">시간복잡도</h2>
<p>접근/수정: O(1)</p>
<p>삽입/삭제: O(n)</p>
<h2 id="java에서의-array">java에서의 array</h2>
<p>arrayList가 array가 아니다!</p>
<p>→ 선형 데이터구조를 정리하다가 arrayList와 array가 헷갈려서 확실히정하고 간다!</p>
<pre><code class="language-json">int[] array = new int[5];</code></pre>
<p>이런식으로 <strong>대괄호로 선언</strong>하는 것이 array이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[큐(queue)]]></title>
            <link>https://velog.io/@ji-ha/%ED%81%90queue</link>
            <guid>https://velog.io/@ji-ha/%ED%81%90queue</guid>
            <pubDate>Mon, 03 Jan 2022 08:58:35 GMT</pubDate>
            <description><![CDATA[<h2 id="queue의-정의">queue의 정의</h2>
<p><strong>FIFO</strong>(First In First Out) 구조로 저장하는 자료구조</p>
<p>FIFO: 먼저 집어 넣은 데이터가 먼저 나오는 것</p>
<h2 id="시간복잡도">시간복잡도</h2>
<p>삽입/삭제: O(1)</p>
<h2 id="java에서의-queue">java에서의 queue</h2>
<p><img src="https://images.velog.io/images/ji-ha/post/4fdedb48-54d1-4f26-bc78-d8197875f186/1.png" alt=""></p>
<p><strong>Collection</strong>을 상속받는다.</p>
<p>Interface이기 때문에 LinkedList를 통하여 구현한다.</p>
<p><img src="https://images.velog.io/images/ji-ha/post/2c904c60-ef5d-4c6e-b347-5b2e31014c74/2.png" alt=""></p>
<p>add: 원하는 요소를 삽입하는 메소드. <strong>현재 사용 가능한 공간이 없으면</strong> exception을 던진다.</p>
<p><img src="https://images.velog.io/images/ji-ha/post/c1e41c81-bef1-4e91-8622-63a626c645b4/3.png" alt=""></p>
<p>offer: add와 하는 일은 똑같다. 하지만 현재 사용 공간이 없으면 false를 return한다. 값을 추가할 때는 <strong>offer() 추가하길 권장</strong>하고 있다.</p>
<p><img src="https://images.velog.io/images/ji-ha/post/8e4db704-cca1-47b2-b70a-eb6efd587842/4.png" alt=""></p>
<p>remove와 poll: 요소를 삭제하는 역할을 한다. 차이점은 remove는 queue가 비어있다면 <strong>exception</strong>을 던지고, poll은 <strong>null</strong>을 던진다는 점이다.</p>
<p>element와 peek: queue에 head에 있는 요소를 보여준다. element는 queue가 비어있다면 <strong>exception</strong>을 던지고, peek은 <strong>null</strong>을 return한다.</p>
<h2 id="priorityqueue">PriorityQueue</h2>
<p>알고리즘을 풀 때나, 여러 방면으로 자주 사용하는 queue인 거 같다.</p>
<p>이름은 queue이지만, 실제 구현에 사용되는 방식은 <strong>heap</strong>이다.</p>
<p>queue와의 가장 큰 차이점은 들어간 순서에 상관없이 <strong>우선순위가 높은 데이터</strong>가 먼저 나온다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스택(stack)]]></title>
            <link>https://velog.io/@ji-ha/%EC%8A%A4%ED%83%9Dstack</link>
            <guid>https://velog.io/@ji-ha/%EC%8A%A4%ED%83%9Dstack</guid>
            <pubDate>Mon, 03 Jan 2022 08:11:19 GMT</pubDate>
            <description><![CDATA[<h2 id="stack의-정의">stack의 정의</h2>
<p><strong>LIFO</strong>(Last In First Out) 형식의 자료구조</p>
<p>LIFO: 한 쪽 끝에서만 자료를 넣거나 빼는 것</p>
<h2 id="시간-복잡도">시간 복잡도</h2>
<p>삽입/삭제: O(1)</p>
<p>검색: O(n)</p>
<h2 id="java에서의-stack">java에서의 stack</h2>
<p><img src="https://images.velog.io/images/ji-ha/post/79eb2f61-26ae-426b-8a7b-c33874d8cac0/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-01-03%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.40.03.png" alt=""></p>
<p>stack은 vector를 <strong>상속</strong>받으므로써 구현된다</p>
<p><img src="https://images.velog.io/images/ji-ha/post/f538b855-6f9f-409e-9ae4-6f7f2ffc20d1/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-01-03%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.42.06.png" alt=""></p>
<p>push: 상속받은 vector에 존재하는 Object리스트에 값을 추가하는 메소드</p>
<p><img src="https://images.velog.io/images/ji-ha/post/81f65a5b-8f4a-40d6-9c52-25dcd1efde2d/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-01-03%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.43.15.png" alt=""></p>
<p>pop: stack에서 가장 최근에 push한 값을 빼는 메소드</p>
<p><img src="https://images.velog.io/images/ji-ha/post/43e3e94c-c067-4ecc-b18a-d7399c9567f6/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-01-03%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.44.58.png" alt=""></p>
<p>peek: stack에서 가장 위에 있는 값을 보여주는 메소드</p>
<p>이 외에는 serach(), empty()같은 메소드들이 존재한다.</p>
<p>여기서 주의깊게 봐야할 점은 pop(), peek(), search()에 모두 <strong><em>synchronized</em></strong>가 붙어있다는 것이다!</p>
<h3 id="java에서-stack이-쓰이지-않는-이유--vector가-쓰이지-않는-이유">java에서 stack이 쓰이지 않는 이유? == vector가 쓰이지 않는 이유</h3>
<p>stack이 상속하는 vector를 확인해보면, 우리가 왜 stack이 쓰이지 않는지 알 수 있다.</p>
<p><strong>vector의 문제점</strong></p>
<blockquote>
<p>get()이나 set()이 사용되는 메소드 외에도 여러 메소드에 synchronized 키워드가 붙는다</p>
</blockquote>
<p><strong>이게 왜 문제일까?</strong></p>
<ul>
<li>sychronized는 특정상황에서 <strong>성능이 저하</strong>되기 때문이다.<ul>
<li>vector에 존재하는 다양한 메소드가 sychronized 키워드를 가지고 있기 때문에 메소드를 부를 때마다 lock을 한다. 한번으로 충분한 <strong>lock을 무분별하게 사용</strong>하기 때문에 비효율적일 뿐더러 시간적으로도 오버헤드가 존재하여 사용하지 않는 게 낫다.</li>
<li>따라서, vector를 사용하기보다는 vector와 매우 비슷하지만, 빠른 arrayList를 사용하는 게 더 낫다고 한다.</li>
<li>그리고 java에서 스택을 구현할 일이 필요하다면, 구현체를 <a href="https://velog.io/@ji-ha/%EB%8D%B1deque"><strong>deque</strong></a>로 설정하는 게 좋다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[덱(deque)]]></title>
            <link>https://velog.io/@ji-ha/%EB%8D%B1deque</link>
            <guid>https://velog.io/@ji-ha/%EB%8D%B1deque</guid>
            <pubDate>Sun, 02 Jan 2022 11:14:12 GMT</pubDate>
            <description><![CDATA[<h2 id="deque의-정의">deque의 정의</h2>
<ul>
<li>덱은 <strong>double ended queue</strong>의 줄임말로 queue 인터페이스를 확장한 것이다.</li>
<li>자료의 입출력(추가, 삭제)을 <strong>양 끝에서 할 수 있다는 특징</strong>을 가지고 있다.</li>
<li>인덱스로 요소에 액세스, 삽입, 제거를 허용하지 않는다!</li>
<li>필요한 모든 스택 작업을 제공하기 때문에 편리하다.</li>
</ul>
<h2 id="">+</h2>
<blockquote>
<p>Deques can also be used as LIFO (Last-In-First-Out) stacks. This interface should be used in preference to the legacy Stack class. When a deque is used as a stack, elements are pushed and popped from the beginning of the deque.</p>
</blockquote>
<p>공식 문서에 있는 내용으로, <strong>deque</strong>가 LIFO인 stack으로 사용이 가능하니 <strong>레거시에 존재하는 stack 클래스보다 우선적으로 사용</strong>할 것을 권장하고 있다! == Deque의 구현체인 <strong>ArrayDeque</strong>를 사용하라는 뜻</p>
<h3 id="stack보다는-deque인-이유">stack보다는 deque인 이유?</h3>
<ol>
<li>stack은 vector를 상속받았다</li>
<li>vector는 <strong>특정상황</strong>(단일 스레드 실행, 단순 Iterator 탐색...)에서 효율적이지 않다!<ol>
<li>모든 작업에 Lock이 사용되기 때문에 단일 스레드 실행 성능이 저하된다</li>
</ol>
</li>
</ol>
<h2 id="deque의-시간-복잡도">deque의 시간 복잡도</h2>
<p>삽입/삭제(원소를 앞/뒤에 삽입 또는 삭제하는 경우): O(1)</p>
<p>조회: O(n)</p>
<h2 id="java에서의-deque">java에서의 deque</h2>
<h3 id="어떻게-저장이-되는걸까">어떻게 저장이 되는걸까?</h3>
<p><img src="https://images.velog.io/images/ji-ha/post/4e9c9ab3-7673-43a3-bbe7-048d55e328cb/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-01-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.43.47.png" alt=""></p>
<ul>
<li>deque의 element가 저장되는 <strong>배열</strong>.</li>
<li>element가 없는 셀은 항상 null이다.</li>
<li>배열에는 하나 이상의 null(꼬리 부분)이 있다.</li>
</ul>
<p><img src="https://images.velog.io/images/ji-ha/post/39007359-6cb0-4483-a368-dff379f3453b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-01-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.03.05.png" alt=""></p>
<p><img src="https://images.velog.io/images/ji-ha/post/5a739756-af7b-4244-b53d-66e91423499a/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-01-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.03.16.png" alt=""></p>
<ul>
<li>array 안에서 <strong>circular</strong>하게 데이터를 저장한다.</li>
<li>배열이 다 찼다면, grow()를 통하여 배열의 크기를 늘린다.</li>
<li>이 과정에서 head와 tail이 로직에 맞게 변경된다.</li>
</ul>
<p>단순한데 구현 참 잘했다..!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[String vs Object]]></title>
            <link>https://velog.io/@ji-ha/String-vs-Object</link>
            <guid>https://velog.io/@ji-ha/String-vs-Object</guid>
            <pubDate>Sat, 04 Dec 2021 08:42:27 GMT</pubDate>
            <description><![CDATA[<h2 id="string-클래스">String 클래스</h2>
<p>문자열을 저장하기 위해서 char[] value를 인스턴스 변수로 정의하고 있는 클래스
<img src="https://images.velog.io/images/ji-ha/post/4cceebec-7288-496d-8223-dddbd958832d/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202021-12-04%20%EC%98%A4%ED%9B%84%205.19.29.png" alt=""></p>
<blockquote>
<p>한번 생성된 String은 변경할 수 없다!
-&gt; +연산자를 이용해 문자열을 결합하는 경우 새로운 문자열이 담긴 인스턴스가 생성된다!
-&gt; 따라서, <strong>문자열을 다루는 작업이 필요한 경우</strong>는 <strong>StringBuffer클래스</strong>를 사용하자!</p>
</blockquote>
<h3 id="string을-만들-때-사용하는-두가지-방법">String을 만들 때 사용하는 두가지 방법</h3>
<pre><code>String literal = &quot;abc&quot;;
String constr = new String(&quot;abc&quot;);</code></pre><blockquote>
<p>리터럴 지정: 같은 내용의 문자열을 모두 하나의 String인스턴스를 참조.
생성자: new를 통한 메모리 할당으로, 새로운 String 인스턴스 생성</p>
</blockquote>
<h3 id="intern-메서드">intern() 메서드</h3>
<p>String인스턴스의 문자열을 &#39;constant pool&#39;에 등록하는 메서드
이미 등록되어 있다면 문자열의 주소값을 반환함</p>
<p>intern()을 사용하면, equals 대신 ==를 사용할 수 있다.
-&gt; 문자열의 개수가 많은 경우에는 <strong>equals보다 성능이 좋다</strong>!</p>
<h3 id="object와-string-비교">Object와 String 비교</h3>
<p>String이 Object에서 상속받은 equals와 hashCode를 Object와 비교하며 보려고 한다.</p>
<pre><code>public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (!COMPACT_STRINGS || this.coder == aString.coder) {
                return StringLatin1.equals(value, aString.value);
            }
        }
        return false;
}

// StringLatin1의 equals
@HotSpotIntrinsicCandidate
    public static boolean equals(byte[] value, byte[] other) {
        if (value.length == other.length) {
            for (int i = 0; i &lt; value.length; i++) {
                if (value[i] != other[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
}</code></pre><p>Object를 상속받은 String 클래스는 equals()를 오버라이딩했다.</p>
<ul>
<li>Object와는 다르게, String이 가지고 있는 &quot;값&quot;이 같은지 확인한다.</li>
<li>코드 자체로 서로의 문자들을 일일히 비교하며 작동하기 때문에 이해가 되었다.</li>
</ul>
<h4 id="궁금한-점은">궁금한 점은</h4>
<ol>
<li>리터럴로 String이 생성될 때 constant pool에 등록하는 과정을 찾아볼 수 없었다.</li>
<li>equals를 사용할 때 hashCode역시 오버라이딩을 해야한다고 하는데, 둘의 접점이 String 클래스에서는 찾을 수 없었다.</li>
</ol>
<p>-&gt; 해쉬에 대한 추가 공부</p>
<h3 id="equals를-사용할-때는-hashcode역시-오버라이딩해야한다">equals를 사용할 때는 hashCode역시 오버라이딩해야한다?</h3>
<p>따라서, hashCode를 오버라이딩하지 않는다면, 새로운 객체를 만들 때 마다 Object클래스에 정의된 대로 모든 객체가 서로 다른 해시코드를 가질 것이다.
-&gt; 그렇기때문에 equals를 오버라이딩할 때 hashCode메서드도 같이 오버라이딩해야한다?</p>
<pre><code>//String
public int hashCode() {
        int h = hash;
        if (h == 0 &amp;&amp; !hashIsZero) {
            h = isLatin1() ? StringLatin1.hashCode(value)
                           : StringUTF16.hashCode(value);
            if (h == 0) {
                hashIsZero = true;
            } else {
                hash = h;
            }
        }
        return h;
}

//StringLatin1.java
public static int hashCode(byte[] value) {
        int h = 0;
        for (byte v : value) {
            h = 31 * h + (v &amp; 0xff);
        }
        return h;
}</code></pre><p>가지고 있는 문자(value)를 hash해서 갖는다.
만약에 존재하지 않는다면 새로운 hash값이 생길테고, hash값이 존재한다면 그 존재하는 값을 가지게 된다.</p>
<p>하지만, String 코드에서 hash가 어떻게 사용하는지를 모르겠다.
내가 생각한 가정은,
이 고유한 해쉬가 constant pool에 존재하고, 같은 이름이 들어왔을 때 같은 해쉬값이 나오면, 그 해쉬 값을 기준으로 메모리를 찾아가 연결한다고 생각하였는데 이걸 증명할 수 있을만한 코드가 보이지 않는다.</p>
<ol>
<li>리터럴로 만들어지는 String 코드를 알아내야함.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[java.lang - Object클래스]]></title>
            <link>https://velog.io/@ji-ha/java.lang-Object</link>
            <guid>https://velog.io/@ji-ha/java.lang-Object</guid>
            <pubDate>Sat, 04 Dec 2021 08:16:23 GMT</pubDate>
            <description><![CDATA[<h2 id="미리-알고-가야할-팁">미리 알고 가야할 팁</h2>
<ul>
<li>객체를 생성할 때 <strong>비어있는 메모리 공간</strong>을 찾아 생성한다
  -&gt; 서로 다른 두 개의 객체가 <strong>같은 주소를 갖는 일</strong>은 없다.
  -&gt; 하지만, 두개 이상의 참조변수가 <strong>같은 주소값을 갖는 것</strong>은 가능하다.</li>
</ul>
<h2 id="object-클래스">Object 클래스</h2>
<p>모든 클래스들의 최고 조상</p>
<h3 id="equals-메서드">equals 메서드</h3>
<p>객체의 참조변수를 받아 비교하는 메서드</p>
<pre><code>public boolean equals(Object obj) {
        return (this == obj);
}</code></pre><blockquote>
<ul>
<li>Object에서의 equal은 <strong>==</strong> 에 의해 판단된다. 
  -&gt; 이는 <strong>참조변수</strong>의 값을 비교함으로써 판단한다.
<img src="https://images.velog.io/images/ji-ha/post/73956fe6-bbf8-46be-95f4-d152264b07cb/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202021-12-04%20%EC%98%A4%ED%9B%84%204.31.51.png" alt="">사진으로 보면, 두 참조변수의 <strong>뿌리가 같은지 확인</strong>하는 과정이 equal의 로직인 것을 확인할 수 있다.</li>
</ul>
</blockquote>
<h3 id="hashcode-메서드">hashCode 메서드</h3>
<p>Object의 hashCode 메서드</p>
<pre><code>@HotSpotIntrinsicCandidate
    public native int hashCode();</code></pre><blockquote>
<ul>
<li>해싱?: 데이터관리기법 중 하나. 다량의 데이터를 저장하고 검색</li>
</ul>
</blockquote>
<ul>
<li>같은 객체라면? hashCode메서드를 호출했을 때 결과값인 해시코드도 같아야한다.</li>
</ul>
<p><strong>+ native메서드</strong> </p>
<ul>
<li>추상메서드처럼 몸통 없이 선언부만 있는 메서드이다.</li>
<li>자바로 구현하지 않고 <strong>해당 OS에 이미 존재하는 메서드</strong>를 사용한다.</li>
</ul>
<h3 id="clone-메서드">clone 메서드</h3>
<p>자신을 복제하여 새로운 인스턴스를 생성하는 메서드</p>
<pre><code>int[] arr = [1, 2, 3, 4, 5];
int[] arrClone = arr.clone();</code></pre><blockquote>
<ul>
<li>단순히 멤버변수의 값만 복사한다.</li>
</ul>
</blockquote>
<ul>
<li><strong>배열이나 인스턴스가 멤버</strong>로 정의되어 있는 클래스의 인스턴스는 완전한 복제가 불가능하다!</li>
<li><blockquote>
<p>복제된 인스턴스도 <strong>같은 주소</strong>를 갖기 때문에 원래의 인스턴스에 영향을 미친다.</p>
</blockquote>
</li>
</ul>
<pre><code>public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5};
        int[] arrClone = arr.clone();

        System.out.println(arr); //[I@2d6e8792
        System.out.println(arr.clone()); //[I@2812cbfa
        System.out.println(arrClone); //[I@2acf57e3

        arrClone[1] = 0;
        System.out.println(arr[1]); // 2
        System.out.println(arrClone[1]); // 0
}</code></pre><h4 id="배열-복사가-되는-이유-">배열 복사가 되는 이유 ?</h4>
<p>-&gt; 배열도 객체이기 때문에 Object를 상속 받고, Coneable과 Serializable을 구현하였기 때문에 clone()을 통해 복제가 가능하다.
-&gt; 해당 복제본은 원본과 다르다!</p>
]]></description>
        </item>
    </channel>
</rss>