<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Seungjae.log</title>
        <link>https://velog.io/</link>
        <description>코드 품질의 중요성을 아는 개발자 👋🏻</description>
        <lastBuildDate>Tue, 21 Jun 2022 08:32:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Seungjae.log</title>
            <url>https://images.velog.io/images/l0_0l/profile/236c2789-5f7a-4da1-94f9-6207dde22cbc/github 프로필사진.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Seungjae.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/l0_0l" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[9장. 애플리케이션 조립하기]]></title>
            <link>https://velog.io/@l0_0l/9%EC%9E%A5.-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%A1%B0%EB%A6%BD%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@l0_0l/9%EC%9E%A5.-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%A1%B0%EB%A6%BD%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 21 Jun 2022 08:32:02 GMT</pubDate>
            <description><![CDATA[<h2 id="왜-조립까지-신경-써야-할까">왜 조립까지 신경 써야 할까?</h2>
<hr>
<ul>
<li><p><strong>모든 의존성은 애플리케이션의 도메인 코드 방향으로 향해야 도메인 코드가 바깥 계층의 변경으로부터 안전하다!</strong></p>
</li>
<li><p>유스케이스가 영속성 어댑터를 직접 호출하고 스스로 인스턴스화 한다면 <strong>의존성 방향이 잘못되게 된다.</strong></p>
<ul>
<li>이것을 해결하기 위해 우리는 <strong>아웃고잉 포트 인터페이스를 도입</strong>했다.</li>
<li>유스케이스는 <strong>인터페이스만 알아야</strong> 하고, <strong>런타임에 이 인터페이스의 구현을 제공받아야</strong> 한다.</li>
</ul>
</li>
<li><p>클래스가 필요로 하는 <strong>모든 객체를 생성자로 전달</strong>한다면 <strong>테스트하기 더 용이</strong>하다.</p>
<ul>
<li>실제 객체 대신 <strong>Mock</strong>으로 전달할 수 있고, 이로 인해 <strong>격리된 단위 테스트를 생성하기가 쉬워</strong>진다.</li>
</ul>
</li>
<li><p>그러면 결국 누군가 객체 인스턴스를 생성해야할텐데… 누가 책임을 가지게 되는가?</p>
<ul>
<li><strong>⇒ 설정 컴포넌트</strong></li>
</ul>
</li>
<li><p><strong>설정 컴포넌트</strong> → 아키텍처에 대해 중립적이고 인스턴스 생성을 위해 모든 클래스에 대한 의존성을 가진다.</p>
</li>
<li><p>설정 컴포넌트는 클린 아키텍처 구조에서 원의 가장 바깥쪽에 위치!</p>
</li>
<li><p>설정 컴포넌트는 애플리케이션을 <strong>조립하는 것을 책임</strong>진다. (우리가 설정한대로!) 세부적으로는 아래와 같은 역할을 수행한다.</p>
</li>
</ul>
<blockquote>
</blockquote>
<ul>
<li>웹 어댑터 인스턴스 생성</li>
<li>HTTP 요청이 실제로 웹 어댑터로 전달되도록 보장</li>
<li>유스케이스 인스턴스 생성</li>
<li>웹 어댑터에 유스케이스 인스턴스 제공</li>
<li>영속성 어댑터 인스턴스 생성</li>
<li>유스케이스에 영속성 어댑터 인스턴스 제공</li>
<li>영속성 어댑터가 실제로 데이터베이스에 접근할 수 있도록 보장</li>
</ul>
<ul>
<li><p>또한 설정 컴포넌트는 설정 파일이나 커맨드라인 파라미터 등과 같은 설정 파라미터의 소스에도 접근 가능해야한다!</p>
</li>
<li><p>사실 설정 컴포넌트는 책임이 굉장히 많다. → SRP 위반일까?</p>
<ul>
<li>맞다. SRP 위반이다. 하지만 애플리케이션의 다른 부분을 깔끔하게 유지하기 위해 이처럼 모든 구성 요소들을 알고 조립해주는 바깥쪽 컴포넌트를 둔 것이다.</li>
<li>즉 <strong>Trade-Off</strong>라고 볼 수 있겠다.</li>
</ul>
</li>
</ul>
<h2 id="평범한-코드로-조립하기">평범한 코드로 조립하기</h2>
<hr>
<ul>
<li><p><strong>자바의 main 메서드 안에서 웹 컨트롤러부터 영속성 어댑터까지, 필요한 모든 클래스의 인스턴스를 생성한 후 연결한다. 뿐만 아니라 웹 컨트롤러를 HTTP로 노출시키는 로직도 필요하다.</strong></p>
</li>
<li><p>애플리케이션을 조립하는 가장 기본적인 방법이다.</p>
</li>
<li><p>하지만 <strong>단점</strong>이 존재한다.</p>
<ol>
<li>완전한 엔터프라이즈 애플리케이션을 실행하기 위해서는 정말 많은 양의 코드를 작성해야 한다.</li>
<li>각 클래스가 속한 외부에서 인스턴스를 생성하기 때문에 이 클래스들은 전부 public이어야 한다.</li>
</ol>
</li>
<li><p><strong>package-private 의존성을 유지하면서 지저분한 작업들을 대신해주는 의존성 주입 프레임워크들이 존재한다.</strong></p>
<ul>
<li>ex) 스프링 → 웹과 DB 환경을 지원한다!</li>
</ul>
</li>
</ul>
<h2 id="스프링-클래스패스-스캐닝으로-조립하기">스프링 클래스패스 스캐닝으로 조립하기</h2>
<hr>
<ul>
<li><p><strong>애플리케이션 컨텍스트</strong> → 스프링을 이용해서 애플리케이션을 조립한 결과물</p>
</li>
<li><p><strong>Bean</strong> → <strong>애플리케이션을 구성하는 모든 객체</strong></p>
</li>
<li><p>스프링은 classpath Scanning으로 classpath에서 접근 가능한 모든 클래스를 확인해서 @Component가 붙은 클래스를 찾는다. 그리고 이러한 클래스들의 인스턴스를 모두 만들어 애플리케이션 컨텍스트에 추가한다.</p>
</li>
</ul>
<h3 id="classpath">classpath?</h3>
<ul>
<li><p>JVM 혹은 자바 컴파일러가 클래스나 패키지를 찾을 때 기준이 되는 경로를 말한다.</p>
</li>
<li><p>소스 코드(.java)를 컴파일 후 바이트코드(.class)로 변환하고, JVM이 바이트코드로 된 파일을 실행하려면 찾아야 하는데 이 바이트코드까지의 경로를 클래스패스라고 한다.</p>
<ul>
<li>출처: <a href="https://beststar-1.tistory.com/17">https://beststar-1.tistory.com/17</a></li>
</ul>
</li>
<li><p>@Component를 활용해서 메타-애너테이션으로 임의의 정보를 더 표현하는 애너테이션을 만들어서 사용할 수도 있다. (책 내의 @PersistenceAdapter)</p>
</li>
<li><p>classpath Scanning은 단점이 존재한다.</p>
<ol>
<li>프레임워크에 특화된 애너테이션을 붙여야 한다는 점에서 침투적이다.<ol>
<li>특히 다른 개발자들이 사용할 라이브러리나 프레임워크를 만드는 입장에서는 매우 지양해야한다.</li>
</ol>
</li>
<li>원인을 찾는데 수일이 걸릴 수 있는 숨겨진 부수 효과를 야기할 수 있다.</li>
</ol>
</li>
<li><p><strong>즉, classpath Scanning + @Component 방식은 애플리케이션 내의 모든 관계를 파악하기 매우 어렵다. 그 관련된 설정 정보가 전부 흩어져있기 때문이다!</strong></p>
</li>
</ul>
<h2 id="스프링의-자바-컨피그로-조립하기">스프링의 자바 컨피그로 조립하기</h2>
<hr>
<ul>
<li><p><strong>애플리케이션 컨텍스트에 추가할 빈을 생성하는 설정 클래스를 만드는 방식이다.</strong></p>
</li>
<li><p><strong>@Configuration</strong>을 통해서 스프링의 classpath scanning에서 발견해야할 설정 클래스임을 표시한다.</p>
<ul>
<li><strong>똑같이 classpath scanning을 사용하지만 모든 빈을 애플리케이션 전체에서 다 확인하며 컨텍스트에 넣는 것이 아닌 설정 클래스에서 모든 설정 관련 작업이 이뤄지기에 그 관계를 파악하기 쉽다.</strong></li>
</ul>
</li>
<li><p><strong>@Bean</strong>가 붙은 팩터리 메서드를 통해 빈 생성</p>
</li>
<li><p><strong>@EnabledJpaRepositories</strong>를 사용하면 우리가 정의한 모든 스프링 데이터 리포지토리 인터페이스의 구현체를 생성해서 제공한다.</p>
<ul>
<li>설정 클래스뿐만 아니라 메인 애플리케이션에도 붙일 수 있다.</li>
<li><strong>하지만, 그러면 애플리케이션이 시작할 때마다 JPA가 활성화된다. 즉, 영속성이 필요없는 테스트에서도 JPA 리포지토리들을 활성화하게 된다.</strong></li>
<li><strong>즉 이런 ‘기능 애너테이션’을 별도의 설정 모듈로 옮기는 편이 애플리케이션을 더 유연하게 만들고, 항상 모든 것을 한꺼번에 시작할 필요 없게 해준다.</strong></li>
</ul>
</li>
<li><p>또한 특정 모듈에 대한 설정 클래스를 따로 두어, 특정 모듈만 포함하고 그 다른 모듈의 빈은 모킹해서 애플리케이션 컨텍스트를 만들 수 있다. → <strong>테스트에 큰 유연성</strong></p>
</li>
<li><p>또한 애플리케이션 계층을 스프링 프레임워크에 대한 의존성 없이 깔끔하게 유지할 수 있다. @Component를 여기저기에 안붙여도 되기 때문!</p>
</li>
<li><p>하지만 <strong>문제점</strong>도 존재한다.</p>
<ul>
<li><strong>설정 클래스가 생성하는 빈이 설정 클래스와 같은 패키지에 존재하지 않는다면 이 빈들은 public으로 만들어야한다.</strong></li>
</ul>
</li>
</ul>
<h2 id="유지보수-가능한-sw를-만드는데-어떻게-도움이-될까">유지보수 가능한 SW를 만드는데 어떻게 도움이 될까?</h2>
<hr>
<ul>
<li><p><strong>스프링은 우리가 제공하는 부품들을 이용해서 애플리케이션을 조립해준다.</strong></p>
</li>
<li><p>이런 기능을 통해 애플리케이션 전체를 고민하지 않고도 빠르게 개발할 수 있다.</p>
</li>
<li><p><strong>애플리케이션 조립을 책임지는 전용 설정 컴포넌트를 만들면,</strong> 서로 다른 모듈로부터 독립되어 코드 상에서 손쉽게 옮겨 다닐 수 있는 응집도 높은 모듈을 만들 수 있다. 물론 설정 컴포넌트를 유지보수하는데의 cost가 생긴다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[8장. 경계 간 매핑하기]]></title>
            <link>https://velog.io/@l0_0l/8%EC%9E%A5.-%EA%B2%BD%EA%B3%84-%EA%B0%84-%EB%A7%A4%ED%95%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@l0_0l/8%EC%9E%A5.-%EA%B2%BD%EA%B3%84-%EA%B0%84-%EB%A7%A4%ED%95%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 21 Jun 2022 08:24:37 GMT</pubDate>
            <description><![CDATA[<h2 id="매핑하지-않기-전략">‘매핑하지 않기&#39; 전략</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/24c334cb-d47c-46c1-bc03-bc49b3bfcb2d/image.png" alt=""></p>
<ul>
<li><p>포트 인터페이스가 도메인 모델을 입출력 모델로 사용하면 두 계층 간의 매핑을 할 필요가 없다.</p>
</li>
<li><p>즉, <strong>웹 계층과 애플리케이션 계층, 영속성 계층 모두 도메인 모델인 Account에 접근하는 것</strong>이다.</p>
<ul>
<li>물론 책의 그림상으로는 연결되어 있지 않지만, 실제 코드를 작성하면 어쩔 수 없이 웹 계층과 애플리케이션 계층도 Account를 알게 된다.</li>
</ul>
</li>
<li><p>이 <strong>결과는?</strong></p>
<ul>
<li>도메인과 애플리케이션 계층은 웹이나 영속성과 관련된 특수한 요구사항에 관심이 없음에도 웹과 영속성 관련 요구사항을 다뤄야 한다.</li>
<li>기술적 요구사항이 아니더라도, 특정 계층에만 필요한 필드로 도메인 모델이 더럽혀질 수 있다.</li>
<li>즉 Account는 웹, 애플리케이션, 영속성 계층과 관련된 이유로 변경된다!<ul>
<li><strong>SRP 위반</strong></li>
</ul>
</li>
</ul>
</li>
<li><p>하지만 이 “No Mapping 전략”이 딱 들어맞을 때가 있다.</p>
<ul>
<li>간단한 CRUD 유스케이스에서 같은 필드를 가진 웹 모델을 도메인 모델로, 혹은 도메인 모델을 영속성 모델로 매핑할 필요가 있을까?</li>
<li><strong>그럴 필요 없다.</strong></li>
</ul>
</li>
<li><p><strong>즉 모든 계층이 정확히 같은 구조, 같은 정보를 필요로 한다면  “No Mapping 전략”은 완벽한 선택지이다.</strong></p>
</li>
<li><p>물론 애플리케이션 계층이나 도메인 계층에서 웹과 영속성 문제를 다루게 되면 곧바로 다른 전략을 고려해야한다.</p>
</li>
<li><p><strong>중요한 점 → 어떤 매핑 전략을 선택했더라도 나중에 언제든 바꿀 수 있다!</strong></p>
</li>
</ul>
<h2 id="양방향-매핑-전략">‘양방향’ 매핑 전략</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/28333381-70fc-46b7-8ff0-52396af6041e/image.png" alt=""></p>
<ul>
<li><p>각 어댑터가 <strong>전용 모델</strong>을 가지고 있어서 <strong>해당 모델을 도메인 모델로, 도메인 모델을 해당 모델로 매핑할 책임</strong>을 가진다.</p>
</li>
<li><p>각 계층은 도메인 모델과는 완전히 다른 구조의 전용 모델 보유</p>
</li>
<li><p><strong>웹 계층</strong> → 웹 모델을 인커밍 포트에서 필요한 도메인 모델로 매핑, 인커밍 포트에 의해 반환된 도메인 객체를 다시 웹 모델로 매핑</p>
</li>
<li><p><strong>영속성 계층</strong> → 웹 계층에서 이뤄지는 매핑과 유사</p>
</li>
<li><p>이때 두 계층 모두 양방향으로 매핑하기 때문에 → <strong>‘양방향’ 매핑 전략</strong></p>
</li>
<li><p>각 계층의 전용 모델을 변경해도 <strong>다른 계층에 영향 X</strong></p>
<ul>
<li><strong>각각의 웹 모델, 도메인 모델, 영속성 모델이 자신의 목적에 부합하는 최적의 구조를 가질 수 있다.</strong></li>
</ul>
</li>
<li><p>‘양방향’ 매핑 전략의 사용은 웹이나 영속성 관심사로 오염되지 않은 깨끗한 도메인 모델로 이어진다.</p>
<ul>
<li><strong>SRP 만족</strong></li>
</ul>
</li>
<li><p><strong>매핑 책임이 명확하고, 안쪽 계층이 해당 계층의 모델만 알면 되기 때문에 매핑 대신 도메인 로직에 집중할 수 있다!</strong></p>
</li>
<li><p>하지만! 아래와 같은 <strong>단점</strong> 보유</p>
<ul>
<li>너무 많은 보일러플레이트 코드</li>
<li>도메인 모델이 계층 경계를 넘어서 통신하는데 사용 → 포트의 파라미터, 반환값으로 도메인 모델이 사용되어 바깥쪽 계층의 요구에 따른 변경에 취약</li>
</ul>
</li>
<li><p>매핑 전략 고려시 <strong>주의점</strong>!</p>
<ul>
<li><strong>은총알은 없다! → 모든 상황에 맞는 완벽한 해결책은 없다!</strong></li>
<li>어떤 매핑 전략도 철칙처럼 여겨져서는 안 된다!</li>
<li>각 유스케이스마다 적절한 전략을 선택할 수 있어야 한다!</li>
</ul>
</li>
</ul>
<h2 id="완전-매핑-전략">‘완전’ 매핑 전략</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/81ff7296-d3ad-434a-9cce-43c41432ad46/image.png" alt=""></p>
<ul>
<li><p><strong>각 연산마다 별도의 입출력 모델을 사용한다.</strong></p>
</li>
<li><p>웹 어댑터와 애플리케이션 계층 각각이 자신의 전용 모델을 각 연산을 실행하는데 필요한 모델로 매핑</p>
</li>
<li><p><strong>웹 계층은</strong> 입력을 애플리케이션 계층의 커맨드 객체로 매핑할 책임을 가진다.</p>
<ul>
<li>커맨드 객체는 애플리케이션 계층의 인터페이스를 해석할 여지 없이 명확하게 만든다.</li>
</ul>
</li>
<li><p><strong>각 유스케이스</strong>는 전용 필드와 유효성 검증 로직을 가진 <strong>전용 커맨드를 가진다.</strong></p>
</li>
<li><p><strong>애플리케이션 계층</strong>은 커맨드 객체를 유스케이스에 따라 도메인 모델을 변경하기 위해 필요한 무엇인가로 매핑할 책임을 가진다.</p>
</li>
<li><p><strong>앞에 것들보다 더 많은 코드가 필요하지만, 구현하고 유지보수하기는 매우 쉽다.</strong></p>
<ul>
<li><strong>유효성 검증</strong>을 SendMoneyCommand같은 <strong>전용 커맨드 객체에서 수행해줄 수 있다!</strong></li>
</ul>
</li>
<li><p>이 전략은 애플리케이션 계층과 웹 계층 사이에서 상태 변경 유스케이스의 경계를 명확하게 할 때 가장 빛을 발한다!</p>
<ul>
<li>애플리케이션 계층과 영속성 계층 사이에서는 매핑 오버헤드 때문에 사용하지 않는 것이 좋다!</li>
</ul>
</li>
</ul>
<h3 id="매핑-오버헤드">매핑 오버헤드?</h3>
<ul>
<li><p>왜 애플리케이션 계층과 웹 계층 사이의 매핑은 추천하면서 애플리케이션 계층과 영속성 계층 사이에서의 매핑은 매핑 오버헤드라고 할까?</p>
</li>
<li><p>⇒ 웹 어댑터 계층과 유스케이스 계층 사이에서는 유효성 검증이라는 분명한 책임이 있지만, 애플리케이션 계층에서 영속성 계층으로 넘겨줄 때에는 전용 모델을 따로 두고 매핑할만한 명확한 이유, 책임, 효용성이 없다. 그렇기에 매핑 오버헤드라 표현했다고 생각한다.</p>
</li>
<li><p>어떤 경우에는 연산의 입력 모델에 대해서만 이 매핑을 사용하고 도메인 객체를 그대로 출력 모델로 사용하는 것도 좋다!</p>
</li>
<li><p><strong>즉, 여러가지 전략을 섞어쓸 수 있고, 섞어 써야만 한다! → 어떤 매핑 전략도 모든 계층에 걸쳐 전역 규칙일 필요가 없다!</strong></p>
</li>
</ul>
<h2 id="단방향-매핑-전략">‘단방향’ 매핑 전략</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/bf5ede92-c0e8-48c0-8e9f-70c5aa78fb7c/image.png" alt=""></p>
<ul>
<li><p><strong>동일한 상태 인터페이스</strong>를 구현하는 도메인 모델과 어댑터 모델을 이용하면 각 계층은 다른 계층으로부터 온 객체를 단방향으로 매핑하면 된다.</p>
</li>
<li><p>상태 인터페이스는 관련 있는 특성에 대한 <strong>getter 메서드</strong>를 제공! → 도메인 모델의 상태 <strong>캡슐화</strong></p>
</li>
<li><p><strong>도메인 모델</strong> → 풍부한 행동 구현 가능하고 애플리케이션 계층 내의 서비스에서 이러한 행동에 접근 가능</p>
</li>
<li><p>도메인 객체를 <strong>바깥 계층으로</strong> 전달하고 싶으면 <strong>매핑 없이 가능!</strong></p>
</li>
<li><p><strong>행동이 상태 인터페이스에 의해 노출돼 있지 않기 때문에 실수로 도메인 객체의 상태를 변경하는 일은 발생X</strong></p>
</li>
<li><p>애플리케이션 계층에서는 바깥에서 전달한 이 상태 인터페이스를 도메일  모델로 매핑해서 도메인 모델의 행동에 접근</p>
</li>
<li><p>상태 인터페이스를 받아서 해당 계층에서 이용할 수 있는 다른 무엇인가로 매핑해 사용할 수 있기 때문에 한 방향으로만 매핑하는 <strong>‘단방향’ 매핑 전략</strong>인 것이다!</p>
</li>
<li><p>매핑이 계층을 넘나들며 퍼져있기 때문에 다른 전략에 비해 개념적으로 어렵다!</p>
</li>
<li><p>하지만 계층간의 모델이 비슷할 경우 사용하면 효과적이다. 예를 들어 읽기 전용 연산 처럼 상태 인터페이스가 필요한 모든 정보를 제공해줄 경우에는 웹 계층에서 전용 모델로 매핑할 필요가 없어진다.</p>
</li>
</ul>
<h2 id="언제-어떤-매핑-전략을-사용할-것인가">언제 어떤 매핑 전략을 사용할 것인가?</h2>
<hr>
<ul>
<li><p>답은 <strong>‘그때 그때 다르다’</strong></p>
</li>
<li><p>매핑 전략은 모두 각각의 장단점을 가지고 있다! 그렇기에 <strong>어떤 한 전략을 코드 전체에 대해 적용하면 안된다!</strong></p>
</li>
<li><p>또한 <strong>SW는 시간이 지나며 변화하기 때문에, 어제는 최선이었던 전략이 오늘은 아닐수도 있다.</strong></p>
</li>
<li><p><strong>고정된 매핑 전략을 유지하기보다는 빠르게 코드를 짤 수 있는 간단한 전략으로 시작해서 계층 간 결합을 떼어내는 데 도움이 되는 복잡한 전략으로 갈아타는 것도 좋은 방법</strong>이다.</p>
</li>
</ul>
<h3 id="올가미를-미리-두지-말자-첫번째-총알은-맞고-다음-번에-날아올-총알에-대비하자">올가미를 미리 두지 말자! 첫번째 총알은 맞고, 다음 번에 날아올 총알에 대비하자!</h3>
<blockquote>
</blockquote>
<ul>
<li><p>추상화에 대해서 나온 이야기지만 매핑 전략에 관련되서도 어느정도 적용되는 이야기인 것 같다.</p>
</li>
<li><p>일어나지도 않은 변화를 미리 예상하고 걱정하여 올가미를 두는 행동은 코드 악취로 이어질 수 있음을 경고하는 이야기이다!</p>
</li>
<li><p>이런 전략의 사용에 대해 팀 내에서 합의하기 위해 <strong>가이드라인</strong>을 정해둘 필요가 있다!</p>
</li>
<li><p>가이드라인은 <strong>아래와 같은 질문에 답할 수 있어야한다.</strong></p>
<ul>
<li>어떤 상황에서 어떤 매핑 전략을 가장 먼저 택해야하는가?</li>
<li>왜 해당 전략을 최우선으로 택해야하는가?</li>
</ul>
</li>
</ul>
<h2 id="유지보수-가능한-sw를-만드는-데-어떻게-도움이-될까">유지보수 가능한 SW를 만드는 데 어떻게 도움이 될까?</h2>
<hr>
<ul>
<li><p>인커밍 포트, 아웃고잉 포트는 서로 다른 계층이 어떻게 통신해야하는지 정의</p>
</li>
<li><p>좁은 포트를 사용하면 유스케이스마다 다른 매핑 전략을 사용할 수 있다.</p>
</li>
<li><p>즉, 다른 유스케이스에 영향을 미치지 않으면서 코드를 개선할 수 있다. → 특정 상황, 특정 시점에 최선의 전략 선택 가능!</p>
</li>
<li><p>상황별로 매핑 전략을 어떻게 설정할지 정의한 <strong>매핑 가이드 라인</strong>을 통해, 코드가 정확히 해야 하는 일만 수행하면서도 더 유지보수하기 쉬운 코드가 될 것이다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[7장. 아키텍처 요소 테스트하기]]></title>
            <link>https://velog.io/@l0_0l/7%EC%9E%A5.-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%9A%94%EC%86%8C-%ED%85%8C%EC%8A%A4%ED%8A%B8%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@l0_0l/7%EC%9E%A5.-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%9A%94%EC%86%8C-%ED%85%8C%EC%8A%A4%ED%8A%B8%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 21 Jun 2022 08:08:24 GMT</pubDate>
            <description><![CDATA[<h2 id="테스트-피라미드">테스트 피라미드</h2>
<hr>
<p><img src="blob:https://velog.io/276bf16e-5aee-4d8f-aab6-b0bb938551bb" alt="업로드중.."></p>
<ul>
<li><p><strong>만드는 비용이 적고, 유지보수하기 쉽고, 빨리 실행되고, 안정적인 작은 크기의 테스트들에 대해 높은 커버리지를 유지해야한다.</strong></p>
</li>
<li><p>테스트가 비싸질수록 테스트의 커버리지 목표는 낮게 잡아야한다.  그렇지 않으면 새로운 기능을 만드는 것보다 테스트를 만드는데 시간을 더 쓰게 된다.</p>
</li>
<li><p>위의 ‘시스템 테스트’, ‘통합 테스트’, ‘단위 테스트’의 정의는 맥락에 따라 다를 수 있다.</p>
</li>
<li><p><strong>단위 테스트</strong> → 일반적으로 하나의 클래스를 인스턴스화하고 해당 클래스의 인터페이스를 통해 기능들을 테스트</p>
<ul>
<li>테스트 대상 클래스가 <strong>다른 클래스에 의존</strong>하고 있다면 의존되는 클래스들은 인스턴스화하지 않고 <strong>테스트 동안 필요한 작업들을 흉내내는 Mock으로 대체!</strong></li>
</ul>
</li>
<li><p><strong>통합 테스트</strong> → 연결된 여러 유닛을 인스턴스화하고 시작점이 되는 클래스의 인터페이스로 데이터를 보낸 후, 유닛들의 네트워크가 기대한대로 잘 동작하는지 검증</p>
</li>
<li><p><strong>시스템</strong> <strong>테스트</strong> → 애플리케이션을 구성하는 모든 객체 네트워크를 가동시켜 특정 유스케이스가 전 계층에서 잘 동작하는지 검증</p>
</li>
</ul>
<h2 id="단위-테스트로-도메인-엔티티-테스트하기">단위 테스트로 도메인 엔티티 테스트하기</h2>
<hr>
<ul>
<li><p>책 내의 Account에 대한 <strong>단위 테스트</strong></p>
<ol>
<li>특정 상태의 Account를 인스턴스화</li>
<li>withdraw() 메서드 호출</li>
<li>출금 성공했는지 검증</li>
<li>Account 객체의 상태에 대해 기대되는 부수효과들 잘 일어났는지 확인</li>
</ol>
</li>
<li><p>만들고 이해하기 쉬운 편이고, 아주 빠르게 실행된다.</p>
</li>
<li><p><strong>이런 식의 단위 테스트는 도메인 엔티티에 녹아 있는 비즈니스 규칙을 검증하기에 가장 적절한 방법이다.</strong></p>
</li>
</ul>
<h2 id="단위-테스트로-유스케이스-테스트하기">단위 테스트로 유스케이스 테스트하기</h2>
<hr>
<ul>
<li><p>테스트 <strong>가독성</strong>을 높이기 위해 <strong>행동-주도 개발</strong>에서 일반적으로 사용되는 방식으로 작성</p>
<ul>
<li>given / when / then<ul>
<li><strong>given</strong> → 테스트에 필요한 것들을 준비</li>
<li><strong>when</strong> → 테스트 하려하는 행위 호출</li>
<li><strong>then</strong> → 테스트로 인해 의도된 행위가 호출되었는지, 원하는 상태 변화가 발생했는지 검증</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>이때 테스트에서 특정 메서드와 상호작용했는지 여부를 검증하는 경우</strong></p>
<ul>
<li>테스트가 코드의 행동 변경뿐만 아니라 코드의 구조 변경에도 취약해진다.</li>
<li>코드가 리팩토링되면 <strong>테스트도 변경될 확률이 높아진다.</strong></li>
<li>즉, 신중하게 생각해야한다.</li>
<li><strong>모든 동작을 검증하려는 것보다, 중요한 핵심에 집중해서 테스트하자!</strong></li>
</ul>
</li>
<li><p>책 내의 예시 테스트는 단위 테스트지만 의존성의 상호작용을 테스트하고 있기 때문에 통합 테스트와 유사</p>
<ul>
<li>하지만 Mock으로 작업하고 있고, 실제 의존성을 관리해야 하는 것은 아니기 때문에 완전한 통합 테스트에 비해 만들고 유지보수하기 쉽다!</li>
</ul>
</li>
</ul>
<h2 id="통합-테스트로-웹-어댑터-테스트하기">통합 테스트로 웹 어댑터 테스트하기</h2>
<hr>
<ul>
<li><p>웹 어댑터 테스트는 <strong>아래의 것들이 모두 기대한 대로 동작하는지 검증</strong></p>
<ol>
<li>JSON 문자열 등의 형태로 HTTP를 통해 입력 받기</li>
<li>입력에 대한 유효성 검증</li>
<li>유스케이스에서 사용할 수 있는 포맷으로 매핑</li>
<li>유스케이스에 전달</li>
<li>유스케이스의 결과를 JSON으로 매핑</li>
<li>HTTP 응답을 통해 클라이언트에 반환</li>
</ol>
</li>
<li><p><strong>웹 어댑터 테스트</strong></p>
<ul>
<li>Mock HTTP 요청을 웹 컨트롤러에 보낸다.</li>
<li>요청 바디는 JSON 문자열의 형태로 입력 객체에 포함한다.</li>
<li>HTTP의 응답 상태가 기대했던 것과 같은지 검증하고, 모킹한 유스케이스가 잘 호출됐는지 검증한다.</li>
</ul>
</li>
<li><p>MockMvc를 사용해 모킹했기 때문에 실제로 <strong>HTTP 프로토콜을 통해 테스트한 것은 아니다.</strong></p>
<ul>
<li>프레임워크가 HTTP 프로토콜에 맞게 모든 것을 적절히 잘 변환한다고 믿는 것!</li>
<li><strong>프레임워크를 테스트할 필요는 없기 때문!</strong></li>
</ul>
</li>
</ul>
<h3 id="테스트-해야할-것-테스트-할-필요없는-것">테스트 해야할 것, 테스트 할 필요없는 것</h3>
<blockquote>
</blockquote>
<ul>
<li><p>위에 나온대로 프레임워크를 테스트할 필요는 없다.</p>
<ul>
<li>Why?</li>
<li>프레임워크는 이미 똑똑하신 분들이 많은 검증을 거쳐서 만들어 놓으신 것이다. 바퀴를 다시 만들 필요는 없다는 말과 같은 의미이다.</li>
</ul>
</li>
<li><p>이러한 맥락을 바탕으로 <strong>테스트가 필요한 것, 필요 없는 것을 구분하는 것도 매우 중요한 포인트</strong>라고 생각한다.</p>
</li>
<li><p>이 테스트는 왜 단위 테스트가 아닌 통합 테스트일까?</p>
<ul>
<li>컨트롤러 클래스만 테스트한 것 같지만, 그렇지 않다. 훨씬 더 많은 일이 벌어지고 있다.</li>
<li><strong>@WebMvcTest</strong> 애너테이션은 스프링이 특정 요청 경로, 자바와 JSON 간의 매핑, HTTP 입력 검증 등에 필요한 <strong>전체 객체 네트워크를 인스턴스화</strong>하도록 만든다.</li>
<li>테스트에서는 웹 컨트롤러가 이 네트워크의 일부로서 잘 작동하는지 검증</li>
<li>즉, 웹 컨트롤러가 스프링 프레임워크에 강하게 묶여 있다!<ul>
<li>⇒ <strong>격리된 상태로 테스트하기보다는 이 프레임워크와 통합된 상태로 테스트하는 것이 합리적</strong></li>
</ul>
</li>
<li>웹 컨트롤러만 따로 <strong>단위테스트로 테스트한다면</strong> 모든 매핑, 유효성 검증, HTTP 항목에 대한 커버리지가 낮아지고, 프레임워크를 구성하는 이런 요소들이 프로덕션 환경에서 정상적으로 작동하는지 확신할 수 없게 된다.</li>
</ul>
</li>
</ul>
<h2 id="통합-테스트로-영속성-어댑터-테스트하기">통합 테스트로 영속성 어댑터 테스트하기</h2>
<hr>
<ul>
<li><p><strong>웹 어댑터 테스트와 비슷한 이유로, 영속성 어댑터도 통합 테스트 적용이 합리적이다.</strong></p>
</li>
<li><p><strong>@DataJpaTest</strong> 사용</p>
<ul>
<li>스프링 데이터 리포지토리들을 포함해서 DB 접근에 필요한 객체 네트워크를 인스턴스화해야 한다고 스프링에 알려준다.</li>
</ul>
</li>
<li><p>이 테스트에서 DB를 모킹하지 않는다.</p>
<ul>
<li>즉, DB에 접근하게 된다.</li>
</ul>
</li>
<li><p><strong>모킹을 이용할 경우, 실제 DB와 연동했을 때, SQL 구문의 오류나 DB 테이블과 자바 객체 간의 매핑 에러 등으로 문제가 생길 확률이 높아지기 때문!</strong></p>
</li>
<li><p>스프링에서는 기본적으로 인메모리 DB를 테스트에서 사용한다. 하지만 프로덕션 환경에서 인메모리 DB를 사용하는 경우는 적기 때문에, 인메모리 DB에서 테스트를 통과했더라도 실제 DB에서 문제가 생길수도 있다. (DB 방언 같은 것 때문에..!)</p>
<ul>
<li><strong>즉, 영속성 어댑터 테스트는 실제 DB를 대상으로 진행하는 것이 좋다!</strong></li>
<li>인메모리DB를 사용하지 않고 실제 DB를 사용하고자 하는 경우 <strong>@AutoConfigureTestDatabase</strong>를 이용하여 손쉽게 설정할 수 있다.</li>
</ul>
</li>
</ul>
<h2 id="시스템-테스트로-주요-경로-테스트하기">시스템 테스트로 주요 경로 테스트하기</h2>
<hr>
<ul>
<li><p><strong>시스템 테스트는 전체 애플리케이션을 띄우고 API를 통해 요청을 보내고, 모든 계층이 조화롭게 잘 동작하는지 검증한다.</strong></p>
</li>
<li><p><strong>@SpringBootTest</strong> 사용</p>
<ul>
<li>스프링이 애플리케이션을 구성하는 모든 객체 네트워크를 띄우게 한다.</li>
<li>책 내 예제에서는 랜덤 포트로 애플리케이션을 띄우도록 하고 있다.</li>
</ul>
</li>
<li><p>MockMvc가 아닌 <strong>TestRestTemplate</strong>를 이용</p>
<ul>
<li><strong>실제 HTTP 통신</strong>을 수행(프로덕션 환경에 조금 더 가깝다.)</li>
</ul>
</li>
<li><p>실제 HTTP 통신을 하는 것처럼 실제 출력 어댑터도 사용</p>
</li>
<li><p>지저분한 로직들은 <strong>헬퍼 메서드</strong> 안으로 숨겼다. → <strong>가독성 증가</strong></p>
<ul>
<li>이 헬퍼 메서드들은 여러 가지 상태를 검증할 때 사용할 수 있는 <strong>DSL</strong>(도메인 특화 언어, 특정한 도메인을 적용하는 데 특화된 언어)을 형성</li>
</ul>
</li>
<li><p>시스템 테스트는 <strong>훨씬 더 실제 사용자와 유사</strong>하다. → 사용자 관점에서 애플리케이션을 검증할 수 있다.</p>
<ul>
<li><strong>어휘를 사용하면 도메인 전문가가 테스트에 대해 이해하고, 생각하고, 피드백을 줄 수 있다.</strong></li>
<li>JGiven 같은 라이브러리를 활용</li>
</ul>
</li>
<li><p><strong>시스템 테스트는 단위 테스트와 통합 테스트가 발견하는 버그와는 또 다른 종류의 버그를 발견해서 수정할 수 있게 해준다.</strong></p>
</li>
<li><p>시스템 테스트는 여러 개의 유스케이스를 결합해서 <strong>시나리오</strong>를 만들 때 더 빛이 난다.</p>
<ul>
<li><strong>시나리오</strong> → 사용자가 애플리케이션을 사용하면서 거쳐갈 특정 경로</li>
<li>중요한 시나리오들이 커버된다면 최신 변경사항들이 애플리케이션을 망가뜨리지 않았음을 가정할 수 있고, 배포될 준비가 됐다는 확신을 가질 수 있다.</li>
</ul>
</li>
</ul>
<h2 id="얼마만큼의-테스트가-충분할까">얼마만큼의 테스트가 충분할까?</h2>
<hr>
<ul>
<li>라인 커버리지는 테스트 성공을 측정하는 데 있어서 잘못된 지표이다.</li>
</ul>
<h3 id="잘못된-지표">잘못된 지표..?</h3>
<blockquote>
</blockquote>
<ul>
<li><p>잘못된 지표보다는 <strong>절대적이지 않은 지표</strong>라고 보는게 맞다고 생각한다.</p>
</li>
<li><p>라인 커버리지가 높다고 검증이 잘 된, 잘 만들어진 프로젝트라고 할 수는 없다.</p>
</li>
<li><p>하지만 라인커버리지가 낮으면 보통 검증이 제대로 되지 않은, 테스트가 여러 상황을 커버하지 못하는 프로젝트이다.</p>
</li>
<li><p>물론 상황마다 다르겠지만, 외부와 분리된 도메인 코드들이 들어있는 패키지의 커버리지가 매우 낮게 나온다면 그것은 주의깊게 다시 확인할 필요가 있다고 생각한다.</p>
</li>
<li><p>얼마나 <strong>마음 편하게 SW를 배포할 수 있느냐</strong>를 테스트의 성공 기준으로 잡는 것이 좋다!</p>
<ul>
<li>더 자주 배포할수록, 테스트를 더 신뢰할 수 있다!</li>
</ul>
</li>
<li><p>각각의 프로덕션 버그에 대해서 테스트가 그 버그를 잡지 못한 이유에 대해 생각하고, 기록하고 커버할 수 있는 테스트를 추가하는 것이 중요!</p>
</li>
<li><p>책에서 소개하는 <strong>육각형 아키텍처에서 사용하는 테스트 전략</strong></p>
<ol>
<li>도메인 엔티티를 구현할 때는 단위 테스트로 커버하자</li>
<li>유스케이스를 구현할 때는 단위 테스트로 커버하자</li>
<li>어댑터를 구현할 때는 통합 테스트로 커버하자</li>
<li>사용자가 취할 수 있는 중요 애플리케이션 여로(시나리오)는 시스템 테스트로 커버하자</li>
</ol>
</li>
<li><p>테스트 작성 시 <strong>주의 사항</strong></p>
<ul>
<li>개발 후가 아닌 개발 중에 테스트가 이뤄져야한다!<ul>
<li>개발 후에 하는 테스트는 그저 귀찮게 느껴진다...</li>
</ul>
</li>
<li>리팩토링할 때마다 테스트 코드도 변경해야 한다면 테스트는 테스트로서의 가치를 잃는다.<ul>
<li>테스트는 테스트하려는 대상의 구현 세부사항을 드러내면 안된다!</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="유지보수-가능한-sw를-만드는-데-어떻게-도움이-될까">유지보수 가능한 SW를 만드는 데 어떻게 도움이 될까?</h2>
<hr>
<ul>
<li><p>육각형 아키텍처는 <strong>도메인 로직과 바깥으로 향한 어댑터</strong>를 깔끔하게 분리</p>
<ul>
<li><strong>“핵심 도메인 →</strong> <strong>단위 테스트 / 어댑터 → 통합 테스트”</strong> 로 처리하는 명확한 테스트 전략 정의 가능!</li>
</ul>
</li>
<li><p><strong>입출력 포트는 테스트에서 아주 뚜렷한 모킹 지점</strong></p>
<ul>
<li>포트가 아주 작고 핵심만 담고 있다면 모킹하는 것이 아주 쉬울 것이다.</li>
</ul>
</li>
<li><p>모킹하는 것이 너무 버겁거나, 코드의 특정 부분을 커버하기 위해 어떤 종류의 테스트를 써야할지 모르겠다.</p>
<ul>
<li><strong>⇒  이것은 경고 신호다!</strong></li>
<li>테스트는 아키텍처의 문제에 대해 경고</li>
<li><strong>테스트가 피드백을 주고 있는 것이다!</strong></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[6장. 영속성 어댑터 구현하기]]></title>
            <link>https://velog.io/@l0_0l/6%EC%9E%A5.-%EC%98%81%EC%86%8D%EC%84%B1-%EC%96%B4%EB%8C%91%ED%84%B0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@l0_0l/6%EC%9E%A5.-%EC%98%81%EC%86%8D%EC%84%B1-%EC%96%B4%EB%8C%91%ED%84%B0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 09 Jun 2022 07:04:41 GMT</pubDate>
            <description><![CDATA[<ul>
<li>의존성을 역전시키기 위해 영속성 계층을 애플리케이션 계층의 플러그인으로 만드는 방법을 알아보자!</li>
</ul>
<h1 id="의존성-역전">의존성 역전</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/58e1eedb-d68a-4b21-8656-4fb8e4cbb7ff/image.png" alt=""></p>
<ul>
<li><p>코어의 서비스가 영속성 어댑터에 접근하기 위해 포트를 사용, 해당 포트는 영속성 어댑터가 구현하는 형태이다.</p>
</li>
<li><p>포트는 영속성 작업을 수행하고 DB와 통신할 책임을 가진 영속성 어댑터 클래스에 의해 구현된다.</p>
</li>
<li><p>이러한 포트 계층은 영속성 계층에 대한 서비스의 <strong>직접적인 의존을 없애기 존재한다!</strong></p>
<ul>
<li>이로 인해, <strong>영속성 코드를 리팩토링하더라도 코어 코드를 변경하는 결과로 이어지지 않게 된다!</strong></li>
<li><strong>부수효과를 막을 수 있다!</strong></li>
</ul>
</li>
</ul>
<h1 id="영속성-어댑터의-책임">영속성 어댑터의 책임</h1>
<hr>
<blockquote>
</blockquote>
<ol>
<li>입력을 받는다.</li>
<li>입력을 DB 포맷으로 매핑한다.</li>
<li>입력을 DB로 보낸다.</li>
<li>DB 출력을 애플리케이션 포맷으로 매핑한다.</li>
<li>출력을 반환한다.</li>
</ol>
<ul>
<li><p>영속성 어댑터는 포트 인터페이스를 통해 입력을 받는다.</p>
<ul>
<li>입력 모델 - 인터페이스가 지정한 도메인 엔티티나 특정 DB 연산 전용 객체가 된다.</li>
</ul>
</li>
<li><p>입출력 과정에서 매핑이 발생한다.</p>
</li>
<li><p><strong>영속성 어댑터의 입출력 모델이 영속성 어댑터 내부에 있는 것이 아니라 애플리케이션 코어에 있기 때문에, 영속성 어댑터 내부를 변경하는 것이 코어에 영향을 미치지 않게 된다!</strong></p>
</li>
</ul>
<h3 id="지속적으로-강조되고-있는-핵심">지속적으로 강조되고 있는 핵심</h3>
<p><strong>⇒ 외부의 변경이 애플리케이션 코어에 영향을 미치지 못하게 한다!</strong></p>
<h3 id="그게-왜-중요">그게 왜 중요...?</h3>
<p><strong>⇒ 애플리케이션 코어에는 실질적으로 비즈니스적 가치를 전달하는 도메인 로직이 존재하기 때문에!</strong></p>
<h1 id="포트-인터페이스-나누기">포트 인터페이스 나누기</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/4dd5eaad-bab7-4424-9188-a10b6b69226d/image.png" alt=""></p>
<ul>
<li><p>일반적으로 특정 엔티티가 필요한 모든 DB 연산을 하나의 리포지토리 인터페이스에 넣어둔다.</p>
</li>
<li><p>하지만 이러면 <strong>모든 서비스가 실제로는 필요하지 않은 메서드에도 의존</strong>하게 된다!</p>
</li>
<li><p>10개의 메서드를 가지고 있는 인터페이스 중 A 서비스는 3번 메서드 1개만 사용하더라도 이 “넓은” 포트 인터페이스에 의존성을 갖게 되는 것이다. → 코드에 <strong>불필요한 의존성</strong> 발생</p>
<ul>
<li>코드를 이해하고 테스트하기 어렵게 만든다!</li>
</ul>
</li>
<li><p>이러한 상황은 ISP(인터페이스 분리 원칙)를 어긴 것이다.</p>
<ul>
<li><strong>ISP → 클라이언트가 오로지 자신이 필요로 하는 메서드만 알게 되도록 넓은 인터페이스를 특화된 인터페이스로 분리해야 한다.</strong></li>
<li><strong>즉 클라이언트가 필요로하는 최소의 인터페이스만 제공해야한다!</strong></li>
</ul>
</li>
<li><p>아래의 그림은 ISP를 적용하여 불필요한 의존성을 제거한 것이다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/f0aa8ca8-b4ea-4277-b4ed-bf5d3958432d/image.png" alt=""></p>
<ul>
<li><p>각 서비스는 필요한 메서드에만 의존하게 된다.</p>
</li>
<li><p>포트의 이름을 좀 더 포트의 역할을 명확하게 표현하도록 네이밍할 수 있다.</p>
</li>
<li><p>대부분의 경우 각 포트 인터페이스 당 메서드 1개만 존재할 것이기에 필요한 것만 모킹할 수 있다.</p>
</li>
<li><p>매우 좁은 포트 → <strong>플러그 앤드 플레이(plug-and-play)</strong> 경험</p>
<ul>
<li>서비스코드 작성시 다른 과정 필요없이 그저 필요한 포트에만 꽂아서 사용할 수 있는 경험!</li>
</ul>
</li>
<li><p>물론 응집성이 매우 높고 함께 사용될 때가 많은 경우, 하나로 묶을 수 있을 것이다.</p>
</li>
</ul>
<h1 id="영속성-어댑터-나누기">영속성 어댑터 나누기</h1>
<hr>
<ul>
<li>영속성 어댑터 또한 포트처럼 <strong>나눌 수 있다.</strong><ul>
<li><strong>영속성 연산이 필요한 도메인 클래스 하나당 하나의 영속성 어댑터</strong>를 구현하는 방식으로 나눌 수 있다.</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/8876ef65-0640-4d6d-8df3-118883746a61/image.png" alt=""></p>
<ul>
<li><p>이로 인해, 각 영속성 기능을 이용하는 도메인 경계를 확인할 수 있다.</p>
</li>
<li><p>더 많이 나눌 수도 있다. ex) JPA 어댑터와 SQL 어댑터 하나를 만들고 각각 특정한 좁은 영속성 포트를 구현하도록!</p>
</li>
<li><p><strong>도메인 코드는 영속성 포트에 의해 정의된 명세를 어떤 클래스가 충족 시키는지에 관심 없다!</strong></p>
</li>
<li><p>도메인 클래스당 하나의 영속성 어댑터로 나눠 도메인 경계를 확인하는 방식은 나중에 <strong>여러 개의 바운디드 컨텍스트(DDD에서 하나의 경계화된 단위)의 영속성 요구사항을 분리하기 위한 좋은 토대</strong>가 될 수 있다!</p>
<ul>
<li>각 바운디드 컨텍스트 간의 경계를 명확하게 구분하고 싶다면, 바운디드 컨텍스트 각각이 영속성 어댑터를 하나씩 가지고 있어야 한다.</li>
</ul>
</li>
<li><p>이렇게 맥락을 나눴을 때, A 맥락이 다른 맥락인 B의 무엇인가 필요하다면 → 전용 인커밍 포트를 통해 접근한다.</p>
<ul>
<li>즉, A맥락은 B맥락을 <strong>또 다른 인커밍 어댑터</strong>로 보고 있다.</li>
<li><strong>저번에 스터디</strong>에서 이야기 나온 <strong>하나의 프로젝트 내에서 여러개의 도메인</strong>이 나왔을 때!<ul>
<li><strong>이 책에서는 각각의 도메인을 헥사고날 아키텍처로 나누고 서로를 인커밍 어댑터로 취급하며 소통하는 방식을 추구하는 것 같다!</strong></li>
</ul>
</li>
</ul>
</li>
</ul>
<h1 id="스프링-데이터-jpa-예제">스프링 데이터 JPA 예제</h1>
<hr>
<ul>
<li>스프링 데이터 JPA를 사용하여 앞에서 설명한 것들을 예제 코드로 구현하고 있다.</li>
</ul>
<h3 id="영속성-layer아웃고잉에서의-입출력">영속성 Layer(아웃고잉)에서의 입출력...</h3>
<ul>
<li>예제를 보면 <strong>도메인 엔티티</strong> ↔  <strong>영속성 엔티티 를</strong> 서로 매핑해가며 사용하고 있다.<ul>
<li><strong>물론 Cost가 있지만, 영속성 측면과의 타협 없이 풍부한 도메인 모델을 생성하고 싶다면 도메인 모델과 영속성 모델 구분하고 양방향매핑하는 것이 좋다!</strong></li>
</ul>
</li>
<li>여기까지는 OK!</li>
<li><strong>근데 왜! Usecase, Web Layer(인커밍)에서는 입출력 포맷을 각각 나눠서 다시 정의할 것을 추천해놓고 이 예제에서는 도메인 엔티티 그대로 사용할까?</strong><ul>
<li>저의 생각은... → <strong>클라이언트는 누구인가? [Usecase]</strong><ul>
<li>Usecase는 주로 도메인 로직을 통한 도메인 엔티티의 상태 변경을 주로 수행한다.</li>
<li>즉 어차피 <strong>영속성 Layer로 다루는 것, 이 Layer에 요구하는 것</strong> 모두 <strong>도메인 엔티티</strong>이다.</li>
<li>그렇기에 영속성 Layer에서는 굳이 입출력을 따로 정의할 것을 주장하지 않는다고 생각한다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h1 id="db-트랜잭션은-어떻게-해야-할까">DB 트랜잭션은 어떻게 해야 할까?</h1>
<hr>
<ul>
<li><p>트랜잭션은 하나의 특정한 유스케이스에 대해서 일어나는 모든 쓰기 작업에 걸쳐 있어야 한다.</p>
<ul>
<li><strong>그래야 한번에 커밋되고, 중간에 실패할 경우 한번에 롤백할 수 있으니까!</strong></li>
</ul>
</li>
<li><p>헥사고날 아키텍처 구조에서 영속성 어댑터는 어떤 데이터베이스 연산이 유스케이스에 포함되는지 알 수 없다!</p>
<ul>
<li><strong>즉, 이 책임은 영속성 어댑터 호출을 관장하는 서비스에 위임해야 한다!</strong></li>
</ul>
</li>
</ul>
<h3 id="근데-이것도-이-transaction도-외부에-대한-의존성-아닌가">근데 이것도 이 @Transaction도 외부에 대한 의존성 아닌가?</h3>
<p><strong>⇒ 그래서 책에서는 오염되지 않고 깔끔하게 처리하고 싶다면 AspectJ 같은 도구를 이용해 AOP로 트랜잭션 경계를 코드에 위빙할 것을 추천하고 있다.</strong></p>
<h3 id="aspectj를-사용한-위빙이란"><strong>AspectJ를 사용한</strong> 위빙이란?</h3>
<p>컴파일 타임이나 또는 로드 타임때, 타깃 클래스 파일의 바이트 코드를 조작하여 부가기능을 직접 넣어주는 방법</p>
<h1 id="유지보수-가능한-sw를-만드는-데-어떻게-도움이-될까">유지보수 가능한 SW를 만드는 데 어떻게 도움이 될까?</h1>
<hr>
<ul>
<li><p><strong>도메인 코드에 플러그인처럼 동작하는 영속성 어댑터를 만들면 → 도메인 코드가 영속성과 관련된 것들로부터 분리 → 풍부한 도메인 모델을 만들 수 있다!</strong></p>
</li>
<li><p>좁은 포트 인터페이스 사용(ISP 적용) → 포트마다 다른 방식으로 구현 가능 → <strong>유연함</strong></p>
<ul>
<li>또한 <strong>테스트 용이성, 불필요한 의존성 제거!</strong></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[5장. 웹 어댑터 구현하기]]></title>
            <link>https://velog.io/@l0_0l/5%EC%9E%A5.-%EC%9B%B9-%EC%96%B4%EB%8C%91%ED%84%B0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@l0_0l/5%EC%9E%A5.-%EC%9B%B9-%EC%96%B4%EB%8C%91%ED%84%B0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 09 Jun 2022 06:55:35 GMT</pubDate>
            <description><![CDATA[<ul>
<li>이번장은 웹 인터페이스를 제공하는 어댑터의 구현 방법을 알아본다.</li>
</ul>
<h1 id="의존성-역전">의존성 역전</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/311ad673-428a-4a41-bada-3f85aab65ce6/image.png" alt=""></p>
<ul>
<li><p>웹 어댑터는 외부로부터 요청을 받아 애플리케이션 코어를 호출한다.</p>
</li>
<li><p>제어 흐름은 웹 어댑터에 있는 컨트롤러에서 애플리케이션 계층에 있는 서비스로 흐른다.</p>
</li>
<li><p>애플리케이션 계층은 웹 어댑터가 통신할 수 있는 특정 포트를 제공한다.</p>
</li>
<li><p>서비스는 이 포트를 구현하고, 웹 어댑터는 포트를 호출한다.</p>
</li>
<li><p>제어 흐름을 봐서는 웹 어댑터가 유스케이스를 직접 호출해도 되는데, 왜 굳이..? 포트를..?</p>
<ul>
<li><strong>코어가 외부 세계와 통신할 수 있는 곳에 대한 명세가 포트이기 때문! → 이 자체로도 애플리케이션이 커질수록 큰 기능이 된다!</strong></li>
<li>외부와 어떤 통신이 일어나고 있는지 정확히 인지 가능</li>
<li>유지보수하는 엔지니어에게 큰 정보다!</li>
</ul>
</li>
<li><p>또한 <strong>상호작용이 많이 일어나는 애플리케이션에서! [웹 소켓]</strong></p>
<ul>
<li>실시간 데이터를 사용자의 브라우저로 보내야한다.</li>
<li>코어에서 이러한 실시간 데이터를 어떻게 웹 어댑터로 보내고, 웹 어댑터는 이 데이터를 어떻게 사용자의 브라우저로 전송할까?</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/90bedaa5-4b4a-4359-983d-b285f7a9337c/image.png" alt=""></p>
<ul>
<li><p><strong>위 그림처럼 애플리케이션이 웹 어댑터에 능동적으로 알림을 줘야한다면, 의존성을 올바른 방향으로 유지하기 위해 아웃고잉 포트를 통과해야한다! [웹 → 서비스로 바로 포트 없이 의존하고 있었다면 의존성이 순환하게 된다!]</strong></p>
</li>
<li><p>이때 아웃고잉 포트를 구현하기 때문에, 웹 어댑터는 인커밍 어댑터인 동시에 아웃고잉 어댑터가 된다.</p>
</li>
</ul>
<h1 id="웹-어댑터의-책임">웹 어댑터의 책임</h1>
<hr>
<blockquote>
</blockquote>
<ol>
<li>HTTP 요청을 자바 객체로 매핑</li>
<li>권한 검사</li>
<li>입력 유효성 검증</li>
<li>입력을 유스케이스의 입력 모델로 매핑</li>
<li>유스케이스 호출</li>
<li>유스케이스의 출력을 HTTP로 매핑</li>
<li>HTTP 응답을 반환</li>
</ol>
<ul>
<li><p><strong>웹 어댑터 입력 모델은 유스케이스 입력 모델과 구조나 의미가 완전히 다를 수 있다! → 또 다른 유효성 검증을 수행해야 한다.</strong></p>
<ul>
<li><strong>웹 어댑터의 입력 모델을 유스케이스의 입력 모델로 변환할 수 있다는 것을 검증해야한다!</strong></li>
</ul>
</li>
<li><p><strong>웹 어댑터의 책임이 매우 많아보인다. 하지만 이 책임들은 애플리케이션 계층이 신경 쓰면 안되는 것들이다!</strong></p>
</li>
<li><p>HTTP와 관련된 것이 애플리케이션 계층으로 침투하면 안 된다.</p>
<ul>
<li>만약 침투하면?<ul>
<li><strong>HTTP를 사용하지 않는 또 다른 인커밍 어댑터의 요청에 대해 동일한 도메인 로직을 수행할 수 있는 선택지가 사라지게 된다!</strong></li>
<li>좋은 아키텍처에서는 선택의 여지를 남겨둔다.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>웹 어댑터와 애플리케이션 계층 간의 이 같은 경계는 도메인과 애플리케이션 계층부터 개발하기 시작하면 자연스럽게 생긴다.</strong></p>
</li>
</ul>
<h1 id="컨트롤러-나누기">컨트롤러 나누기</h1>
<hr>
<ul>
<li><p>웹 어댑터 → 1개 이상의 클래스로 구성 가능!</p>
<ul>
<li>단, 같은 패키지 수준! (같은 소속이라는 것을 표현)</li>
</ul>
</li>
<li><p>컨트롤러는 얼마나 만들어야하는가?</p>
<ul>
<li><strong>너무 적은 것보다는 너무 많은게 낫다!</strong></li>
<li>가능한 한 좁고 다른 컨트롤러와 가능한 한 적게 공유하는 웹 어댑터 조각을 구현해야한다!</li>
<li><strong>즉, 컨트롤러도 쪼갤 수 있으면 쪼개라!</strong></li>
</ul>
</li>
<li><p><strong>클래스마다 코드는 적을수록 좋다!</strong></p>
<ul>
<li>클래스의 코드가 많을 수록 그 코드의 의미를 정확하게 파악하는 난이도가 매우 높아진다.</li>
</ul>
</li>
<li><p><strong>컨트롤러에 코드가 많다면 그에 해당하는 테스트 코드도 많아지게 된다!</strong></p>
<ul>
<li><strong>특정 프로덕션 코드에 해당하는 테스트 코드를 찾기 쉬워야하는데, 클래스가 작을수록 더 찾기 쉽다!</strong></li>
</ul>
</li>
<li><p>모든 연산을 단일 컨트롤러에 모아놓으면...</p>
<ul>
<li>데이터 구조의 재활용을 촉진한다..!</li>
<li>즉 모델 클래스를 공유할 확률이 높아진다.</li>
<li>해당 연산에 필요없는 모델 클래스를 사용함으로써 혼란이 생길 수 있다.</li>
</ul>
</li>
<li><p><strong>별도의 패키지 안에</strong>, <strong>별도의 컨트롤러를 만들자! → 메서드와 클래스명을 유스케이스를 최대한 반영해서!</strong></p>
</li>
<li><p>이렇게 별도 컨트롤러를 만들고, 그에 대한 전용 클래스들이 생기게 되면!</p>
<ul>
<li>패키지 private으로 인해 모델이 다른 곳에서 재사용되지 않는다!</li>
<li>컨트롤러끼리 모델을 공유할 수는 있지만 세부 패키지를 구분함으로써, 공유하기 전에 한번 더 생각하게 된다!</li>
</ul>
</li>
<li><p>이렇게 나누는 스타일의 또 다른 장점 → 서로 다른 연산에 대한 동시 작업이 쉬워진다!</p>
</li>
</ul>
<h1 id="유지보수-가능한-sw를-만드는-데-어떻게-도움이-될까">유지보수 가능한 SW를 만드는 데 어떻게 도움이 될까?</h1>
<hr>
<ul>
<li><p>웹 어댑터를 구현할 때</p>
<ul>
<li><strong>HTTP 요청을 애플리케이션의 유스케이스에 대한 메서드 호출로 변환하고</strong></li>
<li><strong>결과를 HTTP로 변환한다.</strong></li>
<li><strong>이때 어떤 도메인 로직도 수행하지 않는 어댑터를 만든다.</strong></li>
</ul>
</li>
<li><p><strong>애플리케이션 계층은 HTTP에 대한 상세 정보를 노출시키지 않도록 HTTP와 관련된 작업을 해서는 안 된다!</strong></p>
</li>
<li><p><strong>웹 컨트롤러를 나눌 때, 모델을 공유하지 않는 여러 작은 클래스들을 만드는 것을 두려워해서는 안 된다!</strong></p>
<ul>
<li>작은 클래스들은 더 파악하기 쉽고, 테스트하기 쉽고, 동시 작업을 지원한다!</li>
</ul>
</li>
<li><p><strong>물론 Cost가 더 있지만, 유지보수 측면에서 큰 이득이 있다!</strong></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[4장. 유스케이스 구현하기 ]]></title>
            <link>https://velog.io/@l0_0l/4%EC%9E%A5.-%EC%9C%A0%EC%8A%A4%EC%BC%80%EC%9D%B4%EC%8A%A4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@l0_0l/4%EC%9E%A5.-%EC%9C%A0%EC%8A%A4%EC%BC%80%EC%9D%B4%EC%8A%A4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 09 Jun 2022 06:43:29 GMT</pubDate>
            <description><![CDATA[<ul>
<li>헥사고날 아키텍처에서 유스케이스를 구현하기 위해 이 책에서 제시하는 방법을 설명한다.<ul>
<li><strong>도메인 중심의 아키텍처에 적합하기 때문에 도메인 엔티티를 만드는 것으로 시작한 후 도메인 엔티티를 중심으로 유스케이스 구현!</strong></li>
</ul>
</li>
</ul>
<h1 id="도메인-모델-구현하기">도메인 모델 구현하기</h1>
<hr>
<ul>
<li><p>예제에서 한 계좌에서 다른 계좌로 송금하는 유스케이스를 구현!</p>
</li>
<li><p><strong>Account</strong> 엔티티 → 실제 계좌의 현재 스냅숏 제공</p>
</li>
<li><p><strong>Activity</strong> 엔티티 → 계좌에 대한 모든 입금과 출금을 포착</p>
</li>
<li><p>입금과 출금은 새로운 Activity를 추가하는 것에 불과하다.</p>
</li>
<li><p>출금하기 전에는 잔고를 초과하는 금액은 출금할 수 없도록 하는 <strong>비즈니스 규칙을 검사</strong>한다.</p>
</li>
</ul>
<h1 id="유스케이스-둘러보기">유스케이스 둘러보기</h1>
<hr>
<ul>
<li>유스케이스의 일반적 단계는 아래와 같다.</li>
</ul>
<blockquote>
</blockquote>
<ol>
<li>입력을 받는다.</li>
<li>비즈니스 규칙을 검증한다.</li>
<li>모델 상태를 조작한다.</li>
<li>출력을 반환한다.</li>
</ol>
<ul>
<li><p><strong>유스케이스 코드는 도메인 로직에만 신경 써야 한다. → 입력 유효성 검증으로 오염되면 안된다! → 책임의 분리!</strong></p>
</li>
<li><p>이때<strong>, 유스케이스는 비즈니스 규칙을 검증할 책임이 있다! → 도메인 엔티티와 이 책임을 공유하게 된다.</strong></p>
</li>
</ul>
<h3 id="유스케이스에서-일어나는-일">유스케이스에서 일어나는 일...</h3>
<ul>
<li><strong>비즈니스 규칙을 만족하면 → 유스케이스는 입력을 기반으로 모델의 상태를 변경 → 영속성 어댑터를 통해 구현된 포트로 이 상태를 전달 → 저장 → 아웃고잉 어댑터에서 온 출력을 유스케이스를 호출한 어댑터로 반환할 출력 객체로 변환 → 반환</strong></li>
</ul>
<h1 id="입력-유효성-검증">입력 유효성 검증</h1>
<hr>
<ul>
<li><p><strong>입력 유효성 검증은 유스케이스 클래스의 책임이 아니다! → 하지만 애플리케이션 계층의 책임이다!</strong></p>
</li>
<li><p>호출하는 어댑터(인커밍 어댑터)가 유스케이스에 입력을 전달하기 전에 입력 유효성을 검증하면?</p>
<ul>
<li>유스케이스 입장에서 필요로하는 것을 모두 검증했다고 믿을 수 있나?</li>
<li>하나 이상의 어댑터에서 호출되는 유스케이스의 경우, 유효성 검증을 각 어댑터에서 전부 구현해야 하나?</li>
<li>그 과정에서 실수가 나올 수 있지 않나?</li>
</ul>
</li>
<li><p>그럼 애플리케이션 계층 책임 OK, 근데 유스케이스 클래스의 책임이 아니면 어디서 검증하지..?</p>
<ul>
<li>→ <strong>“입력 모델”</strong></li>
</ul>
</li>
<li><p><strong>더 정확히는 입력 모델의 생성자 내에서 입력 유효성을 검증하도록 한다!</strong></p>
<ul>
<li>이때 조건을 위배하면 예외를 던져서 객체 생성을 막는다!</li>
<li>또한 필드는 final로 하여, 불변으로 한다! → 검증이 끝나면 그 상태는 계속해서 유효하다는 것을 보장할 수 있다!</li>
</ul>
</li>
<li><p><strong>이때, 입력 모델은 사실상 유스케이스 API의 일부이기 때문에 인커밍 포트 패키지에 위치시킨다!</strong></p>
<ul>
<li>이로 인해, 유효성 검증이 애플리케이션 코어에 남아 있지만, 유스케이스 코드를 오염시키지는 않는다!</li>
</ul>
</li>
<li><p>이러한 유효성 검증은 직접 구현하는 방법 외에도, <strong>Bean Validation API</strong>를 통해 해결할 수 있다!</p>
</li>
</ul>
<h1 id="생성자의-힘">생성자의 힘</h1>
<hr>
<ul>
<li><p>입력 모델은 생성자에서 유효성 검증을 수행한다.</p>
<ul>
<li><strong>즉, 유효하지 않은 상태의 객체를 만드는 것은 불가능하다!</strong></li>
</ul>
</li>
<li><p>이때 입력 모델의 파라미터가 많다면..?</p>
<ul>
<li><strong>빌더 패턴을 활용하면 되지 않을까?</strong></li>
</ul>
</li>
<li><p>하지만 빌더의 경우, 필드를 새로 추가하는 상황에 놓여있을 때, 그것을 추가하는 것을 쉽게 잊게 된다!</p>
<ul>
<li>이때 컴파일러도 경고를 해주지 않는다!</li>
<li>런타임이 되어서야, 유효성 검증 로직을 통해 누락된 것을 알게 된다!</li>
</ul>
</li>
<li><p>필자는 빌더를 쓰는 것보다 긴 생성자를 쓰는 편이 더 좋다고 주장한다!</p>
<ul>
<li>Why?<ul>
<li><strong>새로운 필드를 추가하거나 필드를 삭제할 때마다 컴파일 에러를 따라 나머지 코드에 변경사항을 반영할 수 있다!</strong></li>
<li>또한 IDE의 도움을 받을 수 있다!</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="흠-이게-맞나">흠... 이게 맞나?</h3>
<ul>
<li>사실 생성자의 인자는 최대한 적은 것이 맞다고 생각한다.</li>
<li>물론 빌더 패턴의 단점도 인지하였다.</li>
<li><strong>하지만 그렇다고 긴 생성자를 사용하자! 빌더보다는 좋다! 보다는 최대한 관련 값들끼리 래핑하여 인자를 줄여 가독성을 높이는 방향이 좀 더 맞다고 생각한다...!</strong></li>
</ul>
<h1 id="유스케이스마다-다른-입력-모델">유스케이스마다 다른 입력 모델</h1>
<hr>
<ul>
<li><p>다른 유스케이스에서 같은 입력 모델을 공유할 경우?</p>
<ul>
<li>특정 경우에 대해서, 입력 모델의 값 중 필요 없는 것, 또는 null 이어야하는 것이 발생할 수 있다.</li>
</ul>
</li>
<li><p><strong>불변 객체의 필드에 대해서 null을 유효한 상태로 받아들이는 것은 그 자체로 code smell(코드 악취)이다!</strong></p>
</li>
<li><p>물론 Cost가 들지만, <strong>각 유스케이스 전용 입력 모델은 유스케이스를 훨씬 더 명확하게 만들고 다른 유스케이스와의 결합도 제거해서 불필요한 부수효과가 발생하지 않게 한다!</strong></p>
</li>
</ul>
<h1 id="비즈니스-규칙-검증하기">비즈니스 규칙 검증하기</h1>
<hr>
<ul>
<li><p><strong>비즈니스 규칙 검증은 유스케이스 로직의 일부다!</strong></p>
</li>
<li><p><strong>비즈니스 규칙은 애플리케이션의 핵심이기 때문이다!</strong></p>
</li>
<li><p><strong>비즈니스 규칙 vs 입력 유효성 검증</strong></p>
<ul>
<li>비즈니스 규칙 → 도메인 모델의 현재 상태에 접근 필요, 유스케이스 맥락 속에서 <strong>의미적인</strong> 유효성을 검증</li>
<li>입력 유효성 검증 → 그럴 필요 X, <strong>구문 상의</strong> 유효성을 검증</li>
</ul>
</li>
<li><p><strong>사실 위의 구분이 매우 모호하기에, 도메인 모델의 현재 상태 접근이라는 보다 명확한 구분을 지어놓은 듯 하다!</strong></p>
</li>
<li><p>이로 인해, 특정 유효성 검증 로직을 코드 상의 어느 위치에 둘 지 결정하고 나중에 그것이 어디에 있는지 더 쉽게 찾는데 도움이 된다!</p>
</li>
<li><p>그럼 비즈니스 규칙은 어디에..?</p>
<ol>
<li><strong>도메인 엔티티에 넣는다! → 비즈니스 로직 바로 옆에 규칙이 위치하기에, 위치를 정하기도 쉽고, 추론하기 쉽다!</strong></li>
<li><strong>유스케이스 코드에서 도메인 엔티티를 사용하기 전에 넣는다!</strong></li>
</ol>
</li>
</ul>
<h1 id="풍부한-도메인-모델-vs-빈약한-도메인-모델">풍부한 도메인 모델 vs 빈약한 도메인 모델</h1>
<hr>
<h3 id="풍부한-도메인-모델">풍부한 도메인 모델</h3>
<ul>
<li>코어에 있는 엔티티에서 가능한 한 많은 도메인 로직이 구현된다!</li>
<li>엔티티들은 상태를 변경하는 메서드를 제공하고, 비즈니스 규칙에 맞는 유효한 변경만을 허용한다.</li>
<li>유스케이스는 도메인 모델의 진입점으로 동작한다.</li>
<li>유스케이스는 사용자의 의도만을 표현하면서 이 의도를 실제 작업을 수행하는 체계화된 도메인 엔티티 메서드 호출로 변환한다!</li>
<li>많은 비즈니스 규칙이 유스케이스 구현체 대신 엔티티에 위치한다.</li>
</ul>
<h3 id="빈약한-도메인-모델">빈약한 도메인 모델</h3>
<ul>
<li>엔티티 자체가 굉장히 얇다.</li>
<li>상태를 표현하는 필드와 getter, setter만 포함!</li>
<li>도메인 로직을 가지고 있지 않다!</li>
<li>도메인 로직이 유스케이스 클래스에 구현돼 있다!</li>
<li>비즈니스 규칙을 검증하고, 엔티티의 상태를 바꾸고, 데이터베이스 저장을 담당하는 아웃고잉 포트에 엔티티를 전달할 책임 모두 유스케이스 클래스에 있다!</li>
<li>풍부함이 유스케이스로!</li>
</ul>
<h3 id="그래서-나는">그래서 나는..?</h3>
<ul>
<li>나는 개인적으로 빈약한 도메인 모델을 선호한다.</li>
<li>Why?<ul>
<li>물론 저 방식처럼 풍부함을 유스케이스로 모두 넣기보다는, 각각을 다 클래스로 나눌 것 같다.</li>
<li>그로인해, 테스트가 더 용이해지고 책임이 조금 더 분리된다고 생각한다.</li>
<li>도메인 모델이 풍부해지면, 그리고 로직이 복잡해지면 결국 독립적인 도메인 모델이 아니라, 어딘가 의존 관계가 발생할 가능성도 높아지고, 가독성도 떨어지지 않을까?</li>
<li>풍부한 도메인 모델은 그 상태를 변경하기 위해 setter를 허용해야한다는 단점이 있지만, 빈약한 도메인 모델은 불변 객체를 가져갈 수 있다.</li>
<li>예를 들어 송금 유스케이스를 조금 더 복잡하게 가정해보자.<ul>
<li>A가 B에게 돈을 보낼 수 있다.</li>
<li>이때 A와 B에게 각각 입금, 출금 되었다는 메세지가 전달된다.</li>
</ul>
</li>
<li>이때 송금하기와 메세지를 보낸다는 유스케이스가 분리되어야할까? 나는 이것은 동일한 유스케이스 내에 존재하는 비즈니스 로직들이라고 생각한다.</li>
<li>그렇기에 각각은 MoneySender, MessageSender 같은 각 비즈니스 로직들에 대한 클래스로 뽑아내고 SendMoneyUsecase에서는 이 로직들을 순서에 맞게 오케스트레이션만 해주면 된다고 생각한다.</li>
</ul>
</li>
</ul>
<h1 id="유스케이스마다-다른-출력-모델">유스케이스마다 다른 출력 모델</h1>
<hr>
<ul>
<li><p><strong>입력과 비슷하게 출력도 가능하면 각 유스케이스에 맞게 구체적인 것이 좋다!</strong></p>
<ul>
<li><strong>출력은 호출자에게 꼭 필요한 데이터만 들고 있어야 한다!</strong></li>
</ul>
</li>
<li><p>유스케이스들 간에 같은 출력 모델을 공유하게 되면 유스케이스들도 강하게 결합된다.</p>
</li>
<li><p>공유 모델은 결국 여러 이유로 점점 커지게 돼 있다!</p>
<ul>
<li>SRP를 적용하고 모델을 분리해서 유지하는 것은 유스케이스에 결합을 제거하는데 도움이 된다!</li>
</ul>
</li>
<li><p><strong>같은 이유로 도메인 엔티티를 출력 모델로 사용하고 싶은 유혹도 견뎌야 한다!</strong></p>
<ul>
<li>도메인 엔티티를 변경할 이유를 필요 이상으로 늘어나는 것을 원치 않을 것이다.</li>
</ul>
</li>
</ul>
<h1 id="읽기-전용-유스케이스는-어떨까">읽기 전용 유스케이스는 어떨까?</h1>
<hr>
<ul>
<li><p>애플리케이션 코어의 관점에서 그저 읽기 전용, 유스케이스라고 언급하기에 조금 이상한 경우, 그냥 <strong>간단한 데이터 쿼리</strong>라고 취급한다!</p>
<ul>
<li>물론 전체 프로젝트 맥락에서 이러한 작업이 유스케이스로 분류된다면 유스케이스처럼 구현하고 처리!</li>
</ul>
</li>
<li><p>인커밍 전용 포트를 만들고 이를 ‘<strong>쿼리 서비스</strong>’에서 구현한다.</p>
<ul>
<li>유스케이스 서비스와 동일한 방식으로 동작한다!</li>
</ul>
</li>
</ul>
<h1 id="유지보수-가능한-sw를-만드는-데-어떻게-도움이-될까">유지보수 가능한 SW를 만드는 데 어떻게 도움이 될까?</h1>
<hr>
<ul>
<li><p>입출력 모델을 독립적으로 모델링 함으로써 원치 않는 부수효과를 피할 수 있다.</p>
</li>
<li><p>물론 이로 인해 많은 입출력모델 클래스 + 매핑하는 Cost가 생기게 된다!</p>
</li>
<li><p>하지만 장기적으로보면, 유스케이스를 명확하게 이해할 수 있고, 유지보수 측면에서도 매우 큰 장점을 얻을 수 있다!</p>
</li>
<li><p>꼼꼼한 입력 유효성 검증, 유스케이스별 입출력 모델은 지속 가능한 코드를 만드는 데 큰 도움이 된다!</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[3장. 코드 구성하기]]></title>
            <link>https://velog.io/@l0_0l/3%EC%9E%A5.-%EC%BD%94%EB%93%9C-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@l0_0l/3%EC%9E%A5.-%EC%BD%94%EB%93%9C-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 16 May 2022 00:36:40 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>코드를 구성하는 몇 가지 방법을 소개한다.</p>
</li>
<li><p>소개할 예시들은 송금 서비스 BuckPal에 대한 것들이다.</p>
</li>
<li><p>특히 사용자가 본인의 계좌에서 다른 계좌로 돈을 송금할 수 있는 ‘송금하기’ 유스케이스에 대해 살펴본다.</p>
</li>
</ul>
<h1 id="계층으로-구성하기">계층으로 구성하기</h1>
<hr>
<pre><code class="language-markdown">buckpal
|
|--- domain
|     |--- Acount
|     |--- Activity
|     |--- AccountRepository
|     |--- AccountService
|
|--- persistence
|     |--- AccountRepositoryImpl
|
|--- web
      |--- AccountController</code></pre>
<ul>
<li><p>웹, 도메인, 영속성 계층 각각에 해당하는 전용 패키지인 web, domain, persistence를 둔다.</p>
</li>
<li><p>DIP를 이용해 의존성이 domain 패키지에 있는 도메인 코드만을 향하도록 한다.</p>
</li>
<li><p>단 이 패키지는 최적의 구조가 아니다! → <strong>Why?</strong></p>
<ol>
<li><strong>애플리케이션의 기능 조각이나 특성을 구분 짓는 패키지 경계가 없다.</strong><ol>
<li>즉, 서로 연관되지 않은 기능들끼리 예상하지 못한 부수효과를 일으킬 수 있는 클래스들의 엉망진창 묶음이 될 가능성이 높다!</li>
</ol>
</li>
<li><strong>애플리케이션의 어떤 유스케이스들을 제공하는지 파악할 수 없다.(개인적으로 이 부분은 패키지 구조 문제라기보다는 네이밍 문제라고 생각한다.)</strong><ol>
<li>특정 기능을 찾기 위해서는 어떤 서비스가 이를 구현했는지 추측해야 하고, 해당 서비스 내의 어떤 메서드가 그에 대한 책임을 수행하는지 찾아야 한다. (→ 2장에서 이야기했던 내가 □□□Service라는 네이밍을 싫어하는 이유 중 하나이기도 하다.)</li>
</ol>
</li>
<li><strong>패키지 구조를 통해서는 우리가 목표로 하는 아키택처를 파악할 수 없다. (목표로 하는 아키텍처가 헥사고날 아키텍처라고 가정)</strong><ol>
<li>어떤 기능이 웹 어댑터에서 호출되는지, 영속성 어댑터가 도메인 계층에 어떤 기능을 제공하는지 등을 한눈에 알아보기 힘들다.</li>
<li>인커밍 포트와 아웃고잉 포트가 코드 속에 숨게 된다.</li>
</ol>
</li>
</ol>
</li>
</ul>
<h1 id="기능으로-구성하기">기능으로 구성하기</h1>
<hr>
<pre><code class="language-markdown">buckpal
|
|--- account
      |--- Acount
      |--- AccountController
      |--- AccountRepositoryImpl
      |--- AccountRepository
      |--- SendMoneyService</code></pre>
<ul>
<li><p>계좌와 관련된 모든 코드를 최상위 account 패키지에 넣었다.</p>
</li>
<li><p>계층 패키지들도 모두 없앴다.</p>
</li>
<li><p>패키지 외부에서 접근되면 안 되는 클래스들에 대해 <strong>package-private</strong> 접근 수준을 이용해 패키지 간의 경계를 강화할 수 있다.</p>
<ul>
<li><strong>각 기능 사이의 불필요한 의존성을 방지!</strong></li>
</ul>
</li>
<li><p>AccountService → SendMoneyService로 <strong>네이밍 변경!</strong></p>
<ul>
<li><strong>유스케이스를 구현한 코드를 찾기 쉽게!</strong></li>
</ul>
</li>
<li><p>애플리케이션의 <strong>기능을 코드를 통해 볼 수 있게</strong> 만드는 것을 가리켜 ‘<strong>소리치는 아키텍처</strong>’ → <strong>코드가 그 의도를 우리에게 소리치고 있기 때문</strong></p>
</li>
</ul>
<h2 id="하지만-이-구조도-문제가-있다">하지만 이 구조도 문제가 있다!</h2>
<ol>
<li><strong>아키텍처의 가시성을 훨씬 더 떨어뜨린다.</strong><ol>
<li>어댑터를 나타내는 패키지명 존재하지 않고, 인커밍 포트, 아웃고잉 포트를 확인할 수 없다.</li>
<li>이 문제점은 근데 잘 공감은 못하겠다. 물론 모두가 헥사고날 아키텍처에 대해 완벽하게 이해한경우 아키텍처의 가시성을 높인 구조화된 패키지 구조가 매우 큰 도움이 되겠지만, 전체적인 팀의 학습 난이도를 높이는 단점이 존재한다고 생각한다. 과연 팀에 새로 합류하게된 10명의 개발자가 모두 헥사고날 아키텍처를 이해하고 있을까? 모르는 팀원들의 경우 오히려 코드를 읽고, 원하는 부분을 찾는게 매우 힘들지 않을까?</li>
</ol>
</li>
<li><strong>package-private 접근 수준으로 인해, 도메인 코드가 실수로 영속성 코드에 의존하게 될 수 있다!</strong></li>
</ol>
<h1 id="아키텍처적으로-표현력-있는-패키지-구조">아키텍처적으로 표현력 있는 패키지 구조</h1>
<hr>
<pre><code class="language-markdown">buckpal
|
|--- account
      |--- adapter
      |     |--- in
      |     |    |--- web
      |     |          |--- AccountController
      |     |--- out
      |          |--- persistence
      |                |--- AcountPersistenceAdapter
      |                |--- SpringDataAccountRepository
      |      
      |--- domain
      |     |--- Acount
      |     |--- Activity
      |     
      |--- application
            |--- SendMoneyService
            |
            |--- port
                  |--- in
                  |     |--- SendMoneyUseCase
                  |
                  |--- out
                        |--- LoadAccountPort
                        |--- UpdateAccountStatePort</code></pre>
<ul>
<li><p>패키지의 의존성 방향이 <strong>adapter → application → domain</strong> 으로 흐른다.</p>
</li>
<li><p>헥사고날 아키텍처에서 구조적 핵심 요소 : <strong>엔티티(도메인 엔티티), 유스케이스, 인커밍/아웃고잉 포트, 인커밍/아웃고잉 어댑터</strong></p>
</li>
<li><p>위 패키지 구조에서는 각 아키텍처 요소들에 <strong>정해진 위치</strong>가 있다.</p>
</li>
<li><p>최상위에는 Account와 관련된 유스케이스를 구현한 모듈임을 나타내는 account 패키지가 존재</p>
</li>
<li><p>큰 <strong>구성</strong></p>
<ul>
<li><strong>도메인 모델이 속한 domain 패키지</strong></li>
<li><strong>도메인 모델을 둘러싼 서비스 계층을 포함하는 application 패키지</strong></li>
<li><strong>애플리케이션 계층의 인커밍 포트를 호출하는 인커밍 어댑터와 아웃고잉 포트에 구현을 제공하는 아웃고잉 어댑터를 포함하는 adapter 패키지</strong></li>
</ul>
</li>
<li><p>이 패키지 구조는 ‘아키텍처 - 코드 gap’을 효과적으로 다룰 수 있다!</p>
</li>
<li><p><strong>패키지 구조가 아키텍처를 반영할 수 없다면 시간이 지남에 따라 코드는 점점 목표하던 아키텍처로부터 멀어지게 될 것이다.</strong></p>
</li>
<li><p><strong>어댑터 패키지</strong>의 모든 코드들은 application 패키지 내에 있는 포트 인터페이스를 통하지 않고서는 밖에서 호출되지 않는다.</p>
<ul>
<li>따라서 <strong>package-private</strong>으로 두는 것이 적절하다.</li>
<li>이로인해 <strong>application 계층에서 adapter 클래스로 향하는 의존성은 존재하지 않게 된다.</strong></li>
</ul>
</li>
<li><p>application 패키지와 domain 패키지 내의 일부 클래스들은 public으로 지정해야 한다.</p>
<ul>
<li><strong>어댑터</strong>에서 접근 가능해야하는 포트들 → <strong>public</strong></li>
<li><strong>도메인 클래스</strong>들도 서비스, 잠재적으로는 어댑터에서도 접근 가능하게 → <strong>public</strong></li>
<li>이때 서비스는 인커밍 포트 인터페이스 뒤에 숨겨질 수 있기 때문에 public일 필요가 없다.</li>
</ul>
</li>
<li><p><strong>어댑터 코드를 자체 패키지로 이동시킴으로써, 하나의 어댑터를 다른 구현으로 필요에 따라 쉽게 교체 가능하다!</strong></p>
</li>
<li><p><strong>이 패키지 구조는 DDD 개념에 직접적으로 대응시킬 수 있다.</strong></p>
<ul>
<li>하나의 account 같은 상위 레벨 패키지가 하나의 바운디드 컨텍스트(DDD에서 하나의 경계화된 단위)가 되고, 이 바운디드 컨텍스트는 통신할 전용 진입점과 출구도 포함하고 있게 된다!</li>
</ul>
</li>
<li><p>물론 완벽한 방법은 없다!</p>
<ul>
<li><strong>하지만 표현력 있는 패키지 구조는 적어도 코드와 아키텍처 간의 갭을 줄여준다!</strong></li>
</ul>
</li>
</ul>
<h2 id="그러나">그러나..!</h2>
<ul>
<li><p><strong>학습 난이도</strong>의 문제도 분명 존재한다고 생각한다.</p>
</li>
<li><p><strong>또한 인커밍 포트의 경우 진입점이라는 아키텍처 상의 명목을 제외하고는 실제로 그 필요성이 의문이다.</strong></p>
<ul>
<li>굳이 인커밍 포트가 존재하지 않아도 의존성 방향의 문제가 전혀 없고 아무리 봐도 인커밍 포트는 아키텍처의 구조를 맞추기 위해서만 쓰이지, 실제로 실효성이 없어보인다. 그저 패키지 구조를 더 복잡하게 만들고 불필요한 인터페이스 늘어나기만 할 것이라고 생각한다. 또한 그로 인해 오히려 유지보수하기 더 힘들어지기만 하지 않을까..!</li>
</ul>
</li>
</ul>
<h1 id="의존성-주입의-역할">의존성 주입의 역할</h1>
<hr>
<ul>
<li><p><strong>클린 아키택처의 본질적인 요소 → 애플리케이션 계층이 인커밍/아웃고잉 어댑터에 의존성을 갖지 않는다!</strong></p>
<ul>
<li>이를 지키기 위해, 헥사고날 아키텍처에서는 <strong>포트</strong> 인터페이스를 이용!</li>
</ul>
</li>
<li><p>근데 누가 포트 인터페이스를 구현한 실제 객체를 애플리케이션에 제공 하는가..?</p>
<ul>
<li><strong>이때 의존성 주입이 활용된다!</strong></li>
</ul>
</li>
<li><p><strong>모든 계층에 의존성을 가진 중립적인 컴포넌트를 하나 도입한다!</strong></p>
<ul>
<li>→ 의존성 주입을 통해 아키텍처를 구성하는 대부분의 클래스를 초기화하는 역할을 한다!</li>
<li>의존성을 주입받은 클래스는 해당 인터페이스만 알고 있을 뿐, 그 인터페이스의 실제 구현체(인스턴스)에 대해서는 알지 못한다.</li>
</ul>
</li>
</ul>
<h1 id="유지보수-가능한-sw를-만드는-데-어떻게-도움이-될까">유지보수 가능한 SW를 만드는 데 어떻게 도움이 될까?</h1>
<hr>
<ul>
<li><p>실제 코드 구조를 목표하는 아키텍처에 가깝게 만들어주는 <strong>헥사고날 아키텍처의 패키지 구조</strong>를 살펴봤다.</p>
</li>
<li><p><strong>헥사고날 아키텍처의 패키지 구조</strong>를 사용함으로써, 의사소통, 개발, 유지보수가 모두 조금 더 수월해진다.</p>
<ul>
<li>학습 난이도를 충족한 경우라고 판단된다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2장. 의존성 역전하기]]></title>
            <link>https://velog.io/@l0_0l/2%EC%9E%A5.-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%97%AD%EC%A0%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@l0_0l/2%EC%9E%A5.-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%97%AD%EC%A0%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 16 May 2022 00:33:47 GMT</pubDate>
            <description><![CDATA[<h1 id="단일-책임-원칙-srp">단일 책임 원칙 (SRP)</h1>
<hr>
<ul>
<li><p>일반적인 해석 → “<strong>하나의 컴포넌트는 오로지 한 가지 일만 해야 하고, 그것을 올바르게 수행해야 한다.</strong>”</p>
</li>
<li><p>실제 정의 → “<strong>컴포넌트를 변경하는 이유는 오직 하나뿐이어야 한다.</strong>”</p>
<ul>
<li>이것이 좀 더 <strong>SRP의 목적에 부합한 설명!</strong></li>
<li><strong>책임 → ‘변경할 이유’로 해석!</strong></li>
</ul>
</li>
<li><p><strong>아키텍처에서 SRP의 의미</strong></p>
<ul>
<li><strong>컴포넌트를 변경할 이유가 한 가지</strong>이다. → <strong>우리가 다른 이유로 SW를 변경하더라도 이 컴포넌트에 대해서는 전혀 신경 쓸 필요가 없다. 즉 의도치 않은 부수효과를 걱정할 필요 없다! 이것이 SRP의 목적이기도 하다!</strong></li>
</ul>
</li>
<li><p>아쉽게도 변경할 이유(책임)라는 것은 컴포넌트 간의 <strong>의존성을 통해 너무도 쉽게 전파된다.</strong></p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/b7953ee2-1cbf-42b3-ba35-06d003728fe5/image.png" alt=""></p>
<ul>
<li><p>의존성 각각은 변경하는 이유 하나씩에 해당한다. 점선 화살표 같은 전이 의존성도 마찬가지이다.</p>
</li>
<li><p>컴포넌트 A의 경우 모든 컴포넌트에 의존하고 있다. 즉 다른 어떤 컴포넌트가 바뀌던지 영향을 받게 된다.</p>
</li>
<li><p><strong>일반적으로 많은 코드는 SRP를 위반한다. 그리고 그로인해, 점점 변경하기가 더 어려워지고 변경 비용도 증가한다.</strong></p>
</li>
</ul>
<h2 id="의존하면-srp-위반">의존하면 SRP 위반..?</h2>
<ul>
<li><p>의존에 따라 변경 이유가 늘어나게 된다. 즉, 의존 관계가 있을 경우 엄격하게 따지면 <strong>SRP 위반</strong>이 맞다고 생각한다.</p>
</li>
<li><p>하지만 애플리케이션의 사이즈가 조금만 커져도 의존 관계를 이용하지 않고 작성하는 건 <strong>불가능</strong>하고, 가능하더라도 오히려 <strong>더 많은 문제를 야기한다.</strong></p>
</li>
<li><p><strong>그렇기에 의존으로 생기는 변경 이유는 제외하고 하나의 책임, 즉 하나의 변경 이유를 갖는 것이 현실적인 SRP의 실현이라고 생각한다. 하지만 그렇다고 하더라도 의존 관계가 지나치게 많은 것은 부적합하며 SRP를 어겼다고 판단해야한다.</strong></p>
</li>
</ul>
<h2 id="부수효과">부수효과</h2>
<ul>
<li><p>요구사항의 변경 등으로 코드에 한 영역을 변경했다. → 예상하지 못한 곳에서 <strong>부수효과</strong>가 발생한다.</p>
</li>
<li><p>이 경우 클라이언트가 변경을 원하지만 <strong>부수효과</strong>를 우려해서, <strong>올바른 방향의 변경으로 나아갈 수 없는 악순환</strong>이 반복될 수 있다. → SW <strong>신뢰</strong>의 문제이기도 하다고 생각한다.</p>
</li>
</ul>
<h1 id="의존성-역전-원칙-dip">의존성 역전 원칙 (DIP)</h1>
<hr>
<ul>
<li><p>계층형 아키텍처에서 영속성 계층에 대한 도메인 계층의 <strong>의존성</strong>으로 인해, <strong>영속성 계층을 변경할 때 마다 도메인 계층에 영향이 가게 된다.</strong></p>
<ul>
<li>하지만 <strong>도메인 코드는 애플리케이션에서 가장 중요한 코드(실질적으로 비즈니스적 가치를 전달하는 코드)</strong>이다.</li>
<li>영속성 코드의 변경으로 도메인 코드가 영향을 받는 것은 <strong>옳지 못하고, 이런 상황을 원하지 않는다.</strong></li>
</ul>
</li>
<li><p>그럼 어째?</p>
<ul>
<li><strong>DIP가 답을 알려준다.</strong></li>
</ul>
</li>
<li><p><strong>DIP → “코드 상의 어떤 의존성이든 그 방향을 바꿀 수(역전시킬 수) 있다.”</strong></p>
<ul>
<li>단 이때, 의존성의 양쪽 코드를 모두 제어할 수 있을 때만 의존성 역전이 가능하다.</li>
</ul>
</li>
<li><p><strong>도메인 코드와 영속성 코드 간의 의존성 역전 → 도메인 코드의 변경할 이유의 개수를 줄여보자.</strong></p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/b1ed8ca8-8dba-4dc1-bbe2-6dc26d533d61/image.png" alt=""></p>
<ul>
<li><p><strong>엔티티는 도메인 객체를 포현하고 도메인 코드는 이 엔티티들의 상태를 변경하는 일을 중심으로 하기 때문에 엔티티가 도메인 계층에 위치</strong></p>
</li>
<li><p><strong>“도메인 → 영속성”</strong> 방향의 의존성을 <strong>“영속성 → 도메인”</strong> 방향으로 <strong>역전</strong></p>
</li>
</ul>
<h1 id="클린-아키텍처">클린 아키텍처</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/609f9d81-9a35-479e-8b0c-4941d45ce543/image.png" alt=""></p>
<ul>
<li><p>로버트 C.마틴 → ‘<strong>클린 아키텍처</strong>’</p>
<ul>
<li><strong>“설계가 비즈니스 규칙의 테스트를 용이하게 하고, 비즈니스 규칙은 프레임워크, DB, UI 기술, 그 밖의 외부 애플리케이션이나 인터페이스로부터 독립적일 수 있다.”</strong></li>
<li><strong>도메인 코드가 바깥으로 향하는 어떤 의존성도 없어야 함을 의미</strong></li>
<li><strong>DIP를 이용하여 모든 의존성이 도메인 코드로 향하도록</strong></li>
</ul>
</li>
<li><p>이 아키텍처에서 가장 중요한 규칙은 <strong>의존성 규칙</strong></p>
<ul>
<li><strong>→ 계층 간의 모든 의존성이 안쪽으로 향해야 한다.</strong></li>
</ul>
</li>
<li><p>Core에는 주변 유스케이스에서 접근하는 도메인 엔티티들이 존재</p>
</li>
<li><p>유스케이스 = 앞 쪽 설명의 서비스</p>
<ul>
<li>SRP를 지키기 위해 조금 더 세분화돼 있다.</li>
<li>넓은 서비스 문제를 피하기 위해!</li>
</ul>
</li>
<li><p>도메인 코드에서는 어떤 영속성 프레임워크나 UI 프레임워크가 사용되는지 알 수 없기 없다!</p>
<ul>
<li><strong>→ 특정 프레임워크에 특화된 코드를 가질 수 없고 비즈니스 규칙에 집중</strong></li>
<li>도메인 코드를 자유롭게 모델링</li>
</ul>
</li>
<li><p>다소 추상적이다.</p>
</li>
</ul>
<h3 id="너무-좋아-하지만-대가가-있다">너무 좋아! 하지만 대가가 있다...</h3>
<ul>
<li><p><strong>애플리케이션의 엔티티에 대한 모델을 각 계층에서 유지보수해야한다..!</strong></p>
</li>
<li><p>영속성 계층에서 ORM 프레임워크를 사용한다고 가정</p>
<ul>
<li>이때 DB 컬럼과 객체 필드와의 매핑 정보 같은 것을 가지고 있는 엔티티 클래스가 필요하다.</li>
<li><strong>도메인 계층은 영속성 계층을 모르기에 두 계층에서 각각 엔티티를 만들어야한다.</strong></li>
<li>또한 이 두 계층이 데이터를 주고 받을 때, 두 엔티티를 <strong>서로 변환</strong>해야 한다. 도메인 계층과 다른 계층들 사이에서도 마찬가지</li>
</ul>
</li>
<li><p>근데 위와 같은 상황은 바람직하다!</p>
<ul>
<li><strong>도메인 코드가 프레임워크에 특화된 문제로 부터 해방된, 결합이 제거된 상태!</strong></li>
<li>Java Persistence API에서는 ORM이 관리하는 엔티티에 인자가 없는 기본 생성자를 추가하도록 강제한다. 이것이 바로 도메인 모델에서는 포함해서 안되고, 굳이 포함할 필요도 없는 프레임워크에 특화된 결합의 예이다.</li>
</ul>
</li>
</ul>
<h3 id="java-persistence-api에서는-orm이-관리하는-엔티티에-인자가-없는-기본-생성자를-추가하도록-강제-→-why">Java Persistence API에서는 ORM이 관리하는 엔티티에 인자가 없는 기본 생성자를 추가하도록 강제 → Why?</h3>
<ul>
<li><p><strong>동적으로 객체 생성 시 Reflection API를 활용하기 때문이다.</strong></p>
</li>
<li><p><strong>Reflection API</strong> → 구체적인 클래스 타입을 알지 못해도 ****그 클래스의 정보(메서드, 타입, 변수 등등)에 접근할 수 있게 해주는 자바 API</p>
<ul>
<li>컴파일 시간이 아니라 실행 시간에 동적으로 특정 클래스의 정보를 객체화를 통해 분석 및 추출해낼 수 있는 프로그래밍 기법</li>
</ul>
</li>
<li><p>대부분 프레임워크나 라이브러리 같은 사용하는 사람이 어떤 클래스를 만들지 모르는 경우 리플렉션을 통해 동적으로 이 문제를 해결하기 위해 많이 사용한다.</p>
</li>
<li><p>Reflection API로 가져올 수 없는 정보 중 하나가 생성자의 인자 정보!</p>
<ul>
<li>그래서 기본 생성자가 반드시 있어야 객체를 생성할 수 있는 것이다.</li>
<li>기본 생성자로 객체를 생성만 하면 필드 값 등은 Reflection API로 넣어줄 수 있다.</li>
</ul>
</li>
<li><p><strong>Ref</strong></p>
<ul>
<li><a href="https://tecoble.techcourse.co.kr/post/2020-07-16-reflection-api/">https://tecoble.techcourse.co.kr/post/2020-07-16-reflection-api/</a></li>
<li><a href="https://1-7171771.tistory.com/123">https://1-7171771.tistory.com/123</a></li>
</ul>
</li>
</ul>
<h1 id="헥사고날-아키텍처">헥사고날 아키텍처</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/7c578c01-3aac-4a85-85a2-2d0df01cd3e4/image.png" alt=""></p>
<ul>
<li><p>클린 아키텍처의 원칙들을 조금 더 구체적으로 만들어준다!</p>
</li>
<li><p>애플리케이션 코어가 각 어댑터와 상호작용하기 위해 특정 포트를 제공하기 때문에 “<strong>포트와 어댑터 아키텍처</strong>”이라고도 한다.</p>
</li>
<li><p>육각형 안에는 도메인 엔티티와 이와 상호작용하는 유스케이스 존재</p>
</li>
<li><p>육각형에서 <strong>외부로 향하는 의존성 존재 X</strong></p>
<ul>
<li><strong>→ 클린 아키텍처에서 제시한 의존성 규칙이 그대로 적용</strong></li>
<li>모든 의존성은 코어를 향한다.</li>
</ul>
</li>
<li><p><strong>왼쪽</strong>에 있는 어댑터</p>
<ul>
<li><strong>애플리케이션 코어를 호출하는 애플리케이션을 주도하는 어댑터</strong></li>
</ul>
</li>
<li><p><strong>오른쪽</strong>에 있는 어댑터</p>
<ul>
<li><strong>애플리케이션 코어에 의해 호출되는 애플리케이션에 의해 주도되는 어댑터</strong></li>
</ul>
</li>
<li><p>애플리케이션 코어 - 어댑터 통신을 위해 애플리케이션 코어가 각각의 <strong>포트를 제공</strong>해야한다.</p>
<ul>
<li><strong>주도하는 어댑터(왼쪽)</strong>에게는 그러한 포트가 <strong>코어에 있는 유스케이스 클래스들에 의해 구현되는 인터페이스</strong>가 ****된다.</li>
<li><strong>주도되는 어댑터(오른쪽)</strong>에게는 그러한 포트가 <strong>어댑터에 의해 구현되고 코어에 의해 호출되는 인터페이스</strong>가 된다.</li>
</ul>
</li>
<li><p><strong>헥사고날 아키텍처를 계층으로 구성해보면...</strong></p>
<ol>
<li>가장 바깥쪽 → 애플리케이션과 다른 시스템 간의 번역을 담당하는 어댑터로 구성</li>
<li>그 다음 → 포트와 유스케이스 구현체를 결합해서 애플리케이션 계층을 구성<ul>
<li>이 2가지가 애플리케이션의 인터페이스를 정의하기 때문</li>
</ul>
</li>
<li>마지막 계층(가장 안쪽) → 도메인 엔티티가 위치</li>
</ol>
</li>
</ul>
<h1 id="유지보수-가능한-sw를-만드는데-어떻게-도움이-될까">유지보수 가능한 SW를 만드는데 어떻게 도움이 될까?</h1>
<hr>
<ul>
<li><p>“<strong>의존성을 역전시켜 도메인 코드가 다른 바깥쪽 코드에 의존하지 않게 함으로써 영속성과 UI에 특화된 모든 문제로부터 도메인 로직의 결합을 제거하고 코드를 변경할 이유의 수를 줄일 수 있다.”</strong></p>
<ul>
<li>→ 변경할 이유가 적을수록 유지보수성은 더 좋아진다.</li>
</ul>
</li>
<li><p>도메인 코드를 비즈니스 문제에 맞게 자유롭게 모델링 할 수 있다.</p>
</li>
<li><p>영속성과 UI코드도 각각의 문제에 맞게 자유롭게 모델링 할 수 있다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[1장. 계층형 아키텍처의 문제는 무엇일까?]]></title>
            <link>https://velog.io/@l0_0l/1%EC%9E%A5.-%EA%B3%84%EC%B8%B5%ED%98%95-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98%EC%9D%98-%EB%AC%B8%EC%A0%9C%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@l0_0l/1%EC%9E%A5.-%EA%B3%84%EC%B8%B5%ED%98%95-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98%EC%9D%98-%EB%AC%B8%EC%A0%9C%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Mon, 16 May 2022 00:25:36 GMT</pubDate>
            <description><![CDATA[<h1 id="계층형-아키텍처">계층형 아키텍처</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/c7562c57-6471-4b73-87ba-0dc64b8e2cfc/image.png" alt=""></p>
<h3 id="flow">Flow</h3>
<ol>
<li>맨 위의 웹 계층에서 요청을 받는다.</li>
<li>도메인 혹은 비즈니스 계층에 있는 서비스로 요청을 보낸다.</li>
<li>서비스에서는 필요한 비즈니스 로직을 수행한다.</li>
<li>이때 도메인 엔티티의 현재 상태를 조회하거나 변경하기 위해 영속성 계층의 컴포넌트를 호출한다.</li>
</ol>
<ul>
<li><p>잘 만들어진 계층형 아키텍처는 선택의 폭을 넓히고, 변화하는 요구사항과 외부 요인에 빠르게 적응할 수 있게 해준다.</p>
</li>
<li><p>일반적으로 로직 flow와 컴포넌트들의 의존성 flow가 일치하여 받아들이기 쉽다.</p>
</li>
</ul>
<h1 id="뭐가-문제지">뭐가 문제지?</h1>
<hr>
<ul>
<li>코드에 나쁜 습관들이 스며들기 쉽게 만든다.</li>
<li>시간이 지날수록 SW를 점점 더 변경하기 어렵게 만드는 수많은 허점들을 노출한다.</li>
</ul>
<h2 id="계층형-아키텍처는-데이터베이스-주도-설계를-유도한다">계층형 아키텍처는 데이터베이스 주도 설계를 유도한다.</h2>
<ul>
<li><p>전통적인 계층형 아키텍처의 토대는 <strong>데이터베이스</strong></p>
<ul>
<li>위의 구조에서 의존성 구조를 따라가보면 자연스레 결국은 DB에 의존하게 될 것을 짐작할 수 있다.</li>
</ul>
</li>
<li><p>따라서 모든 것이 결국은 영속성 계층을 토대로 만들어진다.</p>
</li>
<li><p>하지만 우리가 만드는 대부분의 애플리케이션은 <strong>상태</strong>가 아니라 <strong>행동</strong>을 중심으로 모델링한다.</p>
<ul>
<li>여기서 ‘<strong>상태 → 영속성</strong>, <strong>행동 → 도메인 로직’</strong> 으로 볼 수 있다.</li>
<li><strong>행동이 상태를 바꾸는 주체이기 때문에 행동이 비즈니스를 이끌어간다!</strong></li>
</ul>
</li>
<li><p>하지만 계층형 아키텍처는 데이터베이스의 구조를 먼저 생각하고, 이를 토대로 도메인 로직을 구현하게 하는 <strong>데이터 중심적 사고</strong>를 유발한다.</p>
</li>
<li><p><strong>비즈니스 관점에서는 전혀 맞지 않는 방법이다.</strong></p>
<ul>
<li>도메인 로직을 먼저 만들어야한다! → 우리가 로직을 제대로 이해했는지 확인 가능</li>
<li>도메인 로직이 맞다는 것을 확인한 후, 이를 기반으로 영속성 계층과 웹 계층을 만들어야한다!</li>
</ul>
</li>
<li><p>이런 데이터베이스 중심적인 아키텍처가 만들어지는 가장 큰 원인은  → <strong>ORM</strong></p>
<ul>
<li><strong>ORM + 계층형 아키텍처 ⇒ 비즈니스 규칙을 영속성 관점과 섞고 싶은 유혹</strong></li>
</ul>
</li>
<li><p>ORM에 의해 관리되는 엔티티들은 일반적으로 영속성 계층에 위치</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/95c5cd66-1b87-48a8-bf6d-f86af21a160e/image.png" alt=""></p>
<ul>
<li><p>즉 위 그림과 같은 영속성 계층과 도메인 계층 사이에 <strong>강한 결합</strong>이 발생!</p>
</li>
<li><p>서비스는 이로 인해, 영속성 계층과 관련된 작업들을 해야만 한다.</p>
</li>
<li><p><strong>영속성 코드가 사실상 도메인 코드에 침투하여 둘 중 하나만 바꾸는 것이 어려워진다!</strong></p>
</li>
</ul>
<h2 id="지름길을-택하기-쉬워진다">지름길을 택하기 쉬워진다.</h2>
<ul>
<li><p><strong>전통적인 계층형 아키텍처</strong>에서 전체적으로 적용되는 유일한 <strong>규칙</strong> → <strong>특정 계층에서는 같은 계층에 있는 컴포넌트와 아래에 있는 계층에만 접근 가능</strong></p>
</li>
<li><p>만약 상위 계층에 위치한 컴포넌트에 접근해야 한다면?</p>
<ul>
<li>→ 그 컴포넌트를 계층 아래로 내려버린다.</li>
<li>하지만 과연 이게 1번으로 끝날까? ⇒ <strong>깨진 유리창 이론</strong> → 하나 둘씩 이런 코드가 늘어가며 애플리케이션 전체로 퍼지게 된다.</li>
</ul>
</li>
<li><p>이런 상황이 쌓이며... 아래와 같은 그림의 현상 발생</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/4b8c07b4-b557-459f-a5e6-239a3b914ccf/image.png" alt=""></p>
<ul>
<li>영속성 계층에서 모든 것에 접근 가능하기에 시간이 지나며 점점 <strong>비대</strong>해진다.</li>
</ul>
<h3 id="비대해지면-안돼">비대해지면 안돼?</h3>
<ul>
<li><p><strong>현재 상황에서 의존성 방향의 끝이며 변경하기 어려운 안정적인 컴포넌트여야하는 영속성 layer</strong>가 <strong>비대</strong>해지며 <strong>변경될 일(이유)이 많아지는 모순적인 일</strong>이 발생!</p>
</li>
<li><p>변경하기도 힘들고 그로인해 부수효과가 얼마나 생길지 가늠조차 안되는 상태인데 계속 해서 변경해야하는 답도 없는 상황 발생...</p>
</li>
</ul>
<h2 id="테스트하기-어려워진다">테스트하기 어려워진다.</h2>
<ul>
<li><p>계층형 아키텍처에서는 계층을 건너뛰는 현상이 발생하기도...</p>
<ul>
<li>엔티티 필드를 단 하나만 조작하는 경우 같은 굳이 도메인 계층을 거치지 않고, 간단하게 웹 계층에서 영속성 계층에 접근하면 해결될 것 같은 일들</li>
</ul>
</li>
<li><p>이것도 처음에는 편하고 좋아 보인다...</p>
<ul>
<li>하지만 → <strong>깨진 유리창 이론</strong></li>
</ul>
</li>
<li><p>결국 크게 2가지 문제가 발생</p>
</li>
</ul>
<ol>
<li><strong>도메인 로직을 웹 계층에 구현</strong><ol>
<li>유스케이스가 확장된다면?</li>
<li>더 많은 도메인 로직을 웹 계층에 추가</li>
<li><strong>결국 애플리케이션 전체적으로 책임이 섞이고 도메인 로직들이 퍼져나가게 된다.</strong></li>
</ol>
</li>
<li><strong>웹 계층 테스트에서 도메인 계층뿐만 아니라 영속성 계층도 모킹해야...</strong><ol>
<li>테스트의 복잡도가 증가한다.</li>
<li>그로 인해 테스트를 작성하기 힘들어지고, 이로 인해 <strong>테스트를 작성하지 않게 된다!</strong></li>
</ol>
</li>
</ol>
<h2 id="유스케이스를-숨긴다">유스케이스를 숨긴다.</h2>
<ul>
<li><p>개발자들은 사실상 새로운 코드를 짜는데 시간을 쓰기보다는 기존 코드를 바꾸는 데 더 많은 시간을 할애한다.</p>
</li>
<li><p>아키텍처는 <strong>코드를 빠르게 탐색하는데 도움이 돼야</strong> 한다.</p>
</li>
<li><p>위에서 이야기했던 것처럼, 계층형 아키텍처는 도메인 로직이 여러 계층에 걸쳐 흩어지기 쉽다!</p>
<ul>
<li>새로운 기능을 어디에 넣어야 적당한지 찾기도 어려워질 수 있고, 찾고자 하는 기능과 관련된 코드를 찾기도 어려워질 수 있다!</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/5c9ab5cc-9c62-4150-a4bd-57c174f0e221/image.png" alt=""></p>
<ul>
<li><p>계층형 아키텍처는 도메인 서비스의 <strong>‘너비’에 관한 규칙을 강제하지 않는다.</strong></p>
</li>
<li><p>즉 위처럼 아주 넓은 서비스가 만들어질 수 있다. (이 부분은 계층형 아키텍처가 아니라 뒤에 나오는 아키텍처에서도 주의하고 신경써야할 부분이라 생각한다.)</p>
</li>
<li><p><strong>넓은 서비스 → 코드 상에서 특정 유스케이스를 찾기 어렵다!</strong></p>
<ul>
<li>또한 영속성 계층에 많은 의존성을 가지게 되며, 웹 계층의 많은 컴포넌트가 이 서비스를 의존!</li>
<li>서비스를 테스트하기 어려워진다!</li>
</ul>
</li>
<li><p><strong>고도로 특화된 좁은 도메인 서비스가 유스케이스 하나씩만 담당해야..!! (UserService → RegisterUserService)</strong></p>
</li>
</ul>
<h3 id="□□□service에-대해">□□□Service에 대해...</h3>
<ul>
<li><p>난 사실 이 네이밍을 선호하지 않는다.</p>
</li>
<li><p>이 네이밍 자체가 서비스의 너비를 넓히고, 많은 책임을 섞이게 만든다고 생각한다. 너무 넓은 범위를 아우르기 쉬운 네이밍인 것 같다.→ 이 부분에 대해서 고도로 특화된 좁은 도메인 서비스 네이밍을 잘하면 해결된다고 생각할수도 있을 것 같다.</p>
</li>
<li><p>위 처럼 고도로 특화된 좁은 도메인 서비스가 필요하다는 개념이 잡히지 않은 개발자가 팀의 합류한다면? 그 사람이 과연 Service라는 네이밍이 붙은 클래스를 보며 무슨 생각을 할까?</p>
<ul>
<li>고도로 특화된 좁은 도메인 서비스를 만들까?</li>
<li>또 UserService 같은 것들이 애플리케이션 전체적으로 퍼지게 될 가능성이 높아진다고 생각한다.</li>
</ul>
</li>
</ul>
<h2 id="동시-작업이-어려워진다">동시 작업이 어려워진다.</h2>
<ul>
<li><p>일반적으로 프로젝트에 인원이 더 투입될수록 더 빠른 속도를 기대한다.</p>
</li>
<li><p>하지만, 아키텍처가 동시 작업을 지원하는 것은 쉽지 않은 일이다.</p>
</li>
<li><p>계층형 아키텍처에서 계층별로 맡아서 작업하기란 쉽지 않다. 모든 것이 영속성 계층 위에 만들어지기 때문에 아래 계층의 개발이 선행되어야한다.</p>
</li>
<li><p>그렇기에 특정 기능은 동시에 한 명의 개발자만 작업할 수 있다.</p>
</li>
<li><p>인터페이스를 이용하면 되지 않은가?</p>
<ul>
<li>데이터베이스 주도 설계를 하지 않은 경우만 가능!</li>
<li><strong>데이터베이스 주도 설계는 영속성 로직이 도메인 로직과 너무 뒤섞여서 각 측면을 개별적으로 작업 불가</strong></li>
</ul>
</li>
<li><p>또한 코드에 넓은 서비스가 존재한다면, <strong>서로 다른 기능을 동시에 작업하기가 더욱 어려워</strong>진다.</p>
<ul>
<li>같은 서비스를 동시에 편집하는 상황 발생</li>
<li>merge conflict같은 문제 야기</li>
</ul>
</li>
</ul>
<h1 id="유지보수-가능한-소프트웨어를-만드는-데-어떻게-도움이-될까">유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까?</h1>
<hr>
<ul>
<li><p>계층형 아키텍처는 많은 것들이 잘못된 방향으로 흘러가도록 용인</p>
</li>
<li><p>엄격한 자기 훈련 없이는 시간이 지날수록 코드 품질이 저하되고 유지보수하기 어려워진다.</p>
</li>
<li><p>계층형 아키텍처의 함정을 염두하면, 유지보수하기에 더 쉬운 솔루션을 만드는 데 도움이 될 것이다!</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[👊🏼 우아한 스터디 시작!]]></title>
            <link>https://velog.io/@l0_0l/%EC%9A%B0%EC%95%84%ED%95%9C-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%8B%9C%EC%9E%91</link>
            <guid>https://velog.io/@l0_0l/%EC%9A%B0%EC%95%84%ED%95%9C-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%8B%9C%EC%9E%91</guid>
            <pubDate>Mon, 16 May 2022 00:19:45 GMT</pubDate>
            <description><![CDATA[<h2 id="우아한-스터디-시작">우아한 스터디 시작!</h2>
<hr>
<p>이번에 올라왔던 우아한 스터디에 지원했었다. 여러 스터디가 있었지만 &quot;<strong>헥사고날 아키텍쳐로 구현하는 작은 스프링 부트 토이 프로젝트</strong>&quot; 스터디에 지원하였다. 스터디에 사용하는 책은 &quot;<strong>만들면서 배우는 클린 아키텍처 자바 코드로 구현하는 클린 웹 애플리케이션</strong>&quot;을 사용하는 것 같았다. 애초에 클린 아키텍처에 관심이 많았고, 언젠가 헥사고날 아키텍처도 한번 공부해보고 싶었기 때문에 너무 좋은 기회라고 생각했다. 너무 대단하신 분들이 많이 지원할거라고 생각해서 간절하게 스터디에 합격했으면 좋겠다고 생각했다.</p>
<p>결과는... &quot;<strong>합격</strong>&quot;이었다. 너무 기뻤고, 앞으로의 스터디가 너무 기대되었다. 스터디가 시작되고, 조가 편성되었는데 조원분들도 너무나 대단하시고 실력이 좋으신 분들이라 더 행복했다. 정말 많이 배우기위해 최선을 다해 노력할 것이다.</p>
<p>화이팅~!👊🏼</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Prototype Pattern]]></title>
            <link>https://velog.io/@l0_0l/Prototype-Pattern</link>
            <guid>https://velog.io/@l0_0l/Prototype-Pattern</guid>
            <pubDate>Wed, 20 Apr 2022 12:00:30 GMT</pubDate>
            <description><![CDATA[<p>코드를 복사하려는 구체적인 클래스에 종속시키지 않고 기존 개체를 복사할 수 있는 패턴이다.</p>
<h2 id="problem">Problem</h2>
<hr>
<p>객체가 있고 그 객체의 정확한 복사본을 만들고 싶다고 가정해보자. 먼저 동일한 클래스의 새 객체를 생성해야 한다. 그런 다음 원본 객체의 모든 필드를 살펴보고 해당 값을 새 객체에 복사한다.</p>
<p>하지만 이런 경우도 있을 것이다. 개체의 필드 중 일부가 private이라서 객체 외부에서 볼 수 없는 경우에는 그런 식으로 복사할 수 없을 것이다.</p>
<p>또한 한 가지 문제가 더 있다. 복제본을 생성하려면 객체의 클래스를 알아야 하므로 클라이언트 코드가 해당 클래스에 종속된다. 그래서 클라이언트가 복사하려는 객체의 구체적인 클래스까지 알게되는 단점이 있다.</p>
<h2 id="solve">Solve</h2>
<hr>
<p>Prototype Pattern은 복제되는 실제 객체에 복제와 관련된 책임을 위임한다. 패턴을 적용하기 위해 복제를 지원하는 모든 객체에 대한 공통 인터페이스를 선언한다. 이 인터페이스를 사용하면 코드를 해당 객체의 구체적인 클래스에 연결하지 않고도 객체를 복제할 수 있다. 일반적으로 이러한 인터페이스에는 단일 clone메서드만 포함된다.</p>
<p>clone의 구현은 모든 클래스에서 매우 유사하다. 이 메서드는 현재 클래스의 객체를 만들고 이전 객체의 모든 필드 값을 새 객체로 전달한다. 동일 클래스이기에 private한 프로퍼티에 접근할 수 있다.</p>
<p>여기서 복제를 지원하는 객체를 프로토타입 이라고 한다. 객체에 수십 개의 필드와 수백 개의 가능한 구성이 있고, 이와 똑같은 객체가 필요할 경우 복제하는 것은 좋은 해결책이 될 수 있다.</p>
<h2 id="code">Code</h2>
<hr>
<h3 id="shape">Shape</h3>
<pre><code class="language-kotlin">package prototype

abstract class Shape() {
  abstract val x: Int
  abstract val y: Int
  abstract val color: String

  abstract fun clone(): Shape

  override fun equals(other: Any?): Boolean {
    if (other is Shape) {
      return x == other.x &amp;&amp; y == other.y &amp;&amp; color == other.color
    }

    return false
  }
}</code></pre>
<h3 id="circle">Circle</h3>
<pre><code class="language-kotlin">package prototype

class Circle(
  override val x: Int,
  override val y: Int,
  override val color: String,
  val radius: Int
) : Shape() {
  override fun clone(): Shape = Circle(x, y, color, radius)

  override fun equals(other: Any?): Boolean {
    if (other is Circle) {
      return super.equals(other) &amp;&amp; (radius == other.radius)
    }

    return false
  }

  override fun toString(): String = super.toString() + &quot; ,radius : ${radius}&quot;
}</code></pre>
<h3 id="rectangle">Rectangle</h3>
<pre><code class="language-kotlin">package prototype

class Rectangle(
  override val x: Int,
  override val y: Int,
  override val color: String,
  val width: Int,
  val height: Int
) : Shape() {
  override fun clone(): Shape = Rectangle(x, y, color, width, height)

  override fun equals(other: Any?): Boolean {
    if (other is Rectangle) {
      return super.equals(other) &amp;&amp; (width == other.width &amp;&amp; height == other.height)
    }

    return false
  }

  override fun toString(): String = super.toString() + &quot; ,width: ${width}, height: ${height}&quot;
}</code></pre>
<h3 id="tester">Tester</h3>
<pre><code class="language-kotlin">package prototype

class Tester {
  fun compareClone(shapeList: List&lt;Shape&gt;) {
    shapeList.forEach {
      val clone = it.clone()
      println(&quot;shape1: ${it}&quot;)
      println(&quot;shape2: ${clone}&quot;)
      println(&quot;equality: ${it == clone}&quot;)
      println(&quot;identity: ${it === clone}&quot;)
    }
  }
}</code></pre>
<h3 id="main">Main</h3>
<pre><code class="language-kotlin">package prototype

fun main() {
  val tester = Tester()

  val shapeList = mutableListOf&lt;Shape&gt;()

  val circle = Circle(10, 20, &quot;red&quot;, 15)
  shapeList.add(circle)

  val rectangle = Rectangle(10, 20, &quot;blue&quot;, 15, 20)
  shapeList.add(rectangle)

  tester.compareClone(shapeList)
}</code></pre>
<h2 id="구조">구조</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/93be4466-0599-42e7-93b3-a3e47760b2f7/image.png" alt=""></p>
<h2 id="적용가능성">적용가능성</h2>
<hr>
<blockquote>
</blockquote>
<ul>
<li>클라이언트가 복사해야 하는 구체적인 객체 클래스에 의존하지 않았으면 하는 경우</li>
<li>각각의 객체를 초기화하는 방식만 다른 하위 클래스의 수를 줄이려는 경우(객체의 값 복사에 대한 답으로 서브 클래싱을 선택한 경우) (예를 들어 Circle의 특정 복사본을 얻기 위해 Circle을 상속하여 radius가 100인 BigCircle을 아예 따로 만드는 방안을 선택한 경우를 말하는 것 같다.)</li>
</ul>
<h2 id="장점﹒단점">장점﹒단점</h2>
<hr>
<h3 id="장점">장점</h3>
<blockquote>
</blockquote>
<ul>
<li>구체적인 클래스에 연결하지 않고 개체를 복제할 수 있다.</li>
<li>복제를 위해 반복되는 초기화 코드를 제거할 수 있다.</li>
<li>복잡한 객체의 복사본을 보다 쉽게 얻을 수 있다.</li>
</ul>
<h3 id="단점">단점</h3>
<blockquote>
</blockquote>
<ul>
<li>순환 참조가 있는 복잡한 개체를 복제하는 것은 매우 까다로울 수 있다.</li>
</ul>
<h2 id="git">Git</h2>
<hr>
<p><a href="https://github.com/oh980225/DesignPattern/tree/main/src/main/kotlin/prototype">https://github.com/oh980225/DesignPattern/tree/main/src/main/kotlin/prototype</a></p>
<h2 id="ref">Ref</h2>
<hr>
<p><a href="https://refactoring.guru/design-patterns/prototype">https://refactoring.guru/design-patterns/prototype</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Builder Pattern]]></title>
            <link>https://velog.io/@l0_0l/Builder-Pattern</link>
            <guid>https://velog.io/@l0_0l/Builder-Pattern</guid>
            <pubDate>Tue, 19 Apr 2022 12:29:30 GMT</pubDate>
            <description><![CDATA[<p>복잡한 객체를 단계별로 구성할 수 있는 방안을 제시하는 디자인 패턴이다. 또한 해당 패턴을 통해 동일한 구성 코드를 사용하여 객체의 다양한 유형과 표현을 생성할 수 있다.</p>
<h2 id="problem">Problem</h2>
<hr>
<p>많은 필드와 중첩 객체를 힘들게 단계별로 초기화해야 한다고 가정해보자. 이런 복잡한 코드는 또한 클라이언트 코드 전체에 흩어져 있을 수도 있다. 예를 들어 House 객체를 생성한다고 생각하면, 기본적인 창문, 문, 지붕, 벽이 필요할 것이다. 하지만 경우에 따라서 앞마당이 있는 집, 차고가 있는 집도 있을 것이다. 이런 모든 상황을 어떻게 다 고려할 수 있을까?</p>
<p>가장 간단한 방법으로는 상속을 통한 해결이다. 하위 클래스에서 House를 확장하여 앞마당이 있는 하위클래스, 차고가 있는 하위 클래스를 만드는 것이다. 하지만 이렇게 될 경우 상당한 수의 하위 클래스가 만들어지게 된다. 또한 확장 요소가 추가될 때마다 하위 클래스를 추가로 만들어야한다.</p>
<p>다른 방법으로는 그냥 필요한 모든 것을 House에 넣고 그에 대한 생성자를 만들어주는 것이다. 이 방법으로 하위 클래스의 필요성을 제거할 수 있다. 그러나 생성자 호출이 매우 보기 흉해지고 앞마당이 있는 집을 거의 사용하지 않는 다면 앞마당 필드는 10번 중 9번을 필요가 없는 필드가 될 것이다.</p>
<h2 id="solve">Solve</h2>
<hr>
<p>Builder 패턴은 자체 클래스에서 객체 생성 코드를 추출해 Builder라는 별도의 객체로 이동시킨다. 객체를 생성하기 위해서는 Builder의 일련의 과정을 실행시키면 된다. 이때 포인트는 모든 단계를 호출할 필요가 없다는 것이다. 필요한 단계만 호출하여, 필요한 것들로만 구성하여 객체를 만들 수 있다.</p>
<p>또한 동일한 빌드 단계여도 다른 방식으로 여러 다른 빌더 클래스를 작성할 수 있다. 그 후 적합한 빌더를 사용하여 다양한 종류의 객체를 생성하는 것이다.</p>
<p>더 나아가 Director라는 별도의 클래스를 두어 빌더 단계에 대한 일련의 호출 부분을 뽑아낼 수도 있다. Dircetor는 빌드 단계를 실행하는 순서를 정의하고, 반면 Builder는 이러한 단계에 대한 구현을 제공한다. 물론 Director 클래스는 꼭 필요한 클래스는 아니다. 그냥 클라이언트 코드에서 직접 특성 빌드 순서를 호출해도 된다. 하지만 Director 클래스는 다양한 구성 루틴을 포함하여 프로그램 전체에서 재사용할 수 있는 좋은 장소이다. 그 뿐만 아니라 클라이언트 코드에서 제품 구성의 세부 정보를 완전히 숨길 수 있다는 장점도 있다.</p>
<h2 id="code">Code</h2>
<hr>
<h3 id="builder">Builder</h3>
<pre><code class="language-kotlin">package builder

import java.time.LocalDate

interface Builder {
  fun seatCount(count: Int)
  fun carType(carType: CarType)
  fun engine(engine: Engine)
  fun dateOfManufacture(date: LocalDate)
}</code></pre>
<h3 id="carbuilder">CarBuilder</h3>
<pre><code class="language-kotlin">package builder

import java.time.LocalDate

class CarBuilder : Builder {
  var seatCount: Int? = null
  var carType: CarType? = null
  var engine: Engine? = null
  var dateOfManufacture: LocalDate? = null

  override fun seatCount(count: Int) {
    this.seatCount = count
  }

  override fun carType(carType: CarType) {
    this.carType = carType
  }

  override fun engine(engine: Engine) {
    this.engine = engine
  }

  override fun dateOfManufacture(date: LocalDate) {
    this.dateOfManufacture = date
  }

  fun build() = Car(seatCount, carType, engine, dateOfManufacture)
}</code></pre>
<h3 id="manualbuilder">ManualBuilder</h3>
<pre><code class="language-kotlin">package builder

import java.time.LocalDate

class ManualBuilder : Builder {
  var seatCount: Int? = null
  var carType: CarType? = null
  var engine: Engine? = null
  var dateOfManufacture: LocalDate? = null

  override fun seatCount(count: Int) {
    this.seatCount = count
  }

  override fun carType(carType: CarType) {
    this.carType = carType
  }

  override fun engine(engine: Engine) {
    this.engine = engine
  }

  override fun dateOfManufacture(date: LocalDate) {
    this.dateOfManufacture = date
  }

  fun build() = Manual(seatCount, carType, engine, dateOfManufacture)
}</code></pre>
<h3 id="car">Car</h3>
<pre><code class="language-kotlin">package builder

import java.time.LocalDate

data class Car(val seatCount: Int?, val carType: CarType?, val engine: Engine?, val dateOfManufacture: LocalDate?)</code></pre>
<h3 id="manual">Manual</h3>
<pre><code class="language-kotlin">package builder

import java.time.LocalDate

data class Manual(val seatCount: Int?, val carType: CarType?, val engine: Engine?, val dateOfManufacture: LocalDate?)</code></pre>
<h3 id="cartype">CarType</h3>
<pre><code class="language-kotlin">package builder

enum class CarType {
  SPORTS_CAR, SUV
}</code></pre>
<h3 id="engine">Engine</h3>
<pre><code class="language-kotlin">package builder

data class Engine(val mileAge: Double, val volume: Double)</code></pre>
<h3 id="director">Director</h3>
<pre><code class="language-kotlin">package builder

import java.time.LocalDate

class Director {
  fun makeSportsCar(builder: Builder) {
    builder.seatCount(2)
    builder.carType(CarType.SPORTS_CAR)
    builder.engine(Engine(3.0, 0.0))
    builder.dateOfManufacture(LocalDate.of(1998, 2, 25))
  }

  fun makeSUV(builder: Builder) {
    builder.seatCount(4)
    builder.carType(CarType.SUV)
    builder.engine(Engine(2.5, 0.0))
    builder.dateOfManufacture(LocalDate.of(1998, 2, 25))
  }
}</code></pre>
<h3 id="main">Main</h3>
<pre><code class="language-kotlin">package builder

fun main() {
  println(&quot;which car is better?&quot;)
  println(&quot;1. SportsCar&quot;)
  println(&quot;2. SUV&quot;)

  val carBuilder = CarBuilder()
  val manualBuilder = ManualBuilder()
  val director = Director()

  when (readLine()) {
    &quot;1&quot; -&gt; {
      director.makeSportsCar(carBuilder)
      director.makeSportsCar(manualBuilder)
    }
    &quot;2&quot; -&gt; {
      director.makeSUV(carBuilder)
      director.makeSUV(manualBuilder)
    }
    else -&gt; {
      println(&quot;Error!&quot;)
      return
    }
  }

  println(&quot;My Car is ${carBuilder.build()}&quot;)
  println(&quot;This Manual is ${manualBuilder.build()}&quot;)
}</code></pre>
<h2 id="구조">구조</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/723a660a-26c2-405d-8a47-ac1c0a46afbd/image.png" alt=""></p>
<h2 id="적용가능성">적용가능성</h2>
<hr>
<blockquote>
</blockquote>
<ul>
<li>선택적 매개변수가 매우 많은 생성자에 빌더 패턴을 적용할 수 있다. 패턴을 사용하면 더 이상 수십 개의 매개변수를 생성자에 집어넣을 필요가 없다.</li>
<li>Builder 패턴은 제품의 다양한 표현을 구성하며 세부 사항만 다른 유사한 단계를 포함할 때 적용할 수 있다. 기본 빌더 인터페이스는 가능한 모든 구성 단계를 정의하고 구체적인 빌더는 이러한 단계를 구현하여 제품의 특정 표현을 구성한다. Director는 빌드의 순서를 안내한다.</li>
<li>빌더를 사용하여 제품을 단계별로 구성할 수 있다. 빌더는 빌드 단계 중 미완성인 제품을 노출하지 않는다. 즉 클라이언트 코드가 불완전한 결과를 가져오는 것을 방지할 수 있다.</li>
</ul>
<h2 id="장점﹒단점">장점﹒단점</h2>
<hr>
<h3 id="장점">장점</h3>
<blockquote>
</blockquote>
<ul>
<li>개체를 단계별로 구성 가능</li>
<li>제품의 다양한 표현을 작성할 때 동일한 구성 코드를 재사용</li>
<li><strong>SRP</strong> =&gt; 제품의 비즈니스 로직에서 복잡한 구성 코드를 분리</li>
</ul>
<h3 id="단점">단점</h3>
<blockquote>
</blockquote>
<ul>
<li>패턴을 위해 여러 개의 새 클래스를 생성 -&gt; 코드의 전반적인 복잡성이 증가</li>
</ul>
<h2 id="git">Git</h2>
<hr>
<p><a href="https://github.com/oh980225/DesignPattern/tree/main/src/main/kotlin/builder">https://github.com/oh980225/DesignPattern/tree/main/src/main/kotlin/builder</a></p>
<h2 id="ref">Ref</h2>
<hr>
<p><a href="https://refactoring.guru/design-patterns/builder">https://refactoring.guru/design-patterns/builder</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Chapter 22] 급여 관리 사례 연구(2부)]]></title>
            <link>https://velog.io/@l0_0l/Chapter-21-%EA%B8%89%EC%97%AC-%EA%B4%80%EB%A6%AC-%EC%82%AC%EB%A1%80-%EC%97%B0%EA%B5%AC2%EB%B6%80</link>
            <guid>https://velog.io/@l0_0l/Chapter-21-%EA%B8%89%EC%97%AC-%EA%B4%80%EB%A6%AC-%EC%82%AC%EB%A1%80-%EC%97%B0%EA%B5%AC2%EB%B6%80</guid>
            <pubDate>Thu, 14 Apr 2022 09:34:49 GMT</pubDate>
            <description><![CDATA[<h2 id="급여-관리-사례-연구2부-key-point-🔑">급여 관리 사례 연구(2부) Key Point 🔑</h2>
<hr>
<ul>
<li><strong>패키지 다이어그램은 의존 관계가 아래쪽으로 향하도록 그린다</strong> → 관례적 표현</li>
<li>항상 동일한 변화에 동일하게 폐쇄되어 있는지 패키지 점검 <strong>(CCP)</strong></li>
<li>거의 아무도 A패키지에 의존하지 않는다! → A는 <strong>책임이 없는</strong> 패키지!</li>
<li>A패키지는 어떤 것도 의존하지 않는다! → A는 <strong>독립적</strong>인 패키지!</li>
<li><strong>애플리케이션이 얼마나 안정적인지, 자주 바뀌는지, 재사용할 클라이언트는 어느정도인지에 원칙의 적용 정도가 달라진다! 자주 바뀌지도 않고 재사용할 클라이언트도 거의 없으며, 매우 안정적이라면 원칙을 철저하게 적용하여 의존 관계 아키텍쳐가 복잡해지게 되는 것이 더 손해일 수 있다!</strong></li>
<li><strong>처음에는 간단히 시작하고 필요에 따라 패키지 구조를 발전시키는 것이 best</strong></li>
<li>해당 패키지로 들어오는 결합을 막기 위해 private같은 접근 제어자를 사용 가능하다 → <strong>다른 패키지에서 알 필요 없는 클래스들을 숨기는 목표</strong></li>
<li>세부 구현이 담긴 클래스를 자유롭게 고치고 싶다면, 다른 누구도 그 클래스에 의존하지 못하도록 만들어야한다</li>
<li>책에서 나오는 <strong>측정법</strong><ul>
<li>관계 응집도</li>
<li>들어오는 결합</li>
<li>나가는 결합</li>
<li>추상도</li>
<li>불안정도</li>
<li>주계열로부터의 거리</li>
<li>정규화된 주계열로부터의 거리</li>
</ul>
</li>
<li>이런 측정값을 <strong>자동으로 계산해주는 도구</strong>도 존재!</li>
<li>이런 측정값을 프로젝트에 적용하며 상대적으로 주계열로부터 멀거나 응집도가 낮은 패키지들을 수정할 수 있게 된다 → 더욱 <strong>패키지 응집도와 결합도</strong>를 신경 쓴 구조가 된다!</li>
<li>패키지 다이어그램이 엉켜있으면 관리가 매우 힘들다 → <strong>계속 실용적으로 사용할 수 있도록 간단하게 유지</strong>하자</li>
<li><strong>추상 패키지들은 변경에 폐쇄되어 있고, 재사용 가능하고, 자신들은 별로 많이 의존하지 않도록! 그리고 많은 의존의 대상이 되도록! → (안정적 패키지)</strong></li>
<li><strong>구체적 패키지들은 재사용성에 바탕을 두고 분리한다. 일반적으로 추상 패키지들에게 매우 의존하는 형태이다. 그렇기에 심한 의존의 대상이 되어서는 안된다! → (불안정적 패키지)</strong></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Chapter 21] 팩토리 패턴]]></title>
            <link>https://velog.io/@l0_0l/Chapter-21-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@l0_0l/Chapter-21-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 12 Apr 2022 11:05:35 GMT</pubDate>
            <description><![CDATA[<h2 id="팩토리-패턴-🔑-정리">팩토리 패턴 🔑 정리</h2>
<hr>
<blockquote>
</blockquote>
<ul>
<li><strong>DIP</strong>에 따르면 구체 클래스에 의존하는 것은 피하고 <strong>추상 클래스에 의존</strong>하는 것을 선호해야 한다.</li>
<li>사실 <strong>new 키워드 사용하면 엄격하게 DIP를 어기는 셈이다.</strong></li>
<li>사실 근데 구<strong>체 클래스가 쉽게 변경되는 종류의 클래스가 아니라면(String같은) 큰 문제는 없다.</strong></li>
<li><strong>하지만 변경되기 쉬운 구체 클래스들에 의존하는 것은 문제가 된다</strong><ul>
<li><strong>대부분의 변경에 영향을 받지 않도록 추상 인터페이스에 의존하는 것이 Good!</strong></li>
</ul>
</li>
<li><strong>팩토리 패턴 =&gt; 추상 인터페이스에만 의존하게! 그러면서도 구체적 객체들의 인스턴스를 만들 수 있다.</strong><ul>
<li><strong>사용되는 구체 클래스의 변경이 잦을 때 사용하면 좋은 패턴이다.</strong></li>
</ul>
</li>
<li>팩토리 패턴의 큰 장점 중 하나 =&gt; 팩토리의 구현을 다른 구현으로 대체 가능하다! <ul>
<li>즉 애플리케이션 안에 사용하던 객체 집합을 <strong>다른 객체 집합으로 통째로 변경도 가능하다.</strong></li>
</ul>
</li>
<li>또한 <strong>단위 테스트를 작성할 때도 팩토리 패턴을 응용 가능하다.</strong></li>
<li>하지만 사실 <strong>DIP를 극단적으로 지키기 위해 팩토리를 너무 많이 사용하는 것은 너무 극단적</strong>이라고 볼 수 있다.</li>
<li>보통 팩토리를 고려하지 않고 <strong>꼭 필요할때 도입하는 것이 좋다.</strong></li>
<li>당연히 필요할 것이라고 가정하지 말자!</li>
<li><strong>피할려면 피할 수 있는 복잡함</strong>이다.</li>
<li>팩토리를 기본으로 사용하여 설계하면 <strong>설계를 확장하기 어려워지는 지점이 생기게 된다.</strong>(지금 단계에서 크게 감은 안 온다. 하지만 구조가 조금 더 복잡해지고 클래스를 많이 만들어야하는 것은 맞는 것 같다.) </li>
<li>또한 <strong>만들어야할 클래스도 매우 증가</strong>한다.</li>
<li><strong>팩토리 패턴이 최선인 경우는 드물다...</strong></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Abstract Factory Pattern]]></title>
            <link>https://velog.io/@l0_0l/Abstract-Factory</link>
            <guid>https://velog.io/@l0_0l/Abstract-Factory</guid>
            <pubDate>Tue, 12 Apr 2022 10:45:15 GMT</pubDate>
            <description><![CDATA[<p>구체적인 클래스를 지정하지 않고 관련 객체의 패밀리를 생성할 수 있는 생성 디자인 패턴입니다.</p>
<h2 id="problem">Problem</h2>
<hr>
<p>가구 매장 시뮬레이터를 만들고 있다고 가정해보자. 고객의 요구사항은 어울리는 가구 제품군들을 받는 것이다. 동일한 패밀리의 다른 객체와 일치하도록 개별 가구 객체를 작성하는 방법이 필요하다. 또한 프로그램에 새 제품이나 제품군을 추가할 때 기존 코드를 변경하고 싶지 않다. 가구 공급업체는 카탈로그를 매우 자주 업데이트하므로 발생할 때마다 핵심 코드를 변경하고 싶지 않을 것이다.</p>
<h2 id="solve">Solve</h2>
<hr>
<p><strong>Abstract Factory</strong> 패턴이 제안하는 첫 번째는 제품군의 개별 제품에 대한 인터페이스를 명시적으로 선언하는 것이다. 그런 다음 제품의 모든 변형이 이러한 인터페이스를 따르도록 한다. 예를 들어, 모든 의자 변형은 Chair 인터페이스 를 구현할 수 있다.</p>
<p>다음으로 제품 패밀리 내 모든 제품에 대한 생성 방법 목록이 있는 인터페이스인 <strong>추상 팩토리</strong>를 선언한다. 이러한 메서드는 각각 알맞은 추상 제품 유형을 반환해야 한다.</p>
<p>제품군의 각 변형에 대해 AbstractFactory 인터페이스를 기반으로 별도의 팩토리 클래스를 생성한다. 팩토리는 특정 종류의 제품을 반환하는 클래스이다. 클라이언트 코드는 각각의 추상 인터페이스를 통해 공장과 제품 모두에 대해 작동한다. 이를 통해 실제 클라이언트 코드를 손상시키지 않고 클라이언트 코드에 전달하는 팩토리 유형과 클라이언트 코드가 수신하는 제품 변형을 변경할 수 있게 된다.</p>
<p>고객이 공장에서 의자를 생산하기를 원한다고 가정해보자. 클라이언트는 공장의 구체 클래스를 알 필요도 없고 어떤 종류의 의자를 가져오는지도 알 필요없다. 현대 모델이든 빅토리아 스타일의 의자이든 클라이언트는 추상 Chair인터페이스를 사용하여 모든 의자를 동일한 방식으로 취급해야 한다. 또한 어떤 변형의 의자가 반환되든 동일한 공장 개체에서 생산된 테이블의 유형과 항상 일치한다.</p>
<p>명확히 해야 할 것이 한 가지 더 있다. 클라이언트가 추상 인터페이스에만 노출된다면 실제 팩토리 객체를 생성하는 것은 무엇일까? 일반적으로 애플리케이션은 초기화 단계에서 구체적인 팩토리 객체를 생성한다. 그 직전에 앱은 구성 또는 환경 설정에 따라 공장 유형을 선택해야하고 그러는 것이 일반적이다.</p>
<h2 id="code">Code</h2>
<hr>
<h3 id="furniturefactory">FurnitureFactory</h3>
<pre><code class="language-kotlin">package abstract_factory

interface FurnitureFactory {
  fun createChair(): Chair
  fun createTable(): Table
}</code></pre>
<h3 id="modernfactory">ModernFactory</h3>
<pre><code class="language-kotlin">package abstract_factory

class ModernFactory : FurnitureFactory {
  override fun createChair() = ModernChair()

  override fun createTable() = ModernTable()
}</code></pre>
<h3 id="victorianfactory">VictorianFactory</h3>
<pre><code class="language-kotlin">package abstract_factory

class VictorianFactory: FurnitureFactory {
  override fun createChair() = VictorianChair()

  override fun createTable() = VictorianTable()
}</code></pre>
<h3 id="chair">Chair</h3>
<pre><code class="language-kotlin">package abstract_factory

interface Chair {
  fun print()
}</code></pre>
<h3 id="modernchair">ModernChair</h3>
<pre><code class="language-kotlin">package abstract_factory

class ModernChair: Chair {
  override fun print() {
    println(&quot;It&#39;s a modern chair&quot;)
  }
}</code></pre>
<h3 id="victorianchair">VictorianChair</h3>
<pre><code class="language-kotlin">package abstract_factory

class VictorianChair: Chair {
  override fun print() {
    println(&quot;It&#39;s a victorian chair&quot;)
  }
}</code></pre>
<h3 id="table">Table</h3>
<pre><code class="language-kotlin">package abstract_factory

interface Table {
  fun print()
}</code></pre>
<h3 id="moderntable">ModernTable</h3>
<pre><code class="language-kotlin">package abstract_factory

class ModernTable: Table {
  override fun print() {
    println(&quot;It&#39;s a modern table&quot;)
  }
}</code></pre>
<h3 id="victoriantable">VictorianTable</h3>
<pre><code class="language-kotlin">package abstract_factory

class VictorianTable: Table {
  override fun print() {
    println(&quot;It&#39;s a victorian table&quot;)
  }
}</code></pre>
<h3 id="application">Application</h3>
<pre><code class="language-kotlin">package abstract_factory

class Application(private val factory: FurnitureFactory) {

  fun printMySet() {
    factory.createChair().print()
    factory.createTable().print()
  }
}

fun main() {
  println(&quot;What type of furniture do you like?&quot;)
  println(&quot;1. Victorian&quot;)
  println(&quot;2. Modern&quot;)

  val factory: FurnitureFactory = when (readLine()) {
    &quot;1&quot; -&gt; VictorianFactory()
    &quot;2&quot; -&gt; ModernFactory()
    else -&gt; {
      println(&quot;Error!&quot;)
      return
    }
  }

  val application = Application(factory)
  application.printMySet()
}</code></pre>
<h2 id="구조">구조</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/1e2cea1f-20fa-4f2b-8410-0019d6a47632/image.png" alt=""></p>
<h2 id="적용가능성">적용가능성</h2>
<hr>
<blockquote>
</blockquote>
<ul>
<li>코드가 관련 제품의 <strong>특정한 제품 패밀리와 함께 작동</strong>해야 하지만 <strong>해당 제품의 구체적인 클래스에 의존하고 싶지 않은 경우</strong></li>
<li>Abstract Factory는 각 구체 클래스에서 객체를 생성하기 위한 인터페이스를 제공한다. 코드가 이 인터페이스를 통해 객체를 생성하는 한 앱에서 이미 생성한 제품과 일치하지 않는 잘못된 제품 변형을 생성하는 것에 대해 걱정할 필요가 없다.</li>
<li><strong>기본 책임을 흐리게 하는 팩토리 메소드 세트</strong>가 있는 클래스가 있는 경우 <strong>추상 팩토리 구현을 고려</strong></li>
</ul>
<h2 id="장점﹒단점">장점﹒단점</h2>
<hr>
<h3 id="장점">장점</h3>
<blockquote>
</blockquote>
<ul>
<li>공장에서 생성한 제품이 서로 호환되는 것을 보장한다.</li>
<li>구체적인 제품과 클라이언트 코드 간의 긴밀한 결합을 피한다.</li>
<li><strong>SRP</strong> =&gt; 제품 생성 코드를 한 곳으로 추출</li>
<li><strong>OCP</strong> =&gt; 기존 클라이언트 코드를 손상시키지 않고 제품의 새로운 변형을 도입 가능</li>
</ul>
<h3 id="단점">단점</h3>
<blockquote>
</blockquote>
<ul>
<li>많은 새로운 인터페이스와 클래스가 패턴과 함께 도입되기 때문에 <strong>코드가 생각보다 복잡</strong>해질 수 있다.</li>
</ul>
<h2 id="git">Git</h2>
<hr>
<p><a href="https://github.com/oh980225/DesignPattern/tree/main/src/main/kotlin/abstract_factory">https://github.com/oh980225/DesignPattern/tree/main/src/main/kotlin/abstract_factory</a></p>
<h2 id="ref">Ref</h2>
<hr>
<p><a href="https://refactoring.guru/design-patterns/abstract-factory">https://refactoring.guru/design-patterns/abstract-factory</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Chapter 20] 패키지 설계의 원칙]]></title>
            <link>https://velog.io/@l0_0l/Chapter-20-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%84%A4%EA%B3%84%EC%9D%98-%EC%9B%90%EC%B9%99</link>
            <guid>https://velog.io/@l0_0l/Chapter-20-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%84%A4%EA%B3%84%EC%9D%98-%EC%9B%90%EC%B9%99</guid>
            <pubDate>Fri, 08 Apr 2022 07:51:51 GMT</pubDate>
            <description><![CDATA[<p>큰 애플리케이션을 조직화할 때는 클래스보다 더 큰 단위가 필요하다. 이때 패키지를 사용하여 그 단위를 잡는다. 이번 챕터에서는 이 패키지를 설계하는 6가지 원칙에 대해 설명한다. 원칙은 총 6개로 3개 / 3개 씩 그 종류가 아래와 같이 구분된다.</p>
<blockquote>
</blockquote>
<ul>
<li>3개 → <strong>패키지 응집도에 대한 원칙</strong>, 클래스를 패키지에 할당하는 일을 도움</li>
<li>3개 → <strong>패키지 결합도에 대한 원칙</strong>, 패키지 간의 관계를 결정하는 일을 도움</li>
<li>추가적으로 설계 안에 존재하는 의존성 구조를 측정하고 특징을 찾을 수 있게 해주는 <strong>의존성 관리 측정법</strong> 소개 <strong>[책 내에서 소개]</strong></li>
</ul>
<h2 id="패키지-응집도에-대한-원칙"><strong>패키지 응집도에 대한 원칙</strong></h2>
<hr>
<blockquote>
</blockquote>
<ol>
<li><strong>REP (재사용 릴리즈 등가 원칙)</strong><ul>
<li><strong>재사용의 단위가 릴리즈의 단위이다.</strong></li>
<li>재사용 단위는 릴리즈 단위보다 작을 수 없다. (여기서 재사용 단위의 예는 패키지가 될 수 있다.)</li>
<li>재사용성은 반드시 패키지에 기반을 두어야 한다. → 재사용 가능한 패키지는 재사용 가능한 클래스를 포함해야한다.</li>
<li>SW가 재사용될 예정이라면, 그 <strong>목적을 가진 사람이 편리하게 느낄 방식으로</strong> 분할</li>
<li>잠재적인 재사용자의 입장에서 봐야한다.</li>
<li>패키지에 재사용될 소프트웨어가 들어 있다면 그 패키지에는 재사용을 목적으로 설계되지 않은 소프트웨어는 들어 있지 않아야 한다. ⇒ 즉 <strong>패키지의 모든 클래스가 재사용 가능하든, 아니면 모두 그렇지 않아야한다!</strong></li>
<li>패키지 안의 모든 클래스는 동일한 재사용자를 고려한다.</li>
<li>재사용성이 유일한 기준이 아닌 누가 재사용자인지도 고려한다.</li>
</ul>
</li>
</ol>
<blockquote>
</blockquote>
<ol start="2">
<li><strong>CRP (공통 재사용 원칙)</strong><ul>
<li><strong>패키지 안의 클래스들은 함께 재사용되어야 한다. 어떤 패키지의 클래스 하나를 재사용한다면 나머지도 모두 재사용한다. (위에서 언급한 이야기와 유사)</strong></li>
<li>어떤 클래스들이 패키지에 포함되어야 하는지 결정할 때 도움이 된다.</li>
<li>자주 함께 재사용되는 클래스들은 동일한 패키지에 위치시킨다.</li>
<li>CRP를 따른 패키지 안을 보면 클래스들이 서로 상당한 정도의 의존 관계를 맺고 있다.</li>
<li>CRP는 어떤 클래스를 같은 패키지에 넣지 않아야 할지도 말해준다.</li>
<li>어떤 패키지에 의존한다면 그 패키지의 모든 클래스에 의존하는지 확실히 해두어야한다.</li>
<li>CRP에 따르면 클래스 관계로 서로 단단히 묶여 있지 않은 클래스들은 같은 패키지에 넣지 말아야한다.</li>
</ul>
</li>
</ol>
<blockquote>
</blockquote>
<ol start="3">
<li><strong>CCP (공통 폐쇄 원칙)</strong><ul>
<li><strong>같은 패키지 안의 클래스들은 동일한 종류의 변화에는 모두 폐쇄적이어야 한다. 패키지에 어떤 변화가 영향을 미친다면, 그 변화는 그 패키지의 모든 클래스에 영향을 미쳐야 하고 다른 패키지에는 영향을 미치지 않아야한다.</strong></li>
<li>대상이 패키지인 <strong>SRP</strong>이다. → 패키지를 변경할 이유가 여러가지면 안된다는 것이다.</li>
<li>코드를 변경해야한다면 우리는 여러 패키지를 고치는 것보다 해당하는 패키지 하나만 고치고 싶을 것이다. → 이것이 최종 목표이다.</li>
<li>동일한 이유로 변할 것 같은 클래스들은 한 장소에 모아놓으라고 권장</li>
<li>클래스 A, B가 물리적으로나 개념적으로나 단단히 결합되어 있어 항상 함께 변경된다면 → A, B는 같은 패키지이다.</li>
<li><strong>특정 종류의 변화에 개방되어 있는 클래스들은 같은 패키지로! → 요구사항 변경시 그에 따라 변경할 패키지수를 최소화!</strong></li>
</ul>
</li>
</ol>
<h2 id="패키지-결합도에-대한-원칙"><strong>패키지 결합도에 대한 원칙</strong></h2>
<hr>
<blockquote>
</blockquote>
<ol>
<li><strong>ADP (의존 관계 비순환 원칙)</strong><ul>
<li><strong>패키지 의존성 그래프에서 순환을 허용하지 말라.</strong></li>
<li><strong>패키지의 의존 관계 구조에 순환이 있으면 안된다.</strong></li>
<li><strong>패키지 다이어그램은 비순환 방향 그래프가 되어야한다.</strong></li>
<li>왜 순환이 없어야 하지? → <strong>변화로 인해 생기는 영향이 상대적으로 작아진다.</strong></li>
<li>패키지에 순환이 발생하면 그 패키지들은 언제나 서로의 일에 간섭할 수 밖에 없게되고 그로 인해 생기는 영향이 매우 커진다.</li>
<li>책의 예시를 보면 결국 의존을 따라가다 보면 모든 패키지에 의존하게 되고 → 그만큼 의도치 않은 변경이 생기게 될 가능성이 높아지게 된다.</li>
<li>이미 순환이 존재하면? -&gt; 이러한 <strong>순환을 끊는 방법은 크게 2가지</strong>가 존재<ol>
<li><strong>DIP 적용</strong> → 이때 클라이언트를 중심으로 인터페이스 이름을 지어야한다는 것에 주의</li>
<li>순환이 일어났던 원인 패키지 A, B가 둘 다 의존하는 새로운 패키지 생성</li>
</ol>
</li>
<li>패키지 구조는 하향식으로 설계하기 매우 힘들다. → 패키지 구조는 상향식으로 설계해야한다.</li>
<li><strong>패키지구조는 시스템이 성장하고 변화하며 같이 진화</strong></li>
<li><strong>패키지 의존 관계 다이어그램은 애플리케이션의 기능을 기술하는 일과는 거의 아무런 관계가 없다는 것에 주의!</strong></li>
<li><strong>결국 우리는 변화의 영향을 줄이기 위해 SRP와 CCP에 주의를 기울여서 함께 변경되기 쉬운 클래스들을 함께 묶어놓는 것이 목적</strong></li>
<li>애플리케이션 성장에 따라 재사용 가능한 요소를 만드는 일도 고려 → CRP 적용</li>
<li>이때 순환이 발생하면 <strong>ADP</strong> 적용 → 패키지 구조가 흔들리면서 성장</li>
<li><strong>공통으로 무엇을 폐쇄해야할지, 재사용 가능한 요소가 어떤 것인지도 모르고 클래스를 설계하기 전에 패키지 의존 관계 구조를 먼저 설계하려하면 큰 실패를 맛볼 수 있다.</strong></li>
</ul>
</li>
</ol>
<blockquote>
</blockquote>
<ol start="2">
<li><strong>SDP (안정된 의존 관계 원칙)</strong><ul>
<li><strong>의존은 안정적인 쪽으로 향해야 한다.</strong></li>
<li>안정적이다! → 그만큼 변경을 하려면 매우 많은 힘을 써야한다!</li>
<li>모든 패키지가 안정적일 필요는 없다!</li>
<li>단 패키지의 의존 방향은 “불안정 → 안정” 으로 흘러야한다! <strong>I(불안정성)</strong>이 작아지는 방향으로 흘러야한다!</li>
<li>그 반대가 되면, 변경이 쉬운 패키지도 변경이 어려워지게 된다!</li>
<li>안전성이 높다! → 변경하기 힘들다 → 다른 많은 패키지가 그 패키지에 의존하고 있다!</li>
<li>패키지 X가 다른 패키지에 의존하지 않는다! → 외부의 영향이 없다! → <strong>독립적</strong></li>
<li>X패키지에 의존하는 패키지가 3개이다 → <strong>3개의 패키지에 책임이 있다!</strong></li>
<li>기타 책에서 안정성 측정법에 대한 설명이 있다.→ 수치화시키는 방법</li>
<li>SDP가 위반되는 사례에서도 <strong>DIP</strong>를 이용하여 상황을 바로잡을 수 있다.</li>
</ul>
</li>
</ol>
<blockquote>
</blockquote>
<ol start="3">
<li><strong>SAP (안정된 추상화 원칙)</strong><ul>
<li><strong>패키지는 자신이 안정적인 만큼 추상적이기도 해야 한다.</strong></li>
<li>안정적인 패키지는 그 안정성 때문에 확장이 불가능하지 않도록 <strong>추상적이어야한다</strong>! ( <strong>유연함</strong>을 위해)</li>
<li><strong>불안정한 패키지는 구체적이어야하며 그 불안정성이 패키지 안의 구체적인 코드가 쉽게 변경될 수 있도록 허용</strong>한다. =&gt; 굳이 추상화를 할 필요가 없다는 뜻인 듯하다! 어차피 자주 바뀔 것이고 일반적으로 안정적인(다른 것들이 많이 의존하는) 쪽이 더 중요하고 메인 도메인 로직인 경우가 많기에, 그 쪽에 더 확장을 위한 힘을 쓰라는 것인 듯 하다. 굳이 바뀔 가능성이 많고 이쪽을 의존하는 패키지가 거의 없는 불안정한 패키지까지 추상화를 진행하며 코드 수, 클래스 수, 복잡도를 증가시킬 필요없다는 뜻이라고 해석했다.</li>
<li><strong>확장이 가능한 안정적인 패키지는 유연하며, 설계를 지나치게 제약하지 않는다.</strong></li>
<li><strong>SAP + SDP → DIP의 패키지판 ⇒ SDP는 의존 관계의 방향이 안정성의 증가 방향과 같아야 한다, SAP는 안정성이란 추상성을 내포 ⇒ 의존 관계는 추상성의 방향으로 흘러야한다!</strong></li>
</ul>
</li>
</ol>
<p><strong>⇒ 패키지 구성은 프로젝트의 초점이 개발 용이성에서 재사용성으로 옮겨감에 따라 시간이 흐르면서 조금씩 흔들리며 진화한다.</strong></p>
<h2 id="결론">결론</h2>
<hr>
<p><strong>&quot;안정성&quot;</strong>이라는 개념에 대해 더 확실하게 이해한 것 같아서 개인적으로 얻어간 것이 많은 챕터였다. 또한 SOLID 원칙에 대해서만 공부하고 패키지 단위의 원칙 6개에 대해서는 전혀 알지 못했는데, 이번 기회에 이렇게 공부하게 되어서 좋았다. 물론 아직 어색한 원칙들이기에 천천히 이해해나가야 할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Factory Method Pattern]]></title>
            <link>https://velog.io/@l0_0l/Factory-Method-Pattern</link>
            <guid>https://velog.io/@l0_0l/Factory-Method-Pattern</guid>
            <pubDate>Fri, 08 Apr 2022 07:13:39 GMT</pubDate>
            <description><![CDATA[<p>슈퍼클래스에서 객체를 생성하기 위한 인터페이스를 제공하고 서브클래스가 생성될 객체의 유형을 변경할 수 있도록 하는 디자인 패턴이다. 일반적으로 슈퍼클래스에서 어떠한 비즈니스 로직이 존재하고, 그 로직을 수행하는 객체를 생성하는 것을 서브클래스에서 구현하는 형태이다.</p>
<h2 id="problem">Problem</h2>
<hr>
<p>물류 관리 응용 프로그램을 만들었다. 앱의 첫 번째 버전은 트럭 운송만 처리할 수 있으므로 대부분의 코드는 Truck클래스 내에 있다. 나중에 사업을 확장하며 해상 물류에 대해서도 서비스를 확장해야할 시기가 왔다. 하지만 현재 대부분의 코드는 다 Truck 클래스와 연결되어있다. 지금 전체적으로 Ship클래스를 추가하여 변경한다고 하더라도 나중에 또 다른 운송 수단에 대해서 확장된다면? 문제가 복잡해지고 사이드 이펙트가 커질 수 있다.</p>
<h2 id="solve">Solve</h2>
<hr>
<p>직접적인 객체 생성 호출을 팩토리 메서드 내에서 해결한다. 이때 반환되는 객체를 제품이라고 한다. 팩토리 메서드를 가지고 있는 객체를 상속하여 자신이 원하는 제품을 만들도록 할 수 있다. 이 때 제품은 해당 도메인 내에서 정의된 동작을 하기위해 인터페이스를 구현해야한다.</p>
<p>클라이언트는 모든 제품을 추상적으로 취급할 수 있고, 그저 인터페이스를 사용할 뿐이다. 클라이언트는 내부적으로 어떤 일이 일어나는지 알 필요가 없다. 그저 필요한 기능을 호출할 뿐이다. 이렇게 팩토리 클래스, 제품 클래스를 추상화함으로써 더 유연한 서비스를 만들 수 있다. 운송 수단이 추가되면 기존 코드를 변경하는 것이 아닌 해당하는 클래스를 추가만 하면 된다. 이것은 <strong>&quot;Append Only&quot;</strong>, 즉 <strong>OCP</strong>를 잘 지켰다.</p>
<h2 id="code">Code</h2>
<hr>
<h3 id="logistics">Logistics</h3>
<pre><code class="language-kotlin">package factory_method

abstract class Logistics {
  fun planDelivery() {
    val transport = createTransport()
    println(&quot;---Start Delivery---&quot;)
    transport.deliver()
    println(&quot;---End Delivery---&quot;)
  }

  abstract fun createTransport(): Transport
}</code></pre>
<h3 id="roadlogistics">RoadLogistics</h3>
<pre><code class="language-kotlin">package factory_method

class RoadLogistics : Logistics() {
  override fun createTransport(): Transport = Truck()
}</code></pre>
<h3 id="sealogistics">SeaLogistics</h3>
<pre><code class="language-kotlin">package factory_method

class SeaLogistics : Logistics() {
  override fun createTransport(): Transport = Ship()
}</code></pre>
<h3 id="transport">Transport</h3>
<pre><code class="language-kotlin">package factory_method

interface Transport {
  fun deliver()
}</code></pre>
<h3 id="truck">Truck</h3>
<pre><code class="language-kotlin">package factory_method

class Truck : Transport {
  override fun deliver() {
    println(&quot;Go Go Truck!&quot;)
  }
}</code></pre>
<h3 id="ship">Ship</h3>
<pre><code class="language-kotlin">package factory_method

class Ship : Transport {
  override fun deliver() {
    println(&quot;Go Go Ship!&quot;)
  }
}</code></pre>
<h3 id="main">Main</h3>
<pre><code class="language-kotlin">package factory_method


fun main() {
  println(&quot;What mode of transport would you like to use?&quot;)
  println(&quot;1. Truck&quot;)
  println(&quot;2. Ship&quot;)

  val logistics: Logistics = when(readLine()) {
    &quot;1&quot; -&gt; RoadLogistics()
    &quot;2&quot; -&gt; SeaLogistics()
    else -&gt; {
      println(&quot;Error!&quot;)
      return
    }
  }

  logistics.planDelivery()
}</code></pre>
<h2 id="구조">구조</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/l0_0l/post/81e9aa9b-8d66-4955-b6e0-dc996dd64d5e/image.png" alt=""></p>
<h2 id="적용가능성">적용가능성</h2>
<hr>
<blockquote>
<ul>
<li>코드에서 작업해야 하는 객체의 정확한 유형과 종속성을 미리 모르는 경우</li>
</ul>
</blockquote>
<ul>
<li>라이브러리나 프레임워크의 사용자에게 내부 구성 요소를 확장하는 방법을 제공하려는 경우</li>
<li>매번 재구축하는 대신 기존 개체를 재사용하여 시스템 리소스를 절약하려는 경우</li>
</ul>
<h2 id="장점﹒단점">장점﹒단점</h2>
<hr>
<h3 id="장점">장점</h3>
<blockquote>
<ul>
<li>제작자와 구체적인 제품 간의 긴밀한 결합을 피할 수 있다.</li>
</ul>
</blockquote>
<ul>
<li><strong>SRP</strong> =&gt; 제품 생성 책임을 프로그램의 한 위치로 이동</li>
<li><strong>OCP</strong> =&gt; 기존 클라이언트 코드를 손상시키지 않고 새로운 유형의 제품을 프로그램에 도입할 수 있다.</li>
</ul>
<h3 id="단점">단점</h3>
<blockquote>
<ul>
<li>패턴을 구현하기 위해 많은 새 하위 클래스를 도입해야 하므로 코드가 더 복잡해질 수 있다. 가장 좋은 시나리오는 생성자 클래스의 기존 계층 구조에 패턴을 도입하는 경우이다.</li>
</ul>
</blockquote>
<h2 id="git">Git</h2>
<hr>
<p><a href="https://github.com/oh980225/DesignPattern/tree/main/src/main/kotlin/factory_method">https://github.com/oh980225/DesignPattern/tree/main/src/main/kotlin/factory_method</a></p>
<h2 id="ref">Ref</h2>
<hr>
<p><a href="https://refactoring.guru/design-patterns/factory-method">https://refactoring.guru/design-patterns/factory-method</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Chapter 18,19] 급여 관리 사례 연구]]></title>
            <link>https://velog.io/@l0_0l/Chapter-1819-%EA%B8%89%EC%97%AC-%EA%B4%80%EB%A6%AC-%EC%82%AC%EB%A1%80-%EC%97%B0%EA%B5%AC</link>
            <guid>https://velog.io/@l0_0l/Chapter-1819-%EA%B8%89%EC%97%AC-%EA%B4%80%EB%A6%AC-%EC%82%AC%EB%A1%80-%EC%97%B0%EA%B5%AC</guid>
            <pubDate>Wed, 06 Apr 2022 01:49:21 GMT</pubDate>
            <description><![CDATA[<h2 id="급여-관리-사례-연구의-🔑-key-point">급여 관리 사례 연구의 🔑 Key Point</h2>
<hr>
<p>책에서는 간단한 일괄 임금 지급 시스템 개발을 예로 들어 설명하고 있다. 책에서 나오는 <strong>&quot;반복의 시작&quot;, &quot;구현&quot;</strong> 부분에서 내가 느낀 포인트 위주로 정리하려 한다.</p>
<blockquote>
</blockquote>
<ol>
<li>첫 반복에 선택된 스토리에 대해 간단히 나열한다.</li>
<li><strong>요구사항을 듣고 데이터베이스 스키마를 생성하려 하지 말자!</strong><ul>
<li>이런 접근 방식은 자연스럽게 DB의존적인, 데이터베이스가 중심적 괌심사가 되는 어플리케이션을 만들도록 유도한다.</li>
<li>데이터베이스는 구체적인 구현이다. → 가능한 DB에 대한 고려는 뒤로 미뤄야한다.</li>
<li><strong>본질의 확충과 지엽적(부수적)인 것의 제거</strong>라는 <strong>추상화의 정의</strong>를 상기하자.</li>
<li>데이터베이스는 이 단계의 프로젝트에서는 지엽적인 것. → 그저 데이터를 저장하고 접근하는 용도, 그 이상 이하도 아님.(물론 예외적인 프로젝트도 존재할 수 있다.)</li>
</ul>
</li>
<li><strong>시스템의 데이터보다는 시스템의 행위를 먼저 생각하자!</strong><ul>
<li>우리가 만드는 것은 <strong>시스템의 행위(동작)</strong></li>
<li>이러기 위한 기법 중 하나 → <strong>유스케이스 만들기</strong></li>
<li><strong>유스케이스</strong><ul>
<li>좀 더 구체적인 내용이 추가되어 상세해진 사용자 스토리 (책에서 예시와 함께 잘 나와있음)</li>
<li>순서<ul>
<li>현재 반복에서 구현할 사용자 스토리 선택 → 상세화 → 유스케이스</li>
</ul>
</li>
<li>시스템의 사용자들이 시스템에 줄 수 있는 여러 종류의 자극을 알아내기 위해 사용자 스토리와 인수 테스트 등을 살펴본다</li>
<li>목적<ul>
<li>이 시스템에 어떤 자극을 주면 어떤 식으로 반응 하는지 알아내는 것</li>
</ul>
</li>
<li>상세화는 각 스토리를 충족시키는 코드 설계를 생각하는데 도움이 될 정도만 진행한다.</li>
</ul>
</li>
</ul>
</li>
<li>각각 유저 스토리들을 상세화시켜 유스케이스를 뽑아내고, 그 과정에서 적절한 패턴을 사용해서 클래스 구조를 뽑아낼 수 있다!</li>
<li>여러 유스케이스를 만들어내면서 기존의 생각했던 설계, 적용하려했던 패턴이 변경될 수 있다. -&gt; (구현 단계에서도 더 적절한 형태와 패턴을 찾아가며 설계가 변화할 수 있다고 생각한다. 사실 이 부분은 개인적으로 대략적인 틀만 잡고 TDD방식으로 진행하여 테스트에게 피드백 받으며 구현하고, 리팩토링하며 특정 패턴을 발견하며 설계를 진행하는 것이 더 좋은 설계에 다가가기 좋다고 생각한다.)</li>
<li>설계를 할 때도, 패턴을 적용하는 이유(패턴을 적용하기로 결정했다면), 그리고 패턴을 적용할 때 또는 그냥 클래스 구조를 설계할 때  SOLID 원칙은 잘 지켜지고 있는지, 정말로 요구사항을 잘 만족하고 있는지 등을 확인하며 설계를 해야한다!</li>
<li>책의 예시를 쭉 보면서 유스케이스의 분석이 시스템 설계에 풍부한 정보를 준다는 것을 알 수 있었다. 또한 설계가 진행되는 것들을 보며 이 모든 것이 유스케이스 즉, 행위에 대한 고찰로 인한 결과물이라는 것도 알 수 있었다.</li>
<li><strong>잠재적인 추상화를 찾아내자!</strong><ul>
<li>OCP를 효과적으로 사용하기 위해서는 애플리케이션 내에 <strong>잠재하는 추상화</strong>를 찾아내야 한다!</li>
<li>요구 사항과 유스케이스는 잠재적인 추상화의 일반적인 내용들을 표현하기에는 지나치게 구체적</li>
<li>여러 요구사항과 유스케이스들을 분석하며 <strong>일반화에 대한 힌트</strong>를 얻을 수 있다. 그리고 거기서 <strong>추상화</strong>할 것을 찾아낼 수 있다!</li>
<li>요구사항이 내포하는 것을 잘 catch해야한다! (책 내의 지급 주기와 지급 정책의 분리 → 그로 인해 지급 주기 변경에 대해 지급 정책이 닫혀있게 되고, OCP, SRP를 모두 지킬 수 있게 된다!)</li>
<li>변경하려했던 A를 변경하였더니 B도 영향이 가는, 변경의 영향이 예측되지 않는 상황은 두려움을 야기하고 사용자와 관리자의 개발자에 대한 신뢰성을 떨어뜨린다.</li>
</ul>
</li>
<li><strong>빠른 설계 회의</strong><ul>
<li>한 반복이 시작될 때, 화이트보드 앞에 팀이 모여 그 반복에 선택된 사용자 스토리의 설계를 놓고 논의하는 회의</li>
<li>보통 1시간 전에 종료</li>
<li><strong>목적</strong><ul>
<li>사고 과정을 시작</li>
<li>공통적인 사고 모델을 가짐</li>
</ul>
</li>
<li><strong>확실한 설계가 목적이 아니다!</strong></li>
<li>이번 챕터에서 한 활동이 빠른 설계 회의와 동등한 텍스트 형태</li>
</ul>
</li>
</ol>
<h2 id="결론">결론</h2>
<hr>
<p>사실 공통의 그림을 가질 수 있다는 점에서 이런 설계를 다이어그램으로 뽑아내는 것이 중요하다. 하지만 개인적으로 이러한 설계가 단점이 될 수도 있다고 생각한다. 구현 전의 설계와 구현 후의 설계는 다를 수 있기 때문이다. 실제로 구현하며 발견할 수 있는 부분이 있고, 직접 테스트를 진행하며 발견할 수 있는 부분도 많다. 그렇기에 처음부터 여긴 이 패턴을 적용하고, 이 클래스가 필요할 거고, 이 인터페이스가 필요할 것이고 하는 것보다는 큰 틀만 잡고 간단한 TDD를 사용하여 먼저 구현하여 테스트에게 피드백 받고, 잠재적 추상화를 발견하고 패턴을 발견하는 방향으로 진행하는 것이 더 좋은 설계에 다가가기 좋다고 생각한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Chapter 17] 널 오브젝트 패턴]]></title>
            <link>https://velog.io/@l0_0l/Chapter-17-%EB%84%90-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@l0_0l/Chapter-17-%EB%84%90-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Sat, 19 Feb 2022 12:04:17 GMT</pubDate>
            <description><![CDATA[<h2 id="널-오브젝트-패턴">널 오브젝트 패턴</h2>
<hr>
<p>데이터베이스에 &quot;A&quot;라는 이름의 Employee객체를 요청했을 때, 있는 경우는 그 객체를, 없는 경우는 null을 리턴한다. 하지만 우린 null 테스트를 자주 잊어버리고 그로 인해 다양한 에러를 맞이한다. </p>
<p>그렇다면 null을 반한하지 않고 예외를 발생시키게 하면 에러 발생 위험을 감소시킬 수 있을 것이다. 하지만 try/catch 블록은 null을 검사하는 것보다 보기 싫을 수 있다. 또한 기존 어플리케이션에 적용하기도 까다로울 수 있다.</p>
<p>이럴 때, <strong>널 오브젝트 패턴</strong>을 고려할 수 있다. 이 패턴을 사용하면 <strong>null 검사의 필요를 제거하고, 코드를 단순화</strong>할 수 있다. 예를 들어 Employee 인터페이스의 2개의 구현을 둘 수 있다. <strong>해당된 Employee가 존재하면 일반적인 구현인 EmployeeImplementation을, DB에 없다면 모든 메서드가 아무 일도 하지 않는 NullEmployee를 반환</strong>하는 것이다.</p>
<h3 id="before">before</h3>
<pre><code class="language-java">Employee e = DB.getEmployee(&quot;A&quot;);
if (e != null &amp;&amp; e.isTimeToPay(today)) {
    e.pay();
}</code></pre>
<h3 id="after">after</h3>
<pre><code class="language-java">Employee e = DB.getEmployee(&quot;A&quot;);
if (e.isTimeToPay(today)) { // NullEmployee라면 당연히 임금 지급할 시기가 없을 것!
    e.pay();
}</code></pre>
<p>또한 NullEmployee의 유일한 인스턴스를 저장하는 Employee의 <strong>정적 final 변수</strong>를 만들 수도 있다. 이때 <strong>익명 구현</strong>을 사용할 수 있다. 없는 직원을 익명 내부 클래스로 만드는 것은 <strong>인스턴스가 오직 하나임을 보장</strong>하는 방법일 것이다. 이렇게 되면 <strong>본질적으로 NullEmployee 클래스는 존재하지 않는다.</strong></p>
<pre><code class="language-java">public interface Employee {
    public boolean isTimeToPay(Date payDate);

    public void pay();

    public static final Employee NULL = new Employee() {
        public boolean isTimeToPay(Date payDate) {
            return false;
        }

        public void pay() {}
    }
}</code></pre>
<h2 id="결론">결론</h2>
<hr>
<p>이 패턴은 <strong>null이나 0을 반환할 수 있는 반환 값들을 검사해야한다는 생각을 전환</strong>시킬 수 있다. 이 패턴을 사용하면, <strong>함수가 실패해도 항상 유효한 객체를 반환하도록 보장</strong>할 수 있다. 그리고 이때 <strong>실패를 나타내는 객체들을 아무일도 하지 않을 것</strong>이다.</p>
<h2 id="책-외적으로">책 외적으로...</h2>
<hr>
<h3 id="그렇다-널-오브젝트는-안티-패턴이다">그렇다. 널 오브젝트는 안티 패턴이다.</h3>
<p><strong>널 오브젝트 패턴은 안티 패턴</strong>으로 알려져있다. 이유는 단순하다. 이 패턴은 <strong>문제를 숨길 수 있다!</strong> 실제로 스펙상 존재해야하는 객체인데 null object가 되었다면? 이 상황에서 프로그램은 중지 되지않고 아무 예외도 안 던질 수 있다. 그리고 그 <strong>객체가 필요한 순간 갑자기 어디선가 문제가 발생</strong>할 수 있다. 그렇기에 이 패턴은 안티 패턴으로 알려져있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Chapter 16] 싱글톤과 모노스테이트 패턴]]></title>
            <link>https://velog.io/@l0_0l/Chapter-16-%EC%8B%B1%EA%B8%80%ED%86%A4%EA%B3%BC-%EB%AA%A8%EB%85%B8%EC%8A%A4%ED%85%8C%EC%9D%B4%ED%8A%B8-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@l0_0l/Chapter-16-%EC%8B%B1%EA%B8%80%ED%86%A4%EA%B3%BC-%EB%AA%A8%EB%85%B8%EC%8A%A4%ED%85%8C%EC%9D%B4%ED%8A%B8-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Fri, 18 Feb 2022 06:42:26 GMT</pubDate>
            <description><![CDATA[<p>이 챕터에서는 <strong>단일성을 강제</strong>하는 두 패턴을 다룬다. 때때로 이런 단일성이 적용된 객체는 프로그램의 <strong>루트</strong>가 되기도하고, 다른 객체를 만들기 위해 사용하는 <strong>factory</strong>가 되기도 하며, 다른 객체를 추적하여 그 객체의 pace에 맞게 동작시키는 <strong>관리자</strong>가 되기도 한다.</p>
<h2 id="싱글톤-패턴">싱글톤 패턴</h2>
<hr>
<p>책 내의 2가지 테스트 케이스를 보며 싱글톤이 어떻게 동작하는지 알 수 있다.</p>
<blockquote>
</blockquote>
<ol>
<li>public static 메서드(메서드 명이 Instance라고 가정)를 통해 Singleton 인스턴스에 접근한다.</li>
<li>Instance 메서드는 항상 동일한 참조값을 가진 인스턴스를 반환한다.</li>
<li>Singleton 클래스는 public 생성자가 없기에 Instance메서드를 사용하지 않고서는 인스턴스를 생성할 방법이 없다.</li>
</ol>
<h3 id="구현">구현</h3>
<pre><code class="language-java">public class Singleton {
    private static Singleton theInstance = new Singleton();

    private Singleton() {}

    public static Singleton Instance() {
        return theInstance;
    }

}</code></pre>
<h3 id="이점">이점</h3>
<blockquote>
</blockquote>
<ol>
<li><strong>플랫폼 호환</strong> (RMI를 이용)</li>
<li><strong>어떤 클래스에도 적용 가능</strong></li>
<li><strong>파생을 통해 생성 가능</strong> -&gt; 주어진 클래스에서 싱글톤인 서브 클래스를 만들 수 있다.</li>
<li><strong>게으른 처리</strong>(꼭 필요하기 전까지 처리를 미룸)</li>
</ol>
<h3 id="비용">비용</h3>
<blockquote>
</blockquote>
<ol>
<li><strong>소멸이 정의되어 있지 않음</strong> : 싱글톤을 없애거나 사용을 중지하는 좋은 방법이 없다. null처리를 통해 필드에 할당된 인스턴스를 없애려고해도 다른 모듈에서 그 기존 인스턴스에 대한 참조값을 유지하고 있을 수 있고, 이어서 인스턴스가 2개가 존재하게 될 수도 있다.</li>
<li><strong>상속되지 않음</strong> : 싱글톤에서 파생된 클래스는 싱글톤이 아니다.</li>
<li><strong>효율성</strong> : 싱글톤의 인스턴스를 가져오는 메서드에서 현재 싱글톤 인스턴스가 존재하는지 null체크를 할 경우, 대부분의 경우 필요없는 if문이 계속하여 호출되게 된다.</li>
<li><strong>비투명성</strong> : 싱글톤의 사용자가 public static 메서드를 통해 인스턴스에 접근하므로 자신이 싱글톤을 사용한다는 사실을 안다.</li>
</ol>
<h3 id="동작에-있어서의-싱글톤-🔑key-point">동작에 있어서의 싱글톤 🔑Key point</h3>
<blockquote>
</blockquote>
<ol>
<li>데이터베이스를 사용하는 웹 서비스 Example -&gt; 어떤 사용자를 읽고 쓰기 위해 필요한 모든 모듈에서 데이터베이스에 직접 접근할 수 있는 경우</li>
<li>이 경우 코드 전체에 데이터베이스에 접근하는 서드파티 API사용이 확산되게 됨. 접근이나 구조에 대한 규정을 강제할 수 없게 된다.</li>
<li>좋은 해결책은 퍼사드 패턴을 사용하는 것 -&gt; UserDatabase 클래스</li>
<li>UserDatabase는 User객체와 데이터베이스의 테이블과 행 사이에 변환 작업을 한다. UserDatabase 내에서 구조와 접근의 규정을 강제할 수 있다.</li>
<li>여러 모듈에서 이것을 동시에 읽고 쓰지 않도록 보장하기 위해 싱글톤을 사용할 수 있다. -&gt; UserDatabaseSource</li>
<li>UserDatabaseSource의 단일 인스턴스로 모든 DB접근이 이루어진다는 것을 보장한다면 검사, lock 등을 넣어 접근과 구조에 대한 규정을 강제하기 쉬워진다.</li>
</ol>
<pre><code class="language-java">public class UserDatabaseSource implements UserDatabase {
    private static UserDatabase theInstance = new UserdatabaseSource();

    public static UserDatabase instance() {
        return theInstance;
    }

    private UserDatabaseSource() {}

    public User readUser(String userName) {
        // 구현 부분
    }

    public void writeUser(User user) {
        // 구현 부분
    }
}</code></pre>
<h2 id="모노스테이트-패턴">모노스테이트 패턴</h2>
<hr>
<p>모노스테이트 패턴은 싱글톤 패턴과는 완전히 다른 매커니즘이다. 모노스테이트 패턴도 책 내의 2가지 테스트 케이스를 보며 어떻게 동작하는지 알 수 있다.</p>
<blockquote>
</blockquote>
<ol>
<li>자신의 필드가 설정되거나 검색될 수 있는 객체이다.</li>
<li>한 인스턴스에서 필드 값을 A로 설정하면, 다른 인스턴스에서도 필드 값이 A가 된다.</li>
<li>단일 인스턴스라는 제약을 강제하지 않은 Singleton의 행위를 나타낸다.</li>
<li>모든 변수를 정적으로 만듦으로써 쉽게 구현할 수 있다.</li>
<li>단, 어떤 메서드도 정적이 아니라는 점에 주목하자.</li>
<li>인스턴스가 여러개여도 단일 객체처럼 동작</li>
<li>데이터를 잃지 않고도 현재 있는 모든 인스턴스를 없애거나 사용 중지 가능 (method area에 필드가 static으로 자리하고 있으니까!)</li>
</ol>
<h3 id="구현-1">구현</h3>
<pre><code class="language-java">public class Monostate {
    private static int x = 0;

    public Monostate() {}

    public void setX(int x) {
        this.x = x;
    }

    public int getX() {
        return x;
    }
}</code></pre>
<h3 id="두-패턴의-차이">두 패턴의 차이</h3>
<blockquote>
</blockquote>
<ol>
<li><strong>행위 vs 구조</strong></li>
<li><strong>싱글톤 패턴</strong>은 단일성 구조를 강제 -&gt; 인스턴스가 둘 이상 생성되는 것을 막음!(단일 인스턴스 제약)</li>
<li><strong>모노스테이트 패턴</strong>은 구조적인 제약을 부여하지 않고도 단일성이 있는 행위를 강제!</li>
<li>모노스테이트 테스트 케이스가 싱글톤 클래스에 대해서도 유효! 하지만 그 반대인 싱글톤 테스트 케이스는 모노스테이트 클래스에 대해 유효하지 않다!</li>
</ol>
<h3 id="이점-1">이점</h3>
<blockquote>
</blockquote>
<ol>
<li><strong>투명성</strong> : 사용자는 이 객체가 모노스테이트임을 알 필요가 없다.(일반 객체와 동일하게 사용)</li>
<li><strong>파생 가능성</strong> : 모노스테이트의 파생 클래스는 모노스테이트. 이들은 모두 같은 정적 변수를 공유</li>
<li><strong>다형성</strong> : 모노스테이트의 메서드는 정적이 아님 -&gt; 파생 클래스에서 오버라이드 가능! -&gt; 같은 정적 변수에 대해 다른 행위 제공 가능!</li>
<li><strong>잘 정의된 생성과 소멸</strong> : 정적인 변수를 같기에 생성과 소멸 시기가 잘 정의되어 있다. (시작에 클래스가 로드되며 생성, 프로그램이 종료되며 소멸 이야기인듯?)</li>
</ol>
<h4 id="java의-정적-메서드는-왜-override가-안될까">Java의 정적 메서드는 왜 override가 안될까?</h4>
<p>Java에서 정적 메서드는 재정의가 불가하다. 이유는 Static 메서드는 클래스가 컴파일 되는 시점에 결정되지만, override의 경우는 런타임 시점에 사용될 메서드가 결정되기 때문이다. static의 경우 클래스 단위로 만들어지게 되고, override의 경우 객체 단위로 만들어지게 된다.</p>
<h3 id="비용-1">비용</h3>
<blockquote>
</blockquote>
<ol>
<li><strong>변환 불가</strong> : 보통 클래스는 파생을 통해 모노스테이트로 변환될 수 없다.</li>
<li><strong>효율성</strong> : 실제 객체이기에 많은 생성과 소멸을 겪는다. 종종 비용이 꽤 들 수 있다.</li>
<li><strong>실재함</strong> : 모노스테이트 변수는 정적 변수이기에 사용되지 않더라도 공간을 차지한다. </li>
<li><strong>플랫폼 한정</strong> : 한 모노스테이트는 여러 JVM 인스턴스나 여러 플랫폼에서 동작하게 할 수 없다.</li>
</ol>
<h3 id="동작에-있어서의-모노스테이트-🔑key-point">동작에 있어서의 모노스테이트 🔑Key point</h3>
<blockquote>
</blockquote>
<ol>
<li>지하철 개찰구를 위한 간단한 유한 상태 기계를 구현하는 Example</li>
<li>모노스테이트인 Turnstile을 만들고 2개의 이벤트 함수(coin, pass)는 유한 상태 기계의 상태를 표현하는 Turnstile의 두 파생 클래스에게 위임(Locked, Unlocked)</li>
<li>모노스테이트는 파생 클래스가 다형적이 된다는 것과 파생 클래스들도 모노스테이트가 된다는 것을 주목</li>
<li>단 모노스테이트를 일반 클래스로 바꾸는 것은 매우 어렵다. 아래 예시도 보면 Turnstile은 모노스테이트적 본질에 강하게 의존</li>
<li>예를 들어, 이 코드로 2개 이상의 개찰구를 제어하려 한다면, 많은 리팩토링이 필요할 것</li>
<li>아래 예시에서 Locked와 Unlocked는 별도의 객체로 보기보다는 Turnstile 추상화의 일부라고 볼 수 있다.</li>
</ol>
<pre><code class="language-java">public class Turnstile {
    private static boolean isLocked = true;
    private static boolean isAlarming = false;
    private static int coins = 0;
    private static int refunds = 0;
    protected final static Turnstile LOCKED = new Locked();
    protected final static Turnstile UNLOCKED = new Unlocked();
    protected static Turnstile state = LOCKED;

    // 기타 구현...
}</code></pre>
<pre><code class="language-java">class Locked extends Turnstile {
    public void coin() {
        state = UNLOCKED;
        lock(false);
        alarm(false);
        deposit();
    }

    public void pass() {
        alaram(true);
    }
}</code></pre>
<pre><code class="language-java">class Unlocked extends Turnstile {
    public void coin() {
        refund();
    }

    public void pass() {
        lock(true);
        state = LOCKED;
    }
}</code></pre>
<h2 id="결론">결론</h2>
<hr>
<p><strong>싱글톤</strong>은 <strong>인스턴스 생성을 제어하고 제한하기 위해 private 생성자, 1개 정적 변수, 1개 정적 함수를 사용</strong>한다. <strong>모노스테이트</strong>는 그저 객체의 <strong>모든 변수를 static</strong>으로 만든다.</p>
<p><strong>싱글톤은 파생을 통해 제어하고 싶은 이미 존재하는 클래스가 있는 경우, 그리고 접근하기 위해 모두가 instance()를 호출해도 상관이 없을 때 좋은 선택</strong>이다. <strong>모노스테이트는 단일 객체의 파생 객체가 다형적이 되게 하고 싶을 때 좋은 선택</strong>이다.</p>
<h2 id="책-외적으로">책 외적으로...</h2>
<hr>
<h3 id="그렇다-싱글톤은-안티패턴이다">그렇다. 싱글톤은 안티패턴이다.</h3>
<p>싱글톤은 <strong>안티패턴</strong>이다. 그 이유는 다음과 같다.</p>
<ol>
<li>private 생성자 -&gt; 상속이 불가하다. </li>
<li>Mocking 이용한 테스트가 힘들다. -&gt; Mock은 서브클래싱 기반으로 작동하기 때문이다.</li>
<li>분산된 서버 환경에서는 싱글톤 보장이 안될수도 있다.</li>
<li>전역 상태를 만들 수 있다. -&gt; 즉 전역 상태 관리가 추가적으로 필요하게 된다. (멀티쓰레드 환경에서의 문제)</li>
<li>전체에서 하나의 객체만을 공통으로 사용하고 있기 때문에 각 객체간의 결합도가 높아지고 변경에 유연하게 대처하기 힘들 수 있다. 또한 변경으로 인한 사이드 이팩트가 클 수 있다.</li>
</ol>
<p>싱글톤이 안티패턴인 이유와 문제점에 대해 알고, trade-off를 고려하며 패턴을 사용해야할 것 같다.</p>
]]></description>
        </item>
    </channel>
</rss>