<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>rlj_su.log</title>
        <link>https://velog.io/</link>
        <description>개발블로그</description>
        <lastBuildDate>Sun, 01 Dec 2024 05:59:33 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>rlj_su.log</title>
            <url>https://velog.velcdn.com/images/rlj_su/profile/e7b9512b-53f3-4ea9-931b-8cf407400215/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. rlj_su.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/rlj_su" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Serialize, 제대로 알고 쓰기]]></title>
            <link>https://velog.io/@rlj_su/Serialize-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%95%8C%EA%B3%A0-%EC%93%B0%EA%B8%B0</link>
            <guid>https://velog.io/@rlj_su/Serialize-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%95%8C%EA%B3%A0-%EC%93%B0%EA%B8%B0</guid>
            <pubDate>Sun, 01 Dec 2024 05:59:33 GMT</pubDate>
            <description><![CDATA[<h2 id="01-자바-직렬화의-대안을-찾아라">01. 자바 직렬화의 대안을 찾아라</h2>
<h3 id="serialize">Serialize</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/174f2e0f-acc7-4f68-bae0-d915628904ef/image.png" alt=""></p>
<h3 id="jsonprotocol-buffer">Json,Protocol buffer</h3>
<table>
<thead>
<tr>
<th>JSON</th>
<th>Protocol Buff</th>
</tr>
</thead>
<tbody><tr>
<td>JavaScript Object Notation<br> 경량데이터 교환 형식</td>
<td>데이터를 인코딩 하는 방법<br>Google에서 구조화된 데이터의 직력 / 역직렬화 위해 개발</td>
</tr>
<tr>
<td>No schema</td>
<td>메세지를 정의하고, 교환하기 위한 규칙 필요</td>
</tr>
<tr>
<td>Test 형식 (key, value쌍)</td>
<td>Binary</td>
</tr>
<tr>
<td>가볍고 다른 직렬화 기술들보다 빠름</td>
<td>Json보다 빠름</td>
</tr>
<tr>
<td>문자열, 숫자, Json객체, 배열, boolean, null<br>(class와 function 지원하지 않음)</td>
<td>폭 넓은 데이터 유형 지원</td>
</tr>
</tbody></table>
<blockquote>
<p>JSON, 때떄로 필요할 때 Protocol Buff 기반을 사용하고, 직렬화는 그만 보내주도록 하자. 새로운 시스템에서 직렬화를 사용할 이유가 없다.</p>
</blockquote>
<h2 id="02-serializable을-구현할지는-신중히-결정하라">02. Serializable을 구현할지는 신중히 결정하라</h2>
<h4 id="warning-point">Warning Point</h4>
<ol>
<li>일단 구현하고 나면 돌이킬 수가 없다 (이미 해당 스펙을 구현하고 있다로 알기 떄문)</li>
<li>버그와 보안 구멍이 생길 위험이 높아진다. (우회 객체 생성)</li>
<li>테스트 범위가 늘어난다. (serilize 검사)</li>
<li>상속용으로 설게뙨 클래스는 대부분 Serializable을 구현하면 안되며, 인퍼테이스 또한 마찬가지</li>
<li>내부 클래스는 직렬화를 구현하지 말아야 한다.</li>
</ol>
<h3 id="readobject-메서드는-방어적으로-사용하라">readObject 메서드는 방어적으로 사용하라</h3>
<ul>
<li>Private 이어야 하는 객체 참조 필드는 각 필드가 가리키는 개체를 방어적으로 복사하라. (immutable class 내의 가변 요소)</li>
<li>모든 불변식으로 검사하여 어긋나는 것이 발견되면 invalidObjectException을 던진다.</li>
<li>Deserialize 후 Object Graph의 유효성을 검사해야 한다면 ObjectInputValidation Interface 사용</li>
<li>직/간접적으로 재정의할 수 있는 메서드는 호출하지 말자</li>
</ul>
<h3 id="readresolve">readResolve</h3>
<pre><code>싱글톤 형태를 유지하기 위함
Deserialize중에 readObject 메서드가 존재하더라도 readResolve 메서드에서 반환한 인스턴스로 대체
(readObject를 통해 만들어진 건 바로 객체 참조가 사라짐)

readResolve를 인스턴스 통제 목적으로 사용한다면 객체 참조 타입 인스턴스 필드는 모두 trasient로 선언</code></pre><h2 id="03-직렬화된-인스턴스-대신-직렬화-프록시-사용을-검토하라">03. 직렬화된 인스턴스 대신 직렬화 프록시 사용을 검토하라</h2>
<h3 id="proxy-pattern">Proxy Pattern</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/76c8bc4a-f456-4a3c-a630-3f98ef177eb6/image.png" alt=""></p>
<h4 id="sample-code">Sample Code</h4>
<pre><code class="language-java">public class Item90{
    public static void main(String[] args){
        Subject proxy = new Proxy();
        proxy.request();
    }
}

interface Subject{ 
    void request(); 
}

class RealSuject implements Subject{
    @Override
    public vodi request(){
        System.out.println(&quot;hello world&quot;);
    }
}

class Proxy implements Subject{

    Subject subject;

    @Override
    public void request(){
        if(subject == null){
            subject = new RealSubject();
            subject.request();
        }
    }
}
</code></pre>
<blockquote>
<p>3자가 확장할 수 없는 클래스라면 직렬화 프록시 패턴을 권장
(불변식을 안정저긍로 직렬화 할 수 있음)
단, 클라이언트가 확장할 수 있는 클래스에는 적용 불가, 순환관계의 클래스에 호출 불가</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[동시성, 위험성과 효율 사이]]></title>
            <link>https://velog.io/@rlj_su/%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9C%84%ED%97%98%EC%84%B1%EA%B3%BC-%ED%9A%A8%EC%9C%A8-%EC%82%AC%EC%9D%B4</link>
            <guid>https://velog.io/@rlj_su/%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9C%84%ED%97%98%EC%84%B1%EA%B3%BC-%ED%9A%A8%EC%9C%A8-%EC%82%AC%EC%9D%B4</guid>
            <pubDate>Thu, 28 Nov 2024 06:42:57 GMT</pubDate>
            <description><![CDATA[<h2 id="01-공유중인-가변-데이터는-동기화에-사용">01. 공유중인 가변 데이터는 동기화에 사용</h2>
<h3 id="공유-데이터">공유 데이터</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/048d0784-f6ec-4dc9-b79e-dc7f9274c6ef/image.png" alt=""></p>
<pre><code class="language-java">public synchronized static void threadRunner() throws InterruptedException{
    int cnt = ThreadCounter.cnt;
    TimeUtil.SECONDS.sleep(2);
    ThreadCountter.cnt = cnt + 1;
}

여러 Thread가 가변데이터를 공유한다면 그 데이터를 읽고 쓰는 동작은 반드시 동기화하라. 
가변 데이터는 단일 Thread에서만 사용하자</code></pre>
<h2 id="02-과도한-동기화는-피하라">02. 과도한 동기화는 피하라</h2>
<h3 id="위험성">위험성</h3>
<pre><code>응답 블가와 안전 실패(safety failure)를 피하려면 동기화 메서드나 동기화 블록 안에서는 
제어를 절대로 클라이언트에 양도하면 안 된다.

Fail fast - 가능한 빨리 실패를 노출하고, 전체 작업을 중지한다.
Safety failure(fail safe) - 실패 시에도 작업을 중단하지 않는다.</code></pre><h3 id="외계인-메서드-alien-method">외계인 메서드 (alien method)</h3>
<pre><code>바깥에서 온 alien, 즉 무슨 일을 할지 알지 못하며, 통제할 수도 없다는 뜻.
통제 불능이기 때문에, alien method가 하는 일에 따라 예외를 일으키거나, 
deadlock이 발생하거나, data가 훼손될 수 있다.</code></pre><h4 id="성능이-떨어지는-이유---동기화-영역에서는-가능한-일을-적게-하자">성능이 떨어지는 이유 - 동기화 영역에서는 가능한 일을 적게 하자</h4>
<h3 id="deadlock-교착상태">Deadlock (교착상태)</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/3dc21b42-28c4-4bed-91ee-4d86cf0e7911/image.png" alt=""></p>
<h4 id="필요조건">필요조건</h4>
<pre><code>1. 상호배제 (Mutual Exclusion)
2. 점유대기 (Hold and Wait)
3. 비선점 (No Preemption)
4. 순환대기 (Circular wait)</code></pre><h2 id="03-스레드-보다는-실행자-태스크-스트림을-애용하라">03. 스레드 보다는 실행자 태스크 스트림을 애용하라</h2>
<h3 id="executor-frameword-실행자-framework">Executor Frameword (실행자 Framework)</h3>
<h4 id="주요기능">주요기능</h4>
<ul>
<li>특정 Task가 완료되기를 기다린다.</li>
<li>Task 모음 중 아무 것 하나<strong>(invokeAny method)</strong> 혹은 모든 태스크 <strong>(invoke All method)</strong>가 완료되기를 기다린다.</li>
<li>Executor service가 종료하기를 기다린다** (awaitTermination method)**</li>
<li>완료된 Task의 결과를 차례로 받는다 <strong>(ExcutorCompletionService)</strong></li>
<li>Task의 Scheduling이 가능하다. <strong>(특정시간 혹인 주기적으로)</strong></li>
</ul>
<h2 id="04-wait와-notify보다는-동시성-유틸리티를-애용해라">04. wait와 notify보다는 동시성 유틸리티를 애용해라</h2>
<h3 id="javautilconcurrent">java.util.concurrent</h3>
<ul>
<li>Executor framework</li>
<li>Concurrent collection</li>
<li>synchronizer</li>
</ul>
<h3 id="synchronizermap-vs-concurrenthashmap">synchronizerMap vs ConcurrentHashMap</h3>
<pre><code>과거 단일 Thread에서는 HashMap, Multi thread에서는 SynchronizedMap을 사용

ConcurrentHashMap은 SynchronizedMap으로 감싼 HashMap이나 Hash 테이블보다 빠름.
(Map 전체에 synchronize lock을 거는 것이 아닌 map을 여러 조각으로 쪼개어 걸기 때문에 효율 증대)</code></pre><h2 id="05-스레드-안전성-수준을-문서화하라">05. 스레드 안전성 수준을 문서화하라</h2>
<h3 id="스레드-안정성이-높은-순">스레드 안정성이 높은 순</h3>
<ul>
<li>불변 (Immutable)</li>
<li>무조건적 스레드 안전 (Unconditionally thread-safe)</li>
<li>조건부 스레드 안전 (conditionally tread-safe)</li>
<li>스레드 안전하지 않음 (not thread-safe)</li>
<li>스레드 적대적 (tread-hostile)</li>
</ul>
<h2 id="06-프로그램의-동작을-스레드-스케줄러의-기대지-말아라">06. 프로그램의 동작을 스레드 스케줄러의 기대지 말아라</h2>
<pre><code>스레드는 당장 처리해야 할 작업이 없다면 실행해서는 안 됨
Thread.yield() : 호출한 메서드를 대기로 돌리고, 동일한 우선순위, 높은 우선순위를 가지는 다른 스레드에게 기회를 양보한다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Exception 과하지도 모자라지도 않게]]></title>
            <link>https://velog.io/@rlj_su/Exception-%EA%B3%BC%ED%95%98%EC%A7%80%EB%8F%84-%EB%AA%A8%EC%9E%90%EB%9D%BC%EC%A7%80%EB%8F%84-%EC%95%8A%EA%B2%8C</link>
            <guid>https://velog.io/@rlj_su/Exception-%EA%B3%BC%ED%95%98%EC%A7%80%EB%8F%84-%EB%AA%A8%EC%9E%90%EB%9D%BC%EC%A7%80%EB%8F%84-%EC%95%8A%EA%B2%8C</guid>
            <pubDate>Thu, 28 Nov 2024 05:56:41 GMT</pubDate>
            <description><![CDATA[<h2 id="01-예외는-진짜-예외-상황에만-사용">01. 예외는 진짜 예외 상황에만 사용</h2>
<pre><code class="language-java">try{
    int i = 0;

    while(true){
        range[i++].climb();    
    }
}catch(ArrayIndexOutBoundsException e){
    //올바르지 않은 코드
}</code></pre>
<h3 id="exception의-상속-구조">Exception의 상속 구조</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/a0e2e563-3894-46e7-bbff-e88343afd366/image.png" alt=""></p>
<h2 id="02-필요없는-검사-예외-사항은-피하라">02. 필요없는 검사 예외 사항은 피하라</h2>
<blockquote>
<p>의미없는 예외 처리는 하지 말자.
검사 예외를 던지는 대신 상태 검사 메서드를 활용하라</p>
</blockquote>
<pre><code class="language-java">//리팩터링 전
try{
    obj.action(args);
}catch (TheCheckedException e){
    ...
}

//리팩터링 후
if(obj.actionPermitted(args)){
    obj.action(args);
}else{
    ...
}</code></pre>
<h2 id="03-표준-예외를-사용하라">03. 표준 예외를 사용하라</h2>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/a295174c-1e8e-4b06-8ea5-fe4075388ce1/image.png" alt=""></p>
<h3 id="메서드가-던지는-모든-예외를-문서화-하라">메서드가 던지는 모든 예외를 문서화 하라</h3>
<pre><code>Checked Exception은 항상 따로 선언하고, Javadoc의 
@throws 태그를 사용해서 문서화 하도록 한다.</code></pre><p><img src="blob:https://velog.io/f0e9bb66-af6c-40a0-9d8b-e1fde01c668e" alt="업로드중.."></p>
<h4 id="예외의-상세-메세지에-실패-관련-정보를-담아라">예외의 상세 메세지에 실패 관련 정보를 담아라</h4>
<h4 id="가능한-한-실패-원자적으로-만들라">가능한 한 실패 원자적으로 만들라</h4>
<pre><code>호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다.  </code></pre><h3 id="예외를-무시하지-말라">예외를 무시하지 말라</h3>
<pre><code>Catch 블럭에서는 반드시 필요한 일을 할 것
만약 예외를 무시하기로 했다면 catch 블록 안에 명확한 이유를 주석으로 남기고, 예외 변수의 이름도 ignored로 바꿔라</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Basic한 프로그래밍 원칙]]></title>
            <link>https://velog.io/@rlj_su/Basic%ED%95%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%9B%90%EC%B9%99</link>
            <guid>https://velog.io/@rlj_su/Basic%ED%95%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%9B%90%EC%B9%99</guid>
            <pubDate>Thu, 28 Nov 2024 05:27:04 GMT</pubDate>
            <description><![CDATA[<h2 id="01-지역변수의-범위를-최소화하라">01. 지역변수의 범위를 최소화하라</h2>
<h3 id="선언과-동시에-초기화하기">선언과 동시에 초기화하기</h3>
<pre><code class="language-java">public void test(){
    int size = 30, start = 1, end = 10000, plust = 3;
    FileOutPutStream fos = null;

    try{

    }catch(Exception e{

    }
}</code></pre>
<h3 id="메서드를-작게-유지하고-한-가지-기능에-집중하기">메서드를 작게 유지하고 한 가지 기능에 집중하기</h3>
<pre><code class="language-java">public void order(){
    1. 카드정보 확인
    2. 업체정보 확인
    3. 주문 가능여부 확인
}
public boolean isAvailablePayment(){}
public boolean isOrderAble(){}</code></pre>
<h2 id="02-전통적인-for문-보다는-for-each를-사용하라">02. 전통적인 for문 보다는 for-each를 사용하라</h2>
<h3 id="전통적인-for문">전통적인 for문</h3>
<pre><code class="language-java">List&lt;String&gt; stringList = new ArrayList&lt;&gt;();

for(int i = 0; i &lt; stringList.size(); i++){
    String s = i.next();
    if(s.equals(&quot;test&quot;)){
        i.remove();
    }
}

//향상된 For문의 한계
stringList.removeIf(s -&gt; s.equals(&quot;test&quot;));</code></pre>
<h4 id="파괴적인-필터링">파괴적인 필터링</h4>
<pre><code>* 순회하면서 선택된 원소를 제거해야한다면 반복자의 remove를 호출해야함
* 자바8 부터는 collection의 removeIf를 사용

변형 : 원소의 값 일부 혹은 전체를 교체해야 한다면 리스트의 반복자나 배열의 인덱스 사용 필요</code></pre><h3 id="문자열-연결-느리니-주의">문자열 연결 느리니 주의</h3>
<pre><code>문자열 n개를 잇는 시간은 n 제곱
성능을 포기하고 싶지 않다면 StringBuilder 사용
Lombok의 @ToString은 + 사용</code></pre><h2 id="03-객체는-인터페이스를-사용해-참조하라">03. 객체는 인터페이스를 사용해 참조하라</h2>
<h3 id="interface-better-than-class">Interface better than Class</h3>
<table>
<thead>
<tr>
<th>Interface</th>
<th>Class</th>
</tr>
</thead>
<tbody><tr>
<td>유연(Flexible하다</td>
<td>형태가 고정적이다.</td>
</tr>
<tr>
<td>어떤 구현체일지 알 수 없다.</td>
<td>클래스가 명확하기 때문에 내부가 어떻게 이루어져 있는 지 알 수 있다.</td>
</tr>
</tbody></table>
<h3 id="적합한-interface가-없는-경우">적합한 Interface가 없는 경우</h3>
<pre><code>* String, BigInteger와 같은 값을 나타내는 Class
* Class 기반으로 작성된 framework가 제공하는 객체들 EX).OutPutStream
Interface에 없는 특별한 메서드를 제공하는 클래스들
Ex). PriorityQueue는 Queue에 없는 Comparator 메서드를 제공</code></pre><h2 id="04-리플렉션보다는-인터페이스를-사용하라">04. 리플렉션보다는 인터페이스를 사용하라</h2>
<h3 id="reflection이란">Reflection이란</h3>
<pre><code>실행중인 Java 프로그램이 자체적으로 검사하거나, 수정할 수 있는 기능

예를 들어 Class가 모든 member의 이름을 가져와 출력할 수 있다.
즉 Class의 Structure를 개발자가 확인할 수 있고 값을 가져오거나 메서드를 호출할 수 있음
(Spring, Hibernate, Jackson등)</code></pre><p><img src="https://velog.velcdn.com/images/rlj_su/post/5a00881e-330f-4326-820a-7e12f5a789f9/image.png" alt=""></p>
<h3 id="단점">단점</h3>
<ul>
<li>컴파일타임 타입 검사가 주는 이점을 누릴 수 없음</li>
<li>코드가 지저분해지고 장황해지며 성능이 떨어짐</li>
</ul>
<h5 id="리플렉션을-사용할-때에는-인스턴스-생성에만-쓰고-인스턴스는-인터페이스나-상위-클래스를-참조해-사용">리플렉션을 사용할 때에는 인스턴스 생성에만 쓰고, 인스턴스는 인터페이스나, 상위 클래스를 참조해 사용</h5>
<h3 id="최적화는-신중히-하라">최적화는 신중히 하라</h3>
<h4 id="빠른-프로그램-보다는-좋은-프로그램을-작성">빠른 프로그램 보다는 좋은 프로그램을 작성</h4>
<pre><code>구현의 문제는 최적화로 해결할 수 있지만, 최적화를 위해 아키텍쳐를 손장시키면 돌이킬 수 없다.

성능을 제한하는 설계를 피하라</code></pre><h2 id="05-일반적으로-통용되는-명명-규칙을-따르라">05. 일반적으로 통용되는 명명 규칙을 따르라</h2>
<h3 id="package-명명-규칙">Package 명명 규칙</h3>
<pre><code>* 외부에서 사용된다면 인터넷 도메인 역순 (ex. com.google)
* 각 요소는 8글자 이하의 짧은 단어 사용 (ex. GlobalPositioningSystem -&gt; gps등)
* 필요할 경우 계층을 나누어서 (ex. deliveryDriver -&gt; delivery.driver</code></pre><h3 id="class--interface-명명-규칙">Class &amp; interface 명명 규칙</h3>
<pre><code>* 하나 이상의 단어 (passenger, delivertDriver)
* 널리 통용되는 줄임말을 제외하면 줄여 쓰지 않는다.
* 약자의 경우 첫글자 대문자 or 전체를 대문자 (보통은 첫문자 대글자)</code></pre><h3 id="method--field의-명명-규칙">Method &amp; Field의 명명 규칙</h3>
<pre><code>* 첫 글자는 소문자
* 상수 필드는 전체 대문자 (static final)
* 지역변수는 약어를 조금 더 적극적으로 사용해도 무방</code></pre><h3 id="문법-규칙">문법 규칙</h3>
<pre><code>* 단순명사 or 명사구
* 객체를 생성할 수 있는 클래스의 이름을 복수로 (PatternUtils)
* Interface는 able or ible로 끝나는 형용사

* 동작을 수행하는 메서드는 동사나 (목적어를 포함한 동사구) (ex. append, add)

* 반환타입이 Boolean, void가 아니거나, 
해당 인스턴스의 속성을 반환한다면 get ~을 보통 사용 (필수는 아님)
* 객체의 타입을 바꾼다면 to ~ (toArray, toList, toString)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Effective Method 주의사항]]></title>
            <link>https://velog.io/@rlj_su/Effective-Method-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD</link>
            <guid>https://velog.io/@rlj_su/Effective-Method-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD</guid>
            <pubDate>Wed, 27 Nov 2024 07:11:27 GMT</pubDate>
            <description><![CDATA[<h2 id="01-매개변수가-유효한지-검사하라">01. 매개변수가 유효한지 검사하라</h2>
<h3 id="매개변수가-유요한지-검사하는-기준">매개변수가 유요한지 검사하는 기준</h3>
<pre><code class="language-java">//상황 : 장바구니에 아이템 추가
@RestController
public class ParameterCheckController{
    @Data
    clss AddItemForm{
        private long itemId;
        private int count;
    }

    @PostMapping(valeu = &quot;/{userId}/add&quot;)
    public ResonseEntity getBasketInfo(
            @PathVariable long userId,
            @RequestBody AddItemForm addItemForm){
        .....        
    }
}


//매개변수 검사하는 위치는 반드시 메서드 시작부분을 권장
public static double calculateUserPoint(
        long userId,
        long carId,
        List&lt;OrderItemInfoVo&gt; orderItemInfoVoList){
            //유저 등급 조회
            //카드 정보 조회
        }
)</code></pre>
<h4 id="어디서-호출되는지가-중요-검사-규칙도-tpo가-중요">어디서 호출되는지가 중요. 검사 규칙도 TPO가 중요</h4>
<pre><code>* 공개된 API일 수록 parameter 검사 기준은 엄격하게 이루어져야 함
* 내부에서 소화될 코드라면 공개된 API만큼은 아닐 지라도, 서비스에 영향이 크게 있거나, 
여러 이슈들로 예측되지 않은 값이 들어올 가능성이 있다면 검사하는 것이 좋음.</code></pre><h2 id="02-메서드-시그니처를-신중히-설계하라">02. 메서드 시그니처를 신중히 설계하라</h2>
<h3 id="편의-method-ex-util-class-소속의-method-와-같은-를-너무-많이-만들지-말자">편의 method (ex. Util Class 소속의 method 와 같은) 를 너무 많이 만들지 말자</h3>
<pre><code>정말 자주 쓰일 때에만 편의 method를 제공해야 한다.
확신이 생기지 않는다면 private로 쪼개 놓은 후 차후에 다른 class에서의 니즈가 생길 경우 
리팩토링 해도 늦지 않다</code></pre><h3 id="parameter-목록은-짧게">Parameter 목록은 짧게</h3>
<pre><code>4개 이하 권장. 특히 같은 타입 여러 개는 작성자도 혼란스럽게 한다.

1. 만든 세머드가 너무 장황하였을 확률이 있다.
2. Vo (Value Object) 를 사용한다.</code></pre><pre><code class="language-java">class UserVo{
    private Long id;
    private int age;
    private int footSize;
      private float weight;
    private float height;
}
...
public static void expandParam(long id, int age, int footSize, 
int weight, int height){
}</code></pre>
<h2 id="03-다중정의는-신중히-사용하라">03. 다중정의는 신중히 사용하라</h2>
<h3 id="overroding의-위험함을-피하는-방법">Overroding의 위험함을 피하는 방법</h3>
<p>매개변수 같은 Overroding은 만들지 않는 것을 추천</p>
<p>만약 만들어야 한다면 차라리 메서드 이름을 다르게 짓는 것을 보수적으로 권장</p>
<pre><code class="language-java">public List&lt;E&gt; sort(ArrayList&lt;E&gt; arrayList){
    //1번 알고리즘
    return arrayList;
}
public List&lt;E&gt; sort(LinkedList&lt;E&gt; arrayList){
    //2번 알고리즘
    return arrayList;
}
public List&lt;E&gt; sortFromArrayList(ArrayList&lt;E&gt; arrayList){
    //3번 알고리즘
    return arrayList;
}
</code></pre>
<h2 id="04-null이-아닌-빈-컬렉션이나-배열을-반환하라">04. null이 아닌 빈 컬렉션이나 배열을 반환하라</h2>
<pre><code>에러 처리가 힘들다. (받는 쪽에서 List의 null 처리를 별도로 해야 한다.)

조금 더 유연하게 생각하자면 empty List or array는 null이 아니다. 단지 내부가 비었을 뿐

Collections.emptyList, Collections.emptyList는 불변 객체로 존재하여 성능 걱정을 안 해도됨</code></pre><pre><code class="language-java">public class Collections{
    public static final list EMPTY_LIST = new Collections.EmptyList();
}</code></pre>
<h3 id="api의-json-response는-array-or-null">API의 json response는 array? or null?</h3>
<pre><code class="language-java">@GetMapping
public List&lt;String&gt; getNameList(){
    //이름의 리스트가 비었으면
    return Collection.EmptyList();
}
//항상 []를 null 대신 권장하는 편
//리스트가 없는 것이 아닌, 리스트가 비었다고 생각하자
//특정 리스트를 반환해야 하는 Get API의 호출은 정상적으로 이루어졌으나, 그 response가 빈 것일 뿐이다.</code></pre>
<h2 id="05-옵셔널-반환은-신중히-하라">05. 옵셔널 반환은 신중히 하라</h2>
<h3 id="optional의-올바른-사용">Optional의 올바른 사용</h3>
<pre><code class="language-java">Optional&lt;Laptop) optionalLaptop = laptopResponsitory.findById(id);
Laptop lpatop = optionalLaptop.orElse(null); //좋지 못함</code></pre>
<h4 id="기본값">기본값</h4>
<pre><code class="language-java">값이없을 경우 기본값을 사용하기 위한 용도

//없을 경우 기본값 0을 리턴
public int maxPositiveIntegerValue(List&lt;Integer&gt; integerList){
    return getMaxInteger(integetLisr).orElse(0);
}

private OptionalInt getMaxInteger(List&lt;Integer&gt; integerList){
    retur integerList.stream().mapToInt(Integet::intValue)
    .filter(integer -&gt; integer &gt; 0).max();
}</code></pre>
<h4 id="예외">예외</h4>
<pre><code class="language-java">//JpaRepository의 일부
Optional&lt;T&gt; findById(Id id);

명확히 id 기반으로 찾고, 이 값이 없을 경우 에러라고 가정할 때 원하는 예외를 던지기에 적합</code></pre>
<h3 id="optional-t-가-득이-아닌-경우">Optional&lt; T&gt; 가 득이 아닌 경우</h3>
<ul>
<li>Cotainer type(컬렉션, 배열 등..)</li>
<li>Boxing된 기본 타입 (OptionallInt 같은 것들을 사용)</li>
<li>하단의 코드 처럼, Optional을 사용한다면 null을 반환하지 말자(취지와 맞지 않음)</li>
</ul>
<pre><code class="language-java">public ItemInfo getIteminfo(){
    return itemInfoRepository.findById(1L).orElse(null);
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Lamda의 우아함과 Stream의 주의사항]]></title>
            <link>https://velog.io/@rlj_su/Lamda%EC%9D%98-%EC%9A%B0%EC%95%84%ED%95%A8%EA%B3%BC-Stream%EC%9D%98-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD</link>
            <guid>https://velog.io/@rlj_su/Lamda%EC%9D%98-%EC%9A%B0%EC%95%84%ED%95%A8%EA%B3%BC-Stream%EC%9D%98-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD</guid>
            <pubDate>Wed, 27 Nov 2024 07:01:56 GMT</pubDate>
            <description><![CDATA[<h2 id="01-익명-클래스보다는-람다를-사용하라">01. 익명 클래스보다는 람다를 사용하라</h2>
<h3 id="익명-함수를-람다로-변환">익명 함수를 람다로 변환</h3>
<pre><code class="language-java">//익명 함수
List&lt;String&gt; words = List.of(&quot;사과&quot;, &quot;배&quot;);
Collections.sort(words, new Comparator&lt;&gt;(){
    public int compare(String o1, String o2){
        return Integer.compare(o1.legth(), o2.legth());
    }
});

//Lamda
Collections.sort(words, Comparator.compareingInt(s -&gt; s.length()));
Collections.sort(words, Comparator.compareingInt(String::length));
word.sort(Comparator.comparingInt(String::length));
</code></pre>
<blockquote>
<p>람다를 사용할 수 있는 자바 버전이면, 타입 추론 또한 가능하기 때문에 매개변수 타입을 가능하면 생략한다.
익명 함수는 이제 (함수형 인터페이스가 아닌) 타입의 인스턴스를 만들 때만 사용</p>
</blockquote>
<h2 id="02-람다보다는-메서드-참조를-사용">02. 람다보다는 메서드 참조를 사용</h2>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/38db5e28-4527-4f3c-854e-db46f3a67c41/image.png" alt=""></p>
<h5 id="항상-메서드-참조가-정답은-아님">항상 메서드 참조가 정답은 아님</h5>
<pre><code class="language-java">//ide 권장
service.excute(GoshThisClassNameIsHumongous::action);

//람다 (훨씬 간결하다)
service.excute(() -&gt; action);</code></pre>
<h2 id="03-표준-함수형-인터페이스를-사용하라">03. 표준 함수형 인터페이스를 사용하라</h2>
<h3 id="funtaionalinterface">@FuntaionalInterface</h3>
<pre><code>* @Override와 비슷
* 람다형으로 선언되었음을 문서로 알림
* 해당 인터페이스가 추상 메서드를 하나만 가지고 있어야 컴파일 가능
* 다른 의도로 사용되는 것을 막음</code></pre><h3 id="대표적인-기본-함수형-인터페이스">대표적인 기본 함수형 인터페이스</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/5d44be42-c0fe-4c0d-8299-4deccf5c231f/image.png" alt=""></p>
<h2 id="04-스트림을-주의해서-사용하라">04. 스트림을 주의해서 사용하라</h2>
<h3 id="스트림을-사용해야-하지-말아야할-때">스트림을 사용해야 하지 말아야할 때</h3>
<ul>
<li>return (메서드 빠져나가기), break &amp; continue (반복문 종료 or 특정 한 번 건너 뛰기) 같은 행위가 필요할 때</li>
<li>스트림 내부에서 밖의 지역 변수를 수정해야할 때 (금지)</li>
</ul>
<pre><code class="language-java">int a = 1;

List.of(&quot;사과&quot;, &quot;배&quot;).stream().filter(str -&gt; {
    if(str.equals(&quot;배&quot;)) a = 2;

    return true;
});    </code></pre>
<h3 id="스트림을-사용해야할-때">스트림을 사용해야할 때</h3>
<pre><code class="language-java">//원소의 시퀀스 일괄 변화
List&lt;ItemInfo&gt; -&gt; List&lt;String&gt;
//시퀀스 필터링
.filter();
//시퀀스를 하나의 연산을 통해 결합할 때 (더하기, 연결, 최솟값 등)
mapToInt().sum();
//컬렉션 모으기
.collect(Collectors.toList());
//시퀀스에서 특정 조건을 만족하는 원소 찾기
.findFirst();</code></pre>
<h3 id="구현-차이">구현 차이</h3>
<pre><code class="language-java">//반론 방식
public List&lt;Integer&gt; minFice(List&lt;Integer&gt; integerList){
    List&lt;Integer&gt; returnList = new ArrayList&lt;&gt;();
    List&lt;Integer&gt; copiedList = new ArrayList&lt;&gt;(integerList);
    Collections.sort(copiedList);
    int cnt = 0;

    for(int i = 0; i&lt;copiedList.size(); i++){
        if(i==5) break;

        returnList.add(copiedList.get(i));
    }
    return returnList;
}

//스트림 방식
public List&lt;Integer&gt; minFice(List&lt;Integer&gt; integerList){
    return integerList.stream().sorted().limit(5)
    .collect(Collectors.toList());
}</code></pre>
<h2 id="05-스트림에서는-부작용-없는-함수를-사용하라">05. 스트림에서는 부작용 없는 함수를 사용하라</h2>
<h3 id="strema은-순수-함수여야-한다">Strema은 순수 함수여야 한다.</h3>
<h4 id="순수함수란">순수함수란?</h4>
<pre><code>오직 입력만이 결과에 영향을 준다.
다른 가변 상태를 참조하지 않으며, 함수는 다른 상태를 변경시키지 않는다.</code></pre><pre><code class="language-java">//Stream 코드를 사용했을 뿐, 함수형 코드도 아니고, 단순 반복문에 불과하다.
public static List&lt;integer&gt; integerSort(List&lt;Integer&gt; integerList){
    List&lt;Integer&gt; returnList = new ArrayList&lt;&gt;();
    integerList.stream().sorted().forEach(num -&gt; {
        returnList.add(num);
    });

    return returnList;
}

//올바른 코드
public static List&lt;integer&gt; integerSort(List&lt;Integer&gt; integerList){

    return integerList.stream().sorted().collect(Collector.toList());
</code></pre>
<h3 id="tomap-예제">toMap 예제</h3>
<pre><code class="language-java">@Data
@AllArgsConstructor
class User{
    private Long id;
    private String name;
    private int age;
    private float height;
}

...
public static Map&lt;Long, String&gt; getHeightGroup(List&lt;User&gt; userList){
    return userList.stream().collect(Collectors.toMap(
        User::getId, User::getName));
}</code></pre>
<h2 id="06-반환-타입으로는-스트림과-컬렉션이-낫다">06. 반환 타입으로는 스트림과 컬렉션이 낫다.</h2>
<h3 id="strema과-iterable-사이의-어댑터">Strema과 Iterable 사이의 어댑터</h3>
<pre><code class="language-java">public static &lt;E&gt; Iterable&lt;E&gt; iterableOf(Stream&lt;E&gt; stream){
    return stream::iteratore;
}

public static &lt;E&gt; Stream&lt;E&gt; streamOf(Iterable&lt;E&gt; iterable){
    return StreamSupport.stream(iterable.spliterator(), flase);
}

//Stream pipeline에서만 사용한다 : response Stream
//반복문에서만 쓰일 걸 안다 : response Iterable</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Enum과 Annotation의 Effective한 사용]]></title>
            <link>https://velog.io/@rlj_su/Enum%EA%B3%BC-Annotation%EC%9D%98-Effective%ED%95%9C-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@rlj_su/Enum%EA%B3%BC-Annotation%EC%9D%98-Effective%ED%95%9C-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Wed, 27 Nov 2024 06:03:52 GMT</pubDate>
            <description><![CDATA[<h2 id="01-int-상수-대신-enum을-사용하라">01. int 상수 대신 enum을 사용하라</h2>
<h3 id="구별을-위해서는-enum을-사용하자">구별을 위해서는 enum을 사용하자</h3>
<pre><code class="language-java">//간단한 형태의 enum
@AllArgsConstructor
@Getter
public enum Fruit{
    APPLE(1000, 20, &quot;RED&quot;),
    PEACH(2000, 9, &quot;YELLO&quot;);

    private final int price;
    private final int box;
    private final String color;

    public int boxPrice(){
        return price * box;
    }
}</code></pre>
<h3 id="fromstring-method">fromString method</h3>
<pre><code class="language-java">private static final Map&lt;STring, Fruit&gt; stringToEnum = Stream.of(values())
.collect(Collectors.toMap(Objects::toString, e-&gt;e));
public static Optional&lt;Fruit&gt; fromString(String symbol){
    return Optional.ofNullable(StringToEnum.get(Symbol));
}
//타 서버에서 불확실성을 가지고 enum이 넘어오거나 DB등의 값을 처리할 때 등등 유용할 수 있다.</code></pre>
<h2 id="02-ordinal-method-대신-instant-field를-사용하라">02. ordinal method 대신 instant field를 사용하라</h2>
<h3 id="enum의-ordinal-vs-instant-filed">Enum의 Ordinal vs instant Filed</h3>
<pre><code class="language-java">//ordinal() 사용
public enum Ensemble{
    SOLO, DUEL, TRIO, QUARTET;

    public int numberOfMusicians(){
        return ordinal() + 1;
    }
}

//instatnt Filed 사용
@AllArgsConstructor
public enum Ensemble{
    SOLO(1),DUEL(2),TRIO(3),
    QUARTET(4),TRIPLE_QUARTET(12);

    private final int numberOfMusicians;

    public int numberOfMusicians(){
        return ordinal() + 1;
    }
}</code></pre>
<blockquote>
<p>Enum에서 ordinal()이라는 enum의 번호를 변환해 주는 메서드가 있다.
하지만 경우에 따라 넘버링을 bit로 하는 경우도 있고 코드를 잘못 건드리면 겉잡기 힘들다.
그러니 인스턴트 필드에 값을 저장해서 사용하는 것이 좋다.</p>
</blockquote>
<h2 id="03-bit-field-대신-enumset을-사용하라">03. bit field 대신 Enumset을 사용하라</h2>
<h3 id="bit-field로-구현한-style-code를-가져오는-util-class">Bit field로 구현한 style code를 가져오는 Util class</h3>
<pre><code class="language-java">public class TextStyleUtil{
    public static final int STYLE_BOLD = 1 &lt;&lt; 0; //1
    public static final int STYLE_ITALIC = 1 &lt;&lt; 1; //2
    public static final int STYLE_UNDERLINE = 1 &lt;&lt; 2 //4
    public static final int STYLE_STRIKETHROUGH = 1 &lt;&gt; 3 // 8
}</code></pre>
<h3 id="enumset으로-구현한-style-code-가져오기">Enumset으로 구현한 style code 가져오기</h3>
<pre><code class="language-java">@Getter
@AllArgsConstructor
public enum TestStyle{
    BOLD(1), ITALIC(2), UNDERLINE(4), STRIKETHROUGH(8);

    private final int code;

    public static int getStyleCode(Set&lt;TestStyle) styles){
        return style.stream().mapToInt(TestStyle::getCode).sum();    
    }
}

...
int styleCode = TextStyle.getStyleCode(Enumset.of(TextStyle.BOLD,TextStyle.ITALIC));</code></pre>
<h2 id="04-ordinal-indexing-대신-enummap을-사용">04. ordinal indexing 대신 EnumMap을 사용</h2>
<h3 id="ordinal을-사용한-좋지-못한-코드">ordinal()을 사용한 좋지 못한 코드</h3>
<h4 id="요구사항--식묵들을-배열-하나로-관리-생애주기로-묶는다">요구사항 : 식묵들을 배열 하나로 관리, 생애주기로 묶는다.</h4>
<pre><code class="language-java">Set&lt;Plant&gt;[] plantsByLifeCycle = 
(Set&lt;Plant&gt;[]) new Set[Plant.LifeCycle.values().legth];

for(int i = 0; i&lt;plantByLifeCycle.length;i++){
    plantByLifeCycle[i] = new HashSet&lt;&gt;();    
}
for(Plant p : garden){
    plantsByLifeCycle[p.lifecycle.ordinal()].add(p);
}</code></pre>
<h3 id="배열-대신-enummap-변경">배열 대신 EnumMap 변경</h3>
<pre><code class="language-java">Map&lt;Plant.LifeCycle, Set&lt;Plant&gt; plantsByLifeCycle =
new EnumMap&lt;&gt;(Plant.LifeCycle.clas);
for(Plane.LifeCycle lc : Plant.LifeCycle.values()){
    plantsByLifeCycle.put(lc, new HashSet&lt;&gt;());
}

for(Plant p : graden){
    plantsByLifeCycle.get((plantsByLifeCycle)).add(p);
}

...
//EnumMap의 Put 내부
public V put(K ket, V value){
    typeCheck(key);

    int index = ket.ordinal();
    Object oldValue = vals[index];
    vals[index] = maskNull(value);
    if(oldValue == null) size ++;

    return unmaskNull(oldValue);
}</code></pre>
<h2 id="05-명명-패턴보다-annotation을-사용하라">05. 명명 패턴보다 Annotation을 사용하라</h2>
<h3 id="명명패턴">명명패턴</h3>
<p>jpa의 custom method의 경우 또한 postfix가 impl로 고정 되어 있다.</p>
<pre><code>The most important part of the class name that 
corresponds to the fragment interface is the Impl postifx.</code></pre><h3 id="명명-패턴의-문제">명명 패턴의 문제</h3>
<pre><code>* 오타에 취약
* 올바른 프로그램 요소에마서만 사용되라는 법이 없음
* 프로그램 요소를 매개 변수로 전달할 방법이 없다</code></pre><h3 id="annotation">Annotation</h3>
<h4 id="예제">예제</h4>
<pre><code class="language-java">@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test{
}</code></pre>
<h4 id="annotation-의-속성">annotation 의 속성</h4>
<pre><code class="language-java">public enum RetentionPolicy{
    SOURCE, // 컴파일러에 의해 무시
    CLASS, // 런타임 시 무시 (컴파일 시에만 체크)
    RUNTIME // 런타임 시에도 확인
}

public enum ElementType{
    Type,
    FIELD,
    METHOD,
    PARAMETER,
    CONSTRUCTOR.
    LOCAL_VARIABLE,
    ...
    ...
    MODULE
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Generic method와 주의사항]]></title>
            <link>https://velog.io/@rlj_su/Generic-method%EC%99%80-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD</link>
            <guid>https://velog.io/@rlj_su/Generic-method%EC%99%80-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD</guid>
            <pubDate>Wed, 27 Nov 2024 05:00:18 GMT</pubDate>
            <description><![CDATA[<h2 id="01-제네릭-메서드로-만들어라">01. 제네릭 메서드로 만들어라</h2>
<h3 id="type-safe한-generic-method">Type safe한 Generic Method</h3>
<pre><code class="language-java">List&lt;String&gt; stringList = List.of(&quot;T1&quot;,&quot;T2&quot;,&quot;T3&quot;);

static&lt;E&gt; List&lt;E&gt; of (E e1, E e2, E e3) {
    return new ImmutableCollections.ListN&lt;&gt;(e1, e2, e3);
}

private static UnaryOperator&lt;Object&gt; IDENTIFY_FN = (t) -&gt; t;

public static&lt;T&gt; UnaryOperator&lt;T&gt; identityFunction(){
    return (UnaryOperator&lt;T&gt;) IDENTIFY_FN; (O)
    return IDENTIFY_FN; (X)
    //object는 제레닉으로 캐스팅죄디 않음. 유형이 다르기 때문에 에러발생
}</code></pre>
<h3 id="type-한정">Type 한정</h3>
<p>Method의 parameter 타입을, interface의 Type으로 한정한다.</p>
<pre><code class="language-java">interface Comparable&lt;t&gt;{
    int compare(T o);
}</code></pre>
<blockquote>
<p>genric 타입과 같이 형변환 해야하는 method보다 generic method가 더 안전하고, 심지어 사용허기도 쉽다. (형변환 해야하는 메서드는 generic으로 만들자)</p>
</blockquote>
<h2 id="02-한정적-와일드카드를-사용해-api-유연성을-높여라">02. 한정적 와일드카드를 사용해 API 유연성을 높여라</h2>
<h3 id="bounded-wildcard-설명-예제-코드">Bounded Wildcard 설명 예제 코드</h3>
<pre><code class="language-java">public class Stack&lt;E&gt;{
    public static final int DEFAULT_SIZE = 20;
    private int size;
    private E[] elements;
    public Stack(){ elements = (E[]) new Object[DEFAULT_SIZE]; size = 0;}

    public E pusg(E item){
        elements[++size] = item;
        return item;
    }

    public void pushAll(Iterable&lt;E&gt; src){
        for (E e : src){
            push(e);
        }
    }
}


//컴파일 에러 : 불공변이기 때문에 (invariant) 자가 타입만 허용
Stack&lt;Number&gt; numberStack = new Stack&lt;&gt;();
Iterable&lt;Integer&gt; integers = List.of(1,2);
numberStack.pushAll(integers);</code></pre>
<h4 id="해결책">해결책</h4>
<pre><code class="language-java">//제네릭 &lt;E&gt; 를 extends한 와일드카드로 입력
public void pushAll(Iterable&lt;? extends E&gt; src){
    for (E e: src)
        push(e);
}</code></pre>
<h2 id="03-제네릭과-가변인수를-함께-쓸-떄는-신중하라">03. 제네릭과 가변인수를 함께 쓸 떄는 신중하라</h2>
<h3 id="variadic-arguments-가변-인수">Variadic Arguments (가변 인수)</h3>
<p>Mehtod의 arguments의 개수를 클라이언트가 조절할 수있게 한다.
또한 반드시 한 개의 가변 인수만을 사용해야 하며 맨 마지막 Arguments로 사용해야 한다.</p>
<pre><code class="language-java">static void mergeAll(List&lt;String&gt;.. stringList){}
//위의 코드는 컴파일 불가, 가능하게하려면
static void mergeAll(List&lt;String&gt; one, List&lt;String, two){
    List&lt;String&gt;[] stringLists = {one, two};
}</code></pre>
<h3 id="heap-pollution오염">Heap Pollution(오염)</h3>
<pre><code class="language-java">List[] test = {List.of(1), List.of(2)}; // True
List&lt;Integer&gt;[] test2 = {List.of(1), List.of(2)}; // Error

안전하기 위해선 제네릭 배열에 아무것도 저장하거나 덮어쓰지 말고, 배열의 참조를 밖으로 노출시키지 말아야 한다.</code></pre>
<h4 id="remove-warning">Remove Warning</h4>
<ul>
<li>SuppressWarnings (컴파일 경고 숨기기)</li>
<li>SafeVarargs (메서드의 타입 안정성을 보장함)</li>
</ul>
<h4 id="주의-사항">주의 사항</h4>
<blockquote>
<p>제네릭 배열에 아무것도 저장하거나 덮어쓰지말고, 배열의 참조를 밖으로 노출시키지 말아야 한다.
제네릭과 가변인수를 함께 사용할 때에는 궁합이 잘 맞지 않으니 조심하자</p>
</blockquote>
<h2 id="03-타입-안정-이종-컨테이너를-고려하라">03. 타입 안정 이종 컨테이너를 고려하라</h2>
<h3 id="타입-안정-이종-컨테이너">타입 안정 이종 컨테이너</h3>
<pre><code class="language-java">//Key 가 wildcard Type
public class Favorites{
    private Map&lt;Class&lt;?&gt;, Object&gt; favorites = new HashMap&lt;&gt;();
    public &lt;T&gt; void putFavorite&lt;Class&lt;T&gt; type, T instance){
        favorites.put(Objects.requireNonNull(type), instance);
    }
    public &lt;T&gt; T getFavorite(Class&lt;T&gt; type){
        return type.cast(favorites.get(type));
    }
}
//Get할 때 요청받은 타입의 value를 찾아 cast 하여 response함</code></pre>
<h3 id="동적-형-변환">동적 형 변환</h3>
<pre><code class="language-java">public &lt;T&gt; void putFavorite(Class &lt;T&gt; type, T instance){
    favorites.put(Objects.requireNonNull(type), type.cast(instance));
}

Favorites favorites = new Favorites();
Game game = favorites.putFavorite(Game.class, new Game());

//HashSet&lt;Integer&gt;에 string을 넣는 것 같은 문제를 막을 수 있다.</code></pre>
<h3 id="슈퍼-타입-토큰-parameterizedtypereference">슈퍼 타입 토큰 (ParameterizedTypeReference)</h3>
<pre><code class="language-java">//TypeReference, ParameterizedTypeRefernece 등이 있다.
RestTemplate re = enw RestTemplate();
List&lt;String&gt; rest = re.exchange(&quot;http://localhost:8080&quot;, HttpMethod.GET, null, new ParameterizedTypeReference&lt;List&lt;String&gt;&gt;()
{}).getBodt();</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Generic으로 만들어 사용하기]]></title>
            <link>https://velog.io/@rlj_su/Generic%EC%9C%BC%EB%A1%9C-%EB%A7%8C%EB%93%A4%EC%96%B4-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@rlj_su/Generic%EC%9C%BC%EB%A1%9C-%EB%A7%8C%EB%93%A4%EC%96%B4-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 26 Nov 2024 10:42:52 GMT</pubDate>
            <description><![CDATA[<h2 id="01-raw-type은-사용하지-마라">01. raw type은 사용하지 마라</h2>
<h3 id="만약-type-parameter가-없다면">만약 type parameter가 없다면</h3>
<pre><code class="language-java">//(비권장 코드)
List test = new ArraysList&lt;&gt;();
tset.add(&quot;no1&quot;);
test.add(1);

//unbounded wildcard type
private int add(List&lt;?&gt; s1){
    s1.add(1); //error
    return 1;
}</code></pre>
<h3 id="명확하게-타입-추론이-가능하게-하자">명확하게 타입 추론이 가능하게 하자</h3>
<p>그렇지 않다면 런타임 시 예외가 발생할 수 있다.</p>
<p>List&lt; Objct &gt; 는 명확하게 내가 Objct라는 타입을 제시한 것임
하단과 같이 merge해 버린다면, 다른 타입이 들어왔을 때 문제가 생김</p>
<pre><code class="language-java">//잘못된 코드
static List listMerge(List a, List b){
    List c = new ArrayList();
    c.addAll(a);
    c.addAll(b);

    return c;
}</code></pre>
<h3 id="generic-class--generic-interface">Generic Class / Generic Interface</h3>
<pre><code class="language-java">List&lt;String&gt; test = new ArraysList&lt;&gt;(); 

//List : Generic Interface
public interface List&lt;E&gt; extends Collecntion&lt;E&gt; {}

//ArrayList : Generic class
public class ArrayList&lt;E&gt; extends AbstractList&lt;E&gt;
    implments List&lt;E&gt;, RadomAccess, Cloneable, java.io.Serializable</code></pre>
<blockquote>
<p>예외적인 케이스를 제외하면 명확히 타입을 명시하도록 하자.</p>
</blockquote>
<h2 id="02-비검사-경고를-제거하라">02. 비검사 경고를 제거하라</h2>
<h3 id="complier가-보내는-warning을-제거하라">Complier가 보내는 warning을 제거하라</h3>
<p>Warning이 print 된다는 것은 말 그대로 경고를 보내는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/cf51ba68-afdc-46bc-a95a-f0887ac5080a/image.png" alt="">
만약 안전하다고 확신할 수 있으면 @SupperWarnings(&quot;unckecker&quot;)를 통해 경고를 숨기자</p>
<h3 id="단점">단점</h3>
<pre><code>* 서버의 치명적인 에러 감지 불가
* 잘못 작성한 코드 감지 불가
* 내가 만든 많은 waning을 통해, 정작 봐야 할 중요한 warning을 볼 수 없음</code></pre><h2 id="03-배열-대신-리스트를-사용하라">03. 배열 대신 리스트를 사용하라</h2>
<h3 id="배열-보다는-제네릭">배열 보다는 제네릭</h3>
<pre><code class="language-java">//Runtime Error
Object[] objects = new Long[1];
objects[0] = &quot;test&quot;;

//Compile Error
List&lt;Object&gt; objectList = new ArrayList&lt;Long&gt;();</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Interface와 Class 설계 원칙]]></title>
            <link>https://velog.io/@rlj_su/Interface%EC%99%80-Class-%EC%84%A4%EA%B3%84-%EC%9B%90%EC%B9%99</link>
            <guid>https://velog.io/@rlj_su/Interface%EC%99%80-Class-%EC%84%A4%EA%B3%84-%EC%9B%90%EC%B9%99</guid>
            <pubDate>Tue, 26 Nov 2024 10:23:52 GMT</pubDate>
            <description><![CDATA[<h2 id="01-abstract-class-보다는-interface를-우선하라">01. Abstract class 보다는 interface를 우선하라</h2>
<h3 id="extends-vs-implements">Extends vs Implements</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/550d44b2-76fa-4a88-8a3b-a4aa33b7d8a8/image.png" alt=""></p>
<pre><code class="language-java">//extends는 하나만 가능
public class Sub extends Super implements Serializable, Cloneable{}
public interface Sub extends Serializable, Cloneable{}</code></pre>
<h3 id="ex-배달-앱">Ex) 배달 앱</h3>
<pre><code class="language-java">public class Restaurant extends Delibary {}

//포장 주문의 필요성이 생겼지만 한 class 밖에 상속 불가
public class Restaurant implements Delibariable, Packable{}

//interface default method
public interface Packable{
    dafualt void packOrder(){
        System.out.println(&quot;포장 주문이 들어왔습니다.&quot;);
    }
}</code></pre>
<h2 id="02-인터페이스는-타입을-정의하는-용도로만-사용하라">02. 인터페이스는 타입을 정의하는 용도로만 사용하라</h2>
<h3 id="constant-static-final은-ani-pattern">Constant static final은 ani pattern</h3>
<p>클래스 내부에서 사용하는 상수는 내부 구현에 해당된다.
오히려 사용자에게 혼란을 줄 수 있다.
차라리 클래스에 static final로 추가하는 것이 더 낫다.</p>
<pre><code class="language-java">public class OrderService{
    public static final double SECOND_TO_MIN = 60;
}

//만약 여러 곳에서 사용해야할 값이란 util class
pulbic class TimeConvertUtil{
    public static final double SECOND_TO_MIN = 60; 
    public static double secondToMin(double second){
        return second / SECOND_TO_MIN;
    }
}</code></pre>
<h2 id="03-멤버-클래스는-되도록-static으로-만들라">03. 멤버 클래스는 되도록 static으로 만들라</h2>
<h3 id="nested-class---member-class">Nested class - Member class</h3>
<p>Nested 되어 있는 member class가 독립적으로 존재할 수 없으며 바깥 instance 없이는 생성할 수 없어야 함</p>
<pre><code class="language-java">@Data
public class User{
    private String name;
    private Address address;

    @Data
    public class Address{
        String zipcode;
    }
    public String getUserName(){
        //의미가 있는 메서드는 아님
        //접근 범위 설명 위해 추가
        return nmae
    }
}

///
User user = new User();
user.new Address();</code></pre>
<h3 id="nested-class---static-member-class">Nested class - static Member class</h3>
<p>Nested 되어 있는 member class가 독립적으로 존재할 수 있음</p>
<pre><code class="language-java">public class Customer{
    private int age;
    private Address address;
    public String printBarCode(){
        return address.fullAddress + address.zipcode;
    }

    private static class Address{
        private String fullAddress;
        private String zipcode;
    }
}</code></pre>
<h3 id="nested-class">Nested class</h3>
<pre><code>Method 밖에서 사용할 것이다 - member class
그 중 member class가 바깥 instance를 참고한다 -&gt; not-stati 그 외 -&gt; static
딱 한 곳에서 사용하거나 사전 struct가 있다 -&gt; Anonymous class or local class</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Class와 상속]]></title>
            <link>https://velog.io/@rlj_su/Class%EC%99%80-%EC%83%81%EC%86%8D</link>
            <guid>https://velog.io/@rlj_su/Class%EC%99%80-%EC%83%81%EC%86%8D</guid>
            <pubDate>Tue, 26 Nov 2024 09:57:05 GMT</pubDate>
            <description><![CDATA[<h2 id="01-클래스와-멤버의-접근-권한을-최소화하라">01. 클래스와 멤버의 접근 권한을 최소화하라</h2>
<h3 id="public-class의-instance-field">Public class의 instance field</h3>
<ol>
<li>Public 으로 열 경우 Tread safe하지 못하다</li>
<li>꼭 필요한 상수라면 예외적으로 public static final로 공개할 수 있다.</li>
<li>[주의사항] public static final Thing[] values = {...} 는 수정이 그낭하다</li>
</ol>
<h3 id="배열의-해결책">배열의 해결책</h3>
<h4 id="배열을-private로-만들고-불변-리스트를-추가">배열을 private로 만들고, 불변 리스트를 추가</h4>
<pre><code class="language-java">private static final PAGE[] PAGE_INFO = {...};
public staticf inal List&lt;PAGE&gt; VLAUSE =
Collection.unmodeifiableList(Arrays.asList(PAGE_INFO));</code></pre>
<h4 id="배열을-private로-두고-복사본을-변환하는-public-method">배열을 private로 두고, 복사본을 변환하는 public method</h4>
<pre><code class="language-java">public static final PAGE[] vlause(){
    return PAGE_INFO.clone();
}</code></pre>
<h2 id="02-변경-가능성을-최소화-하라">02. 변경 가능성을 최소화 하라</h2>
<h3 id="immutable-class">Immutable class</h3>
<pre><code>1. 상태 변경 method를 제공하지 않는다.
2. Class를 확장하지 않도록 한다.
3. 모든 field를 final로 선언한다.
4. 모든 filed를 private로 선언한다.
5. 자신을 제외하고는 아무도 가변 컴포넌트에 접근할 수 없도록 한다.</code></pre><h4 id="접근-제어">접근 제어</h4>
<pre><code class="language-java">@Getter
class AddressInfo{
    private String address;
}

@AllArgsConstructor
final class User{
    private final String phone;
    private final List&lt;AddressInfo&gt; addressInfoList;

    public List&lt;String getAddressList(){
        //주소 정보 숨기기
        return addressInfoList.stream()
            .map(AddressInfo::getAddress).collect(Collectors.toList());
    }
}</code></pre>
<h3 id="biginteger-immutable-class-example">BigInteger (Immutable class example)</h3>
<pre><code class="language-java">BigInteger bigInteger = new BigInteger(&quot;10000&quot;);

System.out.println(bigInteger.add(new BigInteger(&quot;100&quot;))); // 10100
System.out.println(bigInteger); //10000</code></pre>
<h4 id="조건">조건</h4>
<pre><code>1. Tread safe
2. failure atomicity ~ 예외가 발생 후에도 유효한 상태
3. 값이 다르면 무조건 독립적인 객체로 생성되어야 함</code></pre><h4 id="중간-단계-객체가-완성-중인-상태를-극복하기-위한-방법">중간 단계 (객체가 완성 중인 상태)를 극복하기 위한 방법</h4>
<pre><code>Static factory method를 통해 new instance를 생성해 response Ex) StringBuilder</code></pre><h2 id="03-상속을-고려해-설계하고-문서화-하라-그러지-않았다면-상속을-금지하라">03. 상속을 고려해 설계하고 문서화 하라. 그러지 않았다면 상속을 금지하라</h2>
<h3 id="상속을-금지하는-법">상속을 금지하는 법</h3>
<h4 id="class를-final로-선언하는-법">Class를 final로 선언하는 법</h4>
<pre><code class="language-java">final public class ProhibitIngeritance{
}</code></pre>
<h4 id="모든-생성자를-private-or-package-private로-선언하고-public-static-factory로-만드는-법">모든 생성자를 private or package-private로 선언하고 public static factory로 만드는 법</h4>
<pre><code class="language-java">@Getter
public class ProhibitIngeritance{
    private int sum;

    private ProhibitIngeritance() {}

    private ProhibitIngeritance(int sum){
        this.sum = sum;
    }
}</code></pre>
<h3 id="요약">요약</h3>
<pre><code>웬만하면 interface를 통한 구현

final class보다는 coding rule을 정할 때 웬만하면 상속을 피한다.라고 협의 후 코드 리뷰에 반영하는 편이 더 좋다.

변수 몇 개가 겹친다고 해서 꼭 상속을 통한 확장을 해야 한다는 것을 의미하는 것은 아니다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[습관적으로 사용할 수 있는 Object의 공통 메서드]]></title>
            <link>https://velog.io/@rlj_su/%EC%8A%B5%EA%B4%80%EC%A0%81%EC%9C%BC%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8A%94-Object%EC%9D%98-%EA%B3%B5%ED%86%B5-%EB%A9%94%EC%84%9C%EB%93%9C</link>
            <guid>https://velog.io/@rlj_su/%EC%8A%B5%EA%B4%80%EC%A0%81%EC%9C%BC%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8A%94-Object%EC%9D%98-%EA%B3%B5%ED%86%B5-%EB%A9%94%EC%84%9C%EB%93%9C</guid>
            <pubDate>Tue, 26 Nov 2024 09:31:07 GMT</pubDate>
            <description><![CDATA[<h2 id="01-equals의-일반-규약을-지켜-재정의하라">01. equals의 일반 규약을 지켜 재정의하라</h2>
<h3 id="equals가-만족해야하는-것">Equals가 만족해야하는 것</h3>
<pre><code>1. [reflexivity] e.quals(x) =&gt; true
2. [symmetry] x.equals(y) =&gt; true then y.equals(x) =&gt; true
3. [transitivity] x.equals(y) =&gt; true, y.equals(z) =&gt; true then x.equals(z) =&gt; true
4. [consistency] x.equals(y) 를 여러번 호출해도 항상 결과는 같게
5. [not null] if x is not null, then x.equals(null) = false</code></pre><h3 id="equals의-전형적인-검사-패턴">Equals의 전형적인 검사 패턴</h3>
<ol>
<li>== 를 통해 input이 자기 자신의 참조인지</li>
<li>instanceof를 통해 input의 타입이 명확한지</li>
<li>2를 통해 검사한 객체를 올바른 타입으로 형변환</li>
<li>핵심 필드등ㄹ이 모두 일치하는 지</li>
<li>[not null] if x is not null, then x.equals(null) = false</li>
</ol>
<pre><code class="language-java">@Override
public boolean equals(Object o){
    if(this == o) return true;
    if(o == null || getClass() != o.getClass()) return false;
    LaptopDto laptopDto = (LaptopDto) o;

    return Objects.equals(modelName, laptopDto.modelName) &amp;&amp; Obejcts.equals(company, laptopDto.company);
}</code></pre>
<h3 id="주의사항">주의사항</h3>
<pre><code>1. 만족해야 하는 조건을 만족시켰는가
2. Equals를 재정희 할 때 hashcode도 재정의 하였는가
3. Equals의 input이 Object인가 (Overriding 하였는가)
4. 핵심 필드들이 모두 일치하는 지
5. [not null] if x is not null, then x.equals(null) = false</code></pre><h2 id="02equals를-재정의-하려거든-hashcode도-함께-재정의하라">02.equals를 재정의 하려거든 hashcode도 함께 재정의하라</h2>
<h3 id="비교-방복의-차이">비교 방복의 차이</h3>
<h4 id="">==</h4>
<pre><code>value compare
즉 primitive type일 때는 value compar 
Reference type 일 때는 주소가 같은지 비교</code></pre><h4 id="equals">equals()</h4>
<pre><code>메서드의 의도 : 같은 객체인지
Default : == 와 동일
Override하여 사용</code></pre><h4 id="hashcode">hashcode()</h4>
<pre><code>논리적으로 같은 객체라면 같은 hashcode를 반환해야 함</code></pre><h3 id="간단한-방식의-hash">간단한 방식의 hash</h3>
<pre><code class="language-java">//가장 간단한 방식
@Override
public int hashCode(){
    int result = message.hashCode();
    return result;
}

//속도를 고려해야 한다면
@Override
public int hashCode(){
    return Objects.hash(modelName, company);
}

//속도가 많이 느려지만 lazy init, or caching을 고려하자</code></pre>
<h3 id="objecthash-내부에서-arrayhash-출력">Object.hash() (내부에서 Array.hash 출력)</h3>
<pre><code class="language-java">public static int hashCode(Object a[]){
    if (a == null) return 0;

    int result = 1;

    for (Object element : a){
        result = 31 * result + (element == null ? 0 : element.hashCode());
    }
    return result;
}</code></pre>
<h3 id="lombok을-사용하는-방법">Lombok을 사용하는 방법</h3>
<pre><code class="language-java">@EqualsAndHashCode
public class EqualsAndHashCodeExample{
    private transient int transientVer = 10;
    private String name;
    private double score;
    private String[] tags;

    @EqualsAndHashCode.Exclude
    private int id;
}</code></pre>
<h2 id="03-tostring을-항상-override-하라">03. toString을 항상 override 하라</h2>
<h4 id="tostring의-일반-규약">toString의 일반 규약</h4>
<p>간결하고 사람이 읽기 쉬운 형태의 유익한 정보</p>
<h3 id="lombok의-tostring">Lombok의 @ToString</h3>
<pre><code class="language-java">@AllArgsConstructor
@ToString
public class Laptop{
    private String name;
    private String company;
}

System.out.println(new Laptop(&quot;그램 16인치&quot;, &quot;LG&quot;));
//실행 결과 : Laptop(name = 그램 16인치, company = LG)</code></pre>
<h4 id="불필요한-변수가-있을-경우">불필요한 변수가 있을 경우</h4>
<pre><code class="language-java">@ToString
public class Laptop{
    @ToString.Exclude
    private String modelName;
    private String company;
}</code></pre>
<h3 id="요약">요약</h3>
<pre><code>1. 로그를 찍을 일이 있을 거 같으면 귀찮아하지 말고 toString을 overriding 하자.
2. 전부 다 toString으로 찍지 말고, 필요한 것 위주로 작성하라
3. Lombok은 toString을 만들기 귀찮은 개발자들이 성실하게 toString을 구현하도록 유인할 수 있다.</code></pre><h2 id="04-clone-재정의는-주의해서-사용하라">04. clone 재정의는 주의해서 사용하라</h2>
<h3 id="배열-copy">배열 copy</h3>
<pre><code class="language-java">int[] a = {1,2,3,4};
int[] b = a; //Shallow copy
b = a.clone(); //deep copy


//Copy시 주의사항
Laptop[] a = {new Laptop(&quot;그램 16인치&quot;, &quot;삼성&quot;)};
Laptop[] b = a.clone();
b[0].setComapny(&quot;LG&quot;);
//잘 복사한 거 같지만 Object reference value를 참조했기 때문에 a[0] == b[0] 즉 들이 같은 객체를 가리키고 있음



</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[객체의 파괴]]></title>
            <link>https://velog.io/@rlj_su/%EA%B0%9D%EC%B2%B4%EC%9D%98-%ED%8C%8C%EA%B4%B4</link>
            <guid>https://velog.io/@rlj_su/%EA%B0%9D%EC%B2%B4%EC%9D%98-%ED%8C%8C%EA%B4%B4</guid>
            <pubDate>Tue, 26 Nov 2024 07:41:15 GMT</pubDate>
            <description><![CDATA[<h2 id="01-불필요한-객체-생성-금지">01. 불필요한 객체 생성 금지</h2>
<pre><code class="language-java">public static long sum(){
    Long sum = 0L; (X)

    long sum = 0L: (O)
    //이 메서드가 위에 메서드에 비해 10배 정도 빠른 속도를 나타내었다.
    //Boxing type을 남용하지 않도록 주의하는 것 뿐만 아니라, 의도치 않은 Auto Boxing을 조심하라

    for(long i = 0; i &lt; Integer.MAX_VALUE; i++{
        sum += i;
    }

    return sum;
}</code></pre>
<h3 id="최적화된-valid-check-util">최적화된 valid Check Util</h3>
<h4 id="pattern-insatance가-매번-생성">Pattern insatance가 매번 생성</h4>
<pre><code class="language-java">static boolean isEmailVaild(String s){
    retur s.mathes(&quot;[a-zA-Z0-9.-]\\\\\.[a-zA-Z]{2,6}$&quot;);
}</code></pre>
<h4 id="pattern-instance가-한-번만-생성-최적화">Pattern instance가 한 번만 생성 (최적화)</h4>
<pre><code class="language-java">public class EmailUtil{t
    private static final Pattern EMAIL = 
        Pattern.complie(&quot;[a-zA-Z0-9.-]\\\\\.[a-zA-Z]{2,6}$&quot;);

    static boolean isEmailValid(String s){
        return EMAIL.matcher(s).matches();
    }
}</code></pre>
<h2 id="02-다-쓴-객체-참조를-해제하라">02. 다 쓴 객체 참조를 해제하라</h2>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/b3d78095-982e-4971-b752-21a78b635644/image.png" alt=""></p>
<p>유효 Scope 밖으로 넘어가면 자동으로 GC의 대상이 된다.</p>
<h2 id="03-try-finally-대신-try-with-resources">03. try-finally 대신 try-with-resources.</h2>
<h3 id="try-finally">Try finally</h3>
<pre><code class="language-java">//Exception 시 Stack trace에 어려움이 있음
static void copy(String src, String dst) throws IOException{
    InputStream in = new FileInputStream(src):
    try{
        OutputStream out = new FileOutputStream(src):
        try{
            ...
        }
    }finally{
        out.close();
    }
}finally{
    in.close();
}</code></pre>
<h3 id="try-wirh-resource">Try-wirh-resource</h3>
<pre><code class="language-java">public class Resource implements AutoCloseable{
    @Override
    public void close() throws Exception{
        throw new Exception(&quot;...exception&quot;);
    }
}

try (Resource r1 = new Resource();
     Resource r1 = new Resource();){
         throw new Exception(&quot;asd):
     }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[객체의 생성]]></title>
            <link>https://velog.io/@rlj_su/%EA%B0%9D%EC%B2%B4%EC%9D%98-%EC%83%9D%EC%84%B1</link>
            <guid>https://velog.io/@rlj_su/%EA%B0%9D%EC%B2%B4%EC%9D%98-%EC%83%9D%EC%84%B1</guid>
            <pubDate>Tue, 26 Nov 2024 07:05:08 GMT</pubDate>
            <description><![CDATA[<h2 id="01-constructor-대신-static-factory-method를-고려하라">01. Constructor 대신 Static Factory Method를 고려하라</h2>
<pre><code class="language-java">//Laptop Class
public class Laptop{
    private String model;
    private String company;
}

//이름을 가진 Static Factory Method
public static Labtop of modelNameAndCompany(
    String model, String company){
    Laptop laptop = new Laptop();
    laptop.company = company;
    laptop.modelName = modelName;

    return laptop;
}</code></pre>
<h4 id="장점">장점</h4>
<pre><code>1. 이름을 가질 수 있다.
2. 간다하고 명확하게 사용할 수 있다.
3. 인스턴스를 매번 생성할 필요는 없다.

Flyweight pattern = Collection Object
Singleton pattern = Single Object</code></pre><h4 id="단점">단점</h4>
<pre><code>1. Static Factory method만 제공하면 Constructor가 없을 수 있어 상속받은 Class를 만들 수 없다.
2. 프로그래머에게 인지가 잘 되지 않을 수 있다.</code></pre><h2 id="02-많은-parameter가-있는-constructor은-builder를-고려하라">02. 많은 parameter가 있는 Constructor은 Builder를 고려하라</h2>
<pre><code class="language-java">//예시 코드
public static Facts{
    private final int ...
    private final int ...
    private final int ...
    private final int ...
    private final int ...

    // Pattern 1 : 여러 개의 Constructor를 둔다.
    // Pattern 2 : Java beans Pattern (Setter)
}</code></pre>
<h3 id="lombok을-통하면-훨씬-더-간단해-질-수-있다">Lombok을 통하면 훨씬 더 간단해 질 수 있다.</h3>
<pre><code class="language-java">@Data
@Builder
public class Facts{
    private final int size;
    private final int serving;

    @Builder.Default
    private final int ...
    @Builder.Default
    private final int ...
    @Builder.Default
    private final int ...

    public static FactsBuilder builder(int size int serving
        return Builde()
            .size(size)
            .serving(serving);
    }

}</code></pre>
<h4 id="장점-1">장점</h4>
<pre><code>1. 상속받은 Class의 Builder가 정의한 build 메서드가 상위 메서드의 타입을 return 하는 것이 아닌 자신의 타입을 return 한다.</code></pre><h4 id="단점-1">단점</h4>
<pre><code>1. Builder를 항상 만들어야 하기 때문에 생성 비용이 무조건 생긴다.
2. 점층적 생성자 패턴 (Argument 를 여러 개 가진 Constructor) 보다 장황하여 적은 갯수의 Parameter일 경우 오히려 좋지 않을 수 있다.</code></pre><h2 id="03-private-contructor-나-enum-type으로-singleton임을-보증하라">03. private contructor 나 enum Type으로 Singleton임을 보증하라</h2>
<h3 id="대표적인-singleton-pattern">대표적인 Singleton Pattern</h3>
<h4 id="public-static-member">public static member</h4>
<pre><code class="language-java">//INSTANCE가 초기화 되고 나면 고정이 된다
public class Speaker{
    public static final Speaker INSTANCE = new Speaker();
    private Speaker(){}
}</code></pre>
<h4 id="static-factory">static factory</h4>
<pre><code class="language-java">//상황에 따라 synchrozined나, lazy하게 instance를 생성하는 방법도 있다.
public class Speaker{
    private static Speaker instance;
    private Speaker(){}

    public static synchronized Speaker getInstance(){
        if (instance == null){
            instatnce = new Speaker();
        }
        return instance;
    }

}</code></pre>
<h4 id="enum-type">Enum Type</h4>
<pre><code class="language-java">public enum Speaker{
    INSTANCE;
    private String message;

    public Speaker getInstance(){
        return INSTANCE;
    }
    public void setMessage(String message){
        this.message = message;
    }
}</code></pre>
<h2 id="04-resource를-직접-명시하지-말고-dependency-injection을-사용하라">04. Resource를 직접 명시하지 말고, Dependency Injection을 사용하라</h2>
<pre><code class="language-java">@Configuration
public class Config{
    //Class 내부에서 직접 정의해서 사용하지 않는다.
    private static final String address = &quot;서울시 강남구&quot;; (X)

    @Value(&quot;${base.address}&quot;)
    Private String address;  (O)
}

//application.yml에 등록된 정보
base:
    address: &#39;서울시 강남구&#39;</code></pre>
<h4 id="constructor-injection-의-경우-test-flexibility를-높일-수-있다">Constructor Injection 의 경우 Test, flexibility를 높일 수 있다.</h4>
<pre><code class="language-java">//고정해 높은 값에 비해 훨씬유연해진 class (pattern Injection 가능)
public class Checker{
    private final String pattern;

    public Checker(String pattern){
        this.pattern = pattern;
    }
    public boolean isValid(Stirng phone){
        ...
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[비선형 자료구조 - Graph]]></title>
            <link>https://velog.io/@rlj_su/%EB%B9%84%EC%84%A0%ED%98%95-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Graph-e5na5j2a</link>
            <guid>https://velog.io/@rlj_su/%EB%B9%84%EC%84%A0%ED%98%95-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Graph-e5na5j2a</guid>
            <pubDate>Sun, 24 Nov 2024 06:51:53 GMT</pubDate>
            <description><![CDATA[<h2 id="그래프-graph">그래프 Graph</h2>
<p>정점과 간선으로 이루어진 자료구조 (Cyclic)</p>
<ul>
<li>연결된 정점간의 관계를 표현할 수 있는 자료구조</li>
<li>용도 : 지하철의 노선도, 통신 네트워크, ...</li>
</ul>
<h3 id="그래프-구조">그래프 구조</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/baeb38d5-864c-4048-8e80-f85d9b57006d/image.png" height="100" width="200"></p>

<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody><tr>
<td>정점(Vertex) : 각 노드</td>
<td>간섭(Edge) : 노드와 노드를 연결하는 선 (link, branch)</td>
</tr>
<tr>
<td>인점정점(Adjacent vertext) : 간선 하나를 두고 바로 연결된 정점</td>
<td>정점의 차수 (Degree) : <br> - 무방향 그래프에서 하나의 정점에 인접한 정점의 수 <br> - 무방향 그래프 모든 정점 차수의 합 = 그래프 간선의 2배</td>
</tr>
<tr>
<td>진입 차수 (In-degree) : 방향 그래프에서 외부에서 오는 간선의 수</td>
<td>진출 차수 (Out-degree) : 방향 그래프에서 외부로 나가는 간선의 수</td>
</tr>
<tr>
<td>경로 길이 (Path length) : 경로를 구성하는데 사용된 간선의 수</td>
<td>단순 경로  (Simple path) : 경로 중에서 반복되는 정점이 없는 경우</td>
</tr>
<tr>
<td>사이클 (Cycle) : 단순 경로의 시작 정점과 끝 정점이 동일한 경우</td>
<td></td>
</tr>
</tbody></table>
<h3 id="그래프의-특징과-트리와의-차이">그래프의 특징과 트리와의 차이</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/ad7b08bb-fe3f-402b-aadb-1835fc2be22b/image.png" alt=""></p>
<h3 id="그래프의-종류">그래프의 종류</h3>
<h4 id="무방향-그래프">무방향 그래프</h4>
<ul>
<li>간선에 방향이 없는 그래프 (양방향 이동 가능)</li>
<li>정ㅈ머 A - B 간선의 표현 : (A, B) = (B, A)</li>
</ul>
<h4 id="방향-그래프">방향 그래프</h4>
<ul>
<li>간선에 방향이 있는 그래프 (해당 방향으로 이동 가능)</li>
<li>정점 A -&gt; B 간선의 표현 : &lt;A, B&gt; != &lt;B, A)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/73427ad9-78ef-49bd-b579-6320c99b9268/image.png" alt=""></p>
<h4 id="가중치-그래프">가중치 그래프</h4>
<ul>
<li>간선에 값이 있는 그래프 (이동 비용)</li>
</ul>
<h4 id="완전-그래프">완전 그래프</h4>
<ul>
<li>모든 정점이 서로 연결되어 있는 그래프</li>
<li>정점이 N개일 경우, 간선의 수는 n(n-1) / 2개</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/bb826a7d-def0-4c10-ab58-c058d6af35d8/image.png" alt=""></p>
<h3 id="그래프-탐색---dfs">그래프 탐색 - DFS</h3>
<h4 id="깊이-우선-탐색-depth-first-search">깊이 우선 탐색 (Depth First Search)</h4>
<p>각 노드에 방문했는지 여부를 체크할 배열과 스택을 이용하여 구현
<img src="https://velog.velcdn.com/images/rlj_su/post/6a2168b9-6b1e-4f85-9d8a-9518fd7d1b0b/image.png" alt=""></p>
<h3 id="그래프-탐색---bfs">그래프 탐색 - BFS</h3>
<h4 id="너비-우선-탐색-breath-first-search">너비 우선 탐색 (Breath First Search)</h4>
<p>각 노드에 방문했는지 여부를 체크할 배열과 큐를 이용하여 구현
<img src="https://velog.velcdn.com/images/rlj_su/post/264f5902-8497-4d3b-a82a-ab725793c857/image.png" alt=""></p>
<h3 id="그래프의-구현">그래프의 구현</h3>
<h4 id="인접-행렬-adjacency-matrix---2차원-배열-이용">인접 행렬 (Adjacency Matrix) - 2차원 배열 이용</h4>
<ul>
<li>인접 행렬의 장단점<ul>
<li>간섭 정보의 확인과 업데이트가 빠름 O(1)</li>
<li>인접 행렬을 위한 메모리 공간 차지</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/fedeea24-4c08-4bd5-8caf-271674da85ac/image.png" alt=""></p>
<h4 id="인접-리스트-adjacency-list---연결리스트-이용">인접 리스트 (Adjacency List) - 연결리스트 이용</h4>
<ul>
<li>인접 리스트의 장단점<ul>
<li>메모리 사용량이 상대적으로 적고, 노드의 추가 삭제가 빠름</li>
<li>간선 정보 확인이 상대적으로 오래 걸림</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/03298442-cb54-4f39-9d44-d709a6ee8d9c/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드를 바라보는 시각 기르기]]></title>
            <link>https://velog.io/@rlj_su/%EC%BD%94%EB%93%9C%EB%A5%BC-%EB%B0%94%EB%9D%BC%EB%B3%B4%EB%8A%94-%EC%8B%9C%EA%B0%81-%EA%B8%B0%EB%A5%B4%EA%B8%B0</link>
            <guid>https://velog.io/@rlj_su/%EC%BD%94%EB%93%9C%EB%A5%BC-%EB%B0%94%EB%9D%BC%EB%B3%B4%EB%8A%94-%EC%8B%9C%EA%B0%81-%EA%B8%B0%EB%A5%B4%EA%B8%B0</guid>
            <pubDate>Sat, 23 Nov 2024 09:59:06 GMT</pubDate>
            <description><![CDATA[<h2 id="01-내용-요약">01. 내용 요약</h2>
<h3 id="15장-junit-들여다보기">15장 JUnit 들여다보기</h3>
<h4 id="세상에-완벽한-코드는-없다">세상에 완벽한 코드는 없다</h4>
<pre><code>* 의도륵 명확하게 표현하기 위해 조건문을 메서드로 분리
* 전후 단계가 있는 변수들 사이 시간적인 결합 (hidden temporal coupling)을 해결하기 위해 리팩터링
* 더 적절한 의미로 네이밍 변경
* 불 필요한 연산을 하는 코드 제거</code></pre><h4 id="남의-코드를-비판하고-내-코드의-비판을-듣는-건-편안하게-여겨야-할-활동이다">남의 코드를 비판하고, 내 코드의 비판을 듣는 건 편안하게 여겨야 할 활동이다.</h4>
<h2 id="02-오픈-소스-접근법">02. 오픈 소스 접근법</h2>
<h3 id="해당-솔류션에-대한-기본-지식을-먼저-익혀라">해당 솔류션에 대한 기본 지식을 먼저 익혀라</h3>
<pre><code>하둡을 분석하려면 구글에서 발표한 논문을 읽어 봐여하고, HBase를 분석하기 위해서는 BigTable 논문을 읽어야 합니다. 
분석하고자 하는 솔루션에 대한 이론적인 배경 지식이 없는 상태에서 소스 코드를 바로 보면 그냥 얽혀있는 코드를 보고 있는 느낌이 든다.

복잡한 분산 컴퓨팅 환경에서 운영되는 솔류션인 경우 더욱 더 그 시스템의 기본 개념과 아키텍처를 이해하고 있어야합니다.</code></pre><h3 id="본인-pc에-빌드-및-실행-환경을-구축하라">본인 PC에 빌드 및 실행 환경을 구축하라</h3>
<pre><code>코드 분석을 빨리하기 위해서는 분석에 필요한 로그를 추가하여 재 컴파일한 후 실행하면서 로그를 확인하는 것이 좋다.
단순 코드만 보면 특정 연산의 흐름이 어떻게 진행되고 있는지를 파악하기 어려운 경우가 많기 때문이다.

최근의 오픈소스들을 분산 환경에서 운영되는 경우가 많은데 이 경우라 하더라도 개발자의 PC에 빌드와 실행 환경을 모두 구성하는 것이 좋다.

빌드 및 실행환경을 구성하는 것만으로도 코드 분석의 50%는 진행되었다고 할 수 있다.</code></pre><h3 id="수정-실행-확인-사이클을-짧게-만들어라">수정, 실행, 확인 사이클을 짧게 만들어라</h3>
<pre><code>코드를 분석하기 위해서는 분석에 필요한 정보를 출력하는 코드나 확인을 위한 코드를 추가한 다음에 기능을 실행해서 확인해야 하는 경우가 많다.
이 경우 수정, 실행, 확인을 위한 시간이 길어지면 그 만큼 효율이 떨어지게 되고 많은 시간이 소요됨

몇 번 반복하다 보면 같은 작업 패턴을 찾게되는데 이 때에는 스크립트를 만들어서 반복 작업을 효율적으로 하는 것이 좋다.</code></pre><h3 id="분석하면서-문서로-정리하라">분석하면서 문서로 정리하라</h3>
<pre><code>분석을 하면서 그림 또는 문서로 정리를 하면 분석하는 그 시점에도 도움이 되지만 나중에도 도움이 된다.
문서는 굳이 UML이 아니더라도 ppt 같은 도구로 정리하고, 이렇게 중간 중간에 정리하면 머리속에서만 빙빙 돌던 생각이 정리될 때가 많다.</code></pre><h3 id="디버거-활용">디버거 활용</h3>
<pre><code>* LOG level을 DEBUG로 설정
* 디버거의 breakpoint 기능을 활용
* System.out.println 보다는 Thread.dumpStack() 활용</code></pre><h3 id="코드의-일부를-통해-먼저-파악하기">코드의 일부를 통해 먼저 파악하기</h3>
<pre><code>* 당장 관심있는 부분부터 집중적으로 파악하라
* 테스트 코드는 좋은 교본이 된다.
* 그래도 어려우면 초기 버전을 다운로드 받아 분석하라</code></pre><h2 id="03-spring-프로젝트-접근법">03. Spring 프로젝트 접근법</h2>
<ol>
<li>repository 이름과 README.ml를 보고 프로젝트의 성격 파악</li>
<li>패키지 구조를 살펴본다(멀티 모듈인지)</li>
<li>build.gradle을 보고 어떤 디펜던시를 쓰는 지 살펴본다.</li>
<li>config 패키지 하위에 어떤 설정들이 되어있나 본다.</li>
<li>controller 패키지 하위 코드를 보고 어떤 요청들을 처리하는 지 감을 잡는다.</li>
<li>service 패키지 하위를 보고 비즈니스 로직을 추측한다.</li>
<li>데이터 구조를 알기 위해 resource 하우의 db 설정 파일을 보고 db에 접근. schema.sql 파일이 있으면 DDL을 읽어본다.</li>
<li>세부적인 비즈니스 로직을 확인할 때는 test 코드와 비교하며 이해</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[동시성을 구현할 때 명심할 것들]]></title>
            <link>https://velog.io/@rlj_su/%EB%8F%99%EC%8B%9C%EC%84%B1%EC%9D%84-%EA%B5%AC%ED%98%84%ED%95%A0-%EB%95%8C-%EB%AA%85%EC%8B%AC%ED%95%A0-%EA%B2%83%EB%93%A4</link>
            <guid>https://velog.io/@rlj_su/%EB%8F%99%EC%8B%9C%EC%84%B1%EC%9D%84-%EA%B5%AC%ED%98%84%ED%95%A0-%EB%95%8C-%EB%AA%85%EC%8B%AC%ED%95%A0-%EA%B2%83%EB%93%A4</guid>
            <pubDate>Sat, 23 Nov 2024 09:03:27 GMT</pubDate>
            <description><![CDATA[<h2 id="01-동시성-프로그래밍이란">01. 동시성 프로그래밍이란</h2>
<h3 id="동시성-프로그래밍">동시성 프로그래밍</h3>
<blockquote>
<p>어플리케이션을 효율적으로 실행하기 위해 멀티코어를 온전히 활용하도록 구현하는 방식
(외부 서비스의 응답을 기다리면서 아무일도 하지 않으면 CPU 사이클이 낭비된다.)</p>
</blockquote>
<h2 id="02-동시성-프로그래밍이-필요한-이유">02. 동시성 프로그래밍이 필요한 이유</h2>
<h3 id="동시성-프로그래밍의-미신과-오해">동시성 프로그래밍의 미신과 오해</h3>
<h4 id="동시성은-항상-때로-성능을-높여준다">동시성은 <del>항상</del> <strong>때로</strong> 성능을 높여준다</h4>
<pre><code>* 대기 시간이 아주 길어 여러 스레드가 프로세서를 공유할 수 있거나, 여러 프로세스가 동시에 처리할 독립적인 계산이 충분히 많은 경우에만 높아짐
* Ex) 웹 브라우저에서 여러 가지 이미지 리소스들을 불러와 다운로드할 때</code></pre><h4 id="동시성은-구현해도-설계는-변하지-않는다-바꿔야-한다">동시성은 구현해도 설계는 <del>변하지 않는다</del> <strong>바꿔야 한다.</strong></h4>
<pre><code>* 단일 스레드 시스템과 다중 스레드 시스템은 설계가 판이하게 다르다.
* &#39;무엇&#39;과 &#39;언제&#39;를 분리하면 시스템의 구조가 크게 달라진다.</code></pre><h4 id="컨테이너를-사용해도-동시성을-이해하지-않아도-된다-이해해야-한다">컨테이너를 사용해도 동시성을 <del>이해하지 않아도 된다</del> <strong>이해해야 한다</strong>.</h4>
<pre><code>* 어플리케이션이 컨테이너를 통해 멀티 쓰레드를 사용하는 것이기 때문에 컨테이너의 동작을 이해해야 한다.
* 동시 수정, 데드락 같은 문제를 피할 수 있는지를 알아야 한다.</code></pre><h3 id="java-servlet-동시성-구현">Java Servlet 동시성 구현</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/83a8a41e-d8a3-4050-96d3-e18608d77a8b/image.png" alt=""></p>
<pre><code>* 요청이 들어오면 Thread Pool에 있는 Thread가 서블릿의 service() 메서드 호출
* service doGet(), doPost()에서 요청에 대한 처리를 하도록 구현</code></pre><h2 id="03-안정한-동시성-프로그래밍-규칙">03. 안정한 동시성 프로그래밍 규칙</h2>
<h3 id="단일-책임-원칙srp-설계">단일 책임 원칙(SRP) 설계</h3>
<h4 id="동시성-관련-코드는-다른-코드와-분리하라">동시성 관련 코드는 다른 코드와 분리하라</h4>
<pre><code>* 동시성 코드는 독자적인 개발, 변경, 조율 주기가 있다.
* 동시성 코드에는 독자적인 난관이 있다. 다른 코드에서 겪는 난관과 다르며 훨씬 어렵다.
* 잘못 구현한 동시성 코드는 별의별 방식으로 실패한다.</code></pre><h3 id="자료-범위를-제한하라">자료 범위를 제한하라</h3>
<h4 id="공유-자료를-최대한-줄여라">공유 자료를 최대한 줄여라</h4>
<pre><code>* 동시 수정 문제를 피하기 위해 객체를 사용하는 코드 내 임계영역을 sychronized 키워드로 보호
* 보호할 임계영역을 뺴먹거나, 모든 임계영여억을 보호했는 지 확인하느라 수고가 드므로 임계 영역의 수를 최소화 해야함</code></pre><h3 id="thread는-가능한-독립적으로-구현하라">Thread는 가능한 독립적으로 구현하라</h3>
<h4 id="다른-스레드와-자료를-공유하지-않는다">다른 스레드와 자료를 공유하지 않는다.</h4>
<pre><code>* 서블릿처럼 각 Thread는 클라이언트 요청 하나를 처리한다.
* 모든 정보는 비공유 출처(client의 request)에서 가져오며 로컬 변수에 저장한다.
* 각 서블릿은 마치 자신이 독자적인 시스템에서 동작하는 양 요청을 처리한다.</code></pre><h3 id="라이브러리를-이해하라">라이브러리를 이해하라</h3>
<h4 id="javautilconcurrent-패키지를-익혀라">java.util.concurrent 패키지를 익혀라</h4>
<pre><code>* Thread Safe한 컬렉션을 사용(ConcurrentHashMap, AtomicLong)
* 서로 무관한 작업을 수행할 때는 executor 프레임워크를 사용
* 가능하다면 Thread가 Blocking 되지 않는 방법을 사용</code></pre><h3 id="동기화하는-메서드-사이에-존재하는-의존성을-이해하라">동기화하는 메서드 사이에 존재하는 의존성을 이해하라</h3>
<h4 id="공유-객체-하나에는-메서드-하나만-사용">공유 객체 하나에는 메서드 하나만 사용</h4>
<pre><code>* 클라이언트에서 잠금 - 클라이언트에서 첫 번째 메서드를 호출하기 전에 서버를 잠근다
* 서버에서 잠금 - 서버에다 &quot;서버를 잠그고 모든 메서드를 호출한 후 잠금을 해제하는&quot; 메서드를 구현
* 연결(Adapter) 서버 - 잠금을 수행하는 중간 단계를 생성</code></pre><h2 id="04-동시성-테스트-방법">04. 동시성 테스트 방법</h2>
<h3 id="동시성-코드를-테스트-해야-한다">동시성 코드를 테스트 해야 한다</h3>
<h4 id="테스트를-했다고-동시성-코드가-100-올바르다고-증명하기는-불가능하지만-충분한-테스트는-위험을-낮춘다">테스트를 했다고 동시성 코드가 100% 올바르다고 증명하기는 불가능하지만 충분한 테스트는 위험을 낮춘다.</h4>
<pre><code>* 문제를 노출하는 테스트 케이스를 작성하라
* 프로그램의 설정과 시스템 설정과 부하를 바꿔가며 자주 돌려라
* 테스트가 실패하면 원인을 추적하라
* 다시 돌렸더니 통과한다는 이유로 그냥 넘어가면 절대 안 된다.</code></pre><h3 id="코드에-보조-코드를-넣어라">코드에 보조 코드를 넣어라</h3>
<h4 id="드물게-발생하는-오류를-자주-발생시키도록-보조-코드를-추가">드물게 발생하는 오류를 자주 발생시키도록 보조 코드를 추가</h4>
<pre><code>*코드에 wait(), sleep(), yield(), priority() 함수를 직접 구현
* 보조코드를 넣어주는 도구를 사용해  테스트
    * 다양한 위치에 ThreadJigglePoing.jiggle()을 추가해 무작위로 sleep(), yield()가 호출되도록 한다.
* 테스트 환경에서 보조 코드를 돌려본다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[창발적 설계로 깔끔한 코드 구현하기]]></title>
            <link>https://velog.io/@rlj_su/%EC%B0%BD%EB%B0%9C%EC%A0%81-%EC%84%A4%EA%B3%84%EB%A1%9C-%EA%B9%94%EB%81%94%ED%95%9C-%EC%BD%94%EB%93%9C-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@rlj_su/%EC%B0%BD%EB%B0%9C%EC%A0%81-%EC%84%A4%EA%B3%84%EB%A1%9C-%EA%B9%94%EB%81%94%ED%95%9C-%EC%BD%94%EB%93%9C-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 22 Nov 2024 10:35:20 GMT</pubDate>
            <description><![CDATA[<h2 id="00-창발적-설계란">00. 창발적 설계란</h2>
<h3 id="창발성-emergence">창발성 (Emergence)</h3>
<h4 id="하위-계층에는-없는-특성이나-행동이-상위-계층전체구조에서-자발적으로-돌연히-출연하는-현상">하위 계층에는 없는 특성이나 행동이 상위 계층(전체구조)에서 자발적으로 돌연히 출연하는 현상</h4>
<blockquote>
<p>각각의 개미는 집을 지을 능력이 없지만, 작은 개미들의 상호작용을 통해 집이라는 결과물이 나오는 것 처럼 작은 요소들의 상호작용의 반복이 전체구조에 영향을 미친다.</p>
</blockquote>
<h3 id="창발적-설계">창발적 설계</h3>
<ol>
<li>모든 테스트를 실행한다.</li>
<li>중복을 없앤다.</li>
<li>프로그래머 의도를 표현한다.</li>
<li>실용적 관점에서 타협한다.</li>
</ol>
<h2 id="01-모든-테스트를-실행한다">01. 모든 테스트를 실행한다</h2>
<pre><code>* 모든 테스트 케이스를 항상 통과하는 시스템은 &#39;테스트가 가능한 시스템&#39;이다.
* 테스트가 가능한 시스템을 만들려도 애쓰면 설계 품질이 높아 진다.
* 결합도가 높으면 테스트 케이스를 작성하기 어렵기 때문에 결합도를 낮추는 설계를 하게 된다.
* 규칙을 따르면 시스템은 낮은 결합도와 높은 응집력이라는 목표를 저절로 달성할 수 있다.</code></pre><h2 id="02-중복을-없앤다">02. 중복을 없앤다</h2>
<h3 id="template-method-패턴">Template Method 패턴</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/27585ea6-44b7-4edb-beee-b8c8cd44a54f/image.png" alt=""></p>
<h4 id="알고리즘의-구조를-상위-클래스의-메서드에서-정의하고-하위-클래스에서-자신에-맞게-세부-알고리즘을-정의한다">알고리즘의 구조를 상위 클래스의 메서드에서 정의하고, 하위 클래스에서 자신에 맞게 세부 알고리즘을 정의한다.</h4>
<ul>
<li>구현하려는 알고리즘에 일정한 단계가 있고, 세부 단계마다 조금씩 구현 내용이 다를 때 사용</li>
<li>알고리즘의 여러 단계를 각 메서드로 선언하고, 그 알고리즘을 수행할 템플릿 메서드를 만든다.</li>
<li>하위 클래스에서는 나눠진 메서드를 구현한다.<h2 id="03-의도를-표현한다">03. 의도를 표현한다</h2>
</li>
</ul>
<ol>
<li>좋은 이름 선택</li>
<li>함수와 클래스 크기를 가능한 줄임</li>
<li>표준 명칭 사용</li>
<li>단위 테스트 케이스를 꼼꼼하게 작성</li>
<li>가독성이 좋게 만드려고 노력<h2 id="04-실용적-관점에서-타협한다">04. 실용적 관점에서 타협한다</h2>
</li>
</ol>
<ul>
<li>여러가지 규칙에 극단적으로 심취해 클래스와 메서드를 무수하게 만들지 않음</li>
<li>결국 좋은 코드를 만드는 이유는 생산성을 올리기 위한 것</li>
</ul>
<h3 id="dip-의존성-역전-원칙">DIP (의존성 역전 원칙)</h3>
<h4 id="상위-모델은-하위-모델에-의존하면-안된다-추상화는-세부-사항에-의존해서는-안된다">상위 모델은 하위 모델에 의존하면 안된다. 추상화는 세부 사항에 의존해서는 안된다</h4>
<ul>
<li>하위 모델에 변경이 상위 모듈의 변경을 요구하는 위계관계를 끊는다.</li>
<li>실제 사용관계는 그대로이지만, 추상화를 매개로 메세지를 주고 받으면서 관계를 느슨하게 만든다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[관심사 분리 패턴들]]></title>
            <link>https://velog.io/@rlj_su/%EA%B4%80%EC%8B%AC%EC%82%AC-%EB%B6%84%EB%A6%AC-%ED%8C%A8%ED%84%B4%EB%93%A4</link>
            <guid>https://velog.io/@rlj_su/%EA%B4%80%EC%8B%AC%EC%82%AC-%EB%B6%84%EB%A6%AC-%ED%8C%A8%ED%84%B4%EB%93%A4</guid>
            <pubDate>Fri, 22 Nov 2024 10:21:31 GMT</pubDate>
            <description><![CDATA[<h2 id="01-관심사-분리">01. 관심사 분리</h2>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/3c63ad81-6177-414f-8ce4-05126fd0a77d/image.png" alt=""></p>
<h4 id="construction-생성-과-use-사용-은-다르다">construction (생성) 과 use (사용) 은 다르다</h4>
<ul>
<li>소프트웨어 시스템은 준비 과정과 런타임 로직을 분리</li>
<li>객체의 생성과 객체를 사용하는 부분은 분리</li>
</ul>
<h3 id="시작에-대한-관심사-분리">시작에 대한 관심사 분리</h3>
<h4 id="객체의-생성은-시작-단계에서-비즈니스-로직은-객체를-사용하는데-집중">객체의 생성은 시작 단계에서, 비즈니스 로직은 객체를 사용하는데 집중</h4>
<ul>
<li>시작 단계는 모든 어플리케이션이 풀어야할 관심사</li>
<li>main 함수에서 시스템에 필요한 객체를 생성한 후 어플리케이션에 넘긴다.</li>
<li>어플리케이션은 그저 만들어진 객체를 사용한다.</li>
<li>모든 객체가 잘 생성되었다고 가정하고, 객체를 이용한 개발에 집중할 수 있다.</li>
</ul>
<h3 id="요청에-대한-관심사-분리">요청에 대한 관심사 분리</h3>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/38de89b5-c383-4fd7-a9c6-aa378e7012c4/image.png" alt=""></p>
<h4 id="filter-intercepter-aop">Filter, intercepter, AOP</h4>
<p>Spring 프레임 워크를 통해 요청에 대한 관심사를 분리해 요청 처리에 대한 비즈니스 로직에 집중할 수 있다.</p>
<h2 id="02-dependency-injection-의존성-주입">02. Dependency Injection (의존성 주입)</h2>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/ae255de2-4aa5-47b8-bb55-d3e80da740cc/image.png" alt=""></p>
<h4 id="객체-의존성을-di-컨테이너에게-맡긴다">객체 의존성을 DI 컨테이너에게 맡긴다</h4>
<ul>
<li>Setter 메소드 or 생성자 인수를 통해 의존성을 주입</li>
<li>DI 컨테이너는 요청이 들어올 때 필요한 객체의 인스턴스를 만든 후 의존성 설정</li>
</ul>
<h4 id="ex-spring-ioc-container">Ex) Spring IoC Container</h4>
<h2 id="03-cross-cutting-concerns-횡단-관심-분리">03. Cross Cutting Concerns (횡단 관심 분리)</h2>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/06837d49-368d-4dad-bc4e-0486d2370f36/image.png" alt=""></p>
<h4 id="어플리케이션-전반에서-가지는-공통적인-관심사를-분리한다">어플리케이션 전반에서 가지는 공통적인 관심사를 분리한다.</h4>
<ul>
<li>비즈니스 로직 외에 Logging, Transaction 관리, Securitiy 등 신경써야할 관심사들이 많다. </li>
<li>관심사들은 많은 어플리케이션 레이어에 퍼져있는데, 이 관심사들을 분리해 처리하는 것이 효율적이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[클래스 잘 설계하기]]></title>
            <link>https://velog.io/@rlj_su/%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9E%98-%EC%84%A4%EA%B3%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@rlj_su/%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9E%98-%EC%84%A4%EA%B3%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 22 Nov 2024 10:11:54 GMT</pubDate>
            <description><![CDATA[<h2 id="01-캡슐화-되어야-한다">01. 캡슐화 되어야 한다.</h2>
<h3 id="캡슐화-encapsulation">캡슐화 (Encapsulation)</h3>
<h4 id="객체의-실제-구현을-외부로부터-감추는-방식">객체의 실제 구현을 외부로부터 감추는 방식</h4>
<ul>
<li>클래스를 개발할 때 기본적으로 구현을 감추고, 외부 객체와 상호작용하는 부분만 노출</li>
<li>외부의 잘못된 사용 방지</li>
</ul>
<h2 id="02-단일-책임-원칙">02. 단일 책임 원칙</h2>
<h3 id="클래스는-작아야-한다">클래스는 작아야 한다.</h3>
<h4 id="클래스가-많은-책임이-한-개인가">클래스가 많은 책임이 한 개인가</h4>
<pre><code>* 함수와 마찬가지로 클래스도 작아야 한다.
* 함수는 라인 수로 크기를 측정했는데, 클래스는 맡은 책임의 수로 크기를책정
* 클래스 설명은 if, and, or, but 을 사용하지 않고 25단어 내외로 가능 해야 한다.</code></pre><h3 id="단일-책임-원칙-srp-중요성">단일 책임 원칙 (SRP) 중요성</h3>
<blockquote>
<ul>
<li>자잘한 단일 클래스가 많아지면 큰 그림을 이해하기 어렵다고 우려.</li>
</ul>
</blockquote>
<ul>
<li>하지만 작은 클래스가 많은 시스템이든 큰 클래스가 몇 개뿐인 시스템이든 돌아가는 부품은 그 수가 비슷.</li>
<li>큼직한 다목적 클래스 몇개로 이뤄진 시스템은 당장 알 필요가 없는 사실까지 들이밀어 독자를 방해.</li>
</ul>
<h2 id="03-낮은-결합도-높은-응집도">03. 낮은 결합도, 높은 응집도</h2>
<p><img src="https://velog.velcdn.com/images/rlj_su/post/f151bf8c-a5ab-4ff0-b91e-3f8f1a1b1c9c/image.png" alt=""></p>
<h4 id="결합도는-낮을-수록-응집도는-높을-수록-유지-보수성이-좋다">결합도는 낮을 수록 응집도는 높을 수록 유지 보수성이 좋다.</h4>
<h5 id="결합도가-높을-경우">결합도가 높을 경우</h5>
<ul>
<li>연관된 클래스가 변경되면 수정이 필요</li>
<li>결합도가 높으면 연관된 클래스들을 모두 이해해야 한다.</li>
</ul>
<h5 id="응집도가-낮은-경우">응집도가 낮은 경우</h5>
<ul>
<li>여러 기능이 있으므로 이해하기 어렵다.</li>
<li>재사용하기 어렵다</li>
</ul>
<h3 id="낮은-결합도">낮은 결합도</h3>
<pre><code>* 시스템의 결합도를 낮추면 유연성과 재사용성도 더욱 높아진다.
* DIP - 클래스가 상세한 구현이 아니라 추상화에 의존해야한다.
* 추상화를 이용하면 테스트 코드 짜기에 용이한다.</code></pre><h3 id="높은-응집도">높은 응집도</h3>
<pre><code>* 클래스는 인스턴스 변수 수가 적어야 한다. 메서드는 인스턴스 변수를 하나 이상 사용해야 한다.
* 클래스에 속한 메서드와 변수가 서로 의존하며 논리적인 단위로 묶인다 = 서로 관계있는 애들만 모여있다.</code></pre>]]></description>
        </item>
    </channel>
</rss>