<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>pood-tech.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 08 Feb 2023 07:45:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>pood-tech.log</title>
            <url>https://velog.velcdn.com/images/pood-tech/profile/661501dd-e7a0-41fb-bf86-b1aa354beac4/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. pood-tech.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/pood-tech" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[LocalDateTime 조롱하기]]></title>
            <link>https://velog.io/@pood-tech/LocalDateTime-%EC%A1%B0%EB%A1%B1%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@pood-tech/LocalDateTime-%EC%A1%B0%EB%A1%B1%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 08 Feb 2023 07:45:40 GMT</pubDate>
            <description><![CDATA[<p><code>안녕하세요 푸드 테크팀 백엔드 개발자 박형민입니다 :)</code></p>
<p>👏🏻 최근 프로젝트에서 특정일자와 오늘날짜의 차이를 구하는 로직을 구현해야했었는데, 이 날짜 로직에 LocalDate.now() 가 포함되어있어 오늘만 통과하는 테스트코드를 작성하게되어 곤란함이 있었습니다.</p>
<br>

<p>그래서 이번 포스팅에서는 제가 mocking 할 수 없는, LocalDateTime.now( ) 메소드를 어떻게 mocking 했는지에 대해 작성해보고자 합니다. </p>
<hr>
<h1 id="1-localdatenow-테스트하기">1) LocalDate.now() 테스트하기</h1>
<ul>
<li>먼저 성공하는 테스트코드를 작성해 보았습니다.</li>
<li>포스팅 작성일자 기준, 오늘은 2023-2-8일 이기 때문에, 아래 코드는 now() 메소드가 성공하는 테스트 코드입니다.</li>
<li>📌 하지만 이렇게 작성한다면, 내일은 실패하는 테스트 코드가 되고 맙니다.
→ 테스트코드는 항상 성공해야한다는 법칙이 깨지는 것이죠
<img src="https://velog.velcdn.com/images/pood-tech/post/6ca91ff1-8b08-4c00-88f3-9ba0e4fa2bc8/image.png" alt=""></li>
</ul>
<br>

<h2 id="localdate-mocking">LocalDate Mocking</h2>
<p>하지만 저희에게는 mocking 이라는 훌룡한 조롱수단이 있습니다.
LocalDate 객체를 mocking 하고 now() 메소드에 원하는 값을 반환시켜주면 항상 성공하는 테스트 케이스가 작성되겠죠</p>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/6d594869-7248-4e98-8dd9-32ca201ea286/image.png" alt=""></p>
<p>하지만 실패합니다.</p>
<ul>
<li>그 이유는, LocalDate 객체는 final 로 선언된 객체이며, now() 메소드 또한 정적 메소드이기 때문입니다.
<img src="https://velog.velcdn.com/images/pood-tech/post/1b8e219f-21e3-468b-8780-887f12af26e9/image.png" alt="">
<img src="https://velog.velcdn.com/images/pood-tech/post/1a21c3ff-948b-46e8-8f68-c1b33a63865c/image.png" alt=""></li>
</ul>
<hr>
<br>

<h1 id="2-그럼에도-불구하고-localdate-를-조롱하는-방법들">2) 그럼에도 불구하고 LocalDate 를 조롱하는 방법들</h1>
<blockquote>
<p>그럼에도 불구하고 LocalDate 의 정적 메소드인 now()를 mocking 할 수 있는 몇가지 방법들이 존재합니다.</p>
</blockquote>
<br>

<h2 id="1-power-mockito">1. Power Mockito</h2>
<blockquote>
<p>가장 쉬운 방법입니다.</p>
</blockquote>
<p>수많은 블로그나, 레펀런스를 보면 보통 Mockito-inline 을 dependecy 에 추가해주어야한다고 이야기합니다.</p>
<ol>
<li>mockito 3.4.0 전에는 powermock 라이브러리를 따로 추가해주어야했지만, 그 이후 버전부터는 mockito 에 추가되었습니다.</li>
<li>maven 혹은 gradle 에 mockito-inline 이나 mockito-core를 종속성 추가해주면 Mockito.mockStatic() 메소드를 사용할 수 있게됩니다.</li>
<li>이름 그대로 정적 메소드를 mocking하기 위해 만든 메소드입니다.</li>
</ol>
<pre><code>//이런식으로 mocking 이 가능해집니다.
MockedStatic&lt;LocalDate&gt; localDateMockedStatic = Mockito.mockStatic(LocalDate.class);

localDateMockedStatic.when(LocalDate::now).thenReturn(date);
</code></pre><br>

<p>🔥 하지만, PowerMock을 지양해야하는 몆가지 이유가 존재합니다.</p>
<ol>
<li>테스트코드 작성 방식이 복잡하고 try문으로 감싸거나 명시적으로 Mocking 정적객체를 close() 하지 않으면 계속해서 해당 스레드에서는 정적객체 mocking 활성상태가 유지됩니다.</li>
<li>특정 라이브러리를 의존해야하고 이 과정에서 일부 라이브러리와 호환되지 않을 수 도 있습니다.</li>
<li>static mock은 안티패턴입니다.<ul>
<li>static method를 모킹하기 위해 PowerMock이나 mockito-inline 라이브러리를 설치하면 private 메서드, final 클래스 등 테스트 가능한 상태가 됩니다.     <ul>
<li><a href="http://shoulditestprivatemethods.com/">http://shoulditestprivatemethods.com/</a> 라는 사이트가 있을 정도로 private method의 테스트 불필요성에 대해선 많은 자료가 있으니 허용하지 않는 상태로 두는 것이 좋습니다. </li>
</ul>
</li>
</ul>
</li>
</ol>
<p><br><br></p>
<h2 id="2-class-로-감싸기">2. Class 로 감싸기</h2>
<blockquote>
<p>두번째 방법은 정적 메소드를 커스텀한 class 로 감싸는 방법입니다.</p>
</blockquote>
<p>final 클래스라 mocking 이 불가능하고, 정적 메소드라 mocking 이 불가능하다면 새로운 객체에 해당 기능만을 담아 만들어 mocking 하는 방법도 있습니다.</p>
<br>

<p>👏🏻 간단하게 LocalDate.now() 를 감싼 객체를 만들었습니다.</p>
<pre><code>public class DateUtil {

    public LocalDate now() {
        return LocalDate.now();
    }
}</code></pre><ol>
<li>이제 이 객체를 mocking 하여 LocalDate.now() 가 아닌 DateUtil.now() 를 mocking 합니다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/7a401777-7dd6-4386-9229-21d5c703d713/image.png" alt=""></p>
<ol start="2">
<li>결과를 보시면 내부적으로 LocalDate.now() 를 호출하여 현재 날짜를 반환하게 하는 DateUtil.now() 가 27년 뒤를 반환하고 있습니다.</li>
</ol>
<p>👍 Power Mock 을 사용하지도 않았고, 외부 라이브러리에 종속적이지도 않습니다 :)</p>
<br>

<p>🙅‍♂️ 하지만 이 방법은 저만을 위한 객체가 될 수 있기 때문에, 협업을 하는 상황에서 좋지 않다고 생각했습니다.</p>
<ul>
<li>이 객체를 모르는 팀원은 또 다시 power mock 이든 새로운 객체를 생성하든 할 수 있기때문에, 조금더 범용적인 방법을 고민했습니다.</li>
</ul>
<hr>
<br>


<h2 id="3-localdatenowclock-clock-사용하기">3. LocalDate.now(Clock clock) 사용하기</h2>
<blockquote>
<p>✔️ 마지막 방법이고 채택한 방법입니다.</p>
</blockquote>
<p>진짜 오랫동안 LocalDate.now() 메소드를 째려보니(?) 1가지 묘한 점을 발견할 수 있었습니다.</p>
<p>static 메소드인 LocalDate.now() 메소드가 내부적으로 LocalDate.now(Clock clock) 메소드를 호출하면서 Clock 객체를 파라미터로 주입하고있었고</p>
<p>Clock 객체는 final class 도 아니면, now() 에서 호출하고잇는 instance() 메소드도 static 메소드가 아니였습니다.</p>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/c1a55bdf-b5ca-4ece-b389-39fb5ee98bf7/image.jpg" alt=""></p>
<p><strong>👏🏻 즉! Clock 객체를 mocking 할 수 있다!</strong></p>
<h3 id="코드로-적용해본다면">코드로 적용해본다면</h3>
<ol>
<li>항상 Clock.systemDefaultZone() 을 매번 주입하기는 힘들고, 위험성이 존재하니 Clock을 Bean으로 올려 관리하도록하고, </li>
<li>호출하는 부분에서 DI 로 주입한다면 종속성도 끊어내 테스트 코드 작성에도 유용해집니다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/d0ec5ab1-9a88-4a49-81c4-22d7d112f913/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/9a1c7763-68da-4e90-90ff-2daf8a3c7be9/image.png" alt=""></p>
<h3 id="테스트-코드">테스트 코드</h3>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/ba27612c-23c2-4aab-b046-494047b9bb5d/image.png" alt=""></p>
<br>


<ul>
<li><p>Clock 객체를 mocking 하기 위해서는 결국 호출하는 프로젝션 코드를 변경할 수 밖에 없습니다.</p>
</li>
<li><p>하지만, <a href="https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#now-java.time.Clock-">Oracle</a>에서 테스트를 위해 Clock을 받아 사용하는 목적으로 사용하라고 명시되어있어서 쿨하게 넘어가기로 했습니다.</p>
</li>
</ul>
<blockquote>
<p>This will query the specified clock to obtain the current date - today. Using this method allows the use of an alternate clock for testing. The alternate clock may be introduced using dependency injection.</p>
</blockquote>
<hr>
<br>

<p align=center>
  이렇게 정적 메소드인 LocalDate.now() 메소드를 mocking 하는 방법에 대해서 알아보았습니다.<br><br><br>
  더 좋은 방법과 질문이 있으시다면 댓글 언제나 환영이고</br>
✨ 긴글 읽어주셔서 감사합니다! ✨
  </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SLA, SLO, SLI]]></title>
            <link>https://velog.io/@pood-tech/SLA-SLO-SLI</link>
            <guid>https://velog.io/@pood-tech/SLA-SLO-SLI</guid>
            <pubDate>Tue, 07 Feb 2023 01:05:57 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>안녕하세요. 오늘은 사용자에게 품질의 보장하는 합의에 대한 용어에 대해 설명하겠습니다.</p>
</blockquote>
<h3 id="1slaservice-level-agreement서비스-수준-협약">1.SLA(Service Level Agreement/서비스 수준 협약)</h3>
<h4 id="정의">정의</h4>
<ul>
<li>서비스 제공자와 클라이언트 또는 사용자 간의 협의</li>
<li>가용성, 성능, 데이터 내구성, 시스템 장애 발생 시 응답에 소요되는 시간 등 품질 서비스 관련해서 사용자들과 체결하는 일종의 합의를 뜻하는 법적 제약</li>
<li>SLA에는 우리가 해당 협의를 이행하지 못하고 계약을 위반했을 시 부여되는 패널티와 금전적 보상도 명시적으로 언급되어 있음</li>
</ul>
<h4 id="sla가-필요한-이유">SLA가 필요한 이유</h4>
<ul>
<li>서비스 이용자와 합의를 통한 가이드를 줘 원반한 처리</li>
<li>합의가 불명확할 경우 서비스 제공자와 서비스 이용자간의 혼란이 발생함</li>
</ul>
<h3 id="2-sloservice-level-objectives서비스-수준-목표">2. SLO(Service Level Objectives/서비스 수준 목표)</h3>
<h4 id="정의-1">정의</h4>
<ul>
<li>시스템과 과련해서 설정하는 개별 목표에 해당</li>
<li>각 SLO는 서비스가 충족해야 하는 목표값이나 또는 목표 값의 범위를 의미 
ex) 문제 해결 시간은 24시간에서 48시간 사이로 설정</li>
<li>설계 프로세스의 초반에 설정하는 모든 품질 속성 조건은 물론이고 시스템에 설정하는 다른 목표나 서비스 제공자의 책임으로 설정하는 다른 목표도 모두 한개나 그 이상의 SLO로 만들어지게 됨</li>
</ul>
<h3 id="slo-and-sla">SLO and SLA</h3>
<p>만약 시스템에 SLA가 있다면 각 SLO는 시스템 내의 특정 척도에 대한 SLA 내에서의 개별 협의를 뜻함
따라서 SLA는 모든 서비스 수준 목표를 하나의 법적 문서로 통합한 것에 해당
<img src="https://velog.velcdn.com/images/village_grandfa/post/1493909b-3e6d-4caf-85b5-be25f530220f/image.png" alt=""></p>
<p>하지만 SLA가 없는 시스템일지라도 SLO는 꼭 필요함 
왜냐면 이런 목표가 따로 설정되어 있지 않다면 내부나 외부 사용자가 우리 시스템을 사용함으로써 얻을 수 있는 기대치가 무엇일지 불명확 할수 밖에 없음</p>
<h3 id="3-sliservice-level-indicator서비스-수준-척도">3. SLI(Service Level Indicator/서비스 수준 척도)</h3>
<h4 id="정의-2">정의</h4>
<ul>
<li><p>서비스 수준 척도는 서비스 수준 목표를 이행하는 데 관련된 양적 척도를 의미
ex) 모니터링 시스템을 사용해서 측정하거나 로그에서 계산해서 나온 실제 숫자값</p>
</li>
<li><p>일단 이 서비스 수준 척도에 따라 숫자를 계산하게 되면 그 산출된 값을 나중에 서비스 수준 목표를 정할 때 설정한 목표치와 비교
ex) 성공적인 응답을 받은 사용자 요청의 퍼센티지를 산출해서 그 값을 시스템의 가용성을 측정하는 척도로 사용하여 서비스에 대해 설정한 가용성 서비스 수준 목표인 99.9%와 비교</p>
</li>
</ul>
<p>ex)각 요청의 반응 시간을 수집해서 그 값을 시간대 별로 버킷화한 다음 사용자가 경험한 반응 시간의 평균이나 백분위 분포를 계산할 수도 있음 그리고 나중에 그 산출값을 기존에 설정한 백분위 90에 100밀리초라는 종단간 지연 시간 SLO와 비교할 수 있답니다</p>
<h3 id="4-고려-사항">4. 고려 사항</h3>
<ol>
<li><p>사용자 관심 지표</p>
<ul>
<li>모든 측정할 수 있는 서비스 수준 척도를 가져다가 이 척도와 관련된 목표를 정하면 안 됨</li>
<li>대신에 사용자가 가장 신경을 쓸 법한 척도가 무엇일지 고민한 후에 해당 척도와 관련해서서비스 수준 목표를 정해야 함</li>
<li>그래야 해당 서비스 수준 목표를 추적할 서비스 수준 척도를 마련할 수 있음</li>
</ul>
</li>
<li><p>SLO의 갯수</p>
<ul>
<li>서비스 수준 목표를 더 적게 설정할수록 우리에게는 더 낫음</li>
<li>SLO가 너무 많아지면 모든 목표를 동일한 수준으로 우선시하기가 어렵움</li>
<li>SLO가 적으면 해당 목표와 관련된 전체 소프트웨어 아키텍처에 집중을 해서 목표를 달성하기가 훨씬 쉬워짐 </li>
</ul>
</li>
<li><p>현실적인 SLO 설정</p>
<ul>
<li>오류에 대비한 예산을 포함해 현실적인 목표를 설정</li>
<li>99.9%의 가용성을 제공할 수 있다고 해서 반드시 언제나 그래야만 한다는 건 아님 대신에 제공 가능한 더 낮은 수준의 가용성을 보장하는 데 집중해야 함 그래야 비용도 절감하고 예상치 못한 문제에 대비할 여력도 생김</li>
<li>서비스 수준 목표가 외부의 서비스 수준 협의로 구현되어 있는 경우에는 더욱</li>
<li>이런 경우 회사는 공격적인 성향의 내부 서비스 수준 목표와는 별개로 더 느슨한 수준의 외부 서비스 수준 목표를 따로 설정</li>
</ul>
<p>예를 들어  외부적으로는 가용성을 99.9%로 설정하더라도 내부적으로는 99.99%의 가용성으로 설정 내부적으로 더 좋은 품질의 서비스를 위해 노력하는 동시에 클라이언트 측으로는 신경을 조금 덜 써도 됨</p>
</li>
<li><p>복구 계획</p>
<ul>
<li>다시 말해서 만약에 갑자기 시스템이 오랫동안 다운되거나 또는 짧은 시간 안에 성능이 내려가고 갑자기 문제 발생 리포트를 너무 많이 받게 되는 그런 경우엔 어떻게 대처할 건지 미리 결정해야 한다는 거죠</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래밍의 내결합성]]></title>
            <link>https://velog.io/@pood-tech/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98-%EB%82%B4%EA%B2%B0%ED%95%A9%EC%84%B1</link>
            <guid>https://velog.io/@pood-tech/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98-%EB%82%B4%EA%B2%B0%ED%95%A9%EC%84%B1</guid>
            <pubDate>Fri, 03 Feb 2023 03:20:52 GMT</pubDate>
            <description><![CDATA[<p><code>안녕하세요 푸드 테크팀 서버개발팀 권영호 입니다</code></p>
<blockquote>
<h4 id="내결합성에-대해-이해-해보도록-하는-포스팅을-작성하려고-합니다">내결합성에 대해 이해 해보도록 하는 포스팅을 작성하려고 합니다.</h4>
</blockquote>
<br>

<ul>
<li>내결합성이란? 
내결함성(Fault Tolerance)은 하나 이상의 구성 요소가 고장나도 시스템이 중단 없이 계속 작동할 수 있는 능력을 의미합니다.</li>
</ul>
<hr>
<p>우리가 작성한 프로그램에 오류가 있어도 프로그램에 중단없이 계속 작동할수 있게 작업을 해야될지 아니면 프로세스를 중단시키는게 나을지를 한번쯤은 모두 고민해 봤을 겁니다.</p>
<p>아래 코드는 리스트의 값을 입력받아 sum을 하는 간단한 예제이다.</p>
<pre><code class="language-java">
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;

class FaultToleranceTest {

    @Test
    void print() {
        System.out.println(&quot;fault_tolerance&quot;);
        System.out.println(&quot;-------------------&quot;);
        List&lt;Object&gt; intStrList = Arrays.asList(&quot;1&quot;, &quot;2&quot;, &quot;3&quot;);
        System.out.println(&quot;result : &quot; + listSum(intStrList));
        System.out.println(&quot;-------------------&quot;);
        List&lt;Object&gt; intList = Arrays.asList(1, 2, 3);
        System.out.println(&quot;result : &quot; + listSum(intList));
        System.out.println(&quot;-------------------&quot;);
        List&lt;Object&gt; strList = Arrays.asList(&quot;a&quot;, &quot;2&quot;, &quot;c&quot;);
        System.out.println(&quot;result : &quot; + listSum(strList));
    }

    private static int listSum(List&lt;Object&gt; lists) {
        try {
            return lists.stream().mapToInt(x -&gt; Integer.parseInt(x.toString())).sum();
        }catch (NumberFormatException e){
            return 0;
        }
    }
}</code></pre>
<p>결과는 아래와 같다.
<img src="https://velog.velcdn.com/images/village_grandfa/post/13279b3a-6b20-4d4b-9d18-0d6e27423163/image.png" alt=""></p>
<p>문제는 무엇인가?
Integer 값은 물론이고 Integer로 변환될수 있는 값이면 정상적으로 sum해준다. 또한 잘못된 값이 들어 왔어도 0으로 처리하기 때문에 이 시스템이 멈추는일 없이 항상 운영될것이기 때문에 안정성이 증가되었다.
하지만 안정성을 증가시킨 대신 <strong>신뢰성</strong>이 높다고는 판단할수 없다.
과연 a 2 c를 입력받아 합쳐진 값이 0으로 판단할 기준이 어디에 있을까?
과연 a 2 c에 이 아닌 &quot;11 &quot;, &quot;2&quot;, &quot;2&quot; 이란 띄어쓰기가 잘못들어 갔을 경우도 0으로 반환한다.
그리고 개발자는 잘못된 값에 대한 피드백을 받기 쉽지 않다.</p>
<p>차라리.....</p>
<pre><code class="language-java">@Test
    void print2() {
        try {
            System.out.println(&quot;fault_tolerance&quot;);
            System.out.println(&quot;-------------------&quot;);
            List&lt;Object&gt; intStrList = Arrays.asList(&quot;1&quot;, &quot;2&quot;, &quot;3&quot;);
            System.out.println(&quot;result : &quot; + listSum2(intStrList));
            System.out.println(&quot;-------------------&quot;);
            List&lt;Object&gt; intList = Arrays.asList(1, 2, 3);
            System.out.println(&quot;result : &quot; + listSum2(intList));
            System.out.println(&quot;-------------------&quot;);
            List&lt;Object&gt; strList = Arrays.asList(&quot;a &quot;, &quot;2&quot;, &quot;c&quot;);
            System.out.println(&quot;result : &quot; + listSum2(strList));
        } catch (NumberFormatException e) {
            System.out.println(&quot;error : &quot; + e.getMessage());
        }
    }

    private static int listSum2(List&lt;Object&gt; lists) {
        return lists.stream().mapToInt(x -&gt; Integer.parseInt(x.toString())).sum();
    }</code></pre>
<p><img src="https://velog.velcdn.com/images/village_grandfa/post/a4d0bc20-f787-4c3d-904c-007071a83f91/image.png" alt=""></p>
<p>위와 같이 코드를 만들면 &quot;a &quot;, &quot;2&quot;, &quot;c&quot;가 들어왔을 경우 바로 에러가 나오고 시스템은 멈출것이다.
시스템은 멈춰지만 신뢰성을 높아지고 오류에 대한 피드백이 빨라 개발자는 해당 오류를 찾아 고칠려고 할것이다. 또 중요한점은 NumberFormatException의 처리가 메인 함수에 있다는 것 또한 명심해야 한다.
Exception이 메인 함수로 갈수록 코드를 읽기 쉬워진다. Exception의 처리 로직이 메인에 있을수록 코드에 가시성이 높아지며 처리하기도 쉽다. </p>
<hr>
<ul>
<li>결론에 앞서 ... 
항상 운영중인 시스템에는 회사마다 또는 서비스 마다의 rule이 존재한다. 결국 그 rule에 따라 결정이 달라지며 그 rule에 의해 대책에 마련되어 있기 마련이다.</li>
</ul>
<hr>
<h3 id="결론"><strong>결론</strong></h3>
<p>우린 내부의 오류를 숨기지 말고 최대한 빨리 알려주고 전파를 막아야 한다.
특히 오류를 숨기고 동작하게 만드는 내결합성이 높은 프로그램은 나중에 더 큰문제를 야기할뿐더러
데이터를 항상 깨트릴 수 있다는걸 명심해야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[믹스인(mix in)]]></title>
            <link>https://velog.io/@pood-tech/%EB%AF%B9%EC%8A%A4%EC%9D%B8mix-in</link>
            <guid>https://velog.io/@pood-tech/%EB%AF%B9%EC%8A%A4%EC%9D%B8mix-in</guid>
            <pubDate>Thu, 12 Jan 2023 09:46:32 GMT</pubDate>
            <description><![CDATA[<p><code>안녕하세요 푸드테크팀 백엔드 개발자 권영호 입니다.</code></p>
<h3 id="정의">정의</h3>
<p>믹스인의 정의를 표현한 글을 보면 이해하기가 쉽지 않다</p>
<p><img src="https://velog.velcdn.com/images/village_grandfa/post/b5eb0c1b-385a-46ea-9cf7-7fe1ec8e2faa/image.png" alt=""></p>
<p>글의 정의는 어렵지만 간단하게 결국 멀티 인터페이스 또는 추상 클레스를 계층형으로 구현하여 메소드를 조합하는 것을 말한다.</p>
<h3 id="구현">구현</h3>
<hr>
<p>계층 추상 클레스</p>
<pre><code class="language-java">public abstract class Singer {
    void SingerPrint(){
        System.out.println(&quot;SingerPrint&quot;);
    };
}

public abstract class SongWriter  extends Singer{
    void songWriterPrint(){
        System.out.println(&quot;songWriterPrint&quot;);
    };
}

public class SingSongWriter extends SongWriter {
}

public class Main {
    public static void main(String[] args) {
        SingSongWriter singSongWriter = new SingSongWriter();
        singSongWriter.SingerPrint();
        singSongWriter.songWriterPrint();
    }
}</code></pre>
<hr>
<p>멀티 인터페이스 </p>
<pre><code class="language-java">public interface Singer {
    default void SingerPrint(){
        System.out.println(&quot;SingerPrint&quot;);
    };
}

public interface SongWriter {
    default void songWriterPrint(){
        System.out.println(&quot;songWriterPrint&quot;);
    };
}

public class SingSongWriter implements Singer, SongWriter {
}

public class Main {
    public static void main(String[] args) {
        SingSongWriter singSongWriter = new SingSongWriter();
        singSongWriter.SingerPrint();
        singSongWriter.songWriterPrint();
    }
}</code></pre>
<hr>
<p>결국 추상 클레스와 멀티 인터페이스 모두 믹스인을 구현할수 있지만 결국 멀티인터페이스로 개발할수 밖에 없다.</p>
<p>추상 클레스를 계층형으로 상속하여 믹스인을 구현시 A -&gt; B -&gt; C 순으로 상속하여 만들었을 경우 A,C 만의 기능을 필요로 한 새로운 믹스인을 만들려면 B라는 클레스의 기능을 빼기 위해 상속 계층을 A -&gt; C -&gt; B 로 변경후 C클레스를 상속하는 형식으로 만들수 있지만 이렇게 하지 않고 멀티 인터페이스를 사용하여 구현하자</p>
<p>멀티 인터페이스로 구현시 아무 문제 없이 A,C 인터페이스를 상속하는 새로운 클레스를 만들어 사용하면 쉽게 구현할수 있다.</p>
<p>보시다 시피 추상 클레스로 믹스인을 구현시 계층 구조로 구현할수 밖에 없는데 이건 큰 불편을 가져오고 사용할 메소드가 늘어나거나 줄어들면 수정하기 쉽지 않는 구조이다.</p>
<p>다중 인터페이스로 구현시 조합이 간단하고 사용할 메소드가 늘어나거나 줄어들어도 수정이 용이하다.</p>
<h3 id="장점">장점</h3>
<ol>
<li>단일 기능의 클래스나 인터페이스를 만들수 있다.</li>
<li>불필요한 기능을 상속받지 않고 필요한 기능만을 조합하여 구현할수 있다.</li>
<li>많은 기능을 모두 포함하지않고 조합하여 사용하기 때문에 수정이나 추가의 영향도가 적다. </li>
</ol>
<p>이로써 믹스인에 대한 정리를 마치겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Tech Blog 의 시작, posting →  slack 연동]]></title>
            <link>https://velog.io/@pood-tech/Tech-Blog-%EC%9D%98-%EC%8B%9C%EC%9E%91-posting-slack-%EC%97%B0%EB%8F%99</link>
            <guid>https://velog.io/@pood-tech/Tech-Blog-%EC%9D%98-%EC%8B%9C%EC%9E%91-posting-slack-%EC%97%B0%EB%8F%99</guid>
            <pubDate>Fri, 06 Jan 2023 12:49:22 GMT</pubDate>
            <description><![CDATA[<p><code>안녕하세요 푸드 테크팀 백엔드 개발자 박형민 입니다</code></p>
<p>기존 테크블로그에서 꾸준히(?) 글을 써오다가 오랜만에 블로그 글을 작성합니다.
최근 회사 계정이 바뀌게 되어 이 계정에서는 첫 글이 되어 <code>Tech Blog 의 시작</code> 이라는 거창한 제목을 달았습니다 ㅎㅎ</p>
<p><br><br></p>
<p>** 🐯 이번 포스팅의 목표는 Velog 와 Slack 을 연동해보고자 합니다.**</p>
<hr>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/ebcbb6cb-7a0a-40e0-a449-ab2dcde5fb8a/image.png" alt=""></p>
<br>
 2022년 꾸준히(?) 사내 Pood Tech Blog 에 많은 팀원분들이 글을 써왔지만, 몆가지 아쉬운 점이 있었습니다.
<br>

<p><del>1. Blog 글을 쓰는 사람이 적다.(?)</del>
2. 하나의 계정을 공유에서 사용하는 것이기 때문에, 댓글을 달아도 주기적으로 들어가서 확인해야 알 수 있다.
3. 포스팅을 작성해도 다른사람에게 말해주기 전까지는 모른다..!
4. 매우 많은 피드백을 받고싶다!</p>
<br>

<blockquote>
<p>신년을 맞이하여, 새로운 시작을 하고싶었기 때문에 ! Velog 에 새로운 피드가 올라오면, 사내 Slack에 자동으로 알림이 갈 수 있도록 설정해 보려고 합니다!!!!</p>
</blockquote>
<ul>
<li>사실, 직접 올리면 되지만 귀찮은게 싫기 때문에 자동화를 시키기위한 목적입니다.</li>
<li>Slack 에 연동해서 주기적으로 공유하게되면, 1번(?)과 3번, 4번을 해결할 수 있을거라고 생각했습니다.</li>
</ul>
<br>

<hr>
<br>

<h1 id="1-slack-에-rss-추가하기">1. Slack 에 RSS 추가하기</h1>
<blockquote>
<p>결국은 Velog 구독기능이기 때문에, Slack RSS 앱을 통하여 Velog 의 소식을 받아볼 수 있도록 해야했습니다.</p>
</blockquote>
<h2 id="1slack-rss-설정">1.Slack RSS 설정</h2>
<ul>
<li>먼저 Slack 에서 RSS 구독을 사용할 수 설정해주었습니다.</li>
<li>[Slack] - [관리] - [앱관리] - [rss 검색]</li>
</ul>
<p align="center">
<img src="https://velog.velcdn.com/images/pood-tech/post/4acdf938-a7e3-4c71-a876-e06f055d4542/image.png" width="80%" height="80%">

<p><img src="https://velog.velcdn.com/images/pood-tech/post/d30de20b-e039-4ac5-a0cc-8a7857f53339/image.png" alt=""></p>
</p>                                                                           


<br>

<h2 id="2-velog-rss-등록">2. Velog RSS 등록</h2>
<ul>
<li><p>그다음, velog 의 rss 를 등록해줍니다.</p>
</li>
<li><p>Velog 의 RSS는 다음과 같은 규칙으로 바꿔주시면 됩니다.</p>
</li>
<li><p>앞쪽에 <code>v2</code> or<code>api</code> 가 붙고 뒤쪽에 /rss가 붙고 @가 사라집니다. </p>
</li>
</ul>
<pre><code>ex) velog.io/@(벨로그 이름) → api.velog.io/rss/(벨로그 이름)</code></pre><p align=center>
<img src="https://velog.velcdn.com/images/pood-tech/post/85b65216-429d-47a5-b159-7d9553d06daa/image.png" width="80%">

  <br>
  매우 간단하게, 구독을 끝냈습니다.

</p>


<p><br><br></p>
<p>알림이 안와서 조마조마해 하고 있었는데 약 10분이 지나니 알림이 왔습니다. (<del>중요한건 시간보다 자동화 아니겠습니까ㅠㅠ???</del>)
<img src="https://velog.velcdn.com/images/pood-tech/post/c9fc001e-eae2-4cb0-9e08-8c745e42b3e3/image.png" alt=""></p>
<p align=center>✨ 챠란~~ </p>

<hr>
<p><br><br></p>
<h1 id="2-velog-댓글-알림-slack-연동">2. Velog 댓글 알림 Slack 연동</h1>
<ul>
<li><p>생각보다 연동이 쉬워서, 아쉬원던 점 중 하나인 (2)를 해결하기 위해 댓글 알림을 Slack 과 연동해보려고 합니다.</p>
</li>
<li><p>아이디어는, <code>Velog 댓글 작성 시 가입한 이메일로 댓글알림을 설정할 수 있으니 Slack에서 Email 과 연동할 수 있는게 있지않을까?</code> 였습니다.</p>
</li>
<li><p>결과적으로는 <a href="https://zapier.com/app/dashboard">Zapier</a> 에서 Webhook을 이용해 무료로! 특정 gmail 내용을 slack 메세지로 보낼 수 있었습니다.</p>
</li>
</ul>
<br>

<h2 id="1-email-확인">1) Email 확인</h2>
<p>항상 테스트가 중요하니, Velog 댓글 알림 기능이 회사 계정 이메일에 잘 오는지와 메일 양식을 확인해보았습니다.</p>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/2aec5492-3e6d-485c-8d52-ca7113eb95d3/image.png" alt=""></p>
<br>

<h2 id="2-slack---gmail-연동">2) Slack - Gmail 연동</h2>
<blockquote>
<p>회사 메일인 gmail 로 들어오는 것을 확인하였으니 이제 연동을 시도해봅니다.</p>
</blockquote>
<p>위에서 언급했다 시피 Zapier 를 사용할 것입니다.</p>
<ul>
<li>Zapier가 굉장히 생소해서 찾아보니, 업무 자동화 툴로써 이미 많이 사용되고 있는 노코드 자동화 툴이라고 합니다.</li>
<li><code>재피어(Zapier)는 업무에 사용하는 다양한 업무 툴과 서비스를 연결하고 반복적인 업무를 대신해 주는 대표적인 노코드 자동화 툴입니다.</code> (<a href="https://blog.jandi.com/ko/2022/06/30/how-to-zapier-like-a-pro/">출처</a>)</li>
</ul>
<br>

<h3 id="zapier-사용방법">Zapier 사용방법</h3>
<ul>
<li>먼저 Zapier 에 가입을하고, 특정 이벤트를 수행할 Zap 을 생성하여 줍니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/a3e6df73-8c32-49f8-9358-6a8008d8aade/image.png" alt=""></p>
<h4 id="trigger-생성">Trigger 생성</h4>
<ol>
<li>그다음 이벤트를 수행시킬 Trigger 를 선택해줍니다.
<img src="https://velog.velcdn.com/images/pood-tech/post/4322ee45-6744-4345-8b76-7b21e9558873/image.png" alt=""></li>
</ol>
<ol start="2">
<li>Trigger 가 실행되는 액션도 간편하게 설정해줄 수 있습니다.</li>
</ol>
<ul>
<li>저는 velog 에서 날아오는 댓글만을 slack 으로 보내주고 싶었기 때문에 <code>New Email Matching Search</code> 를 선택하였습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/3afe8964-3c69-493a-b0e1-58a833ed53f4/image.png" alt=""></p>
<ol start="3">
<li>선택한 옵션에 맞춰 필터를 걸어줄 수 있습니다.</li>
</ol>
<ul>
<li>단순한 문자열 매칭은, 보낸문자와 받는문자까지 포함하기 때문에</li>
<li>필터링 동작은, Gmail 의 검색창에서의 조건과 동일하다고 합니다.</li>
<li><a href="https://support.google.com/mail/answer/7190?hl=en">Gmail 에서 사용할 수 있는 검색연산자 리스트</a></li>
</ul>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/fbe21720-4d51-4e89-97ce-7b4900ad6d97/image.png" alt=""></p>
<hr>
<h4 id="action-생성">Action 생성</h4>
<ol>
<li>Trigger를 설정했다면 Action 을 설정해주어야합니다.</li>
</ol>
<ul>
<li>저는 팀내 채널에 업로드하기위해 &quot;Send Channel Message&quot; 를 선택해주었습니다.
<img src="https://velog.velcdn.com/images/pood-tech/post/d5864e78-db16-408d-952c-83c1eaeeb9a5/image.png" alt=""></li>
</ul>
<ol start="2">
<li>세부 디테일 설정하기</li>
</ol>
<ul>
<li>그 외에, 메세지를 보낼 slack channel,  메세지 형식, 봇 아이콘 이름, 이미지 등을 설정할 수 있습니다.</li>
<li>메세지 양식을 <a href="https://help.zapier.com/hc/en-us/articles/8496025607181#lists-0-2">zapier 문서</a>를 참고하였습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/pood-tech/post/630c8123-aa23-4471-aefb-6b82215672da/image.png" alt=""></p>
<h1 id="결과물">결과물</h1>
<ul>
<li>굉장히 만족스러운 형태의 알림을 구성하였습니다.
<img src="https://velog.velcdn.com/images/pood-tech/post/89f12aeb-6aa3-4329-b562-9c05bb0f7725/image.png" alt=""></li>
</ul>
<hr>
<p><br><br></p>
<p align=center>
새해부터 작년의 아쉬웠던 점을 개선할 수 있는 기회가 주어져서 매우 기쁘네요.<br>
끝까지 읽어주셔서 감사합니다!
</p>


]]></description>
        </item>
    </channel>
</rss>