<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>rara.log</title>
        <link>https://velog.io/</link>
        <description>느리더라도 꾸준하게</description>
        <lastBuildDate>Fri, 03 Mar 2023 04:53:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>rara.log</title>
            <url>https://velog.velcdn.com/images/rara_kim/profile/5478b083-989a-45a5-89a5-aed35ae2621d/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. rara.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/rara_kim" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[기술면접 스터디] 병렬 프로그래밍, Spring bean 라이프 사이클]]></title>
            <link>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-%EB%B3%91%EB%A0%AC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-Spring-bean-%EB%9D%BC%EC%9D%B4%ED%94%84-%EC%82%AC%EC%9D%B4%ED%81%B4</link>
            <guid>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-%EB%B3%91%EB%A0%AC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-Spring-bean-%EB%9D%BC%EC%9D%B4%ED%94%84-%EC%82%AC%EC%9D%B4%ED%81%B4</guid>
            <pubDate>Fri, 03 Mar 2023 04:53:32 GMT</pubDate>
            <description><![CDATA[<h2 id="병렬-프로그래밍에-대해-설명해주세요">병렬 프로그래밍에 대해 설명해주세요.</h2>
<p>병렬처리 혹 다른 표현으로 멀티프로세스 프로그래밍이란 쉽게 이야기하여 하나의 프로그램을 하나의 프로세스가 아닌 여러개의 프로세스를 이용하여 동시에 처리하게 만드는 프로그래밍 기법을 말한다.
이렇게 개발하는 이유는 여러 개의 프로세스를 동시에 활용하여 성능을 향상시키기 위함이다.</p>
<p>기본적으로 하나의 프로세스에서 N개의 쓰레드를 실행하는 멀티쓰레드 와는 다른 개념이다.
멀티 쓰레드 프로그래밍은 IO 관련 처리에서 비약적으로 성능을 향상시켜주는 데 비하여 멀티 프로세스 프로그래밍, 병렬 처리는 CPU 관련 처리에서 비약적으로 성능을 향상시킬 수 있다.
<br></p>
<hr>
<br>

<h2 id="spring-bean-container-생성부터-스프링-종료까지의-사이클에-대해-설명해주세요postconstruct-predestroy">Spring bean container 생성부터 스프링 종료까지의 사이클에 대해 설명해주세요.(@PostConstruct, @PreDestroy)</h2>
<p>Spring bean은 객체 생성 및 DI 주입이 끝난 후 부터 사용할 수 있다.
싱글톤 빈의 경우, 아래와 같은 Lifecycle을 가진다.</p>
<blockquote>
<p>스프링 컨테이너 생성 -&gt; 빈 생성 -&gt; 의존관계 주입 -&gt; 초기화 콜백 -&gt; 사용 -&gt; 소멸전 콜백 -&gt; 스프링 종료
<br></p>
</blockquote>
<h3 id="스프링-빈-생명주기-콜백">스프링 빈 생명주기 콜백</h3>
<p>빈 생명주기 콜백은 스프링 빈이 생성된 후 의존관계 주입이 완료되거나 죽기 직전에 스프링 빈 안에 있는 메서드를 호출해주는 기능이다.
스프링 빈 생명주기 콜백 사용방법으로는 3가지 방법이 있는데, 마지막을 가장 추천한다.
(인터페이스 사용, 설정 정보 초기화 메소드, 종료 메소드 지정, @PostConstruct, @PreDestroy 사용)<br></p>
<h4 id="postconstruct">@PostConstruct</h4>
<p>Spring은 bean을 초기화 한 이후에 @PostConstruct을 한번만 호출한다. 
즉 @PostConstruct는 WAS 가 뜰 때 bean이 생성된 다음 딱 한번만 실행된다. 
따라서 @PostConstruct를 사용하여 기본 사용자라던가, 딱 한번만 등록하면 되는 key 값 등을 등록하여 사용할 수 있다.<br></p>
<h4 id="predestroy">@PreDestroy</h4>
<p>@PreDestroy 역시 Spring이 애플리케이션 컨텍스트에서 bean을 제거하기 직전에 단 한 번만 실행된다.
<br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술면접 스터디] 오버로딩/오버라이딩, RDB/NoSQL, static]]></title>
            <link>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9-RDBNoSQL-static</link>
            <guid>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9-RDBNoSQL-static</guid>
            <pubDate>Thu, 02 Mar 2023 03:05:58 GMT</pubDate>
            <description><![CDATA[<h2 id="오버로딩과-오버라이딩의-차이점은-무엇인가요">오버로딩과 오버라이딩의 차이점은 무엇인가요?</h2>
<p>오버로딩은 메소드의 이름은 같고 매개변수의 갯수나 타입이 다른 함수를 정의하는 것을 의미하며, 리턴값만 다르게 갖는 오버로딩은 불가능합니다.
오버라이딩은 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의 하는 것을 의미합니다.
상속받은 메소드를 그대로 사용할 수 있고 또는 자식 클래스에서 상황에 맞게 변경해서 사용할 수 있습니다.
이 경우 오버라이딩 하고자 하는 메소드명, 매개변수, 리턴값이 모두 같아야 합니다.
<br></p>
<hr>
<br>

<h2 id="rdb와-nosql은-무엇인가요">RDB와 NoSQL은 무엇인가요?</h2>
<p>RDB(Relational Database)는 관계형 데이터 모델에 기초를 둔 베이터베이스이다.
관계형 데이터 모델은 모든 데이터를 2차원 테이블로 표현하는데, 테이블은 이름을 가지고 있고 행과 열 그리고 거기에 대응하는 값을 가진다.
RDB는 서로 다른 테이블이 관계를 맺고 모여있는 집합체로 이해할 수 있다.</p>
<p>NoSQL은 비관계형 데이터베이스를 말한다.
관계형 데이터 모델을 지양하며 대량의 분산된 데이터를 저장하고 조회하는데 특화되었으며 스키마 없이 사용 가능하거나 느슨한 스키마를 제공하는 저장소를 말한다.</p>
<p>관계형 데이터베이스(RDB)는 사전에 엄격하게 정의된 DB schema를 요구하는 table 기반 데이터를 구조를 갖는데 반해, 비관계형 데이터베이스(NoSQL)는 table 형식이 아닌 비정형 데이터를 저장할 수 있도록 지원한다. RDB는 엄격한 스키마로 인해 데이터 중복이 없기 때문에 데이터 update가 많을 때 유리하고, NoSQL은 데이터 중복으로 인해 update 시 모든 컬렉션에서 수정이 필요하기 때문에 update가 적고 조회가 많을 때 유리하다.<br></p>
<h4 id="스키마schema란">스키마(Schema)란?</h4>
<p>스키마는 데이터베이스의 구조와 제약조건에 관한 전반적인 명세를 기술한 것이다. 
스키마는 데이터베이스를 구성하는 데이터 개체(Entity), 개체의 특성을 나타내는 속성(Attribute), 개체 사이에 존재하는 관계(Relationship) 및 데이터 조작 시 데이터 값들이 갖는 제약 조건 등에 관하여 기술한다.<br><br></p>
<hr>
<br>

<h2 id="static은-어떤-장담점이-있고-언제-사용하는지">static은 어떤 장담점이 있고 언제 사용하는지?</h2>
<p>정적 멤버는 클래스가 메모리에 올라갈 때 자동적으로 생성되기 때문에 객체 인스턴스를 따로 생성하지 않아도 호출하여 사용할 수 있다.</p>
<p>따라서 static은 유틸리티 함수를 만드는데 사용하거나 변하지 않는 자주 사용하는 값, 설정 정보등을 정적 메모리에 올려 객체 생성 비용을 줄일 수 있다.
그러나 메모리에 올라가는 것이기 때문에 남용하면 메모리를 낭비할 수 있다.
<br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술면접 스터디] 절차지향/객체지향/함수형 프로그래밍, 시간복잡도/공간복잡도, Spring/SpringBoot]]></title>
            <link>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%A0%88%EC%B0%A8%EC%A7%80%ED%96%A5%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%8B%9C%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84%EA%B3%B5%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84-SpringSpringBoot</link>
            <guid>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%A0%88%EC%B0%A8%EC%A7%80%ED%96%A5%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%8B%9C%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84%EA%B3%B5%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84-SpringSpringBoot</guid>
            <pubDate>Wed, 01 Mar 2023 04:50:35 GMT</pubDate>
            <description><![CDATA[<h2 id="절차지향-객체지향-함수형-프로그래밍이란-무엇이고-차이점은-무엇인가요">절차지향, 객체지향, 함수형 프로그래밍이란 무엇이고 차이점은 무엇인가요?</h2>
<p>절차지향 프로그래밍(Procedural Programming)은 일련의 처리 절차를 정해진 문법에 따라 순서대로 기술하는 프로그래밍 방법으로, 대표적인 언어로는 C언어가 있다.
절차지향 프로그래밍은 컴퓨터의 처리구조와 유사하기 때문에 실행속도가 빠르지만 유지보수가 어렵다는 단점이 있다.</p>
<p>객체지향 프로그래밍은 실세상의 물체를 객체로 표현하고 이들 사이의 관계, 상호 작용을 프로그램으로 나타내는 방법으로 객체를 추출하여 관계를 결정하고, 이들의 상호 작용에 필요한 메소드와 필드를 설계 및 구현한 프로그래밍 방법이다.
이미 잘 만들어진 클래스를 가져다 쓰면 되기 때문에 생산성이 높고 코드의 재사용성이 높다는 장점이 있지만, 여러 객체를 나누어서 설계해야하는 복잡성 때문에 아키텍처 설계시 시간이 많이 소요된다는 단점이 있다.</p>
<p>함수형 프로그래밍은 자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임의 하나로 대표적 언어로는 SQL, Scala 등이 존재한다.
함수형 프로그래밍은 과정보다 결과에 관심이 많고 무엇이 실행될 지를 강조한다.
또한 수학적 함수의 개념에 기반하며 If-Else와 같은 조건문 혹은 반복문을 지원하지 않는다는 특징이 있다.
<br></p>
<hr>
<br>

<h2 id="알고리즘에서-시간복잡도와-공간복잡도란-무엇인가-그리고-이것들은-왜-중요한가">알고리즘에서 시간복잡도와 공간복잡도란 무엇인가? 그리고 이것들은 왜 중요한가?</h2>
<p>시간 복잡도란 특정 알고리즘이 어떤 문제를 해결하는데 걸리는 시간을 의미한다.
같은 결과를 가져오는 코드라면 시간 복잡도가 작을수록 더 효율적인 알고리즘이라고 할 수 있다.</p>
<p>공간 복잡도란 작성한 프로그램이 얼마나 많은 메모리를 차지하는지 분석하는 방법이다.
하지만 최근 컴퓨터 성능의 발달로 인해 메모리의 여유 공간이 충분하기 때문에 공간 복잡도의 중요성이 예전에 비해서 많이 낮아졌다.</p>
<p>시간 복잡도의 경우 알고리즘을 잘못 구성하였을 경우 결과값이 나오지 않거나 현저하게 느린속도가 나오기에 최근에는 공간복잡도 보다는 시간 복잡도를 우선시하여 프로그램을 작성한다.
<br></p>
<hr>
<br>

<h2 id="spring과-spring-boot의-차이점은-무엇인가">Spring과 Spring Boot의 차이점은 무엇인가?</h2>
<p>Spring은 엔터프라이즈용 Java 애플리케이션 개발을 편하게 할 수 있게 해주는 오픈소스 경량급 애플리케이션 프레임워크이다. 동적인 웹 사이트를 개발하기 위한 여러가지 서비스를 제공하고 있다.</p>
<p>Spring은 기능이 많은만큼 환경설정이 복잡현 편이기 때문에 이것에 어려움을 느끼는 사용자들을 위해 나온 것이 SpringBoot 이다.
스프링 부트는 스프링을 사용하기 위한 설정의 많은 부분을 자동화 해주며, 스프링부트 starter 의존성만 추가해주면 바로 API를 정의하고 내장된 톰캣으로 웹 어플리케이션 서버를 실행할 수 있다.</p>
<h4 id="차이점">차이점</h4>
<ul>
<li>내장된 톰캣을 사용하기 때문에 별도로 설치하거나 버전을 관리해야하는 수고가 적다.</li>
<li>starter가 대부분의 의존성을 관리해주기 때문에 버전 관리의 어려움이 없다.<ul>
<li>starter:&nbsp;특정 목적을 달성하기 위한 의존성 그룹</li>
</ul>
</li>
<li>XML 설정할 필요가 없다.</li>
<li>.jar 파일을 이용해 자바 옵션만으로 손쉽게 배포가 가능하다.<br></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술면접 스터디] 웹 서버와 WAS의 차이, Stack/Queue  그리고 Array/Linked List]]></title>
            <link>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%9B%B9-%EC%84%9C%EB%B2%84%EC%99%80-WAS%EC%9D%98-%EC%B0%A8%EC%9D%B4-StackQueue-%EA%B7%B8%EB%A6%AC%EA%B3%A0-ArrayLinked-List</link>
            <guid>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%9B%B9-%EC%84%9C%EB%B2%84%EC%99%80-WAS%EC%9D%98-%EC%B0%A8%EC%9D%B4-StackQueue-%EA%B7%B8%EB%A6%AC%EA%B3%A0-ArrayLinked-List</guid>
            <pubDate>Tue, 28 Feb 2023 13:51:26 GMT</pubDate>
            <description><![CDATA[<h2 id="웹-서버와-was의-차이점에-대해-설명해주세요">웹 서버와 WAS의 차이점에 대해 설명해주세요.</h2>
<p>이 둘의 가장 큰 차이점은 &quot;동적인 컨텐츠를 다룰 수 있는가?&quot; 이다.
웹서버는 처리할 수 있는 데이터가 html, css, 이미지 등 정적인 데이터로 한정되며, 정적인 데이터가 아닌 동적인 컨텐츠까지도 쓰기 위해서는 WAS가 필요하다.</p>
<p>WAS(Web Application Server)는 웹 서버에 웹 컨테이너를 붙인 형태이다.
WAS를 사용해서 클라이언트가 서버로부터 데이터를 받는 방식은 아래과 같다.</p>
<ol>
<li>클라이언트가 웹 서버에 데이터를 요청</li>
<li>웹 서버에서는 동적 컨텐츠인지를 확인
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2-1 동적 컨텐츠라면 웹 컨테이너로 전송
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2-2 정적 컨텐츠라면 클라이언트에게 데이터를 전송</li>
<li>동적 컨텐츠를 전송받은 웹 컨테이너는 Servelet 구동환경을 제공</li>
<li>제공받은 환경에서 동적 컨텐츠를 생성하고 이를 웹서버에 전달</li>
<li>넘겨받은 동적 컨텐츠를 클라이언트에게 전송<br>

</li>
</ol>
<hr>
<br>

<h2 id="stack-과-queue-그리고-array-와-linked-list에-대해-설명해주세요">Stack 과 Queue 그리고 Array 와 Linked List에 대해 설명해주세요.</h2>
<h4 id="stack-과-queue">Stack 과 Queue</h4>
<p>Stack은 한 쪽 끝에서만 자료를 넣고 뺄 수 있는 후입선출(LIFO) 형식의 자료구조 이다.
Stack은 가장 최근에 들어온 자료를 가리키는 TOP을 통해서만 접근할 수 있으며, 후입선출을 따르기 때문에 가장 최근에 삽입된 데이터가 가장 먼저 삭제되는 특징이 있다.</p>
<p>Queue의 경우 Stack과는 달리 한 쪽 끝에서 삽입, 다른 쪽 끝에서 삭제 작업이 이루어진다.
먼저 들어온 데이터가 먼저 삭제되는 선입선출(FIFO) 방식으로 동작하는데, 이때 삭제 연산만 수행되는 곳을 프론트(Front), 삽입 연산만 이루어지는 곳을 리어(Rear)라고 하며 각각의 연산작업만 수행된다.<br></p>
<h4 id="array배열-와-linked-list">Array(배열) 와 Linked List</h4>
<p>배열은 특정 크기만큼 연속된 메모리 공간에 데이터를 저장하는 정적 자료구조 이다.
배열을 만들기 위해서는 미리 크기를 정하는데, 해당 크기만큼 연속된 메모리 주소를 할당받게 된다.
연속된 메모리 주소를 할당받고 있기 때문에 배열의 데이터는 인덱스라는 것을 갖게 되고 이는 접근과 탐색에 용이하다. 하지만 크기를 미리 정해 놓았기 때문에 수정하는 것은 불가능하며 해당 배열 크기 이상의 데이터를 저장할 수 없다는 단점이 있다.</p>
<p>링크드리스트는 배열과 다르게 연속된 메모리 공간에 저장되어 있지 않고 각각의 데이터가 메모리 공간 상에 고유한 노드로 존재하는 동적 자료구조 이다. 그리고 이 노드는 자신의 앞뒤에 있는 데이터에 대한 주소를 기억하고 있다. 
하지만 배열과는 다르게 노드는 연속된 메모리 공간에 존재하지 않고 모두가 떨어져 있기 때문에, 특정 데이터를 조사하기 위해서는 처음부터 순차적으로 탐색해야 한다는 차이점이 있다.
<br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술면접 스터디] @SpringBootTest/@WebMvcTest, 트랜잭션, TCP/UDP]]></title>
            <link>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-SpringBootTestWebMvcTest-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-TCPUDP</link>
            <guid>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-SpringBootTestWebMvcTest-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-TCPUDP</guid>
            <pubDate>Mon, 27 Feb 2023 02:41:29 GMT</pubDate>
            <description><![CDATA[<h2 id="springboottest-와-webmvctest의-차이점을-설명하세요">@SpringBootTest 와 @WebMvcTest의 차이점을 설명하세요.</h2>
<p><code>@SpringBootTest</code>는 프로젝트 내부에 있는 스프링 빈을 모두 등록하며, 실제 운영 환경에서 사용되는 클래스들을 통합해서 테스트를 진행한다.
따라서 실제 환경과 유사하게 테스트가 가능하다는 장점이 있지만, 모든 빈을 등록하기 때문에 느리고 테스트 단위가 커서 디버깅이 까다롭다는 단점이 있다.</p>
<p><code>@WebMvcTest</code>는 컨트롤러의 역할만을 테스트하며 Web Layer에 해당하는 빈만 빠르게 생성한다.
@Component를 등록하지 않기 때문에 필요한 빈을 직접 채워야하지만 테스트가 훨씬 빠르다는 장점이 있다.
통합테스트에서 진행이 어려운 경우 Mock으로 테스트할 수 있으나 Mock 객체를 사용하므로 실제 동작과 차이가 있다.
<br></p>
<hr>
<br>

<h2 id="트랜잭션이-무엇인지-설명하세요">트랜잭션이 무엇인지 설명하세요.</h2>
<p>트랜잭션은 데이터베이스의 상태를 변경시키기 위해 수행하는 작업의 단위를 말하며, 원자성/일관성/독립성/지속성의 특징을 가지고 있다.</p>
<p><code>원자성</code>은 트랜잭션 내에서 실행한 작업들은 하나의 작업인 것 처럼 모두 성공하거나 모두 실패해야 함을 의미하며, <code>일관성</code>은 모든 트랜잭션의 작업 결과가 같아야 한다는 것을 의미한다.
<code>독립성</code>은 각각의 트랜잭션은 독립적으로 수행되어야 함을 뜻하는데, 동시에 같은 데이터를 수정하지 못하도록 하는 것을 말한다.
또한, <code>지속성</code>은 트랜잭션이 성공적으로 완료된다면 변화된 상태가 지속적으로 반영되어야 함을 말한다.<br></p>
<h3 id="트랜잭션의-전파속성propagation">트랜잭션의 전파속성(Propagation)</h3>
<p>이미 트랜잭션이 진행중일 때 추가 트랜잭션 진행을 어떻게 할 지 결정하는 것을 말한다.</p>
<ul>
<li>REQUIRED(default)</li>
<li>REQUIRES_NEW</li>
<li>MANDATORY</li>
<li>SUPPORTS</li>
<li>NOT_SUPPORTED</li>
<li>NESTED</li>
<li>NEVER<br>

</li>
</ul>
<hr>
<br>

<h2 id="tcp-와-udp의-공통점과-차이점을-설명하세요">TCP 와 UDP의 공통점과 차이점을 설명하세요.</h2>
<p>TCP와 UDP는 인터넷 프로토콜 스택의 4계층 중 전송계층에 속하는 전송 제어 프로토콜이다.
둘다 포트 번호를 이용하여 주소를 지정하고, 데이터 오류 검사를 위한 체크섬이 존재한다는 공통점이 있다.</p>
<p>TCP는 연결형 프로토콜이며 UDP는 비연결형 프로토콜이다.
TCP는 신뢰성 있는 데이터 송수신을 지원하지만, UDP는 신뢰성이 낮은 대신 TCP보다 전송 속도가 빠르다는 차이점을 가지고 있다.
<br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술면접 스터디] Parameter와 Argument의 차이, 프로세스와 스레드의 차이]]></title>
            <link>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-Parameter%EC%99%80-Argument%EC%9D%98-%EC%B0%A8%EC%9D%B4-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-Parameter%EC%99%80-Argument%EC%9D%98-%EC%B0%A8%EC%9D%B4-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Fri, 24 Feb 2023 04:46:53 GMT</pubDate>
            <description><![CDATA[<h2 id="parameter와-argument의-차이에-대해-설명해주세요">Parameter와 Argument의 차이에 대해 설명해주세요.</h2>
<p>매개변수(Parameter)란 함수의 정의에서 전달받은 인수를 함수 내부로 전달하기 위해 사용하는 <code>변수</code>를 의미하며, 인수(Argument)란 함수를 호출할 때 함수로 전달해주는 <code>값</code>을 말한다.</p>
<pre><code class="language-java">public static void main(String[] args) {
    sayHello(&quot;Sora&quot;);   -&gt; Sora: Argument
}

static void sayHello(String name) {   -&gt; name: Parameter
    System.out.println(name + &quot; Hello!&quot;);
}</code></pre>
<br>

<hr>
<br>

<h2 id="프로세스와-스레드의-차이에-대해-설명해주세요">프로세스와 스레드의 차이에 대해 설명해주세요.</h2>
<p><code>프로세스</code>는 운영체제로 부터 자원을 할당받은 작업의 단위를 말하며, <code>스레드</code>는 프로세스로 부터 할당받은 자원을 이용하는 실행 흐름의 단위를 의미한다.</p>
<p>하나의 프로세스 안에서 스레드는 프로세스의 code/data/heap 공간을 공유하지만, 해당 스레드만의 stack을 가지고 동작한다.
그래서 하나의 프로세스 안에서 생성된 스레드 간에는 별도 기술을 쓰지 않고도 데이터 공유가 가능하다.<br></p>
<h4 id="프로세스의-특징">프로세스의 특징</h4>
<ul>
<li>프로세스 생성에 큰 오버헤드가 있다.(생성시 많은 시간이 소요됨)</li>
<li>프로세스 컨텍스트 스위칭의 비효율성, 오버헤드가 크다.</li>
<li>프로세스 사이에 통신이 어렵다.(IPC 사용이 필요)<br></li>
</ul>
<h4 id="스레드의-출현-목적">스레드의 출현 목적</h4>
<ul>
<li>프로세스보다 크기가 작은 실행 단위 필요</li>
<li>프로세스의 생성 및 소멸에 따른 오버헤드 감소</li>
<li>빠른 컨텍스트 스위칭</li>
<li>프로세스들의 통신 시간, 방법 어려움 해소<br>

</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술면접 스터디] MSA, 제네릭, List/Set/Map의 차이]]></title>
            <link>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-MSA-%EC%A0%9C%EB%84%A4%EB%A6%AD-ListSetMap%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-MSA-%EC%A0%9C%EB%84%A4%EB%A6%AD-ListSetMap%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Thu, 23 Feb 2023 04:53:54 GMT</pubDate>
            <description><![CDATA[<h2 id="msamicroservice-architecture란">MSA(MicroService Architecture)란?</h2>
<p>MSA는 하나의 서비스를 만들 때 도메인별로 서비스를 쪼개어 독립적으로 서비스하고, 배포할 수 있도록 구성하는 아키텍쳐이다.
MSA는 1개의 시스템을 독립적으로 배포 가능한 각각의 서비스로 분할하며, 각각의 서비스는 API를 통해 데이터를 주고 받으며 1개의 큰 서비스를 구성한다.</p>
<p>모든 시스템의 구성요소가 한 프로젝트에 통합되어 있는 Monolithic Architecture의 한계점을 극복하고자 등장하게 되었다.</p>
<p>MSA는 각각의 서비스들을 서로 다른 언어와 프레임워크로 구성할 수 있어 일부 서비스에 장애가 발생해도 전체 서비스에 영향을 끼치지 않고, 확장에 용이하다는 장점이 있다.</p>
<p>반면, 서비스가 분리되어 있기 때문에 테스트나 트랜잭션 처리 등이 어렵고, 서비스 간에 API로 통신하기 때문에 그에 대한 비용이 발생한다는 단점이 있다.
또 서비스 간의 호출이 연속적이기 때문에 디버깅 및 에러 트레이싱이 어렵다.</p>
<br>

<hr>
<br>

<h2 id="제네릭에-대해-설명하고-컬렉션-클래스에서-왜-제네릭을-사용하는지-설명해주세요">제네릭에 대해 설명하고, 컬렉션 클래스에서 왜 제네릭을 사용하는지 설명해주세요.</h2>
<p>제네릭이란 클래스에서 다룰 객체를 미리 명시해줌으로써 형 변환을 하지 않고 사용하는 것을 말한다.</p>
<p>만약 제네릭을 사용하지 않을 경우엔 빈번하게 타입 변환이 발생할 수 있으며, 이는 곧 프로그램의 성능을 저하시킬 가능성이 있다.</p>
<p>제네릭을 사용하여 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 객체의 타입을 미리 명시해줌으로써, 번거로운 형변환을 줄여주고 컴파일 시에 객체의 타입을 체크하기 때문에 런타임에 발생할 수 있는 오류를 줄여준다.  </p>
<p>제네릭을 사용하기 위해서는 컬렉션 클래스에 <code>&lt;&gt;</code> 부호를 붙이고 타입 변수나 타입을 적어주면 된다.
<br></p>
<hr>
<br>

<h2 id="list-set-map-hashmap의-차이에-대해서-설명해주세요">List, Set, Map, HashMap의 차이에 대해서 설명해주세요.</h2>
<h4 id="list">List</h4>
<p>List는 배열과 유사하게 연속된 공간에 데이터를 저장하며 인덱스로 데이터에 접근이 가능하다. 
또한 저장공간이 필요에 따라 자동으로 늘어나고 데이터의 중복을 허용한다.<br></p>
<h4 id="set">Set</h4>
<p>데이터의 집합이며 순서가 없고 중복된 데이터를 허용하지 않는다.
인덱스가 따로 존재하지 않기 때문에 iterator를 사용하여 데이터에 접근한다.<br></p>
<h4 id="map">Map</h4>
<p>Key와 Value의 한쌍으로 연관지어 데이터를 저장한다.
Key 값은 중복을 허용하지 않으며 순서를 보장하지 않는다.
Set과 마찬가지로 인덱스가 따로 존재하지 않기 때문에 iterator를 사용하여 데이터에 접근한다.<br></p>
<h4 id="hashmap">HashMap</h4>
<p>Map 인터페이스를 구현한 대표적인 Map 컬렉션이다.
HashMap은 특정 데이터의 저장위치를 해시함수를 통해 바로 알 수 있기 때문에 데이터의 검색 성능이 뛰어나며, Key와 Value 값으로 Null을 허용한다는 특징이 있다.
<br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[이메일 발송 비동기 처리]]></title>
            <link>https://velog.io/@rara_kim/%EC%9D%B4%EB%A9%94%EC%9D%BC-%EB%B0%9C%EC%86%A1-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC%EB%A1%9C-%EC%86%8D%EB%8F%84-%EA%B0%9C%EC%84%A0</link>
            <guid>https://velog.io/@rara_kim/%EC%9D%B4%EB%A9%94%EC%9D%BC-%EB%B0%9C%EC%86%A1-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC%EB%A1%9C-%EC%86%8D%EB%8F%84-%EA%B0%9C%EC%84%A0</guid>
            <pubDate>Wed, 22 Feb 2023 11:45:34 GMT</pubDate>
            <description><![CDATA[<h2 id="문제상황">문제상황</h2>
<p>실전 프로젝트에서 유저의 이메일로 인증번호를 보내 해당 인증번호를 입력받아 확인하여 회원가입, 비밀번호 변경을 진행했다.
그런데 이메일을 발송하고 완료했다는 응답을 프론트에 보내기까지 평균4~5초 걸리다보니 배포 후 유저가 이용했을 때 메일이 발송이 된건지 안된건지 알지 못해 여러번 발송 버튼을 누르게 되는 일이 있었다.
그래서 인증번호를 생성하고 해당 인증번호를 이메일로 발송하는 로직을 뜯어보기로 했다.
<br></p>
<h2 id="의견결정">의견결정</h2>
<p>기존 코드의 경우 영어 대소문자 + 숫자로 조합한 8자리의 인증번호를 생성하도록 하고 있었다.
그런데 우리 프로젝트에서는 인증번호를 Redis에 저장하여 5분간만 유효하도록 관리하고 있었고, 규모가 크지 않은 프로젝트 이기에 불필요하게 복잡한 로직이라고 판단하여 간소화 하기로 결정했다.</p>
<ul>
<li><p>기존의 인증번호 생성 로직</p>
<pre><code class="language-java">public String createKey() {
  StringBuffer key = new StringBuffer();
  Random random = new Random();

  for (int i = 0; i &lt; 8; i++) {
      int index = random.nextInt(3);

      switch (index) {
          case 0:
              key.append((char) ((random.nextInt(26)) + 97));
              break;
          case 1:
              key.append((char) ((random.nextInt(26)) + 65));
              break;
          case 2:
              key.append((random.nextInt(10)));
              break;
      }

  for (int i = 0; i &lt; 6; i++) {    // 인증코드 6자리
      key.append((random.nextInt(10)));
  }
  return key.toString();
}</code></pre>
</li>
<li><p>새로운 인증번호 생성 로직</p>
<pre><code class="language-java">public String createKey() {
  StringBuilder key = new StringBuilder();
  Random random = new Random();

  for (int i = 0; i &lt; 6; i++) {    // 인증코드 6자리
      key.append((random.nextInt(10)));
  }
  return key.toString();
}</code></pre>
</li>
</ul>
<p>위와 같이 로직을 간소화 하여 테스트를 진행한 결과 기존 코드보다 조금 속도가 향상되었다.(4.47s -&gt; 3.96s)
그러나 실제 사이트에서 테스트를 해보니 체감될 정도로 응답속도가 크게 빨라지지는 않아 추가적인 방법을 찾아보기로 했다.</p>
<p>그러던 중 이메일을 발송하는 메소드를 비동기 방식으로 처리하여 프론트로 보내는 응답속도를 높이기로 했다.
AsyncConfig 클래스에서 관련 설정을 해주고, <code>@Async</code> 어노테이션을 비동기 처리 하고자 하는 메소드에 붙여주어 
이메일 발송 메소드가 호출되는 경우 비동기로 처리하도록 했다.</p>
<pre><code class="language-java">@Async
public void sendSimpleMessage(String email)throws Exception {
    ePw = createKey();
    MimeMessage message = createMessage(email);
    upsert(new EmailConfirm(email,ePw));

    try {   
        emailSender.send(message);
    } catch (MailException e) {
        e.printStackTrace();
        throw new RestApiException(ErrorStatusCode.DELETED_ACCOUNT);
    }
}</code></pre>
<h2 id="문제-해결-결과">문제 해결 결과</h2>
<p>위와 같이 인증번호 생성 로직 간소화와 이메일 발송의 비동기 처리를 통해 기존 코드 실행시 4.47s 소요되던 응답 속도가 489ms로 <strong>약 827%</strong> 향상 되었다.</p>
<table>
<thead>
<tr>
<th align="center">기존 코드</th>
<th align="center">로직 간소화</th>
<th align="center">로직 간소화 + 비동기 처리</th>
</tr>
</thead>
<tbody><tr>
<td align="center">4.47s</td>
<td align="center">3.96s</td>
<td align="center">489ms</td>
</tr>
</tbody></table>
<br>]]></description>
        </item>
        <item>
            <title><![CDATA[[기술면접 스터디] DI, 인덱스]]></title>
            <link>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94</link>
            <guid>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94</guid>
            <pubDate>Wed, 22 Feb 2023 02:47:04 GMT</pubDate>
            <description><![CDATA[<h1 id="di란-무엇인가">DI란 무엇인가?</h1>
<p>Spring 프레임워크가 제공하는 의존 관계 주입 기능이다.
외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.</p>
<p>클래스 사이의 의존관계를 빈 설정 정보를 바탕으로 컨테이너가 자동적으로 연결해주기 때문에 개발자들은 제어할 필요없이 빈 설정 파일에 의존관계가 필요하다는 정보만 추가해주면 된다.</p>
<p>두 객체 간의 관계(의존성)를 맺어주는 것을 의존성 주입이라고 하며 <code>생성자 주입</code>, <code>필드 주입</code>, <code>수정자 주입</code> 등 다양한 주입 방법이 있는데, Spring 개발팀에서는 생성자 주입을 권장하고 있다.<br></p>
<h3 id="di가-필요한-이유는-무엇인가">DI가 필요한 이유는 무엇인가?</h3>
<pre><code class="language-java">public class Store {
    private Pencil pencil;

    public Store() {
        this.pencil = new Pencil();
    }
}</code></pre>
<p>위와 같은 예시 클래스는 아래와 같은 문제점을 가진다.</p>
<ul>
<li><strong>두 클래스가 강하게 결합되어 있다.</strong><ul>
<li>만약 Store에서 Pencil이 아닌 Food와 같은 다른 상품을 판매하고자 한다면 Store 클래스의 생성자를 변경해야 한다.</li>
</ul>
</li>
<li><strong>객체들 간의 관계가 아니라 클래스 간의 관계가 맺어진다.</strong><ul>
<li>객체들 간에 관계가 맺어졌다면 다른 객체의 구현 클래스(Pencil 혹은 Food 등)을 알지 못하더라도 해당 클래스가 인터페이스를 구현했다면 인터페이스의 타입(Product)으로 사용할 수 있다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>이러한 문제가 발생하는 이유는 <strong>관심이 분리되지 않았기</strong> 때문이다.
Spring 에서는 DI를 적용하여 이러한 문제를 해결하고자 하였다.</p>
</blockquote>
<h3 id="di의-장점은-무엇인가">DI의 장점은 무엇인가?</h3>
<ul>
<li>클래스를 재사용 할 가능성을 높이고, 다른 클래스와 독립적으로 클래스를 테스트 할 수 있다.</li>
<li>비즈니스 로직의 특정 구현이 아닌 클래스를 생성하는데 매우 효과적이다.<br>

</li>
</ul>
<hr>
<br>

<h1 id="db에서-인덱스를-잘-사용하면-어떤-장점이-있을까요">DB에서 인덱스를 잘 사용하면 어떤 장점이 있을까요?</h1>
<h3 id="인덱스란">인덱스란?</h3>
<p>인덱스란 인덱스란 추가적인 쓰기 작업과 저장 공간을 활용하여 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조 이다.
데이터베이스에서도 테이블의 모든 데이터를 검색하면 시간이 오래 걸리기 때문에 데이터와 데이터의 위치를 포함한 자료구조를 생성하여 빠르게 조회할 수 있도록 돕고 있다.</p>
<p>인덱스를 활용하면 데이터를 조회하는 SELECT외에도 UPDATE나 DELETE의 성능이 함께 향상된다.
해당 연산을 수행하려면 대상을 먼저 조회해야 작업을 할 수 있기 때문에, SELECT 성능이 향상됨에 따라 함께 성능이 향상된다.<br></p>
<h3 id="인덱스를-사용하는-이유는-무엇인가">인덱스를 사용하는 이유는 무엇인가?</h3>
<p>인덱스의 가장 큰 특징은 데이터들이 정렬되어 있다는 것이다. 이 특징으로 인해 조건 검색에서 강점을 가진다.</p>
<p>데이터가 쌓여 순서없이 뒤죽박죽으로 저장되면 Where 조건 검색, Order by 정렬을 수행할 시 Full Table Scan을 하게 속도도 느려지고 부하가 걸릴 수도 있다.
그런데 적절히 인덱스를 사용하게 되면 이미 정렬이 되어 있기 때문에 빠르게, 전반적인 자원의 소모없이 해당 작업을 수행할 수 있다.</p>
<blockquote>
<p><strong>인덱스의 장점</strong>
&nbsp;&nbsp;- 테이블을 조회하는 속도와 그에 따른 성능을 향상시킬 수 있다.
&nbsp;&nbsp;- 전반적인 시스템의 부하를 줄일 수 있다.</p>
</blockquote>
<p>그러나 인덱스를 관리하기 위해 DB의 약10%에 해당하는 저장공간이 필요하며, 추가적인 작업을 해야한다.
또, 인덱스를 잘못 사용할 경우 오히려 성능이 저하되는 역효과가 일어날 수 있다.<br></p>
<h3 id="그러면-인덱스는-언제-사용하면-좋을까">그러면 인덱스는 언제 사용하면 좋을까?</h3>
<ul>
<li>중복된 데이터가 적은 컬럼</li>
<li>INSERT, UPDATE, DELETE가 자주 발생하지 않는 컬럼</li>
<li>JOIN이나 WHERE 또는 ORDER BY에 자주 사용되는 컬럼</li>
<li>규모가 작지 않은 테이블<br></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술면접 스터디] OOP, REST API ]]></title>
            <link>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-OOP-REST-API</link>
            <guid>https://velog.io/@rara_kim/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-OOP-REST-API</guid>
            <pubDate>Tue, 21 Feb 2023 15:04:28 GMT</pubDate>
            <description><![CDATA[<h1 id="객체지향-프로그래밍oop에-대해-설명해주세요">객체지향 프로그래밍(OOP)에 대해 설명해주세요.</h1>
<p>객체지향 프로그래밍은 프로그래밍에서 필요한 데이터를 추상화시켜 <strong>상태</strong>와 <strong>행위</strong>를 가진 <code>객체</code>를 만들고, 그 객체들간의 유기적인 상호작용을 통해 로직을 구성하는 프로그래밍 방법이다.</p>
<p>즉, 상태와 행위를 가진 객체들을 레고 블럭처럼 조립해서 하나의 프로그램을 만드는 것을 객체지향 프로그래밍 이라고 할 수 있다.</p>
<p>객체지향 프로그램은 코드 재사용 및 유지보수가 용이하고, 대규모 프로젝트에 적합하다는 장점이 있다.
반면, 처리 속도가 상대적으로 느리고 객체의 수가 증가함에 따라 용량이 커질 수 있수 있다. 
또한 현실을 잘 반영하기 위해서는 설계시 많은 시간과 노력이 필요하다는 단점이 있다.<br></p>
<h3 id="객체지향의-4가지-특징에-대해-알고-있나요">객체지향의 4가지 특징에 대해 알고 있나요?</h3>
<h4 id="1️⃣-추상화">1️⃣ 추상화</h4>
<p>구체적인 사물들의 공통적인 특징을 파악해서 이를 하나의 개념(집합)으로 다루는 것</p>
<h4 id="2️⃣-캡슐화">2️⃣ 캡슐화</h4>
<ul>
<li>정보 은닉&nbsp;:&amp;nbsp 필요가 없는 정보는 외부에서 접근하지 못하도록 제한하는 것</li>
<li>높은 응집도, 낮은 결합도를 유지하여 유연함과 유지보수성 증가</li>
</ul>
<h4 id="3️⃣-상속">3️⃣ 상속</h4>
<p>여러 개체들이 가진 공통된 특성을 부각시켜 하나의 개념이나 법칙으로 성립시키는 과정</p>
<h4 id="4️⃣-다형성">4️⃣ 다형성</h4>
<ul>
<li>서로 다른 클래스의 객체가 같은 메시지를 받았을 때 각자의 방식으로 동작하는 능력</li>
<li>오버라이딩(Overriding), 오버로딩(Overloading)<br>

</li>
</ul>
<h3 id="객체지향에-대해-알고있는-원칙이나-키워드가-있나요">객체지향에 대해 알고있는 원칙이나 키워드가 있나요?</h3>
<h4 id="1️⃣-단일-책임-원칙single-responsibility-principle">1️⃣ 단일 책임 원칙(Single Responsibility Principle)</h4>
<p>객체는 단 하나의 책임만 가져야 한다.</p>
<h4 id="2️⃣-개방-폐쇄-원칙open-closed-priciple">2️⃣ 개방 폐쇄 원칙(Open Closed Priciple)</h4>
<p>기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계가 되어야 한다.</p>
<h4 id="3️⃣-리스코프-치환-원칙liskov-substitution-principle">3️⃣ 리스코프 치환 원칙(Liskov Substitution Principle)</h4>
<p>일반화 관계에 대한 원칙이며, 자식 클래스는 최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야 한다.</p>
<h4 id="4️⃣-인터페이스-분리-원칙interface-segregation-principle">4️⃣ 인터페이스 분리 원칙(Interface Segregation Principle)</h4>
<p>인터페이스를 클라이언트에 특화되도록 분리시키라는 설계 원칙이다.</p>
<h4 id="5️⃣-의존-역전-원칙dependency-inversion-principle">5️⃣ 의존 역전 원칙(Dependency Inversion Principle)</h4>
<p>의존 관계를 맺을 때 변화하기 쉬운 것 또는 자주 변화하는 것 보다는 변화하기 어려운 것, 거의 변화가 없는 것에 의존하라는 것이다.</p>
<br>

<hr>
<br>

<h1 id="rest-api란-무엇인가요">REST API란 무엇인가요?</h1>
<ul>
<li>REST 기반으로 서비스 API를 구현한 것</li>
<li>Open API는 대부분 REST API를 제공한다.</li>
</ul>
<h3 id="rest-api-설계-규칙">REST API 설계 규칙</h3>
<ul>
<li>URI는 자원의 정보를 표시해야 한다.<ul>
<li>resource는 동사보다는 명사를, 대문자보다는 소문자를 사용한다.</li>
<li>resource는 도큐먼트 이름으로는 단수명사를 사용해야 한다.</li>
<li>resource는 컬렉션 이름으로는 복수 명사를 사용해야 한다.</li>
<li>resource는 스토어 이름으로는 복수 명사를 사용해야 한다.</li>
</ul>
</li>
<li>자원에 대한 행위는 HTTP Method(GET/POST/PUT/DELETE)로 표현한다.<ul>
<li>URI HTTP Method가 들어가면 안된다. </li>
</ul>
</li>
<li>URI에 행위에 대한 동사 표현이 들어가면 안된다(CRUD 기능을 나타내는 것은 URI에 사용하지 않는다.)</li>
<li>경로 부분 중 변하는 부분은 유일한 값으로 대체한다(즉, id는 하나의 특정 resource를 나타내는 고유값이다.)<br></li>
</ul>
<h3 id="rest란">REST란?</h3>
<p>HTTP URI를 통해 자원(Resource)을 명시하고, HTTP Method(POST, GET, PUT, DELETE)를 통해 해당 자원에 대한 CRUD Operation을 적용하는 것을 의미한다.<br></p>
<h3 id="프로젝트에-rest-api를-사용한-이유가-무엇인가요">프로젝트에 REST API를 사용한 이유가 무엇인가요?</h3>
<p>REST는 HTTP 프로토콜의 인프라를 그대로 사용하므로 REST API 사용을 위한 별도의 인프라를 구축할 필요가 없고, REST API 메시지가 의도하는 바를 명확하게 나타내므로 의도하는 바를 쉽게 파악할 수 있다는 장점이 있다.</p>
<p>또한  클라이언트와 서버는 REST API를 이용해 정보를 주고 받기 때문에 서버는 클라이언트의 히스토리, 문맥을 유지할 필요가 없게 된다.
각자의 역할이 명확하게 나뉘어져 있어 개발자의 업무량이 감소되고 플랫폼의 독립성 확장이라는 효과를 기대할 수 있다.<br></p>
<h3 id="rest-api-말고-다른-비교할만한-것을-알고-있나요">REST API 말고 다른 비교할만한 것을 알고 있나요?</h3>
<p>그러나 REST API는 표준이 존재하지 않으며, 사용할 수 있는 메소드가 제한적 이라는 단점이 있다.</p>
<p>이러한 단점을 가진 REST API를 대체할 수 있는 것으로는 SOAP과 GraphQL이 있다.</p>
<h4 id="1️⃣-soap">1️⃣ SOAP</h4>
<p>서로 다른 애플리케이션 통신을 지원하는 초기 통신 프로토콜이다.</p>
<ul>
<li>HTTP Method중 POST만을 이용하여 데이터의 CRUD를 처리하는 특징이 있다.</li>
<li>다양한 오류에 대한 처리가 가능하고, stateful / stateless 모두 지원한다. </li>
</ul>
<h4 id="2️⃣-graphql">2️⃣ GraphQL</h4>
<ul>
<li>GraphQL은 필요한 컬럼에 대해서만 선택적으로 요청할수 있어 불필요한 데이터를 받지 않고, 필요한 데이터만 받을 수 있다.</li>
<li>GraphQL은 REST와는 다르게 Resource에 대한 엔드포인트가 따로 존재하지 않고, 하나의 엔드포인트만 존재한다.</li>
<li>해당 엔드포인트로 요청 시, 원하는 리소스와 해당 리소스에서 원하는 필드를 특정하는 GraphQL query를 함께 보낸다.<ul>
<li>GraphQL은 여러 Depth의 조인이 필요한 복잡한 요청 데이터도 할 수 있어서, 효율적으로 데이터를 주고 받을 수 있다. <br></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ImgScalr] 이미지 리사이징]]></title>
            <link>https://velog.io/@rara_kim/ImgScalr-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%A6%AC%EC%82%AC%EC%9D%B4%EC%A7%95</link>
            <guid>https://velog.io/@rara_kim/ImgScalr-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%A6%AC%EC%82%AC%EC%9D%B4%EC%A7%95</guid>
            <pubDate>Mon, 13 Feb 2023 15:21:42 GMT</pubDate>
            <description><![CDATA[<h2 id="1-의사결정">1. 의사결정</h2>
<p>실전 프로젝트를 진행하며 이미지 업로드 최적화에 대해 고민하게 되었다.
이미지를 최대5장까지 함께 등록할 수 있는 게시글 기능을 구현해야 했는데, 유저가 업로드할 이미지의 크기가 제각기 다르다는 점과 고해상도의 이미지를 업로드 했을 때 조회 속도가 느려지는 경우가 있다는 점에서 이미지 리사이징이 필요하다고 판단했다.</p>
<p>프론트에서 이미지 업로드시 용량을 줄이는 방법으로 리사이징을 했지만, 그와 더불어 백엔드에서도 일정한 크기와 비율로 이미지를 리사이징 하여 저장하기로 했다.</p>
<p>기술적 대안으로는 Marvin, S3 Lambda, imgScalr이 있었다.
S3 Lambda는 참고할 만한 reference가 적었고, Marvin의 경우 압축 비율이 우수하다는 reference를 확인했으나 처리 속도가 빠르고 화질이 깨지지 않는 imgScalr을 사용하는 것이 낫다고 최종 판단했다.
<br></p>
<h2 id="2-이미지-리사이징-구현">2. 이미지 리사이징 구현</h2>
<p>imgScalr 라이브러리를 사용하여 이미지를 리사이징 한 뒤 S3에 저장하도록 구현하였다.</p>
<pre><code class="language-java">private static final int TARGET_HEIGHT = 650;

// 이미지 업로드
public String uploadImage(MultipartFile file) throws IOException {
    String fileFormat = Objects.requireNonNull(file.getContentType())
        .substring(file.getContentType().lastIndexOf(&quot;/&quot;) + 1).toLowerCase();

    String fileName = createFileName(file.getOriginalFilename());

    BufferedImage croppedImage = resizeImage(file);

    ObjectMetadata objectMetadata = new ObjectMetadata();
    ByteArrayInputStream byteArrayInputStream = convertImage(croppedImage, file.getContentType(), fileFormat, objectMetadata);

    amazonS3.putObject(new PutObjectRequest(bucket, fileName, byteArrayInputStream, objectMetadata).withCannedAcl(CannedAccessControlList.PublicRead));

    return amazonS3.getUrl(bucket, fileName).toString();
}


    // imgscalr 라이브러리로 resizing(TARGET_HEIGHT를 정하고 비율에 맞춰 리사이징)
private BufferedImage resizeImage(MultipartFile multipartFile) throws IOException {

    BufferedImage sourceImage = ImageIO.read(multipartFile.getInputStream());

    if (sourceImage.getHeight() &lt;= TARGET_HEIGHT) {
        return sourceImage;
    }

    double sourceImageRatio = (double) sourceImage.getWidth() / sourceImage.getHeight();

    int newWidth = (int) (TARGET_HEIGHT * sourceImageRatio);

    return Scalr.resize(sourceImage, newWidth, TARGET_HEIGHT);
}

private ByteArrayInputStream convertImage(BufferedImage croppedImage, String contentType, String fileFormat, ObjectMetadata objectMetadata) throws IOException {

    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    ImageIO.write(croppedImage, fileFormat, byteArrayOutputStream);

    objectMetadata.setContentType(contentType);
    objectMetadata.setContentLength(byteArrayOutputStream.size());

    return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}</code></pre>
<br>

<h2 id="3-리사이징-적용-전후">3. 리사이징 적용 전후</h2>
<p>이미지 리사이징을 적용하여 게시글 등록 속도는 전보다 조금 느려졌으나 저장한 이미지를 조회해오는 속도는 크게 개선되었다.
동일한 고해상도 이미지 5장을 등록하여 조회해본 결과, 리사이징 적용 전에는 이미지 조회에 333ms가 소요되었었는데 적용 후에는 79ms까지 개선된 것을 확인할 수 있었다.</p>
<h3 id="적용-전이미지-5장-조회">적용 전(이미지 5장 조회)</h3>
<p><img src="https://velog.velcdn.com/images/rara_kim/post/0d15a513-bcb0-4a0c-b58a-06c066fd5774/image.png" alt=""></p>
<h3 id="적용-후동일-이미지-5장-조회">적용 후(동일 이미지 5장 조회)</h3>
<p><img src="https://velog.velcdn.com/images/rara_kim/post/e55b41ea-0dab-465d-9291-29d5a7289941/image.png" alt="">
<br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] 항해99 실전프로젝트 회고]]></title>
            <link>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B499-%EC%8B%A4%EC%A0%84%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B499-%EC%8B%A4%EC%A0%84%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 12 Feb 2023 14:08:36 GMT</pubDate>
            <description><![CDATA[<p>6주간에 걸친 프로젝트가 끝이 났다.
프로젝트 도중 디자이너님 이탈, 부팀장 이탈 등으로 프로젝트의 결과물에 아쉬움이 많이 남지만, 그래도 보다 더 성능을 향상시키려 노력했던 기록들을 남겨보려고 한다.</p>
<h2 id="아쉬웠던-점">아쉬웠던 점</h2>
<h3 id="기획">기획</h3>
<blockquote>
<p>기획단계부터 <code>선택과 집중</code>이 정말 중요하다는 것을 이번 실전 프로젝트로 제대로 알게되었다.</p>
</blockquote>
<p>프로젝트를 기획했을 당시 욕심이 앞서 이런저런 기능을 너무 몰아넣은 것 같다.
프로젝트를 진행하며 추가하고 싶었지만 프론트엔드에서 소화하지 못해 결국 포기하게 된 기능들이 많은데, 이런 기능들을 기획 초반에 잘 추려서 기획했더라면 훨씬 알찬 서비스가 되었을 것 같다.
(검색 기능, 기간별 조회, 관심사 추천 기능 등 ...)<br></p>
<h3 id="동영상-업로드-최적화">동영상 업로드 최적화</h3>
<p>서비스에서 메인이 되는 기능이 동영상을 포함한 게시글인데 동영상 용량이 커질수록 업로드에 시간이 걸려 고민이 많았다.
압축을 해서 올리더라도 압축하는 데 시간이 소요되고 해당 동영상을 메인페이지에 바로 재생을 할 수 있어야 하기에 압축해서 올리는 방법은 적합하지 않다고 판단했다.
팀원분께서는 스트리밍 서버를 구축하는 것이 어떻냐고 이야기를 하셨었는데, 서버를 별도로 구축해야해서 한정된 기간내에 구현하기에는 무리라고 생각했다.
게다가 동영상 업로드 최적화에 관련한 Reference를 거의 찾아볼 수 없어서 더 여러운 부분이었다.</p>
<p>그러다가 동영상 업로드 메소드를 비동기로 처리하면 게시글 등록 속도가 조금이라도 향상되지 않을까? 싶었다.
동영상을 S3에 저장한 뒤 저장한 주소를 DB에 저장해야 했기에 <code>CompletableFuture</code>를 사용해서 반환값을 가져오려 했는데, 왜인지 에러는 나지 않지만 DB에 저장되는 것이 저장 주소값이 아닌 <code>Not Completed</code>라는 문구였다. </p>
<p>그렇게 이런저런 시도를 해보았으나 결국 프로젝트 기간내에 동영상 업로드 최적화를 구현해내지 못했다.
지금도 관련자료가 없을지 찾아보고 있는데, 꼭 동영상 업로드 속도를 향상시키고 싶다!!(계속 도전예정)
<br></p>
<h2 id="프로젝트를-진행하며-개선한-점">프로젝트를 진행하며 개선한 점</h2>
<p>프로젝트가 끝나고 정리를 하게 되어 부끄럽지만 하나씩 정리해 나갈 예정이다!</p>
<ol>
<li>이미지 리사이징을 통한 응답속도 향상&nbsp;<a href="https://velog.io/@rara_kim/ImgScalr-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%A6%AC%EC%82%AC%EC%9D%B4%EC%A7%95">여기서 확인하기!</a></li>
<li>이메일 발송 비동기 처리와 인증번호 생성 로직 간소화를 통한 응답속도 개선(827%)&nbsp;<a href="https://velog.io/@rara_kim/%EC%9D%B4%EB%A9%94%EC%9D%BC-%EB%B0%9C%EC%86%A1-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC%EB%A1%9C-%EC%86%8D%EB%8F%84-%EA%B0%9C%EC%84%A0">여기서 확인하기!</a></li>
<li>서브쿼리, 조인 등 복잡한 쿼리 작성 필요에 따른 QueryDSL 적용</li>
<li>Redis 데이터 캐싱을 통한 조회 속도 향상</li>
<li>WebHook을 활용한 프로젝트 빌드 결과 확인, 실시간 에러 로그 확인<br>

</li>
</ol>
<h2 id="추가하고-싶은-기능">추가하고 싶은 기능</h2>
<p>같은 백엔드 팀원분과 추가하고 싶은 기능을 일찌감치 리스트업 해보았다.
항해99를 먼저 거쳐가신 분들의 깃허브를 보면 추가하고 싶은 기능 리스트를 정리해두고 정작 실제로 구현한 건 못봤는데, 우리 조는 느리더라고 꼭 하나씩 다 구현해 나가려고 한다!!
(사실 프로젝트에 추가하지 못해 아쉬운 기능들도 있어서 더 열의 넘치게 기능 추가를 외치고 있다ㅎㅎ)</p>
<ul>
<li>검색 기능</li>
<li>태그 기능</li>
<li>Refresh Token</li>
<li>대댓글</li>
<li>부적절한 게시글 신고 기능</li>
<li>공연정보 기간별 조회</li>
<li><strong>동영상 업로드 속도 개선</strong></li>
<li>마이페이지 기능(작성한 댓글 조회, 좋아요한 게시글 조회, 구독 리스트 조회 등)<br>

</li>
</ul>
<h2 id="앞으로-나는-어떤-개발자가-될까">앞으로 나는 어떤 개발자가 될까?</h2>
<p>실전 프로젝트를 마친 지금 본격적으로 개발자가 되기 위한 지원 주차에 들어선다.
지금까지는 주어진 미션(1주일안에 프로젝트 완성하기 등)을 해결하기에 급급했는데, 이제부터는 누군가로부터 주어지는 것이 아니라 스스로가 발전해나가기 위해 공부하고 계속 발전을 거듭해야 한다.</p>
<p>과연 취업은 할 수 있을까, 앞으로 꾸준히 발전해 나갈 수 있을까 걱정되고 겁나기도 하지만, 한편으로는 앞으로의 삶이 기대된다.
전직장에서는 늘 스스로 한계를 정해놓고 &quot;이정도면 됐어&quot;하고 흘러가는 대로 살아왔는데, 지금은 하루하루 나아가는 내 자신이 대견하고 이런 내모습이 기쁘기만 하다!</p>
<p>실전 프로젝트를 진행하며 내손으로 무언가를 만들어내는 재미를 느낄 수 있었다.
처음 혼자 개발 공부를 시작했을 땐 어렵게만 느껴져서 재미는 있어도 새로운 것에 도전하는 것에 벽을 느꼈었다.
그런데 실전 프로젝트를 진행하며 팀원들과 기술 이야기, 코드 이야기를 나누며 매일이 두근두근했다.
같은 기능을 구현하더라도 다양하게 코드를 작성할 수 있는 것도 흥미롭고, 여러 사람의 코드를 보고 이야기를 들을 수 있는 것도 흥미로웠다.</p>
<p>개발자로서는 이제 막 첫발을 뗐다.
앞으로 배울 것도 정말정말 많고 모자란 실력에 절망하고 지칠때도 있겠지만, 지금 느끼는 이런 두근두근함을 계속 기억하고 느낄 수 있는 개발자가 되고 싶다.
그러면 아무리 힘들어도 결국 다시금 떨쳐내고 힘낼 수 있을 테니까..!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] 항해99 10주차 회고(feat.실전 프로젝트)]]></title>
            <link>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B499-10%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0feat.%EC%8B%A4%EC%A0%84-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B499-10%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0feat.%EC%8B%A4%EC%A0%84-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Sun, 22 Jan 2023 16:23:34 GMT</pubDate>
            <description><![CDATA[<h2 id="실전프로젝트를-진행하며">실전프로젝트를 진행하며...</h2>
<p>실전프로젝트 3주차가 지났다.</p>
<p>비교적 백엔드의 기능 구현이 프론트엔드보다 빠른편이라 우리팀 백엔드는 3주차 스코프에 해당하는 기능을 구현하며 종종 코드리뷰를 진행했다.
전체적인 코드 스타일을 맞춰가며 왜 이러한 코드를 썼는지, 왜 이렇게 예외처리를 했는지 등등을 이야기 하며 정말 많이 배울 수 있는 시간이었다.
개인적으로 어떻게 하면 데이터를 빠르면서 정확하게 가져올 수 있을까에 대해 고민이 많은데, 중간발표를 마치고 그동안 고민하던 QueryDSL을 적용해보기로 결심했다.</p>
<p>사실 처음부터 나는 QueryDSL을 꼭 프로젝트에 적용해보고 싶다고 생각하고 있었는데, 우리 프로젝트에서는 검색기능도 없고(앞으로 도입할지도 모르지만), 생각만큼 복잡한 쿼리를 쓰지 않을 것 같아 팀원들은 꼭 그걸 써야하냐며 회의적인 시각을 가지고 있었다.
그런데 프로젝트를 진행하며 내가 담당 기능 부분에서 이러저러한 조건으로 데이터를 찾아와야하는 일이 발생했고, 페이징 기능까지 함께 구현하려니 쿼리가 길어지고 복잡해져서 QueryDSL을 도입을 위해 팀원들을 설득해봐야지 생각하고 있었다.
그때마침 중간발표회에서 시니어 멘토님이 네이티브 쿼리보다는 QueryDSL을 쓰는 것이 좋다, Repository에 네이티브 쿼리(&amp;JPQL)이 너무 많이 사용된다.고 피드백을 주셔서 팀원들과 다시한번 이에 대해 이야기 해보려고 한다.</p>
<p>개인적으로 3주차에 좀 더 많은 기술을 다루고 싶었는데, 그러지 못해 아쉬웠다.
토요일에 진행된 중간 발표회에서도 시니어 멘토님의 예리하면서도 공부해두었어야 할 질문들에 대답을 잘 하지 못한 것도 아쉬움이 많다.
나름대로 <code>왜 기술을 써야 하는지</code>, <code>왜 이렇게 코드를 짰는지</code> 고민하며 프로젝트를 진행하고 있다고 생각했는데 막상 설명하려니 제대로 설명하기가 어려웠다. 
게다가 꼬리에 꼬리를 무는 질문의 향연... 제대로 대답하지 못해 참 부끄러웠지만, 많이 느끼고 배울 수 있었다.
그리고 다시금 불타오르기 시작했다. 프로젝트 힘내자 힘!! 설연휴 끝나고 다시 달리는 거다!!!🔥
<br></p>
<hr>
<h2 id="프로젝트에-도입한-기술들">프로젝트에 도입한 기술들</h2>
<h3 id="github-actions-cicd">Github Actions CI/CD</h3>
<p>지난번 클론코딩에서 매번 File Zila를 이용해 서버를 배포해야해서 정말 번거롭다고 생각했었고, 이번 실전 프로젝트에서는 초반부터 꼭 자동배포를 도입하고 싶다고 생각했다.
기술적으로 여러 대안들이 있었지만, 깃허브에서 빌드과정을 확인하기 쉬우면서 서버를 따로 사용할 필요가 없고, 비교적 설정이 쉬운 Github Actions을 사용하기로 했다.</p>
<p>CI/CD에 대해서 워낙에 잘 정리해둔 블로그들이 많아서 설정 자체는 어렵지 않았다.
코드를 특정 브랜치에 pull request 하는 것만으로도 자동으로 jar 파일을 만들어 배포할 수 있어, 일일히 빌드하고 파일을 교체해주는 번거로운 작업을 하지 않아도 되니 절약한 시간은 개발에 더 집중할 수 있게 되었다.</p>
<p>그리고 CI/CD를 통한 빌드 결과를 깃허브를 통해 별도로 확인하는 번거로움을 줄이고, 편히 확인하기 위해 슬랙과 연동하여 팀 워크스페이스에서 확인하도록 하고 있다.
<br></p>
<h3 id="sentry-slack-web-hook">sentry, Slack Web hook</h3>
<p>모두가 알듯이 배포한 서버의 로그를 확인하기란 쉽지않다.
테스트를 거치고 배포하더라도 개발중엔 어떠한 에러가 일어날지 모르는데 어떻게 해야 로그를 확인할 수 있을까? 고민하던 중 sentry를 알게 되었다.
적용법도 쉬워서 금방 프로젝트에 적용하고 사용했다.
에러 메세지 외에도 여러 정보를 확인할 수 있어서 유용하게 활용하고 있었는데, 알고보니 팀원들이 함께 이용하려면 비지니스 버전을 구매해서 사용해야 했다.</p>
<p>그래서 sentry 외에 다른 대안이 없을까 알아보던 중, slack web hook을 알게 되었다.
슬랙에 연동하여 로그를 실시간으로 확인할 수 있어 팀 워크스페이스에 적용하면 딱이겠다 싶어 바로 적용하여 slack으로 실시간 로그를 확인하고 있다.</p>
<p>팀 워크스페이스를 만들어두니 빌드 결과, 에러 로그를 함께 확인할 수 있어 활용도 만점이다!!<br></p>
<h3 id="소셜로그인네이버">소셜로그인(네이버)</h3>
<p>우리 프로젝트는 힙합 콘텐츠를 보다 많은 사람들이 즐길 수 있도록 장벽을 낮추고 싶다는 것을 목표로 진행중이다.
그래서 회원가입에 소셜로그인을 도입하여 보다 편하게 회원가입할 수 있도록 했다.
많은 소셜로그인 중에서도 한국인들이 보편적으로 편하게 사용하는 카카오와 네이버를 도입했다.</p>
<p>나는 둘중에서 네이버 로그인을 담당했는데, 카카오와 달리 네이버는 이런저런 조건이 세세하게 정해져있어 생각보다 번거로웠다.
로그인 코드를 구현하는 것 자체는 어렵지 않았는데, 개발자센터에 등록할 수 있는 서비스 Url을 하나밖에 등록할 수 없고, 실제 서비스에 적용하여 모든 사람들이 사용할 수 있게 하려면 사전에 검수요청을 해야하는 번거로움들이 존재했다.(그래서 사람들이 네이버보단 카카오 로그인을 많이 구현하나...?)</p>
<p>그런 점들은 불편했지만, 한편으로는 카카오보다 이런면에서는 구현하기 좋았다.
카카오는 사용자의 이메일이나 프로필 사진등의 정보를 사용자의 선택에 의해서 받아올 수 있도록 하고 있는데, 네이버는 개발자가 필수값으로 지정할 수 있어, 우리 서비스에서 필수로 하는 값이 없을 때의 예외처리가 간편하다는 장점이 있었다.</p>
<p>소셜 로그인은 이번에 처음 사용해보았는데, 사용자도 회원가입/로그인이 간편하고 개발자의 입장에서는 사용자에게 직접 개인정보를 입력받는 것이 아니기 때문에 보안성을 향상시킬 수 있어 활용하길 잘 했다고 생각한다!!
<br></p>
<hr>
<h2 id="앞으로-도입하고-싶은-기술">앞으로 도입하고 싶은 기술</h2>
<p>앞으로는 아래와 같은 기술을 우리 프로젝트에 적용하고 싶다.
현재 우리 프로젝트에 어떤 것을 빨리 도입해야할지 우선순위를 잘 정해서 하나씩 적용해 나가고 싶다.</p>
<p>아직 프론트엔드의 기능 구현이 반정도 밖에 진행되지 않지만, 빠르게 기능 구현을 끝내고 리팩토링을 통한 최적화에 시간을 많이 투자하고 싶다.  </p>
<ul>
<li>@Dynamicupdate</li>
<li>QueryDSL</li>
<li>Nginx&nbsp;:&nbsp;무중단 배포</li>
<li>AWS Lambda&nbsp;:&nbsp;동영상 업로드 최적화</li>
<li>Redis&nbsp;:&nbsp;데이터 캐싱</li>
</ul>
<blockquote>
<p>충분히 할일이 넘치는데, 이것도 해보고 싶고 저것도 해보고 싶고...😅</p>
</blockquote>
<br>]]></description>
        </item>
        <item>
            <title><![CDATA[[EC2] Swap 메모리 설정(메모리 늘리기, CPU 부하 줄이기)]]></title>
            <link>https://velog.io/@rara_kim/EC2-Swap-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%84%A4%EC%A0%95%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%8A%98%EB%A6%AC%EA%B8%B0-CPU-%EB%B6%80%ED%95%98-%EC%A4%84%EC%9D%B4%EA%B8%B0</link>
            <guid>https://velog.io/@rara_kim/EC2-Swap-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%84%A4%EC%A0%95%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%8A%98%EB%A6%AC%EA%B8%B0-CPU-%EB%B6%80%ED%95%98-%EC%A4%84%EC%9D%B4%EA%B8%B0</guid>
            <pubDate>Fri, 20 Jan 2023 07:03:47 GMT</pubDate>
            <description><![CDATA[<h2 id="ec2-부하-문제">EC2 부하 문제</h2>
<p><img src="https://velog.velcdn.com/images/rara_kim/post/6b114e8e-6dd2-433d-87b1-69c781f45a8a/image.png" alt=""></p>
<p> 실전 프로젝트를 진행하던 중 점점 코드량이 늘어나고, 프론트에서 API 요청 횟수가 늘어감에 따라 개발중이던 코드에서 에러도 여럿 발생하면서 서버가 터지는 일이 빈번하게 발생하기 시작했다.</p>
<p>처음엔 EC2를 중지시켰다가 다시 시작하고 했는데, 서버가 터지는 횟수가 늘어나기 시작했고 그 간격도 짧아지기 시작했다.
또, EC2를 다시 시작하는 경우 포트포워딩(80 -&gt; 8080)을 매번 다시 해주어야 했기에 여간 번거로운게 아니었다.
(잠을 자다가도 서버가 터졌다는 연락이오면 비몽사몽한 상태로 서버를 재가동 시켜야 했다...)</p>
<p>현재는 수익성을 목표로 한 프로젝트가 아니기에 프리티어를 사용중인데, 구글링을 해보니 프리티어의 1GB 메모리로는 감당이 안되는 경우 CPU 사용률이 급격하게 증가해 서버가 퍼지는 터져버리는 일이 종종 있다고 한다...</p>
<br>

<hr>
<br>

<h2 id="swap-메모리-설정">Swap 메모리 설정</h2>
<h3 id="swap-메모리란">Swap 메모리란?</h3>
<p>스왑 메모리란, 실제 메모리 Ram이 가득 찼지만 더 많은 메모리가 필요할 때 디스크 공간을 이용하여 부족한 메모리를 대체할 수 있는 공간을 의미한다.
실제 디스크 공간을 메모리처럼 사용하는 개념이기 때문에 가상 메모리라고 할 수 있다.<br></p>
<h3 id="swap-메모리-설정-1">Swap 메모리 설정</h3>
<p>AWS 공식 사이트에서는 EC2 인스턴스에서 스왑 공간으로 사용할 메모리를 할당하는 방법을 안내해주고 있다.</p>
<h4 id="1️⃣-스왑-파일-생성">1️⃣ 스왑 파일 생성</h4>
<p>dd 명령을 사용하여 루트 파일 시스템에 스왑 파일을 생성한다. 
bs는 블록 크기이고 count는 블록 수, 스왑 파일의 크기는 dd 명령의 블록 크기 옵션에 블록 수 옵션을 곱한 값이다. 이러한 값을 조정하여 원하는 스왑 파일 크기를 결정한다.(나의 경우 디스크 4GB를 할당해 주었다.)</p>
<pre><code class="language-java">$ sudo dd if=/dev/zero of=/swapfile bs=128M count=32</code></pre>
<h4 id="2️⃣-스왑-파일의-읽기-및-쓰기-권한-업데이트">2️⃣ 스왑 파일의 읽기 및 쓰기 권한 업데이트</h4>
<pre><code class="language-java">$ sudo chmod 600 /swapfile</code></pre>
<h4 id="3️⃣-linux-스왑-영역을-설정">3️⃣ Linux 스왑 영역을 설정</h4>
<pre><code class="language-java">$ sudo mkswap /swapfile</code></pre>
<h4 id="4️⃣-스왑-공간에-스왑-파일-추가">4️⃣ 스왑 공간에 스왑 파일 추가</h4>
<pre><code class="language-java">$ sudo swapon /swapfile</code></pre>
<h4 id="5️⃣-프로시저-확인">5️⃣ 프로시저 확인</h4>
<pre><code class="language-java">$ sudo swapon -s</code></pre>
<h4 id="6️⃣-etcfstab-파일을-편집하여-부팅-시-스왑-파일-시작">6️⃣ /etc/fstab 파일을 편집하여 부팅 시 스왑 파일 시작</h4>
<pre><code class="language-java">// 편집기에서 파일을 열어준다.
$ sudo vi /etc/fstab

// 파일 끝에 아래의 내용을 추가하고 파일을 저장한다.(/포함)
/swapfile swap swap defaults 0 0</code></pre>
<h4 id="7️⃣-메모리-확인-명령어로-결과-확인">7️⃣ 메모리 확인 명령어로 결과 확인</h4>
<pre><code class="language-java">$ free -m</code></pre>
<p><img src="https://velog.velcdn.com/images/rara_kim/post/a8c1d45d-eb4b-45d3-8c94-931915a267cd/image.png" alt=""></p>
<p>명령어를 입력하면 <code>Swap: 4095</code>을 확인할 수 있다!
부디 이것으로 서버가 터지는 일이 더이상 발생하지 않기만을 바래본다...🥹</p>
<br>

<hr>
<p>📚참고자료
<a href="https://aws.amazon.com/ko/premiumsupport/knowledge-center/ec2-memory-swap-file/">AWS 공식사이트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] 항해99 8,9주차 회고(feat. 실전 프로젝트)]]></title>
            <link>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B499-89%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0feat.-%EC%8B%A4%EC%A0%84-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B499-89%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0feat.-%EC%8B%A4%EC%A0%84-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Sun, 15 Jan 2023 16:31:59 GMT</pubDate>
            <description><![CDATA[<h2 id="8주차-회고">8주차 회고</h2>
<p>드디어 6주간의 실전프로젝트가 시작되었다.
우리팀은 팀리더를 맡은 분께서 <code>힙합</code>을 주제로 진행하고 싶다고 먼저 말을 하셨고, 다같이 회의를 진행하여 그 주제를 가지고 프로젝트를 진행하기로 했다.</p>
<p>힙합에 관련된 공연 정보나, 힙합 크루들 정보같은 건 현재 하나의 사이트에서 확인할 수 있는 곳이 거의 없고, 대부분 각자의 팀SNS로 공연을 홍보하고 팀을 홍보하고 있다고 한다.
그래서 힙합에 관심이 있는 사람이 아니면 정보를 얻기가 어렵다고 한다.</p>
<p>위와 같은 상황을 고려하여 우리팀은 힙합에 관련한 쇼츠 영상,피드를 게시할 수 있는 커뮤니티를 기반으로 한 서비스를 기획했다. 
힙합 크루로 인증을 받은 크루의 경우에는 공연 정보를 게시할 수 있게 하여 보다 효율적으로 홍보를 할 수 있도록하고, 유저에게는 힙합에 관한 영상/게시글을 통해 소통하고 공연정보를 한곳에서 얻을 수 있도록 하는 서비스를 만들고자 한다.</p>
<p>실전 프로젝트는 6주이지만 총 3주에 걸쳐 MVP를 개발하고 나머지는 유저 피드백을 받으며 , 우선은 와이어프레임을 만들고 첫주차 개발 scope를 정했다.
다들 항해에서 마지막으로 진행하는 프로젝트이고 실전 프로젝트인 만큼 욕심들이 생겨 상당히 많은 수의 기능 이야기가 나왔고, 그것들을 추리는데 많은 시간을 소비했다.</p>
<blockquote>
<p><strong>💡그렇게 정해진 1주차 Scope</strong></p>
<ol>
<li>회원가입, 로그인, 소셜로그인(카카오)</li>
<li>Shorts 등록,수정,삭제 / Shorts 댓글 등록,수정, 삭제 / Shorts 좋아요</li>
<li>Feed 등록,수정,삭제 / Feed 댓글 등록,수정, 삭제 / Feed 좋아요</li>
<li>전체적인 디자인 결정, 로고 결정</li>
</ol>
</blockquote>
<p>1주차 Scope가 정해지고 백엔드에서는 바로 엔티티 설계를 시작했는데, 지금까지 진행했던 프로젝트에서보다 다뤄야할 테이블이 늘어나고 여러 연관관계를 맺어줘야 하다보니 테이블 설계도 정말 어려웠다.
(프로젝트 도중에 여러번 테이블을 전부 날리고 다시 생성하는 삽질도 했다...)</p>
<p>테이블 설계가 끝나고 1주차 개발은 단순 CRUD라서 코드 작성이 오래걸리지는 않았다.
나의 경우 이미지, 동영상 업로드를 위해 S3 설정과 관련 코드 작성도 함께 해야 했는데, 처음 다뤄보는 S3라 걱정했지만 여러 기술 블로그를 참고하여 큰 문제없이 금방 구현할 수 있었다.
(기술 블로그여 영원하라!✨)</p>
<p>생각보다 담당 부분의 구현이 빨리 마무리 되어, 팀원들에게 자청하여 https 설정 및 서버 배포를 맡아 진행하였다.
서버 배포는 지금까지 여러번 해왔기에 큰 문제가 없었지만 https 설정은 2일에 걸쳐 겨우 마무리 할 수 있었다.
여러 기술 블로그를 보며 설정을 진행했는데, 원래 가지고 있던 가비아 도메인으로 https 설정을 진행하니 중간 과정이 없는 블로그들도 있어 따로 찾아보며 진행하느라 허둥지둥 했었다. 
그리고 EC2에서 설정해준 포트포워딩에서 80 -&gt; 8080 하나의 경우만 진행해도 되는데, 443 -&gt; 8080도 같이 진행해버려 무언가 충돌이 나는 건지 계속 https 접속이 실패해서 &quot;혹시나..?&quot;하고 두번째 포트포워딩 설정은 삭제하니 아무문제 없이 https 접속이 되어버려 잠깐 현타가 오기도 했다🙀</p>
<p>1주차는 비교적 여유로웠기에 CI/CD 를 활용한 자동 배포도 도전해보고 싶었는데, https 설정에 생각보다 많은 시간이 소요되어 2주차로 미뤄진게 너무 아쉬웠다.</p>
<p>앞으로는 기술 블로그를 참고할 때 무작정 따라하는 것이 아니라, 한번 내용을 정독하고 나의 상황과 맞는지 잘 살펴보고 진행 해야겠다고 다짐하게 되었다. 
(늘 이렇게 생각하지만 성격이 급해 무작정 해보고 마는데, 앞으로는 반복되는 삽질을 줄이기 위해서라도 찬찬히 살펴보는 습관을 들여야 겠다!)
<br></p>
<h2 id="9주차-회고">9주차 회고</h2>
<p>실전 프로젝트 2주차가 시작되었다.</p>
<p>2주차에서는 1주차에 비해 비교적 작은 범위의 Scope를 진행하기로 했다.
1주차의 CRUD를 전부 구현한 백엔드와 다르게 프론트엔드 분들은 기능에 관련하여 따로 공부하고 구현을 진행하느라 생각만큼 CRUD 기능 구현이 되지 않아, 2주차의 목표는 작게 잡을 수 밖에 없었다.</p>
<blockquote>
<p><strong>💡2주차 개발 Scope</strong></p>
<ol>
<li>CI/CD 자동 배포</li>
<li>관리자 기능 구현</li>
<li>구독,알람 기능 구현</li>
<li>이메일 인증 기능 구현</li>
<li>서버 로깅 설정</li>
<li>Redis Cache 설정</li>
</ol>
</blockquote>
<p>그래서 백엔드에서는 첫날에 CI/CD 자동 배포를 설정하고 2주차 부터 구현한 코드를 자동 배포해보기로 했다.
CI/CD 설정 자체는 큰 문제없이 완료되었는데, 2주차 내내 여러번 배포에 실패하는 일이 있었다.
원인은 여러가지가 있었다.
EC2에 설치한 Code Deploy Agent가 중지된 상태에서 배포를 시도해서 배포에 실패하기도 했고, 수동으로 서버에 nohup으로 어플리케이션은 실행시킨 다음번에 CI/CD를 통해 자동배포를 한 경우도 배포에 실패했다.
추측컨데, 수동으로 실행한 경우 EC2의 Code Deploy Agent가 인식하지 못해서 배포에 실패하는 것이 아닌가 생각된다.
그렇게 여러번 배포 소동을 겪고 나서, 배포 하기 전에 Code Deploy Agent의 실행 상태를 확인하고 배포를 진행하니 문제없이 배포가 되는 것을 확인할 수 있었다.</p>
<p>또 CI/CD 외에 쿼리 성능 향상과 Redis 캐시 설정에 대해 팀원들과 많은 이야기를 나누었다.
지금까지는 발생하는 쿼리의 횟수를 줄이는 것에 중점을 두고 JPQL을 사용해 테이블을 조인해서 한번에 데이터를 조회 해오도록 해왔는데, 기술 매니저님께서 쿼리의 횟수보다는 한번의 쿼리에 얼마나 많은 조건이 걸려있느냐가 성능을 더 저하시키는 요인이라고 말씀하셔서 쿼리문을 리팩터링하여 지금까지 작성한 쿼리와 어느쪽의 성능이 더 좋은지 테스트를 거친뒤 프로젝트에 적용하기로 했다.
사실 우리 프로젝트의 규모에는 크게 성능 차이가 느껴질 것 같지는 않지만, 쿼리 성능 향상에는 원래부터 관심이 많았기에 여러 방식으로 쿼리문을 작성해보고 반드시 성능 테스트를 진행하려고 한다.</p>
<p>Redis를 이용한 캐시 기능을 적용하려고 하던 중 &quot;우리 프로젝트에는 캐시 기능을 적용하지 않는 것이 더 좋은게 아닐까?&quot;하는 생각이 들었다.
동영상, 이미지를 메인화면에 많이 불러오기 때문에 캐시 기능을 사용하려고 했던 것인데, 아무래도 SNS 처럼 생성하고 수정하는 서비스 이기 때문에, 우리 서비스에서 대량의 트래픽이 발생하진 않겠지만, 게시글이나 댓글을 작성했을 때 바로 바로 반영시켜 주려고 하니 어떻게 캐시 기능을 설정해줘야 할지 고민이 되기 시작했다.
등록, 삭제때는 캐시를 삭제해주고 수정때는 등록된 캐시를 수정하는 방식으로 운영하려고 했는데, 수정된 사항을 실시간으로 반영시키는 부분에서 작성된 코드가 생각대로 작동하지 않아서 코드에 대한 고민과 함께 수정,삭제를 하기 쉬운 SNS 서비스에 캐시 기능을 적용하는 것이 맞는가? 하는 의문이 들기 시작했다.</p>
<p>이글을 쓰는 지금까지 계속 Redis 캐시 기능에 대한 자료들을 찾아보고 있는데, 내일 팀원들과 좀 더 구체적으로 캐시 기능을 어떻게 적용하고 운영할 것인지 이야기를 해봐야 할 것 같다.
<br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] 항해99 7주차 회고(feat. 클론코딩)]]></title>
            <link>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B499-7%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0feat.-%ED%81%B4%EB%A1%A0%EC%BD%94%EB%94%A9</link>
            <guid>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B499-7%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0feat.-%ED%81%B4%EB%A1%A0%EC%BD%94%EB%94%A9</guid>
            <pubDate>Sat, 07 Jan 2023 02:59:48 GMT</pubDate>
            <description><![CDATA[<p>일주일이 지나서 적어보는 7주차 회고...</p>
<h2 id="클론코딩-주차">클론코딩 주차</h2>
<p>우리조는 <code>채팅</code> 기능을 구현하고 싶어 채팅 기능을 사용하는 서비스들을 위주로 찾아보았다.
처음엔 유명하지 않은 실시간 채팅 사이트를 클론코딩 하려고 했으나, 기술 매니저님 피드백을 받아 디스코드를 클론코딩 하기로 결정했다.</p>
<p>구현한 것을 보았을 때 어떤 서비스를 구현 한건지 바로 알수 있을 정도의 서비스를 클론코딩 하는 것이 좋다는 피드백을 받았다.</p>
<p>그리고 시작한 프로젝트에서 악몽이 시작됐다...
구현 방법도 잘 모르고 어떤 기술을 사용해야하는지만 대략적으로 알고 있었던 터라 일주일 안에 구현하려고 하니 난이도가 정말 높았다.
(여담이지만, 담당 기술 매니저님의 멘토링은 없는 것보다 못할 정도라... 난이도x10000000)</p>
<p>채팅 기능은 WebSocket + Stomp + Redis를 이용해서 구현했는데, 깃허브란 깃허브는 죄다 찾아보고 온갖 블로그를 찾아보며 조금씩 구현해나갔다.
그런데 초반부터 Redis 관련 에러가 계속 되었는데, <code>EmbeddedRedisConfig</code> 의 빈을 생성할 수 없다는 메세지가 나올 뿐 도대체 뭐가 문제인지를 몰라 2일을 허비했다.</p>
<p>다른반 담당 매니저님께서 시간을 내주셔서 봐주신 결과 Redis의 포트가 충돌하고 있어서 난 에러였다.
<code>왜</code> 에러가 났는지 알기까지 정말 오래 걸렸는데, 해결법은 너무도 간단해서 허무할 정도였다..</p>
<p>그렇게 며칠동안 우리를 괴롭히던 에러가 해결되고 프로젝트가 잘 진행이 되나... 싶었는데, 프로젝트 기한 전날 프론트와 연결하여 테스트를 진행하던 중 WebSocekt 통신은 연결됐는데, 메세지 통신을 위한 Subscribe 요청에서 JWT 토큰 에러가 나기 시작했다.</p>
<p>에러 메시지로보면 JWT 토큰을 풀어내는 과정에서 공백이 들어가는 것 같은데 어느부분에서 문제가 일어나 공백이 들어가는 것인지를 몰라 또다시 에러의 늪에 빠지고 말았다.</p>
<p>무려 세명의 매니저님이 해당 에러를 봐주셨지만 프로젝트 발표 당일이 되어서도, 발표 직전까지도 해결하지 못해 결국 우리조의 클론코딩은 미완성인 채로 마무리할 수밖에 없었다.</p>
<p>클론코딩을 진행하면서 채팅 기능을 과연 구현할 수 있을까 하는 걱정과 담당 기술 매니저님으로 부터 전혀 도움을 받지 못하는 현실, 프론트엔드 팀원들을 기다리게 만들고 있다는 부담감 등에 스트레스가 극에 달해 밥도 못 먹을 정도였다.
그 정도로 너무너무 힘들었지만, 같이 힘내보자고 이 에러를 해결해 나가는 과정은 그것대로 의미가 있을 것이라고 북돋아준 팀원들이 있어서 포기않고 마지막까지 에러를 마주할수 있었다.</p>
<p>비록 정해진 기간내에 프로젝트를 마무리 하지 못했지만, 에러를 해결하려고 노력한 그 과정들에서 에러메세지를 확인하고 원인을 찾아나가는 방법을 배울 수 있었다.
그리고 무엇보다도 개발은 혼자하는 것이 아니라 팀원들과 같이 하는 것이다!라는 당연하지만 당연하지 않은 것을 몸소 깨닫는 한주가 되었다.</p>
<p>현재 미완성인 프로젝트는 8주차~13주차에 진행되는 실전 프로젝트가 끝나면 같이 모여 마무리 하기로 했다.
(팀원들도 이제는 오기가 생겨서 마무리 하고야 말겠다!하는 생각들이다ㅎㅎ)</p>
<p>실전 프로젝트에서 실력을 더 쌓아서 클론코딩 프로젝트를 보다 더 업그레이드 시켜서 잘 마무리 지을 수 있기를! 열심히 해야지.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] 항해 6주차 회고 (feat. 첫 FE/BE 협업)]]></title>
            <link>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B4-6%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-feat.-%EC%B2%AB-FEBE-%ED%98%91%EC%97%85</link>
            <guid>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B4-6%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-feat.-%EC%B2%AB-FEBE-%ED%98%91%EC%97%85</guid>
            <pubDate>Wed, 28 Dec 2022 19:45:24 GMT</pubDate>
            <description><![CDATA[<p>바쁜 일상에 뒤늦게 적어보는 첫 협업 회고...</p>
<h2 id="첫-협업-미니-프로젝트">첫 협업, 미니 프로젝트</h2>
<p>항해 6주차에는 처음으로 프론트엔드(React) 분들과 협업으로 미니프로젝트를 진행했다.
처음 진행하는 협업인만큼 무리하지 않고 기본 CRUD를 구현할 수 있도록 주제를 정했다.</p>
<p>우선 커뮤니티 서비스를 구현해보고 싶다는 것은 정해졌었지만 <code>어떤 것을 나누는</code> 커뮤니티가 좋을지 고민이 많았다.
의견은 많이 나왔지만 동물병원, 스포츠 등 어디라도 있을 법한 주제들이었기에 약 한시간 팀원들과 회의를 지속한 결과 강남언니 서비스에서 영감을 얻어 성형에 대한 경험을 나눌 수 있는 커뮤니티 서비스를 구현하기로 했다.</p>
<p>사실 백엔드(Spring) 쪽은 주특기 입문,숙련,심화 주차를 거치면서 기본 CRUD(+회원가입, 로그인) 구현력을 키워왔기 때문에, 그것에서 나아가 새로운 기술을 도입해 보고 싶은 욕심이 있었다.
그런데 같이 협업을 진행하실 프론트 분들은 JWT 토큰을 사용하는 회원가입 로그인을 진행한 경험이 없어서 이런저런 기능보다도 기본 CRUD를 구현하는데에 의의를 두고 싶다고 하셨다.</p>
<p>프론트엔드 분들이 좀 더 열심히 해주시면 이 기능도 저 기능도 가능 할 것 같은데.... 라고 개인적 욕심으로 생각해보았지만 이건 <code>내</code> 프로젝트가 아니라 <code>우리</code> 프로젝트 이기에 의견을 맞춰가며 협업을 진행했다.</p>
<p>그리고 프론트엔드 분들과의 협업은 물론, 백엔드들 끼리의 협업도 어려웠다.
나는 집중해서 후딱 코드를 작성하고 빨리빨리 Postman을 이용해서 테스트를 진행해 보는 스타일인데, 같이 프로젝트를 진행하는 분들은 비교적 여유있게 작업을 하는 스타일이셨다.
프로젝트 기간은 1주일밖에 안되고 프론트엔드와의 첫 협업인 만큼 빨리 구현하고 테스트를 진행하고 배포를 끝내서 프론트와의 연결은 잘 되는지 시간을 들이고 싶었는데, 전혀 그렇게 진행할 수 없었다.</p>
<p>그래서 여러모로 답답하기는 했지만, 그 과정에서 소통하는 방법에 대해 배울 수 있었고, <code>팀</code>프로젝트의 결과물을 위해서 내가 할 수 있는 것은 무엇인지 생각하는 시간을 가지고 내 코드를 여러번 리팩토링하면서 보다 더 좋은 코드를 짤 수 있었다.
또한 시도해 보고 싶었던 <strong>log 기록을 파일로 남기는 기능</strong>도 구현해 볼 수 있어서 좋았다.</p>
<p>그런데 비교적 순탄하게 프로젝트를 진행한 백엔드는 배포도 프로젝트 제출일 오전에 끝내고 테스트가 다 끝났는데, 프론트의 기능구현이 거의 되지 않았다는게 문제였다..
프론트 배포도 되지 않았고, CSS는 다 깨지고 기능은 작동하지도 않고...
결국엔 전체 발표가 끝나고 기술 매니저님께서 쓴소리를 남기셨다. </p>
<p>프론트 분들이 매일 노력하신건 잘 알지만 아쉬움이 많이 남는 프로젝트였다.
이번 프로젝트는 항해 수료 후에도 좋으니, 프론트도 백엔드도 더 보완해서 꼭 완성시키고 싶다.</p>
<p><a href="https://github.com/HanghaeSisters">GitHub: 미니 프로젝트(HanghaeSisters)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Builder 패턴은 왜 사용하는 것일까?]]></title>
            <link>https://velog.io/@rara_kim/Spring-Builder-%ED%8C%A8%ED%84%B4%EC%9D%80-%EC%99%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@rara_kim/Spring-Builder-%ED%8C%A8%ED%84%B4%EC%9D%80-%EC%99%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Sun, 18 Dec 2022 13:18:19 GMT</pubDate>
            <description><![CDATA[<p>개발을 진행하다보면 생성자를 통해 객체를 많이 만들게 된다.
객체가 가지고 있는 인자들이 많을 경우, 그 인자들이 어떠한 것인지 헷갈리는 경우가 있다.
또한 생성자 호출을 위해서 설정하고싶지 않는 매개변수의 값까지 지정해줘야 하는 불편함도 있다.</p>
<p>즉, 생성자를 빌더 패턴으로 생성하지 않았을 경우 코드를 읽을 때 각 값의 의미가 무엇인지 헷갈릴 수 있고, 매개변수가 몇 개 인지 항상 확인해야 하며, 실수로 매개변수의 순서가 바뀌더라도 컴파일러가 잡지 못하여 런타임 에러로 이어지게 될 수 있다.
<br></p>
<h2 id="builder-패턴이란">Builder 패턴이란?</h2>
<p>빌더 패턴(BUilder Pattern)이란 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴이다.</p>
<p>생성자 인자로 너무 많은 인자가 사용되는 경우, 어떠한 인자가 어떠한 값을 나타내는지 확인하기 힘들다.
또 어떠한 인스턴스의 경우에는 특정 인자만 생성해야 하는 경우가 발생한다.</p>
<p>이러한 문제를 해결하기 위해서 빌더 패턴을 사용할 수 있다.
<br></p>
<h2 id="builder의-사용">@Builder의 사용</h2>
<p>@Builder 어노테이션을 사용하면 따로 Builder Class를 만들지 않고 사용할 수 있다.</p>
<h3 id="builder-패턴을-적용할-클래스">Builder 패턴을 적용할 클래스</h3>
<pre><code class="language-java">@Entity
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
    private String username;
    private int age;
    private String email;
    private String address;
    private int zipCode;

    @Builder
    public User(String username, int age, String eamil, String address, int zipCode) {
        this.username = username;
        this.age = age;
        this.email = email;
        this.address = address;
        this.zipCode = zipCode;
    }
}</code></pre>
<h3 id="builder-패턴을-사용한-객체-생성">Builder 패턴을 사용한 객체 생성</h3>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {

        //빌더 패턴을 통해 어떤 필드에 어떤 값을 넣어주는지 명확히 눈으로 확인할 수 있다.    
        User user = User.builder(&quot;소라&quot;)
                        .age(30)
                        .email(test@gmail.com)
                        .address(&quot;서울특별시 강남구&quot;)
                        .zipCode(06325)
                        .build();
    }
}</code></pre>
<ul>
<li><p><code>@Builder</code> 
Builder 패턴을 자동으로 생성해주는데, builderMethodName에 들어간 이름으로 빌더 메소드를 생성해 준다.</p>
</li>
<li><p><code>생성자에 @Builder 사용</code>
클래스 레벨에서 @Builder와 @NoArgsConstructor를 함께 쓰면 오류가 발생한다.
이를 해결하기 위해서는 모든 필드를 가지는 생성자를 만들어야 하는데, @AllArgsConstructor를 사용하는 것은 위험하다.
클래스에 존재하는 모든 필드에 대한 생성자를 자동으로 생성하는데, 인스턴스 멤버의 선언 순서에 영향을 받기 때문에 변수의 순서를 바꾸면 생성자의 입력 값 순서도 바뀌게 되어 검출되지 않는 치명적인 오류를 발생시킬 수도 있다.
이를 해결하기 위해 생성자에 <code>@Builder를</code> 붙여주어, @AllArgsConstructor를 쓰는 일이 없도록 한다.</p>
</li>
<li><p><code>builder 메소드</code></p>
<ul>
<li>필수로 들어가야 할 필드들을 검증하기 위해 만들어 졌다.</li>
<li>꼭 name이 아니더라도 해당 클래스를 객체로 생성할 때 필수적인 필드가 있다면 활용할 수 있다.</li>
<li>보통 PK를 정정한다. </li>
</ul>
</li>
</ul>
<br>

<h2 id="builder-패턴의-장점">Builder 패턴의 장점</h2>
<h3 id="1️⃣필요한-데이터만-설정할-수-있다">1️⃣필요한 데이터만 설정할 수 있다.</h3>
<p>User객체를 생성해야 하는데 address 필드와 zipCode의 필드가 필요 없는 상황이 있다고 가정을 한다면
우리는 address 필드와 zipCode에 더미 값을 넣어주거나 그 두 개의 필드를 가지고 있지 않은 생성자를 새로 만들어주어야 한다.</p>
<p>이러한 작업이 반복이 된다면 많은 시간을 낭비하고 코드의 양이 증가할 수 있는데, 이럴 때 빌더를 이용하면 동적으로 처리할 수 있다.
그리고 이렇게 필요한 데이터만 설정할 수 있는 빌더의 장점은 테스트용 객체를 생성할 때 용이하게 해 주고, 불필요한 코드의 양을 줄이는 등의 이점을 가질 수 있다.
<br></p>
<h3 id="2️⃣유연성을-확보할-수-있다">2️⃣유연성을 확보할 수 있다.</h3>
<p>새롭게 추가되는 변수 때문에 기존의 코드를 수정해야 하는 상황이 발생했을 때, 기존에 작성된 코드의 양이 방대하다면 감당하기 어려울 수도 있다.
하지만 빌더 패턴을 이용하면 새로운 변수가 추가되는 등의 상황에도 기존의 코드에 영향을 주지 않을 수 있다.
<br></p>
<h3 id="3️⃣가독성을-높일-수-있다">3️⃣가독성을 높일 수 있다.</h3>
<p>빌더 패턴을 사용하면 매개 변수가 많아져도 가독성을 높일 수 있다.
생성자로 객체를 생성하는 경우, 매개변수가 많아지면 코드의 가독성이 떨어지게 된다.
각각의 값들이 무엇을 의미하는지 바로 파악이 어렵고, 클래스 변수가 많아지면 더욱 코드를 읽기 힘들어진다.</p>
<p>하지만 빌더 패턴을 적용하면 가독성을 높일 수 있고, 직관적으로 어떤 데이터에 어떤 값이 설정되는지 쉽게 파악할 수 있다.
<br></p>
<h3 id="4️⃣불변성을-확보할-수-있다">4️⃣불변성을 확보할 수 있다.</h3>
<p>개발을 진행하면서 많은 개발자들이 흔히 수정자 패턴(Setter)을 흔히 사용한다.
굉장히 편하다는 장점이 있지만 Setter를 구현한다는 것은 불필요하게 확장 가능성을 열어두는 것이다.</p>
<p>이는 Open-Closed 법칙에 위배되고, 불필요한 코드 리딩 등을 유발한다. 
그렇기 때문에 클래스 변수를 final로 선언하고 객체의 생성은 빌더에 맡기는 것이 좋다.
<br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] Entity Class의 @NoArgsConstructor(access = AccessLevel.PROTECTED)]]></title>
            <link>https://velog.io/@rara_kim/JPA-Entity-Class%EC%9D%98-NoArgsConstructoraccess-AccessLevel.PROTECTED</link>
            <guid>https://velog.io/@rara_kim/JPA-Entity-Class%EC%9D%98-NoArgsConstructoraccess-AccessLevel.PROTECTED</guid>
            <pubDate>Sun, 18 Dec 2022 12:14:15 GMT</pubDate>
            <description><![CDATA[<p>JPA에서는 프록시 생성을 위해 <code>@NoArgsConstructor</code>를 강제하게 되는데, 이때 AccessLevel을 따로 설정해주지 않으면 외부에서 생성자에 쉽게 접근할 수 있게 된다.</p>
<p>유지 보수성을 최대화하고 접근 가능성을 최소화하기 위해 AccessLevel을 PROTECTED 이하로 거는 것이 좋다.</p>
<pre><code class="language-java">@Entity
@NoArgsConstructor(access = AcessLevel.PROTECTED)
public class User {

}</code></pre>
<br>]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] 항해 5주차 회고(feat. CORS)]]></title>
            <link>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B4-5%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0feat.-CORS</link>
            <guid>https://velog.io/@rara_kim/WIL-%ED%95%AD%ED%95%B4-5%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0feat.-CORS</guid>
            <pubDate>Sun, 18 Dec 2022 11:27:26 GMT</pubDate>
            <description><![CDATA[<h2 id="한주-동안의-이야기">한주 동안의 이야기</h2>
<p>5주차인 주특기 심화주차에는 백엔드끼리 협업하는 팀과제를 진행했다.</p>
<p><code>나만의 블로그 API 만들기</code>라는 주제로 진행했는데, 입문주차와 숙련주차에서 진행한 개인 과제의 연장선이었다.
그런데 숙련주차에서 Lv1, Lv2의 과제 중 Lv2의 과제가 선택이었던 터라 팀원별 기능 구현 경험이 제각각이었다.</p>
<p>팀장으로서 어떻게 담당을 나눠야 할까 고민이 정말 많았다.
각각의 실력차도 고려해야 하고, 과제 제출일까지 완성할 수 있을 지도 고려해야 했다.
그러나 팀장이라고 혼자 결정하는 것은 있을 수 없기에, 팀원들과 회의를 통해 결정하기로 했다.</p>
<p>팀원들에게는 솔직하게 과제 제출 기한까지 완성을 할 수 있는지도 중요하다고 내 의견을 전달하고, 각자가 해보고 싶은 기능이 있는지 의견을 먼저 수집했다.
그 결과 각자가 지난주 과제에서 해보지 않은 기능 중에서 본인이 해보고 싶은 기능을 담당하기로 했다.</p>
<p>다행히 팀원들끼리의 대화가 활발해서 모르는 부분에 대한 질문이나, 진행사항 공유 등 정보 교환이 적극적으로 이루어졌다. 
또, 우리팀은 매일 13시, 20시에 정기적으로 회의를 통해 코드 확인, 테스트 등을 진행했는데 덕분에 자주 리팩토링을 거치며 코드를 보다 더 깔끔하게 효율적으로 짜려고 노력했다.</p>
<p>그리고 나는 내 담당 기능(Spring security를 적용한 회원가입, 로그인)을 빠르게 구현하고, 팀원들의 코드를 보며 과제 요구사항에 알맞게 구현이 되었는지를 확인하며 코드를 조금씩 고쳐나갔는데, 그 과정에서 내가 생각했던 코드와 어떻게 다른지를 비교해보며 보며 많이 배울 수 있었다.</p>
<p>이제 6주차에는 본격적으로 프론트엔드 분들과 협업을 진행하게 되는데, 잘 할 수 있을지 걱정 또 걱정뿐이다..
이번 협업에서는 <code>소통 제일!</code>을 모토로 주특기 입문-심화주차에 걸쳐 배운 것들을 복습하고 앞으로 있을 클론 코딩, 실전 프로젝트에 대비해 기초를 탄탄히 해 나가고 싶다.</p>
<p>피할 수 없으면 즐기자!
<br></p>
<hr>
<br>

<h2 id="cors">CORS</h2>
<p>프론트엔드와 협업을 진행할 때 CORS가 중요하다고 하는데, CORS가 도대체 뭔지 정리해보려고 한다.<br></p>
<h2 id="cors란-무엇인가">CORS란 무엇인가?</h2>
<p>CORS(Cross-Origin Resource Sharing)는 <code>출처가 다른 자원들을 공유</code>한다는 뜻으로, 한 출처에 있는 자원에서 다른 출처에 있는 자원에 접근하도록 하는 개념이다.
직역하면 교차되는 출처 자원들의 공유로, 다른 출처에 있는 자원을 요청한다고 하면, 이를 교차 출처 요청이라고 부른다.</p>
<blockquote>
<p>교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행합니다.
<strong>- mdn</strong></p>
</blockquote>
<h3 id="다른-출처-요청의-위험성">다른 출처 요청의 위험성</h3>
<p>&lt;img&gt;, &lt;script&gt;, &lt;frame&gt;, &lt;video&gt;, &lt;audio&gt; 등이 웹에 등장하면서, 페이지 로딩 이후에 브라우저에서 이러한 하위 자원들을 가져올 수 있게 되었습니다. 그러므로 동일 출처, 다른 출처 모두 호출이 가능하게 되었다.</p>
<p>CORS 정책이 없고 모든 다른 출처 요청이 가능한 브라우저를 생각해보자.</p>
<p>홈페이지를 서핑하고 있는데, &lt;script&gt;가 심어진 evil.com 페이지를 열었다고 생각해보자. 
굉장히 유용한 정보를 담고 있는 사이트이지만, 페이지를 열면서 &lt;script&gt;가 실행되어 은행에 <code>Delete /account</code>를 요청하도록 되어 있다. AJAX 호출로 은행 API를 호출하여 나의 은행 계좌를 삭제해버리는 사고가 발생한다.
따라서, 다른 출처의 접근을 막기 위해서 동일 출처 정책이 등장하게 되었다.
<br></p>
<h3 id="동일-출처-정책same-origin-policy">동일 출처 정책(Same-Origin policy)</h3>
<p>동일 출처 정책(Same-origin policy)은 다른 출처로부터 조회된 자원들의 읽기 접근을 막아 다른 출처 공격을 예방한다. 
그러나, 다른 출처에서 얻은 이미지를 담는 &lt;img&gt;, 외부 주소를 담는 &lt;link&gt; 같은 여러 태그들을 허용한다. 동일 출처 정책의 정확한 구현 명세는 없지만 최신의 브라우저들은 일정 규칙을 따르고 있다.(RFC6454)</p>
<p>동일 출처 정책은 다른 출처 자원을 가져오는 것을 굉장히 제한적으로 허용한다.
따라서 다른 출처 리소스에 접근성을 높이기 위해서 CORS가 등장했다.
<br></p>
<h2 id="cors-접근제어에-사용되는-시나리오3가지">CORS 접근제어에 사용되는 시나리오(3가지)</h2>
<h3 id="1️⃣단순-요청simple-request">1️⃣단순 요청(Simple Request)</h3>
<p>Preflight 요청 없이 바로 요청을 보내며, 아래와 같은 조건을 만족해야한다.</p>
<ul>
<li>메서드 : GET, POST, HEAD</li>
<li>Content-Type은 아래 셋 중 하나여야 한다.<ul>
<li>application/x-www-form-urlencoded</li>
<li>multipart/form-data</li>
<li>text/plain</li>
</ul>
</li>
<li>헤더 : Accept, Accept-Language, Content-Language, Content-Type 만 허용 한다.<br></li>
</ul>
<h3 id="2️⃣사전-요청preflight-request">2️⃣사전 요청(Preflight Request)</h3>
<p>사전 요청은 OPTIONS 메서드를 통해 다른 도메인 리소스에 요청이 가능한지 확인하는 작업이다.
요청이 가능한 것을 확인하면 실제 요청을 보내게 된다.</p>
<h4 id="preflight-request">Preflight Request</h4>
<ul>
<li>origin : 어디서 요청을 했는지 서버에 알려주는 주소</li>
<li>access-control-request-method : 실제 요청이 보낼 HTTP 메서드</li>
<li>access-control-request-headers : 실제 요청에 포함된 header</li>
</ul>
<h4 id="preflight-response">Preflight Response</h4>
<ul>
<li>access-control-allow-origin : 서버가 허용하는 출처</li>
<li>access-control-allow-methods : 서버가 허용하는 HTTP 메서드 리스트</li>
<li>access-control-allow-headers : 서버가 허용하는 header 리스트</li>
<li>access-control-max-age : 프리 플라이트 요청의 응답을 캐시에 저장하는 시간</li>
</ul>
<blockquote>
<p>Preflight Response의 응답 코드는 200대여야하고 Body는 비어있는 것이 좋다.</p>
</blockquote>
<h3 id="3️⃣신용-요청credentialed-request">3️⃣신용 요청(Credentialed Request)</h3>
<p>인증 관련 헤더를 포함할 때 사용하는 요청으로, 쿠키, 인증 헤더, TLS 클라이언트 인증서 등의 신용정보와 함께 요청한다. 
기본적으로, CORS 정책은 다른 출처 요청에 인증정보 포함을 허용하지 않지만, 요청에 인증을 포함하는 플래그가 있거나 access-control-allow-credentials를 true로 설정 한다면 요청할 수 있다.</p>
<ul>
<li><p>클라이언트
쿠키 또는 JWT 토큰을 담아 보낼 경우 credentials : include 를 포함하여 보낸다.</p>
</li>
<li><p>서버
Access-Control-Allow-Credentials : true 로 설정해야 클라이언트의 인증 포함 요청에 허용이 가능하다.</p>
<br>

</li>
</ul>
<h2 id="cors-해결방법">CORS 해결방법</h2>
<h3 id="프론트-프록시-서버-설정">프론트 프록시 서버 설정</h3>
<p>프론트 서버에서 백엔드로 요청을 보낼 때, 대상의 URL을 변경한다.</p>
<h3 id="직접-헤더-설정">직접 헤더 설정</h3>
<p>직접 헤더에 설정을 추가한다.</p>
<h3 id="백엔드-설정spring-boot">백엔드 설정(Spring Boot)</h3>
<p>config 클래스를 만들고 CORS의 출처 및 설정 관리를 할 수 있다.
<br></p>
<h2 id="spring-boot에서-cors-설정하기">Spring Boot에서 CORS 설정하기</h2>
<p>Spring Security를 적용하는 경우엔 SecurityConfig 클래스에서 같이 설정해줄 수 있다.</p>
<pre><code class="language-java">@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf().disable();

    http.authorizeRequests()
        .antMatchers(&quot;/api/auth/**&quot;).permitAll()
        .anyRequest().authenticated();

    // 이 설정을 해주지 않으면 밑의 corsConfigurationSource가 적용되지 않는다.
    http.cors()
        .and()
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .apply(new JwtConfig(jwtUtil, om));

    return http.build();
}


@Bean
public CorsConfigurationSource corsConfigurationSource(){
    CorsConfiguration config = new CorsConfiguration();

    config.addAllowedOrigin(&quot;http://localhost:3000&quot;);

    config.addExposedHeader(JwtUtil.AUTHORIZATION_HEADER);

    config.addAllowedMethod(&quot;*&quot;);

    config.addAllowedHeader(&quot;*&quot;);

    config.setAllowCredentials(true);

    config.validateAllowCredentials();

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration(&quot;/**&quot;, config);

    return source;
}</code></pre>
<br>

<hr>
<p>📚참고
<a href="https://escapefromcoding.tistory.com/724">CORS란 무엇인가?</a>
<a href="https://velog.io/@frankle97/CORS%EB%9E%80">CORS란</a></p>
]]></description>
        </item>
    </channel>
</rss>