<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ggam-nyang.log</title>
        <link>https://velog.io/</link>
        <description>개발 꿈나무</description>
        <lastBuildDate>Mon, 31 Oct 2022 12:37:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>ggam-nyang.log</title>
            <url>https://images.velog.io/images/ggam-nyang/profile/5d144d39-9ecb-4233-96eb-899e7c96e226/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ggam-nyang.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ggam-nyang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[WHY?] ConcurrentHashMap은 어떻게 동시성을 보장할까]]></title>
            <link>https://velog.io/@ggam-nyang/WHY-ConcurrentHashMap%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%8B%9C%EC%84%B1%EC%9D%84-%EB%B3%B4%EC%9E%A5%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@ggam-nyang/WHY-ConcurrentHashMap%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%8B%9C%EC%84%B1%EC%9D%84-%EB%B3%B4%EC%9E%A5%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Mon, 31 Oct 2022 12:37:31 GMT</pubDate>
            <description><![CDATA[<h2 id="hashtable">HashTable</h2>
<p>동시성을 보장하는 Map 자료구조 중 하나이다.
그러나 성능이 좋지 않은 오래된 녀석이라 잘 사용하지 않는다.</p>
<pre><code class="language-java">    public synchronized int size() { return count; }
    public synchronized V put(K key, V value) { ... }</code></pre>
<p>Java API 문서를 보면 알겠지만, <code>synchronized</code> 범벅을 통해 동시성을 보장한다.
동시성을 보장해주는 <code>synchronized</code>는 편리한 키워드지만
컬렉션의 get, put 등 모든 메소드에 사용하게 되면, 당연히 성능이 저하된다.</p>
<h2 id="concurrenthashmap">ConcurrentHashmap</h2>
<p>결론적으로 <code>ConcurrentHashmap</code>은 좋은 성능과 함께 동시성을 보장한다.
어떻게 그럴 수 있을까?</p>
<pre><code class="language-java">    public V get(Object key) {
        Node&lt;K,V&gt;[] tab; Node&lt;K,V&gt; e, p; int n, eh; K ek;
        int h = spread(key.hashCode());
        if ((tab = table) != null &amp;&amp; (n = tab.length) &gt; 0 &amp;&amp;
            (e = tabAt(tab, (n - 1) &amp; h)) != null) {
            if ((eh = e.hash) == h) {
                if ((ek = e.key) == key || (ek != null &amp;&amp; key.equals(ek)))
                    return e.val;
            }
            else if (eh &lt; 0)
                return (p = e.find(h, key)) != null ? p.val : null;
            while ((e = e.next) != null) {
                if (e.hash == h &amp;&amp;
                    ((ek = e.key) == key || (ek != null &amp;&amp; key.equals(ek))))
                    return e.val;
            }
        }
        return null;
    }</code></pre>
<p>get의 경우 동시에 여러 쓰레드에서 접근이 가능하다.
tabAt() 메소드가 내부적으로 <code>volatile</code> 관련 함수로 되어 있긴하다.</p>
<p><code>putval()</code> 메소드를 보자 (put과 같다)</p>
<pre><code class="language-java">    final V putVal(K key, V value, boolean onlyIfAbsent) {
        // null은 저장하지 않는다.
        if (key == null || value == null) throw new NullPointerException();
        int hash = spread(key.hashCode());
        int binCount = 0;
        for (Node&lt;K,V&gt;[] tab = table;;) {
            Node&lt;K,V&gt; f; int n, i, fh; K fk; V fv;
            // 최초 실행 시, table 생성
            if (tab == null || (n = tab.length) == 0)
                tab = initTable();
            // 존재하지 않는 key(정확히는 hashCode) 값이라면 casTabAt 실행    
            else if ((f = tabAt(tab, i = (n - 1) &amp; hash)) == null) {
                if (casTabAt(tab, i, null, new Node&lt;K,V&gt;(hash, key, value)))
                    break;                   // no lock when adding to empty bin
            }
            else if ((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else if (onlyIfAbsent // check first node without acquiring lock
                     &amp;&amp; fh == hash
                     &amp;&amp; ((fk = f.key) == key || (fk != null &amp;&amp; key.equals(fk)))
                     &amp;&amp; (fv = f.val) != null)
                return fv;
            else {
                V oldVal = null;
                // 버킷의 root 노드를 lock 객체로 사용한다.
                synchronized (f) {
                    if (tabAt(tab, i) == f) {
                        if (fh &gt;= 0) {
                            binCount = 1;
                            // 버킷의 LinkedList를 순회하며 값을 삽입 or 변경 해준다.
                            for (Node&lt;K,V&gt; e = f;; ++binCount) {
                                K ek;
                                if (e.hash == hash &amp;&amp;
                                    ((ek = e.key) == key ||
                                     (ek != null &amp;&amp; key.equals(ek)))) {
                                    oldVal = e.val;
                                    if (!onlyIfAbsent)
                                        e.val = value;
                                    break;
                                }
                                Node&lt;K,V&gt; pred = e;
                                if ((e = e.next) == null) {
                                    pred.next = new Node&lt;K,V&gt;(hash, key, value);
                                    break;
                                }
                            }
                        }
                        // 버킷이 RB Tree로 구현되어 있는 경우
                        else if (f instanceof TreeBin) {
                            Node&lt;K,V&gt; p;
                            binCount = 2;
                            if ((p = ((TreeBin&lt;K,V&gt;)f).putTreeVal(hash, key,
                                                           value)) != null) {
                                oldVal = p.val;
                                if (!onlyIfAbsent)
                                    p.val = value;
                            }
                        }
                        else if (f instanceof ReservationNode)
                            throw new IllegalStateException(&quot;Recursive update&quot;);
                    }
                }
                if (binCount != 0) {
                    if (binCount &gt;= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
                    if (oldVal != null)
                        return oldVal;
                    break;
                }
            }
        }
        addCount(1L, binCount);
        return null;
    }</code></pre>
<p>굉장히 복잡해 보이지만 정리해보면 제법 단순하다.</p>
<ul>
<li><p>저장하려는 key의 hashCode 값에 해당하는 버킷이 존재하나?</p>
<ul>
<li>존재하지 않는다면, <a href="https://jenkov.com/tutorials/java-concurrency/compare-and-swap.html">Compare And Swap</a>를 이용해 저장한다.</li>
</ul>
</li>
<li><p><code>f.hash == MOVED</code> 와 같은 특수 상황을 제외하고 버킷이 존재하나?</p>
</li>
<li><p>버킷의 root 노드를 <code>synchronized</code>의 lock 객체로 사용하고
LinkedList(Separate Chaining)을 순회하며 value를 삽입 or 수정한다.</p>
</li>
<li><p>만약 버킷이 Tree(RB Tree)로 구현되어 있다면, <code>putTreeVal</code>을 실행한다.</p>
</li>
</ul>
<p>단순화 하면, key가 없으면 CAS를 이용하고 이미 존재한다면 <code>synchornized</code>를 통해 동시성을 보장한다.</p>
<h3 id="cas는-어떻게-원자성을-보장할까">CAS는 어떻게 원자성을 보장할까?</h3>
<p><a href="https://jenkov.com/tutorials/java-concurrency/compare-and-swap.html">Compare And Swap</a> 해당 링크에 자세히 설명되어 있지만, 단순화 해보자면
실제 주소값에 저장된 값과 목표값을 비교하기 때문이다.
즉, 위의 경우에 <code>casTabAt(tab, i, null, new Node&lt;K,V&gt;(hash, key, value))</code>
저장된 Node&lt;K, V&gt;가 없으므로 null을 기대하고 실제로 그렇다면
<code>new Node&lt;K,V&gt;(hash, key, value)</code>를 저장한다.</p>
<p>이는 읽기, 쓰기 등의 모든 과정이 하나의 인스트럭션에서 이뤄지기 때문에 원자성을 보장해주는 것이다.</p>
<h3 id="synchronized를-썻는데">synchronized를 썻는데?!</h3>
<p>성능이 좋지 않다고 한 HashTable처럼 <code>synchronized</code>를 사용했다.
중요한 건, 각 버킷마다 사용한 것이다.</p>
<p>각 버킷의 root 노드를 lock으로 사용했으므로, 해쉬 충돌이 발생하지 않는 경우에는 여러 쓰레드에서 접근이 가능하다.
때문에 컬렉션 대부분의 method에 <code>synchronized</code>를 사용한 것보다 훨씬 성능이 좋다.</p>
<p>해쉬 충돌이 자주 발생하면 hashTable로 수렴하겠지만,
내부적으로 spread 함수를 통해, 해쉬 충돌을 줄인다.</p>
<pre><code class="language-java">    static final int spread(int h) {
        return (h ^ (h &gt;&gt;&gt; 16)) &amp; HASH_BITS;
    }</code></pre>
<h3 id="fast-safe">Fast-safe?</h3>
<p>Java.Collection의 대부분은 Fast-fail이다. (HashMap, ArrayList ..)
당연하게도 이는 동시성을 보장해주지 않으므로, 공유 자원에 접근하는 경우에 사용하지 말라는 의미이다.</p>
<p>그래서 <code>ConcurrentModificationException</code>이 메소드 전반에 걸쳐 나타난다. (32개 정도..)</p>
<p>Fast-Fail, Fast-safe는 <a href="https://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator">여기</a>서 보면 될 것 같다.</p>
<p>아무튼, <code>ConcurrentHashMap</code>은 내부적으로 <img src="https://velog.velcdn.com/images/ggam-nyang/post/365f01c8-61e4-4769-adb3-5c97359c9d19/image.png" alt="">
iterator를 따로 구현했다.
때문에 remove() 메소드에서 <code>ConcurrentModificationException</code>이 발생하지 않는다.</p>
<h3 id="동시성은-concurrenthashmap으로-종결">동시성은 ConcurrentHashMap으로 종결?</h3>
<p>이 부분은.. 동시성 프로그래밍 환경을 더 겪어봐야 알 것 같다.
그러나 hashMap 말고도 여러가지 멀티 스레드 환경에서 문제가 생기는 일은 많다.</p>
<p>때문에 어떻게 동시성을 보장하고, 내부적으로 구현되어 있는지 파악해둔다면
라이브러리 등을 써도 컨트롤이 가능하지 않을까싶다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WHY] Static 무엇일까?]]></title>
            <link>https://velog.io/@ggam-nyang/WHY-Static-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@ggam-nyang/WHY-Static-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Tue, 20 Sep 2022 09:10:09 GMT</pubDate>
            <description><![CDATA[<h2 id="static이-정확히-뭘까">Static이 정확히 뭘까?</h2>
<h3 id="static-변수">Static 변수</h3>
<pre><code class="language-java">public Static{
    public String notStatic;
    public static String staticVariable = &quot;sv&quot;;
    public static void main(String[] args) {

    }

    public void someMethod() {

    }
}</code></pre>
<p>위와 같은 Static 클래스가 존재할 때, 
notStatic은 인스턴스 변수, StaticVariable은 클래스 변수이다.</p>
<p>인스턴스 변수는, 객체의 생성과 함께 시작되고 저장된다.
    - new 연산자로 생성되고 Heap 영역에 저장된다.</p>
<p>클래스 변수는 클래스의 생성과 함께 저장된다.
    - 클래스에 대한 정보와 클래스 변수는 메소드 영역에 저장된다.</p>
<p>즉, 생명 주기도 다르고 저장되는 위치도 다르다.</p>
<p>모든 Static 객체의 notStatic 값이 &quot;no!!&quot;로 동일하다고 했을 때,
100개의 Static 객체가 생성되면 100개의 동일한 notStatic 인스턴스 변수가 생성되고 저장된다.</p>
<p>그러나 static으로 정의한 경우, 1개의 동일한 변수를 바라보게 된다.
(값을 변경할 경우 모든 객체에서 값이 변경되므로 final 키워드를 붙이는게 좋다.)</p>
<h3 id="static-메소드">Static 메소드</h3>
<p>클래스 변수와 유사하게, static 메소드도 클래스 생성과 함께 생성된다.
그래서 객체의 생성 없이도, 해당 메소드를 사용할 수 있다.</p>
<pre><code class="language-java">    public static String join(CharSequence delimiter, CharSequence... elements) {  
        var delim = delimiter.toString();  
        var elems = new String[elements.length];  
        for (int i = 0; i &lt; elements.length; i++) {  
            elems[i] = String.valueOf(elements[i]);  
        }    return join(&quot;&quot;, &quot;&quot;, delim, elems, elems.length);  
    }


// 이렇게 사용할 수 있다
String test = String.join(...);

// 이렇게가 아닌!!
String str = new String();
String test = str.join(...);</code></pre>
<p>String에 정의된 join 메소드이다.
이는 static 메소드로, 아래 2줄처럼 String 객체를 생성하지 않고도
메소드를 호출하여 사용할 수 있다.</p>
<p>변수와 마찬가지로 메모리 효율에서 장점이 있다고 생각한다.
객체를 생성하지 않아도 되니까!</p>
<p>당연하게도, static 메소드에서는 static 변수만 참조할 수 있다.
인스턴스 변수는 객체 생성시에 생성되기 때문이다.</p>
<p>(static class는 다음에..!)</p>
<h3 id="급한-정리">급한 정리</h3>
<p>결국 static과 아닌 것의 차이는 생성 시점과 저장되는 메모리의 위치가 다름이다.</p>
<p>내 나름의 장단을 생각해보면
장점: </p>
<ul>
<li>메모리 효율이 올라간다.</li>
<li>객체를 생성하지 않아도 돼서 코드 작성이 편해진다.</li>
</ul>
<p>단점:</p>
<ul>
<li>전역 변수처럼 남용할 경우, 오히려 메모리 비효율이 발생할 수 있다.
(자바 프로그램의 종료와 함께 메모리가 정리되므로 GC가 관리해주는
heap 영역과는 다르다)</li>
<li>final 변수가 아닌 경우, 에러 나기 쉽다..!</li>
</ul>
<p>자바를 프로덕트 레벨에서 사용하다보면 더 많은 장단을 느끼게 될 것 같다.</p>
<h4 id="why">WHY?</h4>
<p>내 생각에는 static은 결국 저장 위치가 다른게 핵심이고
-&gt; 이에 따라 생명주기도 달라지고
-&gt; 객체 생성 없이 메소드를 사용하고, 변수를 사용하고 등등 
    효과가 생긴다고 생각한다.</p>
<h5 id="더-알아볼-것">더 알아볼 것:</h5>
<ul>
<li><p>메모리 계층 구조와 JVM이 관리하는 메모리 계층 구조가 다른지?</p>
<ul>
<li>다르다면 어떻게 다른건지..? (method 영역이 무엇일까)</li>
</ul>
</li>
<li><p>WHY?가 부실하다... 1주일 뒤 복기하며 조금 더 찾아보기!</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바의 신] 8장]]></title>
            <link>https://velog.io/@ggam-nyang/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%8B%A0-8%EC%9E%A5</link>
            <guid>https://velog.io/@ggam-nyang/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%8B%A0-8%EC%9E%A5</guid>
            <pubDate>Wed, 14 Sep 2022 08:42:36 GMT</pubDate>
            <description><![CDATA[<h2 id="8장-참조-자료형">8장. 참조 자료형</h2>
<p>7장까지의 내용은 자바 및 프로그래밍 기초에 관한 것으로 따로 정리하지 않고 복기하자.</p>
<ul>
<li>추가로 책을 옮기고자 하는 것이 아닌, 복기 + Why 위주로 글을 적어보자!</li>
</ul>
<h3 id="참조-자료형-reference-type"><strong>참조 자료형 (Reference Type)</strong></h3>
<p>자바의 기본 자료형(primitive type) 8가지를 제외한 모든 자료형이다.
new를 사용해 객체를 생성하는 것들이다. (String 제외)</p>
<h4 id="생성자">생성자</h4>
<pre><code class="language-java">public class ReferenceType {
    public ReferneceType(String name){

    }
}</code></pre>
<p>클래스명과 동일하게 작성된 메소드가 생성자이다.
위와 같이 생성자를 한개도 정의하지 않으면, 매개변수가 없는 기본 생성자가 생긴다.</p>
<p>생성자는 매개변수 타입과 개수에 따라 여러 개 작성할 수 있다.</p>
<p>*<em>WHY 생성자는 왜 필요할까? *</em>
자바의 생성자는 객체(인스턴스)를 생성하기 위해 필요하다.
우리가 필요한건 클래스가 아니라 객체니까 말이다.</p>
<pre><code class="language-java">public class User {
    public String name;
    public Int age;
    public String address;
    ...


    public User(String name) {
        this.name = name;
    }

    public User(String name, Int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

}</code></pre>
<p>User 클래스가 여러가지 인스턴스 변수를 가질 때 생성자를 통해 편하게 다룰 수 있다. 매개변수로 name만 전달하거나, 모든 정보를 전달하여 생성자를 정의할 수 있고
DTO로 사용할 때 편리하다.</p>
<p>this 예약어는 스킵!</p>
<h4 id="메소드-overloading">메소드 overloading</h4>
<pre><code class="language-java">public class Overload {
    ...
    public void someMethod(String str)
    public void someMethod(Int int)
}</code></pre>
<p>메소드의 이름은 동일하게 하고 매개 변수들을 다양하게 변화시켜 작성할 수 있다.
오버로딩은 확장의 개념으로 이해할 수 있다.</p>
<p>즉, 같은 역할(행동)을 하는 메소드는 같은 메소드 이름을 가지게 한다.
매개 변수의 타입, 개수는 다르더라도 말이다.</p>
<p><strong>Static 메소드</strong></p>
<pre><code class="language-java">public class Static {
    ...
    public static void staticMethod() {
        ... 
    }
}
// 이렇게 하지 않아도 된다.
Static staticTemp = new Static();
staticTemp.staticMethod()

// 이렇게 가능
Static.staticMethod()</code></pre>
<p>static 메소드는 객체를 생성하지 않고도 메소드를 호출 할 수 있다.
그러나, 클래스 변수만 사용할 수 있다. (인스턴스 변수를 사용할 수 없다)</p>
<p>마찬가지로 static을 붙여 클래스 변수로 정의할 수 있는데,
모든 객체에서 하나의 값을 바라보기 때문에 사용에 주의해야 한다.</p>
<pre><code class="language-java">public class Static {
    static String name;
    public static void staticMethod() {
        ... 
    }
}

// Static 객체가 2개라고 하면
static1.name // &quot;normal&quot;
static1.name = &quot;changed&quot;
static2.name // &quot;changed&quot;</code></pre>
<h4 id="static-block">static block</h4>
<p>static 블록은 객체가 생성되기 전 한번만 호출되고, 그 이후에는 호출하지 못한다.
static { }</p>
<h4 id="pass-by-value-pass-by-reference">pass by value, pass by reference</h4>
<p>기본 자료형은 pass by value
참조 자료형은 pass by reference</p>
<p>메소드의 매개 변수로 참조 자료형을 사용한다면, 메소드 안에서 객체의 상태 변경 사항이 매개 변수로 사용된 객체에 반영된다.
당연히 주소값을 넘겼으니, 같은 주소값을 참조하는 객체(변수)도 값이 변화한다!</p>
<br>
<br>
<br>
<br>
피드백:
공부 기록을 남기고, 복기는 좋다.
그러나 복기 대비 시간 소요가 너무 크다.

<p>중요한 내용만 빠르게 정리하거나, 난이도 있게 추가 학습한 것만 정리하는게 나을지도?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[북스터디] 객체지향의 사실과 오해 (2)]]></title>
            <link>https://velog.io/@ggam-nyang/%EB%B6%81%EC%8A%A4%ED%84%B0%EB%94%94-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%9D%98-%EC%82%AC%EC%8B%A4%EA%B3%BC-%EC%98%A4%ED%95%B4-1-7vmayuph</link>
            <guid>https://velog.io/@ggam-nyang/%EB%B6%81%EC%8A%A4%ED%84%B0%EB%94%94-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%9D%98-%EC%82%AC%EC%8B%A4%EA%B3%BC-%EC%98%A4%ED%95%B4-1-7vmayuph</guid>
            <pubDate>Sat, 09 Apr 2022 09:04:02 GMT</pubDate>
            <description><![CDATA[<h3 id="개괄">개괄</h3>
<p>3, 4, 5장은 결국 협력, 책임, 역할에 관한 얘기들이었다. 1주차와 비슷하게 코드가 있진 않아서, 너무 추상적이게 느껴지기도 했다. 그래도 개념을 이해하고 객체지향의 오해를 해소하는 좋은 책임이 분명하다.</p>
<h2 id="3장-타입과-추상화">3장. 타입과 추상화</h2>
<p>추상화에 관한 내용이다.
SW 사관학교 정글을 수료하며, 프로그래밍을 배우며 느낀건.</p>
<blockquote>
<p>프로그래밍 == 추상화</p>
</blockquote>
<p>결국 모든건 추상화의 과정이라고 생각하는데, 결국 객체지향도 고도화된 추상화들을 통해
개발을 용이하게 하는 패러다임이 아닌가싶다.</p>
<p>지하철 노선도를 생각해보자. 우리의 2호선 노선도와 실제 지리적 위치는 차이가 있다.
그럼에도 우리는 노선도가 훌륭한 지도라고 생각한다.
이것 또한 추상화다. 추상화란, 공통점을 모아놓는 것 + 불필요한 부분을 삭제하는 것이다.
전자의 개념이 곧 추상화라고 생각해서 후자의 개념이 신기했다.</p>
<p>지하철 노선도는 지리적 위치라는 불필요한(지도를 보는 사람에게) 정보를 제외하고,
역의 관계에만 집중한 추상화된 지도이다.
목적지에 가기 위해 노선도를 확인하는 사람들에게 적합한 지도를, 추상화를 통해 생성했다.</p>
<p>즉 객체들의 공통점 혹은 불필요한 정보를 제외한 알맹이 정보를 추상화하여 표현할 수 있다.</p>
<p>책의 예시로, 트럼프 카드로 된 하트 여왕, 국왕, 경비병, 정원사등은 모두 트럼프 카드로 추상화할 수 있다. 
이들 모두 트럼프 카드의 특징(네모, 모서리 둥금)을 가지지만, 각각 객체를 설명하기보다 트럼프 카드로 묶는 것이다!</p>
<pre><code>class TrumpCard {
    둥근 모서리,
    네모 모양,
    클로버, 하트, 다이아, 스페이드 타입을 가짐
}</code></pre><p>이런 느낌으로 추상화를 하고, 객체는 상속을 받는다던지 할 수 있을 것 같다.</p>
<h2 id="4장-역할-책임-협력">4장. 역할, 책임, 협력</h2>
<p>이하는 기억에 남는 것들 위주로 정리하겠다.</p>
<p>1, 2장의 핵심 내용을 떠올려보자. 객체를 생성, 설계할 때 <strong>상태</strong>가 아닌 <strong>행동</strong>을 먼저 설계하자.
행동에 필요한 상태를 정의하면 되는 것이다.</p>
<p>행동은 왜 필요할까?
객체들의 책임을 다하기 위해서다. 바리스타는 손님에게 커피를 만들어줄 책임이 있고, 커피를 만드는 행동이 필요하다.</p>
<p>다시 한번, 책임은 왜 필요할까?
협력을 하기 위해서다. 객체지향 프로그래밍은 결국 객체들의 협력으로 이루어진다.
협력을 하기 위해 책임을 다해야 하고, 책임을 위해 행동이, 행동에 필요한 상태가 정의돼야한다.</p>
<p>즉, 어떤 협력이 필요한지 설계하는 것이 우선이다.</p>
<p>이 내용이 4장의 핵심 내용이라 생각하고, 스프링 개발 1달차인 나는 정확히 반대로 객체지향을 다뤄왔지 않나 싶다.</p>
<h2 id="5장-메세지">5장. 메세지</h2>
<blockquote>
<p>객체지향은 곧 협력</p>
</blockquote>
<p>4장의 내용이 위와 같다.</p>
<p>그렇다면 어떻게 협력할까?
앞선 내용은 객체지향 프로그래밍에 대한 WHY라면, 이젠 HOW이다.</p>
<p>객체간의 협력을 위해, 객체는 서로 메세지를 통해 소통한다.
각 메세지에 대한 송신자, 수신자가 존재한다.
송신자는 최대한 추상화된(?) 메세지를 전달한다.
예를 들어, 캐셔는 바리스타에게 </p>
<pre><code>커피를 만들어줘</code></pre><p>라고 메세지를 보내면, 어떤 <strong>방법</strong>으로 커피를 만들지는 바리스타의 자율이다.</p>
<p>이 자율이 굉장히 중요한 부분인데, 각 수신자(객체)는 자율성이 보장되어야하고
말인 즉, 송신자는 자율성을 보장하는 메세지를 보내야한다.</p>
<pre><code>95도 뜨거운 물로 만든 커피 만들어줘</code></pre><p>라고 한다면, 바리스타는 퇴사할지도 모른다.</p>
<p>결국 메세지라는 HOW를 통해 객체지향의 유명한 특성들이 설명된다.</p>
<h4 id="다형성">다형성</h4>
<p>메세지의 타입, 인자 개수 등에 따라 수신자가 Method를 선택한다!
(즉, 커피 만드는 방법은 바리스타가 선택한다.)</p>
<h4 id="캡슐화">캡슐화</h4>
<p>송신자는 수신자가 어떤 상태, 메서드를 가지고 있는지 알 수 없다.
(캐셔는 바리스타의 커피 제조 방법을 모르고, 그저 커피 제작 메세지를 보낼 뿐이다.)</p>
<h3 id="마치며">마치며</h3>
<p>출퇴근 시간을 이용해 책을 읽는 것이 쉽지 않다.
하루 1시간만 읽어도 1주일에 2장은 쉬울텐데!
좀 더 화이팅해보자!</p>
<p>++
책이 무겁지 않지만, 핵심 내용을 많이 담고 있다.
아는 만큼 보이는 책이라고 느껴져서 내가 많이 흡수를 못했을 수도 있다.
후에, 스프링과 더 친해지면 다시 읽어보자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring 프레임워크 핵심기술] 강의 기록 2.]]></title>
            <link>https://velog.io/@ggam-nyang/Spring-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%ED%95%B5%EC%8B%AC%EA%B8%B0%EC%88%A0-%EA%B0%95%EC%9D%98-%EA%B8%B0%EB%A1%9D-2</link>
            <guid>https://velog.io/@ggam-nyang/Spring-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%ED%95%B5%EC%8B%AC%EA%B8%B0%EC%88%A0-%EA%B0%95%EC%9D%98-%EA%B8%B0%EB%A1%9D-2</guid>
            <pubDate>Sat, 09 Apr 2022 08:27:57 GMT</pubDate>
            <description><![CDATA[<h2 id="ioc-컨테이너-4부">IoC 컨테이너 4부</h2>
<h3 id="component-컴포넌트-스캔">@Component, 컴포넌트 스캔</h3>
<pre><code>@SpringBootApplication
=&gt;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
</code></pre><p><code>@SpringBootApplication</code>안에는 이렇게 많은 어노테이션이 포함되어있다.
이중 <code>@ComponentScan</code>을 알아보자.</p>
<pre><code>@AliasFor(&quot;value&quot;)
    String[] basePackages() default {};

    /**
     * Type-safe alternative to {@link #basePackages} for specifying the packages
     * to scan for annotated components. The package of each class specified will be scanned.
     * &lt;p&gt;Consider creating a special no-op marker class or interface in each package
     * that serves no purpose other than being referenced by this attribute.
     */
    Class&lt;?&gt;[] basePackageClasses() default {};</code></pre><p>다시 <code>@ComponentScan</code>안에는 basePackages()가 있는데, String을 받는다.
Type-safe를 위해 아래 basePackageClasses()를 통해, 입력 클래스 기준으로 scan을 시작한다.
=&gt; 외부 package는 스캔이 되지 않고, Bean으로 등록이 안된다.</p>
<p>@Filter도 중요하다.
해당하는 클래스는 스캔하지 않게 해준다!</p>
<p>이렇게 스프링 실행 시, 빈을 스캔해서 등록해준다.
실제 스캐닝은 ConfigurationClassPostProcessor 라는 BeanFactoryPostProcessor에 의해 처리된다.</p>
<p>단점: 초기 구동에서 모두 등록하기 때문에 (싱글톤 스코프), 최초 스프링 구동시에 시간이 걸린다.
(프록시? 등을 사용하기 때문이라는데, 정확한 이유는 찾아보자)</p>
<p>그래서 functional하게 빈을 직접 코드로 등록하는 방법도 가능하다. (스프링 부트는 이렇게 하는듯?)</p>
<pre><code>public static void main(String[] args) {
        new SpringApplicationBuilder()
            .sources(Demospring51Application.class)
            .initializers((ApplicationContextInitializer&lt;GenericApplicationContext&gt;)
applicationContext -&gt; {
}</code></pre><p>이렇게 initializers를 이용해 직접 Bean 등록이 가능하다.
이를 통해 조건문(if)등을 추가하여 빈을 등록하는 방식을 구현할 수 있다.</p>
<p>정리: 
@ComponentScan은 스캔 범위, 스캔 필터를 지정한다.
@Component(Controller, Service etc)를 스캔하고 빈으로 등록한다.
Functional한 방식의 빈 등록도 가능은 하다! (Component Scan을 대체하는건 비추!!)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 강의 기록하기]]></title>
            <link>https://velog.io/@ggam-nyang/Spring-%EA%B0%95%EC%9D%98-%EA%B8%B0%EB%A1%9D%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@ggam-nyang/Spring-%EA%B0%95%EC%9D%98-%EA%B8%B0%EB%A1%9D%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 09 Apr 2022 06:27:28 GMT</pubDate>
            <description><![CDATA[<h1 id="스프링-프레임워크-핵심-기술">스프링 프레임워크 핵심 기술</h1>
<h2 id="강의-기록">강의 기록</h2>
<h4 id="ioc-1부">IOC 1부</h4>
<p>Bean이란 IoC 컨테이너가 관리하는 <strong>객체</strong>
Bean으로 등록하는 이유는?</p>
<ul>
<li>의존성 주입을 하기 위해, 또 받기 위해 (의존성 관리)</li>
<li>빈의 Scope 때문.<ul>
<li>싱글톤 관리 (빈에 등록될 때 기본적으로 싱글톤 Scope으로 등록됨)</li>
<li>프로토타입 ( 매번 다른 객체로 등록)</li>
</ul>
</li>
<li>라이프 사이클 인터페이스<ul>
<li>ex. 객체 생성 때 뭔가 실행 (@PostConstruct)</li>
</ul>
</li>
</ul>
<h4 id="ioc-2부">IOC 2부</h4>
<p>Bean은 어떻게 등록하는가?</p>
<ol>
<li>xml 파일에 하나하나 등록 (불편)</li>
<li>bean-scanning을 xml에 등록해서 context를 scan 하기 (@Component + @Autowired)</li>
<li>xml -&gt; 자바 파일로 바꾸자! @Configuration에 Bean을 등록</li>
<li>마찬가지로 @ComponentScan 으로 스캔 기능 추가</li>
<li>그 자바 파일도 없애서, @SpringBootApplication을 붙이면, 그 파일 역할을 해줌 (Spring boot)</li>
</ol>
<h4 id="ioc-3부">IOC 3부</h4>
<p>@Autowired</p>
<p>Bean에 등록하고 DI를 하는 방법 </p>
<ol>
<li>생성자로 받는다. (@Autowired, Bean 등록하면 문제없음)</li>
<li>setter로 받는다.</li>
</ol>
<ul>
<li>bookRepository가 bean이 아니어도, 생성이 가능해야하지만
   @autowired가 있으면 실패함. (<code>required = false</code> 하면 실행가능)</li>
<li>bookRepository implement가 두개라면?
=&gt; Error (어떤건지 알 수 없음)
=&gt; 3가지 action 가능 (@Primary, Qulifier, 모두 주입받기)
++ specificBookRepository라고 이름을 명시하면 이름이 같은걸 주입해주긴 함 (비추)</li>
</ul>
<p>Bean 라이프사이클
@BeanPostProcessor (Bean 등록 이후 작업을 처리해주는?)
새로 만든 빈 인스턴스를 수정할 수 있는 라이프사이클 인터페이스</p>
<p>AutowiredAnnotationBeanPostProcessor​ extends BeanPostProcessor
스프링이 제공하는 @Autowired와 @Value 애노테이션 그리고 JSR-330의 @Inject 애노테이션을 지원하는 애노테이션 처리기</p>
<p>결국 스프링은 추상화의 산물이고, 현재 단계의 스프링을 이해하기 위해선 추상화의 역사를 알아야한다.
@Autowired는 해당 class가 빈으로 등록되어 있는지 확인하고, 자동으로 주입을 해준다.
이를 위해선 Bean으로 먼저 등록이 되어야하고
빈 등록은 xml or @Configuration 작성 =&gt; @Component 스캔으로 빈 등록을 하고
등록된 빈은, 자동 주입이 가능하다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[북스터디] 객체지향의 사실과 오해 (1)]]></title>
            <link>https://velog.io/@ggam-nyang/%EB%B6%81%EC%8A%A4%ED%84%B0%EB%94%94-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%9D%98-%EC%82%AC%EC%8B%A4%EA%B3%BC-%EC%98%A4%ED%95%B4-1</link>
            <guid>https://velog.io/@ggam-nyang/%EB%B6%81%EC%8A%A4%ED%84%B0%EB%94%94-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%9D%98-%EC%82%AC%EC%8B%A4%EA%B3%BC-%EC%98%A4%ED%95%B4-1</guid>
            <pubDate>Fri, 25 Mar 2022 12:52:40 GMT</pubDate>
            <description><![CDATA[<h1 id="북스터디-첫-시작">북스터디 (첫 시작)</h1>
<p>첫 북스터디를 객체지향의 사실광 오해로 시작해본다.
시작이 반이니 반만 더 성공해보자!</p>
<h3 id="첫-주-개괄">첫 주 개괄</h3>
<p>책에 머리에도 나오지만, 코드는 아주 일부만 등장한다. 특히 1, 2장은 소설같은 느낌이다.
객체 지향을 이야기(이상한 나라의 앨리스)에 비유하여 풀어나간다. 그래서 읽는 내내 그냥 소설을 읽는 기분이 들었다.
때문에 1, 2장은 뇌리에 남는 구절들을 위주로 남겨보고자 한다.</p>
<h2 id="1장-협력하는-객체들의-공동체">1장. 협력하는 객체들의 공동체</h2>
<p>객체 지향은 객체를 지향하는 프로그래밍 페러다임이다. 객체지향을 써보지 않은 사람도 이는 분명히 인지할 것이다. 그럼 객체 지향을 사용해본 사람들은 객체를 지향하며 프로그래밍을 했을까?
1달차 스프링 부트 응애인 나는 아니다. 객체 지향하면 바로 생각나는 것은 무수히 많은 class를 통해 추상화를 하고, 이에 연장선으로 캡슐화, 상속 등을 하며 코드를 작성한다. 그래서 객체 지향하면 생각나는건 Class다.</p>
<br>
그럼 객체 지향에서 객체는 Class인가? 당연히 아니다. 객체는 Object이지 않는가.
1장은 객체 지향의 주인공은 객체임을 말한다. 그리고 이 객체는 **역할, 책임, 협력**을 가진다.
흔한 비유를 해보자. 커피를 주문하는 손님, 주문을 받는 캐셔 그리고 커피를 만드는 바리스타가 있다. 손님은 커피를 주문하고, 캐셔는 바리스타에게 주문을 전달하고, 바리스타는 커피를 만든다.
다시 바리스타는 커피를 캐셔에게 전달하고, 캐셔는 손님에게 커피를 준다.

<p>다시, 각자 커피를 주문, 전달, 제작등의 역할을 하고 커피 한잔이 주문되는데까지 협력한다.
즉, 손님 객체는 주문을 제작하고 캐셔는 전달, 바리스타는 제작할 것이다. 이는 각각의 역할이다. 또 이를 행할 책임이 있고, 이를 위해 협력한다. 협력을 위해서는 객체 간의 메세지를 전달한다. 손님 객체는 주문을 생성하고 캐셔 객체에게 메세지를 보낸다. 캐셔는 메세지를 받고 주문을 확인하고 바리스타 객체에게 메세지를 보낸다.</p>
<p>아무튼 이런 이야기는 우리가 흔히 아는 객체 지향의 비유이다. 결국 핵심은 다음과 같다.</p>
<li> 객체지향이란 시스템을 상호작용하는 <b>자율적인 객체들의 공동체</b>로 바라보고 객체를 이용해 시스템을 분할하는 방법이다.
<li> 자율적인 객체란 <b>상태와 행위</b>를 함께 지니며 스스로 자기 자신을 책임지는 객체를 의미한다.
<li> 객체는 다른 객체와 협력한다. 협력 내에서 역할을 수행하며 역할은 관련된 책임의 집합이다.

<p>정말 못 썻지만, 객체는 현실과 달리 자율적이라는 점을 기억하자.</p>
<h2 id="2장-이상한-나라의-객체">2장. 이상한 나라의 객체</h2>
<p>  <strong>상태, 행동, 식별자</strong>는 객체의 중요한 특징이다. 
상태는 동적이다. 예를 들어, 나라는 객체는 유일함이 분명하다. 과거의 나와 지금의 나는 상태가 다르다. (최근 살이 많이 쪘다..) 상태가 다르다고 해서 과거의 나와 지금의 내가 다르진 않다. 이렇듯 객체의 상태는 계속 변화할 수 있고, 상태가 같다고 같은 객체가 아니다! (도플갱어는 나와 다른 존재이다.)
중요한건 객체는 다른 객체의 상태에 접근할 수 없다.객체는 자율적이고, 자신의 상태를 스스로 변경한다.</p>
<p>  어떻게 상태를 변경할까? 바로 <strong>행동</strong>을 통해서다. 앨리스는 음료수를 마셔서 키가 작아진다. 즉 앨리스 객체는 음료수를 마시는 행동을 통해 상태(키)를 변경한다. 추가로, 앨리스가 문을 통과하는 행동을 하기 위해서는 키가 작아야한다. </p>
<ol>
<li>객체의 행동은 상태를 변화시키고</li>
<li>객체의 행동은 상태에 의존한다.</li>
</ol>
<p>그럼 앨리스가 문을 통과하기 위해서는 음료수를 마셔야한다.(키가 작아져야한다)
앨리스 객체는 음료수 객체에게 요청(메세지)를 통해, 협력한다. 이 협력을 통해 앨리스는 상태가 변경되고 (키가 작아짐), 음료수 또한 변경된다 (양이 줄어듦). 객체는 유일하게 메세지를 통해 협력하고 그 결과로 자신의 상태를 스스로 변경한다.</p>
<p>식별자는 id값이다. 대충 이해하니 넘어가자. (귀찮은게 아니다.)</p>
<p>  자 다시 중요한 내용이다. 우리는 Class에 집중하는 실수를 했다. 다음 실수는 뭘까?
객체의 상태에 집중한다는 것이다. 객체를 설계할 때 어떤 상태를 가져야 하는지 생각한다. 그러나 행동보다 상태를 먼저 결정할 경우</p>
<ol>
<li>캡슐화가 저해된다. 상태가 공용 인터페이스에 노출될 확률이 있다.</li>
<li>객체를 협력자가 아닌 섬으로 만든다. 상태를 먼저 고려하면 협력에서 멀어진다.</li>
<li>객체의 재사용성이 저하된다. 마찬가지로 협력을 못하기 때문이다.</li>
</ol>
<p><strong>객체의 행동은 협력에 참여하는 유일한 방법이다.</strong>
즉, 객체지향 설계는 어플리케이션에 필요한 협력을 생각하고, 필요한 행동을 생각하고, 이를 수행할 객체를 선택하는 방식으로 수행해야 한다. 이때 행동에 필요한 정보를 생각하게 되고, 필요한 상태가 결정되는 것이다.</p>
<h3 id="마치며">마치며</h3>
<pre><code>다음 독서에서는 이를 주의하자.</code></pre><li> 매일 조금씩 읽자.
<li> 매일 조금씩 읽었으면, 매일 조금씩 기록하자.
<li> 기록했다면 추가 공부를 찾아보자.
]]></description>
        </item>
    </channel>
</rss>