<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Dongle Blog</title>
        <link>https://dgle.dev/</link>
        <description>Dongle Blog</description>
        <lastBuildDate>Thu, 27 Apr 2023 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Spring Boot Batch 따라가보기 - 1]]></title>
            <link>https://dgle.dev/spring-boot-batch-1</link>
            <guid>https://dgle.dev/spring-boot-batch-1</guid>
            <pubDate>Thu, 27 Apr 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Follow up Spring Boot Batch]]></description>
            <content:encoded><![CDATA[<p>코린이의 Spring Boot Batch 파헤쳐보기</p><h1>스프링 배치</h1><h2 class="anchor anchorWithStickyNavbar_LWe7" id="배치-사용-이유">배치 사용 이유<a href="#배치-사용-이유" class="hash-link" aria-label="Direct link to 배치 사용 이유" title="Direct link to 배치 사용 이유">​</a></h2><p>대량의 레코드의 로깅 분석, 트랜잭션 관리, 잡 프로세스 관리, 잡 재시작, skip, 리소스 관리등 사용성좋은 기능들을 제공해준다. 가장 큰 이점으로는 여러 data formatter를 지원하여 Read,
Write 를 도와줘서 복잡한 코드를 사용하지 않아도 사용하기가 쉽다.</p><p>또한 중요한 다른 이점으로 청크 기반의 프로세싱을 지원하며, 배치 잡 상태를 관리해주는데, 중단된 실패한 잡의 재시작, 여러 이유로 skip되버린 records의 재시작, 또는 잡의 진행상태 들을 관리해주어
유지보수관리에 용이하다.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="배치-아키텍처">배치 아키텍처<a href="#배치-아키텍처" class="hash-link" aria-label="Direct link to 배치 아키텍처" title="Direct link to 배치 아키텍처">​</a></h2><h2 class="anchor anchorWithStickyNavbar_LWe7" id="job-시작-flow">Job 시작 flow<a href="#job-시작-flow" class="hash-link" aria-label="Direct link to Job 시작 flow" title="Direct link to Job 시작 flow">​</a></h2><p><img loading="lazy" alt="batch-job-start-flow" src="/assets/images/Untitled-8f9b75217ec848de0ad7318844ac96ec.png" width="6488" height="4284" class="img_ev3q"></p><ol><li>마지막에 실행된 job을 조회</li><li>없으면 새로운 job을 등록</li><li>있을 경우 해당하는 job을 조회한다.<ul><li>여러가지 상태들을 확인한다.<ul><li>ex) step 들의 상태가 running 또는 <em>STOPPING 일시 throw</em></li></ul></li></ul></li></ol><h3 class="anchor anchorWithStickyNavbar_LWe7" id="배치-비지니스-로직-flow">배치 비지니스 로직 flow<a href="#배치-비지니스-로직-flow" class="hash-link" aria-label="Direct link to 배치 비지니스 로직 flow" title="Direct link to 배치 비지니스 로직 flow">​</a></h3><p><img loading="lazy" alt="spring-boot-batch-business-flow" src="/assets/images/Untitled-8f9b75217ec848de0ad7318844ac96ec.png" width="6488" height="4284" class="img_ev3q"></p><p><strong>JobInstance</strong></p><p>JobInstace는 논리적으로 실행을 나타낸다. JobInstae는 Job 이름과 인수로 식별된다. Job명이 동일하다면 동일한 JobInstance로 생각을하여, Job이 에러 등으로 처리가 도중에 중단하고
있었을 경우 재실행을 보장 할 수 있고, 처리의 도중부터 실행된다.</p><p><strong>JobExecution</strong></p><p>JobExecution은 작업의 실행을 나타낸다. JobInstance 와 1:N의 관계를 가진다.<br>
<!-- -->ExecutionContext를 가지고있는데 Spring Batch가 여러 진행 상황과 메타데이터를 체크하기위해 가지기도 하지만 사용자가 공유를위해 사용할 수 도 있다.</p><p><strong>StepExecution</strong></p><p>StepExecution은 Step의 실행을 나타낸다. JobExecution과 StepExecution은 1:N의 관계를 가진다.
JobExecution과 마찬가지로 ExecutionContext를 가지는데, 복수의 step간의 공유를 위해서 사용하지 않을려면 StepExecution을 사용 할 수 있다.</p><h1>참고</h1><p><a href="https://medium.com/dreamifly/spring-batch-tutorial-batch-processing-made-easy-with-spring-3219b4de052" target="_blank" rel="noopener noreferrer">Spring Batch Tutorial: Batch Processing Made Easy with Spring | by Jalal Nasser | DreamiFly | Medium</a><br>
<a href="https://www.baeldung.com/rest-assured-tutorial" target="_blank" rel="noopener noreferrer">https://www.baeldung.com/rest-assured-tutorial</a>)</p>]]></content:encoded>
            <category>SpringBoot</category>
            <category>SpringBootBatch</category>
        </item>
        <item>
            <title><![CDATA[RestAssured]]></title>
            <link>https://dgle.dev/rest-assured</link>
            <guid>https://dgle.dev/rest-assured</guid>
            <pubDate>Sat, 25 Mar 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[RestAssured Test]]></description>
            <content:encoded><![CDATA[<p>Test시 Mock 이 지겹다면 RestAssured 를 강력추천합니다.    </p><p>모든 소스는 <a href="https://github.com/sk1737030/til/tree/master/rest-assured" target="_blank" rel="noopener noreferrer">이곳에서</a> 확인이 가능합니다!</p><h1>Rest Assured</h1><p>REST Assured Java 라이브러리를 사용하여 REST 어플리케이션의 HTTP Endpoint에 초첨을 맞춘 테스트 도구이며, MockMVC와 같이 테스트를 편리하게 해주는 <strong><code>유용한 테스트 도구</code></strong>이며, 인수테스트 작성으로도 많이 사용이됩니다.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="사용">사용<a href="#사용" class="hash-link" aria-label="Direct link to 사용" title="Direct link to 사용">​</a></h2><h3 class="anchor anchorWithStickyNavbar_LWe7" id="gradlebuild">gradle.build<a href="#gradlebuild" class="hash-link" aria-label="Direct link to gradle.build" title="Direct link to gradle.build">​</a></h3><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">testImplementation 'io</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rest</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">assured</span><span class="token operator" style="color:#393A34">:</span><span class="token plain">rest</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">assured'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li>당연하지만, 기본적인 test 를 위한 기본 것들은 import 하고 있어야한다.</li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="코드">코드<a href="#코드" class="hash-link" aria-label="Direct link to 코드" title="Direct link to 코드">​</a></h3><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@SpringBootTest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">webEnvironment </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">SpringBootTest</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">WebEnvironment</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">RANDOM_PORT</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//(0)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">RestAssuredApplicationTests</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">protected</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token class-name">RequestSpecification</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">REQUEST_SPEC</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@LocalServerPort</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">Integer</span><span class="token plain"> port</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@BeforeEach</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">setRequestSpec</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">RequestSpecBuilder</span><span class="token plain"> reqBuilder </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">RequestSpecBuilder</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    reqBuilder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setContentType</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ContentType</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">JSON</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    reqBuilder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setPort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">port</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token constant" style="color:#36acaa">REQUEST_SPEC</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> reqBuilder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">build</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@Test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getOrder</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">ExtractableResponse</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Response</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> actualResponse </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">RestAssured</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// (1)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">given</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// (2)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token function" style="color:#d73a49">spec</span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">REQUEST_SPEC</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">all</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">when</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// (3)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/order/{orderId}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1L</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// (4)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token function" style="color:#d73a49">log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">all</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">extract</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// (5)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">assertThat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actualResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">statusCode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isEqualTo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">HttpStatus</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">OK</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">value</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">assertThat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">actualResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">jsonPath</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getObject</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"."</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">OrderController</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">OrderResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">class</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isEqualTo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">OrderController</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">OrderResponse</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1L</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10000L</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000L</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>간단한 타켓 url 을 get 요청 및 검증하는 테스트입니다.</p><p>(0)<code>@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)</code></p><ul><li><p>End to End 테스트 목적이니 SpringBootTest를 사용합니다.</p></li><li><p><code>webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT</code></p><ul><li>지정된 포트로 톰캣을 띄우게 됩니다. 이는 실제로 mock이 아닌 별도의 스레드로 톰켓을 시작하게됩니다</li></ul><p><img loading="lazy" alt="/tomcatstart" src="/assets/images/Untitled-022136c140567157d079dc8e34bcbb58.png" width="2442" height="514" class="img_ev3q"></p><aside>💡 `WebEnvironment` **default** 설정은 **mock**입니다!<p>In WebEnvironment.java<br>
<code>WebEnvironment webEnvironment() default WebEnvironment.MOCK;</code></p></aside></li></ul><p>(1) <code>RestAssured</code></p><ul><li><p><code>RestAssured</code> 를 시작으로 Java DSL 형태로 작성이 가능합니다.</p><aside>💡 Java DSL이란?<p>DSL(Domain-specific Languages, 도메인 전용언어), 특정 비지니스 도메인의 문제를 해결하려고 만든 특수 프로그래밍 언어입니다.
Stream, Collector 같은 것들도 DSL입니다.</p></aside></li></ul><p>(2) <code>given().log().all()</code></p><ul><li>모든 request 헤더와 바디 부분을 상세하게 로깅해줍니다.</li><li>all 말고도 원하는 params, body, path 것을 명시가능합니다.</li><li>given 에서 header 등에 여러 인증을 명시 할 수 있습니다.</li></ul><p>(3) <code>when().get("/template/{targetId}", targetId)</code></p><ul><li>get, post, put 등 원하는 httpMethod를 명시 할 수 있습니다.</li><li>안에 target url을 넣어서 요청이 됩니다.</li></ul><p>(4) <code>then()</code></p><ul><li>then 절에서는 주로 여러 응답을 검증 할 수 있습니다.</li><li>또는 응답 로그 확인용으로 사용이 가능합니다.</li></ul><p>(5) <code>extract()</code></p><ul><li>response 로 추출을 할 수 있습니다.</li><li>가져온 response로 추가 검증이 가능합니다.</li></ul><p><code>log.all</code></p><p>아래왜 같이 콘솔에 요청 또는 응답 로그를 남기겠다고 명시하는 것입니다.</p><p><img loading="lazy" alt="request" src="/assets/images/Untitled 1-4ee71d54f26408a22a743812de2bfa60.png" width="1260" height="640" class="img_ev3q"></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="번외">번외<a href="#번외" class="hash-link" aria-label="Direct link to 번외" title="Direct link to 번외">​</a></h2><p>Mock을 사용하지 않고 end to end 테스트하기 <code>with FeignClient</code></p><p>외부 request 요청 시 FeignClient를 많이 사용하는데, 이는 자연스럽게 외부 자원에 대한 테스트 고민을 하게 만들어줍니다.</p><p>여러가지 문제가 있는데요. 그것을 어떻게 해결 할 수 있는지 알아봅시다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="feignclient-는-primary-default-인-config-이다">FeignClient 는 Primary default 인 Config 이다.<a href="#feignclient-는-primary-default-인-config-이다" class="hash-link" aria-label="Direct link to FeignClient 는 Primary default 인 Config 이다." title="Direct link to FeignClient 는 Primary default 인 Config 이다.">​</a></h3><p>즉, Bean으로 같은 name으로 생성해서는 FeignClient 를 갈아끼울 수 있는 방법이 없습니다. 이를 해결하고자 여러 방법이 있습니다.</p><p><img loading="lazy" alt="문제의 primary" src="/assets/images/Untitled 2-6dbf92265cb815cd969e701b5355698f.png" width="1200" height="144" class="img_ev3q">  </p><ol><li><p>가장 쉬운 방법은 default를 false로 선언하는 것입니다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@FeignClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"order"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  url </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"${targetUrl}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  primary </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// (1)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">OrderClient</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Long</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">orderAmount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Long</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Component</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Primary</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">FakeOtherOrderClient</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">OtherOrderClient</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// (2)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Long</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">orderAmount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Long</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10000L</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@RestController</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@RequestMapping</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/order"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">OrderController</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">OtherOrderClient</span><span class="token plain"> otherOrderClient</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">OrderController</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">OtherOrderClient</span><span class="token plain"> otherOrderClient</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">otherOrderClient </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> otherOrderClient</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@GetMapping</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/{orderId}"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">ResponseEntity</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">OrderResponse</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getOrder</span><span class="token punctuation" style="color:#393A34">(</span><span class="token annotation punctuation" style="color:#393A34">@PathVariable</span><span class="token plain"> </span><span class="token class-name">Long</span><span class="token plain"> orderId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Long</span><span class="token plain"> amount </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> otherOrderClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">orderAmount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">orderId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">ResponseEntity</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ok</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">OrderResponse</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">orderId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> amount</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000L</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li>이런식으로 테스트 패키지 아래 위치를 시켜 fake로 만들어서 대신 응답을 뱉을 수 있습니다 (<del>예제는 사실 stub에 가깝긴하지만..</del>)</li></ul><p>(1) <code>@FeignClient(primary = false)</code></p><ul><li>false로 primary config 로 등록이 안되도록 명시 해줍니다.</li></ul><p>(2) <code>public class FakeOtherOrderClient implements OtherOrderClient</code></p><ul><li>Fake 클래스로 상속을 받아 primary 로 선언을해서 테스트 시 Bean을 강제로 바꿔치기하는 것입니다.</li></ul></li><li><p>만약 FeignClient가 외부 dependency 인 경우에는 Feign Client에 false를 집어 넣을 수 없는데요 이때에는, OrderClient를 한 번더 감싸서 클래스로 만들고 만든 부분을 fake로 만드는 것입니다.</p><ul><li><p>글로 표현하면 어려운데요. 코드로 보시면 쉬울 거 같습니다!</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@FeignClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"order"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  url </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"{targetUrl}"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">OrderClient</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Long</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">orderAmount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Long</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Service</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">WrapperOrderClient</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// (1)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">OtherOrderClient</span><span class="token plain"> otherOrderClient</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">WrapperOrderClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">OtherOrderClient</span><span class="token plain"> otherOrderClient</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">otherOrderClient </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> otherOrderClient</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Long</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">orderAmount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Long</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> otherOrderClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">orderAmount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@RestController</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@RequestMapping</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/v2/order"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">OrderControllerV2</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">WrapperOrderClient</span><span class="token plain"> wrapperOrderClient</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">OrderControllerV2</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">WrapperOrderClient</span><span class="token plain"> wrapperOrderClient</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">wrapperOrderClient </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> wrapperOrderClient</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@GetMapping</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/{orderId}"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">ResponseEntity</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">OrderResponse</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getOrder</span><span class="token punctuation" style="color:#393A34">(</span><span class="token annotation punctuation" style="color:#393A34">@PathVariable</span><span class="token plain"> </span><span class="token class-name">Long</span><span class="token plain"> orderId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Long</span><span class="token plain"> amount </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> wrapperOrderClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">orderAmount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">orderId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// (2)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">ResponseEntity</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ok</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">OrderResponse</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">orderId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> amount</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000L</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Component</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Primary</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">FakeOtherOrderClientV2</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">WrapperOrderClient</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// (3)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">FakeOtherOrderClientV2</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">OtherOrderClientV2</span><span class="token plain"> otherOrderClientV2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Long</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">orderAmount</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Long</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10000L</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li></ul><p>(1) <code>public class WrappedOrderClient</code></p><ul><li>우리 코드에서 컨트롤이 가능하도록 WrapperOrderClient를 한 번더 감쌉니다.  </li></ul><p>(2) <code>Long amount = wrapperOrderClient.orderAmount(orderId);</code></p><ul><li>일반적으로 사용 사용 할 때와 동일하게 사용합니다. 그저 감싼 객체로 사용을 합니다. </li></ul><p>(3) <code>public class FakeOtherOrderClientV2 extends WrapperOrderClientTest</code></p><ul><li>테스트 패키지에서 생성 후 감싼 객체를 상속을 받게 합니다.</li></ul></li></ol><h3 class="anchor anchorWithStickyNavbar_LWe7" id="mockmvc와-차이점">MockMvc와 차이점<a href="#mockmvc와-차이점" class="hash-link" aria-label="Direct link to MockMvc와 차이점" title="Direct link to MockMvc와 차이점">​</a></h3><p>MockMvc는 웹 애플리케이션을 애플리케이션 서버에 배포하지 않고도 스프링 MVC의 동작을 재현할 수 있는 라이브러리이며 대부분 Controller Layer Unit Test(단위 테스트)에 사용됩니다.</p><p>실제 서버 환경과 동일한 <code>@SpringBootTest</code>를 사용하지않고 Presentation Layer Bean들만 불러온다. 그리고 그 외 Bean은 Mock 객체 설정을 해주어 순수한 Controller 로직을 테스트를 할 수 있게 도와줍니다</p><p>물론 <code>@SpringBootTest</code> 를 사용하면 end to end 테스트가 가능하나, <code>RestAssured</code> 는 bdd기반의 테스트 코드를 작성 할 수 있게 도와줘서 테스트 가독성을 높여주며, json 검증시에도 상대적으로 쉽게 검증이 가능한 장점이 있다.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="결론">결론<a href="#결론" class="hash-link" aria-label="Direct link to 결론" title="Direct link to 결론">​</a></h2><p>이상으로 RestAssured를 알아봤는데요. 그러면 RestAssured의 단점은 SpringBootTest를 사용하게되다보니 테스트 속도가 mock을 사용 할 때 보다 매우 느립니다. 그래서 상황에 맞게 사용하는게 좋고, 개인적으로는 테스트 작성시에 <code>end-to-end</code> 테스트 시에는 BDD 형태로 가독성이 좋은 <code>RestAssured</code>를 사용하고, <code>Unit test</code> 또는 특정 레이어 텟트시에는 <code>mockmvc</code> 로 테스트를 한다면 좋을 거 같습니다.</p><h1>참고</h1><p><a href="https://github.com/rest-assured/rest-assured/wiki/Usage" target="_blank" rel="noopener noreferrer">Restaussred used docs</a>
<a href="https://www.baeldung.com/rest-assured-tutorial" target="_blank" rel="noopener noreferrer">https://www.baeldung.com/rest-assured-tutorial</a></p>]]></content:encoded>
            <category>SpringBoot</category>
            <category>Test</category>
            <category>rest-assured</category>
        </item>
        <item>
            <title><![CDATA[어른의 문해력]]></title>
            <link>https://dgle.dev/adult-literacy</link>
            <guid>https://dgle.dev/adult-literacy</guid>
            <pubDate>Mon, 07 Nov 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[내가 쓴 문장이 어른의 문장일까?]]></description>
            <content:encoded><![CDATA[<p>내가 쓴 문장이 어른의 문장일까라고 고민을 해봤다면 이 책을 추천한다. </p><h1>어른의 문장력</h1><p>내가 쓴 문장이 어른의 문장일까라고 고민을 한 번 이라도 해봤다면 이책을 추천한다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="타깃을-분명하게">타깃을 분명하게<a href="#타깃을-분명하게" class="hash-link" aria-label="Direct link to 타깃을 분명하게" title="Direct link to 타깃을 분명하게">​</a></h3><p>글을 쓰기 전에 글을 읽는 사람이 누구일까를 먼저 떠올린다.<br>
<!-- -->타깃이 있는 문장은 다음과 같은 특징이있다.  </p><ol><li>친절하다.<ul><li>나는 알아도 상대방은 모를 수 있다는 사실을 항상 전제하고 글을 쓴다.</li></ul></li><li>책임을 지려고 한다. 의사 전달이 제대로 안 되거나 상대가 뜻을 이해하지 못하면, 상대방의 탓하는 게 아니라 표현을 정확하게 쓰지 못한 자신을 되돌아본다.</li></ol><p>요즘 같이 온라인으로 소통을 많이 하는 시대에서는 더욱 <code>어휘력</code>은 중요하다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="메시지-챙기기">메시지 챙기기<a href="#메시지-챙기기" class="hash-link" aria-label="Direct link to 메시지 챙기기" title="Direct link to 메시지 챙기기">​</a></h3><p>성과라는 목적이 있는 문장은 반드시 구체적인 메시지를 품고 있어야한다. (p.35)
심리학에는 초두효과, 최근효과라는 것이 있다. 보통 중간보다는 가장 처음과 마지막에 제시된 내용을 더 잘 기억한다는 뜻이다.<br>
<!-- -->블로그를 쓸 때 만앞 또는 맨뒤에 3줄 요약을 쓰면 효과적인 이유이다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="말-끊는-습관-없애기">말 끊는 습관 없애기<a href="#말-끊는-습관-없애기" class="hash-link" aria-label="Direct link to 말 끊는 습관 없애기" title="Direct link to 말 끊는 습관 없애기">​</a></h3><p>나는 주로 고민을 듣는 입장이었는데 곰곰이 생각해보면 진짜로 ‘듣는 사람’이 었는지 반성하게 된다. (p.44)<br>
<!-- -->미국의 사회학자 찰스 더버는 대화 주도권을 자신에게 돌려놓으려는 욕망을 ‘대화 나르시시즘’이라 표현했다. 재밌는 점은 상대방의 대화 나르시시즘 의도는 빤히 보이지만 내가 저지르고 있단느 사실은 쉽게 깨닫기 힘들다.<br>
<!-- -->서로에게 유익한 대화가 되려면 아무리 내 말이하고 싶어서 손가락이 근질근해도 참는 훈련이 필요하다.<br>
<!-- -->상대와 아직 친분이 없다면 격의 없게 다가가는 것보다는 과한 예의를 차리는 편이 낫다. 쿠션어를 적극적으로 사용하는 것도 한 가지 방법인데, 주로 ‘바쁘시겠지만’ ‘죄송하지만’이 있다.<br>
<!-- -->내 마음의 거리와 상대방의 마음의 거리는 다를 수 있다라는 것을 인지하자.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="문장-다이어트">문장 다이어트<a href="#문장-다이어트" class="hash-link" aria-label="Direct link to 문장 다이어트" title="Direct link to 문장 다이어트">​</a></h3><p>어른의 문장을 쓰려면 글 종류를 불문하고 퇴고를 여러번 해야 한다. 문장 다이어트를 해야한다.  </p><ul><li>있어도 괜찮을 말을 두는 너그러움보다, 없어도 좋은 말을 기어이 찾아내어 없애는 신경질이 글쓰기에선 미덕이다. - 이태준, &lt;문장강화&gt;  <ul><li>과도한 부사제거</li><li>들, 것 빼기<ul><li>영화 제작진들이 무대로 올라갔다.<br>→ 영화 제작진이 무대로 올라갔다.  </li><li>우리들은 다음 목적지로 향했다.<br>→우리는 다음 목적지로 향했다.  </li><li>아픈 것은 사실이지만 아닌 척했다.  <ul><li>아팠지만 아닌 척했다.</li></ul></li></ul></li></ul></li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="긍정의-문장이-긍정적인-첫인상을-만든다">긍정의 문장이 긍정적인 첫인상을 만든다.<a href="#긍정의-문장이-긍정적인-첫인상을-만든다" class="hash-link" aria-label="Direct link to 긍정의 문장이 긍정적인 첫인상을 만든다." title="Direct link to 긍정의 문장이 긍정적인 첫인상을 만든다.">​</a></h3><ul><li><p>너무 어려워요, 제가 머리가 좀 나빠서요. 여기 계신 분들은 다들 똑똑하신 거 같은데 저만 부끄럽네요 ㅠㅠ<br>
<!-- -->→ 어렵긴 한데 재밋어요. 뭔가 잠들어 있던 도전정신이 꺠어나는 느낌? ㅎㅎ 벌써 다음이 기대돼요!  </p></li><li><p>어른의 문장은 긍정적이고 자신감 넘치는 문장이다.</p></li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="일잘러">일잘러<a href="#일잘러" class="hash-link" aria-label="Direct link to 일잘러" title="Direct link to 일잘러">​</a></h3><p>일을 잘하는 사람은 사소한 회의 시간일지라도 맨몸으로 ‘팔랑’ 가기보다는 정갈하게 정리된 문장을 준비한다. 논의 주제와 보고할 내용을 나누어 메모해두면 전달할 내용을 깜빡하지 않는다. (p.68)</p><p>어른의 문장 쓰기는 하루아침에 얻는 기술이 아니다. 쓰는 만큼 정갈해진다. 주체적인 나로 살고 싶다면 매일 쓰고 고치기 바란다. ‘나는 내향인이라서…’라는 말은 이제 허울 좋은 핑계에 불과하다.</p><p>“특히 스크럼에 들어가기 전에 10분간 정리하는 시간을 가지자.“</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="정돈된-문장으로-머릿속을-정리하다">정돈된 문장으로 머릿속을 정리하다<a href="#정돈된-문장으로-머릿속을-정리하다" class="hash-link" aria-label="Direct link to 정돈된 문장으로 머릿속을 정리하다" title="Direct link to 정돈된 문장으로 머릿속을 정리하다">​</a></h3><p>책을 읽은 후 우리는 그냥 뭉뚱그려진 감정과 생각의 덩어리를 갖고 있을 뿐이다. 결국 기억하기 위해서라도, 또 표현하기 위해서라도 말하고 쓰는 것이 중요하다.
걱정이 많을 때는 마인드 맵을 그려보자.(p.90)<br>
<!-- -->간결하고 정확한 문장을 써버릇하면 우유부단한 성격에도 조금씩 균일이 생기지 않을까?</p><p><strong>피동형 문장을 능동형으로 바꿔보자.</strong></p><p>그녀가 멀리서 나를 바라봄이 느껴졌다.<br>
<!-- -->→ 그녀가 멀리서 나를 바라봤다.</p><p>활활 타오르는 장작불을 보니 학창 시절 수련회가 떠올려졌다.<br>
<!-- -->→ 활활 타오르는 장작불을 보니 학창 시절 수련회가 떠올랐다.  </p><p>이제는 외벌이가 됐으니 그만큼 씀씀이가 적어져야 될 것 같다.<br>
<!-- -->→이제는 외벌이가 됐으니 그만큼 씀씀이를 줄여야겠다.  </p><p><strong>뭉뚱그리지 말고 구체적으로</strong></p><p>공원에는 정말 다양한 사람들이 모여있다.<br>
<!-- -->→안양공원에는 이십 대부터 칠십 대 노인까지 다양한 연령대 사람들이 모여있다.</p><p>오랜만에 만난 선생님과 이런저런 대화를 나누었다.
→오랜만에 만난 요가 선생님과 새로 취직한 회사 이야기를 나누었다.</p><p>말글을 쓰기 전 한 번더 생각하자. 맞춤법, 어긋난 핵심 등등  </p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="항상-인사-할-때">항상 인사 할 때<a href="#항상-인사-할-때" class="hash-link" aria-label="Direct link to 항상 인사 할 때" title="Direct link to 항상 인사 할 때">​</a></h3><p>‘안녕하세요’ 이 짧은 인사와 자기소개는 생각보다 많은 의미를 담고 있다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="win-win하는-질문-법">win-win하는 질문 법<a href="#win-win하는-질문-법" class="hash-link" aria-label="Direct link to win-win하는 질문 법" title="Direct link to win-win하는 질문 법">​</a></h3><p>‘예, 아니요’ 식으로 대답하게 만드는 닫힌 질문보다는 열린 질문이 좋지만, 열린 질문이 추상적인 질문을 의미하지 않는다. 이어령 선생님도 큰 질문을 경계하고 작은 질문을 하라고 강조하셨다.</p><ul><li><p>제 글이 어떤가요<br>
<!-- -->→ 제 글의 주제가 잘 드러났나요?</p></li><li><p>행복이 무엇일까요?
→ 주로 무엇을 하고 있을 때 기분이 좋아요?</p></li><li><p>음악 좋아세요?<br>
<!-- -->→ 요즘 즐겨든는 국내 가수 음악이 있어요?</p></li></ul><p>매니저한테: 저에게 피드백 주실 부분 있으세요?<br>
<!-- -->→ 최근 1주일간 지켜 보시면서(우리는 워너원을 현재 일주일에 한 번씩 한다.),제가 타 팀 협업 또는 팀원간의 커뮤니케이션이 잘 하고 있다고 생각이 드시나요?</p><p><strong>내가 이해한 내용을 설명하며 묻는다</strong></p><p>불확실한 의사소통을 해결하려고 묻는데 상대의 수준을 얕잡아볼 사람은 없다. 오히려 긴가민가하고 넘어갔는데 <strong>문제가 터지면 주워 담기 힘들다.</strong>  </p><p>내가 긴가민가 하면 ‘나만 이해력이 떨어지나?’라고 눈치 볼 필요 없다. 보통 내가 혼란을 느끼면 다른 사람도 비슷한 고충을 겪고 있을 확률이 높다.</p><p>서평 제목을 쓸 때 ‘어른의 문장력'을 읽고… <strong>이런 제목은 무조건 피하자.</strong> 아무도 읽고 싶지 않을 것이다.  </p><ul><li>문자 한 줄이라도 정갈하게 쓰고 싶다면?: 이 책을 추천한다.</li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="형식을-무시하는-사람이-무시당한다">형식을 무시하는 사람이 무시당한다<a href="#형식을-무시하는-사람이-무시당한다" class="hash-link" aria-label="Direct link to 형식을 무시하는 사람이 무시당한다" title="Direct link to 형식을 무시하는 사람이 무시당한다">​</a></h3><p>신청서 양식에 맞게 쓴 사람을 우선 추렸어요. 그랬더니 몇 명 안 남더라고요?(p.190)<br>
<!-- -->‘자기소개를 500자 내로 써주세요’라는 지문에 열정을 담아 1000자를 쓴 사람도 제외시켰다’<br>
<!-- -->‘이메일 주소에 오타를 쓴 사람, 대답 양식을 건너 뛴 사람은 탈락시켰다.’<br>
<!-- -->내용은 얼마든지 꾸며도 태도는 숨기기 어려운 법이다.<br>
<!-- -->기본에만 충실해도 해결되는 많은 일이 있다. 내가 한 번더 움직여서, 상대방을 배려하는 마음을 가지자.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="문장에-허세와-기름기를-빼자">문장에 허세와 기름기를 빼자<a href="#문장에-허세와-기름기를-빼자" class="hash-link" aria-label="Direct link to 문장에 허세와 기름기를 빼자" title="Direct link to 문장에 허세와 기름기를 빼자">​</a></h3><p>허세는 어려운 단어들을 의미하고, 기름기는 과도한 외래어를 의미한다.<br>
<!-- -->읽었을 때 편안한 담백한 문장이 사랑받는다.<br>
<!-- -->부탁을 해야 할 때, 문장 앞 이름을 넣는 것은 반응 속도나, 온도가 미묘하게 달라진다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="생각-안-나-대신-끝까지-찾기">생각 안 나 대신 끝까지 찾기<a href="#생각-안-나-대신-끝까지-찾기" class="hash-link" aria-label="Direct link to 생각 안 나 대신 끝까지 찾기" title="Direct link to 생각 안 나 대신 끝까지 찾기">​</a></h3><p>목표를 손으로 쓸 때 키보드로 쓰는 것보다 글로써 쓰면 목표를 이룰 가능성이 높아진다.<br>
<!-- -->이야기를 하다가 떠오를 듯 말 듯 애태우는 기억을 고이 보내지 말고 메모나, 스마트폰이든 어디든 기록을 해서 어떻게든 떠올리자.</p><p>“그걸 뭐라고 하지, 모든 게 좋은 시기를 이르는…”<br>
<!-- -->“호황?”<br>
<!-- -->“아니, 아니”<br>
<!-- -->“화양연화?”<br>
<!-- -->“아니, 모든 게 더할 나위 없이 좋다 .뭐 그런 뜻인데 ‘뭐뭐’가 따로 없다! 하는 말 있잖아”<br>
<!-- -->“태평성대!”  </p><p>휘발성 기억으로 넘기지 말고, 기록하자.<br>
<!-- -->대충 넘어가면 <strong>‘대충 인간’</strong> 이 된다.</p><h1>느낀점</h1><p>평소 나는 내가 쓴 문장들이 어른의 문장인가라는 고민을 많이 했는데, 이 책이 어른의 문장은 이런거다라고 가이드를 해주어서 너무 좋았다.<br>
<!-- -->특히,‘문장을 쓸 때, 이렇게 쓰지마세요!’라고 끝내지 않고 실제로 자주 사용하는 문장들을 예시로 들고 다듬어 줌으로써, 어른의 문장은 이런 문장이다라고 말을 해주는 부분이 도움이 많이 되었다.<br>
<!-- -->그리고 스스로 액션 아이템이 몇 가지 생겼는데 그 중 하나 비지니스적으로 커뮤니케이션이 필요 할 때 상대방에게 내 의도가 잘 전달되었나? 이상하게 생각하지 않겠지? 이런 고민들을 정말 많이 한다.<br>
<!-- -->그래서 평소에 부족함을 많이 느꼈는데, 이 책을 읽고 개인 액션 아이템으로 회의 전, 또는 대화 전 논의 주제 정리, 보고 정리 즉, 시작 전 글로 쓰고 체크리스트 작성을 남은 하반기 동안 실행 해 볼 것이다.</p>]]></content:encoded>
            <category>books</category>
            <category>adult-literacy</category>
        </item>
        <item>
            <title><![CDATA[프로그래머의 뇌]]></title>
            <link>https://dgle.dev/programmers-brain</link>
            <guid>https://dgle.dev/programmers-brain</guid>
            <pubDate>Sun, 09 Oct 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[프로그래머의 뇌 책을 읽고]]></description>
            <content:encoded><![CDATA[<p>인지과학으로 프로그래머의 입장에서 뇌가 어떻게 반응하는지를 한 번 생각 해 볼 수 있는 책</p><h1><a href="http://www.yes24.com/Product/Goods/105911017" target="_blank" rel="noopener noreferrer">프로그래머의 뇌</a></h1><p>이 책의 목적은 두뇌가 코드를 처리하는 방식을 이해하도록 돕는 것이다.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="코드-잘읽기">코드 잘읽기<a href="#코드-잘읽기" class="hash-link" aria-label="Direct link to 코드 잘읽기" title="Direct link to 코드 잘읽기">​</a></h2><h3 class="anchor anchorWithStickyNavbar_LWe7" id="코드가-초래하는-세-가지-종류의-혼란">코드가 초래하는 세 가지 종류의 혼란<a href="#코드가-초래하는-세-가지-종류의-혼란" class="hash-link" aria-label="Direct link to 코드가 초래하는 세 가지 종류의 혼란" title="Direct link to 코드가 초래하는 세 가지 종류의 혼란">​</a></h3><ol><li>지식의 부족<ul><li>LTM (long-term-memory) 장기 기억 공간에 내용이 없다는 것.<ul><li>반영구적으로 저장하는 곳이다.</li></ul></li></ul></li><li>정보의 부족<ul><li>STM(short-term memory) 단기 기억 공간에 내용이 없다는 것.<ul><li>정보를 수집할 때 단기 기억 장소에 일시적으로 저장하지만, 다른 정보를 찾는 과정에서 이미 수집해놓은 정보 중 일부는 잊어 버린다.</li></ul></li></ul></li><li>처리능력의 부족<ul><li>WM(working memory)<ul><li>많은 정보를 처리할 때 사용</li></ul></li></ul></li></ol><br><p><strong>트레이싱</strong></p><ul><li>머리속에서 코드를 컴파일하고 실행하는 과정을 의미한다.</li></ul><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="프로그래밍-업무와-관련한-인지-사항">프로그래밍 업무와 관련한 인지 사항<a href="#프로그래밍-업무와-관련한-인지-사항" class="hash-link" aria-label="Direct link to 프로그래밍 업무와 관련한 인지 사항" title="Direct link to 프로그래밍 업무와 관련한 인지 사항">​</a></h3><p>버그 리포트로 받는 경우 버그를 고치기위해 몇개월 전 작성한 코드를 다시 읽어야한다.<br>
<!-- -->코드 분석을 할 때 읽는 내용은 <code>STM</code>에 저장되며, 몇 개월 전에 구현한 내용을 <code>LTM</code>에서 가져올 것이다.과거의 경험으로 기억된 내용뿐만아니라 오류의 해결법 같은 정보 역시 <code>LTM</code>에 저장되어 있다.<br>
<!-- -->이 모든 정보, 즉 <code>STM</code>에 저장된 새로운 버그 리포트 내용, 그리고 <code>LTM</code>에 저장된 유사한 버그의 해결법이나 개인적인 기억 두 가지가 다 작업 기억 공간으로 들어오게 되고, 그제서야 당면 문제에 대해 생각 할 수 있게 된다.  </p><p>세 가지 인지 과정</p><ol><li>LTM에서 정보를 인출, 키워드의 의미 같은 것들이 해당</li><li>메서드나 변수의 이름과 같이 코드를 읽는 과정에서 발생하는 정보를 STM 일시적으로 저장</li><li>WM 에서 일어 나는데 코드를 읽고 처리하는 일이 여기서 이루어지는데 예를 들면 ‘인덱스 값이 하나 작다’라고 판단하는 것이다.</li><li>서로서로 이 3가지 과정은 보완적으로 작용한다. STM이 n과 같은 변수명을 보게 되면 과거에 읽었던 그와 관련된 프로그램을 LTM으로부터 찾는다. 모호한 단어를 보면 WM이 활성화되며 문맥 속에서 적합한 의미를 찾으려 한다.</li></ol><p>컴퓨터와 마찬가지로 인간의 STM인지 능력은 LTM보다 훨씬 적다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="청크단위"><strong>청크단위</strong><a href="#청크단위" class="hash-link" aria-label="Direct link to 청크단위" title="Direct link to 청크단위">​</a></h3><p>이미지를 청크단위로 기억을 해서 우리는 STM을 더 효율적으로 사용 할 수 있다.</p><p><code>Ozpq odfj</code>  vs <code>like love</code></p><p>생소한 문자로 글을 작성하면 STM에 저장하는데 한계가 있지만, 뒤에 문자는 여러 개의 문자를 한 단위로 묶어서 기억 했기 때문에 쉽게 기억이 가능하다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="코드에서-청킹"><strong>코드에서 청킹</strong><a href="#코드에서-청킹" class="hash-link" aria-label="Direct link to 코드에서-청킹" title="Direct link to 코드에서-청킹">​</a></h3><p>디자인패턴이 한 요소가 될 수 있다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="주석문"><strong>주석문</strong><a href="#주석문" class="hash-link" aria-label="Direct link to 주석문" title="Direct link to 주석문">​</a></h3><p>일반적으로 개발자들은 주석문을 포함하고 있으면 코드를 읽는 시간이 더 많이 들어간다고 한다. 하지만 이는 개발자들이 주석문을 읽는다는 사실을 시사한다. 이것은 최소한 의미없는 일이 아니라는 것을 보여준다. 코르시비의 연구에 따르면 코드에 주석문이 있으면 <code>새로운 팀원</code>이 코드를 쉽게 이해할 수 있다라고 한다.</p><p>주석문은 초급 개발자가 코드를 이해하는 데도 도움이 되지만, 개발자가 코드를 청킹하는 방식에도 영향을 미친다. 취인 판의 연구에 따르면 개발자들은 코드를 읽을 때 주석문에 굉장히 많이 의존한다. 특히 이 함수는 주어진 이진 트리를 중위 순회하며 프린트한다. 같은 <strong>고수준 주석문</strong>은 코드를 청크 단위로 쪼개는 데 도움이 된다. 반면 i++; 다음에 i를 1만큼 증가’ 같은 <strong>저수준 주석문</strong>을 넣는 것은 오히려 청킨 작업에 부담이 된다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="청킹-연습">청킹 연습<a href="#청킹-연습" class="hash-link" aria-label="Direct link to 청킹 연습" title="Direct link to 청킹 연습">​</a></h3><p><strong>의도적 연습(deliberate practice)은</strong> 어떤 기술을 향상하기 위해 조금씩 연습하는 것을 의미.</p><ol><li>코드 선정<ul><li>어느 정도 익숙해져 있는 코드베이스를 하나 고르기. 정기적으로 작업하지만 주로 작업하지 않는 코드베이스면 좋다. 본인이 오래전에 작성한 코드라도 상관없다. 최대 50라인을 넘지 않도록 해야 한다.</li></ul></li><li>코드 파악<ul><li>2분을 넘지 않도록 타이머를 설정하고 코드를 파악해라. 시간이 다 되면 코드는 보지 않는다.</li></ul></li><li>코드 재현<ul><li>IDE에 기억을 되살려 코드를 작성해보자</li></ul></li><li>회고<ul><li>어느 부분을 쉽게 기억했는가?</li><li>부분적으로 기억한 코드가 있는가?</li><li>전체를 다 기억하지 못한 코드가 있는가?</li><li>기억하지 못한 라인들이 있다면 그 이유는 무엇일까?</li><li>기억하지 못한 라인에 본인이 익숙하지 않은 프로그래밍 개념 들어 있지 않는가?</li><li>기억하지 못한 라인에 본인이 익숙하지 않은 도메인 지식이 있나?</li></ul></li></ol><p>option으로 다른사람이랑 같이 비교해보는 것도 좋다. 자신의 실력을 판단 할 수 있는 근거가 될 수 있다.</p><p><code>자료구조, 디자인패턴, 문법을 아는 부분이 중요한 이유가 코를 효율적으로 읽고 이해하는데 상당한 영향을 미친다.</code> ← STM에 해당하는 부분</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="업무-중단이-미치는-나쁜-영향">업무 중단이 미치는 나쁜 영향<a href="#업무-중단이-미치는-나쁜-영향" class="hash-link" aria-label="Direct link to 업무 중단이 미치는 나쁜 영향" title="Direct link to 업무 중단이 미치는 나쁜 영향">​</a></h3><p>파닌 교수는 업무 도중 주단이 되면 프로그래머에 어떤 일이 일어나는지 연구 했고 업무 중 도중 중단이 되고 되돌아 가는데 15분 정도 걸렸다고 한다.(p.38)</p><p>이건 평소 내가 생각했던 생각이랑 다른 시각인데 난 평소에 문법을 검색을 하면 되지 않나? 대충 알고만 있으면 검색을 해서 적용 할 수 있지 않나라고 생각을 할 수 있지만 이게 계속 반복되다보면 다시 일을 복귀 할 때 컨텍스트 스위칭이 내 생각보다 오래 걸릴 수도 있다는 개념이 신선했다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="문법을-빠르게-배우는-법">문법을 빠르게 배우는 법<a href="#문법을-빠르게-배우는-법" class="hash-link" aria-label="Direct link to 문법을 빠르게 배우는 법" title="Direct link to 문법을 빠르게 배우는 법">​</a></h3><p>플래시카드 기법 앞에 암기하려고 하는 내용에 대한 프롬포트, 즉 그것을 지칭하는 단어나 질문이 있고 뒷면에는 그에 대한 내용이나 답이 있다.</p><p>ex) 기본 문법 → numbers = <!-- -->[ x for x in numbers]</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  필터         → odd_numbers = [x for x in numbers if x % 2 = 1 ]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>플래시카드 기법은 내가 새로운 업무에 조인을 할 때도 유용할 거 같다. 특히 새로운 도메인 안익숙한 도메인에 조인을 할 때도 새로운 개념이 나오면 알아야하는 용어들을 앞에 적고 뒤에 적는 방식으로 조금 더 빠르게 개념을 이해 할 수 있을 거 같다.
(이번주에 적용 해보기!)</p><p>일반적으로 STM에 있는 것들을 LTM에 집어 넣으려면 한 달에 한 번씩 복습을 해야한다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="정보를-외우는-것은-기억을-강화한다">정보를 외우는 것은 기억을 강화한다.<a href="#정보를-외우는-것은-기억을-강화한다" class="hash-link" aria-label="Direct link to 정보를 외우는 것은 기억을 강화한다." title="Direct link to 정보를 외우는 것은 기억을 강화한다.">​</a></h3><p><strong>인출 강도</strong></p><ul><li>무언가를 기억해내려고 할 때 나오는 강도<ul><li>filter() 함수를 기억을 하고 잇지만 막상 잘 기억을 못한다면 인출강도가 낮도가 얘기한다.</li><li>시간이 흐를수록 약해진다</li></ul></li></ul><br><p><strong>저장 강도</strong></p><ul><li>LTM에 얼마나 잘 저장하고 있는가를 나타낸다.</li></ul><p>인출을 하려고 노력을 해야한다.<br>
<!-- -->능동적으로 생각을 할 때 인출의 강도는 높아진다.<br>
<!-- -->너무 쉽게 정보를 찾고 또 그것이 너무 일상적으로 이뤄지다 보니 우리 두뇌는 문법을 기억할 필요가 없다고 느낀다.</p><p>구글 검색하기 전에 먼저 능동적으로 의도적으로 기억하려고 시도해보자. 항상 떠올리려고 생각을 해야 내 것이 되는거 같다는 걸 많이 느꼈었다.</p><p>프로그래밍 개념을 새로 배울 때 적용 해볼 만 한 내용</p><ul><li>새로운 개념이 어떤 다른 개념을 생각나게 했는가? 적어보기</li><li>위에서 적은 관련된 개념에 대해 다음 질문에 답해보기<ul><li>새로운 개념은 왜 이미 알고 있는 그 개념을 생각나게 했을까?</li><li>문법에 공통적인 점이 있는가?</li><li>비슷한 환경에서 사용될 수 있는가?</li><li>이 새로운 개념은 이미 알고 있는 그 개념 대신 사용될 수 있는가?</li><li>동일한 목적을 달성하기 이해 작성할 수 있는 다른 방법을 코드를 알고 있는가? 같은 결과를 갖는 비슷한 코드를 최대한 많이 만들어봐라.</li><li>다른 프로그래밍 언어에서 같은 개념이 있는가? 비슷한 동작을 수행하는 다른 언어의 예제 코드를 작성할 수 있는가? 서로 어떻게 다른가?</li></ul></li></ul><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="인지-부하"><strong>인지 부하</strong><a href="#인지-부하" class="hash-link" aria-label="Direct link to 인지-부하" title="Direct link to 인지-부하">​</a></h3><p>인지 부하에는 크게 내재적 인지부하 외재적 인지부하가 있다.<br>
<!-- -->내재적 인지 부하는 내가 이지식을 알고 있냐 모르고 있냐의 차이고<br>
<!-- -->외재적 인지 부하는 지식은 있지만 그걸 적용 할 때 따르는 부하이다.<br>
<!-- -->ex) ( for int v = i / 2;  ; v++;) for 문을 알고 있지만 그 안에 내용이 생소할 경우 나타나는 부하이다.</p><br><p><strong>인지 부하를 줄이는 법</strong></p><ol><li>리팩터링</li><li>코드를 여러번 읽어도 이해가 안된다면 어디서 부터 중점을 두고 읽어야할지 모르는 것이다. 큰 그림을 이해 못 한거일 것이다. 이럴 땐 보조수단을 사용하면 좋다.<ul><li>의존그래프를 그려보자</li><li>정 이해가 안되면 프린트해서 원을 그려보자</li><li>원을 연결하고 선을 이어서 보자</li></ul></li></ol><p>알고리즘 공부할 떄 써먹을 수 있겠다. 상태표를 그리고 그안에 나타나는 모든 변수들을 기입하자. 그리고 그 안에서의 흐름을 적어보자 loop문을 적고 그 때의 나타나는 변환을 적어보자. tip 어떤 변수는 생략하고 지나가고 싶을 때 생략하지말고 최대한 자세히 적자.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="코드-잘-읽기">코드 잘 읽기<a href="#코드-잘-읽기" class="hash-link" aria-label="Direct link to 코드 잘 읽기" title="Direct link to 코드 잘 읽기">​</a></h2><h3 class="anchor anchorWithStickyNavbar_LWe7" id="기존-지식의-활성화"><strong>기존 지식의 활성화</strong><a href="#기존-지식의-활성화" class="hash-link" aria-label="Direct link to 기존-지식의-활성화" title="Direct link to 기존-지식의-활성화">​</a></h3><p>익숙하지 않은 코드를 미리 정한 시간, 5분이나 10분 정도만 봐라 그리고 다음과 같이 질문을 하라</p><ul><li>가장 먼저 시선을 끈 코드 구성요소(변수, 클래스, 프로그래밍 개념등)은 무엇인가?</li><li>왜 그런가?</li><li>두 번째로 주의를 끈 것은 무엇인가?</li><li>왜 그런가?</li><li>그 두 가지(변수 ,클래스 , 프로그래밍 개념 등)는 서로 관련이 있는가?</li><li>코드에 어떤 개념들이 존재하는가? 그 개념 요소들은 다 알고 있는가?</li><li>코드에 어떤 문법 요소들이 존재하는가? 그 문법 요소들은 다 알고 있는가?</li><li>코드에 어떤 도메인 개념들이 존재하는가? 그것들을 다 알고 잇는가?</li></ul><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="모니터링"><strong>모니터링</strong><a href="#모니터링" class="hash-link" aria-label="Direct link to 모니터링" title="Direct link to 모니터링">​</a></h3><p>코드를 읽을 때는 무엇을 읽고 있는지, 이해는 하고 잇는지를 계속 추적 하는것이 중요하다. 코드를 프린트를 해서 이해되는 라인과 이해되지 않는 라인을 표시하는 것도 좋은 방법이다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="코드리뷰할-때-적용-해볼-수-있는-요소"><strong>코드리뷰할 때 적용 해볼 수 있는 요소</strong><a href="#코드리뷰할-때-적용-해볼-수-있는-요소" class="hash-link" aria-label="Direct link to 코드리뷰할-때-적용-해볼-수-있는-요소" title="Direct link to 코드리뷰할-때-적용-해볼-수-있는-요소">​</a></h3><ul><li>코드 작성자가 내린 결정 사항이 무엇인가? 에를 들어 특정 라이브러리나 api를 사용하기로 한 결정, 자료구조, 특정 디자인패턴 등</li><li>그런 결정을 내리는 데 상정한 가정은 무엇인가</li><li>그 결정의 효과는 ?</li><li>그 결정의 잠재적 위험 요소는 무엇인가</li><li>다른 해결책으로  어떤 것이 있을까?</li></ul><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="정신-모델">정신 모델<a href="#정신-모델" class="hash-link" aria-label="Direct link to 정신 모델" title="Direct link to 정신 모델">​</a></h3><p>문제에 대해 생각할 때 두뇌의 외부에서 만들어지지 않은 모델을 말함.
폴더 구조를 생각 할 때를 예로 들 수 있는데 실제로는 0과 1로 이루어 졌지만 모델로 입혀서 생각을 할 때라고 생각하면된다.
잘못된 정신모델이 LTM에서 완전히 제거가 안되고 남아있을 수 있다. </p><p><strong>복잡한 코드에 대한 정신 모델 작업</strong></p><ol><li>국지적 모델을 만든다.<ul><li>큰 개념을 먼저 만든다.</li><li>서로 밀접하게 관련되어 있는 라인을 하나의 의존 그래프로 나타낸다고 할 때 이 의존 그래프는 정신 모델을 형성하는 데 중요한 역할을 할 수 있다.</li></ul></li><li>코드에서 관련된 모든 객체와 객체 간의 관계를 나열한다.<ul><li>코드내에서 객체간에 상호작용을 화이트보드나 디지털 도구를 사용하여 구성 요소를 나열한 다음 그들 사이의 관계를 찾아야 한다.</li></ul></li><li>시스템에 대한 질문을 만들고 이 질문의 답을 사용해서 모델을 개선한다.<ul><li>시스템에서 가장 중요한 요소는 무엇인가? 모델에 그것들이 포함되어 있나?</li><li>이 중요한 요소들 사이의 관계는 무엇인가?<ul><li>내가 생각 했을 땐 쿠폰이라는 큰 개념이 있고 그 쿠폰에 해당하는 여러 사항들 사용자는 하나의 쿠폰만 쓸 수 있다. 이런 요소요소들의 관계를 적어야한다.</li></ul></li><li>프로그램의 주요 목표는 무엇인가?</li><li>목표가 핵심 요소 및 그 관계와 어떻게 관련되어 있는가?</li><li>일반적인 사용 사례는 무엇인가? 모델이 그것을 보여주는가?</li></ul></li></ol><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="개념적기계">개념적기계<a href="#개념적기계" class="hash-link" aria-label="Direct link to 개념적기계" title="Direct link to 개념적기계">​</a></h3><ul><li>스키타마 - LTM이 정보를 저장하는 방식이다. 연상을 하고 집어 넣으면 거기에 맞게 조금 더 쉽게 이해를 할 수 있다. 예를 들어 변수를 상자로 설명을 하는 식의 그러나 이러한 점은 때로는 안좋을 수가 있는데 박스에는 여러 값들이 들어갈 수도 있다. 밀접한 정식 모델을 가지고 있으면 (변수 - 상자) 조금 더 외우기 쉬워진다 반대로 뜬금없이 외발자전거 - 변수 이렇게 연관해버리면 이해하기가 어렵다</li></ul><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="새로운-언어를-배울-때">새로운 언어를 배울 때<a href="#새로운-언어를-배울-때" class="hash-link" aria-label="Direct link to 새로운 언어를 배울 때" title="Direct link to 새로운 언어를 배울 때">​</a></h3><p>새로운 언어를 배우면 기존에 알고 있던 언어를 LTM에서 유사한 점을 가져와서 STM을 적게 사용하고 작업공간을 효율적으로 사용을해서 조금 더 사용 할 수 있다. 또한 작업에 대한 감정이 좋았었다면 새로운 작업이 주어 졌을 때 과거에 사용했던 알고리즘, 여러 같은 방식을 사용하게 될 확률이 높다.</p><p>앞에가 긍정적 전이였으면, 부정적 전이도 있다. 오히려 한 언어에서 다른 언어로의 부정적 전이가 될 수 있다. </p><p>꼭 여러 언어를 안다고 지능이 높아지는 건 아니다(체스선수의 예로… ) </p><p>공통점과 차이점에 의식적으로 주의를 기울이면 새로운 언어를 배우는 일이 쉬워질 것이다.</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">                      유사점              차이점             비고 </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ol><li>문법       </li><li>타입 </li><li>프로그래밍 개념</li><li>런타임</li><li>ide</li><li>테스트 방식</li></ol><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="오개념">오개념<a href="#오개념" class="hash-link" aria-label="Direct link to 오개념" title="Direct link to 오개념">​</a></h3><p><code>자신이 옳다고 확신하지만 실제로는 틀릴 때 오개념을 갖게 된다.</code> 오개념은 단순히 자신이 틀렸다는 것을 꺠닫거나 듣는 것만으로는 해결되지 않는다. 오래되고 잘못된 정신모델을 대체할 새로운 모델이 필요하다.</p><p>고기의 표면이 타면 수분은 오히려 날라간다!  알고 있는 거와 다르게 수분 손실이 더욱 크다.</p><p>알고있는 언어에서 새로운 언어를 배울 때 기존의 지식을 떨쳐내기  위해 많은 에너지를 소비해야 한다. 개념적인 변화가 필요하기 때문에 시간이 오래걸린다. <code>우리가 똑똑하지! 못해서가</code> 아니라 <code>부정적인 전이</code>가 돼서 그렇다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="오개념-방지하기">오개념 방지하기<a href="#오개념-방지하기" class="hash-link" aria-label="Direct link to 오개념 방지하기" title="Direct link to 오개념 방지하기">​</a></h3><p><code>자신이 옳다고 확신하더라도 여전히 틀릴 수도 있따는 것을 아는 것이 중요하다. 열린 마음</code></p><p>흔하게 발생하는 오개념에 대해 의도적으로 연구해봄으로써 그런 오개념에 빠지는 것을 방지 할수 있다. 오개념들에 대한 체크리스트를 사용하는 것이 도움이 될 수 있다. 같은 프로그래밍 언어를 같은 순서로 학습한 다른 프로그래머들에게 조언을 구하는 것이다. </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="검색을-할-때">검색을 할 때<a href="#검색을-할-때" class="hash-link" aria-label="Direct link to 검색을 할 때" title="Direct link to 검색을 할 때">​</a></h3><p>검색은 STM에 무리가 간다. 그래서 이러한 부하를 줄이기 위해 별도의 문서나 노트를 작성하면 도움이 된다. 만약 코드 내에서 살펴 볼 때는 특정 코드를 살펴본 이유를 주석문으로 작성해놓으면 도움이 된다. 나중에 동일한 코드를 검색하고 확인할 때 도움이 될 수 있다. </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="업무-중단에-잘-대비하는-법">업무 중단에 잘 대비하는 법<a href="#업무-중단에-잘-대비하는-법" class="hash-link" aria-label="Direct link to 업무 중단에 잘 대비하는 법" title="Direct link to 업무 중단에 잘 대비하는 법">​</a></h3><ol><li>정신모델 저장<ul><li>코드를 작성 중에 잠시 중단요청이 들어 옸다면 주석문을 작성하자. 그러면 나중에 작업을 쉽게 재개할 수 있다.</li></ul></li><li>미래 기억 향상<ul><li>계획을 완성 할 수 없다면 TODO 문을 적극적으로 사용하자. 기한을 정해 놓으면 더 좋다.</li></ul></li><li>하위 목표 라벨 붙이기<ul><li>하위 목표를 잘 나누자. 큰 부분에 일을 작은 부분의 문제로 쪼개 놓자.</li></ul></li></ol><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="멀티테스킹">멀티테스킹<a href="#멀티테스킹" class="hash-link" aria-label="Direct link to 멀티테스킹" title="Direct link to 멀티테스킹">​</a></h3><p>인스턴트 메신저(페이스북) 특히 메세지를 받는 즉시 답장한다고 응답한 학생들이 상대적으로 매우 생산적이라고느끼지만 수행 능력은 떨어졌다.</p><p>방해를 받더라도 가급적이면 인지 부하가 낮을 때 중단이 일어나도록 해야 한다. 예를 들어 슬랙에서 상태를 설정한다던지.</p><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="새로운-뉴비-개발자-온보딩">새로운 뉴비 개발자 온보딩<a href="#새로운-뉴비-개발자-온보딩" class="hash-link" aria-label="Direct link to 새로운 뉴비 개발자 온보딩" title="Direct link to 새로운 뉴비 개발자 온보딩">​</a></h2><p>흔한 문제점으로 새로온 뉴비 개발자에게 한 번에 많은 정보들을 준다. 예를 들어 코드베이스, 도메인, 워크플로 등 여러가지 많은 정보를 주게 되는데 이는 인지 과부화를 초래하여 새로운 정보를 기억할 공간이 없어서 적응에 어려움을 겪게 된다. 그리고 새 팀원에게 질문을 하거나 과제를 주게 되는데 선임 개발자는 이것이 그냥 흔한 작은 버그를 고치는 과제였겠지만 이는 양쪽 모두 좌절감을 주게 된다. 새로운 팀원은 매우 어려운 프로젝트라고 생각이되고 선임 팀원은 똑독하지 않다고 생각이 되며, 이는 팀워크가 앞으로 잘 이뤄질 것이라고 기대하기 어렵다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="작업은-하나의-프로그래밍-활동으로만-제한"><strong>작업은 하나의 프로그래밍 활동으로만 제한</strong><a href="#작업은-하나의-프로그래밍-활동으로만-제한" class="hash-link" aria-label="Direct link to 작업은-하나의-프로그래밍-활동으로만-제한" title="Direct link to 작업은-하나의-프로그래밍-활동으로만-제한">​</a></h3><p>탐구 - 코드베이스의 전체적인 이해를 위한 코드 훑어보기
검색 - 특정 인터페이스를 구현한 클래스 찾기
전사 - 구현할 메서드에 대한 명확한 계획을 알려주기
이해 - 코드의 여러 측면에 대해 이해하기, 예를 들면 특정 메서드를 요약하기
증가 - 향후 계획을 포함해서 기존 클래스에 한 가지 기능을 추가하기
적응 기간에는, 구체적으로 다섯 가지 범주 각각에 해당하는 활동을 선택하고 새 팀원에게 하씩 시키는 것이 가장 좋다.</p><p>만드는 것보다 이해를 하는 것이 더 좋을 떄도 있다</p><ul><li>새 팀원이 코드의 특정 부분을 이해하길 원하면 구현 작업 대신, 해당 코드를 이해하도록 요청해야 한다. 예를 들어 기존 클래스의 요약을 작성하거나 특정 기능이 실행에 참여하는 모든 클래스를 기록하도록 요청한다.</li></ul><p><code>새로운 개념을 배우는 사람들은 추상적인 용어와 구체적인 에를 모두 배울 필요가 있다. 또한 새로 배운 개념을 기존 지식과 연결할 시간이 필요하다.</code></p><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="후기">후기<a href="#후기" class="hash-link" aria-label="Direct link to 후기" title="Direct link to 후기">​</a></h2>]]></content:encoded>
            <category>books</category>
            <category>programmers-brain</category>
        </item>
        <item>
            <title><![CDATA[DDD-Start를 읽고!]]></title>
            <link>https://dgle.dev/DDD-start</link>
            <guid>https://dgle.dev/DDD-start</guid>
            <pubDate>Mon, 03 Oct 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[DDDStart 책을 읽고 적용 할 거리를 정리]]></description>
            <content:encoded><![CDATA[<p>예전 부터 아껴놓다가 드디어 한 번 읽어보는 DDD Start!</p><h1><a href="http://www.yes24.com/Product/Goods/108431347" target="_blank" rel="noopener noreferrer">DDD-START</a></h1><p><a href="http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&amp;ejkGb=KOR&amp;barcode=9791158390174" target="_blank" rel="noopener noreferrer">마틴 파울러 엔터프라이즈 애플리케이션 아키텍처 패턴</a></p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="도메인-모델시작하기">도메인 모델시작하기<a href="#도메인-모델시작하기" class="hash-link" aria-label="Direct link to 도메인 모델시작하기" title="Direct link to 도메인 모델시작하기">​</a></h2><ol><li>Get/Set method 습관 X<ul><li>의미 있는 단어로 사용</li></ul></li><li>불변 객체 사용하기</li><li>생성자를 적극적으로<ul><li>객체를 비지니스적으로 불완전한하게 시작하지 말자 만약 불완전하게 시작이 된다면 그때는 리팩토링을 생각해보자.</li></ul></li><li><a href="https://martinfowler.com/bliki/UbiquitousLanguage.html" target="_blank" rel="noopener noreferrer">유비쿼터스 언어</a> <ul><li>전문가 관게자 개발자 도메인과 관련된 공통의 언어를 만들고 이를 대화, 문서 도메인모델, 코드 테스트 등 모든 곳에서 같은 용어를 사용한다. 이렇게 하면 소통의 모호함이 줄어들고 불필요한 해석 과정을 줄일 수 이싿.</li></ul></li><li>도메인 용어에 알맞은 단어를 찾는 시간을 아까워 하지 말자.</li></ol><br><p>인프라스트럭처 영역은 구현 기술에 대한 것을 다룬다. RDMS 연동을 처리하거나 메시징 큐에 메세지를 전송하거나 수신하는 기능, 몽고 DB나 redis와의 데이터 연동을 처리한다. SMTP를 이용한 메세지 발송 기능을 구현하거나 http클라이언트를 이용해서 rest api를 호출하는 것도 처리한다. 실제 구현을 다룬다. <code>도메인 영역, 응용 영역, 표현 역역은 구현 기술을 사용한 코드를 직접 만들지 않는다. 대신 인프라스트럭처 영역에서 제공하는 기능을 사용해서 필요한 기능을 개발한다.</code> </p><br><p><img loading="lazy" alt="계층 구조" src="/assets/images/Untitled-99f406139a08d2a7d39ee557a88aaf2c.png" width="334" height="912" class="img_ev3q"></p><br><p><strong>계층 구조</strong>
<code>고수준 모듈</code>은 의미있는 단일 기능을 제공하는 모듈, <code>저수준 모듈</code>은 하위 기능을 실제로 구현하는것. 고수준 모듈이 저수준 모듈을 의존하면 안된다. 그러면 테스트도 어렵고 구현 변경이 어려워진다. </p><p><strong>DIP</strong></p><p>DIP를 잘못 생각하면 단순히 인터페이스와 구현 클래스를 분리하는 정도로 받아드릴 수 있다. 핵심은 고수준 모듈이 저수준 모듈에 의존하지 않도록 하는 것이다.<br>
<!-- -->계층 구조에서 생각해봤을 때 도메인에서 인프라스트럭처를 의존하면 안된다. DIP를 생각해야한다. (p.76)<br>
<!-- -->도메인에 interface를 집어 넣고 인프라에서 그걸 의존받아 구현하게 만들어야한다.  </p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p>💡 그렇다고 무조건 <strong>DIP</strong>를 고집하진 말자 때로는 의존적인 코드를 도메인에 일부 포함하는 게 효과적일 때가 있다.</p></div></div><p><strong>엔티티</strong> </p><p>주문, 회원, 상품과 같이 도메인의 고유한 개념을 표현.  </p><p><strong>벨류</strong> </p><p>배송지 주소를 표현하기 위한 주소Address, Money와 같은 타입이 밸류  </p><br><p><strong>애그리거트</strong></p><p>엔티티와 밸류 객체를 개념적으로 하나로 묶은 것. Order Entity, OrderLine, Orderer ‘주문’ 애그리거트로 묶을 수 있다.<br>
<!-- -->에그리거트가 잘 되어있으면 복잡한 도메인도 사위 수준에서 모델 간의 관계를 더 잘 파악할 수 있다. (p.99)<br>
<!-- -->경계가 설정할 때 기본이 되는 것은 도메인 규칙과 요구사항이다. 도메인 규칙에 따라 함꼐 생성되는 구성요소는 한 에그리거트에 속할 가능성이 높다.
함께 변경되는 빈도가 높은 객체는 한 애그리거트에 속할 가능성이 높다. 예를 들어 주문에 상품 개수, 배송지 정보, 주문자 정보, 주문 금액 등이 될 수 있다.<br>
<!-- -->흔히 ‘A가 B를 갖는다’로 설계할 수 있는 요구사항이 있다면 A와 B를 한 애그리거트로 묶어서 생각하기 쉬운데, 항상 그런것은 아니다 좋은 예가 상품과 리뷰이다.<br>
<!-- -->상품 상세 페이지에 들어가면 상세 정보와 리뷰 내용을 보여줘야한다는 요구사항이 있을 때 Product와 Review 엔티티가 한 애그리거트에 속한다고 생각 할 수 있으나 함께 생성되지 않고, 변경될때 한번에 변경되지 않는다. 주체도 다르다 Prodcut는 변경자가 상품 담당자라면  Review는 생성과 변경하는 주체는 고객이다.  </p><br><p><strong>에그리거트 루트</strong><br>
<!-- -->에그리거트에 속한 모든 객체가 일관된 상태를 유지하도록 전체를 관리하는 주체 (p.104)  </p><br><p><strong>트랜잭션</strong><br>
<!-- -->웬만하면 에그리거트에서 트랜잭션을 한 에그리거트만 변경하자. 응용 서비스에서 수정하도록 구현하자. 자신의 책임 범위를 넘어 다른 애그리거트의 상태까지 관리하는 꼴이된다. </p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>한 번에 여러 에그리거트를 변경할 예외상황이 있을 수 있다</div><div class="admonitionContent_S0QG"><ol><li>팀 표준: 팀이나 조직의 표준에 따라 사용자 유스케이스와 관련된 응용 서비스의 기능을 한 트랜잭션에 실행해야 하는 경우가 있다.</li><li>기술 제약: 이벤트 방식을 도입할 수 없는 경우라면 다수의 트랜잭션을 일관되게 처리해야한다.</li><li>UI 구현의 편리: 운영자의 편리함을 위해 주문 목록 화면에서 여러 주문의 상태를 한 번에변경하고 싶을 것이다. 이경우 한 트랜잭션에서 여러 주문 애그리거트의 상태를 변경해야 한다.</li></ol></div></div><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="리포지터리와-애그리거트">리포지터리와 애그리거트<a href="#리포지터리와-애그리거트" class="hash-link" aria-label="Direct link to 리포지터리와 애그리거트" title="Direct link to 리포지터리와 애그리거트">​</a></h3><p>애그거트는 개념상 한개의 도메인 모델을 표현하므로 객체의 영속성을 처리하는 리포지터리와 애그리거트 단위로 존재한다. Order와 OrderLine을 물리적으로 각각 별도의 DB에 저장한다고 해서 <strong>각각 따로 리포지토리를 만들진 않는다.</strong> Order는 애그리거트 루트고 OrderLine은 애그리거트에 속하는 구성요소이므로 Order위한 리포지터리만 존재한다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="외래키id로-참조하도록-entity를-설계하면--장점">외래키(ID)로 참조하도록 entity를 설계하면  장점<a href="#외래키id로-참조하도록-entity를-설계하면--장점" class="hash-link" aria-label="Direct link to 외래키(ID)로 참조하도록 entity를 설계하면  장점" title="Direct link to 외래키(ID)로 참조하도록 entity를 설계하면  장점">​</a></h3><ol><li>애그리거트간의 의존 결합도를 낮춘다.</li><li>직접 참조하면 성능에 관련된 여러 고민들을 안해도된다. 지연로딩, 즉시로딩과 같은.</li><li>단일 DB를 안써도 된다.확장성에 좋다 에그리트별로 다른 db를 사용 할 수 있다.</li></ol><p>ID를 이용해서 사용하면 즉시 로딩 지연로딩을 고민할 필요 없어지고 구현 복잡도도 낮아진다. 경계도 명확해지기 때문에 모델의 복잡도도 낮춰준다. (p.116)</p><p>애그리거트가 갖고 있는 데이터를 이용해서 다른 애그리거트를 생성해야 된다면 애그리거트에 팩토리 메서드를 구현하는 것을 고려해 보자. 도메인 응집도가 높아지는 효과가 있다. (p.126)</p><p>entity에서 기본생성자를 제공해야하는 이유는 DB에서 데이터를 읽어와 매핑된 객체를 생성할 때 기본 생성자를 이용해서 객체를 생성하기 때문이다 jpa 프로바이더가 객체를 생성할 때만 사용한다. </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="cqrs">CQRS<a href="#cqrs" class="hash-link" aria-label="Direct link to CQRS" title="Direct link to CQRS">​</a></h3><p>명령모델과 조회모델을 분리하는 패턴이다. 명령 모델은 상태를 변경하는 기능을 구현할 때 사용하고 조회 모델은 데이터를 조회하는 기능을 구현할 때 사용한다. </p><p>조회 모델을 구현할 때 JPA를 사용할 때도 있고 마이바티스를 사용할 때도 있고 JdbcTemplate을 사용할 수 있다. 맞춰서 사용하자. 꼭 Jpa만 사용하지 말자.</p><br><p><strong>조회쿼리 깔끔하게 작성하는 법</strong>
<a href="https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/" target="_blank" rel="noopener noreferrer">Spec</a>을 사용하면 코드를 깔-끔하게 조회 쿼리에서 사용 할 수 있다.  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">OrderSummarySpecs</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token class-name">Specification</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">OrderSummary</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ordererId</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token plain"> ordererId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Root</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">OrderSummary</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">CriteriaQuery</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> query</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">CriteriaBuilder</span><span class="token plain"> cb</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                cb</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">equal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"ordererId"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ordererId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token class-name">Specification</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">OrderSummary</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">orderDateBetween</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">LocalDateTime</span><span class="token plain"> from</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">LocalDateTime</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">to</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Root</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">OrderSummary</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> root</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">CriteriaQuery</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> query</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">CriteriaBuilder</span><span class="token plain"> cb</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> cb</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">between</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">OrderSummary_</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">orderDate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> from</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">to</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">OrderSummary</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> results </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> orderSummaryDao</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">findAll</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">spec</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">assertThat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">results</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">hasSize</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>코드 출처  <a href="https://github.com/madvirus/ddd-start2" target="_blank" rel="noopener noreferrer">https://github.com/madvirus/ddd-start2</a></p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="응용-서비스의-크기">응용 서비스의 크기<a href="#응용-서비스의-크기" class="hash-link" aria-label="Direct link to 응용 서비스의 크기" title="Direct link to 응용 서비스의 크기">​</a></h3><p>크게 두 가지 방법으로 응용 서비스를 만드는데</p><ol><li><p>한 응용 서비스 클래스에 한 도메인의 모든 기능 구현</p><ol><li>장점<ul><li>중복 코드를 없앨 수 있음.</li></ul></li><li>단점<ul><li>코드의 줄 수가 길어진다.</li><li>관련 없는 코드들이 많아서  코드 이해하는데 시간이 오래 걸릴 수가 있다.</li></ul></li></ol></li><li><p>구분되는 기능별로 응용 서비스 클래스를 따로 구현하기</p><ol><li>장점<ul><li>코드라인을 깔끔하게 유지 할 수 있다.</li></ul></li><li>단점<ul><li>중복 코드가 있을 수 있다.</li><li>자칫 클랙스가 너무 많아 질 수 있다.</li></ul></li></ol><p>단점 극복 </p><ul><li>중복 코드는 helper클래스를 따로 두어서 해결 할 수 있다 (MemberCheckHelper.validateMember)</li><li>클래스 많아 지는 부분은 알딱깔짝센</li></ul></li></ol><br><p><strong>Impl이 필요한가?</strong>  </p><p>오-래전에는 Dynamic Proxy를 사용해서 reflaction을 proxy가 구현됐지만 지금은 알아서 cglib로 사용하기 바이트코드 조작으로 사용하기 Proxy를 구현하기 때문에 인터페이스를 사용하여 상속 받을 일 없으면 안써도 괜찮다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="도메인-서비스">도메인 서비스<a href="#도메인-서비스" class="hash-link" aria-label="Direct link to 도메인 서비스" title="Direct link to 도메인 서비스">​</a></h3><p>도메인 서비스는 도메인 영역에서 위치한 도메인 로직을 표현할 때 사용. 로직을 실행 할 때 주체가 모호 할 때 도메인영역에 서비스를 넣을 수 있다.</p><p>도메인에 도메인서비스를 주입하지 말자. 메소드로 주입하게 처리하자. (p.239)</p><p><strong>도메인 로직인지 도메인 서비스 로직인지 햇갈린다면</strong> </p><p>상태를 변경하는건지 계산하는건지 생각을 해보자. 상태를 변경하면 도메인에 들어가고 계산을 하게된다면 도메인 서비스 로직에 들어가는 게 코드 유지보수하기가 좋다.</p><p><strong>Find 함수에도 version을 강제로 증가 시킬 수 있다</strong></p><p>애그리거트루트에 값이 변경이 안되었어도 다른 애그리거트가 변경이 된다면 버전을 업데이트 해줘야한다. 이 때 find 함수 안에 강제로 version 증가 할 수 있도록 LockModeType 인자가 있다</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="offline-pessimisitic-lock"><strong><a href="https://www.baeldung.com/cs/offline-concurrency-control" target="_blank" rel="noopener noreferrer">Offline Pessimisitic Lock</a></strong><a href="#offline-pessimisitic-lock" class="hash-link" aria-label="Direct link to offline-pessimisitic-lock" title="Direct link to offline-pessimisitic-lock">​</a></h3><p>비관적인락과 낙관적인락 보다 더 엄격하게 lock을 거는 방법이다. 컨셉은 조회 할 때부터 락테이블을 만들고 지금 조회중이면 락테이블을 update를 해서 선점을 표시하고, 다른 트랜잭션이 조회를 못하도록 하는 방식이다. 이 방식은 여러 고려사항을 해야하는데 최대 lock잠금 시간을 얼마나 해야 하는지와 선점을 하지 못한 트랜잭션은 어떻게 해야할지가 고려대상이다. 선점을 하지 못한 트랜잭션이 스핀락 문제가 발생 할 수도 있으니 주의 해야한다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="바운디드-컨텍스트-p278">바운디드 컨텍스트 p.278<a href="#바운디드-컨텍스트-p278" class="hash-link" aria-label="Direct link to 바운디드 컨텍스트 p.278" title="Direct link to 바운디드 컨텍스트 p.278">​</a></h3><p>모델의 경계를 결정하며 한 개의 바운디드 컨텍스트는 논리적으로 한 개의 모델을 갖는다.<br>
<!-- -->용어를 기준으로 구분한다.<br>
<!-- -->만약 한 바운디드 컨텍스트에서 여러 도메인을 구현해야된다면 패키지로 쪼개서 개발을 하는 게 좋다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="event-방식으로-구현-시-생각-할-점">Event 방식으로 구현 시 생각 할 점<a href="#event-방식으로-구현-시-생각-할-점" class="hash-link" aria-label="Direct link to Event 방식으로 구현 시 생각 할 점" title="Direct link to Event 방식으로 구현 시 생각 할 점">​</a></h3><ol><li>이벤트 주체를 추가 할지 여부<ul><li>Event Entry<ul><li>예를 들어 요구사항이 Order가 발생시킨 이벤트만 조회하기 이런식으로 요청이 왔을 때 기능을 구현을 할 수가 없다.</li></ul></li></ul></li><li>포워더에서 전송 실패를 얼마나 허용할 것이냐<ul><li>이벤트를 전송하는데 3회 이상 실패했다면 해당 이벤트는 생략하고 다음 이벤트로 넘어간다는 등의 정책이 필요하다.</li></ul></li><li>이벤트 손실 <ul><li>이벤트 저장소를 이용하는 방식은 이벤트 발생과 이벤트 저장을 한 트랜잭션으로 처리하기 때문에 트랜잭션이 성공하면 이벤트가 저장소에 보관된다.</li></ul></li><li>이벤트 순서 <ul><li>이벤트 발생 순서대로 외부 시스템에 전달해야 할 경우, 이벤트 저장소를 사용하는 것이 좋다.</li></ul></li><li>이벤트 재처리<ul><li>가장 쉬운 방법은 마지막으로 처리한 이벤트의 순번을 기억해두었다가 이미 처리한 순번의 이벤트가 도착하면 해당 이벤트를 처리하지 않고 무시하는 것.</li></ul></li></ol><p>이벤트가 헨들러가 멱등성을 가지면 중복처리에 대한 부담이 줄어든다.</p><p>예를들어 시스템 장애로 인해 같은 메세지가 보내져도 상관없는 시스템 개인정보의 주소가 변경된다던지 이런 시스템일 경우 중복처리의 부담감이 줄어든다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="cqrs-1">CQRS<a href="#cqrs-1" class="hash-link" aria-label="Direct link to CQRS" title="Direct link to CQRS">​</a></h3><p>도입을 고민 할 때는 트래픽이 많은지와 안 많은지 또 도메인이 복 잡지 안한지를 고민을 하고 <code>CQRS</code>를 고민을하면 두 모델을 유지하는 비용만높고 얻을 수는 있는 이점이 없다. 반면에 트래픽이 높은 서비스으인데 단일 모델을 고집한다면 유지 보수 비용이 높아질 수 있으니 도입을 고려 할만하다.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="후기">후기<a href="#후기" class="hash-link" aria-label="Direct link to 후기" title="Direct link to 후기">​</a></h2><p>Domain Driven Design 책을 읽어야지 하고 지금까지는 개인적으로 도메인에 대해 정말 딥하게 고민 한 적도 없었고<br>
<!-- -->어떤 구조가 더 좋은 구조일까? 도메인을 어떻게 쪼개야 할까? 이런 고민을 깊게 안해 보고 DDD를 읽는 건 도움이 전혀 안된다고 생각을 해서 미루고 미루다가 그래도 최근에는 조금은 어떤 구조가 객체지향적이며 유지보수하기 좋을까라는 고민을 하고 있는 시기여서,<br>
<!-- -->먼저 가볍게 코드도 많은 범균님의 DDD Start를 선택을 했었다. 이 선택은 후회가 없는 선택이였다.<br>
<!-- -->만약 이 책이 아니라 이론만 가득한 책들을 봤다면 아직 "내공이 부족해서 중도 포기를 하지 않았을까"라는 생각을 하게 되었고 가볍게 지금까지 들어보기만 했던 애그리거트 애그리루트 개념에 대해 이해를 할 수가 있었고 단순히 DDD에서 끝내는 것이아니라 MSA를 고려하거나 Event를 처리 할 때 한 번씩 했었던 생각들 나는 어떻게 처리를 했는지 생각을 해 볼 수 있었고, 더욱이 범균님이 실제로 코드들을 작성하면서 했을만한 여러 고민들을 실제로 옆에서 지켜보는 듯한 느낌이 들어 나에게 많은 도움이 되는 책이였다!</p>]]></content:encoded>
            <category>books</category>
            <category>ddd-start</category>
        </item>
        <item>
            <title><![CDATA[규칙없음을 읽고]]></title>
            <link>https://dgle.dev/no_rules</link>
            <guid>https://dgle.dev/no_rules</guid>
            <pubDate>Mon, 19 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[규칙없음 책을 읽고 감명받은 문장 생각해볼 이야기 공부할 거리를 정리]]></description>
            <content:encoded><![CDATA[<p>규칙없음 책을 읽고 감명받은 문장 생각해볼 이야기를 정리</p><h1><a href="http://www.yes24.com/Product/Goods/92275597" target="_blank" rel="noopener noreferrer">규칙없음</a></h1><h2 class="anchor anchorWithStickyNavbar_LWe7" id="색다른-유형의-직장">색다른 유형의 직장<a href="#색다른-유형의-직장" class="hash-link" aria-label="Direct link to 색다른 유형의 직장" title="Direct link to 색다른 유형의 직장">​</a></h2><p>스스로 내린 판단을 실행에 옮길 때 거추장스러운 절차를 밟을 필요 없이 오히려 더 많은 자유를 갖게 되면, 직원들은 좀 더 나은 결정을 내리게 되고, 회사도 책임을 묻기 더 쉬워진다. 그러면 더 즐겁고 의욕적인 분위기가 되어 민첩한 조직이 된다. 이러려면 두 가지 요소가 필요한데</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="인재-밀도를-키워라">인재 밀도를 키워라<a href="#인재-밀도를-키워라" class="hash-link" aria-label="Direct link to 인재 밀도를 키워라" title="Direct link to 인재 밀도를 키워라">​</a></h3><p>뛰어난 실력을 갖춘 인재들로 조직을 꾸리면 거추장스러운 통제 장치가 필요 없어진다. 인재 밀도가 높을 수록 지원들에게 허용되는 자유는 더욱 커진다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="솔직성을-키워라">솔직성을 키워라<a href="#솔직성을-키워라" class="hash-link" aria-label="Direct link to 솔직성을 키워라" title="Direct link to 솔직성을 키워라">​</a></h3><p>재능 있는 직원들은 서로에게서 많은 것을 배운다. 그러나 예의만 강조하는 규정집은 성과를 내는 데 필요한 피드백을 서로에게 제공하는 것을 막는다. 습관처럼 피드백을 서로 주고받게 되면 일을 더 잘하게 되고 동시에 서로 책임질 수 있는 행동을 하게 되며, 통제는 크게 필요하지 않게 된다.</p><p>이 두가지가 되면 </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="통제를-줄이면된다">통제를 줄이면된다<a href="#통제를-줄이면된다" class="hash-link" aria-label="Direct link to 통제를 줄이면된다" title="Direct link to 통제를 줄이면된다">​</a></h3><p>몇 가지 가이드라인만 주어지면 되는데 ‘통제가 아닌 <code>맥락</code>으로 이끌 것’.’평사원에게는 상사의 비위를 맞추려 들지 말 것’ 등과 같다.<br>
<!-- -->리더로서 당신의 첫 번째 목표는 직장에 비범한 동료들로만 채워진 근무 환경을 조성하는 것이다.<br>
<!-- -->비범한 동료들은 중요한 일을 능숙하게 처리한다. 또한 놀라울 정도로 창의적이고 열정적이다.<br>
<!-- -->심사가 비뚤어졌거나 게으르거나 착하긴 한데 성과가 별 볼 일 없거나 매사를 부정적으로 보는 사람들이 끼어 있으면, 팀의 전반적인 성과가 저하된다.</p><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="자신의-생각을-있는-그대로-말하라긍정적인-의도로">자신의 생각을 있는 그대로 말하라(긍정적인 의도로)<a href="#자신의-생각을-있는-그대로-말하라긍정적인-의도로" class="hash-link" aria-label="Direct link to 자신의 생각을 있는 그대로 말하라(긍정적인 의도로)" title="Direct link to 자신의 생각을 있는 그대로 말하라(긍정적인 의도로)">​</a></h2><p>피드백을 주고 받을 때는 선의를 가지고 정식으로 문제를 제기한 후 자신의 감정과 의견, 상대방에 대한 피드백을 솔직하게 표현하게 하였다.</p><p>대부분의 여러이유로 피드백을 주기 포기하는데 '까다로운' 사람이라는 인상을 주고 싶지 않다거나, 내키지 않는 논쟁에 말려들고 싶지 않다거나, 사람들이 내 견해를 지지하지 않을 것 같다거나. 그러나 넷플릭스에서 일하는 사람이라면 아마, 말을 꺼낼 것이다. 상사의 구상이 실제로는 제대로 구현되지 않을 것 가탇고 제동을 건 후 더 <strong>좋은 아이디어를 제시한다.</strong> 동료의 의견에 동의하지 않거나 도움이 될 만한 피드백이 있는데도 말을 하지 않는 것은, 회사에 불충이다.</p><p>실제 사례</p><p>매니저가 인사 몇마디를 건넨 후 친절한 말투로 몇 가지 피드백을 드리고 싶습니다라며 얘기를 꺼냇다. 나는 아무렇지도 않은 표정을 지으려 애썼다. 그는 내가 사전에 인터뷰이들에게 보낸 이메일이 너무 체적이라서 마치 지를 받는 듯한 느낌이 들었다고 했다. 그후 자칫 불편한 기색이 드러나지 않을까 표정부터 신경이 쓰였다. 나중에 그피드백은 도움이 됐다. 솔직한 피드백이 이처럼 도움이 된다. </p><p>부정적인 피드백을 받을 때 인간의 두뇌는 신체적인 위협을 받을 때와 마찬가지로 싸우거나 달아나는 반응을 보이는데, 혈류로 호르몬이 분비되고 대응 시간이 빨라지며 감정이 격해진다.</p><p>피드백을 제사해야 할지 고민할 때, 사람들은 두 가지를 놓고 갈등한다. 상대방의 감정을 건드리고 싶지 않다는 생각과 그래도 그 사람이 성공할수 있게 도와야한다는 생각이다. 넷플릭스에서는 간혹 상대방의 기분을 상하게 하더라도 서로 성공할 수 있게 도우라고 말한다. 무엇보다도 올바른 환경에서 올바른 방식으로 접근하면, 상대방의 감정을 상하게 하지 않고도 피드백을 줄 수 있다는 사실을 우리는 확인해싿.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="임금님에게-벌거벗었다고-말하라">임금님에게 벌거벗었다고 말하라<a href="#임금님에게-벌거벗었다고-말하라" class="hash-link" aria-label="Direct link to 임금님에게 벌거벗었다고 말하라" title="Direct link to 임금님에게 벌거벗었다고 말하라">​</a></h3><p>피드백을 받을 때의 태도도 중요하다. 어떤 비판에도 감사한 마음으로 대응하고 ‘소속 신호'를 줌으로써 피드백을 마음 놓고 제시해도 좋다는 사실을 보여준다.</p><p>목소리에 감사의 뜻을 담거나 상대방에게 물리적으로 가까이 다가서거나 호의적인 시선을 보내는 것 같은 사소한 제스처도 소속 신호가 될수 있다. 용기를 내줘서 고맙다고 말하거나 사람들 앞에서 그런 용기에 관해 언급하는 식의 적극적인 제스처도 좋은 소속 신호다. 소속 신호의 기능은 ‘지금 우리는 안전한가? 우리 앞으로 이들과 어떻게 될 것인가' 보이지 않는 위험이 숨어있는 것은 아닐까'와 같이 오래전부터 인간의 두뇌 속에 자리 잡고 있던 질문에 대답하는 것이다. 상사이든 부하직원이든 회사에 소속된 사람들이 소속 신호를 가지고 모든 순간에 솔직하게 응답할수록 사람들은 더욱 용기를 내어 솔직해질 것이다. </p><p>회의 중 누가 반대를 하고 의견을 격하게 주고 받았다면 회의가 끝나고 어깨에 손을 얹고 오늘 회의 아주 좋았어. 의견을 주어 고마웠네라고 미소 짓자</p><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="4a-피드백-지침">4a 피드백 지침<a href="#4a-피드백-지침" class="hash-link" aria-label="Direct link to 4a 피드백 지침" title="Direct link to 4a 피드백 지침">​</a></h2><h3 class="anchor anchorWithStickyNavbar_LWe7" id="피드백을-줄-때">피드백을 줄 때<a href="#피드백을-줄-때" class="hash-link" aria-label="Direct link to 피드백을 줄 때" title="Direct link to 피드백을 줄 때">​</a></h3><ol><li>AIM TO ASSIST: 구체적인 행동 변화가 상대방 개인이나 회사에 어떻게 도움이 되는지 분명히 설명한다. 자신을 위한 것이 아님을 분명히 납득시켜야 한다. 외부 파트너와 회의할 때 이를 쑤시는 모습이 무척 거슬립다는 잘못된 피드백이다. 올바른 피드백은 외부 파트너와 회의를 할 때 이를 쑤시는 습관을 고치면, 파트너들이 팀장님을 좀 더 전문가답다고 여길 것이고 그래서 더욱 긴밀한 관계를 쌓을 수 있을겁니다.” 이다. </li><li>ACTIONABLE: “교수님의 발표 메세지 자체를 망치고 있다" 이는 잘못된 피드백이다. “청중에게 그런 방식으로 의견을 구하게 되면, 결국 특정 사람들만 참여하게 됩니다" 더 좋은 방법은 “회의장에 있는 다른 나라 출신들에게 의견을 구하는 방법을 찾을 수 있다면 교수님의 메세지는 더욱 분명하게 전달될 것입니다.”</li></ol><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="피드백을-받을-때">피드백을 받을 때<a href="#피드백을-받을-때" class="hash-link" aria-label="Direct link to 피드백을 받을 때" title="Direct link to 피드백을 받을 때">​</a></h3><ol><li>APPRECIATE(감사해라): 어떻게 해야 상대방의 고언을 신중하게 듣고 , 열린 마음으로 그 의미를 짚어보며, 수세를 취하거나 화를 내지 않고 감사한 마음을 표현할 수 있을까" 라고 자문을 해야한다. 자존심이나 체면이 중요한게 아니다.</li><li>ACCEPT OR DISCARD: 항상 반드시 따를 필요는 없다. 진심을 담아 “고맙다"고 말하되, 피드백의 수용 여부는 전적으로 받는 사람에게 달렸다</li></ol><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="모든-것을-공개하라">모든 것을 공개하라<a href="#모든-것을-공개하라" class="hash-link" aria-label="Direct link to 모든 것을 공개하라" title="Direct link to 모든 것을 공개하라">​</a></h2><p>투명성은 우리 직원들이 책임감을 가지고 행동할 것으로 회사가 믿는다는 걸 보여주는 가장 중요한 상징적 개념이다. 우리가 그들에게 보여준 신뢰는 그들로 하여금 주인의식과 헌신, 책임감을 갖게 한다.</p><p>소수의 불미스러운 행동으로 다수를 문책하는 일은 없어야 한다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="실수를-들어내라">실수를 들어내라<a href="#실수를-들어내라" class="hash-link" aria-label="Direct link to 실수를 들어내라" title="Direct link to 실수를 들어내라">​</a></h3><p>실수를 들어냄으로써 더 믿음이 가게 되기 마련이고, 리더가 실수를 하면 직원들은 아 실수는 누구나 하는 거구나라고 생각을 하게 된다. 그렇게 되면 성공 여부가 확실하지 않아도 과감하게 모험을 선택한다. 이는 전반적인 회사에 혁신으로 이어진다. 자신의 약점을ㄷ ㅡ러내면 신뢰를 얻을 수 있다. 도움을 청하면 더 배울 수 있다. 실수를 인정하면 용서받을 수 있다. 리더가 실패한 사례를 공개하면 직원들은 더욱 용기를 갖고 모험하게 된다. 성공 했을 때는 조그맣게 얘기하거나, 스스로를 말하지 말고 다른 사람들의 입에서 그 말이 나올 때까지 가다려라, 하지만 실수를 했을 떄는 분명하게 말하고 큰소리로 말함으로써 모든 사람이 당신의 실수를 알고 타산지석으로 삼게하다. <code>‘잘한 일은 작은 소리로, 실수는 큰 소리로'</code> 말하라</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="실수-효과">실수 효과<a href="#실수-효과" class="hash-link" aria-label="Direct link to 실수 효과" title="Direct link to 실수 효과">​</a></h3><p>실수 효과는 똑같은 실수를 저질러도 평소 인상이 좋았던 사람에겐 그 실수가 오히려 그사람의 매력을 증가시키는 반면, 그 반대인 사람에겐 가뜩이나 좋지 않았던 인상이 더욱 안좋아지는 역할을 하는 것이다. <code>**리더는 자신의 실수를 공개하기 전에, 먼저 유능함을 입증하고 사람들의 신뢰를 얻어야한다.**</code></p><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="어떤-의사결정도-승인받을-필요-없다">어떤 의사결정도 승인받을 필요 없다.<a href="#어떤-의사결정도-승인받을-필요-없다" class="hash-link" aria-label="Direct link to 어떤 의사결정도 승인받을 필요 없다." title="Direct link to 어떤 의사결정도 승인받을 필요 없다.">​</a></h2><p>회사의 상사는 직원들의 결정을 승인해 주거나 거부하기 위해 존재한다. 이것이야말로 혁신을 막고 성장을 더디게 하는 가장 확실한 방법이다. 상사의 비위를 맞추려 들지 말라 회사에 가장 이득이 되게 행동하라. 회사 내의 모든 직원이 각자 판단에 따라 의사를 결정할 때 가장 빠르고 가장 혁신적인 아이디어가 나올 수 있다고 생각한다. 분산된 의사결정은 인재 밀도가 높고 극도로 투명한 조직에서만 위력을 발휘한다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="배팅-전후에-취해야-할-조치">배팅 전후에 취해야 할 조치<a href="#배팅-전후에-취해야-할-조치" class="hash-link" aria-label="Direct link to 배팅 전후에 취해야 할 조치" title="Direct link to 배팅 전후에 취해야 할 조치">​</a></h3><p>베팅을 잘못했다고 쫓아내지는 않는다. 그보다도 큰일을 벌일 수 있는데도 칩을 사용하지 않거나, 잘못된 판단이 장기간 이어질 경우에만 쫓아냈다.</p><p>실패 했을 때는 </p><ol><li>그 프로젝트에서 무엇을 배웠는지 물어봐라.</li><li>그일로 수선을 피우지 마라<ul><li>성과를 내지 못한 베팅을 두고 법석을 떠는 것은, 앞으로 모험 따위는 생각도 하지 말라고 경고와 다를 바 없다. 사람들은 당신이 말로만 분산 의사결정을 말할 뿐, 실제로는 그런 방식을 용납하지 않는다고 생각할 것이다.</li></ul></li><li>실패를 션샤이닝하라고 요청하라<ul><li>션사이닝이란 실패한 모험을 숨기지 않는 걸 말함.</li><li>자초지종을 솔직하게 밝히는 공개 메모를 쓰도록 권하고, 거기에서 얻은 교훈을 첨가하게 한다.</li></ul></li></ol><p>실패한 베팅은 감춰야 할 ‘sos’가 아니라 누구나 하는 실수일 뿐이다. 그러나 실수를 얼버무리려 하거나 같은 실수를 반복한다면(실수를 인정하지 않으면 반복할 가능성이 커진다), 결과는 심각해진다.</p><p>실패에서 어떤 것을 얻었는지 배워라. 그걸 션샤이닝 해서 나의 실수를 팀원들이 하지 않도록 해라</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="키퍼-테스트">키퍼 테스트<a href="#키퍼-테스트" class="hash-link" aria-label="Direct link to 키퍼 테스트" title="Direct link to 키퍼 테스트">​</a></h2><h3 class="anchor anchorWithStickyNavbar_LWe7" id="우리는-가족이-아니라-팀이다">우리는 가족이 아니라, 팀이다.<a href="#우리는-가족이-아니라-팀이다" class="hash-link" aria-label="Direct link to 우리는 가족이 아니라, 팀이다." title="Direct link to 우리는 가족이 아니라, 팀이다.">​</a></h3><p>우승팀이 되려면 모든 포지션에 최고의 선수가 자리를 잡고 있어야 한다. 뭔가 큰 잘못을 저지르거나 게으름을 피우지 않는 한 쫓겨날 일은 없다고 생각한다면, 요즘 사람이 아니다. 프로스포츠나 올림픽에서 감독의 역할은 뛰어난 선수를 위대한 선수로 바꾸는 것이다. 안주하지 마라.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="즉각적인-키퍼-테스트">즉각적인 키퍼 테스트<a href="#즉각적인-키퍼-테스트" class="hash-link" aria-label="Direct link to 즉각적인 키퍼 테스트" title="Direct link to 즉각적인 키퍼 테스트">​</a></h3><p>상사와 일대일로 말할 기회가 있을 때 이렇게 묻는 것이다.</p><p><code>“제가 일을 그만둔다고 하면, 어떻게 해서든 저를 붙잡으실 건가요?”</code> 상사의 답을 들으면 자신이 처한 상황을 정확히 알 수 있다.</p><p>3가지 반응이 있을 수 있는데 </p><ol><li>무슨 수를 써서라도 당신을 놓치지 않겠다고 말하는 경우</li><li>명확하지 않지만 피드백을 주는 경우 - 제 역하을 할 수 있도록 도와주는 말이니 나쁜건 아니다</li><li>노력할 기색이 없는 경우 - 이는 나쁠 수 있지만 아무것도 모르고 있다가 어느 날 아침, 느닷없이 회사를 그만두라는 통고를 받는 거 보다는 낫다.</li></ol><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="피드백-서클">피드백 서클<a href="#피드백-서클" class="hash-link" aria-label="Direct link to 피드백 서클" title="Direct link to 피드백 서클">​</a></h2><p><code>다른 사람의 이야기를 할 때는 그 사람 면접에서 할 수 있는 말만 하라.</code></p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="360-서면-평가">360 서면 평가<a href="#360-서면-평가" class="hash-link" aria-label="Direct link to 360 서면 평가" title="Direct link to 360 서면 평가">​</a></h3><p>사람들은 가능하면 너그럽고 지지하는 어조로 피드백을 주려고 배려한다. 누군가가 선을 넘기면, 이봐요, 그런 말은 도움이 안돼요 라는 피드백이 날라온다
성과 평과는 솔직한 직장 환경을 만드는 데 그다지 바람직한 메커니즘은 아니다. 피드백은 보통 일방적이고(하향 평가) 오직 한 사람(상사)에게서 나오기 때문이다.
반면 360도 서면 평가는 연례적으로 시행 할 수 있는 좋은 피드백 메커니즘이다. 다만 익명이나 점수를 매기는 일은 피하고, 결과를 연봉 인상이나 승진과 연계하지도 마라. 각오가 된 사람에게는 언제든 공개적으로 코멘트를 하라.
긍정적인 코멘트와 시정을 요구하는 코멘트는 25%대 75% 정도가 좋다. 피드백은 실질적인 내용을 담아야 한다.</p><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="통제가-아닌-맥락으로-리드하라">통제가 아닌 맥락으로 리드하라<a href="#통제가-아닌-맥락으로-리드하라" class="hash-link" aria-label="Direct link to 통제가 아닌 맥락으로 리드하라" title="Direct link to 통제가 아닌 맥락으로 리드하라">​</a></h2><p>아이가 위험성을 충분히 이해한 것 같다면, 더는 행동을 제한하거나 감독하지 않고 가고 싶어 하는 파티에 가게 해준다. 이것이 맥락으로 리드하는 방식이다. 하지만 평소에 신뢰를 줄 만큼 분별력이 잇는 아이라면, 맥락을 짚어준 다음 삼가서 처신하리라 여기고 그 이상 참견하지 않아야한다.
인재 밀도가 낮을 수록 나서서 감시하고 제대로 된 결정인지 확인해야한다. 밀도가 높다면 맥락만 짚어줘야 제 실력을 발휘할 것이다.
넷플릭스는 상사가 아니라 정보에 밝은 주장이 의사결정권자다. 상사는 팀이 현명한 결정을 내릴 수 있도록 맥락만 짚어줘야한다. 구조는 피라미드가 아니라 나무여야한다. 169p
맥락을 짚어주고 토론하여 의견을 확실하게 조율하라. 부하직원이 어리석은 행동을 했을 때 나무라지 말라. 대신 맥락을 제대로 짚어주지 않았는지 자문해 보라. 목표와 전략을 분명히 전달하고 실행하는데 필요한 의욕을 제대로 불어넣었는가? 팀이 좋은 결정을 내릴 수 있도록 모든 가설과 위험을 확실하게 설명했는가? 비전과 목표에 관해 부하직원들과 의견을 조율했는가?를 의심해라
부하직원들이 당신과 당신 주변 사람들로부터 받은 정보를 사용하여 팀을 바람직한 방향으로 밀고 나갈 때 맥락을 잘 짚어주어 훌륭한 결정을 직접 내리가 하면, 조직은 성공한다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="모든-건-상대적이다">모든 건 상대적이다.<a href="#모든-건-상대적이다" class="hash-link" aria-label="Direct link to 모든 건 상대적이다." title="Direct link to 모든 건 상대적이다.">​</a></h3><p>전략과 유연성이 필요하다. 항상 모든 사람에게 같은 처방을 할 수 없다.
사소한 실수가 잦으면 고통스럽겠지만, 그래도 무언가를 배울 수 있는 좋은 기화가 된다. 실수는 혁신 사이클에 좋은 영양분이다.</p>]]></content:encoded>
            <category>books</category>
            <category>no_rules</category>
        </item>
        <item>
            <title><![CDATA[함께자라기를 읽고]]></title>
            <link>https://dgle.dev/growup-together</link>
            <guid>https://dgle.dev/growup-together</guid>
            <pubDate>Thu, 15 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[함꼐자라기 책을 읽고 감명받은 문장 생각해볼 이야기 공부할 거리를 정리]]></description>
            <content:encoded><![CDATA[<p>함꼐자라기 책을 읽고 감명받은 문장 생각해볼 이야기를 정리</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="함께-자라기"><a href="https://www.notion.so/TIL-550b1f0592734212b85a7fffc97dfd40" target="_blank" rel="noopener noreferrer">함께 자라기</a><a href="#함께-자라기" class="hash-link" aria-label="Direct link to 함께-자라기" title="Direct link to 함께-자라기">​</a></h2><p>오랜만에 다시 읽어보는 함께 자라기</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="머리말---내가-정말-잘할-수-있을까-아니-우리가-정말-자랄-수-있을까">머리말 - “내가 정말 잘할 수 있을까? 아니, 우리가 정말 자랄 수 있을까?”<a href="#머리말---내가-정말-잘할-수-있을까-아니-우리가-정말-자랄-수-있을까" class="hash-link" aria-label="Direct link to 머리말 - “내가 정말 잘할 수 있을까? 아니, 우리가 정말 자랄 수 있을까?”" title="Direct link to 머리말 - “내가 정말 잘할 수 있을까? 아니, 우리가 정말 자랄 수 있을까?”">​</a></h3><p>“내가 정말 잘할 수 있을까?”의 질문을</p><ul><li>내가 정말 자랄 수 있을까?</li><li>우리가 정말 함꼐 자랄 수 있을까?</li><li>우리가 정말 매일매일 함께 자랄 수 있을까?</li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="자라기---학습">자라기 - 학습<a href="#자라기---학습" class="hash-link" aria-label="Direct link to 자라기 - 학습" title="Direct link to 자라기 - 학습">​</a></h3><p>학교 학습 vs 야생학습</p><ul><li>야생 학습은 대부분 협력적이다.</li><li>야생 학습은 대부분 비순차적이다</li><li>야생 학습은 대부분 자료에 한정이 없다.</li><li>야생 학습은 대부분 명확한 평가가 없다.</li><li>야생 학습은 대부분 정답이 없다.</li><li>야생 학습은 대부분 목표가 불분명하고 바뀌기도 한다.</li></ul><p>사람을 뽑을 때는 구조화된 인터뷰(행동중심적 인터뷰)와 실제 작업을 해보도록 하는 샘플 테스트, 그리고 가능하다면 실제 업무를 주고 시험적으로 짧은 기간 동안 일을 해보게 하는 것등을 권장합니다. </p><p><strong>행동중심적 인터뷰(structured behavioral interview)란?</strong>
“개발자로써 협력에 대한 철학이 뭔가요?” 같은 질문은 행동을 묻는 것이 아니라, “지난 프로젝트에서 동료가 어려움을 겪을 때 어떤 행동을 하셨는지 구체적 예를 들어주세요”라고 물어야 합니다.</p><p><strong>1만 시간의 법칙을 제대로 적용하려면</strong>
“의도적수련”, 애자일 철학을 활용하는 것인데, 즉 피드백을 짧은 주기로 얻는 것, 그리고 실수를 교정할 기회가 있는 것, 이 두가지가 중요하다.</p><p><strong>내가 A 작업을 개선하려면</strong>
두 가지 질문을 해 봐야 한다</p><ol><li>어떻게 하면 더하기보다 곱하기를 할 수 있을까? (복리)</li><li>어떻게 해야 고바는 비율을 높일 수 있을까 혹은 이자 적용 주기를 짧게 할 수 있는가</li></ol><ul><li>자신이 이미 갖고 있는 것들을 잘 활용하라.<ul><li>새로운 것을 유입시키는 데에만 집중하다 보면 새로 들어온 것들이 이미 있는 것들을 덮여버릴 수 있다. 올해 몇 권을 읽었다고 자랑하지 말고, 내가 그 지식을 얼마나 어떻게 활용하는지 반성하라.</li><li>점과 점을 이어라 이미 습득한 지식, 기술, 경험 등을 서로 연결 지어서 시너지 효과가 나게 하고 하나의 영역에서 다른 영역으로 왔다갔다하는 것을 자주 해서 다른 영역 간을 넘나들기가 수월해지도록 하라.</li><li>새로운 것이 들어오면 이미 갖고 있는 것들과 충도을 시도하라.</li></ul></li><li>외무 물질을 체화하라.<ul><li>계속 내부 순환만 하다가는 일정 수준에 수렴할 위험이 있다. 주기적으로 외부 자극을 받으면 좋다. 단, 외부 자극을 받으면 그걸 재빨리 자기화해야 한다.</li></ul></li><li>자신을 개선하는 프로세스에 대해 생각해 보라.<ul><li>A 작업을 되돌아보는 회고/반성 활동을 주기적으로 하는 프로세스를 만들어라<ul><li>내가 생각한 회고는 어떤 것을 했고, 어떤 것을 느꼈고, 어떤 교훈을 배웠는지, 또 자기계발은 어떤걸 했는지 4가지 정도면 적당 할 거 같다.</li></ul></li><li>나를 개선하는 과정을 어떻게 하면 개선할 수 있을지 고민하라.</li></ul></li><li>피드백을 자주 받아라<ul><li>순환율을 높여라. 1달, 작게라도 실험해 보는 것이 좋다.</li><li>일찍, 그리고 자주 실패하라. 실패에서 학습하라</li></ul></li></ul><br><p><strong>소프트웨어 개발자 vs 컴퓨터 프로그래머</strong>
컴퓨터 프로그래머는 다른 사람이 준 스팩대로 개발하는 것을 주 업무로 하며 그 과정에서 협상, 설득이 크게 필요하지 않는다. 반면 소프트웨어 개발자는 뭘 만들지를 고민하고 설계하는 부분이 포함되며, 그 과정에서 타인과 상호작용하는 업무가 많습니다. 즉 소프트웨어 개발자가 되는 걸 목표로 해야한다.</p><p><strong>달인이 되는 비결</strong> </p><ol><li>동기가 부족하다.</li><li>피드백을 제때 받지 못한다</li></ol><p>양치질 예 단순하게 양치질을 10년 한다고 달인이 되는 건 아니다. 어떻게하면 더 잘할 것이고 치과의사에게 피드백을 받음으로써 달인이 된다.
어떻게 하면 내가 더 성장 할 수 있을까를 고민 해본다면, 코드 리뷰를 받거나, 짝 프로그래밍을 진행하거나, 고객에게   개발하는 프로그램에서 피드백을 적극적으로 요구하거나, 직관성을 높이려면 다양한 스스로의 실험을 해봐야 할 거 같다. 업무를 받았을 때 기존에는 3일 이내로 잡았다면 마감기한을 2일로 당겨서 진행을 해본다던지 등을 통해 해볼 수 있을 거 같다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="의도적-수련deliberate-practice">의도적 수련(Deliberate Practice)<a href="#의도적-수련deliberate-practice" class="hash-link" aria-label="Direct link to 의도적 수련(Deliberate Practice)" title="Direct link to 의도적 수련(Deliberate Practice)">​</a></h3><p>나의 작업 난이도와 실력이 비슷해야한다. <a href="https://www.ted.com/talks/mihaly_csikszentmihalyi_flow_the_secret_to_happiness?language=ko" target="_blank" rel="noopener noreferrer">미하이 칙센트미하이의 몰입이</a>론과도 일치하는 부분인다. </p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>몰입을 연구한 계기</div><div class="admonitionContent_S0QG"><p>처음에는, 사람들은 무슨 활동을 할 때 행복한가를 연구했다. 분석 결과 무슨 활동을 하냐가 중요한 게 아니라 뭘 하든지 몰입해서 하면 만족도가 올라간다. 그래서 몰입으로 연구방향을 틀게됐다고한다.</p></div></div><p>업무 시간 중에 불안함이나 지루함을 느끼는 때가 대부분이라면, 실력이 도무지 늘지 않는 환경에 있는 것이다. </p><br><p><strong>제자리걸음에서 벗어나기</strong></p><ol><li><p>지루함을 느끼는 경우: 실력 낮추기 </p><p>예를 들면 마우스를 안쓰고 키보드로만 개발을 한다던지, 디버거를 안써본다던지, 컴파일을 30초마다가아닌 5분마다 한다던지, 조금 더 집중을 할 수 있는 환경을 만들어서 몰입을 높여 만족도를 높인다.</p></li><li><p>지루함을 느끼는 경우: 난이도 높이기</p><p>하루만에 할 개발을 한시간만에 개발 한다던지, 100rps 면 되는 시스템을 1,000rps 기준으로 만든다던지. 익숙한 작업을 새로운 언어로 진행한다던지.</p></li><li><p>불안함을 느끼면 : 실력 높이기 </p><p>사회적 접근: 나보다 뛰어난 전문가의 도움을 얻는 것. 짝 프로그래밍을 해달라고 부탁하거나, 스터디</p><p>도구적 접근: 오픈소스를 활용한다던지, 괜찮은 도구를 찾는 것</p><p>내관적 접근: 예전에 했던 비슷한일의 경험을 떠올려 보는 것 그때 일을 어떻게 했는지를 떠 올리면서 해결</p></li><li><p>불안함을 느끼는 경우 : 난이도 낮추기</p><p>아기 버전을 만든다 0.0.1 버전을 목표로한다. WTSTTCPW(What’s the simplest Thing That Coluld Possibly Work?) 동작을 할 수 있는 가장 간단한 건 뭘까? 쉬운 것 부터 먼저하고 어려운 것을 하자</p></li></ol><p>나는 지금까지 몰입을 했던 경험을 생각해보면</p><ul><li>책에서 말한바와 같이 일을 할 때 난이도가 70%~80%로 정도 느끼는 일들이 몰입을 이끌었고</li><li>다른 사람들(개발자들)과 일을 협업을 하면서 데이터를 하나하나씩 맞춰 나가면서 퇴근 후 자기 전 내가 생각하고 수정되어야 할 부분들을 빨리 출근해서 이야기하고 싶다라는 경험을 함으로써 몰입을 했었으며</li><li>기존 사내에 없었던 성능 테스트를 작성하면서 생겼던 생각하지 못했던 여러 어려웠던 일들이 몰입을 이끌었다.</li><li>이외에도 여러 피드백을 받을 수 있는 일들을 할 때 나는 몰입을 하였고 일에 대해 만족감이 높았고 성장도 높았었다.</li></ul><p>지루함을 느끼지 않도록하자 스스로 몰입을 할 수 있는 환경을 만들어나가자. 몰입을 경험 할 수 있는 환경을 만들면 일의 퍼포먼스가 올라가고, 일적으로나 개인적으로나 만족감 성취감이 높고 성장을 더 할 수 있다. </p><br><p><strong>의도적 수련의 예시</strong></p><ol><li>역엔지니어링 설계도 없이 완성품으로부터 설계를 추론하는 행위</li><li>새로운 프로그래밍 언어를 배울 때 적극적 읽기(무언가를 읽을 때 구체적인 질문이나 목적을 가지고 있는 방법)를 한다.<ul><li>예) 간단한 단어 개수 세기 프로그램를 만들어본다.</li><li>다양한 표준 라이브러리를 보고 스타일을 배운다.</li></ul></li></ol><br><p><strong>누군가에게 빨리 배우려면</strong> </p><ul><li>프로그래밍 언어를 빨리 배우는 비결이 뭔가요?  → 그냥 연습하세요가 된다. 이를 구체적인 사건에 대해 말하도록 유도한다. 최근에 익힌 언어가뭐에요? 어떤 시간별로 행동을 하셨어요?</li></ul><br><p><strong>인지적 작업을 높이려면</strong>
내가 이 문제를 해결할 때 어떤 과정을 거치는가를 생각하며 자신의 머릿속을 <strong>관찰하고 질문을 던지고 분석</strong>하는 것이 도움된다. </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="함께">함께<a href="#함께" class="hash-link" aria-label="Direct link to 함께" title="Direct link to 함께">​</a></h3><p>소프트 스킬(커뮤니케이션이나 협력)이 중요하다. </p><br><p><strong>백지장도 맞들면 찢어진다?</strong>
톱니바퀴 실험 </p><ul><li>혼자 톱니바퀴 수를 세는 것보다 여러명이서 추상화 규칙을 통해 계산을 하는 식의 확률이 더 높았다.<ul><li>요기서 추상화란 시각적인 여러가지 요소를 이용하는 것이다. 서로의 시각이 다르기 때문에 그림을 그린다던지 글을 같이 그려나가는 추상화 하는 방법을 말함.</li></ul></li></ul><br><p><strong>짝 프로그래밍 장점</strong>
두 사람이라는 구성은 대화를 통해 추상화를 높이게 한다. 한 컴퓨터라는 구성은 구체화를 통해 검증하게 한다. 즉 커뮤니케이션을 통해 높여간다. </p><br><p><strong>신뢰</strong>
공유는 복수공유가 더 좋다. 하나를 공유하였을 때는 신뢰를 깍아먹는 공유가 될 확률이 높지만, 복수를 공유하는 것이 상대방의 신뢰를 더 쌓을 수 있는 방법이다. 그리고 커뮤니케이션이 더욱 더 많아지게되는 효과도 있다. 이는 같은 시간을 투자했는데도 신뢰도도 높아지고 성과도 좋아졌다. 실제로 복수 개의 아이디어를 공유했을 때 팀의 결속이 강화되고 오너십을 느낀다는 연구도 있다. </p><br><p><strong>설득</strong></p><p>동료나 상사를을 설득 할 때는 객관적인 자료와 연구자료로 결정되는 게 아니다. 의사결정을 하는 과정에 감정적이고 직관적인 부분이 큰 역할을 하고 있으며, 그런 감정적 부분이 배제된다면 의사결정을 제대로 할 수 없다. 출발은 단순하게 객관적인 자료를 들이미는게 아니라 내가 설득하려는 사람에게서 하는 것이다. 자료에서 출발하는 것이 아니다. 상대방에 대해 얼마나 이해를 하고 얼마나 대화를 해봤냐에 나온다.</p><br><p><strong>팀장</strong>
팀장은 행동을 유대하는 대화로 팀원이 자기주도적으로 되게 돕는 사람. p.105</p><br><p><strong>뛰어난</strong> <strong>팀의 비밀</strong></p><ol><li>팀에 누가 있는지(전문가, 내향/외향, 지능 등)보다 <strong>팀원들이 서로 어떻게 상효작용하고 자신의 일을 어떻게 바라보는지가 훨씬 중요</strong>했다.</li><li>5가지 성공적 팀의 특징을 찾았는데, 그중 앞도적으로 높은 예측력을 보인 변수는 <strong>팀의 심리적 안전감</strong>이다.</li><li>팀 토론 등 특별히 고안된 활동을 통해 <strong>심리적 안전감을 개선할 수 있다.</strong></li></ol><br><p><strong>실수관리</strong>
실수는 예방하는 것이 아닌 관리하는 것이다. 예방만을 위해 노력한다면 실수를 밝히지 않고 숨기려고 할 것인 반면, 실수를 관리함으로써 관리 대상으로 보는 것이다.</p><br><p><strong>심리적 안전감</strong>
내 생각이나 의견, 질문, 걱정, 혹은 실수가 드러났을 때 처벌받거나 놀림받지 않을 거라는 믿음.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="애자일">애자일<a href="#애자일" class="hash-link" aria-label="Direct link to 애자일" title="Direct link to 애자일">​</a></h3><p>기민하게 소프트웨어 개발를 다루는 방법론.<br>
<!-- -->애자일의 불확실성을 다루는 방식은 좀 더 짧은 주기로 더 일찍부터 피드백을 받고, 더 다양한 사람으로부터 더 자주 그리고 더 일찍 피드백을 받는 것으로 정리할 수 있다. </p><br><p><strong>불확실성에 대비</strong>
학습과 협력을 통해 대비를 할 수 있다. </p><br><p><strong>단어</strong>
“고객에게 매일 가치를 전하라”</p><ul><li>고객: 우리의 진짜 고객은 누구인가.</li><li>매일: 어떻게 점진적으로 가치를 전달할 것인가?, 어떻게 보다 일찍, 그리고 자주 가치를 전할 것인가?</li><li>가치를: 무엇이 가치인가? 지금 우리가 하고 있는 일이 정말 가치를 만드는 일인가? 비슷한 수준의 가치를 더 값싸게 전할하는 방법은?</li><li>전하라: 가치를 우리가 갖고 있지 않고 고객에게 정말 전달하고 있는가? 고객이 정말 이 가치를 얻고 싶어하는가?</li></ul><p>프로젝트 성공확률엔 고객의 참여가 제일 높은 기여를한다.
무섭고 두렵지만 중요한 일이라면 계속 미루지 않는 것도 중요하다.</p><br><p><strong>애자일 도입</strong>
확실성 위에서 애자일을 도입하게 되면 실패 확률이 높다. 애자일을 어떻게 도입 해야하는 가는 사실, 애자일 자체는 방법론이기 때문에 정답은 없다. 방법론은 태생적으로 불확실성이기 높기 때문이다. 곁에 있는 주변 사람들과 조금 탐색해나가고 조금 나아가고 확인하고 반복하면 우리의 현 맥락에 맞는 좋은 전략들을 스스로 만들어 나가는 것이 아닐까?</p>]]></content:encoded>
            <category>books</category>
            <category>growup-together</category>
        </item>
        <item>
            <title><![CDATA[신뢰의 과학영상을 보고]]></title>
            <link>https://dgle.dev/persuasion</link>
            <guid>https://dgle.dev/persuasion</guid>
            <pubDate>Sun, 31 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[science of persuasion]]></description>
            <content:encoded><![CDATA[<p>설득을 잘하려면 어떻게 해야할까? 설득의 과학이라는 영상을 보고 느낀점을 정리  </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="설득의-과학"><a href="https://www.youtube.com/watch?v=kIjI_CaNGxk" target="_blank" rel="noopener noreferrer">설득의 과학</a><a href="#설득의-과학" class="hash-link" aria-label="Direct link to 설득의-과학" title="Direct link to 설득의-과학">​</a></h2><ol><li>상호성<ul><li>누군가로부터 호의 선물이나 서비스를 제공받았다면 다시 돌려줘야하는 의무감을 느낀다.</li><li>동료가 호의를 배풀었다면 호의 1건을 빚진거다. 자연스럽게 yes라 답변을 외칠 가능성이 높다.<ul><li>점원이<ol><li>사탕 하나를 주면 팁 3% 상승.</li><li>사탕 두개를 주면 팁 14% 상승.</li><li>처음에 사탕 하나를 주고 갑자기 멈춘 후 다시 테이블로 돌아와서는 정말 좋은 분들이신거 같은데 사탕하나를 더 드리고 싶군요. 팁의 금액이 달라졌다 (23%상승).</li></ol></li></ul></li><li><strong>무엇을</strong> 주느냐가 아닌 <strong>어떻게</strong> 주느냐가 중요하다.</li><li>상호성의 핵심은 <strong>먼저 주라</strong> 이때  단순하게 주는 것이 아닌 개인의 취향을 맞추고 예상치 못하는 것을 주는것이 중요하다.</li></ul></li><li>희귀성<ul><li>사람들은 갖기 힘든 걸 더 갖고 싶어한다.<ul><li>여객기의 중지 발표<ol><li>다음날 여객기 매출이 상승</li></ol></li></ul></li><li>누군가에게 상품과 서비스를 제안할 때 상대방이 장점만 얘기하는 게 아니라 손실이 무엇인지를 얘기 해줘야한다.</li><li></li></ul></li><li>권위<ul><li>불확실한 상황에서 신뢰를 할 수 있는 전문가를 따른다.<ul><li>환자들이<ul><li>물리치료실에 자격증이나 면허증을 걸어 놓는다.</li></ul></li><li>평상복을 입은 사람보다 제복을 입은사람에게 더 신뢰감이 간다.</li></ul></li><li>더 중요한거는 신뢰할만한 전문가라는 것을 신호로 보내는 것이다.</li><li>스스로 떠들고 다닐 수는 없다. 이럴 때는 제 3자를 만드는 것이 좋다.<ul><li>부동산 중개업체는 고객 문의에대한 reception에 응대 방식이다.<ul><li>전문성을 먼저 언급한 후 고객에게 설명<ul><li>~xx씨는 임대분야에 15년 경력이라 잘 설명해주실 거에요. 연결해드릴꼐요.</li></ul></li><li>20% 상승</li><li></li></ul></li></ul></li></ul></li><li>일관성<ul><li>상대방을 작게라도 먼저 개입시키는 요소가 있어야한다.<ul><li>집 앞 흉한 표지물 설치동의에 따른 비결은<ul><li>사전에 창문에 작디작은 표지판을 설치하게 해서이다. 설치 400% 상승으로 나타남</li></ul></li><li>예약 시간을 잘 지키도록 서면으로 본인이 직접 적게해서 18% 상승</li><li></li></ul></li></ul></li><li>호감<ul><li>사람들은 자신에게 호감을 가지고 있는 사람들이 예스를 외칠 확률이 높다.</li><li>어떻게 호감을 높일 수 있을까?<ol><li>사람들은 자신과 비슷한사람</li><li>자신을 칭찬하는사람</li><li>자신과 협력을 하고 공통의 목표로 나가는사람 </li></ol></li><li>개인적 정보를 교환하고 그 다음에 협상을 진행함으로써 90% 정도의 성공적인 합의를 이끌어냈다.</li><li>다른 사람과의 공통점을 찾아내고 정말 <strong>진심으로 칭찬을 해라.</strong></li></ul></li><li>사회적 증거<ul><li>사람들은 확신이 없는 경우 다른 사람의 행동을 보고 의사를 결정하는 것이다.<ul><li>호텔에 작은 카드로 수건 재사용을 자연 보호에 도움된다고 말함으로써 35%의 reuse를 이끌어 냄</li><li>4일 이상 투숙객은 75% 이상 수건 reuse를 한다. 라는 사실을<ul><li>75%로의 장기 투숙객은 수건을 재사용한다. 라고 reuse 26% 증가</li></ul></li></ul></li></ul></li></ol><p>설득에 사회적 증거를 정직하게 알리는 것은 도움이 된다. 그리고 다른 사람들이 이미 하고 있는 행동을 보여주는 것은 훨씬 더 효과적이다. 특히 자신과 유사한 사람들을 예로 든다면 더욱 효과적이다.</p><br><p>예전에 읽은 <a href="http://www.yes24.com/Product/Goods/79297023" target="_blank" rel="noopener noreferrer">데일 카네기 인간관계론</a>의 내용과 비슷한 부분이 많은 거 같다. 상대방을 즉 우리는 동료를 설득을 하기위해서는 기본적으로 신뢰를 얻어야하고 그 신뢰를 얻기 위해서 중요한 게 뭔지 생각을 해보면, 노력과 긍정이 제일 중요하지 않을까 생각이된다. 상대방을 존중하는 마음을 가지고 진심으로하는 칭찬을 하고 항상 미소를 짓고 칭찬을 아끼지 말며 내가 먼저 줄 수 있어야하고 하지만 반대로 내가 먼저 줬는데 상대방이 다음에 안 주었다고 불평 불만하지말고 진심으로 인정해주는 수 많은 <strong>노력과 긍정</strong>들을 통해 상대방에게 <strong>좋은</strong> <strong>신뢰</strong>를 얻을 수 있는 거 같다.</p>]]></content:encoded>
            <category>suddenly</category>
            <category>cross my mind</category>
        </item>
        <item>
            <title><![CDATA[Concurrent Hash Map을 간단하게 만들어보자. - 1편]]></title>
            <link>https://dgle.dev/ConcurrentHashMap</link>
            <guid>https://dgle.dev/ConcurrentHashMap</guid>
            <pubDate>Sat, 30 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Make Verrrrry Simple My Concurrent Hash Map -1]]></description>
            <content:encoded><![CDATA[<p>ConcurrentHashMap 간단하게 만들어보자</p><p>모든 소스코드는 <a href="https://github.com/sk1737030/til/tree/master/simple-concurrenthashmap" target="_blank" rel="noopener noreferrer">이곳</a>에서 확인 가능합니다!  </p><h1>ConcurrentHashMap 간단하게 만들어보자</h1><p>동시성 문제 및 일관성을 위해 Key Value 구조로 사용할 때 가장 쉽게 사용하는 것이 <code>CoucurrentHashMap</code> 이였지만 부끄럽게도 항상 내부구조를 보고 이렇게 동시성을 보장하는 거구나라고 생각만 하고 매번 넘겼었는데 이번 기회에 정리하고 한 번 슥-삭 만들어 보려고 합니다. 그래서 결정한 제목은 간단하게 <code>ConcurrentHashMap</code> 간단하게 만들어보자</p><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="concurrenthashmap">ConcurrentHashMap<a href="#concurrenthashmap" class="hash-link" aria-label="Direct link to ConcurrentHashMap" title="Direct link to ConcurrentHashMap">​</a></h2><p>뭐 여타 다른 말을 생략하고 ConcurrentHashMap 말고도 여러 Map의 구현체들이 있는데, 왜 필요로 했을까를 먼저 생각해본다면 크게 2가지 정도가 있을 거 같은데요.  </p><ol><li><p>우리가 자주 사용하는 <code>HashMap</code>은 <strong>thread-safe</strong> 하지 않은 java collection입니다.</p></li><li><p><code>Hashtable</code>은 <strong>thread-safe</strong>하나 synchronized method 레벨에 사용을하여 비용이 매우 비쌉니다.</p><ul><li>즉 다시 말해 비용이 많이드는 이유는 Race condition(경쟁상태)이 발생할 수 있는 code block을 synchronized 키워드로 감싸면, 하나의 스레드만 이 진입할 수 있는데, <code>HashTable</code>은 메소드 레벨에서 synchronized를 걸어버려서 다른 스레드가 먼저 진입한 스레드가 이 code block을 나갈 때까지 계속 기다려야 해서 비용적으로 매우 비싼 Collection입니다.  </li></ul><br><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 해시테이블의 put</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">synchronized</span><span class="token plain"> </span><span class="token class-name">V</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">put</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">K</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">V</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li></ol><br><p>이러한 이유로 멀티 스레드 환경에서의 map이 필요해졌는데 성능까지 신경 써야 하는 문제가 있어서 등장한 것이 동시성 성능까지 챙기게 되는 <code>ConcurrentHashMap</code>입니다. 참고로 자바 1.5버전부터 들어오게 되었습니다.  </p><br><p><img loading="lazy" alt="`ConcurrentHashMap`은 `ConcurrentMap`을 구현한 해쉬맵이다.  " src="/assets/images/Untitled-0a2d3d2c3c8b41ec1b5ba29ed6097963.png" width="769" height="294" class="img_ev3q"><br>
<!-- -->💡<code>ConcurrentHashMap</code>은 <code>ConcurrentMap</code>을 구현한 해쉬맵입니다.  </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="concurrentmap">ConcurrentMap<a href="#concurrentmap" class="hash-link" aria-label="Direct link to ConcurrentMap" title="Direct link to ConcurrentMap">​</a></h3><p>  <code>ConcurrentMap</code>은 멀티스레딩 환경에서 키/값 작업에 대한 메모리 일관성을 보장하는 java.util.concurrent의 패키지에 있고 구현체로는 <strong>ConcurrentSkipListMap, ConcurrentSkipListMap</strong> 두 개가 있습니다.  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">java</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">util</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">concurrent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">ConcurrentMap</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="그렇다면-어떻게-동시성을-보장할까">그렇다면 어떻게 동시성을 보장할까?<a href="#그렇다면-어떻게-동시성을-보장할까" class="hash-link" aria-label="Direct link to 그렇다면 어떻게 동시성을 보장할까?" title="Direct link to 그렇다면 어떻게 동시성을 보장할까?">​</a></h2><p>사실 동시성을 보장하는 방법 중 가장 쉽게는  synchronized를 쓰면 안전하게 동시성을 보장할 수 있지만 쓰기에 따라서 성능 이슈가 있습니다. 특히 위에서 한 번 얘기 했지만,  HashTable 에서 얘기됐던 성능이 가장 큰 문제가 있습니다. 이를 ConcurrentHashMap은 정말 멋지고 어-썸한 여러가지 방법으로 개-선을 했는데 크게 두 가지 방법들로 해결합니다.</p><ol><li><p><a href="https://howtodoinjava.com/java/multi-threading/compare-and-swap-cas-algorithm/" target="_blank" rel="noopener noreferrer">CAS(Compare And Swap) 알고리즘</a> </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">V</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">putVal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">K</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">V</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">boolean</span><span class="token plain"> onlyIfAbsent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> hash </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">spread</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">hashCode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tabAt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tab</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">n </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> hash</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">           </span><span class="token operator" style="color:#393A34">--</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">casTabAt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tab</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Node</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hash</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">--</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">                   </span><span class="token comment" style="color:#999988;font-style:italic">// no lock when adding to empty bin</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li><li><p>새로운 Node를 삽입하기 위해,&nbsp;<code>tabAt()</code>을 통해 해당 bucket을 가져오고&nbsp;<code>bucket == null</code>로 비어 있는지 확인한다.</p></li><li><p>bucket이 비어 있을 경우 casTabAt을 통해 node를 새로 생성하는데 생성에 실패시에 다시 재시도 한다.</p></li></ol><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token class-name">Node</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tabAt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Node</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> tab</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Node</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token class-name">U</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getObjectAcquire</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tab</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">long</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">ASHIFT</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">ABASE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">boolean</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">casTabAt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Node</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> tab</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                        </span><span class="token class-name">Node</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Node</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">U</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">compareAndSetObject</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tab</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">long</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">ASHIFT</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">ABASE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">Unsafe</span><span class="token plain"> </span><span class="token class-name">U</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Unsafe</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getUnsafe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li><a href="https://rangken.github.io/blog/2015/sun.misc.unSafe/" target="_blank" rel="noopener noreferrer">Unsafe</a> 메모리 접근에 관련된 함수</li></ul><br><ol start="2"><li><p>이미 버킷에 노드가 존재한다면 버킷별로 synchronized 사용합니다.  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">V</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">putVal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">K</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">V</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">boolean</span><span class="token plain"> onlyIfAbsent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> hash </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">spread</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">hashCode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">synchronized</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">tabAt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tab</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fh </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            binCount </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Node</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> e </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">binCount</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token class-name">K</span><span class="token plain"> ek</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">hash </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> hash </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ek </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> key </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ek </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">equals</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ek</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    oldVal </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">onlyIfAbsent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        e</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token class-name">Node</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pred </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    pred</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Node</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">K</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics class-name">V</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hash</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li></ol><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="간단한-성능테스트">간단한 성능테스트<a href="#간단한-성능테스트" class="hash-link" aria-label="Direct link to 간단한 성능테스트" title="Direct link to 간단한 성능테스트">​</a></h2><p>그렇다면 정말 성능에서 많은 차이가 날까? get과 put에 대한 간단한 벤치마크를 작성하면서 <code>Hashtable</code>, <code>concurrentHashMap</code>와 성능을 비교해보겠습니다.<br>
<!-- -->간단하게 5개 스레드를 만들고 1,000,000 개 정도 데이터를 넣고 get을 하는 행위를 통해서 비교를 해보면  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Integer</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics class-name">Integer</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> testHashTable </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Hashtable</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Integer</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics class-name">Integer</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> testConcurrentHashMap </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ConcurrentHashMap</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">test</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">throws</span><span class="token plain"> </span><span class="token class-name">Exception</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">long</span><span class="token plain"> hashTableAvgTime </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">measure_GetPut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">testHashTable</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">long</span><span class="token plain"> concurrentHashMapAvgTime </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">measure_GetPut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">testConcurrentHashMap</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"hashTableAvgTime = "</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> hashTableAvgTime</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"concurrentHashMapAvgTime = "</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> concurrentHashMapAvgTime</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">long</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">measure_GetPut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Map</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Integer</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics class-name">Integer</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> map</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">throws</span><span class="token plain"> </span><span class="token class-name">InterruptedException</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">ExecutorService</span><span class="token plain"> executor </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Executors</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">newFixedThreadPool</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">4</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">long</span><span class="token plain"> startTime </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">nanoTime</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            executor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">submit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> j </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> j </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1_000_000</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> j</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">ThreadLocalRandom</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">current</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">nextInt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">100_000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">put</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        executor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">shutdown</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">executor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">awaitTermination</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">30</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">TimeUnit</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">SECONDS</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">map</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getClass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            executor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">shutdownNow</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">long</span><span class="token plain"> endTime </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">nanoTime</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">endTime </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> startTime</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5_000_000</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Random vs ThreadLocalRandom</div><div class="admonitionContent_S0QG"><p>잘 정리된 사이트가 있어서 올리지만 요약하자면 Random은 멀티 스레드에서 하나의 Random 인스턴스를 공유하여 전역적으로 동작해서 선형 합동 생성기 알고리즘을 사용하는 반면 ThreadLocalRandom 각 스레드마다 다른 인스턴스를 생성합니다.<br>
<a href="https://velog.io/@sojukang/Random-%EB%8C%80%EC%8B%A0-ThreadLocalRandom%EC%9D%84-%EC%8D%A8%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0" target="_blank" rel="noopener noreferrer">https://velog.io/@sojukang/Random-대신-ThreadLocalRandom을-써야-하는-이유</a></p></div></div><br><p>참고로 환경은 <a href="https://www.apple.com/kr/macbook-pro-14-and-16/specs/" target="_blank" rel="noopener noreferrer">m1book Pro</a>, 16GB에서 테스트 해보았습니다.  </p><p>대략 10번 정도의 테스트 후에 나온 결과 값입니다.  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">hashTableAvgTime </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1228</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">concurrentHashMapAvgTime </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">317</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><p>확실히, 메소드 레벨에서 락을 거는 방법으로 put을 처리하는 <code>hashtable</code>과 달리 <code>ConcurrentHashMap</code>은 버킷당으로 lock을 걸고 cas 알고리즘을 사용하는등을 통한 여러 기법들로 성능상 상승이 나타난 걸로 보입니다.</p><p>길었는데 만들어보는 건 다음 2편에서:)</p><h1>참고</h1><p><a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentMap.html" target="_blank" rel="noopener noreferrer">https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentMap.html</a><br>
<a href="https://www.baeldung.com/java-concurrent-map" target="_blank" rel="noopener noreferrer">https://www.baeldung.com/java-concurrent-map</a><br>
<a href="https://www.programiz.com/java-programming/concurrenthashmap" target="_blank" rel="noopener noreferrer">https://www.programiz.com/java-programming/concurrenthashmap</a><br>
<a href="https://www.geeksforgeeks.org/concurrenthashmap-in-java/" target="_blank" rel="noopener noreferrer">https://www.geeksforgeeks.org/concurrenthashmap-in-java/</a><br>
<a href="https://bcho.tistory.com/1072" target="_blank" rel="noopener noreferrer">https://bcho.tistory.com/1072</a><br>
<a href="https://en.wikipedia.org/wiki/Hash_table" target="_blank" rel="noopener noreferrer">https://en.wikipedia.org/wiki/Hash_table</a><br>
<a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html" target="_blank" rel="noopener noreferrer">https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html</a><br>
<a href="https://howtodoinjava.com/java/multi-threading/compare-and-swap-cas-algorithm/" target="_blank" rel="noopener noreferrer">CAS</a><br>
<a href="https://d2.naver.com/helloworld/831311" target="_blank" rel="noopener noreferrer">https://d2.naver.com/helloworld/831311</a><br>
<a href="https://velog.io/@sojukang/Random-%EB%8C%80%EC%8B%A0-ThreadLocalRandom%EC%9D%84-%EC%8D%A8%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0" target="_blank" rel="noopener noreferrer">https://velog.io/@sojukang/Random-대신-ThreadLocalRandom을-써야-하는-이유</a></p>]]></content:encoded>
            <category>Java</category>
            <category>Map</category>
            <category>ConcurrentHashMap</category>
        </item>
        <item>
            <title><![CDATA[레디스 Atomic Operation위해 multi 와 luascript의 차이]]></title>
            <link>https://dgle.dev/redis-multi-lua</link>
            <guid>https://dgle.dev/redis-multi-lua</guid>
            <pubDate>Mon, 18 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[What is difference Between Redis luascript and multi exec]]></description>
            <content:encoded><![CDATA[<p>Redis에서 Atomic Operation을 위해 Luascirpt와 Multi Exec 중 뭘 써야할까?</p><h1>Redis에서 Atomic Operation을 위해 Luascirpt와 Multi Exec 중 뭘 써야할까?</h1><h2 class="anchor anchorWithStickyNavbar_LWe7" id="multi와--exec를-사용하면">Multi와  exec를 사용하면<a href="#multi와--exec를-사용하면" class="hash-link" aria-label="Direct link to Multi와  exec를 사용하면" title="Direct link to Multi와  exec를 사용하면">​</a></h2><p>Multi와 exec는 레디스에서 트랜잭션을 사용하겠다는 명령어인데 일반적인 RDB와 다르게 롤백기능이없다. (롤백기능이 없는 이유는 단순성과 성능에 상당한 영향을 미치기 때문에 RDB와 다르게 없다고한다.)<br>
<!-- -->그러면 레디스는 어떻게 트랜잭션을 바라볼까? Multi로 선언하면 multi안에 명령어들이 묶여 순서대로 같이 큐에 담기게된다. 그리고 EXEC를 만나는 순간 큐에 담긴 명령어들이 순서대로 한 오퍼레이션에 묶여 실행이되고<br>
<!-- -->만약 큐에 쌓인 명령어가 중간에 실패하는 일이 생기면 실패한 부분만 skip하고 다음부분이 연속적으로 실행되게된다. </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">MULTI</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token constant" style="color:#36acaa">OK</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">INCR</span><span class="token plain"> foo</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token constant" style="color:#36acaa">QUEUED</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">INCR</span><span class="token plain"> bar</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token constant" style="color:#36acaa">QUEUED</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token class-name">EXEC</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">integer</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">integer</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>위와 같이, exec의 명령을 한 순서대로 array형태로 응답값을 준다. </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="watch와-같이-사용하면">watch와 같이 사용하면<a href="#watch와-같이-사용하면" class="hash-link" aria-label="Direct link to watch와 같이 사용하면" title="Direct link to watch와 같이 사용하면">​</a></h3><p>우리가 사용하는 RDB의 optimistic lock과 같은데, 만약 짧은시간에 여러 클라이언트가 동시에 접근 할시 흔히 동시성 문제가 생기는데 <code>watch</code> 를 사용하면 해결이 된다. </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token constant" style="color:#36acaa">WATCH</span><span class="token plain"> mykey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">val </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">GET</span><span class="token plain"> mykey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">val </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> val </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token constant" style="color:#36acaa">MULTI</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token constant" style="color:#36acaa">SET</span><span class="token plain"> mykey $val</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token constant" style="color:#36acaa">EXEC</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>myKey라는 key에 watch를 주고(키를 감시) 작업 후에, exec(수신 전) 전 다른 클라이언트에서 먼저 val값을 수정을했으면 트랜잭션은 자동으로 실패하게 된다.<br>
<!-- -->이 때는 클라이언트의 수정뿐만 아니라 ttl에 의한 키만료 제거 등과같이 Redis에 자체에 의한 수정도 포함이된다.  </p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p>Trasnaction 안에 있는 명령은 exec가 전송 될 때까지 큐에 담겨있어서 watch에 트리거 되지 않으니 주의해야한다.</p></div></div><p>💡&nbsp;<code>Discard</code>
Discard는 큐에 담겨있는 것들을 버린다.</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&gt; SET foo 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">OK</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&gt; MULTI</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">OK</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&gt; INCR foo</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">QUEUED</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&gt; DISCARD</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">OK</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&gt; GET foo</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"1"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="luascript란">Luascript란<a href="#luascript란" class="hash-link" aria-label="Direct link to Luascript란" title="Direct link to Luascript란">​</a></h2><p>루아스크립트는 Redis에 내장된 실행 엔진에 의해 실행되는데. 현재 레디스는 단일 스크립트 엔진인 lua 5.1 인터피리터를 지원한다. 또 스크립트는 서버에서 실행되므로 이는 자연스럽게 네트워킹 리소스를 절약하게 되어 스크립트에서 데이터를 읽고 쓰는 건 매우 효율적이게 작동한다. 또 레디스에서 루아 스크립트를 사용하면 atomic을 함을 보장해준다. 또 루아스크립트를 사용하면 조건적인 update를 여러 키에 컬쳐 지원해주고,  개별의 각기다른 데이터 타입을 원자적으로 결합이가능해진다.</p><p>그냥 단순한 사용을 해본다면 </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token operator" style="color:#393A34">&gt;</span><span class="token constant" style="color:#36acaa">EVAL</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"return redis.call('SET', KEYS[1], ARGV[1])"</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> foo bar</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token constant" style="color:#36acaa">OK</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">GET</span><span class="token plain"> foo</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">bar</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>조금 더 사용을 해본다면 </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">EVAL</span><span class="token plain"> "redis</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token char">'sadd'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token char">'myset1'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token char">'user1'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">redis</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token char">'sadd'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token char">'myset2'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token char">'user2'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">local members </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> redis</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token char">'keys'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token char">'myset*'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">local results </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> index</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">key in </span><span class="token function" style="color:#d73a49">ipairs</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">members</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">do</span><span class="token plain"> results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">index</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> redis</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">'smembers'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">end </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> results" </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="차이점">차이점<a href="#차이점" class="hash-link" aria-label="Direct link to 차이점" title="Direct link to 차이점">​</a></h2><p><code>multi/exec</code> 는 트랜잭션 응답을 array 형태로 받아서 여러 명령어를 통해 예를들어 작업은 불가능하지만 Luasript는  script를 이용해 가능하다.<br>
<!-- -->예를 들어 lpop으로 담긴 userlist 큐에 순서대로 꺼내서 그 키값으로 user의 점수를 올린다고한다면 luascript를 사용하면 편하다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> lpush userList user1 user2 user3</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">EVAL</span><span class="token plain"> "</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">local user </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> redis</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token char">'LPOP'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> 'userList'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">local result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> redis</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token char">'INCRBY'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> user</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> result " </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="뭘-사용해야할까">뭘 사용해야할까<a href="#뭘-사용해야할까" class="hash-link" aria-label="Direct link to 뭘 사용해야할까" title="Direct link to 뭘 사용해야할까">​</a></h2><p><code>multi</code>를 사용하던 <code>luascript</code> 를 사용하던 둘다 atomic하게 한 오퍼레이션에 명령들을 한 번에 같이 보낼 수 있지만 특정 상황에서는 <code>multi/exec</code>로는 구현이 힘들 때가있으니 이때 luascript 사용이 대안이 될 수 있다.</p><br><h1>참고</h1><p><a href="https://redis.io/docs/manual/programmability/eval-intro/" target="_blank" rel="noopener noreferrer">https://redis.io/docs/manual/programmability/eval-intro/</a><br>
<a href="https://stackoverflow.com/questions/62970603/lua-scripts-vs-multi-exec-in-redis" target="_blank" rel="noopener noreferrer">https://stackoverflow.com/questions/62970603/lua-scripts-vs-multi-exec-in-redis</a><br>
<a href="https://redis.io/docs/manual/transactions/" target="_blank" rel="noopener noreferrer">redisTransaction</a><br>
<a href="https://redis.io/commands/eval/" target="_blank" rel="noopener noreferrer">https://redis.io/commands/eval/</a><br>
<a href="https://scalegrid.io/blog/redis-transactions-long-running-lua-scripts/" target="_blank" rel="noopener noreferrer">https://scalegrid.io/blog/redis-transactions-long-running-lua-scripts/</a><br>
<a href="https://engineering.linecorp.com/ko/blog/atomic-cache-stampede-redis-lua-script/" target="_blank" rel="noopener noreferrer">https://engineering.linecorp.com/ko/blog/atomic-cache-stampede-redis-lua-script/</a><br>
<a href="https://javamana.com/2022/195/202207141451441296.html" target="_blank" rel="noopener noreferrer">lua script limits to solve the problem of inaccurate high concurrency counts</a></p>]]></content:encoded>
            <category>Redis</category>
            <category>Luascript</category>
            <category>transaction</category>
        </item>
        <item>
            <title><![CDATA[만들면서 배우는 클린 아키텍처 정리 - 2]]></title>
            <link>https://dgle.dev/clean-arch-2</link>
            <guid>https://dgle.dev/clean-arch-2</guid>
            <pubDate>Mon, 27 Jun 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Clean Architecture Study - 2]]></description>
            <content:encoded><![CDATA[<p>만들면서 배우는 클린 아키텍처를 읽고 공부한 내용을 정리. - 2</p><p>모든 소스는 <a href="https://github.com/sk1737030/til/tree/master/clean-architecture" target="_blank" rel="noopener noreferrer">이곳에</a> 있습니다:)</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="테스트-전략">테스트 전략<a href="#테스트-전략" class="hash-link" aria-label="Direct link to 테스트 전략" title="Direct link to 테스트 전략">​</a></h3><p>만드는 비용이 적고, 유지보수하기 쉽고, 빨리 실행되고, 안정적인 작은 크기의 테스트들에 대해 높은 커버리지를 유지해야 한다는 것이다. 가장 확실한 건 하나의 클래스가 제대로 동작하는지 확인할 수 있는 <strong>단위테스트</strong>이다.<br>
<img loading="lazy" alt="테스트피라미드 [https://martinfowler.com/bliki/TestPyramid.html](https://martinfowler.com/bliki/TestPyramid.html)" src="/assets/images/Untitled 6-5ecf2d0767fd338463575c9a68deb301.png" width="560" height="300" class="img_ev3q"><br>
<!-- -->테스트피라미드 <a href="https://martinfowler.com/bliki/TestPyramid.html" target="_blank" rel="noopener noreferrer">https://martinfowler.com/bliki/TestPyramid.html</a><br>
<!-- -->위로 올라 갈 수록 비용이 비싸진다.  </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="테스트를-작성-할-때-지금하려는-목적이-뭔지-생각해야한다">테스트를 작성 할 때 지금하려는 목적이 뭔지 생각해야한다.<a href="#테스트를-작성-할-때-지금하려는-목적이-뭔지-생각해야한다" class="hash-link" aria-label="Direct link to 테스트를 작성 할 때 지금하려는 목적이 뭔지 생각해야한다." title="Direct link to 테스트를 작성 할 때 지금하려는 목적이 뭔지 생각해야한다.">​</a></h3><p>테스트는 서비스가 모킹된 대상의 특정 메서드와 상호작용했는지 여부를 검사 할 수 있는데 만약 모든 것을 검증하려다 보면 클래스가 조금이라도 변경되면 테스트가 쉽게 변경이된다. 이는 테스트의 본질을 떨어뜨리는 행위기 때문에 불필요한 부분은 테스트를 하지 않고 <strong>중요한 핵심 비지니스만 검증</strong>을 하는 것이 더 낫다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="얼마만큼의-테스트면-충분할까">얼마만큼의 테스트면 충분할까?<a href="#얼마만큼의-테스트면-충분할까" class="hash-link" aria-label="Direct link to 얼마만큼의 테스트면 충분할까?" title="Direct link to 얼마만큼의 테스트면 충분할까?">​</a></h3><p>라인 커버리지는 중요하지 않다. 80% 로든 심지어 100%로든 버그가 없다고 할 수 없다. 사람마다 다르겠지만 그냥 내가 마음이 불안하지않고 편하다면 충분하다고 생각이든다. 테스트를 실행 후에 마음이 편안한 상태로 배포를 할 수 있으면 충분하다고 본다.
육각형 아키텍처에서의 테스트 전략은 </p><ol><li><p>도메인 엔티티를 구현할 때에는 <strong>단위 테스트로</strong> 커버  </p></li><li><p>유스케이스를 구현 할 때는 <strong><a href="https://github.com/sk1737030/til/blob/master/clean-architecture/src/test/java/com/clean/architecture/hexagonal/account/application/service/SendMoneyServiceTest.java" target="_blank" rel="noopener noreferrer">단위 테스트로</a></strong> 커버</p></li><li><p>어댑터를 구현할 때는 <strong><a href="https://github.com/sk1737030/til/blob/master/clean-architecture/src/test/java/com/clean/architecture/hexagonal/account/adapter/in/web/SendMoneyControllerTest.java" target="_blank" rel="noopener noreferrer">통합 테스트로</a></strong> 커버</p></li><li><p>사용자가 취할 수 있는 중요 애플리케이션 경로는 <a href="https://github.com/sk1737030/til/blob/e41051a996d373182946204aa5d94a51b7ab0f20/clean-architecture/src/test/java/com/clean/architecture/hexagonal/SendMoneySystemTest.java" target="_blank" rel="noopener noreferrer">시스템 테스트로</a> 커버</p><br></li></ol><p><code>시스템 테스트</code>와 <code>통합테스트</code> 의 목적은 다르다.</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p><strong>통합테스트는</strong> 주로  <code>@WebMvcTest</code> 애너테이션을 사용하여 스프링이 특정 요청 경로, 자바와 JSON간의 매핑, http 입력 검증, 응답 값 검증 등에 필요한 전체 객체 네트워크를 인스턴스화하도록 만든다. 그리고 테스트에서는 웹 컨트롤러가 네트워크의 일부로서 잘 동작하는지 검증하기 때문에 필요하다.</p></div></div><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p>새로운 필드를 추가할 때마다 테스트를 고치는 데 한 시간을 써야 한다면 뭔가 잘못된것이다!!!! 테스트 코드도 리팩토링 대상이다. 모킹하는 것이 너무 버거워지거나 코드의 특정 부분을 커버하기 위해 어떤 종류의 테스트를 써야 할지 모르겠다면 이는 <strong>경고 신호</strong>이다.</p></div></div><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="아키텍처-경계-강제하기">아키텍처 경계 강제하기<a href="#아키텍처-경계-강제하기" class="hash-link" aria-label="Direct link to 아키텍처 경계 강제하기" title="Direct link to 아키텍처 경계 강제하기">​</a></h3><p><img loading="lazy" alt="[https://reflectoring.io/book/](https://reflectoring.io/book/)" src="/assets/images/Untitled 7-816662776ea7dd431b8eb0f2653b63d4.png" width="638" height="639" class="img_ev3q">
<a href="https://reflectoring.io/book/" target="_blank" rel="noopener noreferrer">https://reflectoring.io/book/</a> </p><p>애플리케이션 계층은 애플리케이션 서비스안에 유스케이스를 구현하기 위해 도메인 엔티티에 접근한다.<br>
<!-- -->어댑터는 인커밍 포트를통해 서비스에 접근하고, 반대로 서비스는 아웃고잉 포트를 통해 어댑터에 접근한다.<br>
<!-- -->마지막으로 설정 계층은 어댑터와 서비스 객체를 생성할 팩터리를 포함하고 있고, 의존성 주십 메커니즘을 제공한다.<br>
<!-- -->의존성 규칙에 따르면 계층 경계를 넘는 의존성은 항상 안쪽방향으로 향해야 한다.  </p><br><p>경계표시를 위해서 자바에서 많이 쓰는 방법이  접근제한자를 쓰는 것이다. <code>package-private(default)</code>, <code>protectect</code>, <code>private</code> 를 사용한다.</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p><code>package-private</code>는 만능이 아니다. 패키지 내에 클래스가 특정 개수를 넘어가기 시작하면 하나의 패키지에 너무 많은 클래스를 포함하는 것이 혼란스러워지게 된다. 이렇게 되면 코드를 쉽게 찾을 수 있도록 하위 패키지를 두게 되는데 자바는 하위 패키지를 다른 패키지로 취급하기 때문에 하위 패키지의 package-private 멤버에 접근할 수 없게 된다. 그래서 하위 패키지의 멤버는 public으로 만들어서 바깥 세계에 노출시켜야 하기 때문에 규칙이 깨질 수 있다.</p></div></div><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="깨진창문이론">깨진창문이론<a href="#깨진창문이론" class="hash-link" aria-label="Direct link to 깨진창문이론" title="Direct link to 깨진창문이론">​</a></h3><ul><li>품질이 떨어진 코드에서 작업할 때 더 낮은 품질의 코드를 추가하기가 쉽다.  </li><li>테스트코드가 없는 코드는 테스트코드를 추가하지 않기 쉽다.  </li><li>지름길을 많이 사용한 코드에서 작업할 때 또 다른 지름길을 추가하기 쉽다.  </li><li>코딩 큐칙을 많이 어긴 코드에서 작업할 때 또 다른 큐칙을 어기기도 쉽다.  </li><li>깃 브랜치를 어지럽게 하면 점점 더 어지러워진다.  </li></ul><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="의식적으로-지름길을-사용하기">의식적으로 지름길을 사용하기<a href="#의식적으로-지름길을-사용하기" class="hash-link" aria-label="Direct link to 의식적으로 지름길을 사용하기" title="Direct link to 의식적으로 지름길을 사용하기">​</a></h3><p>지름길이 꼭 나쁜건 아니다. 때로는 시간적, 경제적등 다양한이유로 사용 할 수 있다. 이때에는 의도적으로 지름길을 사용했다는 사실을 문서로 남기고 팀에 공유하자 그러면 깨진 창문 이론의 영향을 더 줄일 수 있을 것이다.  </p><ul><li>인커밍 포트 건너뛰기<ul><li>컨트롤러에서 서비스 바로 접근하기</li></ul></li><li>애플리케이션 서비스 건너뛰기<ul><li>컨트롤러에서 레포지토리 바로 접근하기</li></ul></li><li>도메인 엔티티를 입출력 모델로 사용하기</li><li>유스케이스간 같은 모델 공유하기<ul><li>다른 유스케이스인데 같은 모델을 공유</li></ul></li></ul><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="도메인이-왕이다">도메인이 왕이다<a href="#도메인이-왕이다" class="hash-link" aria-label="Direct link to 도메인이 왕이다" title="Direct link to 도메인이 왕이다">​</a></h3><p>애플리케이션을 개발 할 때 도메인이 정말 중요하다면, 육각형 아키텍처를 사용 할 수 있다. <code>외부의 영향을 받지 않고 도메인 코드를 자유롭게 발전시킬 수 있다는 것은 육각형 아키텍처 스타일이 내세우는 가장 중요한 가치다.</code>  육각형 아키텍처는 당연한 말이겠지만 DDD의 조력자이다.   </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="경험이-여왕이다">경험이 여왕이다.<a href="#경험이-여왕이다" class="hash-link" aria-label="Direct link to 경험이 여왕이다." title="Direct link to 경험이 여왕이다.">​</a></h3><p>인간은 습관의 동물이기 때문에 편안한 길로 가려고한다. 물론 이게 나쁜 결정이 아니지만 다른 경험도 해보면 더 좋은 길을 찾을 수 있기 때문에, 작은 모듈부터 시작을 해서 경험을 해나가는 연습을 가지자. 내가 생각 했을 때는  중요한 것은 <code>정답은 없다</code> 그때그때 다르다 도메인마다 다르고 어떤 소프트웨어를 만드냐에 다르고 팀의 경험에 따라 다르다 그리고 내 마음에 드느냐에 따라서도 다르니 정답이 없다.  </p><br><br><h1>참고</h1><p><a href="http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&amp;mallGb=KOR&amp;barcode=9791158392758&amp;orderClick=LAG&amp;Kc=" target="_blank" rel="noopener noreferrer">만들면서 배우는 클린 아키텍처</a><br>
<a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html" target="_blank" rel="noopener noreferrer">로버트마르틴형의원문</a> → <a href="https://blog.coderifleman.com/2017/12/18/the-clean-architecture/" target="_blank" rel="noopener noreferrer">한글번역</a><br>
<a href="https://martinfowler.com/bliki/TestPyramid.html" target="_blank" rel="noopener noreferrer">마틴형의테스트피라미드</a></p>]]></content:encoded>
            <category>Spring Boot</category>
            <category>Clean Architecture</category>
            <category>Book</category>
        </item>
        <item>
            <title><![CDATA[만들면서 배우는 클린 아키텍처 정리 - 1]]></title>
            <link>https://dgle.dev/clean-arch-1</link>
            <guid>https://dgle.dev/clean-arch-1</guid>
            <pubDate>Sat, 25 Jun 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Clean Architecture Study - 1]]></description>
            <content:encoded><![CDATA[<p>만들면서 배는 클린 아키텍처를 읽고 공부한 내용을 정리. - 1</p><p>모든 소스는 <a href="https://github.com/sk1737030/til/tree/master/clean-architecture" target="_blank" rel="noopener noreferrer">이곳에</a> 있습니다:)</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="계층형-아키텍처의-문제점">계층형 아키텍처의 문제점<a href="#계층형-아키텍처의-문제점" class="hash-link" aria-label="Direct link to 계층형 아키텍처의 문제점" title="Direct link to 계층형 아키텍처의 문제점">​</a></h2><h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-서비스에서-영속성에-강한-결합이-생긴다">1. 서비스에서 영속성에 강한 결합이 생긴다<a href="#1-서비스에서-영속성에-강한-결합이-생긴다" class="hash-link" aria-label="Direct link to 1. 서비스에서 영속성에 강한 결합이 생긴다" title="Direct link to 1. 서비스에서 영속성에 강한 결합이 생긴다">​</a></h3><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled-43962373f5c365a4e0c6dd908ed1bde7.png" width="1364" height="734" class="img_ev3q">
일반적인 프로젝트 구조상 서비스는 영속성 모델을 비지니스 모델처럼 사용하게 되고 이로 인해 도메인 로직뿐만 아니라 여러 영속성 계층과 관련된 작업들을(트랜잭션, 즉시로딩, 지연로딩, 캐시 플러시)등등을 해야한다.  </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-지름길을-택하기-쉬워진다">2. 지름길을 택하기 쉬워진다<a href="#2-지름길을-택하기-쉬워진다" class="hash-link" aria-label="Direct link to 2. 지름길을 택하기 쉬워진다" title="Direct link to 2. 지름길을 택하기 쉬워진다">​</a></h3><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 1-e6377eb94a979516c00ca865ca028415.png" width="1400" height="626" class="img_ev3q">
여러명이 개발하고 시간이 지나다보면 유틸리티, 헬퍼 등 여러 컴포넌트들이 영속성에 추가하여 개발을 하기쉽고 편하기 때문에 결국 영속성 레이어가 비대해지는 현상이 일어나게된다.  </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-서비스-계층을-스킵-할-수가-있다">3. 서비스 계층을 스킵 할 수가 있다<a href="#3-서비스-계층을-스킵-할-수가-있다" class="hash-link" aria-label="Direct link to 3. 서비스 계층을 스킵 할 수가 있다" title="Direct link to 3. 서비스 계층을 스킵 할 수가 있다">​</a></h3><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 2-e09a412c92e8ef89f563909c5a51e694.png" width="1390" height="848" class="img_ev3q"></p><p>간단한 디비 저장일뿐인 단순한 API일 경우 중간에 있는 서비스를 건너뛰고 바로 컨트롤러에서 영속성 계층에 접근을 해서 작업을 할 때가 있는데 이렇게 되면 여러 문제들이 발생 할 수 있다. </p><p>첫 번째 문제는 요구사항이 변경이되면 Controller 여러 추가적인 책임들이 추가가되기 쉬워지는데(혼자 할 때는 괜찮지만, 여러사람이 협업을하다 보면), 레이어간의 책임이 정말 애매모호해 지게된다. </p><p>두 번째 문제는 테스트 코드에서의 복잡도가 올라가게 된다. mock을 만드는 등 추가적인 작업을 해야 할 필요가 있게되는데 이러면 테스트 코드를 이해하는데도 시간이 더 걸리고 그러면 테스트 코드 짜기가 점점 더 힘들어지고 싫어지게된다. </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="4-수정이-힘들어진다">4. 수정이 힘들어진다.<a href="#4-수정이-힘들어진다" class="hash-link" aria-label="Direct link to 4. 수정이 힘들어진다." title="Direct link to 4. 수정이 힘들어진다.">​</a></h3><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 3-d4ff12083fb582a34b5b03a1ea408da3.png" width="1370" height="826" class="img_ev3q"></p><p>여러명이 협업을하면서 시간이 흐르다보면 서비스계층의 책임이 점점 많아지게 되는데, 이렇게 진행되다보면 테스트 코드도 짜기가 점점 힘들어지고, 기능을 추가 혹은 수정 해야 할 때 선뜻 사이드 이펙트를 예측하기가 힘들어지게 된다.</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p>기획자: 이거 기획이 추가되어서, 간단한 기능 하나 추가 할 수 있을까요?<br>
<!-- -->나: 음.. 이건 한 번 봐야할 거 같아요. 조금 소스가 복잡해서… (또르륵)</p></div></div><br><h2 class="anchor anchorWithStickyNavbar_LWe7" id="육각형-아키텍쳐헥사고날">육각형 아키텍쳐(헥사고날)<a href="#육각형-아키텍쳐헥사고날" class="hash-link" aria-label="Direct link to 육각형 아키텍쳐(헥사고날)" title="Direct link to 육각형 아키텍쳐(헥사고날)">​</a></h2><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 4-fc7f43037533474f4154affedf6ea8bd.png" width="1518" height="816" class="img_ev3q"></p><p>육각형 아키텍처는 알리스테어 코번이 만든 용어로, 로버트 마틴이 클린 차키텍처에서 조금 더 일반적인 용어로 설명 하였다. </p><p>안에는 도메인 엔티티와 이와 상호작용하는 유스케이스가 있다. 육각형 바깥에는 애플리케이션과 상호작용하는 다양한 어댑터들이 있다. </p><p>왼쪽에 있는 어댑터들은 애플리케이션을 주도하는 어댑터들이다. 코어와 어댑터들간에 통신을 하려면 각각의 포트들을 제공해야한다. 이 포트들은 <strong>인터페이스</strong>들이 되는 것이다. </p><p>가장 바깥쪽에 있는 계층은 애플리케이션과 다른 시스템 간의 번역을 담당하는 어댑터로 구성되어 있다. </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="case마다-다른-출력-모델">Case마다 다른 출력 모델<a href="#case마다-다른-출력-모델" class="hash-link" aria-label="Direct link to Case마다 다른 출력 모델" title="Direct link to Case마다 다른 출력 모델">​</a></h3><p>항상 나는 이 질문에 고민을 많이 했다. 호출자에게 정보를 어디까지 줘야할까라는 질문에 사실 정답이 없지만, 여러 컨트롤러에서 같은 서비스에 접근을 해야 할 때 처음에는 같은 모델로 돌려주게 개발을 하고 나중에 시간이 지나 점점 눈덩이처럼 점점 커지는 모델들을 경험을 많이 해서 고민이 많았는데 책에서 하는 말이 </p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p>유스케이스를 가능한 한 구체적으로 유지하기 위해서는 <strong>계속 질문을 해야한다</strong>. 만약 의심스럽다면 가능한 한 적게 반환하자. 유스케이스들 간에 같은 출력 모델을 공유하게 되면 유스케이스들도 강하게 결합된다. 한 유스케이스에서 출력 모델에 새로운 필드가 필요해지면 이 값과 관련이 없는 다른 유스케이스들에서도 이 필드를 처리해야 한다. 공유 모델은 장기적으로 봤을 때 갖가지 이유로 점점 커지게 돼 있다. <strong>단일 책임 원칙을 적용하고 모델을 분리해서 유지하는 것은 유스케이스의 결합을 제거하는 데 도움이 된다.</strong></p></div></div><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="웹-어댑터의-책임">웹 어댑터의 책임<a href="#웹-어댑터의-책임" class="hash-link" aria-label="Direct link to 웹 어댑터의 책임" title="Direct link to 웹 어댑터의 책임">​</a></h3><ol><li>HTTP 요청을 자바 객체로 매핑</li><li>권한 검사</li><li>입력 유효성검증<ul><li>유스케이스에서의 입력 모델 검증과 어댑터에서의 검증의 차이는 <strong>맥락의 차이</strong>인데 유스케이스에서의 입력 모델에서 유효한 입력만 허용해야한다. 내 생각에는 출금과 관련된 유스케이스에서 유스케이스에서 검증 할 때 있을 때 ‘잔금은 돈은 0원 보다 더 커야 한다’ 의 차이 이지 않을까라고 생각든다.</li></ul></li><li>입력을 유스케이스의  입력 모델로 매핑</li><li>유스케이스 호출</li><li>유스케이스의 출력을 HTTP로 매핑</li><li>HTTP 응답을 반환</li></ol><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="create로-이름을-짖는거는-지양하자">Create로 이름을 짖는거는 지양하자<a href="#create로-이름을-짖는거는-지양하자" class="hash-link" aria-label="Direct link to Create로 이름을 짖는거는 지양하자" title="Direct link to Create로 이름을 짖는거는 지양하자">​</a></h3><p>이미 어딘가에 많이 쓰이고 있는 예약어이기 때문에 Create→Register 로 변경하여 이름을 짖자.<br>
<!-- -->CreteAccountController → RegisterAccountController<br>
<!-- -->Create, Update, Delete … naming으로 역할을 만들기 전에 한 번더 생각을 해보는 게 좋다.  </p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="여러-작은-클래스들을-만드는-것을-두려워해서는-안된다">여러 작은 클래스들을 만드는 것을 두려워해서는 안된다.<a href="#여러-작은-클래스들을-만드는-것을-두려워해서는-안된다" class="hash-link" aria-label="Direct link to 여러 작은 클래스들을 만드는 것을 두려워해서는 안된다." title="Direct link to 여러 작은 클래스들을 만드는 것을 두려워해서는 안된다.">​</a></h3><p>여러 작은 클래스들을 만드는 것을 두려워해서는 안된다. 작은 클래스들은 파악하기 쉽고, 테스트하기 쉽고, 여러명이서 작업을 할 수 있게된다. 처음에는 공수가 더 들겠지만 나중에 유지보수 할 때에는 시간이 단축될 것이다.</p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="영속성-어댑터">영속성 어댑터<a href="#영속성-어댑터" class="hash-link" aria-label="Direct link to 영속성 어댑터" title="Direct link to 영속성 어댑터">​</a></h3><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 5-b8777d388b7088ad61fc5cfc2e8f1851.png" width="1460" height="532" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="영속성-어댑터의-책임">영속성 어댑터의 책임<a href="#영속성-어댑터의-책임" class="hash-link" aria-label="Direct link to 영속성 어댑터의 책임" title="Direct link to 영속성 어댑터의 책임">​</a></h3><ol><li>입력을 받는다.</li><li>입력을 데이터베이스 포맷으로 매핑한다.</li><li>입력을 데이터베이스로 보낸다</li><li>데이터베이스 출력을 애플리케이션 포맷으로 매핑한다.</li><li>출력을 반환한다.</li></ol><br><br><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p>요기서도 마찬가지로 평소에 영속성 레포지토리가 여러 책임들을 한 번에 가지고 있는 부분이 많아서 얘를 어떻게 해야하나 고민이많았는데, 이 책에서 <strong>ISP</strong>를 지키지 않는지 확인해보라고 조언을 해준다. 지키려고 노력을 하다보면 책임을 분산 할 수 있어진다.</p></div></div><h1>참고</h1><p><a href="http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&amp;mallGb=KOR&amp;barcode=9791158392758&amp;orderClick=LAG&amp;Kc=" target="_blank" rel="noopener noreferrer">만들면서 배우는 클린 아키텍처</a><br>
<a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html" target="_blank" rel="noopener noreferrer">로버트마르틴형의원문</a> → <a href="https://blog.coderifleman.com/2017/12/18/the-clean-architecture/" target="_blank" rel="noopener noreferrer">한글번역</a></p>]]></content:encoded>
            <category>Spring Boot</category>
            <category>Clean Architecture</category>
            <category>Book</category>
        </item>
        <item>
            <title><![CDATA[Spring Kafka Graceful Shutdown]]></title>
            <link>https://dgle.dev/kafkashutodwn</link>
            <guid>https://dgle.dev/kafkashutodwn</guid>
            <pubDate>Mon, 20 Jun 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Spring kafka는 Graceful shutdown하게 잘 죽을까?]]></description>
            <content:encoded><![CDATA[<p>Consumer가 메세지를 처리중에 Spring Boot 어플리케이션에서 shutdown event가 일어 났을 때 과연 잘 Shutdown Graceful하게  종료가 되는지가 궁금해서 해보는 실험. </p><p><a href="https://github.com/sk1737030/til/tree/master/spring-kafka-graceful-shutdown" target="_blank" rel="noopener noreferrer">모든 소스는 이곳</a>에서 확인 가능합니다 :)</p><h1>Spring Boot Kafka Grace full Shutdown</h1><p>Consumer가 메세지를 처리중에 Spring Boot 어플리케이션에서 shutdown event가 일어 났을 때 과연 잘 Shutdown Graceful하게  종료가 되는지가 궁금해서 해보는 실험. </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="무엇을-테스트하냐">무엇을 테스트하냐<a href="#무엇을-테스트하냐" class="hash-link" aria-label="Direct link to 무엇을 테스트하냐" title="Direct link to 무엇을 테스트하냐">​</a></h2><p>Consumer가 컨슘 후 데이터를 잘 commit하는지 Conusmer info 관찰 </p><p><code>shutdownTimeout</code> : defualt 30초 </p><p><code>Kafka version</code>: 2.7.1</p><p><code>SpringBootVersion</code>: v2.5.6</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="방법">방법<a href="#방법" class="hash-link" aria-label="Direct link to 방법" title="Direct link to 방법">​</a></h2><ol><li><code>shutdownTimeout</code>  내 정상적으로 모든 메세지가 잘 처리 되도록<ol><li>Spring Boot Kafka 메세지를 10개 생성</li><li>Consume 할 때 처리 시간이 개당 1초가 걸리도록 실험 </li><li>모든 메세지를 소비 할 때까지 최소 10초의 시간이 필요한 작업으로 설정</li><li>컨슈머 커밋이 어떻게 되는지 확인</li></ol></li><li><code>shutdownTimeout</code>을 넘어서도록 설정 <ol><li>Spring Boot Kafka 메세지를 10개 생성</li><li>Consume 할 때 처리 시간이 개당 10초가 걸리도록 실험 </li><li>모든 메세지를 소비 할 때까지 최소 100초의 시간이 필요한 작업으로 설정 </li><li>컨슈머 커밋이 어떻게 되는지 확인</li></ol></li></ol><p><code>Shutdown Signal</code>은 단순하게 2로 테스트할 예정이다.</p><p>linux의 shutdow number 확인</p><p><img loading="lazy" alt="[https://linuxhint.com/kill-signal-numbers-linux/](https://linuxhint.com/kill-signal-numbers-linux/)" src="/assets/images/Untitled-671ac2e53ea4b2c169c8bb71835d55b4.png" width="1176" height="487" class="img_ev3q">  </p><p><a href="https://linuxhint.com/kill-signal-numbers-linux/" target="_blank" rel="noopener noreferrer">https://linuxhint.com/kill-signal-numbers-linux/</a></p><ul><li><strong>SIGKILL (9)</strong>: SIGKILL signal 은 프로세스를 즉각 종료 할 때 사용한다.</li><li><strong>SIGINT(2)</strong>: 사용자의 요청으로 중단이 될 때 사용한다. (e.g., Ctrl+C).</li><li>S<strong>IGTERM(15)</strong>: SIGTERM signal 종료 요청을 보낸다, 요청을 보낼 뿐 SIGKILL은 아니다.</li></ul><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>aSigterm</div><div class="admonitionContent_S0QG"><p>안전하게 어플리케이션을 종료하고 싶으면 <code>SIGINT</code>나 <code>SIGTEMR</code>으로 요청을 추천한다.</p></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="실험-및-결과">실험 및 결과<a href="#실험-및-결과" class="hash-link" aria-label="Direct link to 실험 및 결과" title="Direct link to 실험 및 결과">​</a></h2><p>각종 설정은 default로 설정하고 진행한다.</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">fetch.max.bytes = 52428800</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">fetch.max.wait.ms = 500</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">fetch.min.bytes = 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">auto.commit.interval.ms = 5000</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="1번">1번<a href="#1번" class="hash-link" aria-label="Direct link to 1번" title="Direct link to 1번">​</a></h3><p>Consumer test.offset.1의  offset 확인  </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 1-4f9e3d4c75374a28b08744721e2462e6.png" width="1658" height="168" class="img_ev3q">  </p><ul><li><code>current-offset</code>: 36</li><li><code>Lag</code>: 9</li></ul><p>어플리케이션 종료 <code>signal 2: SIGINT</code>  </p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">2022-06-08 16:45:18.347 DEBUG 11696 --- [ionShutdownHook] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@34d046b6, started on Wed Jun 08 16:45:09 KST 2022</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2022-06-08 16:45:18.347 DEBUG 11696 --- [ionShutdownHook] ySourcesPropertyResolver$DefaultResolver : Found key 'spring.liveBeansView.mbeanDomain' in PropertySource 'systemProperties' with value of type String</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2022-06-08 16:45:18.348 DEBUG 11696 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147483547</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Debug로 로그 확인  </p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">essageListenerContainer$ListenerConsumer : Commit list: {test-0=OffsetAndMetadata{offset=45, leaderEpoch=null, metadata=''}}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">essageListenerContainer$ListenerConsumer : Committing: {test-0=OffsetAndMetadata{offset=45, leaderEpoch=null, metadata=''}}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">org.apache.kafka.clients.NetworkClient   : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Sending OFFSET_COMMIT request with header RequestHeader(apiKey=OFFSET_COMMIT, apiVersion=7, clientId=consumer-test.offset.1-1, correlationId=17) and timeout 30000 to node 2147483646: {group_id=test.offset.1,generation_id=5,member_id=consumer-test.offset.1-1-0fd44995-c1a6-451a-9987-ab35edab9f74,group_instance_id=null,topics=[{name=test,partitions=[{partition_index=0,committed_offset=45,committed_leader_epoch=-1,committed_metadata=}]}]}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">org.apache.kafka.clients.NetworkClient   : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Received OFFSET_COMMIT response from node 2147483646 for request with header RequestHeader(apiKey=OFFSET_COMMIT, apiVersion=7, clientId=consumer-test.offset.1-1, correlationId=17): OffsetCommitResponseData(throttleTimeMs=0, topics=[OffsetCommitResponseTopic(name='test', partitions=[OffsetCommitResponsePartition(partitionIndex=0, errorCode=0)])])</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.a.k.c.c.internals.ConsumerCoordinator  : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Committed offset 45 for partition test-0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.a.k.c.c.internals.ConsumerCoordinator  : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Executing onLeavePrepare with generation Generation{generationId=5, memberId='consumer-test.offset.1-1-0fd44995-c1a6-451a-9987-ab35edab9f74', protocol='range'} and memberId consumer-test.offset.1-1-0fd44995-c1a6-451a-9987-ab35edab9f74</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.a.k.c.c.internals.ConsumerCoordinator  : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Revoke previously assigned partitions test-0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.s.k.l.KafkaMessageListenerContainer    : test.offset.1: partitions revoked: [test-0]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">essageListenerContainer$ListenerConsumer : Commit list: {}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.a.k.c.c.internals.AbstractCoordinator  : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Member consumer-test.offset.1-1-0fd44995-c1a6-451a-9987-ab35edab9f74 sending LeaveGroup request to coordinator localhost:9092 (id: 2147483646 rack: null) due to the consumer unsubscribed from all topics</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">org.apache.kafka.clients.NetworkClient   : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Sending LEAVE_GROUP request with header RequestHeader(apiKey=LEAVE_GROUP, apiVersion=2, clientId=consumer-test.offset.1-1, correlationId=18) and timeout 30000 to node 2147483646: {group_id=test.offset.1,member_id=consumer-test.offset.1-1-0fd44995-c1a6-451a-9987-ab35edab9f74}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.a.k.c.c.internals.AbstractCoordinator  : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Resetting generation due to consumer pro-actively leaving the group</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.a.k.clients.consumer.KafkaConsumer     : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Unsubscribed all topics or patterns and assigned partitions</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.s.s.c.ThreadPoolTaskScheduler          : Shutting down ExecutorService</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.a.k.c.c.internals.AbstractCoordinator  : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Heartbeat thread has closed</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.a.k.c.c.internals.ConsumerCoordinator  : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Executing onLeavePrepare with generation Generation{generationId=-1, memberId='', protocol='null'} and memberId</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.a.k.c.c.internals.AbstractCoordinator  : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Resetting generation due to consumer pro-actively leaving the group</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">org.apache.kafka.clients.NetworkClient   : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] Received LEAVE_GROUP response from node 2147483646 for request with header RequestHeader(apiKey=LEAVE_GROUP, apiVersion=2, clientId=consumer-test.offset.1-1, correlationId=18): LeaveGroupResponseData(throttleTimeMs=0, errorCode=0, members=[])</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">o.a.k.c.c.internals.AbstractCoordinator  : [Consumer clientId=consumer-test.offset.1-1, groupId=test.offset.1] LeaveGroup response with Generation{generationId=5, memberId='consumer-test.offset.1-1-0fd44995-c1a6-451a-9987-ab35edab9f74', protocol='range'} returned successfully: ClientResponse(receivedTimeMs=1655698563052, latencyMs=12, disconnected=false, requestHeader=RequestHeader(apiKey=LEAVE_GROUP, apiVersion=2, clientId=consumer-test.offset.1-1, correlationId=18), responseBody=LeaveGroupResponseData(throttleTimeMs=0, errorCode=0, members=[]))</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>흥미로운 로그가 몇 개 보인다. </p><ol><li>OFFSET_COMMIT  </li><li>Revoke Listener가 작동을 하고  </li><li>LeaveGroup Request  </li><li>Thread Shutodnw Event가 시작을 하고   </li><li>HeaerBeat thread가 종료 되고   </li><li>LeaveGroup을 받는다.  </li></ol><p>topic의 offset 확인<br>
<img loading="lazy" alt="Untitled" src="/assets/images/Untitled 2-72f0b62cfd75f63232ff3318a762c11b.png" width="1444" height="252" class="img_ev3q">  </p><ul><li><code>current-offset</code>:45</li><li><code>lag</code>: 0</li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="2번">2번<a href="#2번" class="hash-link" aria-label="Direct link to 2번" title="Direct link to 2번">​</a></h3><p>Consumer test.offset.1의  offset 확인 </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 1-4f9e3d4c75374a28b08744721e2462e6.png" width="1658" height="168" class="img_ev3q"></p><ul><li>current-offset: 36</li><li>Lag: 9</li></ul><p>어플리케이션 종료 <code>signal 2: SIGINT</code></p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">2022-06-08 16:45:18.347 DEBUG 11696 --- [ionShutdownHook] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@34d046b6, started on Wed Jun 08 16:45:09 KST 2022</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2022-06-08 16:45:18.347 DEBUG 11696 --- [ionShutdownHook] ySourcesPropertyResolver$DefaultResolver : Found key 'spring.liveBeansView.mbeanDomain' in PropertySource 'systemProperties' with value of type String</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">2022-06-08 16:45:18.348 DEBUG 11696 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147483547</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Shout down TimeOut 이후 로그를 본다면</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">2022-06-03 18:16:35.861  INFO 9116 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  :</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> **Failed to shut down 1 bean with phase value 2147483547 within timeout of 30000ms:** </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[org.springframework.kafka.config.internalKafkaListenerEndpointRegistry]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Offset 확인</p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 3-280c06be7968e3cb3a0a375f7c5bfe0d.png" width="1440" height="264" class="img_ev3q"></p><p><code>shutdown timeout</code>으로 인해 Commit이 정상적으로 안된 상태이다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="결론">결론<a href="#결론" class="hash-link" aria-label="Direct link to 결론" title="Direct link to 결론">​</a></h3><p>Timeout 이내에 메시지는 잘 <code>Graceful</code>하게 처리한다. 그러나 만약 timeout 내에 처리를 못 한다면 메시지를 중복으로 처리하는 상황이 나타날 수 있으니, 적절한 방어 로직과 수동 commit으로 풀어서 처리를하거나 timeout을 알맞게 설정해야 할 거 같다.</p><h1>참고</h1><p><a href="https://docs.spring.io/spring-kafka/docs/2.5.17.RELEASE/reference/html/" target="_blank" rel="noopener noreferrer">https://docs.spring.io/spring-kafka/docs/2.5.17.RELEASE/reference/html/</a><br>
<a href="https://bravenamme.github.io/2020/10/06/graceful-shutdown/" target="_blank" rel="noopener noreferrer">https://bravenamme.github.io/2020/10/06/graceful-shutdown/</a><br>
<a href="https://docs.confluent.io/confluent-cli/current/overview.html" target="_blank" rel="noopener noreferrer">https://docs.confluent.io/confluent-cli/current/overview.html</a><br>
<a href="https://kafka.apache.org/documentation/" target="_blank" rel="noopener noreferrer">https://kafka.apache.org/documentation/</a><br>
<a href="https://linuxhint.com/kill-signal-numbers-linux/" target="_blank" rel="noopener noreferrer">signum 번호 설명</a>
<a href="https://github.com/adevinta/zoe" target="_blank" rel="noopener noreferrer">zoe kafka cli</a><br>
<a href="https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html" target="_blank" rel="noopener noreferrer">consume Config 설명</a></p>]]></content:encoded>
            <category>SpringBoot</category>
            <category>Kafka</category>
            <category>Graceful</category>
            <category>Shutdown</category>
        </item>
        <item>
            <title><![CDATA[내가 겪은 N + 1 문제]]></title>
            <link>https://dgle.dev/my_n+1</link>
            <guid>https://dgle.dev/my_n+1</guid>
            <pubDate>Sat, 28 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Spring Boot N+1 JPA]]></description>
            <content:encoded><![CDATA[<p>JPA를 쓰면서 우리가 일반적으로 발생하여서 해볼 건 다 해봐도 안됐었던 N+1 문제 </p><p><a href="https://github.com/sk1737030/til/tree/master/til-jpa" target="_blank" rel="noopener noreferrer">모든 소스는 이곳</a>에서 확인 가능합니다 :)</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="n--1-문제">N + 1 문제<a href="#n--1-문제" class="hash-link" aria-label="Direct link to N + 1 문제" title="Direct link to N + 1 문제">​</a></h2><p>JPA를 쓰면서 우리가 일반적으로 발생하여서 해볼 건 다 해봐도 안됐었던 N+1 문제<br>
<!-- -->일반적으로 우리가 흔히 N+1문제가 발생을 할 수 있는데 이미 많은 사람이 알겠지만 킹갓영환님의 책을 보거나 강의를 보면 진짜 다 해결이 가능했는데<br>
<!-- -->내가 마주한 문제는 해결이 안 됐었다. 일반적으로 해결을 위해 그에 상황마다 다르겠지만 흔하게 가장 먼저 lazy로 변경, fetch join, fetch size조정 등 여러 작업을 했는데<br>
<!-- -->해결이 안 됐었다.</p><p>코드가 많이 다르고 도메인도 다르지만 그나마 비슷하게 코드를 재현 해보자면</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Entity</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@NoArgsConstructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">access </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">AccessLevel</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">PROTECTED</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@AllArgsConstructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">access </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">AccessLevel</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">PROTECTED</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Getter</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Member</span><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Id</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@Column</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"member_id"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">Long</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> memberEmail</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@OneToMany</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mappedBy </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Member"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cascacde </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">CascadeType</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">ALL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> orphanRemoval </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">Set</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Order</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain">  orders </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">LinkedHashSet</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Entity</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@NoArgsConstructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">access </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">AccessLevel</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">PROTECTED</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@AllArgsConstructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">access </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">AccessLevel</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">PROTECTED</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Getter</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Order</span><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@ID</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Column</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"order_id"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    priate </span><span class="token class-name">Long</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@ManyToOne</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fetch </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">FetchType</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">LAZY</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@JoinColumn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"memberEmail"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> referencedColumnName </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"memberEmail"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nullable </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> updatable </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">Set</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Order</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain">  order </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">LinkedHashSet</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>이런 느낌의 Entity였다.<br>
<!-- -->이때의 나 빼고 엔티티가 어떤 문제가 있는지 알겠지만 이때까지는 나는 꿈에도 몰랐다. <del>5시간을 버릴 줄은 몰랐다!</del>  </p><p>기획: 회원으로 주문 정보를 볼 수 있게 해주세요<br>
<!-- -->나: members 기준으로 Order를 다 가져오면 되겠구나! 음 그러면 가져올 때 속도를 위해 fetch join 해서 가져와야지!<br>
<img loading="lazy" alt="Untitled" src="/assets/images/Untitled-9b8cd5d5174ff20668e14bba4284770a.png" width="400" height="242" class="img_ev3q"></p><p>그렇게 다섯시간을 잡아먹을 줄은 몰랐었다.<br>
<!-- -->아니 진짜 핑계를 대자면 이렇게 엔티티를 구성한 건 내가 아니라 기존 코드를 가지고 다른 곳에서 쓰다가 이렇고 저렇고.. 구구절절 <del><strong>할말하안</strong></del></p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 1-38ae4d40957764c77112ba335338f0c4.png" width="225" height="225" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="내가-그린-그린-쿼리">내가 그린 그린 쿼리<a href="#내가-그린-그린-쿼리" class="hash-link" aria-label="Direct link to 내가 그린 그린 쿼리" title="Direct link to 내가 그린 그린 쿼리">​</a></h3><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">select</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">.</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> member m </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">inner</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">join</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">order</span><span class="token plain"> o </span><span class="token keyword" style="color:#00009f">on</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">memberEmail </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">memberEmail</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>이런 느낌의 (<del>너도 한방 나도한방</del>)쿼리를 원해서</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="fetch를-쓰자">Fetch를 쓰자<a href="#fetch를-쓰자" class="hash-link" aria-label="Direct link to Fetch를 쓰자" title="Direct link to Fetch를 쓰자">​</a></h3><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">ProblemRepository</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">JpaRepository</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Member</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics class-name">Long</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">JPAQueryFactory</span><span class="token plain"> queryFactory</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token annotation punctuation" style="color:#393A34">@Query</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"SELECT distinct m FROM Member m join fetch m.orders"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Member</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">findAllFetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>이렇게 조회를 했는데 </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">save</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       </span><span class="token comment" style="color:#999988;font-style:italic">// Given</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Member</span><span class="token plain"> memFixture </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Member</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@naver.com"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Order</span><span class="token plain"> orderFixture </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Order</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"delivery"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        memFixture</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">addOrder</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">orderFixture</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        problemRepository</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">save</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">memFixture</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        em</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">flush</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        em</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">clear</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Member</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> members </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> problemRepository</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">findAllFetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">assertThat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">members</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isEqualTo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">assertThat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">members</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getOrders</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isEqualTo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">assertThat</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">members</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getOrders</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isEqualTo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>편의를 위해서 대충 이렇게 했다 가정하고..  테스트를 돌려서 확인해보니  </p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">Hibernate</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">select</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  distinct member0_.member_id as member_i1_0_0_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  orders1_.order_id as order_id1_1_1_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  member0_.member_email as member_e2_0_0_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  orders1_.member_email as member_e3_1_1_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  orders1_.order_status as order_st2_1_1_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  orders1_.member_email as member_e3_1_0__</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  orders1_.order_id as order_id1_1_0__ </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">from</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  t_member member0_ </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">inner join</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  t_order orders1_ </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      on member0_.member_email=orders1_.member_email</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>음 .. 예상한 쿼리네 </p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">Hibernate</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    /* load com.example.tiljpa.problem.Member </span><span class="token important">*/</span><span class="token plain"> select</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        member0_.member_id as member_i1_0_0_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        member0_.member_email as member_e2_0_0_ </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    from</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        t_member member0_ </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    where</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        member0_.member_email=</span><span class="token punctuation" style="color:#393A34">?</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">Hibernate</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    /* load com.example.tiljpa.problem.Member </span><span class="token important">*/</span><span class="token plain"> select</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        member0_.member_id as member_i1_0_0_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        member0_.member_email as member_e2_0_0_ </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    from</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        t_member member0_ </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    where</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        member0_.member_email=</span><span class="token punctuation" style="color:#393A34">?</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>?????? 이런 쿼리들이 조회한 멤버 수만큼 다시 쿼리가 쫘라라라라라라라라라라라라라락 나가버렸다..</p><p>이때 엥..? 왜 fetch join을 하고 쿼리를 가져왔는데 다시 member쿼리가 나가지?? </p><p>이떄부터 멘붕의 시작이였다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="디버깅하면서의-추측">디버깅하면서의 추측<a href="#디버깅하면서의-추측" class="hash-link" aria-label="Direct link to 디버깅하면서의 추측" title="Direct link to 디버깅하면서의 추측">​</a></h3><ol><li>일단 fetch mode를 eager로 바꿔보자.. <ul><li>실패</li></ul></li><li>querydsl로 join을 하면 다를까? <ul><li>실패</li></ul></li><li>equals랑 hashcode를 넣어보자<ul><li>실패</li></ul></li><li>아 이건아닌거같은데 yml에 batch size를 넣어보자 <ul><li>당연히 실패</li></ul></li><li>transacton(readonly=true) 때문에 영속성 컨텍스트가 일을 안하나? 좋아 transaction으로만 하자 <ul><li>실패</li></ul></li><li>아 좋아 일단 디버깅을 해보자 <div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">- 디버깅 하면서 보다보니 최초 fetch로 받은 member 객체의 주소와 order가 가지고 있는 member객체의 주소가 확연히 달랐다.  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">![Untitled](./2022-05-28/Untitled%202.png)          </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>어 뭐야 왜달라... 이떄부터 무한 챗바퀴 돌듯 그러면 order의 mode를 eager로 바꾸자! (사실 이미 해봤던거였다) 당연히 실패<br><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 3-1368a6ee87c516b456e672ef751bd824.png" width="224" height="225" class="img_ev3q"></li></ol><p>도저히 좋은 생각이 떠오르지 않아 산책을하고 온 후 </p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="문득">문득<a href="#문득" class="hash-link" aria-label="Direct link to 문득" title="Direct link to 문득">​</a></h3><p>문득 우리가 join을 하면 rdb에서 당연히 여러 개 나오는 문제를 우리는 흔히 distnct를 하는데 이때 jpa에서는 <strong><code>Entity의 @Id</code></strong>로 중복을 제거하는 게 생각이 지나가는데 아 그러면 <strong>fetchjoin</strong>한 이후 가져왔었을 때 영속성 컨테스트에서 <code>**@Id</code>** 로 구분을 한다고 생각이 들어 기존 <code>JoinColumn에 member_email</code>로 되어있는 코드를 <code>member_id</code>로 변경했다. </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Entity</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@NoArgsConstructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">access </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">AccessLevel</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">PROTECTED</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@AllArgsConstructor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">access </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">AccessLevel</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">PROTECTED</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Getter</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Order</span><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@ID</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Column</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"order_id"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    priate </span><span class="token class-name">Long</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@ManyToOne</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fetch </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">FetchType</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">LAZY</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@JoinColumn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"member_id"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> referencedColumnName </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"member_id"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nullable </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> updatable </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">Set</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Member</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> members </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">LinkedHashSet</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>눈 수술 후 건조한 눈 때문에 눈을 개스츠름한 눈빛으로 모니터를 뚫어지게 보며 생각 중에 스쳐 가는 생각이 있었는데, Hibernate 입장에서 생각(뇌 코딩)을 해본다면 당연 할 수 밖에 없구나라는 생각이 들었다.<br>
<!-- -->쿼리를 jqpl로 날려 보내고 온 후에 <strong>영속성 컨텍스트에 친구를 memberId를 기준으로 컨텍스트 테이블에 값을 넣어놓고,</strong> order를 보는데 안에 Lazy가 떡하니 선언되어 있는 걸 보고 허겁지겁 다시 찾으려고 컨텍스트에서 찾았는데 안보였던 것이다.<br>
<!-- -->그래서 1차 캐시에 없네(Joincolumn에 선언된 member_email을 가지고 key를 찾다 보니 실제로는 fetchjoin으로 넣었던 key는 memberId이였어서) 그러면 db에서 조회해야겠다고 판단하고 다시 lazy조인을 날려 발생한 문제인 거지 않을까?</p><h1>참고</h1><p><a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-API%EA%B0%9C%EB%B0%9C-%EC%84%B1%EB%8A%A5%EC%B5%9C%EC%A0%81%ED%99%94/" target="_blank" rel="noopener noreferrer">Inflearn 영환님 강의</a><br>
<a href="http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&amp;ejkGb=KOR&amp;barcode=9788960777330" target="_blank" rel="noopener noreferrer">JPA 프로그래밍</a>
<a href="https://docs.spring.io/spring-data/jpa/docs/2.5.11/reference/html/" target="_blank" rel="noopener noreferrer">docs</a></p>]]></content:encoded>
            <category>SpringBoot</category>
            <category>JPA</category>
            <category>N+1</category>
            <category>Hibernate</category>
        </item>
        <item>
            <title><![CDATA[DB transaction Isolation에 대해서 알아보자]]></title>
            <link>https://dgle.dev/db-isolation</link>
            <guid>https://dgle.dev/db-isolation</guid>
            <pubDate>Tue, 24 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Db 트랜잭션 Isolation]]></description>
            <content:encoded><![CDATA[<p>예전에 한 번 읽었던 RealMysql를 다시금 읽으면서 정리하는 Transaction Isolation!</p><h1>Transaction Isolation Level</h1><h3 class="anchor anchorWithStickyNavbar_LWe7" id="acid">ACID<a href="#acid" class="hash-link" aria-label="Direct link to ACID" title="Direct link to ACID">​</a></h3><p>ACID는 데이터베이스 내에서 일어나는 하나의 트랜잭션(transaction)의 안전성을 보장하기 위해 필요하다.</p><ul><li><code>Atomicity</code>: transaction의 작업이 부분적으로 성공하는 일이 없도록 보장하는 성질이다. 송금하는 사람의 계좌에서 돈은 빠져나갔는데 받는 사람의 계좌에 돈이 들어오지 않는 일은 없어야 한다.  </li><li><code>Consistency</code>: transaction이 끝날 때 DB의 여러 제약 조건에 맞는 상태를 보장하는 성질이다. 송금하는 사람의 계좌 잔고가 0보다 작아지면 안 된다.  </li><li><code>Isolation</code>: transaction이 진행되는 중간 상태의 데이터를 다른 transaction이 볼 수 없도록 보장하는 성질이다. 송금하는 사람의 계좌에서 돈은 빠져나갔는데 받는 사람의 계좌에 돈이 아직 들어가지 않은 DB 상황을 다른 transaction이 읽으면 안 된다.  </li><li><code>Durability</code>: transaction이 성공했을 경우 해당 결과가 영구적으로 적용됨을 보장하는 성질이다. 한 번 송금이 성공하면 은행 시스템에 장애가 발생하더라도 송금이 성공한 상태로 복구할 수 있어야 한다.  </li></ul><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>동시성</div><div class="admonitionContent_S0QG"><p>ACID를 높이면 높일 수록 동시성이 떨어진다, </p></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="read-uncommitted-dirty-read">Read Uncommitted (Dirty Read)<a href="#read-uncommitted-dirty-read" class="hash-link" aria-label="Direct link to Read Uncommitted (Dirty Read)" title="Direct link to Read Uncommitted (Dirty Read)">​</a></h3><ul><li>일반적으로 거의 사용하지 않는다.  </li><li>변경 내용이 commit이나 Rollback 여부에 상관 없이 다른 트랜잭션에게 보여준다.  </li><li>어떤 트랙잭션에서 처리한 작업이 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있게 된다.  </li><li>Dirty read를 유발한다.</li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="read-committed">Read Committed<a href="#read-committed" class="hash-link" aria-label="Direct link to Read Committed" title="Direct link to Read Committed">​</a></h3><ul><li>Oracle Dbms에서 기본적으로 사용되고 있는 격리 수준(<code>Shared Lock</code>을 사용한다)<ul><li>Shared Lock<ul><li>일반적인 SELECT 쿼리는 lock을 사용하지 않고 DB를 읽어 들인다. 하지만 <code>SELECT ... FOR SHARE</code> 등 일부 SELECT 쿼리는 read 작업을 수행할 때 DB가 각 row에 Shared lock을 건다.</li></ul></li></ul></li><li><code>Commit이 완료된 데이터</code>만 다른 트랜잭션에서 조회 할 수 있다.</li><li>어떤 트랜잭션에서 처리한 작업이 Commit이 안되어 있다면 다른 트랜잭션은 undo 영역에 있는 기존 값을 참조해서 보여준다.</li><li>Non-repetable read라는 부정합 문제 발생 할 수 있다.
</li></ul><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p><code>Repeatable read</code>: 하나의 트랜잭션 내에서 동일 select 쿼리를 실행했을 때는 항상 같은 결과가 나와야한다는 정합성 정의</p></div></div><p>동일 Transaction1 내에서 Select문의 결과값을 받고 작업 도중 만약 다른 Transaciton2에서 insert 또는 update를 했다고 가정 했을 때 Transaction1에서 같은 select에 다른 결과값이 보일 수 있는 문제이다. </p><p>글로 설명하면 조금 햇갈리는데 그림으로 보면 쉽다..</p><p><img loading="lazy" alt="[https://akasai.space/db/about_isolation/](https://akasai.space/db/about_isolation/)" src="/assets/images/Untitled-d652008fc6538bcc7bfbc3f1c17629f7.png" width="645" height="554" class="img_ev3q"><br>
<a href="https://akasai.space/db/about_isolation/" target="_blank" rel="noopener noreferrer">https://akasai.space/db/about_isolation/</a></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="repeatable-read">Repeatable Read<a href="#repeatable-read" class="hash-link" aria-label="Direct link to Repeatable Read" title="Direct link to Repeatable Read">​</a></h3><ul><li>Mysql InnoDB에서 기본적으로 사용되는 격리 수준(Shared Lock을 사용한다)</li><li>Non-repetable read라는 부정합 문제가 발생하지 않는다.</li><li>Undo 공간에 백업해두고 실제 레코드 값을 변경한다.</li><li>언두 영역에 백업된 레코드의 여러 버전 가운데 몇 번째 이전 버전까지 찾아 들어가야 하는지에 있다. Undo 영역에서 특정 트랜잭션 번호의 구간 내에서 백업된 데이터를 보여준다. 하지만 트랜잭션을 종료하지 않으면 무한정으로 언두 영역이 커질 수 있어서 성능 하락이 될 수 있음.
</li></ul><p><img loading="lazy" alt="[https://www.cyber.pe.kr/2016/11/mysql-innodb-type.html](https://www.cyber.pe.kr/2016/11/mysql-innodb-type.html)" src="/assets/images/Untitled 1-70723248a8fd0a75d0c4aa3622ef923e.png" width="229" height="443" class="img_ev3q"><br>
<a href="https://www.cyber.pe.kr/2016/11/mysql-innodb-type.html" target="_blank" rel="noopener noreferrer">https://www.cyber.pe.kr/2016/11/mysql-innodb-type.html</a></p><ol><li>시스템 테이블 영역<ul><li>DB의 시스템이 생성한 영역이다. 사용자가 생성한 데이터베이스와 테이블, 테이블에 대한 메타 정보 등을 정리하여 관리한다.</li></ul></li><li>트랜잭션 영역<ul><li>DB가 쿼리를 처리하는 과정에서 시스템 상의 오류가 발생할 경우 원상태로 복구하기 위해 쿼리 처리 이전의 데이터를 보관하는 영역이다.</li></ul></li><li>데이터 영역<ul><li>실제 데이터가 저장되는 영역으로, DB 사용자가 저장한 모든 데이터는 이 영역에 저장된다. 이 영역에서는 DB의 성능을 유지하기 위해 데이터 삭제 시, 완전 삭제 대신 데이터가 삭제된 것으로 표시만 하고 삭제 영역에 데이터를 그대로 유지한다. 이 같은 특징 때문에 삭제된 데이터의 복구가 가능하다.</li></ul></li></ol><h3 class="anchor anchorWithStickyNavbar_LWe7" id="serializable">Serializable<a href="#serializable" class="hash-link" aria-label="Direct link to Serializable" title="Direct link to Serializable">​</a></h3><ul><li>동시성이 중요한 DB에서는 거의 사용하지 않는다.</li><li>읽기 작업도 공유 잠금을 획득 해야 하며 동시에 다른 트랜잭션은 그러한 레코드를 변경하지 못한다.</li><li>한 트랜잭션에서 읽고 쓰는 레코드를 다른 트랜잭션에서는 접근 불가하다</li></ul><h1>참고</h1><p><a href="https://suhwan.dev/2019/06/09/transaction-isolation-level-and-lock/" target="_blank" rel="noopener noreferrer">https://suhwan.dev/2019/06/09/transaction-isolation-level-and-lock/</a> - gap lock, record lock 등 격리 레벨별 설명이 자세하다.<br>
<a href="https://www.cyber.pe.kr/2016/11/mysql-innodb-type.html" target="_blank" rel="noopener noreferrer">https://www.cyber.pe.kr/2016/11/mysql-innodb-type.html</a><br>
<a href="http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&amp;ejkGb=KOR&amp;barcode=9791158392703" target="_blank" rel="noopener noreferrer">RealMysql</a></p>]]></content:encoded>
            <category>DB</category>
            <category>Isolation</category>
        </item>
        <item>
            <title><![CDATA[Spring Kafka Rebalancing 처리 해보기]]></title>
            <link>https://dgle.dev/rebalnace</link>
            <guid>https://dgle.dev/rebalnace</guid>
            <pubDate>Tue, 17 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[카프카 리밸런싱이 일어나는 경우 어떻게 처리]]></description>
            <content:encoded><![CDATA[<p>Kafka를 통해 메시지를 받는 애플리케이션을 구성할 때 프로덕션 환경에서는 고려해야 할 여러 상황이 있는데 지금 생각나는 대표적으로 메시지유실, 중복 메시지 Consume, 확장 가능한 key 정하기, 카프카 리밸런싱 등 카프카를 사용하는데 많은 힘듦이 많이 있는데, 카프카 리밸런싱 상황에서 우리의 애플리케이션이 당황하지 않고 처리를 잘 할 수 있는 방법을 소개해 보려고 한다.</p><p><a href="https://github.com/sk1737030/til/tree/master/kafka-repartitioning" target="_blank" rel="noopener noreferrer">모든 소스는 이곳에서</a> 확인 가능합니다 :)</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="스프링-부트에서-kafka-rebalancing-처리-해보기">스프링 부트에서 Kafka Rebalancing 처리 해보기<a href="#스프링-부트에서-kafka-rebalancing-처리-해보기" class="hash-link" aria-label="Direct link to 스프링 부트에서 Kafka Rebalancing 처리 해보기" title="Direct link to 스프링 부트에서 Kafka Rebalancing 처리 해보기">​</a></h2><p>Kafka를 통해 메시지를 받는 애플리케이션을 구성할 때 프로덕션 환경에서는 고려해야 할 여러 상황이 있는데 지금 생각나는 대표적으로 메시지유실, 중복 메시지 Consume, 확장 가능한 key 정하기, 카프카 리밸런싱 등 카프카를 사용하는데 많은 힘듦이 많이 있는데, 카프카 리밸런싱 상황에서 우리의 애플리케이션이 당황하지 않고 처리를 잘 할 수 있는 방법을 소개해 보려고 한다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="카프카-리밸런싱이란">카프카 리밸런싱이란?<a href="#카프카-리밸런싱이란" class="hash-link" aria-label="Direct link to 카프카 리밸런싱이란?" title="Direct link to 카프카 리밸런싱이란?">​</a></h3><p>먼저 리밸런싱이 뭔지 잠깐 알아보고 간다면, Kafka 토픽을 구성할 때 한 토픽을 여러 개의 Partitions들로 구성하는 일이 많은데, 자연스럽게 Consumer(<code>같은 Group.Id</code>)도 여러 개로 구성이 된다. 이때 메시지를 Consume 하는 상황에서 Consumer가 여러 가지 상황으로 인하여 Broker와 연결이 끊어졌을 때, 일어나는 것이 <code>리밸런싱인데</code> 문제없이 메시지를 소비하게 위해서 브로커가 장애가 일어났다고 판단하고 기존 Consumer에 할당되어 있는 파티션을 다른 Consumer에 재 할당하는 것이다. </p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="그렇다면-꼭-리밸런싱-처리를-해야할까">그렇다면 꼭 리밸런싱 처리를 해야할까?<a href="#그렇다면-꼭-리밸런싱-처리를-해야할까" class="hash-link" aria-label="Direct link to 그렇다면 꼭 리밸런싱 처리를 해야할까?" title="Direct link to 그렇다면 꼭 리밸런싱 처리를 해야할까?">​</a></h3><p>이건 애플리케이션에서 카프카를 사용하는 이유에 따라 다른데, 만약 토픽을 컨슘 할 때 특정 key를 기준으로 컨슘을 하고 있다고 예를 들어 배달 주문에 대해서 카프카를 사용한다고 하였을 때 토픽의 Key를 한식(0 번), 중식(1 번), 양식(2 번), 일식(3 번) 으로 (그럴 리는 없겠지만) 할 경우, 만약 일식을 컨슘하는 애플리케이션이 어떠한 장애로 컨슘을 못한다고 하였을 때, 일식(3 번)의 파티션이 한식(0 번) 파티션으로 할당되었을 때 (런타임에) 처리가 따로 필요할 수가 있다. 한식만 가지고 있는 메뉴 정보를 일식을 포함한 메뉴 정보로 다시 불러온다든지, 아니면 따로 알람 처리를 한다든지 내부 메모리에 가지고 있는 정보들을 초기화 작업이 필요하는 등 여러 가지 처리할 수 있기 때문에 리밸런싱 처리는 카프카를 사용하는 이유에 따라 달라 처리 할 수도 안 해도 된다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="코드로">코드로<a href="#코드로" class="hash-link" aria-label="Direct link to 코드로" title="Direct link to 코드로">​</a></h3><p>코드로 처리하는 부분은 의외로 간단한데 일단 Spring Docs에서 확인을 해본다면<br>
<code>Kafka의 ConsumerRebalanceListener</code> 를 구현한 <code>ConsumerAwareRebalanceListener</code> 를 사용하면 된다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">ConsumerAwareRebalanceListener</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">ConsumerRebalanceListener</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onPartitionsRevokedBeforeCommit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Consumer</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> consumer</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Collection</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">TopicPartition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">onPartitionsRevoked</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Exception</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// NOSONAR</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token constant" style="color:#36acaa">LOGGER</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">debug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"User method threw exception"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onPartitionsRevokedAfterCommit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Consumer</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> consumer</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Collection</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">TopicPartition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onPartitionsLost</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Consumer</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> consumer</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Collection</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">TopicPartition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">onPartitionsLost</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Exception</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// NOSONAR</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token constant" style="color:#36acaa">LOGGER</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">debug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"User method threw exception"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onPartitionsAssigned</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Consumer</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> consumer</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Collection</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">TopicPartition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">onPartitionsAssigned</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Exception</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// NOSONAR</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token constant" style="color:#36acaa">LOGGER</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">debug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"User method threw exception"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onPartitionsRevoked</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Collection</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">TopicPartition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onPartitionsAssigned</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Collection</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">TopicPartition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">default</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onPartitionsLost</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Collection</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">TopicPartition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>onPartitionsAssigned</code> 은 파티션 재할당이 성공적으로 완료될 때 호출된다.<br>
<code>onPartitionsRevoked</code> 은 할당되어 있던 파티션이 제거 될 때 호출된다.<br>
<code>onPartitionsLost</code> 은  일반적인 상황에서는 실행이 안되나 만약 컨슈머의 세션 제한 시간이 만료되었거나 컨슈머가 더 이상 그룹에 속하지 않음을 나타내는 치명적인 오류가 수신된 경우 호출된다.  </p><br><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>ReBalancing순서</div><div class="admonitionContent_S0QG"><p>참고로 일반적인 파티션이 할당되고 잘 실행되고 있는 런타임 환경에서는 당연한 말이 겠지만 <code>PartitionsRevoke</code>가 실행된 후 <code>PartitionsAssigned</code>가 실행된다. 반면 애플리케이션이 실행 될 때에는 <code>PartitionsAssigned</code>만 실행된다.</p></div></div><br>우리 어플리케이션에서는 Spring Kaka에서 잘 감싸서 준 `ConsumerAwareRebalanceListener` 상속 받아서 사용하면 된다.<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Component</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyListener</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">ConsumerAwareRebalanceListener</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onPartitionsAssigned</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Consumer</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> consumer</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Collection</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">TopicPartition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token class-name">ConsumerAwareRebalanceListener</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">onPartitionsAssigned</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">consumer</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"onPartitionsAssigned"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      partitions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">topicPartition </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">topicPartition</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">partition</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onPartitionsLost</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Consumer</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> consumer</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Collection</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">TopicPartition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token class-name">ConsumerAwareRebalanceListener</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">onPartitionsLost</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">consumer</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"onPartitionsLost"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onPartitionsRevoked</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Collection</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">TopicPartition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token class-name">ConsumerAwareRebalanceListener</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">onPartitionsRevoked</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">partitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"onPartitionsRevoked"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>consumer</code> 에는 <code>Consumer</code>에  여러 정보들을 볼 수 있다.<br>
<code>partitions</code> 파라미터로 현재 할당 된 목록을 인자로 준다.  </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled-a7ab9c3a34c1371370ca6e4eebd9065a.png" width="1907" height="242" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="느낀점">느낀점<a href="#느낀점" class="hash-link" aria-label="Direct link to 느낀점" title="Direct link to 느낀점">​</a></h3><p>진짜 카프카 너무 어렵다. 특히 카프카에 의존성이 높으면 높을수록 난도가 올라가는 거 같다. 생각 해 볼 부분들이 많은데, 카프카의 메시지를 produce할 때 유실이 나면 안 되는 서비스인데 어떻게 빠르면서 메시지가 유실되지 않을까를 고려 한다든지, 토픽의 key를 어떤 key로 설정하냐에 확정성이 있고 메시지가 잘 분배 될 때라던지, 리파티니셔닝 상황에서의 서비스가 문제가 없을까 메세지를 중복으로 읽을 경우는 없을 거라든지, 중복으로 메시지를 컨슘 할 경우도 있는데 이때는 어떻게 처리 해야 할까 등등 정말 카프카 어렵다. 그런데 막상 이런 걸 하나하나 해결 해서 서비스가 장애 없고 우아하게 잘 돌아가는 걸 할 수 있다면 얼마나 맛이 있을까? 그런 상상을 하면서 <del>야-근을 한다.</del></p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 1-d906beaf502a07f682c7ddff70c5c686.png" width="300" height="168" class="img_ev3q"></p><h1>참고</h1><p><a href="https://developer.confluent.io/learn-kafka/apache-kafka/partitions/" target="_blank" rel="noopener noreferrer">https://developer.confluent.io/learn-kafka/apache-kafka/partitions/</a><br>
<a href="https://www.popit.kr/kafka-consumer-group/" target="_blank" rel="noopener noreferrer">https://www.popit.kr/kafka-consumer-group/</a><br>
<a href="https://stackoverflow.com/questions/34550873/difference-between-groupid-and-consumerid-in-kafka-consumer" target="_blank" rel="noopener noreferrer">group id와 consume id 차이</a><br>
<a href="https://docs.spring.io/spring-kafka/docs/2.5.17.RELEASE/reference/html/" target="_blank" rel="noopener noreferrer">스프링 Kafka Docs</a><br>
<a href="https://kafka.apache.org/25/javadoc/org/apache/kafka/clients/consumer/ConsumerRebalanceListener.html#onPartitionsLost-java.util.Collection-" target="_blank" rel="noopener noreferrer">ConsumerRebalanceListener설명</a></p>]]></content:encoded>
            <category>Kafka</category>
            <category>Spring Kafka</category>
        </item>
        <item>
            <title><![CDATA[Spring Cloud Gateway Route 설정해보기]]></title>
            <link>https://dgle.dev/gateway</link>
            <guid>https://dgle.dev/gateway</guid>
            <pubDate>Sun, 08 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[스프링 게이트웨이 Route 까보기]]></description>
            <content:encoded><![CDATA[<p>Spring gateway을 사용할 때 일반적으로 2가지 방식으로 route 설정을 할 수 있는데 어떤게 더 좋을까?</p><p>모든 소스는 <a href="https://github.com/sk1737030/til/tree/master/spring-cloud-gateway" target="_blank" rel="noopener noreferrer">이곳</a>에서 확인 가능합니다:)</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="spring-gateway-route">Spring Gateway Route<a href="#spring-gateway-route" class="hash-link" aria-label="Direct link to Spring Gateway Route" title="Direct link to Spring Gateway Route">​</a></h2><p>Spring gateway을 사용할 때 일반적으로 2가지 방식으로 route 설정을 할 수 있다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="yaml">Yaml<a href="#yaml" class="hash-link" aria-label="Direct link to Yaml" title="Direct link to Yaml">​</a></h3><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">spring</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">cloud</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">gateway</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">globalcors</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">corsConfigurations</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">'[/**]'</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">allowedOrigins</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'*'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">allowedMethods</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> POST</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> GET</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> PUT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> OPTIONS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> DELETE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">routes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">id</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">service</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">uri</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//localhost</span><span class="token punctuation" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">18081</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">predicates</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> Path=/aservice/</span><span class="token important">**</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">id</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">service</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">uri</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//localhost</span><span class="token punctuation" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">18082</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">predicates</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> Path=/bservice/</span><span class="token important">**</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-verilog codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-verilog codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">2022-02-19 18:07:46.827 DEBUG 33218 --- [  restartedMain] o.s.c.gateway.config.GatewayProperties   : Routes supplied from Gateway Properties: [RouteDefinition{id='a-service', predicates=[PredicateDefinition{name='Path', args={_genkey_0=/aservice/**}}], filters=[], uri=http://localhost:18081, order=0, metadata={}}, RouteDefinition{id='b-service', predicates=[PredicateDefinition{name='Path', args={_genkey_0=/bservice/**}}], filters=[], uri=http://localhost:18082, order=0, metadata={}}]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="java">Java<a href="#java" class="hash-link" aria-label="Direct link to Java" title="Direct link to Java">​</a></h3><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token import namespace" style="opacity:0.7">org</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">springframework</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">cloud</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">gateway</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">route</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import class-name">RouteLocator</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token import namespace" style="opacity:0.7">org</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">springframework</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">cloud</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">gateway</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">route</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">builder</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import class-name">RouteLocatorBuilder</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token import namespace" style="opacity:0.7">org</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">springframework</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">context</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">annotation</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import class-name">Bean</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token import namespace" style="opacity:0.7">org</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">springframework</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">context</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import namespace" style="opacity:0.7">annotation</span><span class="token import namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token import class-name">Configuration</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Configuration</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">RouteConfig</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Bean</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">RouteLocator</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">bRoue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">RouteLocatorBuilder</span><span class="token plain"> builder</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> builder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">routes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"q-service"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> r </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">path</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/q-service/**"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">uri</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"http://localhost:18081"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"q-service"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> r </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">path</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/w-service/**"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">uri</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"http://localhost:18080"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">build</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Bean</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">RouteLocator</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">cRoute</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">RouteLocatorBuilder</span><span class="token plain"> builder</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> builder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">routes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"c-service"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> r </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">path</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/c-service/**"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">uri</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"http://localhost:18081"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"d-service"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> r </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">path</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/d-service/**"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">uri</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"http://localhost:18080"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">build</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>라우트들을 나눠서 설정할 수 있다. 그렇다면 따로 설정한 라우터들이 어떻게 같이 합쳐져서 작동하는 것 일까?</p><p>Route 구성도<br>
<img loading="lazy" alt="[https://zhuanlan.zhihu.com/p/359523303](https://zhuanlan.zhihu.com/p/359523303)" src="/assets/images/Untitled-b81964f0be36af8e05b92420a9f3fdde.png" width="1749" height="1120" class="img_ev3q">  </p><p><a href="https://zhuanlan.zhihu.com/p/359523303" target="_blank" rel="noopener noreferrer">https://zhuanlan.zhihu.com/p/359523303</a>  </p><p>일단 먼저 봐야할 것은 <code>RouteDefinationLocator</code>이다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="routedefinationlocator">RouteDefinationLocator<a href="#routedefinationlocator" class="hash-link" aria-label="Direct link to RouteDefinationLocator" title="Direct link to RouteDefinationLocator">​</a></h3><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">RouteDefinitionLocator</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">RouteDefinition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getRouteDefinitions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>RouteDefinationLocator</code>을 구현한 객체들은 5개가 있다.  </p><ol><li><code>CachingRouteDefinitionLocator</code></li><li><code>CompositeRouteDefinitionLocator</code></li><li><code>DiscoveryClientRouteDefinitionLocator</code></li><li><code>PropertiesRouteDefinitionLocator</code> </li><li><code>RouteDefinitionRepository</code></li></ol><h3 class="anchor anchorWithStickyNavbar_LWe7" id="discoveryclientroutedefinitionlocator">DiscoveryClientRouteDefinitionLocator<a href="#discoveryclientroutedefinitionlocator" class="hash-link" aria-label="Direct link to DiscoveryClientRouteDefinitionLocator" title="Direct link to DiscoveryClientRouteDefinitionLocator">​</a></h3><p>Service Discovery(Netflix Eureka, Consul, or Zookeeper)와 연동하여 등록된 서비스들을 기준으로 경로를 만든다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="propertiesroutedefinitionlocator">PropertiesRouteDefinitionLocator<a href="#propertiesroutedefinitionlocator" class="hash-link" aria-label="Direct link to PropertiesRouteDefinitionLocator" title="Direct link to PropertiesRouteDefinitionLocator">​</a></h3><p>Yaml에 설정한 property value들이 <strong>GateWayProperty</strong> 직렬화되어 값이 들어가고  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">PropertiesRouteDefinitionLocator</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">RouteDefinitionLocator</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">GatewayProperties</span><span class="token plain"> properties</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">PropertiesRouteDefinitionLocator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">GatewayProperties</span><span class="token plain"> properties</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">properties </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> properties</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">RouteDefinition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getRouteDefinitions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Flux</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">fromIterable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">properties</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getRoutes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 1-537a060eddc6cebb678cb2eed9f7ce6b.png" width="1678" height="568" class="img_ev3q"></p><p>GatewayProperty 값은 <strong>PropertiesRouteDefinitionLocator 에 쓰이게 된다.</strong>  </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 2-2ca8958503e816aee719c207dd1dfb43.png" width="1729" height="678" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="compositeroutedefinitionlocator"><strong>CompositeRouteDefinitionLocator</strong><a href="#compositeroutedefinitionlocator" class="hash-link" aria-label="Direct link to compositeroutedefinitionlocator" title="Direct link to compositeroutedefinitionlocator">​</a></h3><p><a href="https://docs.spring.io/spring-integration/reference/html/dsl.html" target="_blank" rel="noopener noreferrer">자바 DSL</a>(편리하게 fluent API를 지원)로 설정한 라우터들의 값이 들어가 있고  </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 3-9b6e49f05eba03ff26bc2accc55dc845.png" width="2024" height="1003" class="img_ev3q">  </p><p><code>CompositeRouteDefinitionLocator</code>에서 <strong>PropertiesRouteDefinitionLocator에서</strong> 설정한 라우터들에 id가 없을 경우 randid가 들어가게 된다.  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CompositeRouteDefinitionLocator</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">RouteDefinitionLocator</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">RouteDefinition</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getRouteDefinitions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">delegates</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">flatMapSequential</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">RouteDefinitionLocator</span><span class="token operator" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">getRouteDefinitions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">flatMap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeDefinition </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeDefinition</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getId</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">randomId</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            routeDefinition</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setId</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isDebugEnabled</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">debug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Id set on route definition: "</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> routeDefinition</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> routeDefinition</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Mono</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">just</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeDefinition</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="routedefinitionroutelocator">RouteDefinitionRouteLocator<a href="#routedefinitionroutelocator" class="hash-link" aria-label="Direct link to RouteDefinitionRouteLocator" title="Direct link to RouteDefinitionRouteLocator">​</a></h3><p>Route들을 key를 기준으로 확인 후에 <code>RoutePredicateFactory</code>에 집어넣는다.  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">RouteDefinitionRouteLocator</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">RouteLocator</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">RouteDefinitionRouteLocator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">RouteDefinitionLocator</span><span class="token plain"> routeDefinitionLocator</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">RoutePredicateFactory</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> predicates</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">GatewayFilterFactory</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> gatewayFilterFactories</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">GatewayProperties</span><span class="token plain"> gatewayProperties</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">ConfigurationService</span><span class="token plain"> configurationService</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">routeDefinitionLocator </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> routeDefinitionLocator</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">configurationService </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> configurationService</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">initFactories</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">predicates</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        gatewayFilterFactories</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">factory </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">gatewayFilterFactories</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">put</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">factory</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">name</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> factory</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">gatewayProperties </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> gatewayProperties</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// RoutePredicateFactory 검사</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">initFactories</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">RoutePredicateFactory</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> predicates</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        predicates</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">factory </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">String</span><span class="token plain"> key </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> factory</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">name</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">predicates</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">containsKey</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">warn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"A RoutePredicateFactory named "</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> key </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">" already exists, class: "</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">predicates</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">". It will be overwritten."</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">predicates</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">put</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> factory</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isInfoEnabled</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Loaded RoutePredicateFactory ["</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> key </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"]"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Route</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getRoutes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Route</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> routes </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">routeDefinitionLocator</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getRouteDefinitions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token operator" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">convertToRoute</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">gatewayProperties</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isFailOnRouteDefinitionError</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">// instead of letting error bubble up, continue</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            routes </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> routes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">onErrorContinue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">error</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> obj</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isWarnEnabled</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">warn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"RouteDefinition id "</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">RouteDefinition</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> obj</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getId</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">" will be ignored. Definition has invalid configs, "</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> error</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getMessage</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> routes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">route </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isDebugEnabled</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">debug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"RouteDefinition matched: "</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> route</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getId</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> route</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="compositeroutelocator">CompositeRouteLocator<a href="#compositeroutelocator" class="hash-link" aria-label="Direct link to CompositeRouteLocator" title="Direct link to CompositeRouteLocator">​</a></h3><p>여러 개의 <code>RouteLocator</code> 들은 delegates를 가지고, 각 RouteLocator들이 가지고 있는 Route들을 하나로 합친다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CompositeRouteLocator</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">RouteLocator</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">RouteLocator</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> delegates</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">CompositeRouteLocator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">RouteLocator</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> delegates</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">delegates </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> delegates</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Route</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getRoutes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">delegates</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">flatMapSequential</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">RouteLocator</span><span class="token operator" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">getRoutes</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><img loading="lazy" alt="this.deligates 안에 설정한 route들이 담겨있는 것을 볼 수 있다." src="/assets/images/Untitled 4-73c6829a0a54efb556439b564df0be67.png" width="1083" height="517" class="img_ev3q"></p><p>this.deligates 안에 설정한 route들이 담겨있는 것을 볼 수 있다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="cachingroutelocator">CachingRouteLocator<a href="#cachingroutelocator" class="hash-link" aria-label="Direct link to CachingRouteLocator" title="Direct link to CachingRouteLocator">​</a></h3><p>deletgate들을 받아 캐시에 저장해서 route들을 가진다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CachingRouteLocator</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">Ordered</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">RouteLocator</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">ApplicationListener</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">RefreshRoutesEvent</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">ApplicationEventPublisherAware</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics class-name">List</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> cache </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ConcurrentHashMap</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">CachingRouteLocator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">RouteLocator</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">delegate </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        routes </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">CacheFlux</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">lookup</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cache</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">CACHE_KEY</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Route</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">class</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">onCacheMissResume</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token operator" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Route</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">delegate</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getRoutes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">sort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">AnnotationAwareOrderComparator</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">INSTANCE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Cache에 Route들이 담기게 된다.</p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 5-13c825c1eadeb1ce8b242c1ac296ae41.png" width="1049" height="365" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="그리고-마지막으로-최초-시작점인-gatewayautoconfiguration">그리고 마지막으로 최초 시작점인 GatewayAutoConfiguration<a href="#그리고-마지막으로-최초-시작점인-gatewayautoconfiguration" class="hash-link" aria-label="Direct link to 그리고 마지막으로 최초 시작점인 GatewayAutoConfiguration" title="Direct link to 그리고 마지막으로 최초 시작점인 GatewayAutoConfiguration">​</a></h3><p>Gateway의 Route 등 각종 config들을 설정한다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Configuration</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">proxyBeanMethods </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@ConditionalOnProperty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"spring.cloud.gateway.enabled"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> matchIfMissing </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@EnableConfigurationProperties</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@AutoConfigureBefore</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token class-name">HttpHandlerAutoConfiguration</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">class</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">WebFluxAutoConfiguration</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@AutoConfigureAfter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token class-name">GatewayReactiveLoadBalancerClientAutoConfiguration</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">class</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">GatewayClassPathWarningAutoConfiguration</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@ConditionalOnClass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">DispatcherHandler</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">class</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">GatewayAutoConfiguration</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Bean</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Primary</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@ConditionalOnMissingBean</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"cachedCompositeRouteLocator"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">RouteLocator</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">cachedCompositeRouteLocator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">RouteLocator</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> routeLocators</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token operator" style="color:#393A34">*</span><span class="token class-name">CachingRouteLocator</span><span class="token operator" style="color:#393A34">*</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">CompositeRouteLocator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Flux</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">fromIterable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeLocators</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>cachedCompositeRouteLocator</code> 설정한 roteLocator(java, yaml)들이 담기게 된다. </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 6-a002a2368847cac2e7746d6b93736cf0.png" width="1002" height="379" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="결론">결론<a href="#결론" class="hash-link" aria-label="Direct link to 결론" title="Direct link to 결론">​</a></h3><p>개인적으로는 yaml으로 설정하기보다는 <strong>Java Config</strong>로 설정하는 게 좋다고 봅니다.<br>
<!-- -->Yaml 설정하면 간단하게 설정 할 수 있는 반면에, IDE의 도움을 받기 힘들고, 오타, yaml 라인이 다른 경우나 yaml 문법 에러 발생 등 정말 누구나 할 수 있는 실수인데, 만약 인지를 못하고 Product로 배포가 되면 장애가 발생합니다.<br>
<!-- -->또한 게이트웨이다보 니 게이트웨이 뒤로 흐르는 모든 application들이 흐를 수 없게 되어 치명적인 장애가 발생할 수 있으니 Production 환경에서는 Java Config로 설정을 하는 걸 추천드립니다.  </p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="후기">후기<a href="#후기" class="hash-link" aria-label="Direct link to 후기" title="Direct link to 후기">​</a></h3><p>요즘 내부 구현을 많이 까 보면서, 내가 필요한 부분들을 따로 빼서 커스텀해서 쓰는 일이 몇 번 하다보니, 지금도 마찬가지지만 예전에는 진짜 막 썼었구나라고 다시금 많이 느끼고 그러면서 요즘  스프링과 1cm 정도 거리가 가까워졌다는 걸 느끼면서 <del>물론 그러면서 머리가 빠진...</del> 개인적으로 <strong>성장</strong>하고 있는 걸 많이 느끼고 있다.</p><h1>참고</h1><p><a href="https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/" target="_blank" rel="noopener noreferrer">https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/</a><br>
<a href="https://blog.jungbin.kim/spring/2021/02/27/spring-cloud-gateway-route-locator.html" target="_blank" rel="noopener noreferrer">https://blog.jungbin.kim/spring/2021/02/27/spring-cloud-gateway-route-locator.html</a><br>
<a href="https://www.baeldung.com/spring-cloud-gateway#spring-cloud-discoveryclient-support" target="_blank" rel="noopener noreferrer">https://www.baeldung.com/spring-cloud-gateway#spring-cloud-discoveryclient-support</a><br>
<a href="https://dlsrb6342.github.io/2019/05/14/spring-cloud-gateway-%EA%B5%AC%EC%A1%B0/" target="_blank" rel="noopener noreferrer">https://dlsrb6342.github.io/2019/05/14/spring-cloud-gateway-구조/</a></p>]]></content:encoded>
            <category>SCG</category>
            <category>Spring Cloud Gateway</category>
            <category>Route</category>
        </item>
        <item>
            <title><![CDATA[까먹어서 다시 보는 Generic]]></title>
            <link>https://dgle.dev/generic</link>
            <guid>https://dgle.dev/generic</guid>
            <pubDate>Sat, 07 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[까먹어서 다시 찾아보는 제네릭]]></description>
            <content:encoded><![CDATA[<p>제네릭을 사용하는데, 헷갈려서 다시 공부 할 겸 정리</p><p>모든 소스는 <a href="https://github.com/sk1737030/til/tree/master/til-generic/src" target="_blank" rel="noopener noreferrer">이곳에서</a> 확인 가능 합니다!</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="generic-제네릭-지네릭-줴네릭">Generic 제네릭 지네릭 줴네릭<a href="#generic-제네릭-지네릭-줴네릭" class="hash-link" aria-label="Direct link to Generic 제네릭 지네릭 줴네릭" title="Direct link to Generic 제네릭 지네릭 줴네릭">​</a></h2><h3 class="anchor anchorWithStickyNavbar_LWe7" id="제네릭이란">제네릭이란???<a href="#제네릭이란" class="hash-link" aria-label="Direct link to 제네릭이란???" title="Direct link to 제네릭이란???">​</a></h3><p>JDK 1.5에 도입된 <code>컴파일</code> 시에 미리 타입을 지정해서, 런타임시에 오류를 줄이고 타입 검사나 타입 변환과 같은 번거로운 작업을 생략할 수 있는 타입 검사를 도와주는 <strong>갓갓문법</strong>이다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="그렇다면-왜-나왔을까">그렇다면 왜 나왔을까??<a href="#그렇다면-왜-나왔을까" class="hash-link" aria-label="Direct link to 그렇다면 왜 나왔을까??" title="Direct link to 그렇다면 왜 나왔을까??">​</a></h3><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 문제의 코드</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Object</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> list </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ArrayList</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">before</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"pub"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">before</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"dog"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">before</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Object</span><span class="token plain"> o </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> before</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">String</span><span class="token plain"> substring </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">substring</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Runtime Error</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">substring</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>list 안에 어떠한 타입이라도 들어갈 수 있게 돼서, 컴파일 시에 에러를 알 수가 없고, 그러다 보니 런타임시에 에러가 발생을 하게 되고, 개발 할 때에도 더욱 불편한 건 항상 타입체크를 하고 casting을 해야 여러 메소드를 사용할 수 있게 된다. </p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="흔한--generic-사용">흔한  Generic 사용<a href="#흔한--generic-사용" class="hash-link" aria-label="Direct link to 흔한  Generic 사용" title="Direct link to 흔한  Generic 사용">​</a></h3><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Main</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> list </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ArrayList</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 1.7 이후에서는 타입 추론이 가능해서 뒤에 타입은 생략이 가능하다.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        list</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"pub"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        list</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"dog"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        list</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Complie Error</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token plain"> s </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> list</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">String</span><span class="token plain"> substring </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> s</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">substring</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">substring</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>타입을 <code>체크</code>할 필요도 없고 <code>캐스팅</code> 할 필요도 없어진다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="조금-더">조금 더<a href="#조금-더" class="hash-link" aria-label="Direct link to 조금 더" title="Direct link to 조금 더">​</a></h3><p>Dog Sitter(집사) 강아지 집사가 간식을 준다고 했을 때 </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Animal</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Dog</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">Animal</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Pug</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">Dog</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Siba</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">Dog</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Sitter</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">giveSnack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Dog</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> house</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Snack</span><span class="token plain"> snack</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>컴파일 에러나는 상황  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token class-name">Pug</span><span class="token plain"> pug </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Pug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Dog</span><span class="token plain"> dog </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pug</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pug</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getClass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// class generic.animal.Pug</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dog</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getClass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// class generic.animal.Pug</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Sitter</span><span class="token plain"> sitter </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Sitter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Pug</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pugHouse </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">sitter</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">giveSnack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pugHouse</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Snack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 컴파일 error!</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li>매우.. 헷갈리지만 조금 더 생각해보면 컴파일 에러가 나는 이유는 당연하다. 만약 컴파일 에러가 안 난다고 가정을 해보면</li></ul><p>if 컴파일 error가 아니라면 !</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token class-name">Sitter</span><span class="token plain"> sitter </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Sitter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Pug</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pugHouse </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Siba</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> sibaHouse </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">sitter</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">giveSnack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pugHouse</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Snack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 컴파일 error가 아니라면!</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">sitter</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">giveSnack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sibaHouse</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Snack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 컴파일 error가 아니라면!</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li>이렇게 Dog을 상속했지만 두 가지의 다른 타입이 들어갈 수 있게 되는 상황이 발생한다.<!-- -->  <strong>어 아니? 그래서 뭐가 문제야 Dog를 상속한 pug와 siba 가앙지들이 들어 갈 수 있는거 아니야!????</strong></li></ul><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled-f9640314906eaaa3bcd76bde4351df2a.png" width="466" height="1024" class="img_ev3q">  </p><p>만약 저게 허용이 된다고 가정 했을 때의 문제가 되는 부분을 코드로 본다면 </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">T</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">Iterable</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">T</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> lists </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ArrayList</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">T</span><span class="token plain"> t</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        lists</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">T</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> lists</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Iterator</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">iterator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> lists</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">iterator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Consumer</span><span class="token plain"> action</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Iterable</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">forEach</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">action</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Spliterator</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">spliterator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Iterable</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">spliterator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Pug</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pugHouse </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Siba</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> sibaHouse </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Dog</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> dogHouse </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">dogHouse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pugHouse</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Compile Error</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">dogHouse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sibaHouse</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Compile Error</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Dog</span><span class="token plain"> dog</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> dogHouse</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>아까 1.5 이전에 보았던 비슷한 문제가 오른쪽의 코드에서 생기게 된다. </p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>그렇다면 왜 자바는  raw type을 허용했을까?</div><div class="admonitionContent_S0QG"><p><code>List list = new ArrayList&lt;&gt;()</code>가 되는 이유는 호환성 때문이다. 자바가 제네릭을 받아들이기까지 거의 10년이 걸린 탓에 제네릭 없이 짠 코드가 이미 세상을 뒤덮어 버렸다. 그래서 기존 코드를 모두 수용하면서 제네릭을 사용하는 새로운 코드와도 맞물려 돌아가게 해야만 했다. raw 타입을 사용하는 메서드에 매개 변수화 타입의 인스턴스를 넘겨도 동작해야만 했던 것이다.</p></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="무변성-invariant"><a href="https://stackoverflow.com/questions/8902331/what-is-a-class-invariant-in-java" target="_blank" rel="noopener noreferrer">무변성 (invariant)</a><a href="#무변성-invariant" class="hash-link" aria-label="Direct link to 무변성-invariant" title="Direct link to 무변성-invariant">​</a></h3><p>A가 B의 상위 타입일 때 <code>GenericType&lt;A&gt;</code>가 <code>GenericType&lt;B&gt;</code> 의 상위 타입이 아니면 변성이 없다.
다른 코드들이 뭘 하든 간에, 클래스의 모든 인스턴스에 대해 유지되는 속성이다.  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token class-name">Animal</span><span class="token plain"> animal </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Pug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Animal</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> dogHouse </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Dog</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Compile Error </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>House&lt;Animal&gt;</code> 은 <code>House&lt;Dog&gt;</code> 의 상위 타입이 아니다. 아니니까 속성이 유지될 수 없다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="공변-covariant"><strong><a href="https://www.javatpoint.com/covariant-return-type" target="_blank" rel="noopener noreferrer">공변 (covariant)</a></strong><a href="#공변-covariant" class="hash-link" aria-label="Direct link to 공변-covariant" title="Direct link to 공변-covariant">​</a></h3><p>우리가 <del>(그나마 나에게)</del> 가장 흔하게 쓰는 형태이지 않을까 싶다. 상위타입에서 물 흐르듯이 하위타입의 방향으로 코드를 사용할 때이다.  </p><ul><li><p>A가 B의 상위 타입이고 <code>T&lt;A&gt;</code>가 <code>T&lt;B&gt;</code>의 상위 타입이면 공변이라 한다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Sitter</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">giveSnack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics"> </span><span class="token generics keyword" style="color:#00009f">extends</span><span class="token generics"> </span><span class="token generics class-name">Dog</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> dog</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">Snack</span><span class="token plain"> snack</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics"> </span><span class="token generics keyword" style="color:#00009f">extends</span><span class="token generics"> </span><span class="token generics class-name">Dog</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> all </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> dog</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getAll</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 공변</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Sitter</span><span class="token plain"> covariant </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Sitter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Pug</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pug2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">covariant</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">giveSnack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pug2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Snack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Siba</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> siba2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">covariant</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">giveSnack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">siba2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Snack</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li><li><p>문제점</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Pug</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pug </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics"> </span><span class="token generics keyword" style="color:#00009f">extends</span><span class="token generics"> </span><span class="token generics class-name">Dog</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> dogHouse </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pug</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// dogHouse.push(new Pug()); // Compile Error</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">T</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">Iterable</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">T</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> lists </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ArrayList</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">T</span><span class="token plain"> pug</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        lists</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pug</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li></ul><h3 class="anchor anchorWithStickyNavbar_LWe7" id="반공변contravariant"><a href="https://codechacha.com/ko/java-covariance-and-contravariance/" target="_blank" rel="noopener noreferrer">반공변(contravariant)</a><a href="#반공변contravariant" class="hash-link" aria-label="Direct link to 반공변contravariant" title="Direct link to 반공변contravariant">​</a></h3><ul><li><p>A가 B의 상위 타입이고 <code>T&lt;A&gt;</code>가 <code>T&lt;B&gt;</code>의 하위 타입이면 반공변이라한다.  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 반공변</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Pug</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pug </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics"> </span><span class="token generics keyword" style="color:#00009f">super</span><span class="token generics"> </span><span class="token generics class-name">Pug</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pugh </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pug</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Dog</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> dog </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics"> </span><span class="token generics keyword" style="color:#00009f">super</span><span class="token generics"> </span><span class="token generics class-name">Pug</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pughh </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> dog</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li><li><p>반공변은 반대로 Get을 할 때 컴파일 에러가 발생한다.  </p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 반공변</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Dog</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> dog </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics"> </span><span class="token generics keyword" style="color:#00009f">super</span><span class="token generics"> </span><span class="token generics class-name">Dog</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pugh </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> dog</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">pugh</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Pug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">pugh</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Dog</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Pug housePug = pugh.get(0); // Compile Error</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Pug</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pug </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">House</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics"> </span><span class="token generics keyword" style="color:#00009f">super</span><span class="token generics"> </span><span class="token generics class-name">Pug</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> pugh2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pug</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">pugh2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Pug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// pugh2.push(new Dog()); // Compile Error</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Pug housePug = pugh2.get(0); // Compile Error</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li></ul><p>에러가 발생하는 이유는 당연한데 조금만 더 곰곰이 생각해보면, <del>사실 생각해봐도 어렵다</del> get으로 가져올 때 return 값이 Pug일 수도 있고, Pug 위에 상위객체가 올 수 있어서 에러가 날 수밖에 없다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="java-코드에-반공변-볼-수-있는-곳">Java 코드에 반공변 볼 수 있는 곳<a href="#java-코드에-반공변-볼-수-있는-곳" class="hash-link" aria-label="Direct link to Java 코드에 반공변 볼 수 있는 곳" title="Direct link to Java 코드에 반공변 볼 수 있는 곳">​</a></h3><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Collecitons</span><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">T</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">copy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics"> </span><span class="token generics keyword" style="color:#00009f">super</span><span class="token generics"> </span><span class="token generics class-name">T</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> dest</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics"> </span><span class="token generics keyword" style="color:#00009f">extends</span><span class="token generics"> </span><span class="token generics class-name">T</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Integer</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> src </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ArrayList</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Number</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> dest </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ArrayList</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Collections</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">copy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dest</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 1-38c31ff77e69f53c23738e58c4c4ca2f.png" width="646" height="140" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="타입-제거-시기">타입 제거 시기<a href="#타입-제거-시기" class="hash-link" aria-label="Direct link to 타입 제거 시기" title="Direct link to 타입 제거 시기">​</a></h3><p>자바 코드에서 선언되고 사용된 제네릭 타입은 컴파일 시 컴파일러에 의해 자동으로 검사되어 타입 변환된다. 그 후에 코드 내의 모든&nbsp;제네릭 타입은 제거되어, 컴파일된 class 파일에는 어떠한 제네릭 타입도 포함되지 않게 된다. 이런 식으로 동작하는 이유는&nbsp;제네릭을 사용하지 않는 코드와의 호환성을 유지하기 위해서이다.  </p><p>출처<br>
<a href="https://docs.oracle.com/javase/tutorial/java/generics/types.html" target="_blank" rel="noopener noreferrer">https://docs.oracle.com/javase/tutorial/java/generics/types.html</a><br>
<a href="http://www.tcpschool.com/java/java_generic_concept" target="_blank" rel="noopener noreferrer">http://www.tcpschool.com/java/java_generic_concept</a><br>
<a href="https://www.youtube.com/watch?v=PtM44sO-A6g" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=PtM44sO-A6g</a><br>
<a href="http://www.yes24.com/Product/Goods/65551284" target="_blank" rel="noopener noreferrer">Effective Java</a><br>
<a href="https://stackoverflow.com/questions/8902331/what-is-a-class-invariant-in-java" target="_blank" rel="noopener noreferrer">https://stackoverflow.com/questions/8902331/what-is-a-class-invariant-in-java</a> 무변성이란<br>
<a href="https://codechacha.com/ko/java-covariance-and-contravariance/" target="_blank" rel="noopener noreferrer">https://codechacha.com/ko/java-covariance-and-contravariance/</a></p>]]></content:encoded>
            <category>Java</category>
        </item>
        <item>
            <title><![CDATA[Container 환경에서의 JVM GC]]></title>
            <link>https://dgle.dev/container-gc</link>
            <guid>https://dgle.dev/container-gc</guid>
            <pubDate>Mon, 02 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[컨테이너 환경에서의 JVM GC는 무엇이 선택될까?]]></description>
            <content:encoded><![CDATA[<p>당연히 우리의 애플리케이션 GC는 당연히 G1GC를 쓰고 있겠지라고 한치의 의심 없이 생각을 했었다. 아니 적어도 Jdk 11을 사용하면서 GC를 zgc vs g1gc를 뭘 써야 더 좋을까 이런 생각만 했었지 설마 <strong>G1GC vs Serial&nbsp;Collector</strong>를 고민을 하고 있을 줄이야! 꿈에서도 생각을 못했다. 결론부터 말하자면 Container 환경에서 Cpu와 메모리에 따라서 GC선택이 g1gc가 될 수도 있고 아닐 수도 있다.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="jdk-11의-gc는-무조건-g1gc죠">Jdk 11의 GC는 무조건 G1GC죠!<a href="#jdk-11의-gc는-무조건-g1gc죠" class="hash-link" aria-label="Direct link to Jdk 11의 GC는 무조건 G1GC죠!" title="Direct link to Jdk 11의 GC는 무조건 G1GC죠!">​</a></h2><p>당연히 우리의 애플리케이션 GC는 당연히 G1GC를 쓰고 있겠지라고 한치의 의심 없이 생각을 했었다. 아니 적어도 Jdk 11을 사용하면서 GC를 zgc vs g1gc를 뭘 써야 더 좋을까 이런 생각만 했었지 설마 <strong>G1GC vs Serial&nbsp;Collector</strong>를 고민을 하고 있을 줄이야! 꿈에서도 생각을 못했다. 결론부터 말하자면 Container 환경에서 Cpu와 메모리에 따라서 GC선택이 g1gc가 될 수도 있고 아닐 수도 있다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="발단">발단<a href="#발단" class="hash-link" aria-label="Direct link to 발단" title="Direct link to 발단">​</a></h3><p>일단 우리는 흔하디 흔한 <code>Kubernate</code>의 멋있는 오케스트라를 연주를 하며 <code>Container</code>환경에서 app을 배포하고 관리하고 있다. 어느날 Slack에 크루 중 누군가가 우리 당연히 g1gc 쓰고 있죠? 라고 올라와서 나는 엥? 당연한 거 아닌가라고 생각을 하고 다른 일을 했는데 다른 크루가 우리 <strong>Serial&nbsp;Collector</strong> 인 거 같은데요??? 라고 답장을 달았다.  </p><p><img loading="lazy" alt="아니 이게 뭔 개 소리야!" src="/assets/images/Untitled-1da7573e785643ce48b7c5d578a645bc.png" width="236" height="213" class="img_ev3q">  </p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="정말일까">정말일까?<a href="#정말일까" class="hash-link" aria-label="Direct link to 정말일까?" title="Direct link to 정말일까?">​</a></h3><p>나는 우리 jdk11 버전 쓰는데? 그럴 리가 있어? 에이 잘못 봤겠지라고 생각을 하고 좋아 내 눈으로 확인을 해봐야지라며 container에  들어가서 확인을 해 봤는데</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> java -XX:+PrintCommandLineFlags -version</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Picked up JAVA_TOOL_OPTIONS:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-XX:+SegmentedCodeCache </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-XX:+UseCompressedClassPointers </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-XX:+UseCompressedOops </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">**-XX:+UseSerialGC** </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">openjdk version </span><span class="token string" style="color:#e3116c">"11.0.13"</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2021</span><span class="token plain">-10-19</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">OpenJDK Runtime Environment </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">build </span><span class="token number" style="color:#36acaa">11.0</span><span class="token plain">.13+8-post-Debian-1deb11u1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">OpenJDK </span><span class="token number" style="color:#36acaa">64</span><span class="token plain">-Bit Server VM </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">build </span><span class="token number" style="color:#36acaa">11.0</span><span class="token plain">.13+8-post-Debian-1deb11u1, mixed mode</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>일단 다른 Java_Tool Option이 있었지만 다 생략하고 먼저 OpenJdk 사용 중이고 Version은 11.0.13을 사용하는 걸 확인하고, 옵션을 봤는데 <code>-XX:+UseSerialGC</code>  (<del>아니 형이 왜 요기서 나와</del>)  </p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="의심">의심<a href="#의심" class="hash-link" aria-label="Direct link to 의심" title="Direct link to 의심">​</a></h3><p>너무 놀라서, 지금 생각해보면 말도 안 되는 여러 의심들을 했는데 </p><ol><li>저 JDK 버전이 문제가 있어서 무조건 SerialGC를 주입 할 것이다.<ul><li>라고 생각을 했지만, 사실 말도 안 된다 무슨 동네 OpenJdk도 아니고 이 생각은 금방 넘어갔다</li></ul></li><li>누군가가 주입을 했을 것이다.<ul><li>누군가가 build를 할 때 주입을 해놨을 거라고 생각을 하고 build부분을 유심히 봤지만 SerialGC의 S도 찾아볼 수 없었다.</li></ul></li><li>저 옵션이 보여주는 건 가짜야!</li></ol><p>등등 진짜 말도 안 되는 의심들을 하기 시작했다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="침착">침착<a href="#침착" class="hash-link" aria-label="Direct link to 침착" title="Direct link to 침착">​</a></h3><p>사실 위에 저런 의심 말고도 여러 가정과 수많은 의심들을 했었다. 그러다가 현실을 받아들이고 왜 SerialGC를 사용하게 되었을까라고 생각을 했다. 사실 난 나보다 Kube환경에서의 Container가 자동으로 <strong>저렇게 설정한 이유가 있겠지라고</strong> 더 믿기 때문에 오랜만에 SeraliGC와 G1GC를 다시 확인해 보기로 했다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="serail-collector">Serail Collector<a href="#serail-collector" class="hash-link" aria-label="Direct link to Serail Collector" title="Direct link to Serail Collector">​</a></h3><p>The serial collector uses a single thread to perform all garbage collection work, which makes it relatively efficient because there is no communication overhead between threads.</p><p>It's best-suited to single processor machines because it can't take advantage of multiprocessor hardware, although it can be useful on multiprocessors for applications with small data sets (up to approximately 100 MB). The serial collector is selected by default on certain hardware and operating system configurations, or can be explicitly enabled with the option&nbsp;<code>-XX:+UseSerialGC</code>.</p><p>가장 중요한 핵심은 <strong>Single processor</strong> 일 때 Best Suite이다. 물론 작은 메모리 데이터셋(up to approximately 100 MB)을 사용하는 애플리케이션에서는 멀티 프로세서일 경우 쓸만하긴 하나 별로 사용을 안 한다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="g1gc">G1GC<a href="#g1gc" class="hash-link" aria-label="Direct link to G1GC" title="Direct link to G1GC">​</a></h3><p>java 9 부터 채택한 default GC이다. </p><p>The Garbage-First (G1) garbage collector is targeted for <strong>multiprocessor machines</strong> <strong>with a large amount of memory</strong>. It attempts to meet garbage collection pause-time goals with high probability while achieving high throughput with little need for configuration. G1 aims to provide the best balance between latency and throughput using current target applications and environments whose features include:
ㄹ말도
가장 중요한 핵심은 Gabage First GC은 높은 메모리 량과 다중 프로세서를 타깃으로 삼고, 빠른 처리를 지원하여 STW를 줄인다는 것이다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="원인">원인<a href="#원인" class="hash-link" aria-label="Direct link to 원인" title="Direct link to 원인">​</a></h3><p>원인은 <a href="https://developers.redhat.com/articles/2022/04/19/java-17-whats-new-openjdks-container-awareness#tuning_defaults_for_containers" target="_blank" rel="noopener noreferrer">RedHat문서</a>에서 찾을 수 있었는데</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Java 11GC In Container</div><div class="admonitionContent_S0QG"><p>For Java 11+ it's also useful to know which GC is being used, and you can display this information via&nbsp;-Xlog:gc=info. For example, when container limits allow only a single CPU to be active, the Serial GC will be selected. <code>If more than one CPU is active and sufficient memory (at least 2GB) is allocated to the container, the G1 GC will be selected in Java 11 and later versions:</code></p></div></div><p>Container환경에서는 CPU Core를 2개 이상 사용하면서 Memory가 2G 이상이여야 G1GC가 채택된다는 것이다.</p><p><a href="https://developers.redhat.com/articles/2022/04/19/best-practices-java-single-core-containers#the_jvm_as_a_dynamic_execution_platform" target="_blank" rel="noopener noreferrer">아마도  코드에서는 이런 느낌이지 않을까</a></p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">void GCConfig::</span><span class="token function-name function" style="color:#d73a49">select_gc_ergonomically</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">os::is_server_class_machine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">))</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#if INCLUDE_G1GC</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    FLAG_SET_ERGO_IF_DEFAULT</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">UseG1GC, </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#elif INCLUDE_PARALLELGC</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    FLAG_SET_ERGO_IF_DEFAULT</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">UseParallelGC, </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#elif INCLUDE_SERIALGC</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    FLAG_SET_ERGO_IF_DEFAULT</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">UseSerialGC, </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#endif</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#if INCLUDE_SERIALGC</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    FLAG_SET_ERGO_IF_DEFAULT</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">UseSerialGC, </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">#endif</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// This is the working definition of a server class machine:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> physical CPU's and </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain">2GB of memory</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="변경">변경<a href="#변경" class="hash-link" aria-label="Direct link to 변경" title="Direct link to 변경">​</a></h3><p>원인은 일단 알았으니까 기존에 따로 지정을 안 했던 CPU processor를 늘리고 메모리도 증가를 시킨 결과  </p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">/ </span><span class="token comment" style="color:#999988;font-style:italic"># java -XX:+PrintCommandLineFlags -version</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Picked up JAVA_TOOL_OPTIONS: -javaagent:/opt/agent/apm-agent.jar</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-XX:G1ConcRefinementThreads</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> -XX:GCDrainStackTargetSize</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">64</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-XX:+UseCompressedOops </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">**-XX:+UseG1GC** </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">openjdk version </span><span class="token string" style="color:#e3116c">"11.0.13"</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2021</span><span class="token plain">-10-19</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">OpenJDK </span><span class="token number" style="color:#36acaa">64</span><span class="token plain">-Bit Server VM </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">build </span><span class="token number" style="color:#36acaa">11.0</span><span class="token plain">.13+8-post-Debian-1deb11u1, mixed mode</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>그 후 며칠 간격으로 모니터링을 해본 결과 </p><p>기존 SerialGC 사용할 때에는 GC가 일어날 때 전반적으로 pause time이 길었습니다. 100ms </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 1-69ab52e668ab54bc5f495b2da6969372.png" width="1050" height="546" class="img_ev3q">  </p><p>변경 후  </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 2-09e5e763a52808557fcfbd1cc5897173.png" width="1028" height="536" class="img_ev3q">  </p><p>더 모니터링을 해 봐야겠지만 다소 150ms나 먹었던 Major GC부분이 heap size 변경 및 cpu processor증가 GC 변경 후에 아직 일어나지 않았습니다.</p><p>참조<br>
<a href="https://docs.oracle.com/javase/9/gctuning/available-collectors.htm#GUID-45794DA6-AB96-4856-A96D-FDE5F7DEE498" target="_blank" rel="noopener noreferrer">https://docs.oracle.com/javase/9/gctuning/available-collectors.htm#GUID-45794DA6-AB96-4856-A96D-FDE5F7DEE498</a><br>
<a href="https://johngrib.github.io/wiki/java-gc-tuning/#serial-collector" target="_blank" rel="noopener noreferrer">https://johngrib.github.io/wiki/java-gc-tuning/#serial-collector</a><br>
<a href="https://d2.naver.com/helloworld/1329" target="_blank" rel="noopener noreferrer">https://d2.naver.com/helloworld/1329</a> - Naver의 GC정리는 나만 읽고 싶은 Docs 중 하나<br>
<a href="https://docs.oracle.com/javase/9/gctuning/garbage-first-garbage-collector.htm#JSGCT-GUID-0394E76A-1A8F-425E-A0D0-B48A3DC82B42" target="_blank" rel="noopener noreferrer">https://docs.oracle.com/javase/9/gctuning/garbage-first-garbage-collector.htm#JSGCT-GUID-0394E76A-1A8F-425E-A0D0-B48A3DC82B42</a><br>
<a href="https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html" target="_blank" rel="noopener noreferrer">https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html</a> g1gc</p>]]></content:encoded>
            <category>Kubernate</category>
            <category>Container</category>
            <category>JVM</category>
            <category>Java</category>
        </item>
        <item>
            <title><![CDATA[Request Rate Limiter를 만들어보자! 2편]]></title>
            <link>https://dgle.dev/RateLimiter2</link>
            <guid>https://dgle.dev/RateLimiter2</guid>
            <pubDate>Sun, 01 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Make Custom Rate Limiter With Spring Cloud Gateway 2]]></description>
            <content:encoded><![CDATA[<p>Rate Limiter를 만들어보자! 2편</p><p><a href="https://github.com/sk1737030/til/tree/master/./2022-05-01/spring-cloud-gateway-late-limiter" target="_blank" rel="noopener noreferrer">모든 소스</a>는 요기서 확인가능합니다. :)  </p><h1>Spring Cloud Gateway를 사용해서 API Limiter 구현을 해보자! 2편</h1><p>앞서 1편에서 보았던 기본도 잘 쓸 수 있으나, 조금 더 나가서 <del>아구몬이 진화해서 그레이몬이 되듯이</del> Custom을 조금만 더 해주면 나름 괜찮은 RateLimiter가 될 수 있다. </p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="custom-redis-limiter">Custom Redis limiter<a href="#custom-redis-limiter" class="hash-link" aria-label="Direct link to Custom Redis limiter" title="Direct link to Custom Redis limiter">​</a></h2><p>앞에서 사용했던 Default Redis Limiter는 아래 요구사항을 구현하기가 힘든데</p><ol><li>특정 사용자의 주식 조회 요청을 분당 1번으로 설정을 하고 주식 주문을 초당 1번만 가능하다던지 </li><li>속도 문제로 복잡하고 리소스가 많이 드는 요청일 경우 분당 1번만 요청하게 한다던지 </li><li>지금 redis에는 timestamp와 tokenKey 2개만 들어가 있는데 다른 추가적인 정보도 넣고 싶다든지</li><li>Redis TTL를 더 길게 잡는다든지</li><li>User 별로 요청량을 다르게 하고 싶다든지</li></ol><p>이러한 요구사항들을 들어주는 API Limiter를 단순하면서 간단하게(<del>평범하면서도 우아하라고 우리네 클라이언트가 실제로 들은 말</del>) 구현을 한 번 해보자. </p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="custom">Custom<a href="#custom" class="hash-link" aria-label="Direct link to Custom" title="Direct link to Custom">​</a></h3><p>먼저 우리는 잘 구현되어있는<code>RedisRateLimiter</code>를 상속받아서 사용한다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">CustomRedisRateLimiter.java</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Configuration</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Slf4j</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CustomRedisRateLimiter</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">RedisRateLimiter</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>만약 <strong>User</strong> 별로 요청량을 다르게 한다면 우리는 수정해야 할 메서드가 크게 두 개가 있는데<br>
<!-- -->먼저 <strong>isAllowed</strong>, <strong>loadConfiguration</strong> 이 두 개의 메서드를 수정해야 한다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">CustomRedisRateLimiter.java</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Configuration</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Slf4j</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CustomRedisRateLimiter</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">RedisRateLimiter</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">Config</span><span class="token plain"> userAConfig </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Config</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setBurstCapacity</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setReplenishRate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setRequestedTokens</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">Config</span><span class="token plain"> commonUserConfig </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Config</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setBurstCapacity</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setReplenishRate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setRequestedTokens</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Mono</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Response</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">isAllowed</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token plain"> routeId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Config</span><span class="token plain"> routeConfig </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">loadConfiguration</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> replenishRate </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> routeConfig</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getReplenishRate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> burstCapacity </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> routeConfig</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getBurstCapacity</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> requestedTokens </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> routeConfig</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getRequestedTokens</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> keys </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getKeys</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> scriptArgs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Arrays</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">asList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">replenishRate </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> burstCapacity </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> requestedTokens </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Long</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> flux </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> redisTemplate</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">execute</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">script</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> keys</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> scriptArgs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> flux</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">onErrorResume</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">throwable </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isDebugEnabled</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">debug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Error calling rate limiter lua"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> throwable</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Flux</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">just</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Arrays</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">asList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1L</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1L</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ArrayList</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Long</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">longs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> l</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                longs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">addAll</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">l</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> longs</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">results </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">boolean</span><span class="token plain"> allowed </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1L</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token class-name">Long</span><span class="token plain"> tokensLeft </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token class-name">Response</span><span class="token plain"> response </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Response</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">allowed</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeaders</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeConfig</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> tokensLeft</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isDebugEnabled</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">debug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"response: "</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Exception</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Error determining if user allowed from redis"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Mono</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">just</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Response</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeaders</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeConfig</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1L</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Config</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">loadConfiguration</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token plain"> routeId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">equals</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"demo1234"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getConfig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getOrDefault</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeId </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> userAConfig</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getConfig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getOrDefault</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> commonUserConfig</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>우리가 앞에서 <code>UserKeyResolver</code>에서 설정한 <code>key</code>가 들어오게 되는데, 이 키를 가지고 제한하고자 하는 요청량을 먼저 Config를 주입하면 끝이다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">CustomRedisRateLimiter.java</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Configuration</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Slf4j</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CustomRedisRateLimiter</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">RedisRateLimiter</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">Config</span><span class="token plain"> userAConfig </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Config</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setBurstCapacity</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setReplenishRate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setRequestedTokens</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">Config</span><span class="token plain"> commonUserConfig </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Config</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setBurstCapacity</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setReplenishRate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setRequestedTokens</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">ReactiveStringRedisTemplate</span><span class="token plain"> redisTemplate</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">RedisScript</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Long</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> script</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Autowired</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">CustomRedisRateLimiter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ReactiveStringRedisTemplate</span><span class="token plain"> redisTemplate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">RedisScript</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Long</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> script</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">ConfigurationService</span><span class="token plain"> configurationService</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">redisTemplate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> script</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> configurationService</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">redisTemplate </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> redisTemplate</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">script </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> script</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">CustomRedisRateLimiter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> defaultReplenishRate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> defaultBurstCapacity</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">defaultReplenishRate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> defaultBurstCapacity</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">CustomRedisRateLimiter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> defaultReplenishRate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> defaultBurstCapacity</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> defaultRequestedTokens</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">defaultReplenishRate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> defaultBurstCapacity</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> defaultRequestedTokens</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getKeys</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">String</span><span class="token plain"> prefix </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"request_rate_limiter.{"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">String</span><span class="token plain"> tokenKey </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> prefix </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"}.tokens"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">String</span><span class="token plain"> timestampKey </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> prefix </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"}.timestamp"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Arrays</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">asList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tokenKey</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> timestampKey</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Override</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Mono</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Response</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">isAllowed</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token plain"> routeId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Config</span><span class="token plain"> routeConfig </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">loadConfiguration</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> replenishRate </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> routeConfig</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getReplenishRate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> burstCapacity </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> routeConfig</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getBurstCapacity</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> requestedTokens </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> routeConfig</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getRequestedTokens</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> keys </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getKeys</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> scriptArgs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Arrays</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">asList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">replenishRate </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> burstCapacity </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> requestedTokens </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">Flux</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Long</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> flux </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> redisTemplate</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">execute</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">script</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> keys</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> scriptArgs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> flux</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">onErrorResume</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">throwable </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isDebugEnabled</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">debug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Error calling rate limiter lua"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> throwable</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Flux</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">just</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Arrays</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">asList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1L</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1L</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">reduce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">ArrayList</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Long</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">longs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> l</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                longs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">addAll</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">l</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> longs</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">results </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">boolean</span><span class="token plain"> allowed </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1L</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token class-name">Long</span><span class="token plain"> tokensLeft </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token class-name">Response</span><span class="token plain"> response </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Response</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">allowed</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeaders</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeConfig</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> tokensLeft</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isDebugEnabled</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">debug</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"response: "</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Exception</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            log</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Error determining if user allowed from redis"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Mono</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">just</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Response</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getHeaders</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeConfig</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1L</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Config</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">loadConfiguration</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token plain"> routeId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">key</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">equals</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"demo1234"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getConfig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getOrDefault</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeId </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> key</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> userAConfig</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getConfig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getOrDefault</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">routeId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> commonUserConfig</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>그리고 <code>application.yml</code> 파일에 <code>rate-limitter</code> <code>customRedisRateLimiter</code>를 추가해준다.</p><div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">application.yaml</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">spring</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> RequestRateLimiter</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">args</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">rate-limitter</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"#{@customRedisRateLimiter}"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">key-resolver</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"#{@apiKeyResolve}"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="결과">결과<a href="#결과" class="hash-link" aria-label="Direct link to 결과" title="Direct link to 결과">​</a></h3><p><code>Get localhost:18080/demo?userId=demo1234</code> </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 6-2a24462622b3348b88fd7bb5f1c7d9b9.png" width="535" height="131" class="img_ev3q"></p><p>Request 요청 시 위에 설정한 userAConfig에 맞게 응답 값이 돌아오게 된다.</p><p><code>Get localhost:18080/demo?userId=test</code> </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 7-4cb98112e0993f41471bedba911596a6.png" width="550" height="132" class="img_ev3q"></p><p> <code>Remaining</code> 보다 요청을 더 많이 하게 되면 <code>429 Too Many Request</code> 가 응답으로 오게 된다.</p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 8-3124e6119104e3f1247c28dd33a59d96.png" width="1017" height="364" class="img_ev3q"></p><p>추가해도 좋을만한 옵션이 있는데, 만약 다양한 이유로 요청을 거절하고 싶을 때 예를 들어 헤더에 약속된 값이 없거나 등
그럴 때 사용할 수 있는 옵션이 <code>deny-empty-key</code>라는 옵션이다. (default true)이다.<br>
<!-- -->이 옵션을 사용하기 위해서 <strong>_<strong>_EMPTY_KEY</strong></strong> 을 뒤로 넘겨주게 되면 <code>FORBIDDEN</code> 응답으로 돌려주게 된다.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">UserKeyResolver.java</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Bean</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">KeyResolver</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">apiKeyResolve</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">exchange</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getQueryParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">containsKey</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"userId"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Mono</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">just</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"____EMPTY_KEY__"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">Mono</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">just</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">exchange</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getQueryParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getFirst</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"userId"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 9-c27ab7d345cdda32e2833f76169d7895.png" width="1034" height="260" class="img_ev3q"></p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="정말-잘-작동할까">정말 잘 작동할까?<a href="#정말-잘-작동할까" class="hash-link" aria-label="Direct link to 정말 잘 작동할까?" title="Direct link to 정말 잘 작동할까?">​</a></h3><p>이 부분을 확인하기 위해서 짧은 시간에 많은 부하 테스트를 해 볼 것이다. 간단하게 <a href="https://k6.io/" target="_blank" rel="noopener noreferrer">k6</a> 부하 테스트 도구를 이용해서  테스트를 해 볼 겁니다. </p><p>조건 초당 1회 요청을 가능한지를 테스트한다면</p><p>limiter 설정<br>
<code>requestedTokens</code> 1<br>
<code>burstCapacity</code> 1<br>
<code>replenishRate</code> 1 </p><p>k6/loadtest.js</p><div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">loadtest.js</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports">http</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'k6/http'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> check</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> group</span><span class="token imports punctuation" style="color:#393A34">,</span><span class="token imports"> sleep </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'k6'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> options </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">duration</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'10s'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">vus</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'1'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">BASE_URL</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'http://localhost:18080'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">default</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> limiter </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> http</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation constant" style="color:#36acaa">BASE_URL</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c">/demo?userId=test</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">check</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">limiter</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token string-property property" style="color:#36acaa">'success limitter '</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">resp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> resp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">status</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>정말 간단한 스크립트로 보면 알겠지만<br>
<!-- -->10초 동안 get요청을 한다는 스크립트이고, 결과로 200일 경우 성공으로 보겠다는 것이다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="결과-1">결과<a href="#결과-1" class="hash-link" aria-label="Direct link to 결과" title="Direct link to 결과">​</a></h3><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 10-743c5bd798aa8c18e3911f614d961010.png" width="1570" height="898" class="img_ev3q"></p><p>11번의 요청이 성공적으로 200으로 return 되었고, 6045번이 실패한 내역이다.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="이상으로">이상으로<a href="#이상으로" class="hash-link" aria-label="Direct link to 이상으로" title="Direct link to 이상으로">​</a></h2><p>이렇게 간단하게 <code>RateLimiter</code>를 구현을 해보았는떼, 처음에는 구현을 어떻게 하지라며 고민을 하였는데,<br>
<!-- -->Redis를 끄적끄적이며 구현 중에 (<del>Watch와 Multi와 함께라면),</del><br>
<!-- -->Spring 진영에 잘 구현이 되어 있어서 쉽게 가져와서 요구사항에 맞게 사용을 했었다.<br>
<!-- -->이미 잘 만들어져서 역할을 잘하고 있으면 빠르게 잘 사용하는 게 어려운 거구나 다시금 느꼈다.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="추가로-한-번-고민해야-할-부분">추가로 한 번 고민해야 할 부분<a href="#추가로-한-번-고민해야-할-부분" class="hash-link" aria-label="Direct link to 추가로 한 번 고민해야 할 부분" title="Direct link to 추가로 한 번 고민해야 할 부분">​</a></h3><p>Gateway에서 Request body를 읽어서 무언가를 처리 한 후에 다음 Filter로 넘겨 줄 때에는 고민을 해봐야하는데,<br>
<!-- -->잘 알다시피 Servlet Request Body를 Filter에서 한 번 읽으면,<br>
<!-- -->다시 뒤에서 body를 못 읽는다는 문제가 있다.<br>
<!-- -->이 부분은 한 번 읽고 body를 캐싱 해서 다시 body를 넣어주는 추가 작업이 필요하다.</p><h1>참고</h1><p><a href="http://www.yes24.com/Product/Goods/102819435" target="_blank" rel="noopener noreferrer">가상 면접 사례로 배우는 대규모 시스템 설계</a><br>
<a href="https://docs.spring.io/./2022-05-01/spring-cloud-gateway/docs/current/reference/html/" target="_blank" rel="noopener noreferrer">Spring Cloud gateway Docs</a><br>
<a href="https://redis.io/docs/manual/programmability/eval-intro/" target="_blank" rel="noopener noreferrer">https://redis.io/docs/manual/programmability/eval-intro/</a></p>]]></content:encoded>
            <category>SCG</category>
            <category>Spring Cloud Gateway</category>
            <category>Rate Limiter</category>
        </item>
        <item>
            <title><![CDATA[Request Rate Limiter를 만들어보자! 1편]]></title>
            <link>https://dgle.dev/RateLimiter1</link>
            <guid>https://dgle.dev/RateLimiter1</guid>
            <pubDate>Sun, 01 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Make Custom Rate Limiter With Spring Cloud Gateway 1]]></description>
            <content:encoded><![CDATA[<p>SCG와 함꼐 간단한 Api Limiter를 구현해보자! 1편</p><p><a href="https://github.com/sk1737030/til/tree/master/./2022-05-01/spring-cloud-gateway-late-limiter" target="_blank" rel="noopener noreferrer">모든 소스</a>는 요기서 확인가능합니다. :)  </p><h1>Spring Cloud Gateway를 사용해서 API Limiter 구현을 해보자! 1편</h1><h2 class="anchor anchorWithStickyNavbar_LWe7" id="api-limitier가-필요한-이유">Api Limitier가 필요한 이유?<a href="#api-limitier가-필요한-이유" class="hash-link" aria-label="Direct link to Api Limitier가 필요한 이유?" title="Direct link to Api Limitier가 필요한 이유?">​</a></h2><p>limiter는 왜 필요할까를 먼저 생각해보면 다양한 이유가 있겠지만, 정말 간단하게 생각해보면 10초 걸리는 헤비한 api가 있을 때 client들이 짧은 시간에 API를 무분별하게 요청하게 되면 우리의 서버는 <del>끔찍한 결말</del>을 맞게 될 것이다.
저런 단순한 이유말고도 사용자별 차등(A 사용자는 초당 3번 요청, B 사용자는 초당 30번 요청)을 줄 수도 있고 등등 여러 가지 이점이 생긴다. <del>그러므로 정말 꼭 하나쯤은 이참에 장만하시는 게</del></p><p>여러 다른 방법으로도 api limiter를 apllicaiton 단에서 구현할 수 있겠지만,  빠르고 정확하고 serializable하게  Api Limiter를 구현하는 건 정말 하나부터 열까지 생각해야 할 게 많고 <strong>너무 어렵다</strong>(<del>나에게는</del>). </p><p>그렇다면, 어떻게 조금 쉽게 구현할 수 있는가를 찾아보면!!  </p><p><strong><a href="http://www.yes24.com/Product/Goods/102819435" target="_blank" rel="noopener noreferrer">가상 면접 사례로 배우는 대규모 시스템 설계 기초라는 책에서</a></strong>  힌트를 얻을 수 있는데,
핵심은 <code>Redis + Lua Script</code>를 사용하여 구현하는 것이다.</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>왜 Lua Script일까??</div><div class="admonitionContent_S0QG"><p>Redis Document에서 찾을 수 있는데, 루아 스크립트가 실행되는 동안 일단 레디스는 blocked 상태가 된다. 즉 레디스는 루아 스크립트가 atomic 하게 실행하는 걸 보장하기 때문에 RateLimite를 구현할 수 있게 된다.</p></div></div><p>그렇다면, 정말 조금만 더욱더 욕심을 내서 요즘같이 대 MS 시대에 여러 Applicaiton에 Route 역할도 하고 Gateway 역할도 하면서 거기에 더하여 Limiter까지 지원한다면 얼마나 좋을까?
근데 그런 팔방미인의 무-친 캐리머신이 있으니</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="spring-cloud-gateway"><a href="https://docs.spring.io/./2022-05-01/spring-cloud-gateway/docs/2.2.9.RELEASE/reference/html/" target="_blank" rel="noopener noreferrer">Spring Cloud Gateway</a><a href="#spring-cloud-gateway" class="hash-link" aria-label="Direct link to spring-cloud-gateway" title="Direct link to spring-cloud-gateway">​</a></h2><p>Spring Cloud Gateway를 정말 정-말 간단하게  소개하면 그냥 Gateway 역할을 한다.</p><p>우리의 위키에는 Gateway를 설명 잘해놨는데, <strong>게이트웨이</strong>는 컴퓨터 다른 네트워크로 들어가는 입구 역할을 하는 네트워크 포인트이다. 넓은 의미로는 종류가 다른 네트워크 간의 통로의 역할을 하는 장치이다. 쉽게 예를 들자면 해외여행을 들 수 있는데 해외로 나가기 위해서 꼭 통과해야 하는 공항이 게이트웨이와 같은 개념이다. MSA환경에서 정말 빼놓을 수 없는 구현해야 할 애플리케이션 중 하나이다.</p><p>대표적인 기능으로 여러 가지가 있지만 내가 사용하는 기능들만 추리면  </p><ul><li>Router 역할</li><li>각종 Filter</li><li>LB 기능</li><li>Security</li></ul><p>등등 진짜 수많은 기능을 제공하고 있으니 알아보면 나중에 한 번씩 써먹게된다. </p><p>그 중 Gateway Filter 중에 RequestRateLimiter 라는 녀석이 있는데 이 녀석을 잘 써먹으면 손 한 번 까딱으로 Api Limiter가 짜란 구현이된다.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="spring-gateway-limiter">Spring Gateway Limiter<a href="#spring-gateway-limiter" class="hash-link" aria-label="Direct link to Spring Gateway Limiter" title="Direct link to Spring Gateway Limiter">​</a></h2><p>기본적으로 Spring Gateway는 RateLimite를 Redis와 lua를 사용하여 구현을해놨는데 우리는 이걸로 사용하기만 하면 된다. </p><div class="language-groovy codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">build.gradle</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-groovy codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ext </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'springCloudVersion'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token interpolation-string string" style="color:#e3116c">"2020.0.5"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">dependencies </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    implementation </span><span class="token string" style="color:#e3116c">'org.springframework.cloud:spring-cloud-starter-gateway'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    implementation </span><span class="token string" style="color:#e3116c">'org.springframework.boot:spring-boot-starter-data-redis-reactive'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    runtimeOnly </span><span class="token string" style="color:#e3116c">'com.h2database:h2'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    testImplementation </span><span class="token string" style="color:#e3116c">'org.springframework.boot:spring-boot-starter-test'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    testImplementation </span><span class="token string" style="color:#e3116c">'org.junit.jupiter:junit-jupiter:5.7.1'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">dependencyManagement </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    imports </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        mavenBom </span><span class="token interpolation-string string" style="color:#e3116c">"org.springframework.cloud:spring-cloud-dependencies:</span><span class="token interpolation-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token interpolation-string interpolation expression">springCloudVersion</span><span class="token interpolation-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token interpolation-string string" style="color:#e3116c">"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">tasks</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">named</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'test'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">useJUnitPlatform</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="기본-구현">기본 구현<a href="#기본-구현" class="hash-link" aria-label="Direct link to 기본 구현" title="Direct link to 기본 구현">​</a></h3><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Configuration</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CustomUserKeyResolver</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Bean</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">KeyResolver</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">userKeyResolver</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> exchange </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Mono</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">just</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">exchange</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getQueryParams</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getFirst</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"userId"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>keyResolver를 세팅을 먼저 해준다.<br>
<!-- -->return해주는 key를 가지고 뒤에서 구분을 하므로 필수적으로 구현을 해야 한다.<br>
<!-- -->getParameter로 userId가 들어온다는 가정하에 구현하였다.</p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">application.yml</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">spring</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">cloud</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">gateway</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">routes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">id</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> rate_limiter_route</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">uri</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> http</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//localhost</span><span class="token punctuation" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">19000</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">filters</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> RequestRateLimiter</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">args</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">key-resolver</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"#{@userKeyResolver}"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">redis-rate-limiter.replenishRate</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">redis-rate-limiter.burstCapacity</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token key atrule" style="color:#00a4db">redis-rate-limiter.requestedTokens</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>key-resolver</code> 우리가 선언한 bean이름을 주입 해 준다.<br>
<code>requestedTokens</code> 요청시에 소모되는 토큰의 개수<br>
<code>burstCapacity</code> 버킷의 담겨져있는 최대량<br>
<code>replenishRate</code> 초당 버킷 회복량   </p><br><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>RateLimiter 알고리즘</div><div class="admonitionContent_S0QG"><p>  <code>[Token bucket</code> 알고리즘을](<a href="https://dev.to/satrobit/rate-limiting-using-the-token-bucket-algorithm-3cjh" target="_blank" rel="noopener noreferrer">https://dev.to/satrobit/rate-limiting-using-the-token-bucket-algorithm-3cjh</a>) 따른다.</p></div></div><br><p>설정을 다 했으니 한 번 요청을 해보면</p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 1-4ef26521487f3e6eb404c129a7202a71.png" width="1259" height="399" class="img_ev3q"></p><p>설정한 burstCapacity 10 에서 -1 이 된 9가 remain으로 header에 응답이 오게 된다.<br>
<!-- -->돌아오는 응답 헤더가 궁금하면 <code>RedisRateLimiter</code> 에 선언되어있는 Header에서 추가로 확인할 수 있습니다.</p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 2-ffeaf9a6b2278df65cb324c3025fb3bb.png" width="958" height="383" class="img_ev3q"></p><br><h3 class="anchor anchorWithStickyNavbar_LWe7" id="그렇다면-레디스에-저장은-어떻게될까">그렇다면 레디스에 저장은 어떻게될까❓<a href="#그렇다면-레디스에-저장은-어떻게될까" class="hash-link" aria-label="Direct link to 그렇다면 레디스에 저장은 어떻게될까❓" title="Direct link to 그렇다면 레디스에 저장은 어떻게될까❓">​</a></h3><p>일단 레디스에 저장되는 데이터 셋을 본다면<br>
<img loading="lazy" alt="redis data" src="/assets/images/Untitled 3-ad19f11a4a537ede38836d094218f5d6.png" width="442" height="250" class="img_ev3q"></p><p>왜 이렇게 저장되는지는 <code>RedisRateLimiter.java</code>에 <code>getKeys</code>라는 메소드에서 확인할 수 있는데 </p><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 4-6f82ffe1e1d20de59fd1ef77f2691d8b.png" width="595" height="389" class="img_ev3q"></p><br><br><br><p>이상으로 우리의 레디스를 활용한 <del>우아하고 깔끔한</del> <strong>RateLimiter</strong>가 완성됐다!  </p><br><p><img loading="lazy" alt="Untitled" src="/assets/images/Untitled 5-973e34629559a1b47cececb37fc445fd.png" width="420" height="400" class="img_ev3q">   </p><br><br><br><br><br><br><p>사실 요기까지만해도 그냥 쓰기에도 나쁘지 않지만 조금 아쉽다.<br>
<!-- -->그러나 우리의 기획자나 비지니스 요구사항은 이렇게 간단하지 않다. </p><p>예를 들어,  </p><ol><li>특정 사용자의 주식 조회 요청을 분당 1번으로 설정을 하고 주식 주문을 초당 1번만 가능하다던지 </li><li>속도 문제로 복잡하고 리소스가 많이 드는 요청일 경우 분당 1번만 요청하게 한다던지 </li><li>지금 redis에는 timestamp와 tokenKey 2개만 들어가 있는데 다른 추가적인 정보도 넣고 싶다든지</li><li>Redis TTL을 더 길게 잡는다든지</li><li>User 별로 요청량을 다르게 하고 싶다든지 </li></ol><p>냉혹한 비즈니스 세계에서는 이것보다도 더 많은 <strong>Limiter</strong>로써의 더 많은 <strong>역할</strong>과 <strong>책임</strong> 을 요구하게 되는데, 기본적으로 제공하는 <code>RateLimiter</code>로는 작업이 어렵다. 그래서 조금의 커스텀을 해야 할 필요가 있다. </p><p><a href="https://sk1737030.github.io/RateLimiter2" target="_blank" rel="noopener noreferrer">Request Rate Limiter를 만들어보자! 2편</a></p>]]></content:encoded>
            <category>SCG</category>
            <category>Spring Cloud Gateway</category>
            <category>Rate Limiter</category>
        </item>
    </channel>
</rss>