<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>JeongO</title>
        <link>https://velog.io/</link>
        <description>IT'S YOUR VICTORY</description>
        <lastBuildDate>Thu, 02 Mar 2023 04:37:51 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. JeongO. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/snoopy_21" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[RDB와 NoSQL]]></title>
            <link>https://velog.io/@snoopy_21/RDB%EC%99%80-NoSQL</link>
            <guid>https://velog.io/@snoopy_21/RDB%EC%99%80-NoSQL</guid>
            <pubDate>Thu, 02 Mar 2023 04:37:51 GMT</pubDate>
            <description><![CDATA[<h3 id="🟠-rdb">🟠 RDB</h3>
<ul>
<li>TABLE모델에 데이터를 저장한다.</li>
<li>데이터 중복을 감소.</li>
<li>데이터 구조가 엄격하다.</li>
<li>Oracle, MySQL, PostgreSQL 등.</li>
</ul>
<p><strong>장점</strong></p>
<ul>
<li>명확학 데이터 구조를 보장.</li>
<li>무결성 보장(데이터 중복 없이 한 번만 저장).</li>
<li>중복이 없으므로 데이터 Update 용이.</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li>시스템이 커지면 Join문이 많은 복잡한 쿼리 발생.</li>
<li>수평적 확장이 까다로워 수직적 확장(Scale up)이 주로 사용되는데 비용이 크다.</li>
</ul>
<p>👉 데이터 구조가 변경될 여지 없이 명확한 경우, 데이터 update가 잦은 시스템에서 사용</p>
<br>
<br>

<h3 id="🟠nosql">🟠NoSQL</h3>
<ul>
<li>Key-Value, Jason document, 그래프 등의 데이터 저장 형태를 가진다.</li>
<li>확장 및 수정 가능성</li>
<li>데이터 구조가 유연하다.</li>
<li>MongoDB, DynamoDB 등.</li>
</ul>
<p><strong>장점</strong></p>
<ul>
<li>유연하고 자유로운 데이터 구조.</li>
<li>새로운 필드 추가 자유로움.</li>
<li>수평적 확장(Scale out) 용이.</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li>데이터 중복 발생 가능.</li>
<li>중복된 데이터가 많으므로 데이터 Update시, 모든 컬렉션에서 수정필요.</li>
<li>명확학 데이터 구조를 보장하지 않음.</li>
</ul>
<p>👉 정확한 데이터 구조가 정해지지 않은 경우, 데이터 update가 자주 이뤄지지 않는 경우, 데이터 양이 매우 많은 경우 사용</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[오버라이딩과 오버로딩]]></title>
            <link>https://velog.io/@snoopy_21/%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9%EA%B3%BC-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9</link>
            <guid>https://velog.io/@snoopy_21/%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9%EA%B3%BC-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9</guid>
            <pubDate>Thu, 02 Mar 2023 04:27:01 GMT</pubDate>
            <description><![CDATA[<p>오버라이딩, 오버로딩 모두 동일한 메서드명을 다양하게 구현하는 방식이고 OOP의 &#39;다형성&#39;을 구현하는 방법 중 하나이다.</p>
<h3 id="🟠-오버라이딩">🟠 오버라이딩</h3>
<ul>
<li>메소드를 재정의 하는 것을 말한다.</li>
<li>상속 관계에서, 부모가 가진 어떤 메소드들은 자식 클래스가 사용하기에 적합하지 않아 메소드를 수정해서 사용하는 것.</li>
</ul>
<p><strong>규칙</strong></p>
<ul>
<li><p>부모의 메소드와 동일한 <strong>리턴 타입, 메소드 이름, 매개 변수 목록</strong> 을 가져야 한다.</p>
</li>
<li><p>접근 제한을 더 강하게 재정의할 수 없다.</p>
</li>
<li><p>새로운 예외(Exception)를 throws할 수 없다.</p>
</li>
<li><p>final이 선언된 메소드는 더이상 재정의 할 수 없는 최종 메소드이다.</p>
</li>
<li><p>오버라이딩 하면 부모 객체의 메서드는 숨겨지고, 자식 객체에서 메서드 호출하면 반드시 오버라이딩된 자식 메서드가 호출된다.</p>
</li>
<li><p>자식객체가 자신이 오버라이드한 부모의 메소드를 호출하고 싶으면 &#39;super.메소드()&#39;를 사용한다.</p>
</li>
</ul>
<pre><code class="language-Java">
class Parent{
    public void call( ){
        System.out.println(&quot;부모&quot;);
        }
    }


class Child extends Parent{

    @Override
    public void call( ){
        System.out.println(&quot;자식&quot;);
        }
    }


public class Override{

    public static void main(String[] args) {    

    Parent p = new Child();
    p.call();

    }
 }

 👉 &quot;부모&quot;가 아닌 &quot;자식&quot;이 출력된다 
    (동적바인딩 : 재정의된 메서드를 먼저 호출하는 규칙)
</code></pre>
<br>
<br>

<h3 id="🟠-오버로딩">🟠 오버로딩</h3>
<ul>
<li>메서드 확장의 개념이다.</li>
<li>같은 이름의 메소드를 중복하여 정의하는 것.</li>
<li>자바에서는 원래 한 클래스 안에 같은 이름의 메소드를 가질 수 없지만 오버로딩하게되면 여러 메소드를 같은 이름으로 정의할 수 있다.</li>
<li>메소드에 사용되는 이름을 절약할 수 있고, 메소드 호출 시 전달해야 할 매개변수의 타입이나 개수를 신경쓰지 않아도 된다. </li>
<li>대표적인 오버로딩 : println(다양한 매개변수 가능)</li>
</ul>
<p><strong>규칙</strong></p>
<ul>
<li><p>parameter의 개수나 타입이 달라야한다.</p>
</li>
<li><p>리턴타입과 함수명은 같아야 한다. (리턴타입이 다른 경우에는 오버로딩이 성립하지 않는다)</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 패키지와 접근제한자]]></title>
            <link>https://velog.io/@snoopy_21/Java-%ED%8C%A8%ED%82%A4%EC%A7%80%EC%99%80-%EC%A0%91%EA%B7%BC%EC%A0%9C%ED%95%9C%EC%9E%90</link>
            <guid>https://velog.io/@snoopy_21/Java-%ED%8C%A8%ED%82%A4%EC%A7%80%EC%99%80-%EC%A0%91%EA%B7%BC%EC%A0%9C%ED%95%9C%EC%9E%90</guid>
            <pubDate>Wed, 01 Mar 2023 18:27:41 GMT</pubDate>
            <description><![CDATA[<h3 id="패키지-선언"><strong>패키지 선언</strong></h3>
<ul>
<li>클래스 복사하려면 패키지 전체를 복사해야 함</li>
<li>이름은 모두 소문자로</li>
<li>숫자시작 안됨. _$ 제외 특수문자 안됨. java로 시작하면 안됨<br>

</li>
</ul>
<h3 id="패키지-생성"><strong>패키지 생성</strong></h3>
<ul>
<li>src폴더에서 패키지 생성</li>
<li>name 입력란에 상위패키지.하위패키지 로 작성<br>

</li>
</ul>
<h3 id="import문"><strong>import문</strong></h3>
<ul>
<li>사용하려는 클래스나 인터페이스가 다른 패키지에 소속되어 있다면 import문으로 해당 패키지의 클래스 또는 인터페이스를 가져와 사용할 것임을 컴파일러에게 알려줘야 함</li>
<li>import 상위패키지.하위패키지.클래스이름’</li>
<li>import 상위패키지.하위패키지.*;</li>
<li>import문은 패키지 선언과 클래스 선언 사이에 작성</li>
<li>상위 패키지를 import했다고 해서 하위 패키지까지 import되는 것은 아님</li>
<li>자바는 패키지 전체 이름으로 패키지를 식별</li>
<li>서로 다른 패키지에 동일한 클래스 이름이 존재하고, 두 패키지가 모두 import되었다면 컴파일러는 어떤 패키지의 클래스를 사용할 지 알 수 없다. 이 경우 정확하게 패키지가  포함된 클래스 전체 이름을 기술해야 한다.(한국타이어랑 금호타이어 패키지에 있는 각각의 타이어 클래스 import할 경우 패키지 이름부터 다 적어줘야함)<br>

</li>
</ul>
<h3 id="접근제한자"><strong>접근제한자</strong></h3>
<ul>
<li>접근 : 클래스 및 인터페이스, 이들이 가지고 있는 멤버 접근</li>
<li>객체 생성 막으려면 생성자 호출하지 못하게 해야함(싱글톤)</li>
<li>public 외부 클래스 자유롭게 사용</li>
<li>protected 같은 패키지 또는 자식 클래스에서 사용 가능</li>
<li>default 같은 패키지에 소속된 클래스만 사용 가능</li>
<li>private 외부에서 사용 불가(같은 클래스 내에서만 사용가능)<br>

</li>
</ul>
<h3 id="클래스의-접근-제한"><strong>클래스의 접근 제한</strong></h3>
<ul>
<li>클래스 접근 제한은 public, default 둘 중 하나<br>

</li>
</ul>
<h3 id="생성자의-접근-제한"><strong>생성자의 접근 제한</strong></h3>
<ul>
<li>객체 생성 시 new 연산자로 생성자 호출</li>
<li>생성자는 public, protected, default, private 접근제한자 다 가짐</li>
<li>생성자 선언이 없어서 자동으로 생성되는 기본 생성자의 접근 제한은 클래스의 접근 제한과 동일하게 생성된다<br>

</li>
</ul>
<h3 id="싱글톤-패턴"><strong>싱글톤 패턴</strong></h3>
<ul>
<li>하나의 객체만 만들어야 하는 경우, 생성자를 private접근 제한으로 선언하고, 자신의 유일한 객체를 리턴하는 getInstacne( ) 정적 메소드를 선언하는 것<br>

</li>
</ul>
<h3 id="필드와-메소드의-접근-제한"><strong>필드와 메소드의 접근 제한</strong></h3>
<ul>
<li>필드와 메소드도 4가지 접근 제한 모두 가능<br>

</li>
</ul>
<h3 id="getter와-setter메서드"><strong>Getter와 Setter메서드</strong></h3>
<ul>
<li><p>일반적으로 OOP에서는 객체의 필드를 객체 외부에서 직접적으로 접근하는 것을 막는다</p>
</li>
<li><p>외부에서 마음대로 변경할 경우 객체의 무결성이 깨지기 때문</p>
<p>   → 메서드를 통해 필드를 변경하는 방법 선호 (Setter)</p>
<p>  필드는 외부에서 접근할 수 없도록 막고 메소드는 공개해서 외부에서 필드에 접근하려면 메서드를 통하도록 함 (메서드가 매개값을 검증해서 유효한 값만 객체의 필드로 저장할 수 있게 한다)</p>
</li>
<li><p>반대로 필드값을 직접 사용하면 부적절한 경우도 있어, 메서드로 필드값을 가공한 후 외부로 전달하게 하는 메서드가 Getter</p>
</li>
<li><p>클래스 선언시 가능하다면 필드를 private로 선언해서 외부러부터 보호하고, 필드에 대한 Getter와 Setter메서드를 작성해 필드값을 안전하게 변경,사용 하는 것이 좋다</p>
</li>
<li><p>get,set 메서드 이름 지을 때 getFieldName, setFieldName ← 필드명의 첫 글자는 대문자로!</p>
</li>
<li><p>필드타입이 boolean일 경우 Getter는 get으로 시작하지 않고 is로 시작하는 것이 관례(Setter는 그냥 set으로 시작)</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Stack, Queue & Array, LinkedList]]></title>
            <link>https://velog.io/@snoopy_21/Stack-Queue-Array-LinkedList</link>
            <guid>https://velog.io/@snoopy_21/Stack-Queue-Array-LinkedList</guid>
            <pubDate>Tue, 28 Feb 2023 04:58:43 GMT</pubDate>
            <description><![CDATA[<h3 id="🟠-자료구조">🟠 자료구조</h3>
<p>메모리공간이나 접근, 연산시간 등의 관점에서 효율적으로 자료를 저장하고 관리할 수 있게 만든 모델</p>
<p><img src="https://velog.velcdn.com/images/snoopy_21/post/4f2a459b-5494-4cd3-9f6c-a4c4e78c06c1/image.png" alt=""></p>
<p>Stack, Queue, Array, LinkedList 는 Linear 구조에 속하는 자료구조이다.</p>
<p><img src="https://velog.velcdn.com/images/snoopy_21/post/c613e5b1-80d0-4ced-a244-af0d5b3f7fa4/image.png" alt=""></p>
<h3 id="🟠-stack">🟠 Stack</h3>
<p>LIFO구조
push,pop,peek 메서드를 통해 기능을 구현
이전에 한 작업을 기억하거나 되돌려야 하는 경우에 많이 사용됨
(괄호 갯수 새기)</p>
<h3 id="🟠-queue">🟠 Queue</h3>
<p>FIFO구조
enqueue, dequeue 메서드를 통해 기능 구현</p>
<h3 id="🟠-array">🟠 Array</h3>
<p>자료가 연속적으로 저장되는 구조(순차적)
인덱스를 사용할 수 있다
검색, 접근, 정렬 등에 강점을 가진다 (Array에 존재하는 모든 요소에 접근하는 속도는 동일하다)
데이터의 추가, 삭제의 경우 배열의 복사와 이동이 일어나야해서 성능이 떨어진다</p>
<h3 id="🟠-linkedlist">🟠 LinkedList</h3>
<p>자료가 비연속적으로 저장된다(순서 없음)
하나의 노드는 자기자신의 데이터와 다음 연결된 노드의 주소만 가진다
인덱스가 없으므로 검색의 경우 성능이 떨어진다(처음부터 하나하나 찾아야 함)
데이터 추가, 삭제의 경우 앞,뒤 노드의 주소만 변경해주면 되므로 빠르다</p>
<pre><code class="language-java">Class Node{
    Node next;
    Object obj;
}</code></pre>
<br>
LinkedList의 단점을 보완 👉 Doubly LinkedList, Doubly Circular LinkedList <br>
Java는 Doubl LinkedList를 구현 <br><br>




<br>
*참고

<table>
<thead>
<tr>
<th align="left">자료구조</th>
<th>접근시간</th>
<th align="center">중간 추가,삭제</th>
<th align="right">순차적 추가,삭제</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Array</td>
<td>훨씬빠름</td>
<td align="center">느림</td>
<td align="right">빠름</td>
</tr>
<tr>
<td align="left">LinkedList</td>
<td>느림</td>
<td align="center">훨씬 빠름</td>
<td align="right">상대적으로느림</td>
</tr>
</tbody></table>
<p>순차적 추가,삭제는 Array가 더 빠르므로 Stack을 구현하려면 Array이용하는 것이 효율적
Queue를 구현하려면 LinkedList를 이용하는 것이 효율적</p>
<br>

<hr>
<br>

<p>참고 사이트
<a href="https://afteracademy.com/blog/introduction-to-data-structure/">https://afteracademy.com/blog/introduction-to-data-structure/</a>
<a href="https://www.scaler.com/topics/data-structures/what-is-data-structure/">https://www.scaler.com/topics/data-structures/what-is-data-structure/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹서버와 WAS]]></title>
            <link>https://velog.io/@snoopy_21/%EC%9B%B9%EC%84%9C%EB%B2%84%EC%99%80-WAS</link>
            <guid>https://velog.io/@snoopy_21/%EC%9B%B9%EC%84%9C%EB%B2%84%EC%99%80-WAS</guid>
            <pubDate>Tue, 28 Feb 2023 04:19:29 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/snoopy_21/post/92ac04b9-de24-4bd7-b9ce-00b0f559b945/image.png" alt=""></p>
<h3 id="🟠-web-server웹서버">🟠 Web Server(웹서버)</h3>
<p>클라이언트의 요청에 대해 정적 리소스를 반환한다
정적 리소스 : 단순 HTML, CSS, JS, 이미지, 파일 등 즉시 응답 가능한 컨텐츠
비즈니스 로직을 넣을 수 없으므로 동적 컨텐츠를 요청받을 시, WAS에 요청을 넘긴다
WAS에서 처리한 결과를 클라이언트에 전달한다
대표적인 웹서버로는 Apache, Nginx가 있다
프록시 기능을 넣을 수 있다
로드밸런싱 기능을 할 수 있다
SSL/TLS 인증서를 이용해 HTTPS통신을 할 수 있다</p>
<h3 id="🟠-web-application-server웹-애플리케이션-서버">🟠 Web Application Server(웹 애플리케이션 서버)</h3>
<p>비즈니스 로직을 넣을 수 있다
DB조회나 다양한 로직 처리가 필요한 동적 컨텐츠를 제공한다
JSP, Servlet 구동환경을 제공하므로 웹컨테이너 혹은 서블릿컨테이너로 불린다
대표적인 WAS로는 Tomcat, PHP, ASP, .NET 등이 있다</p>
<p>요악 
웹서버는 클라이언트의 요청에 대해 빠르게 응답해줄 수 있는 정적 리소스의 반환을 담당하는 서버이고 
WAS는 비즈니스로직 수행이 필요한 요청에 대해 DB와 소통하여 로직 수행 결과 반환을 담당하는 서버이다.</p>
<br>
<br>

<hr>
<br>

<p>참고사이트
<a href="https://codechasseur.tistory.com/25">https://codechasseur.tistory.com/25</a>
<a href="https://www.youtube.com/watch?v=-WPPadQD3rg">https://www.youtube.com/watch?v=-WPPadQD3rg</a>
<a href="https://www.youtube.com/watch?v=70bzGTx-BHo">https://www.youtube.com/watch?v=70bzGTx-BHo</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[@SpringBootTest와 @WebMvcTest]]></title>
            <link>https://velog.io/@snoopy_21/SpringBootTest%EC%99%80-WebMvcTest</link>
            <guid>https://velog.io/@snoopy_21/SpringBootTest%EC%99%80-WebMvcTest</guid>
            <pubDate>Mon, 27 Feb 2023 04:51:54 GMT</pubDate>
            <description><![CDATA[<p>둘 다 SpringBoot에서 JUnit을 사용하여 테스트코드를 작성할 때 대표적으로 쓰인다.</p>
<h3 id="🟠-springboottest">🟠 @SpringBootTest</h3>
<ul>
<li>프로젝트 내 스프링 빈을 모두 등록하여 테스트에 필요한 의존성을 추가한다.</li>
<li>실제 운영 환경에서 사용될 클래스들을 통합하여 테스트할 수 있다.</li>
<li>단위 테스트 같은 기능 검증이 아니라, Spring Framework에서 전체적으로 Flow가 제대로 동작하는지 검증한다.</li>
</ul>
<p>** 장점**
애플리케이션의 설정이나 모든 빈을 로드하므로 운영환경과 가장 유사하게 테스트 할 수 있다.
Service 메서드의 스펙이 변경되어도 Mocking값을 수정하지 않아도 되므로 변경에 자유롭다.
<BR>
** 단점**
테스트 단위가 크므로 디버깅이 까다롭다.
로드할 것이 많아 시간이 오래 걸린다.
<BR></p>
<h3 id="🟠-webmvctest">🟠 @WebMvcTest</h3>
<ul>
<li><p>슬라이스 테스트.</p>
</li>
<li><p>Controller가 예상대로 동작하는지 테스트하는 것.</p>
</li>
<li><p>Web Layer만 로드하므로 빠르고 가볍게 테스트할 수 있다.</p>
</li>
<li><p>@WebMvcTest() 의 프로퍼티로 테스트를 하려는 컨트롤러 클래스를 넣어준다.</p>
<pre><code>@WebMvcTest(MemberController.class)</code></pre></li>
<li><p>이 어노테이션은 @Controller같은 웹과 관련된 빈만 주입되며 @Service와 같은 일반적인 @Component는 생성되지 않으므로 해당 컨트롤러를 생성하는 데 필요한 다른 빈을 정의하지 못해 NoSuchBeanDefinitionException오류가 발생할 수 있다.
이런 경우에는 @MockBean을 사용해 필요한 의존성을 채워줘야 한다.</p>
</li>
<li><p>@WebMvcTest 어노테이션을 사용하면 아래 항목들만 스캔한다.
(@Controller, @ControllerAdvice, @JsonComponent, @Convert, @GenericConverter, Filter, WebMvcConfigurer, HandlerMethodArgumentResolver)</p>
</li>
<li><p>Security, Filter, Interceptor, request/response Handling, Controller의 항목들만 스캔하도록 제한하며, @Component는 스캔 대상에서 제외된다.</p>
</li>
</ul>
<p><strong>장점</strong>
WebApplication과 관련된 Bean 들만 등록하기 때문에 @SpringBootTest보다 빠르다.
통합테스트를 하기 어려운 경우 개별적으로 테스트가 가능하다.
(ex. 결제 모듈 API사용에서 특정 조건에 따라 실패하는 경우를 Mock을 통해 가짜 객체를 만들어 테스트 가능)
<BR>
<strong>단점</strong>
Mock을 기반으로 테스트하므로 실제 환경에서는 예상 밖의 동작오류가 발생할 수 있다.
Mocking 메서드의 변경이 일어나면 수정해야 한다.</p>
<hr>
<p>참고
<a href="https://astrid-dm.tistory.com/536">https://astrid-dm.tistory.com/536</a>
<a href="https://wiselog.tistory.com/171">https://wiselog.tistory.com/171</a>
<a href="https://jaehoney.tistory.com/213">https://jaehoney.tistory.com/213</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[트랜잭션]]></title>
            <link>https://velog.io/@snoopy_21/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98</link>
            <guid>https://velog.io/@snoopy_21/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98</guid>
            <pubDate>Mon, 27 Feb 2023 04:17:07 GMT</pubDate>
            <description><![CDATA[<h3 id="🟠트랜잭션transaction">🟠트랜잭션(Transaction)</h3>
<ul>
<li><p><strong>데이터베이스의 상태를 변화</strong>시키는 하나의 논리적 기능을 수행하기 위한 <strong>작업 단위</strong></p>
<p><strong>데이터베이스의 상태 변화</strong>
👉 SQL질의어(SELECT, INSERT, DELETE, UPDATE)를 이용해 데이터베이스에 접근하는 것</p>
<p><strong>작업 단위</strong>
👉 한꺼번에 모두 수행되어야 하는 일련의 연산들(정하기 나름이다)</p>
<blockquote>
<p>계좌 송금의 경우 A의 계좌에서 돈이 나가는 것과 B의 계좌에 돈이 들어오는 것은 한꺼번에 수행되어야 하므로 하나의 작업 단위 즉, 트랜잭션에 포함되어야 한다.</p>
</blockquote>
</li>
</ul>
<br>

<h3 id="🟠트랜잭션에-필요한-연산">🟠트랜잭션에 필요한 연산</h3>
<ul>
<li><p>*<em>Commit 연산 *</em>
하나의 트랜잭션이 완수되어 데이터베이스가 일관성 있는 상태에 있음을 의미한다</p>
<blockquote>
<p>A계좌에서 돈이 나가는 것, B의 계좌에 돈이 들어오는 것 모두 성공적으로 수행된 상태</p>
</blockquote>
</li>
<li><p><strong>Rollback 연산</strong>
하나의 트랜잭션 내 비정상적으로 종료된 작업이 있어 트랜잭션의 원자성이 깨진 상태.
해당 트랜잭션이 수행한 모든 연산을 재시작하거나 취소한다.</p>
<blockquote>
<p>A계좌에서 돈이 나가는 것은 성공적으로 수행되었으나, B계좌에 돈이 들어오지 않았을 경우 A계좌에서 돈이 나간 작업을 다시 되돌린다. </p>
</blockquote>
</li>
</ul>
 <br>

<h3 id="🟠트랜잭션의-상태">🟠트랜잭션의 상태</h3>
<p><img src="https://velog.velcdn.com/images/snoopy_21/post/2c8af48a-033a-4b44-94f3-092bde2b73c0/image.png" alt=""></p>
<ul>
<li><strong>Active</strong> : 트랜잭션이 실행 중인 상태</li>
<li><strong>Failed</strong> : 트랜잭션 실행 중 오류가 발생되어 중단된 상태</li>
<li><strong>Aborted</strong> : 트랜잭션이 비정상 종료되어 Rollback연산을 수행한 상태</li>
<li><strong>Partially Committed</strong> : 트랜잭션의 마지막 연산까지 실행했으나 아직 Commit연산을 실행하기 직전 상태</li>
<li><strong>Committed</strong> : 트랜잭션이 성공적으로 종료되어 Commit연산을 실행한 상태</li>
</ul>
<br>

<h3 id="🟠트랜잭션이-가져야-하는-특징acid">🟠트랜잭션이 가져야 하는 특징(ACID)</h3>
<p><strong>1. 원자성(Atomicity)</strong>
트랜잭션 내의 모든 명령은 완벽하게 수행되어야 한다.
어느 하나라도 오류 발생 시, 해당 트랜잭션은 모두 취소된다.
따라서 트랜잭션의 연산이 모두 반영되어 Commit되거나 하나도 반영되지 않게 Rollback되어야 한다.
<br>
<strong>2. 일관성(Consistency)</strong>
트랜잭션의 작업 처리 결과는 항상 일관성 있어야 한다.
<br>
<strong>3. 독립성, 격리성(Isolation)</strong>
하나의 트랜잭션이 수행 중일 때는 다른 트랜잭션 연산에 끼어들 수 없고, 다른 트랜잭션 의 수행 결과를 참조할 수도 없다.
<br>
<strong>4. 영속성, 지속성(Durability)</strong>
성공적으로 완료된 트랜잭션의 결과는 시스템이 고장나더라도 영구적으로 반영되어야 한다.</p>
<br>

<hr>
<br>

<p>참고
<a href="https://cocoon1787.tistory.com/808">https://cocoon1787.tistory.com/808</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Refresh Token 저장소를 Redis로 변경하며 만난 문제]]></title>
            <link>https://velog.io/@snoopy_21/Refresh-Token-%EC%A0%80%EC%9E%A5%EC%86%8C%EB%A5%BC-Redis%EB%A1%9C-%EB%B3%80%EA%B2%BD%ED%95%98%EB%A9%B0-%EB%A7%8C%EB%82%9C-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@snoopy_21/Refresh-Token-%EC%A0%80%EC%9E%A5%EC%86%8C%EB%A5%BC-Redis%EB%A1%9C-%EB%B3%80%EA%B2%BD%ED%95%98%EB%A9%B0-%EB%A7%8C%EB%82%9C-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Sun, 26 Feb 2023 17:34:04 GMT</pubDate>
            <description><![CDATA[<p>당근플래너 서비스에 Redis를 도입한 과정을 간단히 글로 작성했었다.<br>( 도입기 👉 <a href="https://danggeunplanner.tistory.com/entry/BE-%EB%8B%B9%EA%B7%BC%ED%94%8C%EB%9E%98%EB%84%88%EC%97%90-%EB%A0%88%EB%94%94%EC%8A%A4-%EB%BF%8C%EB%A6%AC%EA%B8%B0%EB%8F%84%EC%9E%85%EA%B8%B0">https://danggeunplanner.tistory.com/entry/BE-%EB%8B%B9%EA%B7%BC%ED%94%8C%EB%9E%98%EB%84%88%EC%97%90-%EB%A0%88%EB%94%94%EC%8A%A4-%EB%BF%8C%EB%A6%AC%EA%B8%B0%EB%8F%84%EC%9E%85%EA%B8%B0</a>)</p>
<br>
<br>

<p>사실 처음에는 Refresh Token기능 로직이 다 작성되어 있으니 저장소만 옮기면 된다!고 간단하게 생각했었다.
하지만 머지 않아 그렇지 않다는 것을 알게 되었다.</p>
<p>Redis를 처음 접해본 나에게는, 그리고 당시 구현되어있던 우리의 로직에서는 뿅!하고 순식간에 옮겨지는 것은 아니었다.</p>
<br>

<h3 id="🔴-문제-상황">🔴 문제 상황</h3>
<p>기존 Refresh Token은 단순히 DB의 회원 테이블에 Refresh Token컬럼을 추가하여 저장해 두었었다.
하지만 Redis에서는 데이터의 저장 형태가 key-value 형식이었기 때문에 Refresh Token값과 짝을 이루는 key값이 있어야 했다.
회원의 데이터중 유니크한 값이 email을 key에 넣기로 했는데 문제는 레디스에서 Refresh Token을 조회할 때 email값을 인자로 받아올 수가 없다는 점이었다.</p>
<p>레디스에서 Refresh Token을 조회하는 경우는 Access Token이 만료된 후, 토큰 재발급 요청을 보낼 때인데 이때 클라이언트는 Refresh Token만 헤더에 담아서 보낸다.</p>
<p>문제는 여기서 발생했다.</p>
<ul>
<li>Refresh Token의 목적성을 고려해, 불필요하게 유저의 정보를 토큰에 담지 않는다.</li>
<li>토큰 재발급 요청시에는 Refresh Token만 헤더에 담아 온다.</li>
<li>재발급 요청이 들어왔을 때 레디스에서 Refresh Token을 조회하려면 유저의 email 정보가 필요하다.(근데 없다..)</li>
</ul>
<br>

<h3 id="🟡-첫-번째-해결">🟡 첫 번째 해결</h3>
<p>결국 토큰 재발급 요청시 Access Token도 함께 헤더에 담아 오기로 했다.
Access Token에 담겨 있는 유저의 email을 가지고 레디스에서 Refresh Token을 조회하고, Refresh Token 검증이 끝나면 유저에게 토큰을 재발급해준다.</p>
<p>이렇게 문제가 해결!!!
된 줄 알았으나, 재발급 요청에서 계속 에러가 발생했다.
Access Token에서 유저정보를 추출하기 위해 토큰을 분해하는 과정👇 에서 ExpiredJwtException 에러가 발생하는 것이었다.
<img src="https://velog.velcdn.com/images/snoopy_21/post/74a5578f-43f0-4c83-b773-7e7186c6d780/image.png" alt=""></p>
<br>


<h3 id="🟢-최종-해결">🟢 최종 해결</h3>
<p>생각해보니 토큰이 만료되었고, 만료된 토큰에서 유저정보를 추출하려 하니 에러가 발생하는 건 당연한 것이었다. 
하지만 재발급 요청 시에는 만료된 토큰에서 유저정보를 추출해야 하는 상황이므로 무언가 처리를 해줘야 했다.</p>
<p>ExpiredJwtException예외 클래스를 들어가 보니👇 다음과 같이 예외 객체에 토큰의 Claims가 속성으로 있는 것을 확인할 수 있었다.
<img src="https://velog.velcdn.com/images/snoopy_21/post/74b8886c-5066-4f0e-a0d2-afba36fd3b57/image.png" alt=""></p>
<p>여기서 힌트를 얻어 아래와 같이 try-catch문으로 토큰만료예외를 잡아서 예외 객체의 Claims를 추출해 반환하도록 했다. 
<img src="https://velog.velcdn.com/images/snoopy_21/post/aeccc545-9c2f-416f-b6e1-8776ab0103bc/image.png" alt=""></p>
<p>이렇게 처리를 해주면 만료된 토큰에서도 유저의 email을 추출할 수 있었고, 성공적으로 유저에게 토큰을 재발급할 수 있었다.
<br>
<br></p>
<hr>
<br>
<br>

<p>자바공부를 할 때 예외처리에 대한 부분을 공부하긴 했지만 실제로 예외 객체에 어떤  속성이 있는지 알지 못했었다.
그래서 처음에 토큰 만료 예외처리가 된다는 사실을 발견했을 때 어떻게 해결해야할 지 몰라 당황한 게 사실이었다.</p>
<p>하지만 구글링과 질문과 고민을 통해 예외 객체를 이용하면 된다는 것을 알았고, 성공적으로 Redis로 저장소를 이전할 수 있어서 뿌듯했다.</p>
<p>모를 땐 자바 클래스들을 다 들어가봐야한다....그 곳에 꽤 답이 있나니..🥳</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JWT이용한 인증시 중복로그인 방지 로직 구현 ]]></title>
            <link>https://velog.io/@snoopy_21/JWT%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9D%B8%EC%A6%9D%EC%8B%9C-%EC%A4%91%EB%B3%B5%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%B0%A9%EC%A7%80-%EB%A1%9C%EC%A7%81-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@snoopy_21/JWT%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9D%B8%EC%A6%9D%EC%8B%9C-%EC%A4%91%EB%B3%B5%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%B0%A9%EC%A7%80-%EB%A1%9C%EC%A7%81-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Sun, 26 Feb 2023 16:10:47 GMT</pubDate>
            <description><![CDATA[<p>당근플래너 서비스를 배포하고 발견한 문제가 중복로그인 문제였다.</p>
<h4 id="🔴-문제-상황">🔴 문제 상황</h4>
<ul>
<li>유저가 브라우저에서 로그인을 한다.</li>
<li>시간이 지난 후 새로 연 브라우저에서 또 로그인을 한다.</li>
<li>다시 시간이 지나고 이전에 로그인을 했던 브라우저에서 요청을 보낸다.</li>
<li>이때 시간이 지나 AccessToken이 만료되었으므로 Refresh Token으로 토큰 재발행 요청을 보낸다.</li>
<li>Redis에는 두 번째 로그인했을 때 발급된 새로운 Refresh Token이 저장되어 있으므로 유저가 보낸 Refresh Token과는 일치하지 않게 된다.</li>
</ul>
<br>

<p>문제는 중복로그인이 된 상태로 기능을 이용하는 것도 문제였지만,
이렇게 Refresh Token이 일치하지 않았을 때 유저 입장에서 서비스가 먹통이 된 상태를 마주하게 된다는 것이었다.</p>
<br>

<p>프론트엔드 분과 협의하여 예외처리를 보완해 해당 유저를 로그아웃시키고, 먼저 발급된 Access Token을 무효화 시키는 로직을 추가로 구현하여 중복로그인을 방지했다.
<br></p>
<h4 id="🟡--jwt인증의-단점">🟡  JWT인증의 단점</h4>
<p>세션인증방식을 사용할 경우 서버에서 세션ID를 관리하므로 해당 세션ID를 삭제하기만 하면 중복로그인을 방지할 수 있지만 JWT기반 인증을 사용할 경우, Access Token을 서버에서 관리하지 않기 때문에 이미 발급된 토큰을 제어할 수가 없었다. 
원래도 JWT의 단점으로 많이 언급되는 것이긴 했다.</p>
<br>


<p>어찌되었든, JWT를 이용할 경우 완벽하게 중복로그인을 처리해줄 수 있는 방법은 없다는 의견이 많았고,
최대한 방지할 수 있게 로직을 구성할 수 밖에 없다고 생각했다.</p>
<br>

<h4 id="🟢-해결-방안">🟢 해결 방안</h4>
<p>현재 설계된 인증 방식에서 추가할 수 있는 로직으로 다음과 같은 방법을 생각했다.<img src="https://velog.velcdn.com/images/snoopy_21/post/30123fb5-1ffc-419a-9a40-b70e33438bfa/image.png" alt=""></p>
<h4 id="1-로그인-시-refresh-token만-레디스에-저장하던-로직을-access-token도-함께-저장">1. 로그인 시, Refresh Token만 레디스에 저장하던 로직을 Access Token도 함께 저장</h4>
<p>이때, 레디스에는 하나의 key값에 두 개의 value가 저장될 수 없으므로 원래 key값으로 사용되던 email뒤에   &quot;AT&quot;라는 문자열을 붙여서 Access Token을 저장할 key로 사용했다.<br>
<br></p>
<h4 id="2-로그인-시-해당-유저에게-발급된-access-token이-여전히-레디스에-저장되어-있는지-조회하는-로직-추가">2. 로그인 시, 해당 유저에게 발급된 Access Token이 여전히 레디스에 저장되어 있는지 조회하는 로직 추가</h4>
<p>Access Token이 만료되었을 경우 레디스에서는 자동 삭제가 되었을 것이다.
하지만 만료되지 않은 토큰일 경우, 레디스에 저장되어 있을 것이고 레디스를 조회해 저장된 토큰이 있을 경우
토큰의 남은 만료시간을 다시 계산해 레디스에 블랙리스트로 새로 저장되도록 했다.<br></p>
<p> 블랙리스트에는 key값으로 Access Token값을, value로 &quot;useless&quot;라는 문자열을 넣어주었다.
유저가 요청을 보냈을 때 블랙리스트로 등록된 토큰인지를 조회해야 하는데, 이 과정은 스프링컨테이너로 넘어오기 전인
security 필터단에서 전역적으로 수행되는 것이 좋다고 판단했다. 필터에서 토큰을 분해하지 않고 토큰 값 자체로 조회하는 것이 더 빠르다 생각해서 key에 토큰값 자체를 넣어주었다.</p>
<p> 레디스의 단점 중 하나인 조회할 수 있는 인자가 key밖에 없다는 점을 실감했다...
<br></p>
<h4 id="3-레디스-블랙리스트에서-access-token을-조회하는-로직-추가authfilter에-추가">3. 레디스 블랙리스트에서 Access Token을 조회하는 로직 추가(AuthFilter에 추가)</h4>
<p>유저가 토큰 인증이 필요한 요청을 보낼 때마다 해당 토큰이 블랙리스트에 등록된 토큰인지 조회하는 로직을 추가했다.
사실 당근플래너 서비스는 개인화된 서비스이기 때문에 모든 요청이 토큰인증이 필요하다.
그래서 스프링컨테이너로 들어오기 전 필터단에서 전역적으로 수행될 필요가 있었고, AuthFilter에 로직을 추가해주었다.
블랙리스트에 등록된 토큰일 경우, &quot;블랙리스트에 등록된 Access Token입니다.&quot;이라는 메세지와 함께 &quot;UNAUTHORIZED&quot; status를 반환하도록 했다. 이 경우, 발생한 예외는 EntryPoint에서 핸들링된다.</p>
<br>
<br>

<hr>
<p><br><br></p>
<p>사실 이 중복로그인 문제는 UT가 종료될 때쯤 제대로 원인파악이 되었었다.
당시에는 우선 급하게 처리를 하느라 프론트단에서 임시로 중복로그인을 막는 처리를 해두었었다. 그렇게 프로젝트가 종료되었고, 백엔드에서 추가한 로직은 UT가 종료된 후에 추가된 로직이어서 조금 아쉬운 점이 있다.</p>
<p>하지만 구글링해서 나온 방법을 그대로 적용한 것이 아닌 우리 서비스에서 할 수 있는 로직을 구성했다는 점이 재미있었고, 어떻게든 문제를 해결할 수 있다는 자신감을 얻을 수 있었다.</p>
<p>우리 당근플래너서비스는 팀원들 모두 계속해서 애정을 가지고 있는 서비스라,  언젠가 다들 할 수 있는 상황이 되었을 때 서비스를 더 디벨롭시키기로 했으므로(디자이너님까지 동의!) 조만간 테스트 해볼 수 있을 것이란 희망을..!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[당근플래너 프로젝트 Redis 도입기]]></title>
            <link>https://velog.io/@snoopy_21/%EB%8B%B9%EA%B7%BC%ED%94%8C%EB%9E%98%EB%84%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Redis-%EB%8F%84%EC%9E%85%EA%B8%B0</link>
            <guid>https://velog.io/@snoopy_21/%EB%8B%B9%EA%B7%BC%ED%94%8C%EB%9E%98%EB%84%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Redis-%EB%8F%84%EC%9E%85%EA%B8%B0</guid>
            <pubDate>Sun, 26 Feb 2023 14:43:28 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/snoopy_21/post/11abea38-51b9-45d5-a72b-007b595ed901/image.jpg" alt=""></p>
<p>실전프로젝트를 진행하며 유저의 Refresh Token을 기존 DB에 저장하다가 중간에 Redis로 옮기게 되었고,
Redis를 도입하게 된 과정을 당근플래너 팀블로그에 간단히 작성해두었다.</p>
<p>사실 이때, Redis에 key-value 형태로 저장해야해서 비즈니스 로직을 뜯어 고쳤어야 했는데
(생각보다 이게 고생이었다..)
그 과정은 또 새로운 글로 작성할 예정!
<br>
<strong>Redis 도입기 글 링크👇</strong>
<a href="https://danggeunplanner.tistory.com/entry/BE-%EB%8B%B9%EA%B7%BC%ED%94%8C%EB%9E%98%EB%84%88%EC%97%90-%EB%A0%88%EB%94%94%EC%8A%A4-%EB%BF%8C%EB%A6%AC%EA%B8%B0%EB%8F%84%EC%9E%85%EA%B8%B0">https://danggeunplanner.tistory.com/entry/BE-%EB%8B%B9%EA%B7%BC%ED%94%8C%EB%9E%98%EB%84%88%EC%97%90-%EB%A0%88%EB%94%94%EC%8A%A4-%EB%BF%8C%EB%A6%AC%EA%B8%B0%EB%8F%84%EC%9E%85%EA%B8%B0</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Process와 Thread]]></title>
            <link>https://velog.io/@snoopy_21/Process%EC%99%80-Thread</link>
            <guid>https://velog.io/@snoopy_21/Process%EC%99%80-Thread</guid>
            <pubDate>Sun, 26 Feb 2023 14:31:09 GMT</pubDate>
            <description><![CDATA[<h3 id="🟠-process와-thread">🟠 Process와 Thread</h3>
<p>컴퓨터 시스템에서 프로세스와 스레드는 동시에 실행될 수 있는 작업 단위
<br></p>
<h3 id="🟠-프로세스">🟠 프로세스</h3>
<p>메모리에 적재되어 실행되고 있는 프로그램
운영체제는 각 프로세스에 별도의 메모리 공간을 할당
각 프로세스들은 독립적으로 실행됨
프로세스는 운영체제로부터 자원(CPU, 메모리 등) 할당받아 실행되며 종료될 때까지 운영체제에게 실행 중임을 알린다
<br></p>
<h3 id="🟠-스레드">🟠 스레드</h3>
<p>프로세스 내에서 실행되는 작업 단위
하나의 프로세스 내에서 메모리 공간을 공유
따라서 한 프로세스 내에서 여러 개의 스레드가 동시에 실행될 수 있으며 각 스레드는 서로 다른 실행경로를 가짐
싱글스레드, 멀티스레드가 있음
<br></p>
<h3 id="🟠-차이점">🟠 차이점</h3>
<ul>
<li>메모리 공간</li>
<li>자원 할당</li>
<li>동작 방식 (프로세스 간 메시지 통해 통신 vs 스레드간 직접 통신)</li>
</ul>
<p><br><br></p>
<hr>
<br>

<h4 id="⏱️-요약">⏱️ 요약</h4>
<p>프로세스와 스레드는 모두 컴퓨터 시스템에서 동시에 실행될 수 있는 작업 단위입니다. 프로세스는 각각 독립적인 메모리 공간을 할당받으며, 스레드는 하나의 프로세스 내에서 메모리 공간을 공유합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Parameter와 Argument]]></title>
            <link>https://velog.io/@snoopy_21/Parameter%EC%99%80-Argument</link>
            <guid>https://velog.io/@snoopy_21/Parameter%EC%99%80-Argument</guid>
            <pubDate>Sun, 26 Feb 2023 14:28:56 GMT</pubDate>
            <description><![CDATA[<h3 id="🟠-parameter">🟠 <strong>Parameter</strong></h3>
<p>함수를 정의할 때 선언한 변수(형식 매개변수)
함수를 실행하는데 필요한 데이터를 전달받는 변수
함수의 괄호 ( ) 안에 선언되며 쉼표(,) 로 구분하여 여러 개를 선언할 수 있다
각 Parameter는 자신의 데이터 타입을 가지며, 함수가 실행될 때 반드시 전달받아야 한다</p>
<pre><code class="language-python">def greet(name, age):
    print(&quot;안녕하세요. 저는 {}입니다. {}살입니다.&quot;.format(name, age))
</code></pre>
<p><br><br></p>
<h3 id="🟠-argument">🟠 <strong>Argument</strong></h3>
<p>함수를 호출할 때 전달하는 값(실질 매개변수)
함수가 실행될 때 Parameter에 전달되는 실제 데이터
함수 호출 시, Parameter와 동일한 수와 타입의 Argument를 전달해야한다
호출하는 함수명 뒤에 괄호를 열고, Parameter의 자리에 전달할 값들을 쉼표로 구분하여 작성</p>
<pre><code class="language-python">greet(&quot;홍길동&quot;, 30)</code></pre>
<br>
위 코드에서 "홍길동"은 'name' Parameter에 전달되고, 30은 'age' Parameter에 전달된다
<br><br><br>

<hr>
<br>

<h4 id="⏱️요약">⏱️요약</h4>
<p>Parameter는 함수를 선언할 때 사용하는 매개변수이고 Argument는 함수를 호출할 때 전달하는 실제 매개변수입니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[List, Set, Map, HashMap]]></title>
            <link>https://velog.io/@snoopy_21/List-Set-Map-HashMap</link>
            <guid>https://velog.io/@snoopy_21/List-Set-Map-HashMap</guid>
            <pubDate>Sun, 26 Feb 2023 14:26:02 GMT</pubDate>
            <description><![CDATA[<h3 id="🟠-list">🟠 <strong>List</strong></h3>
<p>순서 O
중복 O
장점 : 가변적인 배열
단점 : 원하는 데이터의 위치가 뒤에 존재할 경우 성능이 떨어짐
방식 : equals( )를 이용한 데이터 검색
<br></p>
<h3 id="🟠-set">🟠 <strong>Set</strong></h3>
<p>순서 X
중복 X
장점 : 빠른 속도
단점 : 단순 집합의 개념으로 정렬하려면 별도의 처리 필요
<br></p>
<h3 id="🟠-map">🟠 <strong>Map</strong></h3>
<p>Key, Value 형태로 저장
Key는 중복 X
Value는 중복 O
장점 : 빠른 속도
단점 : Key의 검색 속도가 성능을 좌우함
<br></p>
<h4 id="🔸hashmap">🔸<strong>HashMap</strong></h4>
<p>Map 인터페이스를 Implements한 클래스
중복 X
Key 또는  Value값으로써 null을 허용
<br><br></p>
<hr>
<br>

<h4 id="⏱️-요약">⏱️ <strong>요약</strong></h4>
<p> List는 데이터에 순서가 있으며 중복을 허용한다.</p>
<p>Set은 데이터에 순서가 없고, 중복을 허용하지 않는 집합의 특징을 가진다.</p>
<p>Map은 데이터의 순서를 보장하지 않고 Key값은 중복을 허용하지만 Value값은 중복을 허용하지 않는다.</p>
<p>HashMap은 Hash Table을 이용해 key-value 관계를 유지하고, Map과의 차이는 red-black tree 알고리즘을 이용하는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MSA(Microservice Architecture)]]></title>
            <link>https://velog.io/@snoopy_21/MSAMicroservice-Architecture</link>
            <guid>https://velog.io/@snoopy_21/MSAMicroservice-Architecture</guid>
            <pubDate>Sun, 26 Feb 2023 14:17:53 GMT</pubDate>
            <description><![CDATA[<h3 id="🟠-개념">🟠 <strong>개념</strong></h3>
<p>1개의 시스템을 독립적으로 배포 가능한 각각의 서비스로 분할하는 것
분할된 각각의 서비스는 API를 통해 데이터를 주고 받으며 하나의 큰 서비스를 구성</p>
<br>

<h3 id="🟠-배경">🟠 <strong>배경</strong></h3>
<p>모든 시스템의 구성요소가 한 프로젝트에 통합되어 있는 모놀리식아키텍쳐(Monolithic Architecture)의 한계점을 극복하고자 등장</p>
<br>

<h3 id="🟠-장점">🟠 <strong>장점</strong></h3>
<p>일부 서비스에 장애가 발생해도 전체 서비스에 영향을 끼치지 않음
각각의 서비스들이 서로 다른 언어와 프레임워크로 구성될 수 있음
서비스 확장 용이
<br></p>
<h3 id="🟠-단점">🟠 <strong>단점</strong></h3>
<p>서비스가 분리되어 테스트나 트랜잭션 처리 등이 어려움
서비스 간  API 통신에 대한 비용 발생
서비스 간 호출이 연속적이어서 디버깅 및 에러 트레이싱이 어려움
서비스 복잡도 증가
데이터 정합성 관리 어려움
<br>
<br></p>
<hr>
<br>

<p>🐌 참고자료</p>
<p><a href="https://velog.io/@tedigom/MSA-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-1-MSA%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90-3sk28yrv0e">MSA 제대로 이해하기 -(1) MSA의 기본 개념</a></p>
<p><a href="https://velog.io/@whitebear/MSA">MSA로 백엔드 개발을 한다는 것</a></p>
<p><a href="https://dev-coco.tistory.com/164">신입 개발자 기술면접 질문 정리 - 프로그래밍 공통/기타</a></p>
<p><a href="https://youtu.be/dSGnJWHuxtQ">Micro Service Architecture 마이크로서비스 아키텍처 간단하게 그리고 도입시 고려사항까지 !! (부제: MSA 과연 득인가 독인가)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[의존성 주입(DI)]]></title>
            <link>https://velog.io/@snoopy_21/%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85DI</link>
            <guid>https://velog.io/@snoopy_21/%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85DI</guid>
            <pubDate>Sun, 26 Feb 2023 14:03:46 GMT</pubDate>
            <description><![CDATA[<br>

<h3 id="🟠-개념">🟠 개념</h3>
<p>객체가 필요할 때 new생성자를 사용하여 새로운 객체를 만드는 것이 아닌 외부로부터 이미 생성되어 있는 객체를 주입받는 것. </p>
<p>각 클래스간의 의존관계를 빈 설정(Bean Definition) 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것.
<br></p>
<h3 id="🟠-장점">🟠 장점</h3>
<p>객체 간의 결합도를 낮추면서 유연한 코드를 작성할 수 있다.</p>
<p>객체 간의 의존성을 줄일 수 있다.</p>
<p>코드의 재사용성을 높일 수 있다.</p>
<p>테스트가 용이하다.
<br></p>
<h3 id="🟠-방법">🟠 방법</h3>
<p><strong>1. 생성자 주입</strong>
    <img src="https://velog.velcdn.com/images/snoopy_21/post/671abbf3-4d76-48e6-b4f5-4162abe65581/image.%25EC%2583%259D%25EC%2584%25B1%25EC%259E%2590%25EC%25A3%25BC%25EC%259E%2585%2520%25EC%25BA%25A1%25EC%25B3%2590" alt=""></p>
<p>클래스의 생성자가 하나이고, 그 생성자로 주입받을 객체가 Bean으로 등록되어 있다면  @Autowired를 생략할 수 있다.
<br></p>
<p><strong>2. Field 주입</strong>
<img src="https://velog.velcdn.com/images/snoopy_21/post/c24636e3-b023-445a-a146-a82d1c3d2e88/image.%25ED%2595%2584%25EB%2593%259C%25EC%25A3%25BC%25EC%259E%2585%25EC%25BA%25A1%25EC%25B3%2590" alt=""></p>
<p>필드에 @Autowired만 붙여주면 자동으로 의존성 주입이 된다. 
사용법이 간단해 가장 쉽게 접할 수 있고, 코드가 간결하다.</p>
<p> <strong>단점</strong> 
외부에서 변경이 힘들다
프레임워크에 의존적이고 객체지향적으로 좋지 않은 코드가 된다
<br></p>
<p><strong>3. Setter 주입</strong></p>
<p> <img src="https://velog.velcdn.com/images/snoopy_21/post/25cf24da-477e-41bc-8232-ef935b102668/image.%25EC%2584%25B8%25ED%2584%25B0%25EC%25A3%25BC%25EC%259E%2585%25EC%25BA%25A1%25EC%25B3%2590" alt=""></p>
<p>Setter 메서드에 @Autowired 를 붙이는 방법.</p>
<p><strong>단점</strong>
set메서드를 public으로 열어두어야 하기 때문에 변경에 취약해진다
<br>   </p>
<h3 id="🔸-생성자-주입이-권장되는-이유">🔸 생성자 주입이 권장되는 이유</h3>
<p><strong>1. 순환 참조 방지</strong></p>
<p>개발을 하다 보면 여러 컴포넌트들 간에 의존성이 생기고, 이때 A클래스가 B클래스를 참조하고, B클래스는 A클래스를 참조하는 순환참조가 생길 수있다.<br>이때, 필드 주입과 Setter주입의 경우 bean이 생성된 후에 참조를 하기 때문에 어플리케이션이 아무런 오류나 경고 없이 구동된다 → 실제 코드가 호출될 때까지 문제를 알 수 없다.<br>하지만 생성자를 통해 주입하고 실행하면 BeanCurrentlyInCreationException 예외가 발생되고 문제를 미리 알 수 있다.<br>순환참조 문제 뿐 아니라 의존 관계 내용을 외부로 노출 시킴으로써 어플리케이션 실행 시점에 오류를 체크할 수 있다.</p>
<br>  


<p><strong>2. 불변성</strong>
생성자로 의존성을 주입할 경우 final 선언을 할 수 있고, 따라서 런타임에서 의존성을 주입받는 객체가 변할 일이 없다.
Setter주입이나 일반 메서드 주입을 하게 되면 수정의 가능성을 열어두게 되고, 이는 OOP의 5가지 원칙 중 OCP(Open-Closed Principal)를 위반하게 된다.
생성자 주입을 통해 변경의 가능성을 배제하고  불변성을 보장하는 것이 권장된다.
그리고 필드 주입 방식의 경우 null이 생성될 가능성이 있는데, final로 선언한 생성자 주입 방식은 null이 생길 가능성이 없다.
<br>  </p>
<p><strong>3. 테스트 용이</strong>
생성자 주입을 하게 되면 테스트코드를 더 편리하게 작성할 수 있다.
DI의 핵심은 관리되는 클래스가 DI컨테이너에 의존성이 없어야 한다는 것이다. 즉, 독립적으로 인스턴스화가 가능한 POJO(Plain Old Java Object)여야 한다.</p>
<p>⇒ 이와 같은 이유로 생성자 주입 방식이 권장된다.
<br>
<br></p>
<hr>
<br>
🐌 참고자료

<p><a href="https://dev-coco.tistory.com/70">[Spring] 의존성 주입 3가지 방법 - (생성자 주입, Field 주입, Setter 주입)</a></p>
<p><a href="https://mangkyu.tistory.com/150">[Spring] 의존성 주입(Dependency Injection, DI)이란? 및 Spring이 의존성 주입을 지원하는 이유</a></p>
<p><br><br>⏱️요약</p>
<p>DI는 객체가 필요할 때 new 생성자를 통해 새로운 객체를 만드는 것이 아니라,</p>
<p>이미 만들어져서 스프링컨테이너에 빈으로 보관되어 있는 객체를 필요할 때 주입받아 사용하는 것을 말합니다. </p>
<p>객체간 의존도와 결합도를 낮추어 유연한 코드를 작성할 수 있는 장점이 있습니다.</p>
<p>의존성을 주입하는 방법은 세 가지, 필드주입, 세터주입, 생성자 주입이 있는데 이 중 생성자 주입이 가장 권장되는 방법입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[객체 지향 프로그래밍(OOP)]]></title>
            <link>https://velog.io/@snoopy_21/%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8DOOP-cl4ce3ja</link>
            <guid>https://velog.io/@snoopy_21/%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8DOOP-cl4ce3ja</guid>
            <pubDate>Sun, 26 Feb 2023 13:48:42 GMT</pubDate>
            <description><![CDATA[<h3 id="🟠-객체-지향-프로그래밍object-oriented-programming">🟠 객체 지향 프로그래밍(Object-Oriented Programming)</h3>
<p>컴퓨터 프로그래밍의 패러다임 중 하나이다.
컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 독립된 단위인 &#39;객체&#39;들의 모임으로 파악한다.
각 객체는 메시지를 주고 받고 데이터를 처리할 수 있다. <br><br></p>
<h3 id="🟠-특징">🟠 특징</h3>
<p>SW 개발과 보수를 간편하게 한다.
대규모 SW개발에 많이 사용된다.
프로그래밍 학습이 더 쉬워진다.
코드 분석을 보다 직관적으로 할 수 있다.<br><br></p>
<h3 id="🟠-단점">🟠 단점</h3>
<p>설계 및 개발 속도가 느리다.
지나친 프로그램의 객체화 경향은 실제 세계의 모습을 그대로 반영하지 못한다.<br><br></p>
<h3 id="🟠-구성요소">🟠 구성요소</h3>
<ul>
<li><strong>클래스</strong></li>
</ul>
<p>같은 종류(또는 문제 해결을 위한)의 집단에 속하는 속성(attribute)과 행위(behavior)를 정의한 것.
OOP의 기본적인 사용자 정의 데이터형(user defined data type).
한 클래스는 다른 클래스 또는 외부 요소와 독립적으로 디자인된다.</p>
<ul>
<li><strong>객체</strong></li>
</ul>
<p>클래스의 인스턴스로 실제 메모리상에 할당된다.
객체는 자신의 고유한 속성(attribute)을 가지며 클래스에서 정의한 행위(behavior)를 수행한다.
객체는 클래스에 정의된 행위에 대한 정의를 공유함으로써 메모리를 경제적으로 사용한다.</p>
<ul>
<li><strong>메서드, 메시지</strong><br>클래스로부터 생성된 객체를 사용하는 방법.
객체에 명령을 내리는 메시지.
한 객체의 서브루틴(subroutine)형태로 객체의 속성을 조작하는데 메서드 사용메시지를 통해 객체간의 통신이 이루어진다.<br><br></li>
</ul>
<h3 id="🟠-oop-4가지-특징">🟠 OOP 4가지 특징</h3>
<ul>
<li><p><strong>추상화</strong></p>
<p>  불필요한 정보는 숨기고 중요한 정보만을 표현함으로써 프로그램을 간단히 만든다.
  추상 자료형 : 추상화를 통해 정의된 자료형.
  추상 자료형은 자료형의 자료 표현과 자료형의 연산을 캡슐화한 것으로 접근 제어를 통해 자료형의 정보를 숨길 수 있다.
  OOP에서 일반적으로 추상 자료형을 클래스, 추상 자료형의 인스턴스를 객체, 추상 자료형에서 정의된 연산을 메서드, 메서드의 호출을 생성자라 한다.</p>
</li>
<li><p><strong>상속</strong></p>
<p>  새로운 클래스가 기존 클래스의 자료와 연산을 이용할 수 있게 하는 기능.
  상속을 통해 기존 클래스를 상속받은 하위 클래스를 이용해 프로그램의 요구에 맞추어 클래스를 수정할 수 있다.
  클래스 간의 종속 관계를 형성함으로써 객체를 조직화할 수 있다.</p>
</li>
<li><p><strong>다형성</strong>
어떤 한 요소에 여러 개념을 넣어 놓는 것.
일반적으로 <em>오버라이딩(overriding)</em> 이나 <em>오버로딩(overloading)</em>을 의미한다.</p>
</li>
<li><p>오버라이딩 : 같은 이름의 메서드가 여러 클래스에서 다른 기능을 하는 것*</p>
</li>
<li><p>오버로딩 : 같은 이름의 메서드가 인자의 개수나 자료형에 따라 다른 기능을 하는 것*
다형 개념을 통해 프로그램 안의 객체 간 관계를 조직적으로 나타낼 수 있다.</p>
</li>
</ul>
<ul>
<li><strong>캡슐화</strong>
<br><br></li>
</ul>
<h3 id="🟠-oop의-5대-원칙---solid">🟠 OOP의 5대 원칙 - SOLID</h3>
<p>SOLID 원칙을 적용하면 시스템에 새로운 요구사항이나 변경이 발생했을 때, 유연하게 대처하고 기존 코드의 변경을 최소화 할 수 있다.
SOLID의 개념들은 자바의 객체 지향 파트에서 학습하는 추상화, 상속, 인터페이스, 다형성 등의 개념을 재정립한 것과 같다.
5가지 원칙들은 서로 독립된 개별적 개념이 아니라 연관되어 있다.<br></p>
<ol>
<li><p><strong>단일 책임 원칙(SRP, Single Responsibility Principle)</strong></p>
<p> 하나의 클래스는 단 하나의 책임(기능)만 가져야 한다.
 하나의 클래스가 여러 책임을 가지게 되면 유지보수성이 떨어지고 코드가 복잡해지며, 확장성이 떨어진다.
 이러한 문제가 발생하지 않도록 단일 책임 원칙을 따르도록 설계하는 것이 좋다.
 책임의 범위는 프로그램과 개발자에 따라 기준이 다르므로 적절한 범위를 설정해야 한다.<br><br></p>
</li>
</ol>
<ol start="2">
<li><p><strong>개방 폐쇄 원칙(OCP, Open Closed Principle)</strong></p>
<p> 새롭게 추가된 클래스는 상위 인터페이스의 추상메서드만 구현하면 되고(확장에 열려있음)
 유저 입장에서는 어떤 변경이 일어나더라도 기존의 기능들이 수행되어야 한다(변경에 닫혀있음).
 다시 말해, 코드를 수정하지 않고 기능을 추가할 수 있도록 설계해야 한다는 원칙이다. <br><br></p>
<p> &#39;운전면허&#39;라는 인터페이스가 &#39;시동을 건다&#39;, &#39;액셀을 밟는다&#39; 등의 추상 메서드를 가지고 있다면
 어떤 자동차 클래스가 추가되더라도 해당 메서드를 구현을 통해 차를 운전할 수 있는 것과 같다.</p>
</li>
</ol>
<pre><code>→ 차 종류의 확장에는 열려있되 어떤 차로 변경되더라도 이용에 문제가 없는 것은 변경에 닫혀있다는 것</code></pre><br>

<ol start="3">
<li><p><strong>리스코프 치환 원칙(LSP, Liskov Substitution Principle)</strong></p>
<p> 하위에 존재하는 클래스는 상위 클래스의 역할을 할 수 있어야 한다.</p>
</li>
</ol>
<br>   

<ol start="4">
<li><p><strong>인터페이스 분리 원칙(ISP, Interface Segregation Principle)</strong></p>
<p> 큰 덩어리의 인터페이스들을 구체적이고 작은 단위들로 분리시켜서, 하위 클래스가 꼭 필요한 메서드만 사용할 수 있어야 한다.
 분리 원칙을 통해 시스템의 의존성을 낮춘다.</p>
 <br>

<p> <em>단일책임원칙(SRP)과 인터페이스 분리 원칙(ISP)은 같은 문제를 다른 방향으로 해결한 것이다.
 프로젝트 환경에 맞게 적절하게 사용해야 한다.</em></p>
</li>
</ol>
<br>

<ol start="5">
<li><p><strong>의존 역전 원칙(Dependency Inversion Principle)</strong><br></p>
<p>상위 계층이 하위 계층에 의존하는 전통적인 의존 관계를 반전 시킨다 → 상위 계층이 하위 계층의 구현으로부터 독립되게 할 수 있다.</p>
<ul>
<li>상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 추상화에 의존해야 한다.</li>
<li>추상화는 세부 사항에 의존해서는 안된다. 세부사항이 추상화에 의존해야 한다.
<br><br></li>
</ul>
</li>
</ol>
<hr>
<br>
🐌 참고

<p><a href="https://brunch.co.kr/@springboot/30">웹프로그래밍 스터디 - 3.디자인패턴(1)-SOLID</a></p>
<p><a href="https://brunch.co.kr/@eddwardpark/37">피그마로 이해하는 SOLID 객체지향 설계 원칙</a></p>
<p><a href="https://inpa.tistory.com/entry/OOP-%F0%9F%92%A0-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84%EC%9D%98-5%EA%B0%80%EC%A7%80-%EC%9B%90%EC%B9%99-SOLID">[OOP] 💠 객체 지향 설계의 5가지 원칙 - S.O.L.I.D</a></p>
]]></description>
        </item>
    </channel>
</rss>