<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hye_b.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 24 Jan 2023 04:10:48 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hye_b.log</title>
            <url>https://images.velog.io/images/hye_b/profile/3f95160b-267b-4cc9-a23d-0d7b60366bd4/1.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hye_b.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hye_b" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Programmers][Java] 연속된 수의 합]]></title>
            <link>https://velog.io/@hye_b/ProgrammersJava-%EC%97%B0%EC%86%8D%EB%90%9C-%EC%88%98%EC%9D%98-%ED%95%A9</link>
            <guid>https://velog.io/@hye_b/ProgrammersJava-%EC%97%B0%EC%86%8D%EB%90%9C-%EC%88%98%EC%9D%98-%ED%95%A9</guid>
            <pubDate>Tue, 24 Jan 2023 04:10:48 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hye_b/post/d297d015-950c-4bb7-b1b8-8a3c53c5698b/image.png" alt=""></p>
<blockquote>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120923">https://school.programmers.co.kr/learn/courses/30/lessons/120923</a></p>
</blockquote>
<h1 id="📒-문제">📒 문제</h1>
<p><img src="https://velog.velcdn.com/images/hye_b/post/29c496d3-d2fd-4110-a09f-d5cfa09783eb/image.png" alt=""></p>
<h1 id="📝-코드">📝 코드</h1>
<pre><code class="language-java"> public int[] solution(int num, int total) {
        int[] answer = new int[num];
        int startNum = total / num - num / 2;

        if (total % num &gt; 0) {
            startNum += 1;
        }

        for (int i = 0; i &lt; num; i++) {
            answer[i] = startNum++;
        }

        return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers][Java] 다음에 올 숫자]]></title>
            <link>https://velog.io/@hye_b/ProgrammersJava-%EB%8B%A4%EC%9D%8C%EC%97%90-%EC%98%AC-%EC%88%AB%EC%9E%90</link>
            <guid>https://velog.io/@hye_b/ProgrammersJava-%EB%8B%A4%EC%9D%8C%EC%97%90-%EC%98%AC-%EC%88%AB%EC%9E%90</guid>
            <pubDate>Tue, 24 Jan 2023 03:36:29 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hye_b/post/1cdea95a-3fc1-429b-9306-8ed26973d4a0/image.png" alt=""></p>
<blockquote>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120924">https://school.programmers.co.kr/learn/courses/30/lessons/120924</a></p>
</blockquote>
<h1 id="📒-문제">📒 문제</h1>
<p><img src="https://velog.velcdn.com/images/hye_b/post/f115e982-1bb9-4b5e-b4ea-75d1622ac1e2/image.png" alt=""></p>
<h1 id="📝-코드">📝 코드</h1>
<pre><code class="language-java">public int solution(int[] common) {
        int lastIndex = common.length - 1;

        if (common[1] - common[0] == common[2] - common[1]) {
            return common[lastIndex] + common[2] - common[1];
        } else {
            return common[lastIndex] * (common[1] / common[0]);
        }
}</code></pre>
<pre><code class="language-java">class Solution {
   public int solution(int[] common) {
        int lastIndex = common.length - 1;

        if (isArithmetic(common[0], common[1], common[2])) {
            return common[lastIndex] + common[2] - common[1];
        }

        if (isGeometric(common[0], common[1], common[2])) {
            return common[lastIndex] * (common[1] / common[0]);
        }
        return -1;
    }

    private boolean isGeometric(int firstNum, int secondNum, int thirdNum) {
        return secondNum / firstNum == thirdNum / secondNum;
    }

    public boolean isArithmetic(int firstNum, int secondNum, int thirdNum) {
        return secondNum - firstNum == thirdNum - secondNum;
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers][Java] 옹알이(1)]]></title>
            <link>https://velog.io/@hye_b/ProgrammersJava-%EC%98%B9%EC%95%8C%EC%9D%B41</link>
            <guid>https://velog.io/@hye_b/ProgrammersJava-%EC%98%B9%EC%95%8C%EC%9D%B41</guid>
            <pubDate>Mon, 23 Jan 2023 13:23:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hye_b/post/15ffe751-95d5-480c-8987-99e9970a62f2/image.png" alt=""></p>
<blockquote>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120956">https://school.programmers.co.kr/learn/courses/30/lessons/120956</a></p>
</blockquote>
<h1 id="📒-문제">📒 문제</h1>
<p><img src="https://velog.velcdn.com/images/hye_b/post/f9d2682e-bcf6-4f4a-8ea7-a677e6329b46/image.png" alt=""></p>
<h1 id="📝-코드">📝 코드</h1>
<pre><code class="language-java">    public class Baby {
        private final List&lt;String&gt; words;

        public Baby(List&lt;String&gt; words) {
            this.words = words;
        }

        public List&lt;String&gt; getWords() {
            return List.copyOf(words);
        }

        public boolean isBabbling(Baby baby, String word) {
            for (String babyWord : baby.words) {
                word = word.replace(babyWord, &quot; &quot;);
            }

            return word.isBlank();
        }
    }

    public int solution(String[] babbling) {
        Baby musseuk = new Baby(List.of(&quot;aya&quot;, &quot;ye&quot;, &quot;woo&quot;, &quot;ma&quot;));
        long answer = Arrays.stream(babbling).filter(bab -&gt; musseuk.isBabbling(musseuk, bab)).count();

        return Math.toIntExact(answer);
    }</code></pre>
<hr>
<h1 id="💡-정리하기">💡 정리하기</h1>
<blockquote>
<p>내가 원했던건 객체지향적으로 풀고싶었다. 무지성으로 문제를 푸는데에만 집중하지 않고 싶었다.
처음에는 문제를 또 급하게 읽어서 contains =&gt; true로 체크했는데 아니였다. 정규표현식을 사용할까 싶었는데, 모든 단어들을 나열하고 싶지 않았다. 결국 마지막으로 작성된 코드인데, 
isBabbling 메서드가 객체에 존재하는게 맞는지에 확신이 없다. 일단 저기에 둔건 어떤 비즈니스적인로직(여기까지 생각할 필요는 없지만) 이 존재하는 것이 아니고 그저 그 객체가 가능한지 판단하는 것이라 생각을 했기 때문이다... </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Cipher]]></title>
            <link>https://velog.io/@hye_b/Cipher</link>
            <guid>https://velog.io/@hye_b/Cipher</guid>
            <pubDate>Thu, 15 Sep 2022 03:00:45 GMT</pubDate>
            <description><![CDATA[<h1 id="cipher">Cipher</h1>
<blockquote>
<p>java 에서 암복호화에 사용하여는 클래스 </p>
</blockquote>
<h2 id="암호화">암호화</h2>
<ul>
<li>권한이 있는 사용자만 메세지를 이해하거나 접근할 수 있도록하는 것 </li>
<li>즉, 원문 메세지를 권한이 없는 사람들은 못 읽게한다.</li>
</ul>
<h2 id="cipher-사용">Cipher 사용</h2>
<pre><code class="language-java">Cipher cipher = Cipher.getInstance(&quot;AES/CBC/PKCSSPadding&quot;, Providername (선택) );
// 파라미터 문자열 각각의 값은 암호화 알고리즘, 운용방식, 패딩방식</code></pre>
<h3 id="암호화-알고리즘">암호화 알고리즘</h3>
<ul>
<li>단방향 알고리즘 : 암호문을 평문으로 되돌리는 복호화가 불가능하다.
=&gt; 해시 기법 (SHA-256, MD-5)</li>
<li>비대칭키 알고리즘 : 암복호화에 사용하는 키가 서로 다르고, 두 개의 키중 하나의 키는 반드시 공개되어야해서 공개키 방식이라고도 부른다.
=&gt; RSA</li>
<li>대칭키 알고리즘 : 암복호화에 사용하는 키가 서로같다. 
=&gt; AES</li>
</ul>
<h3 id="운용-방식">운용 방식</h3>
<ul>
<li>특정 비트 수의 집합을 일정 크기의 블록 단위로 구성하여 처리하는 암호 기법을 블록 암호화</li>
<li>블록을 어떻게 암호화 할지 정해야하는데 이 블록들의 암호화 방식을 운용 방식이라 한다. </li>
</ul>
<h3 id="패딩">패딩</h3>
<ul>
<li>AES나 DES와 같은 브록 암호 알고리즘은 평문의 길이가 해당 암호의 블록크기의 배수로 정확하게 떨어져야한다.</li>
<li>이 마지막 블록의 빈 공간을 채우는 것을 패딩이라한다.</li>
</ul>
<h2 id="secretkey">SecretKey</h2>
<pre><code class="language-java">SecretKey secretKey = new SecretKeySpec(keyBytes, &quot;AES&quot;);</code></pre>
<ul>
<li>암호화 작업들을 위한 키</li>
<li>keys는 인코딩된 키, 키의 인코딩 포맷, 암호화 알고리즘을 포함하는 불투명한 컨테이너</li>
</ul>
<h2 id="init">init</h2>
<pre><code class="language-java">Cipher cipher = Cipher.getInstance(&quot;AES/ECB/PKCS5Padding&quot;);
SecretKey secretKey = new SecretKeySpec(keyBytes, &quot;AES&quot;);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);</code></pre>
<ul>
<li>Cipher 객체 초기화 시 키 또는 증명서 그리고 Cipher의 작동 모드를 나타내는 Opmode와 함께 init() 메서드를 호출할 수 있다. </li>
<li>cipher 작업 모드<ul>
<li>ENCRYPT_MODE : cipher 객체를 암호화 모드로 초기화한다.</li>
<li>DECRYPT_MODE : cipher 객체를 복호화 모드로 초기화한다.</li>
<li>WRAP_MODE : cipher 객체를 key-wrapping 모드로 초기화한다.</li>
<li>UNWRAP_MODE : cipher 객체를 key-unwrapping 모드로 초기화한다.</li>
</ul>
</li>
<li>InvalidKeyException </li>
</ul>
<h2 id="dofinal">doFinal</h2>
<pre><code class="language-java">Cipher cipher = Cipher.getInstance(&quot;AES/ECB/PKCS5Padding&quot;);
SecretKey secretKey = new SecretKeySpec(keyBytes, &quot;AES&quot;);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);

return cipher.doFinl(message);</code></pre>
<ul>
<li>Cipher 객체를 초기화한 후에 암호화 또는 복호화 작업을 위해서 doFinal() 메서드를 호출한다.</li>
<li>암호화 또는 복호화된 메세지를 포함한 Byte 배열을 반환한다. </li>
</ul>
<h2 id="providers">Providers</h2>
<pre><code class="language-java">Security.addProvider(new BouncyCastleProvider());</code></pre>
<ul>
<li>BouncyCastle 인증된 암호화 라이브러리를 보안 공급자로 연결하고 새로운 알고리즘을 원할하게 추가할 수 있다. </li>
<li>Provider 구현체는 보안 알고리즘 구현체 목록을 포함하고 있다.</li>
<li>특정 알고리즘의 인스턴스가 필요해지면 프로바이더 저장소에서 해당 알고리즘의 적합한 구현체 클래스를 찾아 클래스 인스턴스를 생성한다. </li>
</ul>
<h1 id="refer">Refer</h1>
<p><a href="https://devjjsjjj.tistory.com/entry/Cipher-%EC%9E%90%EB%B0%94%EC%9D%98-%EC%95%94%ED%98%B8%ED%99%94%EB%B3%B5%ED%98%B8%ED%99%94%EB%A5%BC-%EB%8B%B4%EB%8B%B9%ED%95%98%EB%8A%94-%ED%81%B4%EB%9E%98%EC%8A%A4-1">https://devjjsjjj.tistory.com/entry/Cipher-%EC%9E%90%EB%B0%94%EC%9D%98-%EC%95%94%ED%98%B8%ED%99%94%EB%B3%B5%ED%98%B8%ED%99%94%EB%A5%BC-%EB%8B%B4%EB%8B%B9%ED%95%98%EB%8A%94-%ED%81%B4%EB%9E%98%EC%8A%A4-1</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Base64 ]]></title>
            <link>https://velog.io/@hye_b/Base64</link>
            <guid>https://velog.io/@hye_b/Base64</guid>
            <pubDate>Thu, 15 Sep 2022 02:10:59 GMT</pubDate>
            <description><![CDATA[<h1 id="base64">Base64</h1>
<blockquote>
<p>8비트 이진 데이터를 문자 코드에 영향을 받지 않는 공통 ASCII 영역의 문자들로만 이루어진 일련의 문자열로 바꾸는 인코딩 방식</p>
</blockquote>
<ul>
<li>화면에 표시가능한 ASCII 코드를 나타낼 수 있는 가장 큰 진법이 64</li>
<li>전자 메일을 통한 이진 데이터 전송에 많이 쓰인다. </li>
<li>알파벳 대소문자, 숫자, +, / 그리고 끝을 알리는 &quot;=&quot; </li>
<li>인코딩 후 원본보다 4/3 정도 크기가 늘어난다. </li>
</ul>
<h2 id="왜-사용하는가-">왜 사용하는가 ?</h2>
<blockquote>
<p>base64로 인코딩할 경우 파일의 크기가 늘어나고 추가연산이 필요한데 사용하는 이유가 무엇인가? </p>
</blockquote>
<ul>
<li>통신 과정에서 바이너리 데이터의 손실을 막기 위해서 사용 </li>
<li>안전한 출력 문자만을 사용하여 시스템별로 상이해서 생기는 문제들의 발생을 막기 위함 =&gt; 일부 제어문자의 경우 시스템 별로 다른 코드 값을 가짐 </li>
<li>문자를 위한 미디어에 포함된 바이너리 데이터가 시스템에 영향을 받지 않고 동일하게 전송 또는 저장되는 걸 보장하기 위함 </li>
</ul>
<h2 id="동작-방식">동작 방식</h2>
<p><img src="https://velog.velcdn.com/images/hye_b/post/3298bab3-af4b-4070-84d2-4b577c685181/image.png" alt=""></p>
<blockquote>
<p>HI 를 변환하면 SEk가 된다. SEk=
간편 확인은 <a href="https://www.useotools.com/ko/base64-decoder">https://www.useotools.com/ko/base64-decoder</a> 여기서 해봐도 좋을 것 같다.  </p>
</blockquote>
<ol>
<li><p>변환하고 싶은 문자열의 ASCII 값을 8비트로 변환</p>
</li>
<li><p>6bit씩 나누고, 6bit 보다 부족할 경우 0을 추가한다.
<img src="https://velog.velcdn.com/images/hye_b/post/34994697-fb56-478c-8af1-ecdb44a6eac1/image.png" alt=""></p>
</li>
<li><p>색인에 맞게 변경하고 마지막에 = 붙여주면 끝 </p>
</li>
</ol>
<h1 id="refer">Refer</h1>
<p><a href="https://ko.wikipedia.org/wiki/%EB%B2%A0%EC%9D%B4%EC%8A%A464">https://ko.wikipedia.org/wiki/%EB%B2%A0%EC%9D%B4%EC%8A%A464</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ASP - 2]]></title>
            <link>https://velog.io/@hye_b/ASP-2</link>
            <guid>https://velog.io/@hye_b/ASP-2</guid>
            <pubDate>Mon, 29 Aug 2022 09:32:43 GMT</pubDate>
            <description><![CDATA[<h1 id="asp">ASP</h1>
<p><img src="https://velog.velcdn.com/images/hye_b/post/f36f29a1-bb45-4780-b743-ede620a8c657/image.png" alt=""></p>
<blockquote>
<p>회사에서 과제로 ASP로 구현된 오랜 레거시 부분을 JAVA로 컨버팅하는 과제를 받았다. ASP ... 그게 뭔데.. 그거 어떻게 하는건데? </p>
</blockquote>
<h2 id="asp-연산자">ASP 연산자</h2>
<h3 id="산술-연산자">산술 연산자</h3>
<ul>
<li>mod : 나머지</li>
<li>^ : 지수</li>
</ul>
<h3 id="관계-연산자">관계 연산자</h3>
<ul>
<li>&lt;&gt; : 같지 않다</li>
<li>is : 객체 동등성 </li>
</ul>
<h3 id="논리-연산자">논리 연산자</h3>
<ul>
<li>AND : 논리곱, 두 조건이 모두 참일 경우 참 </li>
<li>NOT : 논리합, 두 조건 중 하나만 참이면 참</li>
<li>OR : 부정, 조건 값을 반대로 </li>
<li>XOR : Execlusive OR</li>
</ul>
<h3 id="연결-연산자">연결 연산자</h3>
<ul>
<li>&amp; </li>
</ul>
<h2 id="데이터-형식-변환">데이터 형식 변환</h2>
<ul>
<li>Cbool : Boolean </li>
<li>Cbyte : Byte</li>
<li>Ccur : Currency</li>
<li>Cdate : Date</li>
<li>CDbl : Double</li>
<li>Cint : Integer</li>
<li>CLng : Long</li>
<li>CSng : Single</li>
<li>Cstr : String</li>
</ul>
<h2 id="메서드">메서드</h2>
<h3 id="instrrev기준-문자열-찾는-문자">InstrRev(&quot;기준 문자열&quot;, &quot;찾는 문자&quot;)</h3>
<ul>
<li>찾는 문자를 기준 문자열 끝에서 부터 찾는다.<h3 id="alertmsgmove메세지-이동할-url">alertMsgMove(&quot;메세지&quot;, &quot;이동할 url&quot;)</h3>
</li>
<li>메세지를 띄우고 url로 이동 <h3 id="right문자열-숫자">Right(문자열, 숫자)</h3>
</li>
<li>오른쪽에서 숫자만큼의 문자열을 가져온다.<h3 id="left문자열-숫자">Left(문자열, 숫자)</h3>
</li>
<li>왼쪽에서 숫자만큼의 문자열을 가져온다.<h3 id="mid문자열-숫자1-숫자2">Mid(문자열, 숫자1, 숫자2)</h3>
</li>
<li>숫자 1번째 위치에서 숫자2 만큼의 문자열을 가져온다. </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ASP - 1]]></title>
            <link>https://velog.io/@hye_b/ASP-1</link>
            <guid>https://velog.io/@hye_b/ASP-1</guid>
            <pubDate>Sun, 28 Aug 2022 10:36:53 GMT</pubDate>
            <description><![CDATA[<h1 id="asp">ASP</h1>
<p><img src="https://velog.velcdn.com/images/hye_b/post/f36f29a1-bb45-4780-b743-ede620a8c657/image.png" alt=""></p>
<blockquote>
<p>회사에서 과제로 ASP로 구현된 오랜 레거시 부분을 JAVA로 컨버팅하는 과제를 받았다. ASP ... 그게 뭔데.. 그거 어떻게 하는건데? </p>
</blockquote>
<h2 id="🤔-asp-그게-뭔데-">🤔 ASP 그게 뭔데 ?</h2>
<p><img src="https://velog.velcdn.com/images/hye_b/post/f776dacb-0d94-45ab-b3a7-3352f298e338/image.png" alt=""></p>
<ul>
<li>Active Server Page <ul>
<li>서버 사이드 스크립트 엔진 </li>
<li>동적으로 서버에서 작동하는 페이지 </li>
<li>동적 &lt;-&gt; 정적(html)</li>
</ul>
</li>
<li>1995년 말에 등장, MS사 NT Machine 의 IIS 3.0 이상에서만 동작<ul>
<li>윈도우 운영체제에서만 작동</li>
</ul>
</li>
</ul>
<h3 id="특징">특징</h3>
<p style="text-align: center;">
<img src="https://velog.velcdn.com/images/hye_b/post/4d813ce6-b607-4b2f-91c6-be7e7c96e2ac/image.png" width=400/> 
</p>


<ul>
<li>사용자에게 보내주기 이전에 ASP.DLL이란 라이브러리에 넘겨 html 형식으로 만들어서 사용자의 브라우저에게 보내준다.<ul>
<li>소스가 노출되지 않는다.</li>
</ul>
</li>
<li>헝가리안 표기법<ul>
<li>strName, intNumber </li>
</ul>
</li>
<li>변수 선언을 하지 않고, 사용해도 오류를 발생시키지 않습니다.<ul>
<li>하지만 처리 속도가 느려진다.</li>
<li>그리고 가독성을 위해서 선언하자 .. 그냥 하자 </li>
</ul>
</li>
</ul>
<h2 id="asp-그거-어떻게-하는건데-">ASP 그거 어떻게 하는건데 ?</h2>
<p style="text-align: center;">
<img src="https://velog.velcdn.com/images/hye_b/post/f8abdef8-8cb4-4f1c-8845-f5230b98871e/image.png" width=400/>
</p>

<h2 id="📝-문법">📝 문법</h2>
<ul>
<li>세미콜론을 붙이지 않는다.  <h3 id="-">&lt;% %&gt;</h3>
</li>
<li>asp 코드는 &lt;%, %&gt; 사이에 작성해야한다. <h3 id="dim">DIM</h3>
<pre><code class="language-asp">DIM strName
DIM strPhoneNumber, intAge
DIM strMessage = &quot;이렇게 초기화는 안 됩니다.&quot; -&gt; x !! </code></pre>
</li>
<li>Dimension의 약자로 변수를 선언할 때 사용한다.</li>
<li>변수 선언 시 타입을 함께 선언하지 않는다.<ul>
<li>그래서 헝가리안 표기법을 사용해서 가독성을 높이려고 하는 것 같다.</li>
</ul>
</li>
<li>변수 여러개 선언 가능 </li>
<li>선언과 동시에 값 초기화 불가능 </li>
</ul>
<h3 id="set">SET</h3>
<pre><code class="language-ASP">SET myPhone = Server.CreateObject(&quot;Telephone.Handphone&quot;)
myPhone.color = &quot;green&quot;
SET myPhone = Nothing</code></pre>
<ul>
<li>개체를 생성한다. =&gt; like 객체 </li>
<li>Server.CreateObject() <ul>
<li>java의 NEW 와 같은 역할, 인스턴스 생성 </li>
</ul>
</li>
<li>SET ~ = Nothing 을 통해서 NULL로 만들 수 있다.</li>
</ul>
<h3 id="논리구문">논리구문</h3>
<pre><code class="language-ASP">IF intNumber = 1 THEN
    Response.Write &quot;1 입니다.&quot;
ELSEIF intNumber = 2 THEN
    Response.Write &quot;2 입니다.&quot;
ELSE
    Response.Write &quot;1과 2는 아닙니다. &quot;
END IF</code></pre>
<ul>
<li>만약 ~ 라면</li>
</ul>
<pre><code class="language-ASP">SELECT CASE intNumber
CASE 1
    Response.Write &quot;1 입니다.&quot;
CASE 2
    Response.Write &quot;2 입니다.&quot;
CASE ELSE
    Response.Write &quot;1과 2는 아닙니다. &quot;
END SELECT</code></pre>
<ul>
<li>조건이 많을 경우 사용</li>
<li>Java의 Switch</li>
</ul>
<pre><code class="language-ASP">DIM intNumber
FOR intNumber = 1 TO 10 STEP 1
    Response.write intNumber &amp; &quot;&lt;BR&gt;&quot;
NEXT</code></pre>
<ul>
<li>TO {반복횟수}, 반복 횟수만큼 반복한다.</li>
<li>Java의 for문</li>
<li>&amp; : 문자열을 이어준다.<pre><code class="language-ASP">DIM intNumber
intNumber = 1
DO WHILE intNumber &lt;= 10
  Response.write intNumber &amp; &quot;&lt;BR&gt;&quot;
  intNumber = intNumber + 1
LOOP</code></pre>
</li>
<li>WHILE 조건, 해당 조건을 충족하면 반복한다. </li>
<li>Java의 while문</li>
</ul>
<h2 id="☘️-자료형">☘️ 자료형</h2>
<h3 id="숫자">숫자</h3>
<ul>
<li>Byte<ul>
<li>0 ~ 255 까지의 정수</li>
</ul>
</li>
<li>Integer<ul>
<li>-32,768 ~ 32,767(2^15 - 1) 까지의 정수</li>
</ul>
</li>
<li>Long<ul>
<li>-2,147,483,648 ~ 2,147,483,647 까지의 정수 </li>
<li>Java의 int와 같다 </li>
</ul>
</li>
<li>Single<ul>
<li>부동 소수점 숫자</li>
</ul>
</li>
<li>Double<ul>
<li>-1.79769313486232E308 ~ -4.94065645841247E-324의 음수 범위</li>
<li>4.94065645841247E-32 ~ 1.79769313486232E308의 양수 범위</li>
</ul>
</li>
<li>Currency<ul>
<li>-922,337,203,685,477.5808 ~ 922,337,203,685,488.5807의 범위-</li>
<li>통화형을 저장하기 위한 자료형</li>
</ul>
</li>
</ul>
<h3 id="문자">문자</h3>
<pre><code class="language-asp">Dim strFirst, strSecond, strPlus
strFirst = &quot;139&quot;
strSecond = &quot;52&quot;
strPlus = strFirst + strSecond</code></pre>
<ul>
<li>위 코드의 답은 ? <ul>
<li>13952 </li>
<li>문자열 </li>
</ul>
</li>
</ul>
<h3 id="날짜">날짜</h3>
<pre><code class="language-ASP">#28/08/2022#</code></pre>
<ul>
<li>## 사이에 입력해야함</li>
<li>&quot;&quot; 사이에 입력할 경우 문자열이 된다. </li>
</ul>
<h3 id="boolean">Boolean</h3>
<ul>
<li>TRUE = -1</li>
<li>FALSE = 0</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[함께 자라기 (2)]]></title>
            <link>https://velog.io/@hye_b/%ED%95%A8%EA%BB%98-%EC%9E%90%EB%9D%BC%EA%B8%B0-2</link>
            <guid>https://velog.io/@hye_b/%ED%95%A8%EA%BB%98-%EC%9E%90%EB%9D%BC%EA%B8%B0-2</guid>
            <pubDate>Wed, 13 Jul 2022 07:37:04 GMT</pubDate>
            <description><![CDATA[<h2 id="함께-자라기-2">함께 자라기 (2)</h2>
<h3 id="달인이-되는-비결">달인이 되는 비결</h3>
<h3 id="인간은-평생-세수와-양치질을-꾸준하게-반복하는데-왜-달인이-안-될까요">인간은 평생 세수와 양치질을 꾸준하게 반복하는데 왜 달인이 안 될까요?</h3>
<ul>
<li>동기가 부족합니다.<ul>
<li>이를 잘 닦는 것은 일정 수준만 되면 더 잘하고자 하는 동기가 없습니다.</li>
<li>주변에 양치질과 세수 달인을 목표로 하는 분이 흔한가요? </li>
<li>치과에 다녀와서 양치질을 꼼꼼히 하자 라고 작심을 해도 개선되지 않습니다.</li>
</ul>
</li>
<li>피드백을 제때 받지 못합니다.<ul>
<li>내가 한 양치질에 대해 어디가 부족한지 정확한 피드백을 제때 받지 못합니다.</li>
<li>한 일년 닦다가 치과에 가서 의사에게 한소리 듣는 정도로 느린 피드백을 받습니다.</li>
<li>내가 뭘 잘했는지 못했는지 알지 못하고 실력도 늘지 않습니다.</li>
</ul>
</li>
<li>단순한 반복만 한다고 해서 달인이 될 수 없습니다.<ul>
<li>특정 영역에서 자신의 실력을 향상시키고 싶다면 양치질 하듯 수십 년을 단순히 반복해 온 것은 아닌지 반문해봅시다.</li>
</ul>
</li>
</ul>
<blockquote>
<p><em><strong>특정 영역에서 개인이 성취할 수 있는 최고 수준의 퍼포먼스는 경험을 오래한다고 해서 자동으로 얻을 수 있는 것은 아닙니다. -에릭손</strong></em></p>
</blockquote>
<blockquote>
<p>알고리즘 문제를 열심히 풀었을 때가 생각이 났다. 알고리즘 문제를 열심히 풀면서 실력은 늘어갔다 하지만 어느정도 늘고나서 정체가 생기는 느낌이였다. 난 스스로에게 피드백을 주지 않았다. 문제를 풀지 못했다면 다른 풀이를 보고 아 이렇게 하는 구나 라고 생각만하고 넘어가고 내가 이 문제에 대해 어떻게 접근을 하려했는지, 이 접근 방법이 왜 틀렸는지 다음에는 어떤식으로 접근하면 좋을지에 대해 스스로 피드백을 주지 않았다. 그래서 난 어느 순간까지만 실력이 늘었고 제자리에 머물러있었던 것 같다. </p>
</blockquote>
<h3 id="수십-년-동안-전문가가-안-되는-비결">수십 년 동안 전문가가 안 되는 비결</h3>
<h3 id="믿을-수-있는-직관이-형성되기-위해-특정-조건이-필요하다">믿을 수 있는 직관이 형성되기 위해 특정 조건이 필요하다.</h3>
<ul>
<li>타당성<ul>
<li>직관이 적용되는 영역에 어느 정도 인과관계와 규칙성이 존재해야 한다.</li>
<li>예측가능성이라 말할 수도 있습니다.</li>
<li>포커 게임 자체는 운이 작용하기 때문에 불확실한 면이 있지만 타당성이 높아서 전문성이 형성될 수 있습니다 =&gt; 일정한 규칙이 있고, 상대의 카드를 예측가능하다.</li>
</ul>
</li>
<li>피드백<ul>
<li>자신이 내린 직관적 판단에 대해 빨리 피드백을 받고 이를 통해 학습할 기회가 주어지는 환경이 갖춰져야 한다.</li>
<li>피드백이 부족한 직업으로 공항의 보안검사대 조사원을 들 수 있다. 자신이 오늘 얼마나 실수 했는지 아는 방법이 거의 없기 때문이다.</li>
<li>내과 의사보다 외과 의사가 전문성이 더 많이 누적된다. 왜냐하면 자신의 실수를 비교적 빠른 시간 내에 알 수 있기 때문에 </li>
</ul>
</li>
</ul>
<h3 id="타당성을-높이려면-">타당성을 높이려면 ?</h3>
<ul>
<li>변수를 제한하고 실험을 하면서 규칙성과 인과관계를 찾으려는 노력을 하면 된다.<h3 id="피드백을-높이려면-">피드백을 높이려면 ?</h3>
</li>
<li>동료나 상사, 고객에게, 혹은 내가 개발하는 프로그램에서 직접 피드백을 적극적으로 구하면 된다.</li>
</ul>
<h3 id="당신이-제자리-걸음인-이유">당신이 제자리 걸음인 이유</h3>
<ul>
<li>실력을 높이기 위해서는 의도적 수련이 중요한다.</li>
<li>의도적 수련이 되려면?<ul>
<li>나의 실력과 작업의 난이도가 비슷해야한다.</li>
<li>이때, 인간이 몰입을 경험한다고 한다. 이때 최고 수준의 집중력을 보이고, 덕분에 퍼포먼스나 학습 능력이 최대치가 될 수 있다.</li>
<li>또한 최고 수준의 행복감을 경험한다는 흥미로운 사실이 발견되었다.</li>
</ul>
</li>
<li>언어학자 크라센의 입력가설 i + 1 이론<ul>
<li>현재 언어학습자의 언어 수준을 i라고 할 때 딱 한단계 높은 i+1 수준의 입력이 주어질때에만 언어 능력이 유의미하게 진전한다는 이론<ul>
<li>교육학의 인지 부하 이론</li>
<li>학습 시 불필요하게 인지적인 부담을 주면 어떤 것도 제대로 학습하기 어렵다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="제자리-걸음에서-벗어나려면-">제자리 걸음에서 벗어나려면 ?</h3>
<ul>
<li>지루함을 느끼는 경우 방법 : a1 실력 낮추기<ul>
<li>작업의 난이도는 그대로 두고 실력을 낮추는 전략</li>
<li>같은 난이도의 체력 훈련을 하지만 팔과 다리에 모래주머니를 달고 운동하기</li>
<li>프로그래머의 경우 평상시 즐겨 쓰던 보조 도구를 일부러 안 쓰는것<ul>
<li>마우스를 즐겨 쓴다면 키보드로만 개발하기</li>
<li>디버그를 사용하지 않아보기</li>
</ul>
</li>
<li>지루하던 작업이 몰입하는 작업이 되고 실력도 늘 수 있습니다.</li>
</ul>
</li>
<li>지루함을 느끼는 경우 : a2 난이도 높이기<ul>
<li>실력은 그대로 두고 난이도를 높이는 전략</li>
<li>이소룡은 무술을 너무 잘하기 때문에 3분 이내에 이긴다는 자신만의 제약을 추가했다.</li>
<li>하루만에 개발하라고 주어진 업무를 한 시간만에 할 수 있는 방법 고안해보기, 100rps면 되는 시스템을 1000rps 기준으로 만들기, 새로운 언어로 진행해보기</li>
<li>남들보다 일을 더 효율적으로 하기 위해 내가 직접 만들어 쓰는 나만의 도구, 방법 만들기 </li>
</ul>
</li>
<li>불안감을 느끼는 경우 : b2 실력 높이기<ul>
<li>사회적 접근 : 나보다 뛰어난 전문가의 도움을 얻는다.<ul>
<li>짝 프로그래밍, 튜토리얼 문서 보며 따라가보기</li>
</ul>
</li>
<li>도구적 접근 : 능력을 확장시켜 줄 수 있는 도구를 찾아 쓴다.<ul>
<li>디버거, 자동 통합 도구, 코드 분석툴, 오픈소스 라이브러리 ...</li>
</ul>
</li>
<li>내관적 접근 : 비슷한 일을 했던 경험을 머릿속에서 되살려보기<ul>
<li>비유적으로 문제를 해결한다.자기효용감이 증대하면서 스스로 인식하는 자기 실력이 향상되기 쉽고 몰입영역으로 들어가기 좋다.</li>
</ul>
</li>
</ul>
</li>
<li>불안감을 느끼는 경우 : b1 난이도 낮추기<ul>
<li>자신이 맡은 일의 가장 간단하면서 핵심적인 결과물, 즉 아기버전을 첫 번째 목표로 삼는다.<ul>
<li>테트리스를 만들어야 한다면 일단 화면에 사각형을 그려보자</li>
</ul>
</li>
<li>4인치 반사경을 만든 다음에 6인치 반사경을 만드는 것이 6인치 반사경을 하나 만드는 것 보다 빠르다.</li>
</ul>
</li>
</ul>
<h3 id="메타-인지-전략">메타 인지 전략</h3>
<ul>
<li>자기가 지금 어떤 상태인지 살피는 알아차림   </li>
<li>일신우일신 : 나날이 새롭게 한다. 계속적인 자기 혁신과 계발의 의미로 쓰인다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[함께 자라기 (1) ]]></title>
            <link>https://velog.io/@hye_b/%ED%95%A8%EA%BB%98-%EC%9E%90%EB%9D%BC%EA%B8%B0-1</link>
            <guid>https://velog.io/@hye_b/%ED%95%A8%EA%BB%98-%EC%9E%90%EB%9D%BC%EA%B8%B0-1</guid>
            <pubDate>Sat, 09 Jul 2022 09:29:00 GMT</pubDate>
            <description><![CDATA[<h2 id="1-자라기">1. 자라기</h2>
<h3 id="당신은-몇년차">당신은 몇년차?</h3>
<ul>
<li>멘토들이 서로 상반되는 의견을 주면 혼란스럽다 ⇒ 축복 받은일 , 모든 화살표가 같은 곳을 가리키는 경우가 더 예외적이므로 이런 상반된 의견과 정보 속에서 스스로 생각하는 훈련을 해나가야한다.</li>
<li>수파리<ul>
<li>우선 규칙을 지키고, 나중에는 그 규칙을 깨트리고, 다음에는 규칙 자체를 넘어선다.</li>
</ul>
</li>
<li>사람을 잘 뽑다는 기준 ?<ul>
<li>사람들이 채용된 후에 실제 직무를 하면서 얼마나 생산적이고 성과를 잘 내는지</li>
<li>통계적으로 채용 시 선발 여부를 고려하는 변수와 직무 성과라는 변수 양자 간의 상관성이 어떤가</li>
</ul>
</li>
<li>애자일은 학습을 소프트웨어 개발의 가장 큰 병목 중 하나로 본다.<ul>
<li>일반적인 프로젝트에서는 모든 피드백의 주기가 느리다.</li>
<li>하지만 애자일 프로젝트는 지금 내가 한 행동의 피드백을 10분, 한 시간, 하루 , 일주일 등 여러 주기를 통해 지속적으로 얻을 수 있다. ⇒ 그때 저지를 실수는 바로 다음 주기에서 교정할 수 있다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>서로 상반되는 의견을 주면 혼란스럽다. 라는 말이 요즘 내상황이다. 다양한 의견과 그에 타당한 근거들이 넘쳐나는 요즘 바다속에 들어가있는 느낌을 많이 받았고, 어떤 의견이 맞는지에 대해 혼란스러웠다 .. 다 맞는 얘기 같아서 .. 이 상황이 스스로 생각하는 훈련을 할 수 있는 좋은 기회가 된 것같다. 이런 혼란속에 있을 수 있어 다행이라고 생각한다. 하나의 문제를 두고 다양한 시각으로 바라볼 수 있으니까. 내가 잘 활용해야한다. 애자일의 장점 중 하나인 빠른 피드백을 알맞은 예시로 나타내주어서 바로 깨달을 수 있었다.</p>
</blockquote>
<h3 id="자기계발은-복리로-돌아온다">자기계발은 복리로 돌아온다.</h3>
<ul>
<li>회고를 할 때 항상 되짚어 보는 것 중 하나는 “나 자신에게 얼마나 투자를 했나, 소위 자기계발이라 하는 것”</li>
<li>조직이 복리로 성장하는 그림을 유기적이라고 한다.<ul>
<li>조직을 뜻하는 영단어 organization은 유기체 라는 의미도 있다.</li>
<li>조직은 유기적이다.</li>
</ul>
</li>
<li>직전 단계의 결과물을 통해 내가 더 성장하게 되는 것<ul>
<li>더글러스 엥겔바트의 예<ul>
<li>엥겔바트 삶의 목표는 인류가 해결하기 어려운 문제를 풀 수 있게 도와주는 것</li>
<li>처음 했던 작업은 사람들이 모여서 협업하기 좋은 환경과 도구를 만들었다. ⇒ 온라인 협업 도구</li>
<li>외력의 도움 없이 스스로 상황을 개선</li>
</ul>
</li>
</ul>
</li>
<li>지식이나 능력은 복리로 이자가 붙는다.<ul>
<li>어떻게 이율을 높일 것인가</li>
<li>지속적으로 현명한 투자를 하려면 어떻게 할 것인가 </li>
</ul>
</li>
</ul>
<blockquote>
<p>1년, 한달 단위로 회고를 써보지 않아서 나 자신에게 얼마나 투자를 했는지에 대해 생각해보지 않았다. 매일매일 일기처럼 어떤건 좋았고, 어떤건 고쳐보자 라고 작성하다보니 놓치고 있는 부분이다. 6월 한달 회고를 작성해봐야겠다. 조직, 유기적 부분을 보면서 결국 조직은 복리로 성장해야하구나, 이를 이루기 위해서는 어떤 방식이 좋을까 생각을 해봤을 때 결국 회사차원에서 사원들의 자기계발을 장려, 강제 ? 하는 부분이 없지 않아 있어야겠구나 생각이 들었다. 왜냐하면 자기 의지로 제자리 걸음을 할 직원들이 분명이 존재할 거라 생각한다. 그사람들은 그상태가 마음에 들었기 때문이니까 이런 사람들이 스스로의 의지로 자기계발을 한다는건 참 어려운 일 일것이다. 모두를 위해, 결국 회사를 위해 회사는 이런 복지를 강제 해야한다. </p>
</blockquote>
<h3 id="어떻게-이율을-높일-것인가">어떻게 이율을 높일 것인가?</h3>
<ul>
<li>자신이 이미 갖고 있는 것들을 잘 활용하라<ul>
<li>올해 몇 권을 읽었는지 자랑하지 말고, 내가 그 지식을 얼마나 어떻게 활용하는지 반성하라</li>
<li>이미 갖고 있는 것들을 하이퍼링크로 서로 촘촘히 연결하여 시너지 효과가 나게 하라.</li>
<li>하나의 영역에서 다른 영역으로 왔다갔다하는 것을 자주 해서 다른 영역 간을 넘나들기가 수월해지도록 하라.</li>
<li>새로운 것이 들어오면 이미 갖고 있는 것들과 충돌을 시도하라</li>
<li>현재 내가 하는 일이 차후에 밑거름이 될 수 있도록 하라</li>
</ul>
</li>
</ul>
<blockquote>
<p>첫 번째 부터 허를 찔렀다. 몇권을 책을 읽었다고만 말했지 어떻게 활용했는지는 말할 수 없다.. 그래서 지금부터 책을 정리하는 것 뿐만아니라 이 부분을 읽으며 어떤 생각을 가졌고 어떤 것을 배웠는지 써보려한다. 책을 읽었다에서 끝나는 것이 아니라 이책을 읽고 이런 부분을 배웠고 내가 원래 알고있던 ~ 부분과 연관지어 생각을 해보니 ~ 하다. 이런 식의 사고 흐름을 가져가야한다. 기존에 알고 있던것과 상반되는 지식이라면 어떻게 다른건지 왜 다른건지 그래서 어떤게 맞는지에 대해 생각해보는 시간을 가져야겠다. </p>
</blockquote>
<ul>
<li><p>외부 물질을 체화하라</p>
<ul>
<li>계속 내부 순환만 할 경우 수렴할 위험이 있다. 주기적인 외부자극을 통해 재빨리 자기화해라.</li>
<li>외부 물질 유입 이후 생긴 내부 갈등을 해결하려는 데에 노력을 기울여라</li>
</ul>
<blockquote>
<p>끝없이 동기 부여만 받고 이를 행하지 않는 사람들이 있다. (나도 그런듯 반성..) 동기부여를 받았으면 행해야한다. 제일 아래에 나오는 항목과도 연관되는 부분인데, 받았으면 그때 바로 행하자 ! 아무것도 하지 않으면 아무일도 일어나지 않는다.</p>
</blockquote>
</li>
<li><p>자신을 개선하는 프로세스에 대해 생각해 보라</p>
<ul>
<li>작업을 되돌아보는 회고/반성 활동을 주기적으로 하는 프로세스를 만들어라 ⇒ 일을 개선하기위해 하는 작업을 잘하기 위한 작업</li>
<li>나를 개선하는 과정을 어떻게 하면 개선할 수 있을지 고민하라.</li>
</ul>
<blockquote>
<p>일을 개선하기위해 하는 작업을 잘하기 위한 작업 ... ! 회고를 통해 이것이 가능하다고한다. 알고리즘 문제를 잘풀기 위해 1일 1알고리즘을 하는데 1일 1알고리즘을 잘 활용하기 위해 문제를 풀면서 어떤 사고 과정을 거쳤는지 생각을해보자 이런 맥락이 맞는가 .. 아래의 항목처럼 피드백을 받아 봐야하나? 나를 개선하기위한 작업을 개선한다. 심오하다 😅</p>
</blockquote>
</li>
<li><p>피드백을 자주 받아라</p>
<ul>
<li>사이클 타임을 줄여라. 새로운 정보를 얻었다면 1달, 혹은 1주 후에 작게라도 실험해보는 것이 좋다. 순환율을 높여라</li>
<li>일찍, 그리고 자주 실패하고 학습해라</li>
</ul>
<blockquote>
<p>피드백을 받는다는 것을 두려워했다. 피드백이라는건 결국엔 내가 더 개선되어야 하는 점인데 어렸을 땐 이부분이 나의 나쁜 부분을 들키는 .. 혼나는? 것 처럼 느껴져서 두려워했던 것 같다. 조금 어른이 되어서 예의 있는 피드백을 받았을 경우 인정하고 개선하기 위한 일을 행한다. 이런 피드백은 감사히 여긴다. 예의 없는 피드백을 하는 어린이 같은 어른들이 존재하는데, 그저 근거도 없이 개선 방안도 없이 예의 없이 툭 뱉어버리는 ,, (그러고 뿌듯해한다;) 이런 사람들을 보며 하지 말아야 하는 피드백을 배우곤 한다. 
실패는 자주 하고 있다.. 그래도 이 실패의 과정속에서 매번 깨달음을 얻고 있고, 개선하려 노력한다.</p>
</blockquote>
</li>
<li><p>자신의 능력을 높여주는 도구와 환경을 점진적으로 만들어라</p>
<ul>
<li>방이 조용해지고 배도 안 고프고 온도도 적절해지기만 하면 공부 시작해야지 라고 생각하는 사람들 중에 1등은 없다.</li>
<li>실제로 그런 환경이 되어도 몸에 배어든 습관 때문에 결국은 공부하지 못할 것이다.</li>
</ul>
<blockquote>
<p>뼈가 다 박살나버렸다. 2시부터 해야지, 3시 부터 해야지 .. 방금 책읽기 전에도 이거 한편만 보고 해야지 .. 하면서 시작했다. 또 한번 반성하고 간다 😭 오늘은 주말이니까 조금만 쉬어야지 하다가 평일이 되어서도 주말과 같은 패턴을 유지하고 있는 나를 보곤한다. 꾸준히, 한결같이가 중요한데 참 어려운 부분인 것 같다. 생각이 나면 바로 몸을 일으키고 행하는 방향으로 ..!! </p>
</blockquote>
</li>
</ul>
<h3 id="학습-프레임과-실행-프레임">학습 프레임과 실행 프레임</h3>
<ul>
<li>학습 프레임<ul>
<li>내가 안 그려 보았던 방식들을 실험해 보는 시간이에요, 여러가지 방식으로 실험해 보세요.</li>
<li>현재 주어진 과업이 <strong>내가 얼마나 배우느냐</strong>로 여기게 되는 틀</li>
</ul>
</li>
<li>실행 프레임<ul>
<li>여러분이 얼마나 그림을 잘 그리는지 보고자 합니다. 여러분의 창의성을 측정하고 점수를 매길거에요.</li>
<li>사람들이 현재 주어진 과업이 뭔가 <strong>좋은 성과를 내는 걸로</strong> 생각하는 틀</li>
<li>학습을 통한 성장이 목표라면 실행 프레임은 불리한 선택이다.</li>
</ul>
</li>
</ul>
<h3 id="당신이-도와주는-사람은-누구이고-또-당신이-도움을-요청하는-사람은-누구입니까">당신이 도와주는 사람은 누구이고, 또 당신이 도움을 요청하는 사람은 누구입니까?</h3>
<ul>
<li>아직 1년도 되지 않아서 책 보고 코드 보고 업무를 배워가는 중입니다. 그래서 딱히 누구에게 물어보지 않고 또 아직 업무 파악이 안 된 지라 누굴 도와주거나 할 입장도 아닙니다.</li>
<li>아직 1년도 되지 않아서 많이 물어보며 배우고 있습니다. A선임, B책임 … 그리고 제가 공부하고 싶은 내용을 주제로 팀 내 스터디를 운영하고 있습니다. 같이 공부해 가는 거지요. 제가 출퇴근 시간에 지하철에서 많이 봤던 프레임 워크와 관련된 문제로 다른 팀원이 어려워 하는걸 우연찮게 알게 되었습니다. 그래서 도와드렸죠. 아직 1년도 안 되어서 시간이 있으니까 적극적으로 다른 분들 일을 도와드리려고 나서고 있습니다.</li>
</ul>
<blockquote>
<p>같은 아직 1년도 되지 않아서 라는 시작이지만 내용이 확실히 다르다.(소름돋았다) 같은 상황임에도 그 상황을 내가 어떻게 풀어나가는지에 따라 기회로 만들 수 있고, 성장할 수 있음을 느낀다. (지금은 ... 난 후자 아닐까? ㅎ-ㅎ) </p>
</blockquote>
<h3 id="가장-학습하기-힘든-직업이-살아남는다">가장 학습하기 힘든 직업이 살아남는다.</h3>
<ul>
<li>인공지능 시스템에 유리한 조건<ul>
<li>목표가 분명하고 객관적으로 정해져 있으며 정적이다.</li>
<li>매 순간 선택할 수 있는 행동/선택의 종류가 유한하게 정해져 있다.</li>
<li>매 순간 자신이 목표에 얼마나 근접했는지를 알 수 있다. 내가 한 선택의 피드백이 빨리 주어진다.</li>
<li>주로 닫힌 시스템 즉, 예상 못 한 외부 요소가 갑자기 들어오지 않는 시스템 속에서 일한다.</li>
<li>과거의 선택과 결과에 대한 구조화된 기록이 많다.</li>
</ul>
</li>
</ul>
<h3 id="컴퓨터로-대체되기-힘든-일">컴퓨터로 대체되기 힘든 일</h3>
<ul>
<li>독창성<ul>
<li>주어진 주제나 상황에 대해 특이하거나 독창적인 생각을 해내기, 혹은 문제를 해결하는 창의적인 방법들을 만들어내기</li>
</ul>
</li>
<li>사회적 민감성<ul>
<li>타인의 반응을 알아차리고 그사람들이 왜 그렇게 반응하는지 이해하기</li>
</ul>
</li>
<li>협상<ul>
<li>사람들을 화해시키고 서로 간의 차이를 조정하려고 노력하기</li>
</ul>
</li>
<li>설득<ul>
<li>다른 사람들이 마음이나 행동을 바꾸게 설득하기</li>
</ul>
</li>
<li>타인을 돕고 돌보기<ul>
<li>개인적 도움, 치료, 감정적 지지 등 개인적 도움을 제공하는 것</li>
</ul>
</li>
</ul>
<h3 id="무엇에-집중할-것인가">무엇에 집중할 것인가</h3>
<ul>
<li>자신이 주로 하는 일이 남이 시킨 대로 혼자 프로그램을 만드는 것이라면 그런 스킬과 경력만 계속 쌓일 것입니다.</li>
<li>현재 자신의 업무 상황 속에서 창의적으로 사회적으로 일하지 않는 기간이 계속된다면 결국 자신의 커리어에 막대한 손해가 될 수 있다.</li>
<li>혼자서 딱 정해진 이만 할 수 있는 환경은 축복이 아니라 저주가 될 수  있다.</li>
<li>암묵지와 직관을 배우고 수련하는 방법을 배우자.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] Criteria]]></title>
            <link>https://velog.io/@hye_b/JPA-Criteria</link>
            <guid>https://velog.io/@hye_b/JPA-Criteria</guid>
            <pubDate>Wed, 29 Jun 2022 09:31:28 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p> JPQL을 자바 코드로 작성하도록 도와주는 빌더 클래스 API다. 문자가 아닌 코드로 JPQL을 작성하므로 문법 오류를 컴파일 단계에서 잡을 수 있고 동적 쿼리를 안전하게 생성할 수 있다는 장점이있다.
코드가 복잡하고 장황해서 직관적으로 이해가 힘들다는 단점도 있다.</p>
</blockquote>
<h2 id="🐯-criteria">🐯 Criteria</h2>
<blockquote>
<p> javax.persistence.criteria 패키지에 있다.</p>
</blockquote>
<pre><code class="language-java">//JPQL : select m from Member m

CriteriaBuilder cb = em.getCriteriaBuilder(); //Criteria 쿼리 빌더

//Criteria 생성, 반환 타입 지정
CriteriaQuery&lt;Member&gt; cq = cb.createQuery(Member.class);

Root&lt;Member&gt; m = cq.from(Member.class); //FROM 절
cq.select(m); // SELECT 절

// 완성된 쿼리를 넣어주면 된다.
TypeQuery&lt;Member&gt; query = em.createQuery(cq);
List&lt;Member&gt; members = query.getResultList();</code></pre>
<ul>
<li>criteria 쿼리를 생성하려면 먼저  criteria 빌더를 얻어야한다. 빌더는 EntityManager나 EntityManagerFactory에서 얻을 수 있다.</li>
<li>Criteria 쿼리 빌더에서 Criteria 쿼리를 생성한다. 이때 반환 타입을 지정할 수 있다.</li>
<li>FROM 절을 생성하며 반환된 값  m은 Criteria에서 사용하는 특별한 별칭이다. m을 조회의 시작점이라는 의미로 쿼리루트라 한다.</li>
<li>SELECT 절을 생성한다.</li>
</ul>
<h3 id="🦁-검색-조건과-정렬-추가하기">🦁 검색 조건과 정렬 추가하기</h3>
<pre><code class="language-java">//JPQL
//select m from Member m
//where m.username=&#39;회원1&#39;
//order by m.age desc

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery&lt;Member&gt; cq = cb.createQuery(Member.class);
Root&lt;Member&gt; m = cq.from(Member.class); //FROM 절 생성

// 검색 조건 정의
Predicate usernameEqual = cb.equal(m.get(&quot;username&quot;), &#39;회원1&#39;);

//정렬 조건 정의
javax.persistence.criteria.Order ageDesc = cb.desc(m.get(&quot;age&quot;));

//쿼리 생성
cq.select(m)
    .where(usernameEqual) //WHERE 절 생성
    .orderBy(ageDesc); //ORDER BY 절 생성

List&lt;Member&gt; resultList = em.createQuery(cq).getResultList();</code></pre>
<ul>
<li>검색 조건을 정의한 부분을 보면 m.get(&quot;username&quot;) 으로 되어 있는데 m은 회원 엔티티의 별칭이다. 이것은 JPQL에서 m.username과 같은 표현이다. 그리고 cb.equal(A,B)는 이름 그래도 A = B라는 뜻이다. 따라서 cb.equal(m.get(&quot;username&quot;), &quot;회원1&quot;)는 JPQL에서 m.username=&#39;회원1&#39;과 같은 표현이다. </li>
<li>정렬 조건을 정의하는 코드인 cb.desc(m.get(&quot;age&quot;))는 JPQL의 m.age desc와 같은 표현이다.</li>
<li>만들어둔 조건을 where, orderBy에 넣어서 원하는 쿼리를 생성한다.</li>
</ul>
<h3 id="쿼리-루트와-별칭">쿼리 루트와 별칭</h3>
<ul>
<li><code>Root&lt;Member&gt; m = cq.from(Member.class);</code> 여기서 m이 쿼리루트</li>
<li>쿼리 루트트 조회의 시작점이다.</li>
<li>Criteria에서 사용되는 특별한 별칭으로 엔티티에만 부여할 수 있다.</li>
<li>경로 표현식이 존재한다.<ul>
<li>m.get(&quot;username&quot;)은 JPQL의 m.username과 같다.</li>
<li>m.get(&quot;team&quot;).get(&quot;name&quot;)은 JPQL의 m.team.name과 같다.</li>
</ul>
</li>
</ul>
<h3 id="10살을-초과하는-회원을-조회하고-나이-역순으로-정렬">10살을 초과하는 회원을 조회하고 나이 역순으로 정렬</h3>
<pre><code class="language-java">//select m from Member m
//where m.age &gt; 10 order by m.age desc

Root&lt;Member&gt; m = cq.from(Member.class);

//타입 정보 필요
Predicate ageGt = cb.greaterThan(m.&lt;Integer&gt;get(&quot;age&quot;), 10);

cq.select(m);
cq.where(ageGt);
cq.orderBy(cb.desc(m.get(&quot;age&quot;)));</code></pre>
<ul>
<li>m.get(&quot;age&quot;)에서는 &quot;age&quot;의 타입 정보를 알지 못해서 제네릭으로 반환 타입 정보를 명시해야한다.(String과 같은 문자 타입은 지정하지 않아도 된다.)</li>
<li>greaterThan() 대신에 gt()를 사용해도 된다.</li>
</ul>
<h3 id="criteria-쿼리-생성">Criteria 쿼리 생성</h3>
<pre><code class="language-java">public interface CriteriaBuilder {
    CriteriaQuery&lt;Object&gt; createQuery(); //조회값 반환 타입 : Object

    //조회값 반환 타입 : 엔티티, 임베디드 타입, 기타
    &lt;T&gt; CriteriaQuery&lt;T&gt; createQuery(Class&lt;T&gt; resultClass);
    CriteriaQuery&lt;Tuple&gt; createTupleQuery(); //조회값 반환 타입: Tuple
}</code></pre>
<ul>
<li>Criteria를 사용하려면 CriteriaBuilder.createQuery() 메서드로 Criteria 쿼리를 생성하면 된다.</li>
</ul>
<h3 id="반환-타입">반환 타입</h3>
<pre><code class="language-java">CirteriaBuilder cb = em.getCriteriaBuilder();

//Member를 반환 타입으로 지정 
CriteriaQuery&lt;Member&gt; cq = cb.createQuery(Member.class);
...
//위에서 Member를 타입으로 지정했으므로 지정하지 않아도 Member 타입을 반환
List&lt;Member&gt; resultList = em.createQuery(cq).getResultList();</code></pre>
<ul>
<li>Criteria 쿼리를 생성할 때 파라미터로 쿼리 결과에 대한 반환 타입을 지정할 수 있다.</li>
<li>CriteriaQuery를 생성할 때 Member.class를 반환 타입으로 지정하면 em.createQuery(cq)에서 반환 타입을 지정하지 않아도 된다.</li>
</ul>
<h3 id="반환-타입을-지정할-수-없다면">반환 타입을 지정할 수 없다면?</h3>
<pre><code class="language-java">CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery&lt;Object&gt; cq = cb.createQuery(); // 조회값 반환 타입 : Object
...
List&lt;Object&gt; resultList = em.createQuery(cq).getResultList();</code></pre>
<ul>
<li>반환 타입을 지정할 수 없거나 반환 타입이 둘 이상이면 타입을 지정하지 않고 Object로 반환받으면 된다.</li>
</ul>
<h3 id="반환-타입이-둘-이상이면">반환 타입이 둘 이상이면?</h3>
<pre><code class="language-java">Criteriabuilder cb = em.getCriteriaBuilder();

//조회값 반환 타입 : Object[]
CriteriaQuery&lt;Object[]&gt; cq = cb.createQuery(Object[].class);
...
List&lt;Object[]&gt; resultList = em.createQuery(cq).getResultList();</code></pre>
<ul>
<li>반환 타입이 둘 이상이면 Object[]를 사용하는 것이 편리하다. </li>
</ul>
<h3 id="반환-타입을-튜플로-받고-싶으면">반환 타입을 튜플로 받고 싶으면?</h3>
<pre><code class="language-java">CriteriaBuilder cb = em.getCriteriaBuilder();
//조회값 반환 타입 : Tuple
CriteriaQuery&lt;Tuple&gt; cq = cb.createTupleQuery();
...
TypedQuery&lt;Tuple&gt; query = em.createQuery(cq);</code></pre>
<h3 id="튜플">튜플?</h3>
<ul>
<li>Criteria에서 제공하는 Map과 비슷한 반환 객체 <pre><code class="language-java">//JPQL: select m.username, m.age from Member m
CriteriaBuilder cb = em.getCriteriabuilder();
CriteriaQuery&lt;Tuple&gt; cq = cb.createTupleQuery();
//CriteriaQuery&lt;Tuple&gt; cq = cb.createQuery(Tuple.class); 
</code></pre>
</li>
</ul>
<p>Root<Member> m = cq.from(Member.class);
cq.multiselect(
    m.get(&quot;username&quot;).alias(&quot;username&quot;), //튜플에서 사용할 별칭
    m.get(&quot;age&quot;).alias(&quot;age&quot;)
);</p>
<p>TypedQuery<Tuple> query = em.createQuery(cq);
List<Tuple> resultList = query.getResultList();
for (Tuple tuple : resultList) {
    String username = tuple.get(&quot;username&quot;, String.class);</p>
<pre><code>Integer age = tuple.get(&quot;age&quot;, Integer.class);</code></pre><p>}</p>
<pre><code>- 튜플을 사용하려면 cb.createTupleQuery() 또는 cb.createQuery(Tuple.class)로 Criteria 를 생성한다.
- 튜플은 튜플의 검색 키로 사용할 튜플 전용 별칭을 필수로 할당해야 하며 alias() 메서드로 사용해서 지정할 수 있다.
- 선언해둔 튜플 별칭으로 데이터를 조회할 수 있다.
- 튜플은 이름 기반이라 순서 기반의 Object[]보다 안전하고 tuple.getElements()같은 메서드를 사용해서 현재 튜플의 별칭과 자바 타입도 조회할 수 있다.

### 튜플로 엔티티 조회하기
```java
CriteriaQuery&lt;Tuple&gt; cq = cb.createTupleQuery();
Root&lt;Member&gt; m = cq.from(Member.class);
cq.select(cb.tuple(
    m.alias(&quot;m&quot;),
    m.get(&quot;username&quot;).alias(&quot;username&quot;)
));

TypedQuery&lt;Tuple&gt; query = em.createQuery(cq);
List&lt;Tuple&gt; resultList = query.getResultList();
for (Tuple tuple : resultlist) {
    Member member = tuple.get(&quot;m&quot;, Member.class);
    String username = tuple.get(&quot;username&quot;, String.class);
}</code></pre><ul>
<li>cq.multiselect(...) 대신에 cq.select(cb.tuple(...)) 를 사용할 수 있다.</li>
</ul>
<hr>
<h2 id="조회-select-절">조회 (SELECT 절)</h2>
<h3 id="조회-대상을-한-건-여러-건-지정">조회 대상을 한 건, 여러 건 지정</h3>
<pre><code class="language-java">cq.select(m) // JPQL : select m</code></pre>
<ul>
<li>select 조회 대상을 하나만 지정</li>
</ul>
<pre><code class="language-java">sq.multiselect(m.get(&quot;username&quot;), me.get(&quot;age&quot;));</code></pre>
<ul>
<li>조회 대상을 여러건 지정할 때 multiselect를 사용하면 된다.</li>
</ul>
<pre><code class="language-java">CriteriaBuilder cb = em.getCriteriabUILDER();
//JPQL : select m.username, m.age
cq.select(cb.array(m.get(&quot;username&quot;), m.get(&quot;age&quot;)));</code></pre>
<ul>
<li>여러 건 지정은 cb.array를 사용해도 된다.</li>
</ul>
<h3 id="dintinct">DINTINCT</h3>
<blockquote>
<p>select, multiselect다음에 distinct(true)를 사용하면 된다.</p>
</blockquote>
<pre><code class="language-java">JPQL : select distinct m.username, m.age from Member m

CriteriaQuery&lt;Object[]&gt; cq = cb.createQuery(Object[].class);
Root&lt;Member&gt; m = cq.from(Member.class);
cq.multiselect(m.get(&quot;username&quot;), m.get(&quot;age&quot;)).distinct(true);
//cq.select(cb.array(m.get(&quot;username&quot;), m.get(&quot;age&quot;))).distinct(true);

TypedQuery&lt;Object[]&gt; query = em.createQuery(cq);
List&lt;Object[]&gt; resultList = query.getResultList();</code></pre>
<h3 id="newconstruct">NEW.construct()</h3>
<blockquote>
<p>JPQL에서 select new 생성자() 구문을 Criteria에서는 cb.construct(클래스타입, ...)로 사용한다.</p>
</blockquote>
<pre><code class="language-java">//JPQL: select new jpabook.domain.MemberDTO(m.username, m.age)
//from Member m

CriteriaQuery&lt;MemberDTO&gt; cq = cb.createQuery(MemberDTO.class);
Root&lt;Member&gt; m = cq.from(Member.class);

cq.select(cb.construct(MemberDTO.class, m.get(&quot;username&quot;), m.get(&quot;age&quot;)));

TypedQuery&lt;MemberDTO&gt; query = em.createQuery(cq);
List&lt;MemberDTO&gt; resultList = query.getResultList();</code></pre>
<ul>
<li>JPQL 에서는 패키지명을 다 적어주지만 Criteria는 코드를 직접 다루기 때문에 패키지명 생략이 가능하다.</li>
</ul>
<hr>
<h2 id="집합">집합</h2>
<h3 id="group-by">GROUP BY</h3>
<pre><code class="language-java">//팀 이름별로 나이가 가장 많은 사람과 가장 적은 사람을 구하자
/*
    JPQL 
    select m.team.name, max(m.age), min(m.age)
    from Member m
    group by m.team.name
 */

 CriteriaBuilder cb = em.getCriteriaBuilder();
 CriteriaQuery&lt;Object[]&gt; cq = cb.createQuery(Object[].class);
 Root&lt;Member&gt; m = cq.from(Member.class);

 Expression maxAge = cb.max(m.&lt;Integer&gt;get(&quot;age&quot;));
 Expression minAge = cb.min(m.&lt;Integer&gt;get(&quot;age&quot;));

 cq.multiselect(m.get(&quot;team&quot;).get(&quot;name&quot;), maxAge, minAge);
 cq.groupBy(m.get(&quot;team&quot;).get(&quot;name&quot;));

 TypedQuery&lt;Object[]&gt; query = em.createQuery(cq);
 List&lt;Object[]&gt; resultList = query.getResultList();</code></pre>
<ul>
<li>cq.groupBy(m.get(&quot;team&quot;).get(&quot;name&quot;))은 JPQL에서 group by m.team.name 과 같다.</li>
</ul>
<h3 id="having">HAVING</h3>
<ul>
<li>위와 같은 조건에 나이 어린 사람이 10살을 초과하는 팀을 조회하는  조건을 추가해보자<pre><code class="language-java">cq.multiselect(m.get(&quot;team&quot;).get(&quot;name&quot;), maxAge, minAge)
  .groupby(m.get(&quot;team&quot;).get(&quot;name&quot;))
  .having(cb.gt(minAge, 10));</code></pre>
</li>
<li>having(cb.ge(minAge, 10))은 JPQL에서 having min(m.age) &gt; 10 과 같다.</li>
</ul>
<hr>
<h2 id="정렬">정렬</h2>
<blockquote>
<p>cb.desc(...) 또는 cb.asc(...)로 생성할 수 있다.</p>
</blockquote>
<pre><code class="language-java">cq.select(m
    .where(ageGt)
    .orderBy(cb.desc(m.get(&quot;age&quot;)));</code></pre>
<hr>
<h2 id="join">JOIN</h2>
<pre><code class="language-java">public enum JoinType {
    INNER,
    LEFT,
    RIGHT
    // JPA 구현체나 DB에 따라 지원하지 않을 수 있다.
}</code></pre>
<ul>
<li>JoinType 클래스</li>
</ul>
<pre><code class="language-java">/* JPQL
    select m,t from Member m
    inner join m.team t
    where t.name = &#39;팀A&#39;
*/

Root&lt;Member&gt; m = cq.from(Member.class);
Join&lt;Member, Team&gt; t = m.join(&quot;team&quot;, JoinType.INNER);

cq.multiselect(m, t)
    .where(cb.equal(t.get(&quot;name&quot;), &quot;팀A&quot;));</code></pre>
<ul>
<li>쿼리 루트에서 바로 m.join(&quot;team&quot;) 메소드를 사용해서 회원과 팀을 조인했고</li>
<li>조인한 team에 t라는 별칭을 줬다.</li>
<li>조인 타입을 생략하면 내부 조인을 사용한다. </li>
<li>페치 조인시 주의사항은 JPQL과 같다.</li>
</ul>
<hr>
<h3 id="서브-쿼리">서브 쿼리</h3>
<ul>
<li>평균 나이 이상의 회원을 구하는 서브쿼리 (메인과 서브가 상호 관련 x)
```java
/* JPQL :
  select m from Member m
  where m.age &gt;= <pre><code>  (select AVG(m2.age) from Member m2)</code></pre></li>
<li>/</li>
</ul>
<p>CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> mainQuery = cb.createQuery(Member.class);</p>
<p>//서브쿼리 생성
Subquery<Double> subQuery = mainQuery.subquery(Double.class);</p>
<p>Root<Member> m2 = subQuery.from(Member.class);
subQuery.select(cb.avg(m2.<Integer>get(&quot;age&quot;)));</p>
<p>Root<Member> m = mainQuery.from(Member.class);
mainQuery.select(m)
    .where(cb.ge(m.<Integer>get(&quot;age&quot;), subQuery));</p>
<pre><code>
### 메인쿼리와 서브쿼리가 상호관련 있을 경우
```java
/* JPQL
    select m from Member m
    where exists
        (select t from m.team t where t.name=&#39;팀A&#39;)
*/
Criteriabuilder cb = em.getCriteriabUILDER();
CriteriaQuery&lt;Member&gt; mainQuery = cb.createQuery(Member.class);

// 서브 쿼리에서 사용되는 메인 쿼리의 m
Root&lt;Member&gt; m = mainQuery.from(Member.class);

//서브쿼리의 생성
Subquery&lt;Team&gt; subQuery = mainQuery.subquery(Team.class);
Root&lt;Member&gt; subM = subQuery.correlate(m); //메인 쿼리의 별칭을 가져온다.

Join&lt;Member, Team&gt; t = subM.join(&quot;team&quot;);
subQuery.select(t)
    .where(cb.equal(t.get(&quot;name&quot;), &quot;팀A&quot;));

// 메인 쿼리 생성
mainQuery.select(m)
    .where(cb.exists(subQuery));
List&lt;Member&gt; resultList = em.createQuery(mainQuery).getResultList();
</code></pre><ul>
<li>핵심은 subQuery.correlate(m)이다.</li>
<li>correlate(...) 메서드를 사용하면 메인 쿼리의 별칭을 서브 쿼리에서 사용할 수 있다.</li>
</ul>
<h3 id="in식">IN식</h3>
<ul>
<li>Criteria 빌더에서 in(...) 메서드를 사용한다.
```java
/* JPQL
  select m from Member m
  where m.username in (&quot;회원1&quot;, &quot;회원2&quot;)</li>
<li>/</li>
</ul>
<p>CriteriaBuilder cb = em.getCriteriabuilder();
CriteriaQuery<Member> cq = cb.createQuery(Member.class);
Root<Member> m = cq.from(Member.class);</p>
<p>cq.select(m)
    .where(cb.in(m.get(&quot;username&quot;))
    .value(&quot;회원1&quot;)
    .value(&quot;회원2&quot;));</p>
<pre><code>
 ### CASE 식
 &gt; selectCase() 메서드와 when(), otherwise() 메서드를 사용한다.

```java
/* JPQL
    select m.username,
    case when m.age&gt;=60 then 600
         when m.age&lt;=15 then 500
         else 1000
    end
  from Member m
*/

Root&lt;Member&gt; m = cq.from(Member.class);

cq.multiselect(
    m.get(&quot;username&quot;),
    cb.selectCase()
        .when(cb.ge(m.&lt;Integer&gt;get(&quot;age&quot;), 60), 600)
        .when(cb.le(m.&lt;Integer&gt;get(&quot;age&quot;), 15), 500)
        .otherwise(1000)
);</code></pre><h3 id="파라미터-정의">파라미터 정의</h3>
<pre><code class="language-java">/* JPQL 
    select m from Member m
    where m.username = :usernameParam
*/

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery&lt;Member&gt; cq = cb.createQuery(Member.class);

Root&lt;Member&gt; m = cq.from(Member.class);

//정의
cq.select(m)
    .where(cb.equal(m.get(&quot;username&quot;), cb.parameter(String.class, &quot;usernameParam&quot;)));
List&lt;Member&gt; resultList = em.createQuery(cq)
    .setParameter(&quot;usernameParam&quot;, &quot;회원1&quot;)
    .getResultList();</code></pre>
<ul>
<li>cb.parameter(타입, 파라미터 이름) 메서드를 사용해서 파라미터를 정의했다.</li>
<li>setParameter(&quot;usernameParam&quot;, &quot;회원1&quot;) 을 사용해서 해당 파라미터에 사용할 값을 바인딩했다. </li>
</ul>
<blockquote>
<ul>
<li>Criteria에서는 파라미터를 정의하지 않고 직접 값을 입력해도 실제 SQL에서는 PreparedStatement에 파라미터 바인딩을 사용하고 있다.</li>
</ul>
</blockquote>
<pre><code class="language-java">//java
cq.select(m)
    .where(cb.equal(m.get(&quot;username&quot;), &quot;회원1&quot;));
//sql
select * from Member m where m.name=?</code></pre>
<h2 id="네이티브-함수-호출">네이티브 함수 호출</h2>
<blockquote>
<p>cb.function(...)  메서드를 사용하면 된다.</p>
</blockquote>
<pre><code class="language-java">Root&lt;Member&gt; m = cq.from(Member.class);
Expression&lt;Long&gt; function = cb.function(&quot;SUM&quot;, Long.class, m.get(&quot;age&quot;));
cq.select(function);</code></pre>
<ul>
<li>전체 회원의 나이 합을 구하는 코드</li>
<li>SUM 대신에 원하는 네이티브 SQL 함수를 입력하면 된다.</li>
<li>하이버네이트 구현체는 방언에 사용자 정의 SQL함수를 등록해야 호출할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective Java] 아이템 25 - 톱레벨 클래스는 한 파일에 하나만 담으라]]></title>
            <link>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-25-%ED%86%B1%EB%A0%88%EB%B2%A8-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%ED%95%9C-%ED%8C%8C%EC%9D%BC%EC%97%90-%ED%95%98%EB%82%98%EB%A7%8C-%EB%8B%B4%EC%9C%BC%EB%9D%BC</link>
            <guid>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-25-%ED%86%B1%EB%A0%88%EB%B2%A8-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%ED%95%9C-%ED%8C%8C%EC%9D%BC%EC%97%90-%ED%95%98%EB%82%98%EB%A7%8C-%EB%8B%B4%EC%9C%BC%EB%9D%BC</guid>
            <pubDate>Wed, 29 Jun 2022 03:05:53 GMT</pubDate>
            <description><![CDATA[<h2 id="아이템-25--톱레벨-클래스는-한-파일에-하나만-담으라">아이템 25 : 톱레벨 클래스는 한 파일에 하나만 담으라</h2>
<h3 id="톱레벨-클래스">톱레벨 클래스</h3>
<blockquote>
<p>A top level class is a class that is not a nested class. - oracle</p>
</blockquote>
<ul>
<li>중첩 클래스가 아닌 단일 클래스 </li>
</ul>
<h3 id="톱레벨-클래스를-여러개-선언하기">톱레벨 클래스를 여러개 선언하기</h3>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        System.out.println(Utensil.NAME + Dessert.NAME);
    }
}

// 두 클래스가 한 파일에 정의되어있다. Utensil.java
class Utensil {
    static final String NAME = &quot;pan&quot;;
}
class Dessert {
    static final String NAME = &quot;cake&quot;;
}

// 두 클래스가 한 파일에 정의되어있다. Dessert.java
class Utensil {
    static final String NAME = &quot;pot&quot;;
}
class Dessert {
    static final String NAME = &quot;pie&quot;;
}</code></pre>
<ul>
<li>한 클래스를 여러 가지로 정의할 수 있으며, 그중 어느것을 사용할지는 어느 소스 파일을 먼저 컴파일하냐에 따라 달라진다.</li>
<li>javac Main.java Dessert.java 순서로 컴파일 한다면 중복 정의되어 있다고 컴파일 오류가 날 것이다.</li>
<li>javac Main.java 나 javac Main.java Utensil.java 명령으로 컴파일 한다면 pancake가 출력 될 것이다.</li>
<li>javac Dessert.java Main.java 로 컴파일 한다면 potpie 를 출력한다.</li>
</ul>
<h3 id="해결책">해결책?</h3>
<ul>
<li>톱레벨 클래스들을 서로 다른 소스 파일로 분리하면 그만</li>
<li>여러 톱레벨 클래스를 한 파일에 담고 싶다면 정적 멤버 클래스를 사용하는 방법을 고민해볼 수 있다.</li>
<li>다른 클래스에 딸린 부차적인 클래스라면 정적 멤버 클래스로 만드는 쪽이 일반적으로 더 나을 것이다.
=&gt; 읽기 좋고 private로 선언하면 접근 범위도 최소로 관리할 수 있기 때문이다.</li>
</ul>
<h3 id="정적-멤버-클래스">정적 멤버 클래스</h3>
<pre><code class="language-java">public class Test {
    public static void main(String[] args) {
        System.out.println(Utensil.NAME + Dessert.NAME);
    }

    private static class Utensil {
        static final String NAME = &quot;pan&quot;;
    }

    private static class Dessert {
        static final String NAME = &quot;cake&quot;;
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective Java] 아이템 24 : 멤버 클래스는 되도록  static으로 만들라]]></title>
            <link>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-24-%EB%A9%A4%EB%B2%84-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EB%90%98%EB%8F%84%EB%A1%9D-static%EC%9C%BC%EB%A1%9C-%EB%A7%8C%EB%93%A4%EB%9D%BC</link>
            <guid>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-24-%EB%A9%A4%EB%B2%84-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EB%90%98%EB%8F%84%EB%A1%9D-static%EC%9C%BC%EB%A1%9C-%EB%A7%8C%EB%93%A4%EB%9D%BC</guid>
            <pubDate>Wed, 29 Jun 2022 02:49:01 GMT</pubDate>
            <description><![CDATA[<h2 id="아이템-24---멤버-클래스는-되도록-static으로-만들라">아이템 24 - 멤버 클래스는 되도록 static으로 만들라</h2>
<h3 id="중첩-클래스">중첩 클래스</h3>
<ul>
<li>클래스 안에 정의 되어 있는 클래스</li>
<li>자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그외의 쓰임새가 있다면 톱레벨 클래스로 만들어야한다. </li>
<li>중첩클래스를 포함하는 외부 클래스를 Outer 클래스, 내부에 포함된 클래스를 중첩클래스 또는 Inner 클래스</li>
</ul>
<h3 id="중첩-클래스의-종류">중첩 클래스의 종류</h3>
<ul>
<li>정적 멤버 클래스</li>
<li>(비정적) 멤버 클래스 : Inner</li>
<li>익명 클래스 : Inner</li>
<li>지역 클래스 :Inner</li>
</ul>
<h3 id="중첩-클래스--정적-멤버-클래스">중첩 클래스 : 정적 멤버 클래스</h3>
<ul>
<li>다른 클래스 안에 선언되고, 바깥 클래스의 private   멤버에도 접근할 수 있다는 점만 제외하고 일반 클래스와 똑같다. </li>
<li>다른 정적 멤버와 똑같은 접근 규칙을 적용받는다. 
=&gt; private 로 선언하면 outer 클래스에서만 접근할 수 있다.</li>
<li>Outer 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스로 쓰인다.</li>
<li>아래의 Operation 열거 타입은 Caculator 클래스의 public 정적 멤버 클래스가 되어야 한다. 
=&gt; Calculator.Operation.PLUS , Calculator.Operation.MINUS 같은 형태 </li>
</ul>
<pre><code class="language-java">public enum Operation {
    PLUS, MINUS, TIMES, DIVIDE;
    ...
}</code></pre>
<h3 id="중첩-클래스--비정적-멤버-클래스">중첩 클래스 : 비정적 멤버 클래스</h3>
<ul>
<li>정적 멤버 클래스와의 차이는 static 이 붙어 있고 없고 뿐이지만 의미상 차이는 크다.</li>
<li>비정적 멤버 클래스의 인스턴스는 outer 클래스의 인스턴스와 암묵적으로 연결된다.</li>
<li>인스턴스 메서드에서 <strong>정규화된 this 를 사용해 outer 인스턴스의 메서드를 호출하거나 바깥 인스턴스의 참조를 가져올 수 있다.</strong><ul>
<li>정규화된 this? <ul>
<li>className.this 형태로 outer 클래스의 이름을 명시하는 용법 </li>
</ul>
</li>
</ul>
</li>
<li>개념상 중첩 클래스의 인스턴스가 outer 인스턴스와 독립적으로 존재할 수 있다면 정적 멤버 클래스로 만들어야한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_b/post/3a7591f0-e171-4e2b-9174-20fc51511372/image.png" alt=""></p>
<ul>
<li>비정적 멤버 클래스는 outer 인스턴스 없이는 생성할 수 없다. </li>
<li>관계 정보는 비정적 멤버 클래스의 인스턴스 안에 만들어져 메모리 공간을 차지하며, 생성 시간도 더 걸린다. <h4 id="어댑터를-정의할-때-자주-쓰이는-비정적-멤버-클래스">어댑터를 정의할 때 자주 쓰이는 비정적 멤버 클래스</h4>
</li>
<li>어떤 클래스의 인스턴스를 감싸 마치 다른 클래스의 인스턴스처럼 보이게 하는 뷰로 사용하는 것</li>
<li>Map 인터페이스의 구현체들은 보통 자신의 컬렉션 뷰를 구현할 때 비정적 멤버 클래스를 사용한다. </li>
</ul>
<h3 id="멤버-클래스에서-outer-인스턴스에-접근할-일이-없다면-무조건-static-붙여서-정적-멤버-클래스로-만들자">멤버 클래스에서 outer 인스턴스에 접근할 일이 없다면 무조건 static 붙여서 정적 멤버 클래스로 만들자.</h3>
<ul>
<li>static을 생략하면 outer  인스턴스로 숨은 외부 참조를 갖게 된다.</li>
<li>참조를 저장하려면 시간과 공간이 소비되고 심각한 문제는 가비지 컬렉션이 outer클래스의 인스턴스를 수거하지 못하는 메모리 누수가 생길 수 있다.</li>
</ul>
<h3 id="private-정적-멤버-클래스">private 정적 멤버 클래스</h3>
<ul>
<li>흔히 바깥 클래스가 표현하는 객체의 한 부분을 나타낼 때 쓴다.</li>
<li>Map 구현체는 각각의 키-값 쌍을 표현하는 엔트리 객체들을 가지고 있다.</li>
<li>모든 엔트리가 맵과 연관되어 있지만 엔트리의 메서드들은 맵을 직접 사용하지는 않는다.</li>
<li>엔트리를 비정적 멤버 클래스로 표현하느 것은 낭비고, private 정적 멤버 클래스가 가장 알맞다.</li>
</ul>
<h3 id="중첩클래스--익명-클래스">중첩클래스 : 익명 클래스</h3>
<ul>
<li>익명 클래스는 outer  클래스의 멤버가 아니고 쓰이는 시점에 선언과 동시에 인스턴스가 만들어지고 코드의 어디서든 만들 수 있다.</li>
<li>비정적인 쿤맥에서 사용될 때만 outer클래스의 인스턴스를 참조할 수 있다.</li>
<li>정적 문맥에서라도 상수 변수 이외의 정적 멤버는 가질 수 없다.</li>
<li>상수 표현을 위해 초기화된 final 기본 타입과 문자열 필드만 가질 수 있다.</li>
<li>정적 팩토리 메서드를 구현할 때 쓰인다.</li>
</ul>
<h3 id="익명-클래스-응용">익명 클래스 응용</h3>
<ul>
<li>선언한 지점에서만 인스턴스를 만들 수 있다.</li>
<li>instanceof 검사나 클래스의 이름이 필요한 작업은 수행할 수 없다.</li>
<li>여러 인터페이스를 구현할 수 없고, 인터페이스를 구현하는 동시에 다른 클래스를 상속할 수도 없다.</li>
<li>익명 클래스를 사용하는 클라이언트는 그 익명 클래스가 상위 타입에서 상속한 멤버 외에는 호출할 수 없다.</li>
<li>표현식 중간에 등장하므로 짧지 않으면 가독성이 떨어진다. 람다를 지원하기 전에는 즉석에서 작은 함수 객체나 처리 객체를 만드는 데 익명 클래스를 주로 사용했다.</li>
</ul>
<h3 id="중첩-클래스--지역-클래스">중첩 클래스 : 지역 클래스</h3>
<ul>
<li>가장 드물게 사용된다.</li>
<li>지역 변수를 선언할 수 있는 곳이면 실질적으로 어디서든 선언할 수 있고, 유효 범위도 지역변수와 같다.</li>
<li>멤버 클래스처럼 이름이 있고 반복해서 사용할 수 있다.</li>
<li>익명 클래스처럼 비정적 문잭에서 사용될 때만 outer 인스턴스를 참조할 수 있다.</li>
<li>정적 멤버는 가질 수 없으며 가독성을 위해 짧게 작성해야한다.</li>
</ul>
<h3 id="정리하기">정리하기</h3>
<ul>
<li>메서드 밖에서도 사용해야 하거나 메서드 안에 정의하기엔 너무 길다면 멤버 클래스로 만든다.</li>
<li>멤버 클래스의 인스턴스 각각이 outer 인스턴스를 참조한다면 비정적으로, 그렇지 않으면 정적으로 만들자</li>
<li>중첩 클래스가 한 메서드 안에서만 쓰이면서 그 인스턴스를 생성하는 지점이 단 한 곳이고 해당 타입으로 쓰기에 적합한 클래스나 인터페이스가 이미 있다면 익명 클래스로 만들고</li>
<li>그렇지 않다면 지역 클래스로 만들자.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective Java] 아이템 23 : 태그 달린 클래스보다는 클래스 계층구조를 활용하라]]></title>
            <link>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-23-%ED%83%9C%EA%B7%B8-%EB%8B%AC%EB%A6%B0-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%B3%B4%EB%8B%A4%EB%8A%94-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B3%84%EC%B8%B5%EA%B5%AC%EC%A1%B0%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-23-%ED%83%9C%EA%B7%B8-%EB%8B%AC%EB%A6%B0-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%B3%B4%EB%8B%A4%EB%8A%94-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B3%84%EC%B8%B5%EA%B5%AC%EC%A1%B0%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%98%EB%9D%BC</guid>
            <pubDate>Wed, 29 Jun 2022 01:27:40 GMT</pubDate>
            <description><![CDATA[<h2 id="아이템-23---태그-달린-클래스보다는-클래스-계층구조를-활용하라">아이템 23 - 태그 달린 클래스보다는 클래스 계층구조를 활용하라</h2>
<h3 id="태그-달린-클래스">태그 달린 클래스?</h3>
<pre><code class="language-java">class Figure {
    enum Shape { RECTANGLE, CIRCLE};

    //태그 필드 - 현재 모양을 나타낸다.
    final Shape shape;

    //다음 필드들은 모양이 사각형일 때만 쓰인다.
    double length;
    double width;

    //다음 필드는 모양이 원일 때만 쓰인다.
    double radius;

    //원용 생성자
    Figure (double radius) {
        shape = Shape.CIRCLE;
        this.radius = radius;
    }

    // 사각형용 생성자
    Figure(double length, double width) {
        shape = Shape.length;
        this.length = length;
        this.width = width;
    }

    double area() {
        swtich(shape) {
            case RECTANGLE:
                return length * width;
            case CIRCLE:
                return Math.PI * (radius * radius);
            default:
                throw new AssertionError(shape);
        }
    }
}</code></pre>
<ul>
<li>태그<ul>
<li>클래스의 타입에 대한 정보를 가지고 있는 멤버 필드를 의미한다.</li>
</ul>
</li>
</ul>
<h3 id="태그-달린-클래스의-단점">태그 달린 클래스의 단점</h3>
<ul>
<li><p>열거 타입 선언, 태그 필드, switch문 등 쓸데없느 코드가 많다.</p>
</li>
<li><p>여러 구현이 한 클래스에 혼합돼 있어서 가독성이 나쁘다.</p>
</li>
<li><p>다른 의미를 위한 코드도 언제나 함께 하니 메모리도 많이 사용한다.
=&gt; length, width, radius ...</p>
<ul>
<li>필드들을 final로 선언하려면 해당 의미에 쓰이지 않는 필드들까지 생성자에서 초기화 해야한다.
=&gt; 컴파일러가 잡아줄 수 없고 런타임에야 문제가 드러난다.</li>
<li>다른 의미(타입)를 추가하려면 코드를 수정해야한다. 
=&gt; switch문 .. </li>
<li>인스턴스의 타입만으로는 현재 나타내는 의미(타입) 를 알 길이 전혀 없다.</li>
<li>태그 달린 클래스는 장황하고, 오류를 내기 쉽고, 비효율적이다.</li>
</ul>
</li>
</ul>
<h3 id="대안-1-서브-타이핑-클래스-계층-구조">대안 1) 서브 타이핑 (클래스 계층 구조)</h3>
<pre><code class="language-java">abstract class Figure {
    abstract double area();
}

class Circle extends Figure {
    final double radius;

    Circle(double radius) {this.radius = radius;}
} 

class Rectangle extends Figure {
    final double length;
    final double width;

    Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override double area() {return length * width;}
}</code></pre>
<ul>
<li>계층구조의 루트가 될 추상 클래스를 정의한다.</li>
<li>태그 값에 따라 동작이 달라지는 메서드들을 루트 클래스의 추상 메서드로 선언한다
=&gt;  Figure 클래스의 area 메서드 </li>
<li>태그 값에 상관없이 동작이 일정한 메서드들을 루트 클래스에 일반 메서드로 추가</li>
<li>모든 하위 클래스에서 공통으로 사용하는 데이터필드들도 전부 루트 클래스로 올린다.</li>
<li>루트 클래스를 확장한 구체 클래스를 의미별로 하나씩 정의한다.</li>
</ul>
<h3 id="서브-타이핑-장점">서브 타이핑 장점</h3>
<ul>
<li>관련 없던 데이터 필드를 모두 제거 하고, 살아 남은 필드들은 모두 final 이다.</li>
<li>각 클래스의 생성자가 모든 필드를 남김없이 초기화하고 추상 메서드를 모두 구현했는지 컴파일러가 확인해준다.</li>
<li>루트 클래스의 코드를 건드리지 않고도 다른 프로그래머들이 독립적으로 계층구조를 확장하고 함께 사용할 수 있다. </li>
<li>타입별로 존재하니 변수의 의미를 명시하거나 제한할 수 있고, 또 특정 의미만 매개변수로 받을 수 있다.</li>
<li>타입 사이의 자연스로운 계층 관계를 반영할 수 있어서 유연성은 물론이고 컴파일 타임 타입 검사 능력을 높여준다는 장점도 있다.<h3 id="figure-클래스에-정사각형을-만드려면">Figure 클래스에 정사각형을 만드려면?</h3>
<pre><code class="language-java">class Square extends Rectangle {
  Square(double side) {
      super(side, side);
  }
}</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[엘레강트 오브젝트] 3장 - Employment (2)]]></title>
            <link>https://velog.io/@hye_b/%EC%97%98%EB%A0%88%EA%B0%95%ED%8A%B8-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-3%EC%9E%A5-Employment-2</link>
            <guid>https://velog.io/@hye_b/%EC%97%98%EB%A0%88%EA%B0%95%ED%8A%B8-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-3%EC%9E%A5-Employment-2</guid>
            <pubDate>Wed, 22 Jun 2022 05:06:40 GMT</pubDate>
            <description><![CDATA[<h3 id="352-좋은-의도-나쁜-결과">3.5.2 좋은 의도, 나쁜 결과</h3>
<ul>
<li>getter와 setter는 캡슐화 원칙을 위반하기 위해 설계되었습니다.<ul>
<li>클래스를 자료구조로 바꾸기 위해 도입이 되었다.</li>
<li>객체처럼 보이지만 수동적인 자료구조를 만들기 위해 getter, setter가 필요했다.</li>
</ul>
</li>
<li>java에서도 객체의 프로퍼티들을 public으로 만들면 클래스를 자료구조로 바꿀 수는 있습니다.
 <img src="https://velog.velcdn.com/images/hye_b/post/1f9b2aa0-864e-4e07-a43b-372597532b36/image.png" alt=""></li>
<li>하지만 이 방식은 Java 프로그래밍의 기본 규칙을 심각하게 위반하며 프로그래머가 OOP를 제대로 이해하지 못했다고 생각할 것 입니다. <blockquote>
<p>나는 DFS나 BFS 알고리즘 문제를 풀 때 NODE 클래스를 만들어서 활용하는데 그때 마다 필드를 public으로 만들어줬다. DFS, BFS에서도 getter, setter를 만들어서 사용한다는게 굳이라는 생각이 들어서 public으로 만들어준건데.. 한편으로는 이렇게 생각할 수도 있구나 싶어서 문제를 풀 때도 private로 가져가야하나 싶다 ...</p>
</blockquote>
</li>
<li>겉으로는 메서드처럼 보이지만 , 실제로는 우리가 데이터에 직접 접근하고 있다는 불쾌한 현실을 가리고 있을 뿐입니다. <blockquote>
<p>getter와 setter에 대해서는 데브코스 초반에 팀원들이랑 얘기를 나눠본 적이 있었다. 그때도 데이터에 직접 접근하고 그대로 노출하는 점에서 getter와 setter는 없어야하는게 아닌가? 라는 얘기를 나눴지만, 현재 getter를 사용하고 있다. (setter는 지양하려한다.) getter 없이 개발을 한 다는게 가능하다고 생각하지 않는다. 저자의 이상과 현실은 다르다.</p>
</blockquote>
</li>
</ul>
<h3 id="353-접두사에-관한-모든-것">3.5.3 접두사에 관한 모든 것</h3>
<ul>
<li><p>getter/setter 안타 패턴에서 유해한 부분은 두 접두사인 get과 set이라는 사실이 중요합니다.</p>
<ul>
<li>접두사는 객체가 진짜 객체가 아니고, 어떤 종중도 받을 가치가 없는 자료구조라는 사실을 명확하게 전달합니다. </li>
</ul>
</li>
<li><p>객체는 대화를 원하지 않고 그저 우리가 어떤 데이터를 객체 안에 넣어주거나 다시 꺼내주기를 원할 뿐입니다.
<img src="https://velog.velcdn.com/images/hye_b/post/3314ced3-8ee8-4b16-8f0a-61bb28be84f0/image.png" alt=""></p>
</li>
<li><p>getDollars()는 &quot;데이터 중에 dollars를 찾은 후 반환하세요&quot;</p>
</li>
<li><p>dollars()는 &quot;얼마나 많은 달러가 필요한가요?&quot; 객체를 데이터의 저장소로 취급하지 않고, 객체를 존중합니다. </p>
<blockquote>
<p>앞서 말한 팀원들과 나눴던 대화에서도 나왔던 얘기이다. 메서드 명을 변경하는 걸로 간다면 눈가리고 아웅 아니냐? 라는 얘기를 나눴었는데, 이 예시를 보니까 조금 이해가 간다. getDollars()는 너가 가지고 있는 dollars 필드의 값을 반환해라. 인데 dollars()라는 네이밍은 해당 객체에 dollars라는 필드가 있는지 알 수 없다. 즉 내부 구조에 대해서는 노출하지 않고 있다. 네이밍에 관련된 부분은 이제 이해를 했는데 앞의 3.5.2에서는 애초에 해당 메서드 자체가 잘못된 패턴이라고 말을 했던게 아닌가..? 헷갈린다.</p>
</blockquote>
</li>
</ul>
<h3 id="36-부-생성자-밖에서는-new를-사용하지-마세요">3.6 부 생성자 밖에서는 new를 사용하지 마세요</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/fe427a56-118a-4e6a-9e5e-c97559832779/image.png" alt=""></p>
<ul>
<li>위의 코드는 의존성에 문제가 있는 코드의 전형적인 모습을 잘 보여주고 있습니다.</li>
<li>euro() 메서드 안에서는 new 연산자를 이용해 Exchange 인스턴스를 생성하고 있습니다.<ul>
<li>문제를 일으킨 범인의 이름은 &#39;하드코딩된 의존성&#39; 입니다.</li>
<li>Cash 클래스는 Exchange 클래스에 직접 연결되어 있기 때문에, 의존성을 끊기 위해서는 Cash 클래스의 내부 코드를 변경할 수 밖에 없습니다. </li>
</ul>
</li>
<li>Cash 클래스의 소스 코드가 없는 상황에서 이 클래스를 사용하는 경우<ul>
<li>라이브러리는 바이너리 형태로만 존재하고, 우리는 이 라이브러리를 사용해야만 합니다.</li>
</ul>
</li>
<li>Cash를 사용하는 코드 부분을 보면 테스트를 실행할 때마다 매번 뉴욕 증권 거래소서버와 네트워크 통신이 발생합니다.<ul>
<li>저는 five.euro()의 내부 동작에는 전혀 관심이 없고 실행 결과만이 필요합니다.</li>
<li>현재 설계에서는 Cash가 NYSE 서버와 통신하지 않게 만들 수 없습니다.
=&gt; Cash와 Exchange간의 연결을 끊을 수 없습니다.</li>
<li>결합을 끊기 위해서는 Cash의 소스 코드를 수정해야만하며, 클래스가 작다면 큰 문제가 아니지만 더 큰 규모에서는 하드 코딩된 의존성이 소프트웨어를 테스트하고 유지보수하기 어렵게 만듭니다. <h3 id="문제의-근본-원인은-new-연산자-입니다">문제의 근본 원인은 new 연산자 입니다.</h3>
</li>
</ul>
</li>
<li>객체들이 언제 어디서나 다른 객체를 인스턴스화할 수 있도록 허용해 놓고, 정작 객체들이 마음대로 생성하려고 하면 못 마땅해하는 이유는 무엇일까요</li>
<li>Cash가 Exchange의 인스턴스를 직접 생성한 부분이 문제입니다.</li>
<li>만약 new 연산자를 사용할 수 없도록 금지 했다면? 새로운 객체를 생성자의 인자로 전 받아 private 프로퍼티 안에 캡슐화할 수 밖에 없을 것입니다. <h3 id="수정한-코드">수정한 코드</h3>
<img src="https://velog.velcdn.com/images/hye_b/post/bfe9f4b3-9b4a-4b18-a704-44c5399f08a2/image.png" alt=""></li>
<li>수정한 코드에서는 생성자의 두 번째 인자에 Exchange 인스턴스를 전달해야합니다.</li>
<li>Exchange 인스턴스를 직접 생성할 수 없고 오직 생성자를 통해 제공된 Exchange와 협력할 수 있습니다.</li>
<li>의존성을 제어하는 주체가 Cash가 아니라 우리 자신입니다.</li>
<li>Cash는 USD를 EUR로 변환하는데 필요한 환율을 얻을 위치를 직접 결정하지 않고 우리의 결정에 의지하고, 우리가 제공하는 객체와 협력합니다.</li>
<li>즉, 객체가 필요한 의존성을 직접 생성하는 대신 우리가 생성자를 통해 의존성을 주입합니다.</li>
</ul>
<h3 id="어떤-객체라도-훌륭하게-설계할-수-있는-간단한-규칙">어떤 객체라도 훌륭하게 설계할 수 있는 간단한 규칙</h3>
<ul>
<li>부 생성자를 제외한 어떤 곳에서도 NEW를 사용하지마세요.</li>
<li>객체들은 상호간에 충분히 분리되고 테스트 용이성과 유지보수성을 크게 향상시킬 수 있습니다. <blockquote>
<p>이번 주제에 동의합니다. new 연산자를 통해서 하드코딩 하게된다면 위에서 말했듯이 의존성을 끊기 위해서는 클래스 내부 코드가 변경되어야하는데 OOP와 맞지 않다고 생각합니다.</p>
</blockquote>
</li>
</ul>
<h2 id="37-인트로스펙션과-캐스팅을-피하세요">3.7 인트로스펙션과 캐스팅을 피하세요</h2>
<ul>
<li>기술적으로 java의 instanceof 연산자와 Class.cast() 메서드, 다른 언어에서 동일한 기능을 수행하는 연산자들이 모두 이 범주에 포함됩니다.</li>
<li>타입 인트로스펙션은 리플렉션이라는 더 포괄적인 용어로 불리는 여러 가지 기법들 중하나입니다.</li>
<li>리플렉션 <ul>
<li>메서드, 명령어, 구문, 클래스 등을 변경할 수 있습니다. CPU가 이 요소들에 접근하기 전에 쉽고 간다한게 코드를 수정할 수 있습니다.</li>
<li>매우 강력한 기법이지만 동시에 코드를 유지보수하기 어렵게 만드는 매우 너저분한 기법입니다.</li>
<li>코드가 런타임에 다른 코드에 의해 수정된다는 사실을 항상 기억해야하며 코드를 읽기가 매우 어렵습니다.</li>
</ul>
</li>
</ul>
<h3 id="예시-코드">예시 코드</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/215d82a0-424c-42dd-b613-88e4efa0df40/image.png" alt=""></p>
<ul>
<li>Iterable의 크기를 계산합니다. 메서드는 items에 포함된 요소들에 접근하기 전에 items 객체가 size()메서드를 정의하고 있는 Collection의 인스턴스인지 확인합니다. </li>
<li>런타임에 타입을 확인하고, 타입에 따라 적절하게 행동합니다.</li>
<li>사용하기에 매우 편리하고 성능 관점에서도 최적화된 것처럼 보이지만, 사실은 매우 잘못된 방식입니다. </li>
<li>이 접근 방법은 타입에 따라 객체를 차별하기 때문에 OOP의 기본 사상을 심각하게 훼손시킵니다.</li>
<li>요청을 어떤 식으로 처리할 지 객체가 결정할 수 있도록 하는 대신, 객체를 배재한 상태에서 결정을 내리고, 이를 바탕으로 좋은 객체와 나쁜 객체를 차별합니다.</li>
<li><blockquote>
<p>사람들의 세계에서 성별, 민족 ,나이에 따라 차별하는 것과도 유사합니다.</p>
</blockquote>
<h3 id="문제">문제</h3>
</li>
<li>런타임에 객체의 타입을 조사하는 것은 클래스 사이의 결합도가 높아지기 때문에 기술적인 관점에서도 좋지 않습니다.</li>
<li>size 메서드는 Iterable 인터페이스 하나가 아니라, Iterable과 Collection이라는 두 개의 인터페이스에 의존하고 있습니다. =&gt; 의존하는 대상이 늘어날수록 결합도는 높아진다. =&gt; 유지보수성에 악영향을 끼친다.</li>
<li>메서드를 효과적으로 사용하기 위해서는 메서드의 내부 동작을 이해할  필요가 있습니다.</li>
</ul>
<h3 id="개선---오버로딩">개선 - 오버로딩</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/aab0a593-132a-4f7c-ac8a-226b649aa661/image.png" alt=""></p>
<ul>
<li>메서드 오버로딩을 사용하여 더 나은 설계를 할 수있습니다.<h3 id="가정">가정</h3>
<img src="https://velog.velcdn.com/images/hye_b/post/7cfa0a26-e652-4ede-b4d8-e816fca3d379/image.png" alt=""></li>
<li>기술적으로 두 코드는 거의 동일하게 동작합니다. 최종 결과는 items객체가 Collection이다라는 사실입니다.</li>
<li>배관공에게 저는 당신이 컴퓨터 전문가라고 가정하고 있습니다. 그러니 이컴퓨터를 수리해주세요 라고 이야기하는것과 흡사합니다. </li>
</ul>
<pre><code class="language-java">if (items instanceof Collection) {
    return ((Collection) items).size();
}</code></pre>
<ul>
<li>만약 당신이 컴퓨터 전문가이기도 하다면, 이 프린터를 고쳐주세요 라고 말하는 듯이 보입니다.</li>
<li>아무런 대책 없이 추측만으로 프린터 수리를 요구했던 앞의 예제보다는 개선 되었지만 여전히 좋지 않은 방법입니다.
=&gt; 결합도가 숨겨져 있기 때문입니다. </li>
<li>다음에 새로운 배관공을 파견하려고 할 때, 회사는 여러분이 프린터 수리에 추가 금액을 지불하는다는 사실을 기억하고 있기 때문에 배고나공인 동시에 컴퓨터 전문가인 사람을 찾으려고 시도할 것입니다. 여러분과 수도 배관회사 사이에 체결된 계약은  싱크대 수리와 관련이 있지만 실제로는 배관공이 프린터도 수리하고 있는 것입니다. </li>
<li>나중에 수도배관회사를 바꾸기로 결정한다면 여러분은 싱크대와 프린터를 함께 수리할 수 있는 사람을 다시 요청해야합니다. 이 지식은 계약서 어디에도 명시적으로 문서화되어 있지 않습니다. </li>
<li>방문한 객체에 대한 기대를 문서에 명시적으로 기록하지 않은 채로 외부에 노출해버린것입니다. </li>
<li>어떤 클라이언트는 여러분이 기대하는 바를 학습한 후 더 적절한 객체를 제공하겠지만 어떤 클라이언트는 그럴 수 없을 것입니다.</li>
</ul>
<h3 id="정리">정리</h3>
<ul>
<li>instansceof연산자를 사용하거나 클래스를 캐스팅하는 일은 안티패턴이기 때문에 사용해서는 안됩니다.</li>
<li>Java를 포함한 대부분의 OOP언어에서 리플렉션과 함께 이런 기능들을 제공하고 있지만 소프트웨어에는 아무런 도움도 되지 않습니다.</li>
</ul>
<blockquote>
<p>배관공 예시가 이번 주제를 이해하는데 많은 도움이 되었다. 타입 캐스팅은 가능하니까 사용했던거였는데 다른 역할을 기대하고 있었다는 점을 생각하지 못했었다. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective Java] 아이템 22 - 인터페이스는 타입을 정의하는 용도로만 사용하라]]></title>
            <link>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-22-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%8A%94-%ED%83%80%EC%9E%85%EC%9D%84-%EC%A0%95%EC%9D%98%ED%95%98%EB%8A%94-%EC%9A%A9%EB%8F%84%EB%A1%9C%EB%A7%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-22-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%8A%94-%ED%83%80%EC%9E%85%EC%9D%84-%EC%A0%95%EC%9D%98%ED%95%98%EB%8A%94-%EC%9A%A9%EB%8F%84%EB%A1%9C%EB%A7%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%9D%BC</guid>
            <pubDate>Tue, 21 Jun 2022 07:55:55 GMT</pubDate>
            <description><![CDATA[<h2 id="아이템-22---인터페이스는-타입을-정의하는-용도로만-사용하라">아이템 22 - 인터페이스는 타입을 정의하는 용도로만 사용하라</h2>
<h3 id="인터페이스의-용도">인터페이스의 용도</h3>
<ul>
<li>클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에 얘기해주는 것 </li>
<li>인터페이스는 오직 위의 용도로만 사용해야한다.</li>
</ul>
<h3 id="상수-인터페이스">상수 인터페이스</h3>
<ul>
<li>메서드 없이 상수를 뜻하는 satatic final 필드로만 가득 찬 인터페이스</li>
<li>이 상수들을 사용하려는 클래스에서는 정규화된 이름을 쓰는 걸 피하고자 그 인터페이스를 구현하곤 한다.</li>
</ul>
<h3 id="상수-인터페이스-안티패턴">상수 인터페이스 안티패턴</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/28f81546-386b-4618-baae-b45800ae8c62/image.png" alt=""></p>
<ul>
<li>위의 사진은 상수 인터페이스 안티패턴으로 인터페이스를 잘못 사용한 예다.</li>
<li>클래스 내부에서 사용하는 상수는 외부 인터페이스가 아니라 내부 구현에 해당한다.</li>
<li>따라서 상수 인터페이스를 구현하는 것은 내부 구현을 클래스의 API로 노출하는 행위이다.
=&gt; 사용자에게 혼란을 줄 수 있고 클라이언트 코드가 내부 구현에 해당하는 이 상수들에 종속되게 한다.</li>
</ul>
<h3 id="자바의-상수-인터페이스-안티-패턴의-예시">자바의 상수 인터페이스 안티 패턴의 예시</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/52326b9f-ba00-487e-af16-ca988c2f0437/image.png" alt=""></p>
<h3 id="상수를-공개할-목적이라면-더-합당한-선택지">상수를 공개할 목적이라면 더 합당한 선택지</h3>
<ul>
<li>특정 클래스나 인터페이스와 강하게 연관된 상수라면 그 클래스나 인터페이스 자체에 추가해야한다.<ul>
<li>모든 숫자 기본 타입의 박싱 클래스가 대표적으로 Integer와 Double에 선언된 MIN_VALUE와 MAX_VALUE상수가 이런 예다.</li>
</ul>
</li>
<li>열거 타입으로 나타내기 적합한 상수라면 열거 타입으로 만들어 공개하면 된다.</li>
<li>인스턴스화할 수 없는 유틸리티 클래스에 담아 공개하자.</li>
</ul>
<h3 id="physicalconstants의-유틸리티-클래스-버전">PhysicalConstants의 유틸리티 클래스 버전</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/84752a29-af76-4d9b-bb65-d8b140ca3c5d/image.png" alt=""></p>
<ul>
<li>숫자 리터럴의 _ 에 주목하자<ul>
<li>자바 7부터 허용되는 밑줄은 숫자 리터럴의 값에는 아무런 영향을 주지 않으면서 읽기 편하게 해주다.</li>
<li>고정소수점 수든 부동소수점 수든 5자리 이상이라면 밑줄을 사용하는걸 고려하자.</li>
<li>십진수 리터럴도 밑줄을 사용해 세 자릿씩 묶어주는 것이 좋다.</li>
</ul>
</li>
<li>정적 임포트를하여 클래스 이름은 생략할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective Java] 아이템 21 - 인터페이스는 구현하는 쪽을 생각해 설계하라]]></title>
            <link>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-21-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%8A%94-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EC%AA%BD%EC%9D%84-%EC%83%9D%EA%B0%81%ED%95%B4-%EC%84%A4%EA%B3%84%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-21-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%8A%94-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EC%AA%BD%EC%9D%84-%EC%83%9D%EA%B0%81%ED%95%B4-%EC%84%A4%EA%B3%84%ED%95%98%EB%9D%BC</guid>
            <pubDate>Tue, 21 Jun 2022 07:23:47 GMT</pubDate>
            <description><![CDATA[<h2 id="아이템-21--인터페이스는-구현하는-쪽을-생각해-설계하라">아이템 21 : 인터페이스는 구현하는 쪽을 생각해 설계하라</h2>
<h3 id="디폴트-메서드">디폴트 메서드</h3>
<ul>
<li>자바 8에서 부터 기존 인터페이스에 메서드를 추가할 수 있게 되었다.</li>
<li>인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다.</li>
<li>하지만 모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없다.</li>
<li>구현 클래스에 대해 아무것도 모른채 합의 없이 무작정 삽입될 뿐이다.</li>
<li>생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어려운 법이다. </li>
</ul>
<h3 id="removeif">removeIf</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/e9b2d3b8-e76b-4e37-801e-bc1c4574e7c0/image.png" alt=""></p>
<ul>
<li>주어진 predicate가 true를 반환하는 모든 웟노를 제거하는 메서드</li>
<li>아파치의 SynchronizedCollection 클래스는 지금도 활발히 관리되고 있지만, 책을 쓰는 시점엔 removeIf 메서드를 재정의하지 않고 있따.</li>
<li>이 클래스를 자바 8과 함께 사용한다면 모든 메서드 호출을 알아서 동기화해주지 못한다.</li>
</ul>
<h3 id="예방-방법">예방 방법</h3>
<ul>
<li>구현한 인터페이스의 디폴트 메서드를 재정의하고, 다른 메서드에서는 디폴트 메서드를 호출하기 전에 필요한 작업을 수행하도록 했다.</li>
<li>SynchronizedCollection이 반환하는 package-private 클래스들은 removeIf를 재정의하고, 이를 호출하는 메서드들은 디폴트 구현을 호출하기 전에 동기화를 하도록 했다.</li>
<li>하지만 자바 플랫폼에 속하지 않은 제3의 기족 컬렉션 구현체들은 이런 언어 차원의 인터페이스 변화에 발맞춰 수정도리 기회가 없었으며 일부는 여전히 수정되지 않고 있다.</li>
</ul>
<h3 id="default-메서드의-런타임-오류">default 메서드의 런타임 오류</h3>
<ul>
<li>default 메서드는 기존 구현체에 런타임 오류를 일으킬 수 있다.</li>
<li>자바 8은 컬렉션 인터페이스에 많은 default 메서드를 추가했고, 그 결과 기존에 짜여진 많은 자바 코드가 영향을 받았다.</li>
<li>기존 인터페이스에 default 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 한다.</li>
<li>추가하려는 default 메서드가 기존 구현체들과 충돌하지는 않을지 심사숙고해야 함은 당연하다.</li>
</ul>
<h3 id="새로운-인터페이스는">새로운 인터페이스는?</h3>
<ul>
<li>새로운 인터페이스를 만드는 경우라면 표준적인 메서드 구현을 제공하는 데 아주 유용한 수단이다.</li>
<li>해당 인터페이스를 더 쉽게 구현해 활용할 수 있게끔 해준다.</li>
</ul>
<h3 id="정리">정리</h3>
<ul>
<li>default 메서드는 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아님을 명심해야 한다.
=&gt; 이런 형태로 인터페이스를 변경하면 반드시 기존 클라이언트를 망가뜨리게 된다.</li>
<li>default 메서드라는 도구가 생겨도 인터페이스를 설계 할 때는 여전히 세심한 주의를 기울여야 한다.</li>
<li>새로운 인터페이스라면 릴리스 전에 반드시 테스트를 거쳐야한다.<ul>
<li>서로 다른 방식으로 최소한 3가지는 구현해봐야한다.</li>
<li>다양한 작업에 활용하는 클아이언트도 여러 개 만들어봐야 한다.</li>
</ul>
</li>
<li>인터페이스를 릴리스한 후라도 결함을 수정하는 게 가능한 경우도 있겠지만, 절대 그 가능성에 기대서는 안 된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] 비관적 락과 낙관적 락]]></title>
            <link>https://velog.io/@hye_b/JPA-%EB%B9%84%EA%B4%80%EC%A0%81-%EB%9D%BD%EA%B3%BC-%EB%82%99%EA%B4%80%EC%A0%81-%EB%9D%BD</link>
            <guid>https://velog.io/@hye_b/JPA-%EB%B9%84%EA%B4%80%EC%A0%81-%EB%9D%BD%EA%B3%BC-%EB%82%99%EA%B4%80%EC%A0%81-%EB%9D%BD</guid>
            <pubDate>Sat, 18 Jun 2022 10:14:20 GMT</pubDate>
            <description><![CDATA[<h2 id="jpa---비관적-락과-낙관적-락">JPA - 비관적 락과 낙관적 락</h2>
<h2 id="📃-overview">📃 Overview</h2>
<ul>
<li>JPA의 영속성 컨텍스트를 적절히 활용하면 DB 트랜잭션이 READ COMMITTED 격리 수준이어도 애플리케이션 레벨에서 REPETABLE READ가 가능하다. </li>
<li>JPA는 데이터베이스 트랜잭션 격리 수준을 READ COMMITTED 정도로 가정한다.</li>
<li><strong>일부 로직에 더 높은 격리 수준이 필요하다면 ?</strong> =&gt; 낙관적 락과 비관적 락을 사용하자</li>
</ul>
<h2 id="👊-1-비관적-락">👊 1. 비관적 락</h2>
<ul>
<li><strong>트랜잭션의 충돌이 발생한다고 가정하고 우선 락을 걸고 보는 방법</strong></li>
<li><strong>데이터베이스가 제공하는 락 기능</strong>을 사용한다. </li>
<li>주로 SQL 쿼리에 <strong>SELECT FOR UPDATE</strong> 구문을 사용하면서 시작하고 버전 정보는 사용하지 않는다.</li>
<li><strong>데이터를 수정하는 즉시 트랜잭션 충돌을 감지할 수 있다.</strong></li>
</ul>
<h2 id="✌-2-낙관적-락">✌ 2. 낙관적 락</h2>
<h3 id="21-낙관적-락-이란">2.1 낙관적 락 이란?</h3>
<ul>
<li><strong>트랜잭션 대부분은 충돌이 발생하지 않는다고 낙관적으로 가정하는 방법</strong></li>
<li>데이터베이스가 제공하는 락 기능이 아닌 <strong>JPA가 제공하는 버전 관리 기능을 사용</strong>
=&gt; *<em>애플리케이션이 제공하는 락 *</em></li>
<li><strong>트랜잭션을 커밋하기 전까지는 트랜잭션의 충돌을 알 수 없다.</strong></li>
</ul>
<h3 id="22-두-번의-갱신-분실-문제">2.2 두 번의 갱신 분실 문제</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/79619e26-372c-4238-99b1-bed013e86c80/image.png" alt=""></p>
<ul>
<li><strong>데이터베이스 트랜잭션 범위를 넘어서는 문제</strong></li>
<li>사용자 A와 B가 동시에 제목이 같은 내용을 수정할 때, 둘이 동시에 수정 화면을 열어서 내용을 수정하는 중에 사용자 A가 먼저 수정완료 버튼을 누르고 잠시 후에 사용자 B가 수정 완료 버튼을 눌렀다.</li>
<li>이때, 사용자 A의 수정 사항은 사라지고 <strong>나중에 완료한 사용자 B의 수정사항만 남게 되는 현상</strong>을 두 번의 갱신 분실 문제라고 한다.</li>
<li><strong>트랜잭션만으로는 문제를 해결할 수 없다.</strong><h3 id="23-해결-방법">2.3 해결 방법</h3>
</li>
<li><strong>마지막 커밋만 인정하기</strong> : 사용자 A의 내용은 무시하고 마지막에 커밋한 사용자 B의 내용만 인정한다.<ul>
<li>기본으로 사용된다. </li>
</ul>
</li>
<li><strong>최초 커밋만 인정하기</strong> : 사용자 A가 이미 수정을 완료했으므로 사용자 B가 수정을 완료할 때 오류가 발생한다. <ul>
<li>상황에 따라 더 합리적일 수 있다. JPA의 버전 관리 기능을 사용하면 손쉽게 구현할 수 있다.</li>
</ul>
</li>
<li><strong>충돌하는 갱신 내용 병합하기</strong> : 사용자 A와 사용자 B의 수정사항을 병합한다. </li>
</ul>
<h2 id="💎-3-jpa의-버전-관리-기능">💎 3. JPA의 버전 관리 기능</h2>
<h3 id="31-version">3.1 @Version</h3>
<pre><code class="language-java">@Entity
public class Board {
    @Id
    private String id;
    private String title;

    @Version
    private Integer version;
}</code></pre>
<ul>
<li>적용 가능 타입<ul>
<li><strong>Long (long)</strong></li>
<li><strong>Integer (int)</strong></li>
<li><strong>Short (short)</strong></li>
<li><strong>Timestamp</strong></li>
</ul>
</li>
<li>엔티티에 버전 관리용 필드를 하나 추가하고** @Version**을 붙이면 된다.</li>
<li>엔티티를 수정할 때 마다 버전이 <strong>하나씩 자동으로 증가한다.</strong></li>
<li>엔티티를 수정할 때 <strong>조회 시점의 버전과 수정 시점의 버전이 다르면 예외가 발생한다.</strong></li>
</ul>
<h3 id="32-발생하는-예외">3.2 발생하는 예외</h3>
<ul>
<li><strong>OptimisticLockException</strong> (JPA 예외)</li>
<li><strong>StaleObjectStateException</strong> (하이버네이트 예외)</li>
<li><strong>ObjectOptimisticLockingFailureException</strong> (스프링 예외 추상화)</li>
</ul>
<h3 id="33-최초-커밋만-인정하기">3.3 최초 커밋만 인정하기</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/42b76db5-5bbc-4ca3-94ca-ca7b70eca70f/image.png" alt=""></p>
<pre><code class="language-java">//트랜잭션 1 조회 title = &quot;제목a&quot;,  version = 1
Board board = em.find(Board.class, id);
//트랜잭션 2에서 해당 게시물을 수정해서 title=&quot;제목c&quot;, version=2로 증가
board.setTitle(&quot;제목B&quot;);

em.save(board);
tx.commit(); // 예외 발생, 데이터베이스의 version = 2, 엔티티의 version = 1;</code></pre>
<ul>
<li>*<em>버전 정보를 사용하면 최초 커밋만 인정하기가 적용된다. *</em></li>
</ul>
<h3 id="34-jpa가-버전-정보-비교-방법">3.4 JPA가 버전 정보 비교 방법</h3>
<pre><code class="language-sql">UPDATE BOARD
SET
    TITLE=?,
    VERSION=? (version 1 증가)
WHERE 
    ID=?
    AND VERSION=? (버전 비교, 즉 현재의 버전과 같은 버전이 있는지) </code></pre>
<ul>
<li><strong>엔티티를 수정</strong>하고 트랜잭션을 커밋하면 영속성 컨텍스트를 플러시 하면서 <strong>update 쿼리를 실행한다.</strong></li>
<li>버전을 사용하는 엔티티면 검색 조건에 *<em>엔티티의 버전 정보를 추가함과 동시에 버전을 1 증가시킨다. *</em>
=&gt; 버전은 엔티티의 값을 변경하면 증가한다.</li>
<li>연관관계 필드는 외래 키를 관리하는 연*<em>관관계의 주인 필드를 수정할 때만 버전이 증가한다. *</em></li>
<li>버전 관리 필드는 JPA가 직접 관리하므로 <strong>개발자가 임의로 수정하면 안 된다.</strong>
=&gt; <strong>벌크 연산의 경우 버전을 무시하기 떄문에 강제로 증가 시켜야한다.</strong></li>
</ul>
<h2 id="🐾-4-jpa-락-사용">🐾 4. JPA 락 사용</h2>
<h3 id="41-락을-적용할-수-있는-위치">4.1 락을 적용할 수 있는 위치</h3>
<ul>
<li><strong>EntityManager.lock()</strong>, <strong>EntityManager.find()</strong>, <strong>EntityManager.refresh()</strong><pre><code class="language-sql">// 즉시 락 걸기
Board board = em.find(Board.class, id, LockModeType.OPTIMISTIC);
</code></pre>
</li>
</ul>
<p>// 필요할 때 걸기
Board board = em.find(Board.class, id);
...
em.lock(board, LockModeType.OPTIMISTIC);</p>
<pre><code>- **Query.setLockMode()**
```sql
Query query = em.createQuery(&quot;SELECT b FROM Borad b WHERE id = :id&quot;);
query.setParameter(&quot;id&quot;, boardId);
query.setLockMode(LockModeType.OPTIMISTIC);
query.getResultList()</code></pre><ul>
<li><p><strong>@NamedQuery</strong></p>
<pre><code class="language-sql">@NamedQuery(name=&quot;lockBoard&quot;,
query=&quot;SELECT b FROM Borad b WHERE b.id = :boardId&quot;,
lockMode = OPTIMISTIC)</code></pre>
</li>
<li><p><strong>@Lock(LockModeType.PESSIMISTIC_WRITE) JPA Repository</strong></p>
<pre><code class="language-java">@Lock(LockModeType.PESSIMISTIC_WRITE)
findBy~ </code></pre>
<h3 id="42-jpa가-제공하는-락-옵션">4.2 JPA가 제공하는 락 옵션</h3>
</li>
<li><p><strong>javax.persistence.LockModeType</strong>
<img src="https://velog.velcdn.com/images/hye_b/post/f7dd66bb-0b53-455c-b96d-f18f93a15f9a/image.png" alt=""></p>
<table>
<thead>
<tr>
<th align="center">모드</th>
<th align="center">설명</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">낙관적 락</td>
<td align="center">OPTIMISTIC</td>
<td align="center">낙관적 락을 사용한다.</td>
</tr>
<tr>
<td align="center"></td>
<td align="center">OPTIMISTIC_FORCE_INCREMENT</td>
<td align="center">낙관적 락 + 버전정보를 강제로 증가 시킨다.</td>
</tr>
<tr>
<td align="center">비관적 락</td>
<td align="center">PESSIMISTIC_READ</td>
<td align="center">읽기 잠금을 사용한다.</td>
</tr>
<tr>
<td align="center"></td>
<td align="center">PESSIMISTIC_WRITE</td>
<td align="center">쓰기 잠금을 사용한다.</td>
</tr>
<tr>
<td align="center"></td>
<td align="center">PESSIMISTIC_FORCE_INCREMENT</td>
<td align="center">비관적 락 + 버전정보를 강제로 증가시킨다.</td>
</tr>
<tr>
<td align="center">기타</td>
<td align="center">NONE</td>
<td align="center"></td>
</tr>
<tr>
<td align="center"></td>
<td align="center">READ</td>
<td align="center">OPTIMISTIC과 같다.</td>
</tr>
<tr>
<td align="center"></td>
<td align="center">WRITE</td>
<td align="center">OPTIMISTIC_FORCE_INCREMENT 와 같다.</td>
</tr>
</tbody></table>
</li>
<li><p>다크 모드 사용자를 위한 표 </p>
</li>
</ul>
<h3 id="421-none">4.2.1 NONE</h3>
<ul>
<li>락 옵션을 적용하지 않아도 엔티티에 *<em>@Version이 적용된 필드만 있으면 낙관적 락이 적용된다. *</em></li>
<li>조회한 엔티티를 수정할 때 다른 트랜잭션에 의해 변경(삭제) 되지 않아야 한다.</li>
<li><strong>조회 시점부터 수정 시점까지를 보장한다.</strong></li>
<li>엔티티를 수정할 때 버전을 체크하면서 버전을 증가하고 <strong>db의 버전 값이 현재 버전이 아니면 예외가 발생한다.</strong></li>
<li><strong>두 번의 갱신 분실 문제를 예방한다.</strong></li>
</ul>
<h2 id="✌-43-낙관적-락">✌ 4.3 낙관적 락</h2>
<ul>
<li><strong>트랜잭션 대부분은 충돌이 발생하지 않는다고 낙관적으로 가정하는 방법</strong></li>
<li>데이터베이스가 제공하는 락 기능이 아닌 <strong>JPA가 제공하는 버전 관리 기능을 사용</strong>
=&gt; *<em>애플리케이션이 제공하는 락 *</em></li>
<li><strong>트랜잭션을 커밋하기 전까지는 트랜잭션의 충돌을 알 수 없다.</strong></li>
</ul>
<h3 id="431-optimistic-read">4.3.1 OPTIMISTIC (Read)</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/ca129e5d-f7ce-4f7b-8415-2e777f6d2655/image.png" alt=""></p>
<pre><code class="language-java">//트랜잭션 1 조회 title = &quot;제목A&quot;, version = 1
Board board = em.find(Board.class, id, LockModeType.OPTIMISTIC);
// 중간에 트랜잭션 2에서 해당 게시물을 수정해서 title=&quot;제목 C&quot;, version=2로 증가
//트랜잭션 1 커밋 시점에 버전 정보 검증, 예외 발생
// db version = 2, entity version - 1
tx.commit():</code></pre>
<ul>
<li><strong>엔티티를 조회만 해도 버전을 체크한다.</strong></li>
<li><strong>한 번 조회한 엔티티는 트랜잭션을 종료할 때까지 다른 트랜잭션에서 변경하지 않음을 보장한다.</strong></li>
<li>트랜잭션을 커밋할 때 <strong>버전 정보를 조회해서(select 쿼리 사용)</strong> 현재 엔티티의 버전과 같은지 검증하고 같지 않으면 예외 발생</li>
<li><strong>DIRTY READ</strong>와 <strong>NON-REPEATABLE READ</strong>를 방지한다.</li>
</ul>
<h3 id="432-optimistic_force_increment-write">4.3.2 OPTIMISTIC_FORCE_INCREMENT (Write)</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/7a96b717-589e-4c7d-9702-15472d3adb87/image.png" alt=""></p>
<pre><code class="language-java">//트랜잭션 1 조회 title=&quot;제목a&quot;, version=1
Board board = em.find(Board.class, id, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
//트랜잭션 1 커밋 시점에 버전 강제 증가
tx.commit();</code></pre>
<ul>
<li>낙관적 락을 사용하면서 <strong>버전 정보를 강제로 증가한다.</strong></li>
<li><strong>논리적인 단위의 엔티티 묶음을 관리할 수 있다.</strong></li>
<li><strong>엔티티를 수정하지 않아도</strong> 트랜잭션을 커밋할 때 UPDATE 쿼리를 사용해서 <strong>버전 정보를 강제로 증가시킨다.</strong></li>
<li>엔티티를 수정하면 수정 시 버전 UPDATE가 발생한다. 즉, <strong>총 2번의 버전 증가가 나타날 수 있다.</strong></li>
<li><strong>강제로 버전을 증가해서 논리적인 단위의 엔티티 묶음을 버전 관리할 수 있다.</strong></li>
</ul>
<h3 id="optimistic_force_increment-사용하지-않을-때-예시">&lt;OPTIMISTIC_FORCE_INCREMENT 사용하지 않을 때 예시&gt;</h3>
<pre><code class="language-java">@Test
void test() {
    Post post = new Post();
    post.setTitle(&quot;제목&quot;);
    PostImage postImage = new PostImage();
    postImage.addPost(post);
    postRepository.save(Post);

    // Post에 새로운 PostImage를 추가하는 method 
    postService.addPostImage();

    Post foundPost = postRepository.findById(post.getId());
}</code></pre>
<blockquote>
<ol>
<li>Post와 PostImage가 <strong>일대다 양방향 연관관계</strong>이고 <strong>PostImage가 연관관계의 주인</strong>일 때 </li>
<li>단순히 Post에 PostImage만 추가하면 Post의 버전은 증가하지 않는다. </li>
<li>해당 Post는 물리적으로는 변경되지 않았지만, 논리적으로는 변경되었다. 
(3-1) Post 엔티티 PostImage 필드에 새로운 PostImage를 추가
(3-2) 연관관계의 주인이 FK 를 관리하고 있어서 Post에는 PostImage가 추가된다.
(3-3) Post Table에는 물리적인 변화가 없어서 업데이터 쿼리가 나가지 않는다.
(3-4) version 이 증가하지 않는다. </li>
<li>이 게시물의 <strong>버전도 강제로 증가하고 싶을 때</strong> 사용한다.</li>
</ol>
</blockquote>
<h2 id="🧸-44-비관적-락">🧸 4.4 비관적 락</h2>
<ul>
<li><strong>트랜잭션의 충돌이 발생한다고 가정하고 우선 락을 걸고 보는 방법</strong></li>
<li>*<em>데이터베이스가 제공하는 락 기능을 사용한다. *</em></li>
<li><strong>데이터를 수정하는 즉시 트랜잭션 충돌을 감지할 수 있다.</strong></li>
</ul>
<h3 id="441-발생하는-예외">4.4.1 발생하는 예외</h3>
<ul>
<li><strong>PessimisticLockException</strong> (JPA 예외)</li>
<li><strong>PessimisticLockingFailureException</strong> (스프링 예외 추상화)</li>
</ul>
<h3 id="442-pessimistic_write">4.4.2 PESSIMISTIC_WRITE</h3>
<ul>
<li><strong>일반적으로 사용되는 옵션</strong>으로 데이터 베이스에 <strong>쓰기 락을 걸 때 사용한다.</strong></li>
<li>데이터베이스 <strong>SELECT FOR UPDATE</strong>를 사용해서 락을 건다.</li>
<li><strong>락이 걸린 로우</strong>는 다른 트랜잭션이 수행할 수 없다.</li>
<li><strong>NON-REPEATABLE READ를 방지한다.</strong> </li>
</ul>
<h3 id="443-pessimistic_read">4.4.3 PESSIMISTIC_READ</h3>
<ul>
<li>데이터를 반복 읽기만 하고 <strong>수정하지 않는 용도로 락을 걸 때 사용한다.</strong></li>
<li><strong>일반적으로 잘 사용하지 않는다.</strong></li>
<li>데이터베이스 대부분은 방언에 의해 *<em>PESSIMISTIC_WRITE로 동작한다. *</em></li>
</ul>
<h3 id="444-pessimistic_force_increment">4.4.4 PESSIMISTIC_FORCE_INCREMENT</h3>
<ul>
<li>*<em>비관적 락중 유일하게 버전 정보를 사용한다. *</em></li>
<li>*<em>버전 정보를 강제로 증가시킨다. *</em></li>
<li>하이버네이트는 nowait를 지원하는 데이터베이스에 대해서 for update nowait옵션을 적용한다.</li>
</ul>
<h3 id="45-비관적-락과-타임아웃">4.5 비관적 락과 타임아웃</h3>
<ul>
<li><strong>비관적 락을 사용하면 락을 획득할 때까지 트랜잭션이 대기한다.</strong></li>
<li>무한정 기다릴 수는 없으므로 <strong>타임아웃 시간을 줄 수 있다.</strong></li>
</ul>
<h2 id="🤔-5-어떨-때-사용해야하는데-">🤔 5. 어떨 때 사용해야하는데 ?</h2>
<ul>
<li><p><strong>비관적 락은?</strong></p>
<ul>
<li>동시성이 떨어져 성능 저하가 있고, 읽기가 많이 이루어지는 데이터베이스에는 좋지 않다.<ul>
<li>서로 자원이 필요한 경우에, 로우 자체에 락이 걸려있어 데드락이 일어날 가능성이 있다.</li>
<li>데이터의 무결성이 중요하고, 충돌이 많이 발생하여 잦은 롤백이 있는 프로젝트에 사용하는 것이 좋다.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>낙관적 락은?</strong></p>
<ul>
<li>트랜잭션 충돌이 많아 복구 작업을 많이 해야 하는 로직이라면 좋지 않다.</li>
<li>데이터 충돌이 자주 일어나지 않을 것이라고 예상되는 시나리오에서 좋다.</li>
</ul>
</li>
</ul>
<h3 id="재고가-1개인-상품에-동시적으로-주문을-요청하는-경우">재고가 1개인 상품에 동시적으로 주문을 요청하는 경우?</h3>
<ul>
<li><p>비관적 락 : 1명의 사용자 말고는 대기를 하다가 트랜잭션 충돌 여부를 파악하게 된다. 
=&gt; 재고가 없음을 미리 알 수 있어 롤백처리가 필요없다.</p>
</li>
<li><p>낙관적 락 : 동시 요청을 순차적으로 처리 한다.
=&gt; commit을 해야 재고가 없는 걸 알 수 있고 처리한 만큼 롤백을 해줘야한다.</p>
</li>
</ul>
<h3 id="우리는">우리는?</h3>
<ul>
<li>저희 프로젝트에서는 동시 수정이 가능한 기능이 잘 떠오르지 않습니다. 그래서 낙관적 락을 사용해도 될 것 같다고 생각합니다. </li>
</ul>
<h3 id="실제-락을-실행한-예제-코드-사이트">실제 락을 실행한 예제 코드 사이트</h3>
<ul>
<li>모든 락에 대한 예시 코드가 잘 작성 되어 있습니다. </li>
<li><a href="https://ojt90902.tistory.com/723#rp">정리 tistory</a> </li>
</ul>
<hr>
<h2 id="프로젝트에-lock-적용하기-비관적-락">프로젝트에 LOCK 적용하기 (비관적 락)</h2>
<blockquote>
<p>우리 프로젝트에는 락을 적용할만한 부분이 없습니다. 하지만 락을 경험해보기 위해 일단 적용해봅니다 ! Post Update 부분에 적용을 할 것입니다
테스트 방법은 postman을 사용하여 Lock을 사용한 update api 실행 후 기존의 update메서드를 실행합니다.(테스트 진행 코드에는 postService에 Thread.sleep 을 시켰습니다.)</p>
</blockquote>
<h3 id="postservice의-update-메서드-입니다">PostService의 update 메서드 입니다.</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/fe4a8bc7-07e2-4114-9add-cf4cfaf33600/image.png" alt=""></p>
<ul>
<li>기존의 update메서드와 비교하면 repository의 메서드만 다릅니다.</li>
</ul>
<hr>
<h2 id="pessimistic_write">PESSIMISTIC_WRITE</h2>
<h3 id="1-postrepository-에-pessimistic_write-설정">1 PostRepository 에 PESSIMISTIC_WRITE 설정</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/61f09dbc-ec84-48f0-85c5-eec924096b15/image.png" alt=""></p>
<ul>
<li>비관적 락 중 PESSIMISTIC_WRITE 옵션을 줬습니다.</li>
</ul>
<h3 id="2-lock이-설정된-update-api-실행-후">2. Lock이 설정된 update API 실행 후</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/cccf7536-2d8a-4b8c-8fc7-186b4066b611/image.png" alt=""></p>
<ul>
<li>lock이 걸린 update API를 실행합니다.</li>
<li>테스트시 postService 코드에는 Thread.sleep(60 * 1000); 이 들어가 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_b/post/7f032519-687a-49a6-bd30-4e2866aa7a8b/image.png" alt=""></p>
<h3 id="22-기존의-update-api">2.2 기존의 update API</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/313e303b-008e-4f31-9d5b-d83707cd98eb/image.png" alt=""></p>
<ul>
<li>이후 Lock 이 걸려있지 않은 update API 를 실행합니다.</li>
<li>실행하면 Request요청이 Thread.sleep이 끝날때까지 가게됩니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_b/post/ed09a66d-25a8-4cd7-93ba-ce65372ff400/image.png" alt=""></p>
<h3 id="3-threadsleep-이-끝나면">3. Thread.sleep 이 끝나면?</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/d5823c1d-166b-49a7-9b1d-de8667b491b2/image.png" alt=""></p>
<ul>
<li><code>PessimisticLockingFailureException</code> 이 터지게 됩니다.</li>
<li>해당 예외는 Spring에서 터지는 트랜잭션 충돌 예외입니다.</li>
<li>LOCK이 잘 걸려있음을 알 수 있습니다. </li>
</ul>
<hr>
<h2 id="pessimistic_read">PESSIMISTIC_READ</h2>
<h3 id="1-postrepository-에-pessimistic_read-설정">1. PostRepository 에 PESSIMISTIC_READ 설정</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/c005e461-f031-45f3-88f3-745c38c8d8e3/image.png" alt=""></p>
<ul>
<li>이번에는 PESSIMISTIC_READ 설정을 줬습니다. </li>
</ul>
<h3 id="2-lock이-걸린-update-api-실행">2. LOCK이 걸린 UPDATE API 실행</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/3505dabf-5523-4d1c-b23e-9be2d8825ad9/image.png" alt=""></p>
<ul>
<li>select for share 쿼리가 나갑니다.</li>
</ul>
<h3 id="3-기존의-update-api-실행">3. 기존의 UPDATE API 실행</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/5d530e5a-a611-4395-93d9-ade1576c81e7/image.png" alt=""></p>
<ul>
<li>select 쿼리가 나가게됩니다.</li>
</ul>
<h3 id="4-threadsleep-이-끝나면">4. Thread.sleep 이 끝나면</h3>
<p><img src="https://velog.velcdn.com/images/hye_b/post/daf05c12-59b9-47d7-ab17-3d95d41ace02/image.png" alt=""></p>
<ul>
<li>아까와 같은 에러가 나게됩니다.</li>
</ul>
<hr>
<h3 id="select-for-update-가-뭔데-">SELECT FOR UPDATE 가 뭔데 ?</h3>
<ul>
<li><strong>쓰기 잠금 (내가 update하기 전에 거는 잠금)</strong>을 설정하여 다른 트랜잭션에서는 그 레코드를 변경하는 것뿐만 아니라 <strong>읽기도 수행할 수 없습니다.</strong></li>
</ul>
<h3 id="select-for-share-는-뭔데-">SELECT FOR SHARE 는 뭔데 ?</h3>
<ul>
<li>SELECT 된 레코드에 대해 <strong>읽기 잠금 (내가 select 하기전에 거는 잠금)</strong>을 설정하고 다른 세션에서 해당 레코드를 변경하지 못하게 합니다.</li>
<li><strong>다른 세션에서 잠금이 걸린 레코드를 읽는 것은 가능합니다.</strong></li>
</ul>
<h3 id="근데-왜-select-for-update에서-기존의-update-api를-실행하면-select-쿼리가-나가">근데 왜 SELECT FOR UPDATE에서 기존의 update API를 실행하면 select 쿼리가 나가?</h3>
<ul>
<li>FOR UPDATE나 FOR SHARE절을 가지지 않는 SELECT쿼리는 <strong>INNO DB 스토리 엔진을 사용하는 테이블에서는 잠금없는 읽기가 지원</strong>되기 됩니다.</li>
<li>이런 이유 때문에 SELECT FOR UPDATE 쿼리로 잠겨진 상태라 해도 단순 SELECT쿼리는 아무런 대기 없이 실행됩니다.</li>
<li>현재 MYSQL 5.5 버전부터 INNODB가 default로 사용됩니다. </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[엘레강트 오브젝트] 3장 - Employment (1) ]]></title>
            <link>https://velog.io/@hye_b/%EC%97%98%EB%A0%88%EA%B0%95%ED%8A%B8-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-3%EC%9E%A5-Employment-1</link>
            <guid>https://velog.io/@hye_b/%EC%97%98%EB%A0%88%EA%B0%95%ED%8A%B8-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-3%EC%9E%A5-Employment-1</guid>
            <pubDate>Fri, 17 Jun 2022 01:03:51 GMT</pubDate>
            <description><![CDATA[<h2 id="3장---employment">3장 - Employment</h2>
<h2 id="31-5개-이하의-public-메서드만-노출하세요">3.1 5개 이하의 public 메서드만 노출하세요</h2>
<ul>
<li>가장 우아하고, 유지보수가 가능하고, 응집력이 높으면서, 테스트하기도 용이한 객체는 작은 객체입니다. </li>
<li>클래스의 크기를 정하는 기준으로 public, protected 메서드의 개수를 사용하고, 5개를 기준으로 생각하세요.
=&gt; 지극히 개인적인 의견입니다. </li>
<li>클래스가 작으면 메서드와 프로퍼티가 더 가까이 있을 수 있기 때문에 응집도가 높아집니다. <blockquote>
<p>getter 포함인지 궁금한데 포함이겠지? 메서드의 개수를 5개로 유지하려면 하나의 클래스 안에서도 여러개의 객체를 만들어야 할 것 같다. 작은 클래스에 대한 장점은 다 동의한다. 하지만 현재 프로젝트에 반영할 수 있을까? 필드 5개까지는 해보겠지만, 메서드 5개가 가능할까? 의문이 든다. </p>
</blockquote>
</li>
</ul>
<h2 id="32-정적-메서드를-사용하지-마세요">3.2 정적 메서드를 사용하지 마세요</h2>
<ul>
<li>정적 메서드는 OOP에 NULL을 도입한 것 이상으로 커다란 실수입니다.</li>
<li>OOP에 static을 도입한 사람이 누구인지는 알 수 없지만 정적 메서드는 순수한 악입니다. </li>
<li>정적 메서드는 객체 생성과 가비지 컬렉션에 신경 쓸 필요가 없습니다.</li>
<li>유틸클래스의 장점<ul>
<li>많은 메서드를 모아 놓고 쉽고 간편하게 사용할 수 있습니다. </li>
<li>사용성 측면에서도 매우 직관적입니다.
=&gt; 하지만 문맥과 상관없이 정적 메서드를 사용하고 있는지 여부는 OOP를 제대로 이해하지못한 형편없는 프로그래머를 구별하기 위해 사용할 수 있는 최적의 지표입니다. </li>
</ul>
</li>
</ul>
<h3 id="321-객체-대-컴퓨터-사고">3.2.1 객체 대 컴퓨터 사고</h3>
<ul>
<li>컴퓨터가 우리를 위해 일하고 우리는 명시적인 명령어를 제공해서 컴퓨터에게 지시를 내린다는 것입니다. </li>
<li>컴퓨터는 우리가 명령어를 제공해줄 것이라고 기대하고, 제공된 명령어를 하나씩 순차적으로 실행합니다. </li>
<li>새로운 무엇이 필요하다면 그 무엇을 정의합니다. </li>
<li>함수형, 논리형, 객체지향 프로그래밍이 절차적 프로그래밍과 차별화되는 점이 바로 &#39;is a&#39; 입니다. </li>
<li>정적 메서드는 OOP와 아무런 상관이 없으며, 객체 지향 언어의 문법을 이용해서 절차적인 코드를 작성하도록 부추길 뿐입니다.</li>
</ul>
<h3 id="322-선언형-스타일-대-명령형-스타일">3.2.2 선언형 스타일 대 명령형 스타일</h3>
<ul>
<li>명령형 프로그래밍에서는 프로그램의 상태를 변경하는 문장을 사용해서 계산 방식을 서술합니다. </li>
<li>선언형 프로그래밍에서는 제어 흐름을 서술하지 않고 계산 로직을 표현합니다. </li>
<li>선언형 프로그래밍의 장점<ul>
<li>선언형 방식은 더 빠릅니다. </li>
<li>다형성 - 코드 블록 사이의 의존성을 끊을 수 있는 능력 </li>
<li>표현력 - 선언형 방식은 결과를 이야기하는데 반해, 명령형 방식은 수행 가능한 한가지 방법을 이야기합니다.</li>
<li>응집도 - 시간적인 결합 문제를 제거할 수 있으며, 따라서 유지보수성을 개선할 수 있습니다.</li>
</ul>
</li>
</ul>
<h3 id="323-유틸리티-클래스">3.2.3 유틸리티 클래스</h3>
<ul>
<li>유틸리티 클래스란 편의를 위해 다른 메서드들이 사용하는 정적 메서드들을 모아 놓은 정적 메서드들의 컬렉션이라고 부릅니다.</li>
<li>클래스를 객체의 팩토리라고 정의했는데 유틸리티 클래스는 어떤 것의 팩토리가 아니기 때문에 진짜 클래스라고 부를 수 없습니다. </li>
<li>유틸리티 클래스는 끔찍한 안티 패턴입니다. 가까이하지 마세요. </li>
</ul>
<h3 id="324-싱글톤-패턴">3.2.4 싱글톤 패턴</h3>
<ul>
<li>싱글톤 패턴은 정적 메서드 대신 사용할 수 있는 매우 유명한 개념입니다. </li>
<li>싱글톤은 유명한 디자인 패턴이지만 사실 끔찍한 안티 패턴입니다. </li>
<li>싱글톤은 캡슐화할 수 있다. </li>
<li>전역 변수는 순수하게 절차적인 언어를 위해서 존재하는 장치 입니다. 캡슐화를 완벽하게 위반하기 때문에 해롭습니다. </li>
<li>싱글톤은 객체지향 패러다임을 잘못 사용한 예이며, 오직 정적 메서드가 있었기 때문에 탄생할 수 있었습니다.</li>
</ul>
<h3 id="325-함수형-프로그램밍">3.2.5 함수형 프로그램밍</h3>
<ul>
<li>객체의 크기가 작고, 상태가 변하지 않으며 정적 메서드도 포함하지 않는다면, 함수형 프로그래밍을 활용하는 편이 낫지 않느냐? </li>
<li>함수형 프로그래밍보다 객체지향프로그래밍의 표현력이 더 뛰어나고 강력하다. </li>
<li>객체지향 프로그래밍에서는 객체와 메서드를 조합할 수 있다.</li>
<li>이상적인 객체지향 프로그래밍언어에는 클래스와 함께 함수가 포함되어야 합니다. 하나의 출구만 포함하는 순수한 함수형 프로그래밍 패러다임에 기반하는 진정한 함수를 포함해야 합니다.</li>
</ul>
<h3 id="326-조합-가능한-데코레이터">3.2.6 조합 가능한 데코레이터</h3>
<ul>
<li>제가 새로 고안한 용어입니다. 다른 객체를 감싸는 객체일 뿐입니다. </li>
<li>다중계층 구조로 구성하기 시작하면 매우 깔끔하면서도 객체지향적입니다. </li>
<li>객체지향에는 if, for, switch, while 연산자는 필요 없습니다.  If, For, Switch, While 클래스가 필요할 뿐입니다.</li>
<li>정적 메서드는 조합이 불가능합니다. 합성이라는 아이디어와 대치됩니다. static 키워드를 사용해서는 안됩니다.</li>
</ul>
<blockquote>
<p>   선언형 방식이 좋다는 말은 오래전 부터 들었고 장점에 동의합니다. 하지만 적응하고 눈에 익는 시간이 필요한 것 같습니다. 이렇게 해 ! 가 아니라 이건 무엇이야? 라는 말이 이해하는데 많이 도움이 되었다. 연산자는 필요없고 클래스만 존재한다는 발상이 신선했습니다. 데코레이터를 사용하니 확실히 가독성이 더 좋았습니다. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[엘레강트 오브젝트] 2장 - Education (2)]]></title>
            <link>https://velog.io/@hye_b/%EC%97%98%EB%A0%88%EA%B0%95%ED%8A%B8-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-2%EC%9E%A5-Education-2</link>
            <guid>https://velog.io/@hye_b/%EC%97%98%EB%A0%88%EA%B0%95%ED%8A%B8-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-2%EC%9E%A5-Education-2</guid>
            <pubDate>Thu, 16 Jun 2022 14:04:35 GMT</pubDate>
            <description><![CDATA[<h2 id="엘레강트-오브젝트-2장---education">엘레강트 오브젝트 2장 - Education</h2>
<h2 id="27-문서를-작성하는-대신-테스트를-만드세요">2.7 문서를 작성하는 대신 테스트를 만드세요</h2>
<pre><code class="language-java">Employee jeff = department.employee(&quot;jeff&quot;);
jeff.giveRaise(new Cash(&quot;$5.000&quot;));

if (jeff.performance() &lt; 3.5) {
    jeff.fire();
}</code></pre>
<ul>
<li>이상적인 코드는 스스로를 설명하기 때문에 어떤 추가 문서도 필요하지 않습니다.</li>
<li>문서화하는 대신 코드를 깔끔하게 만들기 바랍니다.<h3 id="깔끔한-코드---단위-테스트도-함께-만든다">깔끔한 코드 - 단위 테스트도 함께 만든다.</h3>
</li>
<li>깔끔하고 유지보수 가능한 단위 테스트를 추가하면, 클래스를 더 깔끔하게 만들 수 있고 유지 보수성을 향상 시킬 수 있다. </li>
<li>단위 테스트는 클래스의 일부이지 독립적인 개체가 아닙니다. =&gt; 개념적인 측면에서 </li>
</ul>
<h3 id="느낀점">느낀점</h3>
<blockquote>
</blockquote>
<p>위의 예제 코드처럼 간단한 코드라면 저자가 말하는 이상적인 코드를 만드는데 힘을 많이 들이지 않아도 가능하겠지만, 보통 우리가 작성하는 코드는 저렇게 간단하지 않다고 생각한다. 테스트 코드를 잘 작성하면 문서화를 대신 하는 것 까지는 아니여도 코드를 이해하는데 훨씬 수월하다는 얘기는 많이 들었고 나도 동의한다. DisplayName이나 테스트 이름을 한글로 작성하면서 &quot;어떤 상황에서 어떤 결과가 나와야한다.&quot; 라는 형식을 지키면서 해당 메서드가 어떤 역할을 하는지 알 수 있다고 생각한다. </p>
<h2 id="28-모의-객체-대신-페이크-객체를-사용하세요">2.8 모의 객체 대신 페이크 객체를 사용하세요.</h2>
<pre><code class="language-java">class Cash {
    private final Exchange exchange;
    private final int cents;
    public Cash(Exchange exchange, int cents) {
        this.exchange = exchange;
        this.cents = cents;
    }

    public Cash in(String currency) {
        return new Cash(this.exchange, 
            this.cents * this.exchange.rate(&quot;USD&quot;, currency));
    }
}</code></pre>
<ul>
<li>테스트를 최적화하기 위한 장치라는 표현 방식은 모킹의 동작 방식을 잘 요약한 것이라고 생각합니다.</li>
<li>모킹은 나쁜 프랙티스이며, 최후의 수단으로만 사용해야 한다.</li>
<li>모킹 대신 페이크 객체를 사요할 것을 제안한다.</li>
</ul>
<h3 id="페이크-객체">페이크 객체</h3>
<pre><code class="language-java">public interface Exchange {
    float rate(String source, String target);
    final class Fake implements Exchange {
        @Override
        float rate(String origin, String target) {
            return 1.2345;
        }
    }
}</code></pre>
<ul>
<li>페이크 클래스는 인터페이스의 일부이며 인터페이스와 함께 제공됩니다. </li>
<li>페이크 클래스를 사용하면 테스트를 더 짧게 만들 수 있기 때문에 유지보수성이 눈에 띄게 향상됩니다. </li>
<li>모킹은 가정을 사실로 전환시키기 때문에 단위 테스트를 유지보수하기 어렵게 만든다.</li>
</ul>
<blockquote>
<p>모킹은 구현이 조금만 바껴도 다 깨지는 위험성을 지닌걸로 알고 있다. 모킹 테스트를 사용하는 것이 아닌 페이크 객체를 사용하면 구현이 바뀌어도 영향이 가는 위험성을 조금 줄일 수 있으니 좋은 것 같다. 활용을 하려면 더 공부를 해봐야 알 것 같다. </p>
</blockquote>
<h2 id="29-인터페이스를-짧게-유지하고-스마트를-사용하세요">2.9 인터페이스를 짧게 유지하고 스마트를 사용하세요</h2>
<h3 id="인터페이스를-작게-만드는-것">인터페이스를 작게 만드는 것</h3>
<ul>
<li>클래스가 다수의 인터페이스를 구현하기 때문에 인터페이스를 작게 만들어야합니다.</li>
<li>인터페이스는 구현 클래스가 준수해야하는 계약입니다.</li>
<li>구현자에게 많은 것을 요구하면 단일 책임 원칙을 위반하는 클래스를 만들도록 부추깁니다.
=&gt; 이는 응집도가 낮은 클래스를 만들게 합니다. <blockquote>
<p>데코레이터 패턴이 더 좋지 않을까? </p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective Java] 아이템 19 - 상속을 고려해 설계하고 문서화하라]]></title>
            <link>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-19-%EC%83%81%EC%86%8D%EC%9D%84-%EA%B3%A0%EB%A0%A4%ED%95%B4-%EC%84%A4%EA%B3%84%ED%95%98%EA%B3%A0-%EB%AC%B8%EC%84%9C%ED%99%94%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@hye_b/Effective-Java-%EC%95%84%EC%9D%B4%ED%85%9C-19-%EC%83%81%EC%86%8D%EC%9D%84-%EA%B3%A0%EB%A0%A4%ED%95%B4-%EC%84%A4%EA%B3%84%ED%95%98%EA%B3%A0-%EB%AC%B8%EC%84%9C%ED%99%94%ED%95%98%EB%9D%BC</guid>
            <pubDate>Mon, 13 Jun 2022 12:36:53 GMT</pubDate>
            <description><![CDATA[<h2 id="아이템-19--상속을-고려해-설계하고-문서화하라-그러지-않았다면-상속을-금지하라">아이템 19 : 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라</h2>
<blockquote>
<p>좋은 API 문서란 &#39;어떻게&#39;가 아닌 &#39;무엇&#39;을 하는지를 설명해야 한다.</p>
</blockquote>
<h3 id="상속을-고려한-설계와-문서화란-뭘까">상속을 고려한 설계와 문서화란 뭘까?</h3>
<ul>
<li><p><strong>메서드를 재정의하면 어떤 일이 일어나는지</strong>를 정확히 정리하여 문서로 남겨야한다.</p>
</li>
<li><p><strong>상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지</strong> 문서로 남겨야 한다.</p>
</li>
<li><p><strong>클래스의 API로 공개된 메서드</strong>에서 호출되는 메서드가 재정의 가능 메서드라면 <strong>호출하는 메서드 API 설명에 적시해야한다.</strong></p>
</li>
<li><p><strong>어떤 순서로 호출</strong>하는지, 각각의 <strong>호출 결과가 이어지는 처리에 어떤 영향을 주는지</strong>도 담아야 한다.</p>
</li>
<li><p><strong>재정의 가능</strong>이란 <strong>public과 protected 메서드</strong> 중 <strong>final이 아닌 모든 메서드</strong>를 뜻한다.
=&gt; 더 넓게 말하면 <strong>재정의 가능 메서드를 호출할 수 있는 모든 상황을 문서</strong>로 남겨야 한다.</p>
</li>
</ul>
<h3 id="implspec">@implSpec</h3>
<ul>
<li><p>자바 8에서 처음 도입되어 자바 9부터 본격적으로 사용되기 시작했다.</p>
</li>
<li><p>활성화 방법은 <code>-tag &quot;implSpec:a:Implementaion Requirements:&quot;</code>를 지정해주면 된다. </p>
</li>
<li><p>클래스의 내부 동작 과정 중간에 끼어들 수 있는 훅을 잘 선별하여 protected 메서드 형태로 공개해야 할 수도 있다.</p>
<h4 id="protected-메서드-형태로-공개해야-하는-예시">&lt;protected 메서드 형태로 공개해야 하는 예시&gt;</h4>
<p><img src="https://velog.velcdn.com/images/hye_b/post/a717017d-5fa2-4096-947b-43a3af23802f/image.png" alt=""></p>
</li>
<li><p>List 구현체의 최종 사용자는 removeRange 메서드에 관심이 없지만 하위 클래스에서 부분리스트의 clear 메서드를 고성능으로 만들기 쉽게 하기 위해서 제공한다.</p>
</li>
<li><p>removeRange 메서드가 없다면 하위 클래스에서 clear 메서드를 호출하면 제거할 원소 수의 제곱에 비례해 성능이 느려지거나 부분리스트의 메커니즘을 밑바닥부터 새로 구현해야 한다. </p>
</li>
</ul>
<h3 id="protected로-노출해야할지는-어떻게-결정하는가">protected로 노출해야할지는 어떻게 결정하는가?</h3>
<ul>
<li>심사숙고해서 잘 예측해본다음, <strong>실제 하위 클래스를 만들어 시험해보는 것이 최선</strong></li>
<li>protected 메서드 하나하나가 내부 구현에 해당하므로 그 수는 가능한 한 적어야 한다.</li>
<li>한편으로는 너무 적게 노출해서 상속으로 얻는 이점마저 없애지 않도록 주의</li>
</ul>
<h3 id="상속용-클래스를-시험하는-방법은-직접-하위-클래스를-만들어보는-것이-유일">상속용 클래스를 시험하는 방법은 직접 하위 클래스를 만들어보는 것이 유일</h3>
<ul>
<li>꼭 필요한 protected 멤버를 놓쳤다면 하위 클래슬르 작성할 때 빈자리가 드러나고</li>
<li>하위 클래스를 여러 개 만들 때까지 전혀 쓰이지 않은 protected 멤버는 private이었어야 할 가능성이 크다</li>
<li>저자의 경험상 검증에는 하위 클래스 3개 정도가 적당하고, 이 중 하나 이상은 제 3자가 작성해봐야 한다.</li>
</ul>
<h3 id="상속을-허용하는-클래스가-지켜야-할-제약">상속을 허용하는 클래스가 지켜야 할 제약</h3>
<ul>
<li>상속용 클래스의 생성자는 직접적으로든 간접적으로든 재정의 가능 메서드를 호출해서는 안 된다.
=&gt; 상위 클래스의 생성자가 하위 클래스의 생성자보다 먼저 실행되므로 하위 클래스에서 재정의한 메서드가 하위 클래스의 생성자보다 먼저 호출된다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_b/post/e552d34b-fd16-479c-891c-f0f0c4cd997a/image.png" alt=""></p>
<ul>
<li>instant 두 번 출력하리라 기대했겠지만, 첫 번째는 null을 출력한다. </li>
<li>상위 클래스의 생성자는 하위 클래스의 생성자가 인스턴스 필드를 초기화하기도 전에 overrideMe를 호출한다.</li>
<li>final 필드의 상태가 프로그램에서는 두 가지인데 정상이라면 단 하나뿐이어야 한다.</li>
<li>상위 클래스의 생성자가 overrideMe를 호출할 때 NullPointerException을 던지고 println이 null 입력을 받아 null을 출력한다.</li>
</ul>
<h3 id="clone과-readobject-모두-재정의-가능-메서드를-호출해서는-안-된다">clone과 readObject 모두 재정의 가능 메서드를 호출해서는 안 된다.</h3>
<ul>
<li>readObject의 경우 하위 클래스의 상태가 미처 다 역직렬화되기 전에 재정의한 메서드부터 호출하게 된다.</li>
<li>clone의 경우 하위 클래스의 clone 메서드가 복제본의 상태를 수정하기 전에 재 정의한 메서드를 호출한다.
=&gt; 둘 다 프로그램 오작동으로 이어질 것이다. 특히 clone은 원본에도 피해를 줄 수 있다. </li>
<li>Serializable을 구현한 상속용 클래스가 readResolve나 write Replace 메서드를 갖는다면 이 메서드들은 private이 아닌 protected로 선언해야한다. 
=&gt; private 선언 시 하위 클래스에서 무시됨, 상속을 허용하기 위해 내부 구현을 클래스 API로 공개하는 예 중 하나 </li>
</ul>
<h3 id="상속을-금지하기">상속을 금지하기</h3>
<blockquote>
<p>상속용으로 설계하지 않은 클래스는 상속을 금지한다.</p>
</blockquote>
<ul>
<li>클래스를 final로 선언하기</li>
<li>모든 생성자를 private나 package-private로 선언하고 public 정적 팩터리를 만들어 주는 방법</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>