<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>minkyu.log</title>
        <link>https://velog.io/</link>
        <description>Backend Engineer, Vim User</description>
        <lastBuildDate>Wed, 17 Jan 2024 02:16:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>minkyu.log</title>
            <url>https://velog.velcdn.com/images/minkyu__k/profile/6cfe5606-7b4f-4c95-b8f9-383a016f3cb5/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. minkyu.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/minkyu__k" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[kubectl 명령어]]></title>
            <link>https://velog.io/@minkyu__k/kubectl-%EB%AA%85%EB%A0%B9%EC%96%B4</link>
            <guid>https://velog.io/@minkyu__k/kubectl-%EB%AA%85%EB%A0%B9%EC%96%B4</guid>
            <pubDate>Wed, 17 Jan 2024 02:16:16 GMT</pubDate>
            <description><![CDATA[<h3 id="get">get</h3>
<ul>
<li><p>클러스터를 구성하는 각 노드의 기본적인 정보가 출력된다.</p>
<pre><code class="language-bash">kubectl get nodes</code></pre>
</li>
<li><p>클러스터에 있는 모든 파드의 목록을 출력한다.</p>
<pre><code class="language-bash">kubectl get pods</code></pre>
</li>
<li><p>파드에 대한 기본적인 정보를 확인한다.</p>
<pre><code class="language-bash">kubectl get pod [podName]</code></pre>
</li>
<li><p>네트워크 상세 정보 중 특정한 항목을 따로 지정해서 출력한다. </p>
<pre><code class="language-bash">kubectl get pod [podName] --output custom-columns=NAME:metadata.name,NODE_IP:status.hostIP,POD_IP:status.podIP</code></pre>
</li>
</ul>
<ul>
<li><p>JSON PATH로 복잡한 출력을 구성한다.</p>
<pre><code class="language-bash">kubectl get pod [podName] -o jsonpath=&#39;{.status.containerStatuses[0].containerID}&#39;</code></pre>
</li>
<li><p>파드의 IP 주소 확인</p>
<pre><code class="language-bash">kubectl get pod -l app=[appName] --output  jsonpath=&#39;{.items[0].status.podIP}&#39;</code></pre>
</li>
<li><p>서비스의 상세 정보를 출력한다.</p>
<pre><code class="language-bash">kubectl get svc [appName]</code></pre>
</li>
</ul>
<h3 id="describe">describe</h3>
<ul>
<li>파드의 상세 정보를 확인한다.<pre><code class="language-bash">kubectl describe pod [appName]</code></pre>
</li>
</ul>
<h3 id="run">run</h3>
<ul>
<li>컨테이너 하나를 담은 파드를 실행한다.<pre><code class="language-bash">kubectl run [containerName] --image=[imageName]</code></pre>
</li>
</ul>
<h3 id="wait">wait</h3>
<ul>
<li>파드가 준비 상태가 될 때까지 기다린다.<pre><code class="language-bash">kubectl wait --for=Ready pod -l app=[appName]</code></pre>
</li>
</ul>
<h3 id="exec">exec</h3>
<ul>
<li>ping 보내기<pre><code class="language-bash">kubectl exec deploy/sleep-1 -- ping -c 2 $(kc get pod -l app=sleep-2 --output jsonpath=&#39;{.items[0].status.podIP}&#39;)</code></pre>
</li>
</ul>
<h3 id="delete">delete</h3>
<ul>
<li><p>파드를 삭제한다.</p>
<pre><code class="language-bash">kubectl delete pods -l app=[appName]</code></pre>
</li>
<li><p>모든 파드 삭제</p>
<pre><code class="language-bash">kubectl delete pods --all</code></pre>
</li>
<li><p>디플로이먼트 모두 삭제</p>
<pre><code class="language-bash">kubectl delete deploy --all</code></pre>
</li>
<li><p>현재 배포된 클러스터IP 서비스를 삭제한다.</p>
<pre><code class="language-bash">kubectl delete svc [serviceName]</code></pre>
</li>
</ul>
<h3 id="apply">apply</h3>
<ul>
<li>디플로이먼트를 생성한다.<pre><code class="language-bash">kubectl apply -f [.yaml]</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[옵시디언 한글 받침 씹히는 현상(mac)]]></title>
            <link>https://velog.io/@minkyu__k/%EC%98%B5%EC%8B%9C%EB%94%94%EC%96%B8-%ED%95%9C%EA%B8%80-%EB%B0%9B%EC%B9%A8-%EC%94%B9%ED%9E%88%EB%8A%94-%ED%98%84%EC%83%81mac</link>
            <guid>https://velog.io/@minkyu__k/%EC%98%B5%EC%8B%9C%EB%94%94%EC%96%B8-%ED%95%9C%EA%B8%80-%EB%B0%9B%EC%B9%A8-%EC%94%B9%ED%9E%88%EB%8A%94-%ED%98%84%EC%83%81mac</guid>
            <pubDate>Tue, 16 Jan 2024 14:11:38 GMT</pubDate>
            <description><![CDATA[<p>옵시디언에서 한글로 메모를 작성하는 경우 받침이 씹히는 경우가 발생했다.</p>
<ul>
<li>예를 들어 &quot;상품명&quot;이라고 쓰면 &#39;푸&#39; 밑에 ㅁ 받침이 있고 이어서 &#39;명&#39; 타이핑할때 같은 자음 ㅁ을 쓰게 되면 &#39;상푸명&#39;이 되어버린다.</li>
</ul>
<p>아래 경로의 폴더를 삭제해주고 옵시디언을 재실행했더니 씹히는 현상이 사라졌다.</p>
<pre><code>~/Library/Application Support/obsidian/Cache/Cache_Data</code></pre><hr/>

<h1 id="출처">출처</h1>
<ul>
<li><a href="https://www.clien.net/service/board/cm_mac/17800149">https://www.clien.net/service/board/cm_mac/17800149</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2023년 회고]]></title>
            <link>https://velog.io/@minkyu__k/2023%EB%85%84-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@minkyu__k/2023%EB%85%84-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Fri, 05 Jan 2024 14:22:58 GMT</pubDate>
            <description><![CDATA[<p>2023년 상반기에는 스터디도 2개씩 참여하며 열심히 공부했던 거 같은데, 하반기에는 나태해진 거 같다.
개발 서적뿐만 아니라 다양한 장르의 책을 많이 읽는 것을 목표로 했는데 아래와 같이 나열해 보니 몇 권 되지 않는다.</p>
<p>아기가 돌 이후로 걷기 시작하면서 따라다니고 놀아주느라 체력이 조금 달린다.
앞으로 더 잘 놀아주려면 내 체력부터 키워야 할 거 같다. 운동 열심히 하자.</p>
<p>재직 중인 회사에서 근무한 지 1년 2개월 차가 되었다. 여러 가지 일을 많이 했지만 100% 적응했다고 말할 수 없을 거 같다. 아직도 놓치고 있는 것이 많은 거 같다. 집중력을 잃지 않도록 노력해야겠다.</p>
<p>2024년에는 내 자신만의 목표를 수립하고 이룰수 있도록 노력해야겠다.
글로 적어놓지 않으면 금방 잊어버리거나 망각하게 될 것 같다.</p>
<h1 id="개발-서적">개발 서적</h1>
<ul>
<li><a href="https://www.yes24.com/Product/Goods/108431347" target="_blank">도메인 주도 개발 시작하기</a></li>
<li><a href="http://www.yes24.com/Product/Goods/86542732" target="_blank"/>마이크로서비스 패턴</a></li>
<li><a href="http://www.yes24.com/Product/Goods/109366833" target="_blank">좋은 코드, 나쁜 코드</a></li>
<li><a href="http://www.yes24.com/Product/Goods/104084175" target="_blank">단위테스트</a></li>
<li><a href="http://www.yes24.com/Product/Goods/112927162" target="_blank">만들면서 배우는 헥사고날 아키텍처 설계와 구현</a></li>
<li><a href="http://www.yes24.com/Product/Goods/105138479" target="_blank">만들면서 배우는 클린 아키텍처</a></li>
<li><a href="https://www.yes24.com/Product/Goods/102819435" target="_blank">가상 면접 사례로 배우는 대규모 시스템 설계 기초</a></li>
</ul>
<h1 id="읽은-도서">읽은 도서</h1>
<ul>
<li><a href="https://www.yes24.com/Product/Goods/103286195" target="_blank">서울 자가에 대기업 다니는 김 부장 이야기 1</a></li>
<li><a href="https://www.yes24.com/Product/Goods/103286203" target="_blank">서울 자가에 대기업 다니는 김 부장 이야기 2</a></li>
<li><a href="https://www.yes24.com/Product/Goods/105000751" target="_blank">서울 자가에 대기업 다니는 김 부장 이야기 3</a></li>
<li><a href="http://www.yes24.com/Product/Goods/108887930" target="_blank">작별인사</a></li>
<li><a href="https://www.yes24.com/Product/Goods/97584812" target="_blank">개발자를 위한 글쓰기 가이드</a></li>
<li><a href="http://www.yes24.com/Product/Goods/64610518" target="_blank">골든아워1</a></li>
<li><a href="http://www.yes24.com/Product/Goods/111085946" target="_blank">하얼빈</a></li>
<li><a href="https://www.yes24.com/Product/Goods/110869493" target="_blank">미키7</a></li>
<li><a href="https://m.yes24.com/Goods/Detail/101908580" target="_blank">완전한 행복</a></li>
<li><a href="https://m.yes24.com/Goods/Detail/56935553" target="_blank">아르테미스</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2023년 11월, 12월 회고]]></title>
            <link>https://velog.io/@minkyu__k/2023%EB%85%84-11%EC%9B%94-12%EC%9B%94-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@minkyu__k/2023%EB%85%84-11%EC%9B%94-12%EC%9B%94-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 02 Jan 2024 12:38:58 GMT</pubDate>
            <description><![CDATA[<p>결국 미루고 미루다 보니 11월 회고를 안 쓰게 되었다.
그동안 회사에서 바쁘게 일하느라고 초과근무를 많이 하게 되었다.
이것은 핑계이고 게으름과 귀찮음 때문에 회고를 작성하지 않았다.</p>
<p>2024년 1월 2일 새해가 되어 2023년 11월과 12월 회고를 작성해 본다.</p>
<h1 id="회사">회사</h1>
<p>회사에 진행하던 프로젝트로 여러 가지 배우게 되는 시간이었던 거 같다.
카프카를 처음 사용해 봤고, Elasticsearch의 thread_pool에 대해 깊게 이해할 수 있었다.
그리고 시스템 아키텍처의 중요성에 대해 다시 한번 깨달았다.</p>
<h1 id="여행">여행</h1>
<p>바쁘게 일하고 12월 12일 서비스를 오픈할 수 있었다. 그리고 일본 교토로 2박 3일 짧은 해외여행을 다녀왔다.
날씨가 춥다는 정보를 보고 패딩을 챙겨갔었는데 우리나라보다 날씨가 따뜻해서 패딩은 캐리어에서 꺼내질 않았다.
아기(18개월)와 함께하는 여행이라 쉽지만은 않은 여행이었지만 즐거운 시간이었다.
평소 해가 지고 아기와 산책을 한 적이 없지만 왠지 여행지에서는 저녁 시간을 숙소에서만 흘려보내기엔 아쉬운 마음이 들어서 아기를 유모차에 태워 산책하러 다녔다. 그런데 어둡고 낯설어서 그런지 많이 칭얼대던 모습이 생각난다.
다시 한번 아기에게 많은 경험을 시켜줘야겠다는 생각이 들었다. (물론 잘 놀아주기도 해야 한다)</p>
<h1 id="읽은-도서">읽은 도서</h1>
<ul>
<li><a href="https://m.yes24.com/Goods/Detail/56935553" target="_blank">아르테미스</a><ul>
<li>마션의 저자 앤디 위어가 달에 사는 인간의 이야기를 다룬 소설이다. 마션 영화, 책을 너무 재밌게 봐서 앤디 위어가 쓴 책이라고 해서 무작정 읽어보았다.</li>
<li>책 내용 중에 관절이 안 좋은 사람이 달에 거주해서 관절에 무리가 가지 않는다는 내용이 나오는데, 달의 중력이 지구의 중력보다 약하기 때문에 이런 설정들이 흥미롭게 다가왔다. </li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2023년 10월 회고]]></title>
            <link>https://velog.io/@minkyu__k/2023%EB%85%84-10%EC%9B%94-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@minkyu__k/2023%EB%85%84-10%EC%9B%94-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 21 Nov 2023 00:43:16 GMT</pubDate>
            <description><![CDATA[<p>회사에서 12월 오픈 일정으로 바쁘게 진행하고 있는 일이 있다.
일이 바쁘다는 핑계로 너무나도 늦은 10월 회고를 씁니다.</p>
<p>목과 허리가 아픈데.. 아직도 정신을 못차렸는지 운동을 안하고 있다 😭
요즘 날씨가 추워져서 가족 모두가 감기에 걸려 오랫동안 기침, 콧물을 달고 살았다. 코로나 이후로 강력한 바이러스가 많이 생겨난 느낌이다. 아니면 면역력이 너무 낮아졌다던가...
아무튼 일도 일이지만 건강에 신경써야할거 같다.</p>
<h1 id="스터디">스터디</h1>
<p>보고 싶은 책은 구매해놨지만 못보고 있다.</p>
<ul>
<li><a href="https://www.yes24.com/Product/Goods/102819435" target="_blank">가상 면접 사례로 배우는 대규모 시스템 설계 기초</a> 팀 스터디가 마무리되었다.<ul>
<li>언젠가 개발이 필요한 아키텍처가 있다면 이 책을 참고하면서 설계해도 좋을거 같다.</li>
</ul>
</li>
</ul>
<h1 id="읽은-도서">읽은 도서</h1>
<ul>
<li><a href="https://m.yes24.com/Goods/Detail/101908580" target="_blank">완전한 행복</a><ul>
<li>자신의 행복을 위해 타인의 삶을 휘두르는 자가 만들어내는 비극, 일상의 악을 그리며 &#39;완전한 행복&#39;에 대해, &#39;행복의 책임&#39;에 대해 묻는다. 인간 심연의 깊은 어둠을 직시하는 이야기</li>
<li>실제 사건을 모티브했다고 한다. 그래서 읽는 내내 실제 사건이 떠올랐다. </li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2023년 9월 회고]]></title>
            <link>https://velog.io/@minkyu__k/2023%EB%85%84-9%EC%9B%94-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@minkyu__k/2023%EB%85%84-9%EC%9B%94-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 16 Oct 2023 04:04:06 GMT</pubDate>
            <description><![CDATA[<p>지난달처럼 또 늦은 회고를 쓰게 됐다.
이런저런 핑계로 미루고 미루다가 10월 중순이 되어서야 쓴다.</p>
<p>아기가 17개월이 되면서 저녁 9시~9시반이 되어야 잠을 잔다. (이전까지는 8시 전에 잠듦)
그 전까지 책도 읽어주고 몸으로 놀아준다. 그러면 체력이 바닥난다...
앞으로 아기 활동량이 더 많아질텐데 운동을 열심히 해서 체력을 기르고 잘 놀아줘야겠다는 생각이 든다.💪</p>
<h1 id="스터디">스터디</h1>
<p>육아와 회사 일이 바쁘다는 핑계로 개인적으로 책을 보고 있지는 않고 있다.</p>
<ul>
<li><a href="https://www.yes24.com/Product/Goods/102819435" target="_blank">가상 면접 사례로 배우는 대규모 시스템 설계 기초</a> 팀 스터디로 진행중이다.<ul>
<li>현재 11장까지 진행하였다.</li>
<li>이 책은 여러가지 서비스를 예제로 설명하면서 다양한 시스템 아키텍처를 보여준다.</li>
<li>좋은 내용이 많이 있는거 같다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2023년 8월 회고]]></title>
            <link>https://velog.io/@minkyu__k/2023%EB%85%84-8%EC%9B%94-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@minkyu__k/2023%EB%85%84-8%EC%9B%94-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 12 Sep 2023 13:25:04 GMT</pubDate>
            <description><![CDATA[<p>8월 회고인데 9월 중순이 되어서야 글을 작성하네요.</p>
<h1 id="일상">일상</h1>
<p>8월에는 고성, 평창으로 여름휴가를 다녀왔습니다.
휴가를 가기전에는 반복되는 일상에서 휴가만을 기다렸고, 기대하던 휴가였기에 맛있는 것도 많이 먹고 물놀이도 하고 즐겁고 알차게 보냈습니다.</p>
<p>다시 일상으로 돌아와서는 또 무엇을 기대하면서 보내야하나 했는데, 9월에는 추석연휴(임시휴무일, 개천절)가 있네요.</p>
<p>또 쉬는날을 기다리면서 열심히 일하고 공부해야겠습니다.</p>
<h1 id="스터디">스터디</h1>
<ul>
<li><a href="http://www.yes24.com/Product/Goods/105138479" target="_blank">만들면서 배우는 클린 아키텍처</a> 스터디는 마무리됐다.<ul>
<li>책은 다소 얇지만 내용이 알차게 구성된거 같다.</li>
<li>당장 실무에 헥사고날 아키텍처를 사용한다고 하면 참고해도 좋을거 같다.</li>
</ul>
</li>
<li><a href="https://www.yes24.com/Product/Goods/102819435" target="_blank">가상 면접 사례로 배우는 대규모 시스템 설계 기초</a> 팀 스터디로 진행중이다.<ul>
<li>책 제목과는 다르게 면접을 연습하는 목적은 아니다.</li>
<li>스프트웨어 엔지니어가 알고 있으면 좋을 아키텍처, 프로세스 등 좋은 내용이 많은거 같다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[git stash]]></title>
            <link>https://velog.io/@minkyu__k/git-stash</link>
            <guid>https://velog.io/@minkyu__k/git-stash</guid>
            <pubDate>Wed, 16 Aug 2023 01:30:32 GMT</pubDate>
            <description><![CDATA[<h1 id="저장">저장</h1>
<pre><code class="language-bash">git stash

git stash save {name}</code></pre>
<h1 id="조회">조회</h1>
<pre><code class="language-bash">git stash list</code></pre>
<pre><code class="language-bash">stash@{0}: On refactoring
stash@{1}: On modify template
...</code></pre>
<h1 id="꺼내기">꺼내기</h1>
<pre><code class="language-bash">git stash pop</code></pre>
<p>가장 최근에 저장된 stash를 리스트에서 삭제하면서 꺼낸다.</p>
<pre><code class="language-bash">git stash apply stash@{0}</code></pre>
<p>stash 이름을 지정해서 꺼내기 (삭제안됨)</p>
<h1 id="삭제">삭제</h1>
<pre><code class="language-bash">git stash drop stash@{0}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[2023년 7월 회고]]></title>
            <link>https://velog.io/@minkyu__k/2023%EB%85%84-7%EC%9B%94-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@minkyu__k/2023%EB%85%84-7%EC%9B%94-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 07 Aug 2023 13:20:54 GMT</pubDate>
            <description><![CDATA[<p>7월은 비가 너무 많이 내렸다. 🌧
비로 인해 전국에 안타까운 사건사고도 많았던 한 달이었다.</p>
<h1 id="회사-업무">회사 업무</h1>
<p>회사에서 내가 배포한 작업으로 인해 장애를 유발한 경우가 있었다.
운영 환경 배포전에 성능 테스트를 했음에도 불구하고 기존의 버전보다 다소 증가된 레이턴시를 유발하게 된것이 이유였다.
증가된 레이턴시로 인해 클라이언트로 데이터를 제공하는 API에서 간헐적 타임아웃이 발생했다.
배포한 작업을 롤백한 이후 레이턴시를 줄이기 위한 방법을 찾고 있다.</p>
<h1 id="스터디">스터디</h1>
<ul>
<li><p><a href="http://www.yes24.com/Product/Goods/105138479" target="_blank">만들면서 배우는 클린 아키텍처</a> 2인 스터디는 아직도 진행중이다.</p>
<ul>
<li>책이 분량이 많지 않지만 아키텍처에 대한 내용이 알차게 구성되어 있는거 같다.</li>
<li>헥사고날 아키텍처를 이해하기 쉽게 설명하고 있다.</li>
</ul>
</li>
<li><p><a href="http://www.yes24.com/Product/Goods/104084175" target="_blank">단위테스트</a> 스터디는 마무리되었다.</p>
<ul>
<li>이 책은 테스트를 어떻게 하면 더 잘 만들 수 있는지 알려주고 있다.</li>
<li>책에서 고전파, 런던파에 대한 내용이 나오는데 둘 중 한가지 방식만을 고집하기 보다는 상황에 맞는 적절한 테스트를 적용해야 할거 같다.</li>
<li>테스트를 잘 작성하려면 캡슐화, 추상화 등 구현 코드도 잘 작성되어야 한다.</li>
<li>이 책은 프로그래머에게 필독서인거 같다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[엘라스틱서치 bulk API]]></title>
            <link>https://velog.io/@minkyu__k/%EC%97%98%EB%9D%BC%EC%8A%A4%ED%8B%B1%EC%84%9C%EC%B9%98-bulk-API</link>
            <guid>https://velog.io/@minkyu__k/%EC%97%98%EB%9D%BC%EC%8A%A4%ED%8B%B1%EC%84%9C%EC%B9%98-bulk-API</guid>
            <pubDate>Mon, 07 Aug 2023 06:48:18 GMT</pubDate>
            <description><![CDATA[<h1 id="bulk-api">bulk API</h1>
<blockquote>
<p>bulk API는 여러 색인, 업데이트, 삭제 작업을 한 번의 요청에 담아서 보내는 API다.</p>
</blockquote>
<p>엘라스틱서치의 다른 API와 다르게 요청 본문을 <code>JSON</code>이 아니라 <code>NDJSON</code>(Newline Delimited JSON) 형태로 만들어서 보낸다.</p>
<ul>
<li>Content-Type 헤더도 <code>application/x-ndjson</code>을 사용해야 한다.</li>
<li>가장 마지막 줄은 줄바꿈 문자 <code>\n</code>으로 끝나야 한다.</li>
</ul>
<pre><code class="language-json">POST _bulk
{ &quot;index&quot; : { &quot;_index&quot; : &quot;test&quot;, &quot;_id&quot; : &quot;1&quot; } }
{ &quot;field1&quot; : &quot;value1&quot; }
{ &quot;delete&quot; : { &quot;_index&quot; : &quot;test&quot;, &quot;_id&quot; : &quot;2&quot; } }
{ &quot;create&quot; : { &quot;_index&quot; : &quot;test&quot;, &quot;_id&quot; : &quot;3&quot; } }
{ &quot;field1&quot; : &quot;value3&quot; }
{ &quot;update&quot; : {&quot;_id&quot; : &quot;1&quot;, &quot;_index&quot; : &quot;test&quot;} }
{ &quot;doc&quot; : {&quot;field2&quot; : &quot;value2&quot;} }</code></pre>
<h1 id="bulk-api의-작업-순서">bulk API의 작업 순서</h1>
<blockquote>
<p>bulk API에 기술된 작업은 반드시 그 순서대로 수행된다는 보장이 없다.</p>
</blockquote>
<ul>
<li>조정 역할을 하는 노드가 요청을 수신하면 각 요청의 내용을 보고 적절한 주 샤드로 요청을 넘겨준다. <ul>
<li>여러 개의 주 샤드에 넘어간 각 요청은 각자 독자적으로 수행된다. </li>
<li>따라서 요청 간 순서는 보장되지 않는다.</li>
</ul>
</li>
</ul>
<ul>
<li>그러나 완전히 동일한 인덱스, _id, 라우팅 조합을 가진 요청은 반드시 동일한 주 샤드로 넘어간다. <ul>
<li>따라서 한 bulk API 내에서 이 조합이 같은 요청, 즉 동일한 문서에 대한 요청은 bulk API에 기술된 순서대로 동작한다.</li>
</ul>
</li>
</ul>
<h1 id="bulk-api의-성능">bulk API의 성능</h1>
<blockquote>
<p>네트워크를 통해 요청을 여러 번 반복해서 호출해야 한다면 이를 묶어 한꺼번에 전송하는 것이 일반적으로 성능상 이득이다.</p>
</blockquote>
<ul>
<li>bulk API 요청 한 번에 몇 개의 요청을 모아서 보내는 것이 성능상 적절한지는 정해져 있지 않다. <ul>
<li>각 요청의 크기나 데이터 특성 등에 따라 달라지기 때문이다.</li>
</ul>
</li>
</ul>
<ul>
<li>그러므로 성능 이슈가 있는 경우 수치를 조정해 가며 실험해 보는 것이 좋다.</li>
<li>또한 HTTP 요청을 청크(chunked)로 보내는 것은 성능을 떨어지게 만들기 때문에 피해야 한다.</li>
</ul>
<hr>

<h1 id="참조">참조</h1>
<ul>
<li><a href="https://www.yes24.com/Product/Goods/119719070" target="_blank">엘라스틱서치 바이블</a>. 4장 데이터 다루기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[엘라스틱서치의 데이터 분산 처리 과정]]></title>
            <link>https://velog.io/@minkyu__k/%EC%97%98%EB%9D%BC%EC%8A%A4%ED%8B%B1%EC%84%9C%EC%B9%98%EC%9D%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%82%B0-%EC%B2%98%EB%A6%AC-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@minkyu__k/%EC%97%98%EB%9D%BC%EC%8A%A4%ED%8B%B1%EC%84%9C%EC%B9%98%EC%9D%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%82%B0-%EC%B2%98%EB%A6%AC-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Thu, 27 Jul 2023 13:25:40 GMT</pubDate>
            <description><![CDATA[<h1 id="쓰기-작업-시-엘라스틱서치-동작과-동시성-제어">쓰기 작업 시 엘라스틱서치 동작과 동시성 제어</h1>
<p>쓰기 작업은 3단계로 수행된다.</p>
<ul>
<li>조정 단계(Coordination Stage)</li>
<li>주 샤드 단계(Primary Stage)</li>
<li>복제 단계(Replica Stage)</li>
</ul>
<h3 id="조정-단계">조정 단계</h3>
<ol>
<li>클라이언트로부터 쓰기 작업 요청을 받는다.</li>
<li>라우팅으로 적절한 주 샤드를 찾아 요청을 넘겨준다.</li>
<li>주 샤드 단계 작업을 마치면 최초 요청을 수신했던 조정 노드에게 주 샤드 작업 결과 응답을 넘겨준다.</li>
<li>클라이언트에게 응답을 돌려준다.</li>
</ol>
<h3 id="주-샤드-단계">주 샤드 단계</h3>
<p>주 샤드가 요청을 넘겨 받은 이후 수행하는 작업들을 <code>주 샤드 단계</code>라고 한다.</p>
<ol>
<li>작업 요청을 검증한다.</li>
<li>주 샤드는 로컬에서 쓰기 작업을 수행하고 완료되면 <code>in-sync</code> 복제본에 <strong>병렬적</strong>으로 요청을 넘긴다.</li>
<li>모든 복제본이 작업을 성공적으로 수행하고 주 샤드에 응답을 돌려준다.</li>
<li>주 샤드가 작업 완료 응답을 보낸다.<blockquote>
<p>in-sync 복제본: 마스터 노드가 관리하는 복제받을 샤드 목록</p>
</blockquote>
</li>
</ol>
<h3 id="복제-단계">복제 단계</h3>
<p>각 <code>in-sync</code> 복제본 샤드는 주 샤드에게 받은 요청을 로컬에서 수행하고 주 샤드에게 작업이 완료됐음을 보고한다.</p>
<blockquote>
<p>조정 단계, 주 샤드 단계, 복제 단계는 이 순서대로 실행되지만 종료는 역순이다.</p>
</blockquote>
<br/>
<br/>


<h2 id="낙관적-동시성-제어optimistic-concurrency-control">낙관적 동시성 제어(Optimistic Concurrency Control)</h2>
<pre><code>한 문서의 views 필드 값을 1로 색인했다면 잠시 후 복제본에도 이 내용이 적용된다.
그런데 이 변경 내용이 복제본 샤드에 완전히 적용되기 전에 다른 클라이언트로부터 주 샤드에 같은 문서의 views 필드 값을 2로 색인하는 변경이 발생했다고 가정해 보자.</code></pre><ul>
<li>분산시스템 특성상 두 요청 중 어떤 요청이 먼저 복제본 샤드로 들어올지는 보장할 수 없다.<ul>
<li>메시지 순서의 역전이 일어날 수 있다</li>
</ul>
</li>
<li>views를 2로 색인하는 요청이 먼저 들어온 뒤에 views를 1로 색인하는 요청이 나중에 들어온다면 복제본에서는 최종값이 1로 역전될 수도 있다.</li>
<li>이러한 현상을 막기 위해 <code>_seq_no</code>가 존재한다.</li>
</ul>
<h3 id="_seq_no">_seq_no</h3>
<p><code>_seq_no</code>는 각 주 샤드마다 들고 있는 시퀀스 숫자값이며 매 작업마다 1씩 증가한다.</p>
<ul>
<li>엘라스틱서치는 문서를 색인할 때 이 값을 함께 저장한다.</li>
<li>문서가 색인된 상태에서 <code>_id</code> 값은 같은데 <code>_seq_no</code> 값은 더 작은 색인 요청을 받는다면 이전 버전의 요청을 늦게 들어온 것으로 판단하고 작업을 수행하지 않는다.</li>
</ul>
<h3 id="_primary_term">_primary_term</h3>
<p>주 샤드를 들고 있는 노드에 문제가 발생하여 해당 노드가 클러스터에서 빠진다면 엘라스틱서치는 <strong>복제본 샤드 중 하나를 주 샤드로 지정한다.</strong></p>
<ul>
<li><code>_primary_term</code> 이라는 값으로 새로 임명된 주 샤드를 구분한다.</li>
<li>주 샤드가 새로 지정될 때 1씩 증가한다.</li>
</ul>
<pre><code class="language-json">PUT concurrency_test
{
    &quot;settings&quot;: {
          &quot;number_of_shards&quot;: 2
    }
}</code></pre>
<pre><code class="language-json">PUT concurrency_test/_doc/1
{
      &quot;views&quot;: 1
}</code></pre>
<pre><code class="language-json">{
    &quot;_index&quot;: &quot;concurrency_test&quot;,
    &quot;_type&quot;: &quot;_doc&quot;,
    &quot;_id&quot;: &quot;1&quot;,
    &quot;_version&quot;: 1,
    &quot;result&quot;: &quot;created&quot;,
    // ...
    &quot;_seq_no&quot;: 0,
    &quot;_primary_term&quot;: 1
}</code></pre>
<p>같은 <code>_id</code>로 문서를 색인하면 <code>_seq_no</code>가 올라간다.</p>
<pre><code class="language-json">PUT concurrency_test/_doc/1
{
      &quot;views&quot;: 2
}</code></pre>
<pre><code class="language-json">{
    &quot;_index&quot;: &quot;concurrency_test&quot;,
    &quot;_type&quot;: &quot;_doc&quot;,
    &quot;_id&quot;: &quot;1&quot;,
    &quot;_version&quot;: 2,
    &quot;result&quot;: &quot;updated&quot;,
    // ...
    &quot;_seq_no&quot;: 1,
    &quot;_primary_term&quot;: 1
}</code></pre>
<p><code>_seq_no</code>는 주 샤드마다 따로 매긴다.</p>
<pre><code class="language-json">PUT concurrency_test/_doc/A
{
      &quot;views&quot;: 0
}</code></pre>
<pre><code class="language-json">{
      &quot;_index&quot;: &quot;concurrency_test&quot;,
      &quot;_type&quot;: &quot;_doc&quot;,
    &quot;_id&quot;: &quot;A&quot;,
      &quot;_version&quot;: 1,
      &quot;result&quot;: &quot;created&quot;,
      // ...
      &quot;_seq_no&quot;: 0,
      &quot;_primary_term&quot;: 1
}</code></pre>
<ul>
<li>문서에 색인할 때 <code>if_seq_no</code>와 <code>if_primary_term</code>에 각각 <code>_seq_no</code>와 <code>_primary_term</code>을 넣을 수 있다. </li>
<li>이 경우 문서의 <code>_seq_no</code>와 <code>_primary_term</code>이 지정한 값과 같을 때만 색인 작업이 수행된다.</li>
<li>클라이언트가 자신이 데이터를 확인했을 때와 완전히 동일한 상태인 경우에만 작업을 수행하고 싶을 때 이용한다.</li>
</ul>
<pre><code class="language-json">PUT concurrency_test/_doc/1?if_primary_term=1&amp;if_seq_no=1
{
    &quot;views&quot;: 0
}</code></pre>
<h2 id="버전">버전</h2>
<ul>
<li><code>_version</code>은 <code>_seq_no</code>와 <code>_primary_term</code>처럼 동시성을 제어하기 위한 메타데이터로 모든 문서마다 붙는다.</li>
<li><code>_version</code>은 0이상 long 범위 이내의 정수여야 한다.<ul>
<li>1부터 시작해서 업데이트나 삭제 작업을 수행할 때마다 1씩 증가한다.</li>
</ul>
</li>
<li><code>_seq_no</code>, <code>_primary_term</code>과 다른 점은 클라이언트가 문서의 <code>_version</code> 값을 직접 지정할 수 있다.<ul>
<li>현재의 버전값보다 낮은 값으로 색인할 수 없다.</li>
<li><code>version_type</code>을 <code>external(external_gt)</code>이나 <code>external_gte</code>로 설정하면 클라이언트가 직접 <code>_version</code>을 지정할 수 있다.<ul>
<li>default <code>version_type</code> 은 <code>internal</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>다른 스토리지에서 저장된 데이터의 버전을 따로 관리하고 있고 그 데이터를 엘라스틱서치로 받아 와서 2차 스토리지로 동기화하여 사용하는 경우 활용하기 좋다.</p>
</blockquote>
<br/>
<br/>

<h1 id="읽기-작업-시-엘라스틱서치-동작">읽기 작업 시 엘라스틱서치 동작</h1>
<ol>
<li>조정 노드(<code>Coordination Node</code>)는 클라이언트로부터 읽기 작업을 요청받는다.</li>
<li>조정 노드는 라우팅을 통해 적절한 샤드를 찾아 요청을 넘긴다.<ul>
<li>쓰기 작업과 다르게 주 샤드가 아니라 복제본 샤드로 요청이 넘어갈 수 있다.</li>
</ul>
</li>
<li>요청을 넘겨받은 각 샤드는 <em>로컬에서 읽기 작업을 수행한 뒤 그 결과를 조정 노드로 돌려준다</em>.</li>
<li>조정 노드는 이 결과를 모아서 클라이언트에게 응답한다.</li>
</ol>
<pre><code>🚨 주 샤드에 색인이 완료됐지만 특정 복제본 샤드에는 반영이 완료되지 않은 상태의 데이터를 읽을 수도 있다.</code></pre><h2 id="체크포인트와-샤드-복구-과정">체크포인트와 샤드 복구 과정</h2>
<p>만약 문제가 생겨서 특정 노드가 재기동되었다면 그 노드가 들고 있던 샤드에 복구 작업이 진행된다.</p>
<ul>
<li>복구중인 샤드가 현재 주 샤드의 내용과 일치하는지를 파악할 필요가 있다.</li>
<li>주 샤드가 색인 작업이 있었다면 그 내용을 복제본 샤드에도 반영해야 한다.</li>
</ul>
<p><code>_primary_term</code>과 <code>_seq_no</code>를 조합하면 샤드와 샤드 사이에 어떤 반영 차이점이 있는지를 알 수 있다.</p>
<p>각 샤드는 로컬에 작업을 수행하고나면 몇 번 작업까지 순차적으로 수행을 완료했는지를 <code>✅ 로컬 체크포인트</code>로 기록한다.</p>
<pre><code>ex) _seq_no가 각각 1, 2, 3, 5, 7인 작업을 수행한 샤드는 로컬 체크포인트값을 3으로 업데이트한다.
  - 3번 작업까지는 빠짐없이 반영됐다는 뜻이다.
  - 복제본 샤드는 로컬 체크포인트가 업데이트되면 이를 주 샤드에 보고한다.
  - 이후에 이 복제본 샤드가 4번 작업을 수신하여 반영을 완료하면 로컬 체크포인트를 5로 업데이트한다.</code></pre><p>주 샤드는 각 복제본 샤드로부터 받은 <code>로컬 체크포인트</code>를 비교하여 가장 낮은 값을 <code>✅ 글로벌 체크포인트</code> 값으로 기록한다.</p>
<ul>
<li>해당 작업까지는 그 내용이 모든 샤드에 반영됐다는 것을 나타낸다.</li>
</ul>
<p>글로벌 체크포인트가 업데이트되면 다음 색인 작업 시 그 내용을 주 샤드가 복제본 샤드로 전달한다.</p>
<p>문제가 발생해 샤드를 복구해야 할 경우가 생기면 샤드 간에 <code>글로벌 체크포인트</code>를 비교한다.</p>
<ul>
<li>주 샤드와 복제본 샤드의 <code>글로벌 체크포인트</code>가 같다면 이 샤드는 추가 복구 작업이 필요 없다.</li>
<li>글로벌 체크포인트가 차이 난다면 두 샤드 간 체크포인트를 확인해서 필요한 작업만 재처리하여 복구한다.<ul>
<li>세그먼트 파일을 통째로 전송하는 것보다 효율적이다.</li>
</ul>
</li>
</ul>
<h3 id="샤드-이력-보존shard-history-retention-leases">샤드 이력 보존(Shard History Retention Leases)</h3>
<p>엘라스틱서치는 논리적 삭제를 도입했다. 
최근 삭제한 문서를 일정 기간 보존해 두고 작업 재처리에 활용한다.</p>
<blockquote>
<p>재처리할 내용을 추적하는 메커니즘
루씬의 세그먼트가 병합되는 도중에도 샤드 이력은 지정한 기간 동안은 보존된다. (default: 12시간)</p>
</blockquote>
<pre><code class="language-json">index.soft_deletes.retention_lease.period</code></pre>
<hr>

<h1 id="참조">참조</h1>
<ul>
<li><a href="https://www.yes24.com/Product/Goods/119719070" target="_blank">엘라스틱서치 바이블</a>. 8장 엘라스틱서치의 내부 동작 상세</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[cron 스케줄러]]></title>
            <link>https://velog.io/@minkyu__k/cron-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%9F%AC</link>
            <guid>https://velog.io/@minkyu__k/cron-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%9F%AC</guid>
            <pubDate>Mon, 24 Jul 2023 04:44:47 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>0 3 * * 2-5</p>
</blockquote>
<p><code>cron</code>은 주기적으로 반복적인 작업을 스케줄링하기 위해 사용되는 리눅스/유닉스 기반 시스템에서 흔히 사용되는 도구입니다. 주어진 표기법을 해석하면 다음과 같습니다</p>
<pre><code class="language-bash">분(0-59) 시(0-23) 일(1-31) 월(1-12) 요일(0-7, 0과 7은 일요일)</code></pre>
<p>따라서, 0 3 * * 2-5의 의미는 다음과 같습니다:</p>
<ul>
<li>분: 0</li>
<li>시: 3시 (24시간 형식)</li>
<li>일: 모든 날 (1-31)</li>
<li>월: 모든 달 (1-12)</li>
<li>요일: 화요일(2)부터 금요일(5)까지 (주중)</li>
</ul>
<p>이 스케줄은 매주 화요일(2)부터 금요일(5)까지 총 4번 실행됩니다. 매주 월요일(1)과 주말인 토요일(6)과 일요일(7)에는 실행되지 않습니다. 실행 시간은 항상 오전 3시(3:00 AM)입니다.</p>
<p>🤔 스케줄러 볼때마다 헷갈려서 구글링해서 찾아보곤 하는데 GhatGPT에게 물어보니 자세하게 알려주네요.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[얀테의 법칙]]></title>
            <link>https://velog.io/@minkyu__k/%EC%96%80%ED%85%8C%EC%9D%98-%EB%B2%95%EC%B9%99</link>
            <guid>https://velog.io/@minkyu__k/%EC%96%80%ED%85%8C%EC%9D%98-%EB%B2%95%EC%B9%99</guid>
            <pubDate>Thu, 20 Jul 2023 13:22:51 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>스칸디나비아 반도 국가(노르웨이, 덴마크, 스웨덴, 핀란드)에 존재하는 생활 규범. </p>
</blockquote>
<p>한국의 &quot;연장자에게 높임말을 사용해야 한다.&quot;와 비슷한 수준으로 생활 기저에 깔리는 열 가지  규칙으로, 요약하자면 &#39;겸손의 법칙&#39; 정도로 표현할 수 있다.</p>
<blockquote>
</blockquote>
<p>이는 북유럽의 평등주의적 성격을 잘 나타내는 예시 중 하나이며, 간섭을 거부하는 개인주의를 위하여 우월감의 표출을 부정적으로 보는 사회적 태도를 가리킨다.</p>
<h2 id="1-당신이-특별하다고-생각하지-마라">1. 당신이 특별하다고 생각하지 마라.</h2>
<h2 id="2-당신이-남들만큼-좋은-사람이라고-생각하지-마라">2. 당신이 남들만큼 좋은 사람이라고 생각하지 마라.</h2>
<h2 id="3-당신이-남들보다-똑똑하다고-생각하지-마라">3. 당신이 남들보다 똑똑하다고 생각하지 마라.</h2>
<h2 id="4-당신이-남들보다-낫다고-생각하지-마라">4. 당신이 남들보다 낫다고 생각하지 마라.</h2>
<h2 id="5-당신이-남들보다-많이-안다고-생각하지-마라">5. 당신이 남들보다 많이 안다고 생각하지 마라.</h2>
<h2 id="6-당신이-남들보다-중요하다고-생각하지-마라">6. 당신이 남들보다 중요하다고 생각하지 마라.</h2>
<h2 id="7-당신이-모든-일을-잘한다고-생각하지-마라">7. 당신이 모든 일을 잘한다고 생각하지 마라.</h2>
<h2 id="8-남들을-비웃지-마라">8. 남들을 비웃지 마라.</h2>
<h2 id="9-누군가-당신을-걱정하리라-생각하지-마라">9. 누군가 당신을 걱정하리라 생각하지 마라.</h2>
<h2 id="10-남들에게-무엇이든-가르칠-수-있으리라-생각하지-마라">10. 남들에게 무엇이든 가르칠 수 있으리라 생각하지 마라</h2>
<hr> 

<h1 id="출처">출처</h1>
<ul>
<li><a href="https://namu.wiki/w/%EC%96%80%ED%85%8C%EC%9D%98%20%EB%B2%95%EC%B9%99" target="_blank">얀테의 법칙</a> - 나무위키</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[좋은 단위 테스트의 4대 요소]]></title>
            <link>https://velog.io/@minkyu__k/%EC%A2%8B%EC%9D%80-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%9D%98-4%EB%8C%80-%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@minkyu__k/%EC%A2%8B%EC%9D%80-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%9D%98-4%EB%8C%80-%EC%9A%94%EC%86%8C</guid>
            <pubDate>Tue, 18 Jul 2023 14:10:08 GMT</pubDate>
            <description><![CDATA[<ul>
<li>회귀 방지</li>
<li>리팩터링 내성</li>
<li>빠른 피드백</li>
<li>유지 보수성</li>
</ul>
<h1 id="회귀-방지">회귀 방지</h1>
<ul>
<li>회귀는 소프트웨어 버그다.</li>
<li>코드를 수정한 후 기능이 의도한 대로 작동하지 않는 경우다.</li>
<li>코드베이스가 커질수록 잠재적인 버그에 더 많이 노출된다.<ul>
<li>그래서 회귀에 대해 효과적인 보호를 개발하는 것이 중요하다.</li>
</ul>
</li>
</ul>
<p>회귀 방지 지표에 대한 고려 사항</p>
<ul>
<li>테스트 중에 실행되는 코드의 양</li>
<li>코드 복잡도</li>
<li>코드의 도메인 유의성</li>
<li>라이브러리, 프레임워크, 외부 시스템을 테스트 범주에 포함시켜서 의존성에 대해 검증이 올바른지 확인해야 한다.</li>
<li>단순한 코드를 테스트하는 것은 가치가 거의 없다.<pre><code class="language-java">public class User {
  public string Name { get; set; }
}</code></pre>
</li>
</ul>
<blockquote>
<p>회귀 방지 지표를 극대화하려면 테스트가 가능한 한 많은 코드를 실행하는 것을 목표로 해야 한다.</p>
</blockquote>
<h1 id="리팩터링-내성">리팩터링 내성</h1>
<blockquote>
<p>리팩터링은 식별할 수 있는 동작을 수정하지 않고 기존 코드를 변경하는 것을 의미한다.
의도는 코드의 비기능적 특징을 개선하는 것으로 가독성을 높이고 복잡도를 낮추는 것이다.</p>
</blockquote>
<ul>
<li><p>메서드 이름 변경</p>
</li>
<li><p>코드 조각을 새로운 클래스로 추출</p>
</li>
<li><p>거짓 양성(false positive)은 허위 경보다. 즉, 테스트가 실패했다고 나타내지만 그 기능은 의도한대로 작동한다.</p>
<ul>
<li>거짓 양성을 테스트 스위트에 치명적인 영향을 줄 수 있다.</li>
<li>실제로 기능이 의도한 대로 작동하지만 테스트는 실패를 나타내는 결과다.</li>
</ul>
</li>
<li><p>거짓 양성은 테스트 대상 시스템의 내부 구현 세부 사항과 테스트 간의 강결합의 결과다. 결합도를 낮추려면 테스트는 SUT가 수행한 단계 아니라 SUT가 만든 <code>최종 결과(관련된 절차가 아니라 식별할 수 있는 동작)</code>를 검증해야 한다.</p>
</li>
</ul>
<pre><code class="language-java">public class Message
{
    public string Header { get; set; }
    public string Body { get; set; }
    public string Footer { get; set; }
}

public interface IRenderer
{
    string Render(Message message);
}

public class MessageRenderer : IRenderer
{
    public IReadOnlyList&lt;IRenderer&gt; SubRenderers { get; }

    public MessageRenderer()
    {
        SubRenderers = new List&lt;IRenderer&gt;
        {
            new HeaderRenderer(),
            new BodyRenderer(),
            new FooterRenderer()
        };
    }

    public string Render(Message message)
    {
        return SubRenderers
            .Select(x =&gt; x.Render(message))
            .Aggregate(&quot;&quot;, (str1, str2) =&gt; str1 + str2);
    }
}

public class FooterRenderer : IRenderer
{
    public string Render(Message message)
    {
        return $&quot;&lt;i&gt;{message.Footer}&lt;/i&gt;&quot;;
    }
}

public class BodyRenderer : IRenderer
{
    public string Render(Message message)
    {
        return $&quot;&lt;b&gt;{message.Body}&lt;/b&gt;&quot;;
    }
}

public class HeaderRenderer : IRenderer
{
    public string Render(Message message)
    {
        return $&quot;&lt;h1&gt;{message.Header}&lt;/h1&gt;&quot;;
    }
}</code></pre>
<ul>
<li>MessageRenderer 클래스에 여러 하위 렌더링 클래스가 있고, 메시지의 일부에 대한 실제 작업을 위임한다.</li>
<li>결과를 HTML 문서로 결합한다.</li>
<li>하위 렌더링 클래스는 원본 문자열을 HTML 태그로 조정한다.</li>
</ul>
<pre><code class="language-java">public void MessageRenderer_uses_correct_sub_renderers()
{
    var sut = new MessageRenderer();

    IReadOnlyList&lt;IRenderer&gt; renderers = sut.SubRenderers;

    Assert.Equal(3, renderers.Count);
    Assert.IsAssignableFrom&lt;HeaderRenderer&gt;(renderers[0]);
    Assert.IsAssignableFrom&lt;BodyRenderer&gt;(renderers[1]);
    Assert.IsAssignableFrom&lt;FooterRenderer&gt;(renderers[2]);
}</code></pre>
<ul>
<li>이 테스트는 하위 렌더링 클래스가 예상하는 모든 유형이고 올바른 순서로 나타나는지 여부를 확인한다.</li>
<li>SUT가 생성한 결과가 아니라 SUT의 구현 세부 사항과 결합했다.</li>
</ul>
<pre><code class="language-java">public void Rendering_a_message()
{
    var sut = new MessageRenderer();
    var message = new Message
    {
        Header = &quot;h&quot;,
        Body = &quot;b&quot;,
        Footer = &quot;f&quot;
    };

    string html = sut.Render(message);

    Assert.Equal(&quot;&lt;h1&gt;h&lt;/h1&gt;&lt;b&gt;b&lt;/b&gt;&lt;i&gt;f&lt;/i&gt;&quot;, html);
}</code></pre>
<ul>
<li>이 테스트는 MessageRenderer를 블랙박스로 취급하고 식별할 수 있는 동작에만 신경 쓴다.<ul>
<li>리팩터링 내성이 늘었다.</li>
<li>HTML 출력을 똑같이 지키는 한, SUT의 변경 사항은 테스트에 영향을 미치지 않는다.</li>
</ul>
</li>
</ul>
<h1 id="빠른-피드백">빠른 피드백</h1>
<ul>
<li>빠른 피드백은 단위 테스트의 필수 속성이다.</li>
<li>테스트 속도가 빠를수록 테스트 스위트에서 더 많은 테스트를 수행할 수 있고 더 자주 실행할 수 있다.</li>
<li>테스트가 빠르게 실행되면 코드에 결함이 생기자마자 버그에 대해 경고하기 시작할 정도로 피드백 루프를 대폭 줄여서, 버그를 수정하는 비용을 거의 0까지 줄일 수 있다.</li>
</ul>
<h1 id="유지-보수성">유지 보수성</h1>
<ul>
<li>테스트가 얼마나 이해하기 어려운가<ul>
<li>테스트 크기와 관련이 있다.</li>
<li>테스트는 코드 라인이 적을수록 읽기 쉽다.</li>
<li>테스트 코드의 품질은 제품 코드만큼이나 중요하다.</li>
<li>테스트를 작성할 때 절차를 생략하지 말라.</li>
<li>테스트 코드를 &#39;일급 시민(first-class citizen)&#39;으로 취급하라.</li>
</ul>
</li>
<li>테스트가 얼마나 실행하기 어려운가<ul>
<li>테스트가 프로세스 외부 종석성으로 작동하면 데이터베이스 서버를 재부팅하고 네트워크 연결 문제를 해결하는 등 의존성을 상시 운영하는 데 시간을 들여야 한다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[단위 테스트 구조]]></title>
            <link>https://velog.io/@minkyu__k/%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@minkyu__k/%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Fri, 14 Jul 2023 12:00:00 GMT</pubDate>
            <description><![CDATA[<h1 id="단위-테스트를-구성하는-방법">단위 테스트를 구성하는 방법</h1>
<h2 id="aaa-패턴-사용">AAA 패턴 사용</h2>
<ul>
<li>준비(Arrange)</li>
<li>실행(Act)</li>
<li>검증(Assert)</li>
</ul>
<pre><code class="language-java">public class CalculatorTests
{
    [Fact]
    public void Sum_of_two_numbers()
    {
        // Arrange
        double first = 10;
        double second = 20;
        var calculator = new Calculator();

        // Act
        double result = calculator.Sum(first, second);

        // Assert
        Assert.Equal(30, result);
    }
}</code></pre>
<h3 id="given-when-then-패턴">Given-When-Then 패턴</h3>
<ul>
<li>AAA 패턴과 차이는 없다.</li>
<li>프로그래머가 아닌 사람에게 Given-When-Then 구조가 더 읽기 쉽다.</li>
</ul>
<h2 id="여러-개의-준비-실행-검증-구절-피하기">여러 개의 준비, 실행, 검증 구절 피하기</h2>
<p><img src="https://velog.velcdn.com/images/minkyu__k/post/eef20753-bbe3-4585-aad0-a073abe598e6/image.png" alt=""></p>
<ul>
<li>여러 개의 준비, 실행, 검증 구절은 테스트가 너무 많은 것을 한 번에 검증한다는 의미다.</li>
<li>이러한 테스트는 여러 테스트로 나눠서 해결한다.</li>
</ul>
<blockquote>
<p>통합 테스트에서는 실행 구절을 여러 개 두는 것이 괜찮을 때도 있다.</p>
</blockquote>
<h2 id="테스트-내-if-문-피하기">테스트 내 if 문 피하기</h2>
<ul>
<li>안티 패턴이다.</li>
<li>단위 테스트든 통합 테스트든 테스트는 분기가 없는 간단한 일련의 단계여야 한다.</li>
</ul>
<h2 id="각-구절은-얼마나-커야-하는가">각 구절은 얼마나 커야 하는가?</h2>
<ul>
<li>일반적으로 준비 구절이 세 구절 중 가장 크며, 실행과 검증을 합친 만큼 클 수도 있다.</li>
<li>같은 테스트 클래스 내 비공개 메서드 또는 별도의 팩토리 클래스로 도출하는 것이 좋다.</li>
<li>준비 구절에서 코드 재사용에 도움이 되는 두 가지 패턴<ul>
<li>오브젝트 마더(Object Mother)<ul>
<li>기본값을 사용하면 인수를 선택적으로 지정할 수 있으므로 테스트를 단축할 수 있다.<pre><code class="language-java">private User CreateUser(
string email = &quot;user@mycorp.com&quot;,
UserType type = UserType.Employee,
bool isEmailConirmed = false)
{
/* ... */
}</code></pre>
</li>
</ul>
</li>
<li>테스트 데이터 빌더(Test Data Builder)<ul>
<li>오브젝트 마더와 유사하게 작동하지만 일반 메서드 대신 플루언트(<code>Fluent</code>) 인터페이스를 제공한다.<pre><code class="language-java">User user = new UserBuilder()
.WithEmail(&quot;user@mycorp.com&quot;)
.WithType(UserType.Employee)
.Build();</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="실행-구절이-한-줄-이상인-경우를-경계하라">실행 구절이 한 줄 이상인 경우를 경계하라</h3>
<ul>
<li>실행 구절은 보통 코드 한 줄이다.</li>
<li>실행 구절이 두 줄 이상인 경우 SUT(<code>System Under Test</code>)의 공개 API에 문제가 있을 수 있다.</li>
</ul>
<pre><code class="language-java">public void Purchase_succeeds_when_enough_inventory()
{
    var store = new Store();
    store.AddInventory(Product.Shampoo, 10);
    var customer = new Customer();

    bool success = customer.Purchase(store, Product.Shampoo, 5);
    store.RemoveInventory(success, Product.Shampoo, 5);

    Assert.True(success);
    Assert.Equal(5, store.GetInventory(Product.Shampoo));
}</code></pre>
<ul>
<li>첫 번째 줄에서는 고객이 상점에서 샴푸 다섯 개를 얻으려고 한다.</li>
<li>두 번째 줄에서는 재고가 감소되는데, Purchase() 호출이 성공을 반환하는 경우에만 수행된다.</li>
</ul>
<blockquote>
<p>실행 구절을 한 줄로 하는 지침은 비즈니스 로직을 포함하는 대부분 코드에 적용되지만, 유틸리티나 인프라 코드는 덜 적용된다.</p>
</blockquote>
<h2 id="검증-구절에는-검증문이-얼마나-있어야-하는가">검증 구절에는 검증문이 얼마나 있어야 하는가</h2>
<ul>
<li>단위 테스트의 단위는 동작의 단위이다.</li>
<li>단일 동작 단위는 여러 결과를 낼 수 있으며, 하나의 테스트로 그 모든 결과를 평가하는 것이 좋다.</li>
<li>SUT에서 반환된 객체 내에서 모든 속성을 검증하는 대신 객체 클래스 내에 적절한 <code>동등 멤버(equality member)</code>를 정의하는 것이 좋다.<ul>
<li>단일 검증문으로 객체를 기대값과 비교할 수 있다.</li>
</ul>
</li>
</ul>
<h2 id="종료-단계는-어떤가">종료 단계는 어떤가</h2>
<ul>
<li>준비, 실행, 검증 이후의 네 번째 구절로 <code>종료 구절</code>을 따로 구분하기도 한다.<ul>
<li>테스트에 의해 작성된 파일을 지우거나 데이터베이스 연결을 종료하고자 이 구절을 사용할 수 있다.</li>
</ul>
</li>
<li>종료는 일반적으로 <code>별도의 메서드로 도출돼</code>, 클래스 내 모든 테스트에서 재사용된다. (tearDown)</li>
</ul>
<h2 id="테스트-대상-시스템-구별하기">테스트 대상 시스템 구별하기</h2>
<ul>
<li>SUT는 테스트에서 중요한 역할을 하는데, 애플리케이션에서 호출하고자 하는 동작에 대한 진입점을 제공한다.<ul>
<li>진입점은 오직 하나만 존재한다.</li>
</ul>
</li>
<li>SUT를 의존성과 구분하는 것이 중요하다.</li>
</ul>
<h2 id="준비-실행-검증-주석-제거하기">준비, 실행, 검증 주석 제거하기</h2>
<ul>
<li>AAA 패턴을 따르고 준비 및 검증 구절에 빈 줄을 추가하지 않아도 되는 테스트라면 구절 주석들을 제거하라.</li>
<li>그렇지 않으면 구절 주석을 유지하라.</li>
</ul>
<h1 id="테스트-간-테스트-픽스처-재사용">테스트 간 테스트 픽스처 재사용</h1>
<ul>
<li>준비 구절에서 코드를 재사용하는 것이 테스트를 줄이면서 단순화하기 좋은 방법이다.</li>
</ul>
<h3 id="테스트-픽스처">테스트 픽스처</h3>
<ul>
<li>테스트 픽스처는 테스트 실행 대상 객체다.<ul>
<li>이 객체는 정규 의존성, 즉 SUT로 전달되는 인수다. </li>
<li>데이터베이스에 있는 데이터나 하드 디스크의 파일일 수도 있다. </li>
<li>이러한 객체는 각 테스트 실행 전에 알려진 <code>고정 상태</code>로 유지하기 때문에 동일한 결과를 생성한다. </li>
<li>따라서 <code>픽스처</code>라는 단어가 나왔다.</li>
</ul>
</li>
</ul>
<pre><code class="language-java">public class CustomerTests
{
    [Fact]
    public void Purchase_succeeds_when_enough_inventory()
    {
        Store store = CreateStoreWithInventory(Product.Shampoo, 10);
        Customer sut = CreateCustomer();

        bool success = sut.Purchase(store, Product.Shampoo, 5);

        Assert.True(success);
        Assert.Equal(5, store.GetInventory(Product.Shampoo));
    }

    [Fact]
    public void Purchase_fails_when_not_enough_inventory()
    {
        Store store = CreateStoreWithInventory(Product.Shampoo, 10);
        Customer sut = CreateCustomer();

        bool success = sut.Purchase(store, Product.Shampoo, 15);

        Assert.False(success);
        Assert.Equal(10, store.GetInventory(Product.Shampoo));
    }

    private Store CreateStoreWithInventory(Product product, int quantity)
    {
        Store store = new Store();
        store.AddInventory(product, quantity);
        return store;
    }

    private static Customer CreateCustomer()
    {
        return new Customer();
    }
}</code></pre>
<ul>
<li>공통 초기화 코드를 비공개 팩토리 메서드(<code>CreateStoreWithInventory</code>)로 추출해 테스트 코드를 짧게 하면서, 동시에 테스트 진행 상황에 대한 전체 맥락을 유지할 수 있다.<h3 id="테스트-픽스처-재사용-규칙에-한-가지-예외">테스트 픽스처 재사용 규칙에 한 가지 예외</h3>
</li>
<li>테스트 전부 또는 대부분에 사용되는 생성자에 픽스처를 인스턴스화 할 수 있다.<ul>
<li>데이터베이스와 작동하는 통합 테스트에 종종 해당한다.</li>
<li>데이터베이스 연결이 필요하며, 이 연결을 한 번 초기화한 다음 어디에서나 재사용할 수 있다.</li>
<li>기초 클래스(base class)를 둬서 개별 테스트 클래스가 아니라 클래스 생성자에서 데이터베이스 연결을 초기화하는 것이 더 합리적이다.<pre><code class="language-java">public class CustomerTests2 : IntegrationTests
{
[Fact]
public void Purchase_succeeds_when_enough_inventory()
{
    /* 여기서 _database 사용 */
}
}
</code></pre>
</li>
</ul>
</li>
</ul>
<p>public abstract class IntegrationTests : IDisposable
{
    protected readonly Database _database;</p>
<pre><code>protected IntegrationTests()
{
    _database = new Database();
}

public void Dispose()
{
    _database.Dispose();
}</code></pre><p>}</p>
<p>```</p>
<h1 id="단위-테스트-명명법">단위 테스트 명명법</h1>
<ul>
<li>테스트에 표현력이 있는 이름을 붙이는 것이 중요하다.</li>
<li>올바른 명칭은 테스트가 검증하는 내용과 기본 시스템의 동작을 이해하는 데 도움이 된다.</li>
</ul>
<p>[테스트 대상 메서드]-[시나리오]-[예상 결과]</p>
<ul>
<li>테스트 대상 메서드: 테스트 중인 메서드의 이름</li>
<li>시나리오: 메서드를 테스트하는 조건</li>
<li>예상 결과: 현재 시나리오에서 테스트 대상 메서드에 기대하는 것</li>
</ul>
<blockquote>
<p>테스트명 내 테스트 대상 메서드
테스트 이름에 SUT의 메서드 이름을 포함하지 말라.
코드를 테스트하는 것이 아니라 애플리케이션 동작을 테스트하는 것이라는 점을 명심하자.</p>
</blockquote>
<ul>
<li>테스트 대상 메서드의 이름을 변경할 수 있으며, SUT의 동작에는 아무런 영향을 미치지 않는다.<ul>
<li>반면 원래 명명 규칙에 따르면 테스트 이름을 바꿔야 한다.</li>
<li>동작 대신 코드를 목표로 하면 해당 코드의 구현 세부 사항과 테스트 간의 <code>결합도가 높아진다는 것</code>을 다시 한 번 보여준다.</li>
<li>테스트 스위트의 <code>유지 보수</code>성에 부정적인 영향을 미친다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[마스터 노드와 데이터 노드를 분리해야 하는 이유]]></title>
            <link>https://velog.io/@minkyu__k/%EB%A7%88%EC%8A%A4%ED%84%B0-%EB%85%B8%EB%93%9C%EC%99%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%85%B8%EB%93%9C%EB%A5%BC-%EB%B6%84%EB%A6%AC%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@minkyu__k/%EB%A7%88%EC%8A%A4%ED%84%B0-%EB%85%B8%EB%93%9C%EC%99%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%85%B8%EB%93%9C%EB%A5%BC-%EB%B6%84%EB%A6%AC%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Fri, 14 Jul 2023 11:01:22 GMT</pubDate>
            <description><![CDATA[<h1 id="싱글-노드">싱글 노드</h1>
<ul>
<li>클러스터는 하나 이상의 엘라스틱서치 노드로 구성돼 있고 각 노드는 설정에 따라 특수항 <code>Role</code>을 부여받아 동작한다.</li>
</ul>
<ul>
<li>노드들은 별도의 설정이 없다면 <code>Single Node</code> 모드로 동작한다.<ul>
<li>싱글 노드는 엘라스틱서치의 모든 기능을 사용하는 노드다.</li>
</ul>
</li>
</ul>
<ul>
<li>클러스터의 모든 노드가 싱글 노드로 설정돼 있으면 모든 노드들이 동일한 역할을 수행한다.<ul>
<li>소규모 클러스터에 적합하다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>데이터의 크기가 작거나 노드의 수가 3대 이하일 경우에는 싱글 노드만으로 클러스터를 구성하는 것도 괜찮은 선택이다.</p>
</blockquote>
<h1 id="전용-마스터-노드-구축">전용 마스터 노드 구축</h1>
<ul>
<li>마스터 노드의 Role과 데이터 노드의 Role이 하나의 노드에서 동시에 수행될 경우<ul>
<li>무거운 쿼리가 요청되어 <code>데이터 노드</code>의 부하로 인해 시스템에 행(<code>Hang</code>)이 걸리거나 노드가 다운되는 경우도 발생할 수 있다.</li>
<li>당연히 마스터 노드의 역할도 정상적으로 수행되기 어려울 것이다.<ul>
<li><code>마스터 노드</code>의 역할이 정상적으로 동작하지 못하는 상황에서는 레플리카에 의해 쉽게 복구할 수 있는 단순 장애도 복구되지 못한다.</li>
<li>장애 복구의 책임은 <code>마스터 노드</code>에게 있다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li>마스터 노드는 많은 리소스가 필요 없다.<ul>
<li>역할 분리에 따른 비용 절감 효과도 있다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>안정적인 클러스터 운영을 위해서는 마스터 노드와 데이터 노드를 물리적으로 분리해서 각각 별도의 장비에서 동작할 수 있게 구성하는 것이 좋다.</p>
</blockquote>
<h1 id="전용-coordination-노드-구축">전용 Coordination 노드 구축</h1>
<ul>
<li>서비스가 성장할수록 다양한 지표에 대한 요구사항도 늘어날 것이다.</li>
</ul>
<ul>
<li>엘라스틱서치는 <code>애그리게이션(Aggregation)</code>이라는 강력한 집계 연산을 제공한다.</li>
</ul>
<ul>
<li>대량의 데이터를 처리해야 하는 집계 연산이 많은 경우에는 반드시 전용 Coordination 노드로만 요청을 받아야 한다.<ul>
<li>집계 연산은 메모리를 많이 사용한다.</li>
<li>하나의 물리적인 서버에서 데이터 노드의 역할과 Coordination 노드의 역할이 동시에 수행될 경우 장애가 발생할 가능성이 커진다.</li>
</ul>
</li>
</ul>
<ul>
<li>일정 규모 이상의 클러스터를 운영한다면 노드를 별도로 분리해서 구축하는 것이 좋은 전략이다.<ul>
<li>검색 용도의 Coordination 노드</li>
<li>색인 용도의 Coordination 노드</li>
<li>집계 용도의 Coordination 노드</li>
</ul>
</li>
</ul>
<blockquote>
<p>마스터 노드가 클러스터에 존재하는 모든 노드를 관리하기 때문에 Coordination 노드의 개수가 많아지면 관리에 부담이 생긴다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Elasticsearch 모니터링]]></title>
            <link>https://velog.io/@minkyu__k/Elasticsearch-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81</link>
            <guid>https://velog.io/@minkyu__k/Elasticsearch-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81</guid>
            <pubDate>Fri, 14 Jul 2023 02:35:44 GMT</pubDate>
            <description><![CDATA[<h1 id="search-rate">Search Rate</h1>
<ul>
<li>클러스터에 존재하는 프라이머리 샤드와 레플리카 샤드 모두에서 검색 요청을 처리할 수 있다.</li>
<li>모든 샤드에서 처리 중인 검색 요청 수를 모아서 초당 평균 몇 건이 처리되는지 숫자로 계산해서 보여준다.</li>
</ul>
<blockquote>
<p>전체 샤드에서 실행되는 초당 검색 요청 수</p>
</blockquote>
<h1 id="search-latency">Search Latency</h1>
<ul>
<li>클러스터에서 다수의 검색 요청이 들어오면 순서대로 큐에 쌓이고 처리량에 따라 큐의 요청 내역이 소비된다.<ul>
<li>이때 지연이 발생할 수 있으며 이러한 대기시간을 <code>Latency</code>라고 한다.</li>
<li>대기시간이 길수록 검색 처리 능력이 떨어진다고 볼 수 있다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>검색 요청을 처리하기 위한 평균 대기시간</p>
</blockquote>
<h1 id="indexing-rate">Indexing Rate</h1>
<ul>
<li>클러스터에 데이터가 들어오면 색인 과정을 거친다.</li>
<li>기본적으로 <code>프라이머리 샤드</code>에서 색인이 완료되면 <em>검색이 가능해지지만</em> 클러스터 내부에 <code>레플리카</code>가 존재할 경우 엘라스틱서치는 일관성을 위해 <em>레플리카에서도 색인을 수행한다</em>.<ul>
<li>모든 레플리카 세트에서 색인이 완료돼야 실질적인 색인이 완료됐다고 판단한다.</li>
<li>이러한 이유로 클러스터 내부에 너무 많은 레플리카 세트가 있을 경우 색인 성능이 떨어질 수 있다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>모든 샤드에서 인덱싱 처리가 이뤄지고 있는 초당 문서 수</p>
</blockquote>
<h1 id="indexing-latency">Indexing Latency</h1>
<ul>
<li>색인 처리에 대한 지연시간을 확인할 수 있다.</li>
<li>대기시간이 길수록 색인 처리 능력이 떨어진다고 할 수 있다.</li>
</ul>
<blockquote>
<p>인덱싱 처리를 위한 평균 대기시간</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Elasticsearch index settings]]></title>
            <link>https://velog.io/@minkyu__k/Elasticsearch-index-settings</link>
            <guid>https://velog.io/@minkyu__k/Elasticsearch-index-settings</guid>
            <pubDate>Wed, 12 Jul 2023 23:00:07 GMT</pubDate>
            <description><![CDATA[<h1 id="total_shrads_per_node">total_shrads_per_node</h1>
<ul>
<li><code>total_shards_per_node</code> 옵션은 Elasticsearch 클러스터 내에서 각 노드가 관리하는 샤드(shard)의 수를 제어하는 설정이다.</li>
<li>각 노드가 관리하는 샤드의 최대 수를 제한하는 역할이다.</li>
<li>이 값을 설정하면 클러스터에 새로운 인덱스가 생성될 때 해당 인덱스의 샤드 수가 설정된 값으로 제한된다.</li>
<li>따라서 노드가 가용한 리소스에 따라서 각 노드당 할당되는 샤드 수를 조절할 수 있다.</li>
</ul>
<pre><code class="language-json">{
    &quot;index&quot;: {
        &quot;routing&quot;: {
            &quot;allocation&quot;: {
                &quot;total_shards_per_node&quot;: &quot;4&quot;
            }
        }
    }
}</code></pre>
<h1 id="auto_expand_replicas">auto_expand_replicas</h1>
<ul>
<li><code>auto_expand_replicas</code> 옵션은 샤드의 수가 늘어 날 때 자동으로 복제본(replica)의 개수도 증가시키는 기능을 제어하는 옵션이다.</li>
<li>이 설정을 활성화하면, Elasticsearch 클러스터에 새로운 노드가 추가되거나 기존 노드에서 샤드의 수가 자동으로 조정될 때, 복제본의 수도 자동으로 조정된다.</li>
<li><code>0-1</code>로 지정하면, 샤드의 수가 늘어날 때마다 해당 인덱스의 복제본 수가 1개로 유지되도록 자동으로 관리된다.</li>
<li><code>0-all</code> 로 지정하면, 모든 노드에 복제본을 할당하겠다는 의미다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[단위 테스트란 무엇인가]]></title>
            <link>https://velog.io/@minkyu__k/%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@minkyu__k/%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Wed, 12 Jul 2023 13:52:36 GMT</pubDate>
            <description><![CDATA[<h2 id="단위-테스트-정의">‘단위 테스트’ 정의</h2>
<ul>
<li>작은 코드 조각(단위라고도 함)을 검증하고</li>
<li>빠르게 수행하고</li>
<li>격리된 방식으로 처리하는 자동화된 테스트다.<ul>
<li>격리 문제는 고전파와 런던파를 구분할 수 있게 한다.</li>
</ul>
</li>
</ul>
<h2 id="격리-문제에-대한-런던파의-접근">격리 문제에 대한 런던파의 접근</h2>
<ul>
<li>테스트 대상 시스템(<code>SUT, System Under Test</code>)을 협력자(collaborator)에게서 격리하는 것을 일컫는다.<ul>
<li>하나의 클래스가 다른 클래스 또는 여러 클래스에 의존하면 이 모든 의존성으로 테스트 대역(<code>test double</code>)으로 대체해야 한다.<ul>
<li>테스트가 실패하면 코드베이스의 어느 부분이 고장 났는지 확실히 알 수 있다.</li>
<li>객체 그래프(<code>object graph</code>)를 분할할 수 있다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="격리-문제에-대한-고전파의-접근">격리 문제에 대한 고전파의 접근</h2>
<ul>
<li>각각의 테스트를 격리하는 것은 여러 클래스가 모두 메모리에 상주하고 공유 상태에 도달하지 않는 한, 여러 클래스를 한 번에 테스트해도 괜찮다는 뜻이다.</li>
<li>테스트 대역을 사용할 수 있지만, 보통 테스트 간에 공유 상태를 일으키는 의존성에 대해서만 사용한다.</li>
</ul>
<h1 id="단위-테스트의-런던파와-고전파">단위 테스트의 런던파와 고전파</h1>
<table>
<thead>
<tr>
<th></th>
<th>격리주체</th>
<th>단위의 크기</th>
<th>테스트 대역 사용대상</th>
</tr>
</thead>
<tbody><tr>
<td>런던파</td>
<td>단위</td>
<td>단일 클래스</td>
<td>불변 의존성 외 모든 의존성</td>
</tr>
<tr>
<td>고전파</td>
<td>단위 테스트</td>
<td>단일 클래스 또는 클래스 세트</td>
<td>공유 의존성</td>
</tr>
</tbody></table>
<h3 id="공유-의존성">공유 의존성</h3>
<ul>
<li>공유 의존성(<code>shared dependency</code>)은 테스트 간에 공유되고 서로의 결과에 영향을 미칠 수 있는 수단을 제공하는 의존성이다.<ul>
<li>ex) 정적 가변 필드(<code>static mutable field</code>), 데이터베이스</li>
</ul>
</li>
</ul>
<h2 id="한-번에-한-클래스만-테스트하기">한 번에 한 클래스만 테스트하기</h2>
<blockquote>
<p>테스트는 코드의 단위를 검증해서는 안 된다. 
동작의 단위, 즉 문제 영역에 의미가 있는 것, 이상적으로는 비즈니스 담당자가 유용하다고 인식할 수 있는 것을 검증해야 한다.</p>
</blockquote>
<h2 id="상호-연결된-클래스의-큰-그래프를-단위-테스트하기">상호 연결된 클래스의 큰 그래프를 단위 테스트하기</h2>
<ul>
<li>상호 연결된 클래스의 크고 복잡한 그래프를 테스트할 방법을 찾는 대신, 먼저 이러한 클래스 그래프를 갖기 않는 데 집중해야 한다.<ul>
<li>대개 클래스 그래프가 커진 것은 코드 설계 문제의 결과다.</li>
</ul>
</li>
</ul>
<h2 id="버그-위치-정확히-찾아내기">버그 위치 정확히 찾아내기</h2>
<ul>
<li>런던 스타일 테스트가 있는 시스템에 버그가 생기면, 보통 SUT에 버그가 포함된 테스트만 실패한다.</li>
<li>고전적인 방식이면, 오작동하는 클래스를 참조하는 클라이언트를 대상으로 하는 테스트도 실패할 수 있다.</li>
</ul>
<h2 id="고전파와-런던파-사이의-다른-차이점">고전파와 런던파 사이의 다른 차이점</h2>
<ul>
<li>테스트 주도 개발(TDD, Test-Driven Development)을 통한 시스템 설계 방식</li>
<li>과도한 명세(over-specification) 문제</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[06. 도메인 헥사곤 만들기]]></title>
            <link>https://velog.io/@minkyu__k/06.-%EB%8F%84%EB%A9%94%EC%9D%B8-%ED%97%A5%EC%82%AC%EA%B3%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@minkyu__k/06.-%EB%8F%84%EB%A9%94%EC%9D%B8-%ED%97%A5%EC%82%AC%EA%B3%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Mon, 10 Jul 2023 13:10:01 GMT</pubDate>
            <description><![CDATA[<h1 id="모듈화된-애플리케이션으로-도메인-헥사곤을-생성하는데-어떤-기술이-사용되는가">모듈화된 애플리케이션으로 도메인 헥사곤을 생성하는데 어떤 기술이 사용되는가?</h1>
<ul>
<li>JPMS(<code>Java Platform Module System</code>)로 도메인 헥사곤을 생성함.</li>
</ul>
<h1 id="값-객체를-생성하는-것으로-도메인-헥사곤의-개발을-시작하는-이유는-무엇인가">값 객체를 생성하는 것으로 도메인 헥사곤의 개발을 시작하는 이유는 무엇인가?</h1>
<ul>
<li>값 객체는 더 정교한 값 객체와 가장 중요한 엔티티를 만드는데 사용되는 원자재인 기반 요소이므로 먼저 값 객체를 생성하는 것으로 시작하기를 권장한다.</li>
</ul>
<h1 id="문제-영역을-이해하고-나면-그-다음-단계는-무엇인가">문제 영역을 이해하고 나면 그 다음 단계는 무엇인가?</h1>
<ul>
<li>문제 영역을 더 잘표현하는 도메인 모델을 만들 수 있게 해주는 아키텍처 컴포넌트인 값 객체를 가지고 헥사고날 시스템을 구축하겠다.</li>
</ul>
<h1 id="견고하고-잘-테스트된-도메인-헥사곤을-개발하는-것이-중요한-이유는-무엇인가">견고하고 잘 테스트된 도메인 헥사곤을 개발하는 것이 중요한 이유는 무엇인가?</h1>
<ul>
<li>견고한 도메인 헥사곤을 개발하는 것은 애플리케이션 헥사곤과 프레임워크 헥사곤이 의존할 수 있는 견고한 토대가 된다.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>