<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jazz_avenue.log</title>
        <link>https://velog.io/</link>
        <description>&lt;br&gt;</description>
        <lastBuildDate>Mon, 10 Oct 2022 13:04:09 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jazz_avenue.log</title>
            <url>https://velog.velcdn.com/images/jazz_avenue/profile/0788f3cc-4b92-44b2-bc4b-afc2ea00d58a/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jazz_avenue.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jazz_avenue" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Java Collection의 Unmodifiable과 Immutable]]></title>
            <link>https://velog.io/@jazz_avenue/Java-9%EC%9D%98-of%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%B6%88%EB%B3%80-%EC%BB%AC%EB%A0%89%EC%85%98-%EC%83%9D%EC%84%B1%EC%9D%98-%EC%9D%B4%EC%A0%90</link>
            <guid>https://velog.io/@jazz_avenue/Java-9%EC%9D%98-of%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%B6%88%EB%B3%80-%EC%BB%AC%EB%A0%89%EC%85%98-%EC%83%9D%EC%84%B1%EC%9D%98-%EC%9D%B4%EC%A0%90</guid>
            <pubDate>Mon, 10 Oct 2022 13:04:09 GMT</pubDate>
            <description><![CDATA[<p>페이스북에서 본 <a href="https://www.facebook.com/tobyilee/posts/pfbid02Gd9MNG1QWWf1kpJ6p9FmuxroXvuvLEuHgC8PG5kzjA1FkBwNSrvE1kVMSjFRaLFPl">이일민님의 타임라인 글</a>을 보고 정리 차원에서 다시 작성해본다.</p>
<h2 id="java-9-이전의-불변-컬렉션-생성하기">Java 9 이전의 불변 컬렉션 생성하기</h2>
<ul>
<li>Java 9 이전에 Immutable Collection을 만들기 위한 코드는 다음과 같다.<pre><code class="language-java">Set&lt;String&gt; set = new HastSet&lt;&gt;();
// ... add some elements in set
set = Collections.unmodifiableSet(set);</code></pre>
</li>
<li>이 때 만들어지는 오브젝트들을 확인하면 다음과 같다.<ol>
<li>HashMap 1개 (HashSet 내부에서 생성)</li>
<li>HashSet 1개</li>
<li>Unmodifiable Wrapper Object 1개</li>
<li>Node Object (HashMap 내부에서 생성하는 Node 객체로 저장하는 Item의 개수만큼 생성)</li>
<li>Initaial Capacity 만큼의 <code>Node[]</code> 1개 (HashMap 내부에서 객체를 저장하는 <code>table</code>) </li>
</ol>
</li>
<li>Java에서 Object는 64Bit JVM을 기준으로 12Byte의 헤더를 가진다.
<img src="https://velog.velcdn.com/images/jazz_avenue/post/2f5f7476-cb84-4b4d-a552-def855502b75/image.png" alt=""></li>
<li><a href="https://mvnrepository.com/artifact/org.openjdk.jol/jol-core/0.16">Java Object Layout</a> 이라는 라이브러리를 활용해서 객체의 대략적인 크기를 측정해보면 다음과 같다.
<img src="https://velog.velcdn.com/images/jazz_avenue/post/e0402135-3fe4-4c62-976e-e5600c639d84/image.png" alt="">
<img src="https://velog.velcdn.com/images/jazz_avenue/post/7ccdb230-ae03-4a37-b19b-c8c156425060/image.png" alt=""></li>
</ul>
<br>

<h2 id="java-9의-setof를-이용한-불변-컬렉션-생성">Java 9의 Set.of를 이용한 불변 컬렉션 생성</h2>
<ul>
<li>Java 9에서 도입된 <code>Set.of()</code>를 사용해서 불변 컬렉션을 생성해보자.</li>
<li>이렇게 생성된 Set은 내부적으로 Set12 인스턴스를 참조하고 여기서 직접 저장하는 객체들을 참조한다.
<img src="https://velog.velcdn.com/images/jazz_avenue/post/cf0fe926-4951-4993-803a-952192ead7ac/image.png" alt=""></li>
<li>내부적으로 사용 및 만들어지는 오브젝트의 수가 훨씬 적고 참조 구조도 단순하기 때문에 결과적으로는 Java Object Layout을 통해 확인한 결과가 앞선 방법보다 약 1/3 정도 줄어들었다.
<img src="https://velog.velcdn.com/images/jazz_avenue/post/dfd7fc70-c7e7-4475-a164-6ef815095e03/image.png" alt="">
<img src="https://velog.velcdn.com/images/jazz_avenue/post/66f829c5-b8a9-449d-b213-815414d9651c/image.png" alt=""></li>
</ul>
<br>

<h2 id="unmodifiable-과-immutable은-다르다">Unmodifiable 과 Immutable은 다르다</h2>
<ul>
<li>이일민님의 글의 마무리에는 다음과 같이 적혀있다.<blockquote>
<p>&quot;생성후 변경은 필요없고(+불가능해야 하고) 참조만 한다면 기존의 <code>Collections.unmodifiableSet()</code> 대신 컬렉션 인터페이스의 <code>static</code> 메서드로 추가된 <code>of()</code>로 생성하면 좋다.</p>
</blockquote>
</li>
<li>이와 관련해서 좀 더 부가적인 설명을 하기 위해서 Unmodifiable과 Immutable은 다르다는 것을 짚고 넘어가려고한다.</li>
<li><code>Collections.unmodifiableSet()</code> 이 동작하는 방식을 살펴보면 다음과 같이 <code>set()</code>, <code>add()</code>, <code>addAll()</code> 등의 변경을 가하는 메서드를 호출하면 내부적으로 UnsupportedOperationException을 발생시키도록 되어있다.
<img src="https://velog.velcdn.com/images/jazz_avenue/post/513cc7ca-886e-4dfe-95b8-85651d2ce7f6/image.png" alt=""></li>
<li>이 때 문제가되는 부분은 <code>Collections.unmodifiableSet()</code> 등을 통해 생성된 객체가 아닌 변경 가능한 원본 객체를 통해 접근하게되면 Unmodifiable Collection도 변경된다. (원본 자체에 대한 수정을 막을 수 없음)</li>
<li>즉, &quot;불변&quot;이라는 목적을 완벽하게 달성할 수는 없다. (Unmodifiable Collection을 원본 객체에 할당한다고 하더라도 할당되기 이전의 원본 객체의 레퍼런스를 가지고 있다면 변경이 가능함)
<img src="https://velog.velcdn.com/images/jazz_avenue/post/e3793b32-ce0c-4e7c-bbdc-f14dea063ee0/image.png" alt=""></li>
<li>이 때, Unmodifiable Collection을 이용해서 불변 컬렉션을 만들고 싶다면 읽기 전용 복사본을 활용해서 다음과 같이 코드를 작성해야한다.<pre><code class="language-java">Set&lt;String&gt; immutable = Collections.unmodifiableSet(new HashSet&lt;&gt;(set));</code></pre>
</li>
<li>Java 9의 <code>Set.of()</code> 등은 원본 컬렉션을 참조하는 방식이 아닌 애초에 값들을 가지고 새로운 불변 컬렉션을 생성하기 때문에 불변성을 달성할 수 있다.</li>
<li>다만, 주의할 점은 컬렉션 내부에 저장되어있는 레퍼런스 타입의 객체들의 속성은 외부에 있는 원본 객체들을 통해서 값이 변경될 수 있고, 이를 방지하고 싶다면 해당 객체를 값 타입(불변 객체)로 선언하던지 방어적 복사본을 활용하자. </li>
</ul>
<br>

<p>결론을 3줄 요약해보자면 </p>
<ul>
<li>컬렉션의 불변성을 달성하기 위해서라면 <code>unmodifiableCollection()</code> 대신 Collection의 <code>of()</code> 를 활용하자. (좀 더 쉽고, 내부적으로도 가벼운 불변 컬렉션을 만들 수 있다.)</li>
<li>이를 통해서 달성할 수 있는 것은 컬렉션의 불변성이지 내부에 저장하고 있는 참조 객체들의 불변성은 아니다.</li>
<li>내부에 저장하는 객체들의 불변성까지도 달성하고 싶다면, 해당 객체를 불변 객체로 선언하던지 방어적 복사본을 활용하자.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[좀 더 우아한 Retry (Expenential Backoff with Jitter)]]></title>
            <link>https://velog.io/@jazz_avenue/%EC%A2%80-%EB%8D%94-%EC%9A%B0%EC%95%84%ED%95%9C-Retry-Expenential-Backoff-with-Jitter</link>
            <guid>https://velog.io/@jazz_avenue/%EC%A2%80-%EB%8D%94-%EC%9A%B0%EC%95%84%ED%95%9C-Retry-Expenential-Backoff-with-Jitter</guid>
            <pubDate>Sat, 08 Oct 2022 03:34:57 GMT</pubDate>
            <description><![CDATA[<p>사내에서 APNs 관련 Retry 로직을 작성하기 위해 학습한 Exponential Backoff 관련 내용을 정리한다.</p>
<h2 id="exponential-backoff-가-필요한-이유">Exponential Backoff 가 필요한 이유</h2>
<ul>
<li>서버와 서버간의 API 호출에 대한 재시도 행위는 매우 중요한데 단순히 한번의 네트워크 호출 실패로 서비스의 비즈니스 로직을 모두 실패처리하거나 <code>fallback</code> 처리하는 것은 몇번 재시도하는 것보다 큰 리소스 낭비가 될 수 있다.</li>
<li>특히 명확한 비즈니스 로직상의 실패 응답을 받는 상황이 아니라 네트워크의 일시적인 장애로 인하여 발생한 <code>timeout</code> 의 경우에는 충분히 재시도 해볼만하다고 할 수 있다.</li>
</ul>
<br>

<h3 id="의미없는-retry-행위">의미없는 Retry 행위</h3>
<ul>
<li>평범한 재시도 행위 자체는 대부분 의미 없거나 네트워크에 부담을 더 가중하는 결과로 이어지게된다.</li>
<li>대부분의 <code>timeout</code> 상황의 경우에도 특정 시간동안 네트워크 이슈가 지속되는 경우가 많기 때문에 이를 즉시 재시도한다고해도 모두 실패로 끝날 가능성이 높다.</li>
<li>재시도 자체를 일정 시간 간격을 두지 않고 시도하는 자체가 기존에 문제가 발생한 네트워크에 더 부담을 가중할 뿐이다.<ul>
<li>특정 네트워크에 트래픽이 몰리는 상황이 발생해 요청 자체가 지연되는 상황에서 모든 클라이언트가 연속으로 재시도를 시도한다면, 네트워크 트래픽을 가중시키게 된다.</li>
</ul>
</li>
</ul>
<br>

<h3 id="exponential-backoff-를-이용한-똑똑한-재시도">Exponential Backoff 를 이용한 똑똑한 재시도</h3>
<ul>
<li>일정 시간 간격을 두고 재시도하는 것은 단순히 &quot;일정 시간의 여유&quot;만 주었다는 것을 제외하고는 동일하게 네트워크에 부하를 줄 가능성이 크다.<ul>
<li>ex. 실패시 3초마다 요청을 시도</li>
</ul>
</li>
<li>때문에 일반적인 방법은 재시도하는 시간 간격이 매 시도마다 점차 늘어나는 Exponential Backoff 전략을 사용하는 것이다.<ul>
<li>Exponential Backoff 전략에서는 지수에 비례하여 Backoff 시간을 조절하는데 다음과 같은 방식으로 동작한다.</li>
<li>ex. 첫번째 시도를 위한 대기 시간을 100ms, 두번째 재시도를 위한 대기 시간을 200ms, 세번째 재시도를 위한 대기시간을 400ms</li>
<li>위와 같이 점차 재시도를 위한 시간이 $2^n$ 만큼 증가하는 방식으로 동작한다.</li>
</ul>
</li>
<li>Exponential Backoff 가 이러한 방식을 사용하는 이유는 재시도 횟수가 증가할수록 Backoff 시간이 증가하기 때문에 네트워크에 갑작스럽게 트래픽을 부담시키는 것을 피할 수 있다.</li>
<li>하지만 이러한 방법도 동시에 요청이 몰린다면 동일한 시간 간격으로 모든 재시도가 수행될 것이기 때문에 한계점이 존재한다.</li>
</ul>
<br>

<h3 id="개선된-exponential-backoff-전략-with-jitter">개선된 Exponential Backoff 전략 with Jitter</h3>
<ul>
<li>Jitter는 패킷의 지연이 수시로 변하면서 그 간격이 일정하지 않는 현상 즉, 지연 변이를 의미한다.</li>
<li>Jitter를 Retry에 적용하면 API를 요청하는 클라이언트 사이의 동일한 재시도 시간에 무작위성을 부여하여 서로 요청하는 시간대의 동시성을 분산시킬 수 있다.</li>
<li>즉, 간단하게 말하면 Exponential Backoff에 무작위성을 더하여 동일한 시간대에 재시도 횟수가 집중되는 것을 분산시켜주는 것이라고 볼 수 있다.</li>
</ul>
<br>

<h2 id="exponential-backoff-with-jitter-구현">Exponential Backoff with Jitter 구현</h2>
<ul>
<li>Jitter를 이용한 Exponential Backoff의 기본 아이디어 구현은 다음과 같다.<pre><code class="language-java">int interval = Math.min(MAX_INTERVAL_TIME, base * Math.pow(2, attempt));
int jitter = Random.nextInt(MIN_JITTER_VALUE, MAX_JITTER_VALUE);
Thread.sleep(inteval + jitter);</code></pre>
</li>
<li>위와 같이 시도 횟수에 따른 지수적인 시간의 증가와 더불어 Random한 Jitter 가중치를 부여함으로써 좀 더 개선된 Exponential Backoff를 구현할 수 있다.</li>
<li><em><strong>Resilience4J</strong></em> 라는 라이브러리에서는 <code>ofExponentialRandomBackoff()</code>라는 형태로 이를 지원하고 있다.<pre><code class="language-java">static IntervalFunction ofExponentialRandomBackoff(
long initialIntervalMillis,
double multiplier,
double randomizationFactor
) {
checkInterval(initialIntervalMillis);
checkMultiplier(multiplier);
checkRandomizationFactor(randomizationFactor);
return attempt -&gt; {
  checkAttempt(attempt);
  final long interval = 
  of(initialIntervalMillis, x -&gt; (long) (x * multiplier))
      .apply(attempt);
  return (long) randomize(interval, randomizationFactor);
};
}
</code></pre>
</li>
</ul>
<p>static double randomize(final double current, final double randomizationFactor) {
  final double delta = randomizationFactor * current;
  final double min = current - delta;
  final double max = current + delta;</p>
<p>  return (min + (Math.random() * (max - min + 1)));
}</p>
<pre><code>- 서비스에 간단하게 구현한 형태는 다음과 같다.
```java
public void runWithRetry(Runnable runnable) {
  runWithRetry(runnable, 0);
}

private void runWithRetry(Runnable runnable, int count) {
  try {
    runnable.run();
  } catch (Exception e) {
      if (count &gt;= MAX_RETRY_COUNT) {
        throw e;
    }

    try {
      Thread.sleep(BASE_INTERVAL_TIME * Math.pow(2, count) + ThreadLocalRandom.current().nextInt(MIN_JITTER_VALUE, MAX_JITTER_VALUE));
    } catch(InterrupedException e) {

    }
    runWithRetry(runnable, count + 1);
  }
}
</code></pre><br>

<p>참고</p>
<ul>
<li><a href="https://aws.amazon.com/ko/blogs/architecture/exponential-backoff-and-jitter/">Exponential Backoff and Jitter, AWS</a></li>
<li><a href="https://github.com/resilience4j/resilience4j/blob/master/resilience4j-retry/src/main/java/io/github/resilience4j/retry/IntervalFunction.java">InternalFunction - Resilience4J</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[객체 지향과 데이터 지향 프로그래밍]]></title>
            <link>https://velog.io/@jazz_avenue/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EA%B3%BC-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@jazz_avenue/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EA%B3%BC-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Sun, 25 Sep 2022 16:34:50 GMT</pubDate>
            <description><![CDATA[<h2 id="객체-지향과-데이터-지향-프로그래밍">객체 지향과 데이터 지향 프로그래밍</h2>
<p><em>이야기에 앞서서, &quot;데이터 중심 설계&quot;와 &quot;데이터 지향 프로그래밍&quot;은 &quot;설계&quot;와 &quot;프로그래밍&quot;(구현)의 관점에서 둘은 서로 다를 수 있지만, 어느정도 결은 같이한다고 생각하고 작성하였다. 혹시라도 내가 가정한 부분이 크나큰 오류를 범하고 있다면 언제든지 바로잡아주길 바란다.</em></p>
<p>&quot;오브젝트&quot;를 읽으면서 &quot;데이터 중심 설계&quot;의 문제점에 대해 이야기하는 부분이 있었는데, 최근 읽은 Brian Goetz의 <a href="https://www.infoq.com/articles/data-oriented-programming-java/?topicPageSponsorship=f887b6f5-db7a-4765-a609-cd556cef9128">Data Oriented Programming in Java</a> 라는 아티클의 내용과 같이 이야기해보려고 한다.</p>
<p>&quot;오브젝트&quot; 책의 4장부터 5장에 걸쳐서 &quot;데이터 중심 설계&quot;의 문제점에 대해서 이야기하고 &quot;데이터 중심 설계&quot;에서 &quot;책임 중심 설계&quot;로 리팩토링하는 전반적인 과정에 대해서 다루고있다.</p>
<p>책에서 언급하는 &quot;데이터 중심 설계&quot;의 가장 큰 문제점은 변경에 취약하는 것이다. </p>
<ul>
<li>데이터 중심 설계는 본질적으로 너무 이른 시기에 데이터에 관해 결정하도록 강요한다.</li>
<li>데이터 중심 설계에서는 협력이라는 문맥을 고려하지 않고 객체를 고립시킨채 오퍼레이션을 결정한다.</li>
</ul>
<p>이 두가지 문제점에 대해서 좀 더 풀어서 설명하자면 다음과 같다.</p>
<br>

<h3 id="객체의-행동보다는-상태에-초점을-맞춘다">객체의 행동보다는 상태에 초점을 맞춘다</h3>
<ul>
<li>&quot;데이터 중심 설계&quot;를 시작할 때 던졌던 첫번째 질문은 &quot;이 객체가 포함해야하는 데이터가 무엇인가?&quot;이다.</li>
<li>&quot;데이터&quot;는 구현의 일부로, 시작하는 처음부터 &quot;데이터&quot;에 관해 결정하도록 강요하기 때문에 너무 이른 시기에 내부 구현에 초점이 맞춰진다.</li>
<li>데이터 중심 관점에서는 객체는 그저 단순한 데이터의 집합체일 뿐이며 이는 과도한 접근자와 수정자를 추가하게만들고, 데이터 객체를 사용하는 절차를 분리된 별도의 객체 안에서 구현하게 된다.<ul>
<li>접근자와 수정자는 <code>public</code> 속성과 큰 차이가 없기 때문에 캡슐화가 무너진다.</li>
</ul>
</li>
<li>데이터를 먼저 결정하고 나중에 데이터를 처리하는데 필요한 오퍼레이션을 나중에 결정하는 방식은 데이터에 대한 지식이 객체의 인터페이스에 고스란히 드러난다.</li>
<li>결국 객체의 인터페이스는 구현을 캡슐화하는데 실패하고 코드는 변경에 취약해진다.</li>
</ul>
<br>

<h3 id="객체를-고립시킨채-오퍼레이션을-정의하도록-만든다">객체를 고립시킨채 오퍼레이션을 정의하도록 만든다</h3>
<ul>
<li>올바른 객체지향 설계의 무게중심은 항상 외부에 맞춰져있어야한다.<ul>
<li>객체가 내부에 어떤 상태를 가지고 관리하는지는 부가적인 문제고 중요한 것은 다른 객체와 어떻게 협력하는가이다.</li>
</ul>
</li>
<li>데이터 중심 설계의 초점은 객체 내부로 향한다.<ul>
<li>실행 컨텍스트에 대한 깊이있는 고민 없이 객체가 관리할 데이터의 세부 정보를 먼저 결정한다.</li>
</ul>
</li>
<li>객체의 구현이 이미 결정된 상태에서 다른 객체와의 협력 방법을 고민하기 때문에 이미 구현된 객체의 인터페이스를 억지로 끼워 맞출 수밖에 없다.</li>
</ul>
<br>

<h2 id="극단적인-치우침과-데이터-중심-설계">극단적인 치우침과 데이터 중심 설계</h2>
<p>&quot;데이터 중심 설계&quot;의 문제점에 대해서는 깊이 공감하고있다. </p>
<ul>
<li>소프트웨어 세계는 끊임없이 변한다. 그렇기 때문에 확장가능하고 변경에 유연하게 대처할 수 있는 설계의 중요성에 대해서는 공부하면서 귀에 못이 박히도록 들은 것 같다. </li>
<li>뿐만 아니라 회사 프로젝트의 설계 및 코드 베이스가 데이터 중심이고 이로 인해서 책에서 언급한 여러가지 고충들을 실제로 몸소 경험하고 있기 때문에 공감가는 부분이 많았다.</li>
</ul>
<p>그렇기 때문에 나 스스로도 &quot;데이터 중심 설계&quot;를 안티 패턴이나 구시대의 유물쯤으로 생각하고 있었는데, <em>Brian Goetz</em> 의 글을 읽고는 한번 더 지식의 극단적인 치우침이 얼마나 위험한지 생각하게 되었다.</p>
<p><em>Brian Goetz</em> 가 말하는 &quot;데이터 중심 프로그래밍&quot;이란 무엇일까? 이야기에 앞서서 결론부터 말하자면 프레드 브룩스의 논문의 구문처럼 <a href="http://worrydream.com/refs/Brooks-NoSilverBullet.pdf">&quot;소프트웨어 개발의 복잡성을 한번에 해소할 마법같은 솔루션(은탄환)은 없다&quot;</a>이다.</p>
<br> 

<h3 id="java에서의-데이터-중심-프로그래밍">Java에서의 데이터 중심 프로그래밍</h3>
<p>Brian Goetz가 작성한 &quot;Java에서의 데이터 중심 프로그래밍&quot;은 &quot;데이터 중심 설계&quot;와 비교했을때, &quot;설계&quot;에서 &quot;프로그래밍&quot;으로 이어지는 흐름상 같은 기조를 가지고 있다고 판단했다. (이로인한 논리적 오류나 잘못된 판단을하고 있다면 정정해주길 바란다)</p>
<p>아티클 전반적인 내용에 대해 설명하지는 않고 Brian Goetz가 작성한 아티클의 내용을 일부 요약하려고한다.</p>
<ul>
<li>OOP는 복잡하고 거대한 애플리케이션을 작은 경계를 가진 모듈들로 나누어 복잡성을 효과적으로 제어할 수 있지만, 잘못 수행된 OOP는 끔찍하며, 많은 사람들이 극단적인 OOP의 원칙에 노출되어있다.<ul>
<li>즉, OOP가 어떠한 상황에서도 만능이라고 생각하는 사람들에 의해 잘못 사용되고있다.</li>
</ul>
</li>
<li>현대의 프로그래밍 패러다임은 거대한 모놀리식 프로그램에서 점차 많은 소규모 서비스를 통해 거대한 애플리케이션을 구성하는 마이크로 서비스 형태로 변화하고있다.<ul>
<li>소규모 서비스에서는 내부 경계가 덜 필요하다. (충분히 작은 서비스는 단일 팀 또는 개발자에 의해서 유지보수 될 수 있음)</li>
</ul>
</li>
<li>복잡한 엔티티를 모델링하거나 Java의 Stream API같이 풍부한 라이브러리를 작성할 때 객체 지향은 많은 것을 제공한다.</li>
<li>그러나 단순하고, 임시의 데이터를 처리하는 간단한 서비스를 구현할 떄는 데이터 지향 프로그래밍이 좀 더 나은 방법이 될 수 있다.</li>
<li>객체 지향과 데이터 지향은 결코 상충되는 개념이 아니다 우리는 좀 더 적절하다고 생각하는 곳에 적합한 도구를 사용하면 된다.</li>
<li>Java에서는 이러한 데이터 지향 프로그래밍을 지원하기 위해서 <code>Record</code>, <code>Sealed</code>, 패턴 매칭 등의 다양한 기능을 제공한다.<ul>
<li>이러한 독립적인 개념들은 상호 보조적으로 동작하며 이러한 도구들을 조합해서 사용하면 좀 더 쉽게 유효하지 않은 상태를 표현하는 것을 방지할 수 있다.</li>
<li>이를 통해 코드의 안전성과 유지보수성을 향상시킬 수 있을 것이다.</li>
</ul>
</li>
</ul>
<br>

<p>사실상 &quot;데이터 지향 프로그래밍&quot;을 옹호하는 입장이라기 보다는 객체 지향이든 데이터 지향이든 적합하다고 생각하는 곳에 적절한 도구를 사용해야한다는 말을 하면서, 데이터 지향 프로그래밍을 할 때 좀 더 효과적으로 프로그래밍 할 수 있는 Java의 여러가지 도구들을 소개하는글에 가까운 것 같다.</p>
<p>결론을 지어보자면 &quot;데이터 지향 프로그래밍(설계)&quot;이 틀렸다, &quot;객체 지향 프로그래밍(설계)&quot;이 항상 옳다는 잘못된 말인 것 같다. 특정 사상이나 기술에 매몰되는 것은 위험하다. 상황이나 가치 판단의 기준을 흐리게하고 편협한 사고, 좁은 시야에 개발자를 가두고만다.  </p>
<p>개발자에게 있어서 좀 더 중요한 것은 <em>Brian Goetz</em> 의 말대로 적재적소에 좀 더 적절한 도구를 선택해서 주어진 &quot;문제&quot;를 해결하는 것이 아닐까 생각이든다. (그렇다고해서 기술이나 사상이 덜 중요하다는 이야기는 아니다)</p>
<p>프레드 브룩스의 논문의 구문을 한번더 언급하면서 끝맺으려고한다. <a href="http://worrydream.com/refs/Brooks-NoSilverBullet.pdf">&quot;소프트웨어 개발의 복잡성을 한번에 해소할 마법같은 솔루션(은탄환)은 없다&quot;</a></p>
]]></description>
        </item>
    </channel>
</rss>