From 04780acc73893f9980a37b05cd9a1c820d9719c1 Mon Sep 17 00:00:00 2001
From: mooncw <97713997+mooncw@users.noreply.github.com>
Date: Tue, 30 Jan 2024 23:54:44 +0900
Subject: [PATCH 01/50] Create 2024-01-26-stomp-websocket-programing
---
_posts/2024-01-26-stomp-websocket-programing | 148 +++++++++++++++++++
1 file changed, 148 insertions(+)
create mode 100644 _posts/2024-01-26-stomp-websocket-programing
diff --git a/_posts/2024-01-26-stomp-websocket-programing b/_posts/2024-01-26-stomp-websocket-programing
new file mode 100644
index 0000000..cd9b2d0
--- /dev/null
+++ b/_posts/2024-01-26-stomp-websocket-programing
@@ -0,0 +1,148 @@
+---
+layout: post
+title: STOMP 웹소켓 프로그래밍
+author: 문찬욱
+categories: 기술세미나
+banner:
+ image: https://raw.githubusercontent.com/Kernel360/blog-image/main/2024/0126/thumb.jpg
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+ tags: [웹소켓, STOMP]
+---
+
+안녕하세요. 저는 STOMP 웹소켓 프로그래밍이라는 주제로 발표한 문찬욱입니다.
+
+저는 이번 프로젝트에서 채팅 기능을 구현하고 있는데요, 그 과정에서 사용한 기술에 대해 공유드리고자 이 주제를 선정했습니다.
+
+이 글에서 웹소켓이 무엇인지, http와 웹소켓의 차이점이 무엇인지, 웹소켓 동작 방식은 어떤지, STOMP이 무엇인지 알려드리고자 합니다.
+
+
+
+## 1. 웹소켓
+웹소켓은 http 환경에서 클라이언트와 서버 사이에 하나의 TCP 커넥션을 통해 실시간으로 전이중 통신을 가능하게 하는 프로토콜입니다.
+
+여기서 전이중 통신은 전화기처럼 양방향으로 송신과 수신이 가능한 통신을 뜻합니다.
+
+
+
+## 2. HTTP vs 웹소켓
+그럼 이러한 웹소켓과 HTTP와의 차이점은 무엇일까요?
+
+Http는 클라이언트가 요청을 보낼 때마다 연결을 맺고 응답을 받은 후 연결을 끊어버리기 때문에 비 연결성 프로토콜입니다.
+
+그리고 클라이언트가 요청하고 서버가 응답하는 단방향 통신입니다.
+
+반면에 웹소켓은 한번 연결을 맺으면 어느 한쪽에서 연결을 끊으라는 요청을 보내기 전까진 연결을 유지하기 때문에 연결 지향 프로토콜입니다.
+
+그리고 양 쪽에서 데이터를 주고 받을 수 있는 양방향 통신입니다.
+
+
+이미지1
+
+### 실시간 측면에서는...?
+http는 비 연결성이기 때문에 데이터를 주기 위해선 매번 연결해야 하고 그만큼 연결 비용이 발생하게 됩니다.
+
+즉, 오버헤드가 커집니다.
+
+이미지2
+
+위 이미지에서 왼쪽은 일반적인 http로 주고받는 데이터양이고, 오른쪽 위는 웹소켓 연결요청할 때의 데이터양이고, 그 아래는 연결 이후의 데이터양입니다.
+
+웹소켓은 처음 연결할 때 http로 하기 때문에 처음 데이터 양은 유사하지만, 이후 데이터 양이 매우 줄어든 것을 확인할 수 있습니다.
+
+이러한 점들에서 웹소켓이 http 보다 실시간성에 더 유리합니다.
+
+## 3. 웹소켓 동작 방식
+이미지3
+
+웹소켓의 동작 방식은 크게 3가지로 나눌 수 있는데요,
+
+빨간 박스는 Opening Handshake,
+
+노란 박스는 Data transfer,
+
+보라 박스는 Closing Handshake에 해당됩니다.
+
+### Opening Handshake
+이미지4
+
+빨간 박스 부분인 Opening Handshake는 먼저 웹소켓 클라이언트에서 http 프로토콜을 통해 웹소켓으로 Upgrade 해달라는 요청을 보냅니다.
+
+이 요청의 의미는 웹소켓 프로토콜로 전환해달라는 것입니다.
+
+그 다음 웹소켓 서버는 101 응답과 함께 웹소켓 프로토콜로의 전환을 승인했음을 알립니다.
+
+### Data Transfer
+이미지5
+
+노란 박스 부분인 Data Transfer는 Opening Handshake가 끝나서 전환된 웹소켓 프로토콜을 통해 클라이언트와 서버 간 실시간 전이중 통신을 하는 부분입니다.
+
+### Closing Handshake
+이미지6
+
+보라 박스 부분인 Closing Handshake는 서로 간의 커넥션을 종료하는 부분입니다.
+
+## 4. STOMP
+STOMP는 streaming text oriented messaging protocol의 줄임말이며,
+
+메세지 브로커를 활용하여 쉽게 메시지를 주고 받을 수 있는 프로토콜입니다.
+
+이 프로토콜은 웹소켓 위에 얹어 하위 프로토콜로 함께 사용할 수 있습니다.
+
+### 웹소켓만 사용하는 것 비해 어떤 이점이...?
+웹소켓 프로토콜은 메시지 데이터 타입이 Text인지 Binary인지는 정의하지만, 메시지 내용에 대해서는 정의하지 않습니다.
+
+이는 복잡한 메시지를 주고 받으려면 어떤 메시지인지 알기 위한 로직이 필요하다는 것입니다.
+
+STOMP 프로토콜은 메시지 내용을 구조화 할 수 있어서 효과적인 메시징을 도와줍니다.
+
+예를 들어, A라는 사람이 B라는 사람에게 “안녕”이라는 내용으로 보내는 메시지가 있다고 해보겠습니다.
+
+웹소켓로 보낼 때는 “안녕”이라는 메시지만 보내면 됩니다.
+
+클라이언트가 1명이라면 문제가 없지만, 클라이언트가 여러명이라면, 이 메시지를 누가 보냈는지, 누구한테 가야하는지, 어떤 용도로 보내는 것인지 서버가 알 수가 없습니다.
+
+물론, 단순히 안녕이 아닌 모든 정보가 담긴 한줄의 긴 텍스트 문자열로 보낼 수 있습니다.
+
+하지만 이러면, 서버가 이 메시지를 이해하고 처리하기 쉽지 않을 수 있습니다.
+
+또한 연결된 클라이언트 주소마다 메시지 핸들러를 구현해야 합니다.
+
+이미지7
+
+STOMP는 이미지처럼
+
+destination /app/chat/message로 보내는,
+sender A가,
+
+content “안녕”의 내용의 메시지를,
+
+send 전송했음을
+
+구조화 된 형태로 보낼 수 있기 때문에 서버는 이 메시지가 어떤 메시지인지 이해하고 처리하기 쉽습니다.
+
+또 다른 이점은 STOMP는 pub/sub 구조로 되어있다는 것입니다.
+
+이미지8
+
+pub/sub 구조란 이 이미지처럼 publisher에서 메시지 브로커의 Topic1이라는 특정 토픽에 메시지를 보내면, Topic1을 구독하고 있는 subscribe들에게 메세지를 전달하는 구조를 말합니다.
+
+이 구조로 인해 최대 토픽별로만 메시지 핸들러를 구현해주면 되기 때문에 웹소켓로만 구성된 것에 비해 메시지 핸들러 구현 양이 줄어든다는 이점이 있습니다.
+
+### pub/sub 구조의 특징
+저는 pub/sub 구조의 특징을 크게 3가지로 나눠볼 수 있었습니다.
+
+첫째, pub과 sub을 쉽게 추가할 수 있어서 확장성이 좋습니다.
+
+둘째, pub과 sub 간에 강한 의존성이 없어서 비동기적으로 처리할 수 있습니다.
+
+셋째, sub은 관심 토픽에 대한 메시지만 받을 수 있어서 선택적 수신이 가능합니다.
+
+
+
+## 5. 마무리
+채팅, 실시간 업데이트, 알림 같은 실시간성 기능을 구현하고자 하면,
+
+STOMP도 선택지 중 하나라고 생각합니다.
From 9527940e0bcd793cfb069b796e055d29f233dd57 Mon Sep 17 00:00:00 2001
From: mooncw <97713997+mooncw@users.noreply.github.com>
Date: Mon, 5 Feb 2024 23:24:51 +0900
Subject: [PATCH 02/50] Update 2024-01-26-stomp-websocket-programing
---
_posts/2024-01-26-stomp-websocket-programing | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/_posts/2024-01-26-stomp-websocket-programing b/_posts/2024-01-26-stomp-websocket-programing
index cd9b2d0..16505bf 100644
--- a/_posts/2024-01-26-stomp-websocket-programing
+++ b/_posts/2024-01-26-stomp-websocket-programing
@@ -38,15 +38,14 @@ Http는 클라이언트가 요청을 보낼 때마다 연결을 맺고 응답을
그리고 양 쪽에서 데이터를 주고 받을 수 있는 양방향 통신입니다.
-
-이미지1
+![1](https://github.com/Kernel360/blog/assets/97713997/2d25b3e0-d31f-426b-b69d-001cbcf00d3a)
### 실시간 측면에서는...?
http는 비 연결성이기 때문에 데이터를 주기 위해선 매번 연결해야 하고 그만큼 연결 비용이 발생하게 됩니다.
즉, 오버헤드가 커집니다.
-이미지2
+![2](https://github.com/Kernel360/blog/assets/97713997/580a3e5c-29bc-429e-85c5-8e248e4db002)
위 이미지에서 왼쪽은 일반적인 http로 주고받는 데이터양이고, 오른쪽 위는 웹소켓 연결요청할 때의 데이터양이고, 그 아래는 연결 이후의 데이터양입니다.
@@ -55,7 +54,7 @@ http는 비 연결성이기 때문에 데이터를 주기 위해선 매번 연
이러한 점들에서 웹소켓이 http 보다 실시간성에 더 유리합니다.
## 3. 웹소켓 동작 방식
-이미지3
+![3](https://github.com/Kernel360/blog/assets/97713997/344e5c48-0ead-40f7-bc5c-bc3a9b3f4c4b)
웹소켓의 동작 방식은 크게 3가지로 나눌 수 있는데요,
@@ -66,7 +65,7 @@ http는 비 연결성이기 때문에 데이터를 주기 위해선 매번 연
보라 박스는 Closing Handshake에 해당됩니다.
### Opening Handshake
-이미지4
+![4](https://github.com/Kernel360/blog/assets/97713997/5995bac3-ca2c-4ad7-83d0-ad1d5cce8ad8)
빨간 박스 부분인 Opening Handshake는 먼저 웹소켓 클라이언트에서 http 프로토콜을 통해 웹소켓으로 Upgrade 해달라는 요청을 보냅니다.
@@ -75,12 +74,12 @@ http는 비 연결성이기 때문에 데이터를 주기 위해선 매번 연
그 다음 웹소켓 서버는 101 응답과 함께 웹소켓 프로토콜로의 전환을 승인했음을 알립니다.
### Data Transfer
-이미지5
+![5](https://github.com/Kernel360/blog/assets/97713997/61f2f6b2-c9e7-4436-ba0c-34a75d78e5bb)
노란 박스 부분인 Data Transfer는 Opening Handshake가 끝나서 전환된 웹소켓 프로토콜을 통해 클라이언트와 서버 간 실시간 전이중 통신을 하는 부분입니다.
### Closing Handshake
-이미지6
+![6](https://github.com/Kernel360/blog/assets/97713997/50c700a8-ff7f-4b4a-a5a3-635d0d016a11)
보라 박스 부분인 Closing Handshake는 서로 간의 커넥션을 종료하는 부분입니다.
@@ -110,7 +109,7 @@ STOMP 프로토콜은 메시지 내용을 구조화 할 수 있어서 효과적
또한 연결된 클라이언트 주소마다 메시지 핸들러를 구현해야 합니다.
-이미지7
+![7](https://github.com/Kernel360/blog/assets/97713997/527a4717-9c58-4402-8441-9c4ae7455555)
STOMP는 이미지처럼
@@ -125,7 +124,7 @@ send 전송했음을
또 다른 이점은 STOMP는 pub/sub 구조로 되어있다는 것입니다.
-이미지8
+![8](https://github.com/Kernel360/blog/assets/97713997/23a3e3f0-b8f9-4156-a15a-76bf8cef85bf)
pub/sub 구조란 이 이미지처럼 publisher에서 메시지 브로커의 Topic1이라는 특정 토픽에 메시지를 보내면, Topic1을 구독하고 있는 subscribe들에게 메세지를 전달하는 구조를 말합니다.
From 10a3799276dbfb31fc416674a9053b11339ea844 Mon Sep 17 00:00:00 2001
From: mooncw <97713997+mooncw@users.noreply.github.com>
Date: Mon, 5 Feb 2024 23:29:17 +0900
Subject: [PATCH 03/50] =?UTF-8?q?feat:=2020240126=5Fstomp=20=EC=9B=B9?=
=?UTF-8?q?=EC=86=8C=EC=BC=93=20=ED=94=84=EB=A1=9C=EA=B7=B8=EB=9E=98?=
=?UTF-8?q?=EB=B0=8D=5F=EB=AC=B8=EC=B0=AC=EC=9A=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...socket-programing => 2024-01-26-stomp-websocket-programing.md} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename _posts/{2024-01-26-stomp-websocket-programing => 2024-01-26-stomp-websocket-programing.md} (100%)
diff --git a/_posts/2024-01-26-stomp-websocket-programing b/_posts/2024-01-26-stomp-websocket-programing.md
similarity index 100%
rename from _posts/2024-01-26-stomp-websocket-programing
rename to _posts/2024-01-26-stomp-websocket-programing.md
From c0d49d1d2b77cdc05bd98b52fdf1da9717cd502b Mon Sep 17 00:00:00 2001
From: AN-SOHYEON
Date: Sun, 11 Feb 2024 14:39:22 +0900
Subject: [PATCH 04/50] Chore: Create auto-assign-pr-reviewer.yml
---
.github/workflows/auto-assign-pr-reviewer.yml | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 .github/workflows/auto-assign-pr-reviewer.yml
diff --git a/.github/workflows/auto-assign-pr-reviewer.yml b/.github/workflows/auto-assign-pr-reviewer.yml
new file mode 100644
index 0000000..c1c23b9
--- /dev/null
+++ b/.github/workflows/auto-assign-pr-reviewer.yml
@@ -0,0 +1,16 @@
+name: "Assign Reviewers to PR"
+
+on:
+ pull_request:
+ types: [opened, ready_for_review, reopened, review_requested, review_request_removed]
+
+jobs:
+ assign-pr-reviewers:
+ runs-on: ubuntu-latest
+ steps:
+ - name: "Assign Reviewers to PR"
+ uses: itsOliverBott/assign-pr-reviewers@release
+ with:
+ token: ${{ secrets.TOKEN }}
+ users: "anso33" # comma-separated (example: "itsOliverBott, SantaClaus, b4tman, sp0derman")
+ ignore-drafts: true # defaults to false if not provided
From cfa7a1b079b872f9be98d731f831408da4a7305b Mon Sep 17 00:00:00 2001
From: anso33
Date: Sun, 11 Feb 2024 14:58:27 +0900
Subject: [PATCH 05/50] Chore: update auto-assign-reviewers
---
.github/auto_assign.yml | 11 +++++++++++
.github/workflows/auto-assign-pr-reviewer.yml | 11 ++++-------
2 files changed, 15 insertions(+), 7 deletions(-)
create mode 100644 .github/auto_assign.yml
diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml
new file mode 100644
index 0000000..54ac9f0
--- /dev/null
+++ b/.github/auto_assign.yml
@@ -0,0 +1,11 @@
+addReviewers: true
+
+
+addAssignees: author
+
+
+reviewers:
+ - anso33
+
+
+numberOfReviewers: 1
\ No newline at end of file
diff --git a/.github/workflows/auto-assign-pr-reviewer.yml b/.github/workflows/auto-assign-pr-reviewer.yml
index c1c23b9..5aa86ae 100644
--- a/.github/workflows/auto-assign-pr-reviewer.yml
+++ b/.github/workflows/auto-assign-pr-reviewer.yml
@@ -1,4 +1,4 @@
-name: "Assign Reviewers to PR"
+name: "Assign Reviewer"
on:
pull_request:
@@ -8,9 +8,6 @@ jobs:
assign-pr-reviewers:
runs-on: ubuntu-latest
steps:
- - name: "Assign Reviewers to PR"
- uses: itsOliverBott/assign-pr-reviewers@release
- with:
- token: ${{ secrets.TOKEN }}
- users: "anso33" # comma-separated (example: "itsOliverBott, SantaClaus, b4tman, sp0derman")
- ignore-drafts: true # defaults to false if not provided
+ - uses: kentaro-m/auto-assign-action@v1.2.4
+ with:
+ configuration-path: ".github/auto_assign.yml"
From 691c22c0820af3d20c3a7f8458e7ec299a2d0ae6 Mon Sep 17 00:00:00 2001
From: isevou__
Date: Tue, 13 Feb 2024 00:46:45 +0900
Subject: [PATCH 06/50] =?UTF-8?q?feat=20:=2020240125=5F=EC=BD=94=EB=94=A9?=
=?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=5F=EA=B3=A0=EB=B3=91=EB=A3=A1.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_posts/2023-01-25-coding-test.md | 94 ++++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 _posts/2023-01-25-coding-test.md
diff --git a/_posts/2023-01-25-coding-test.md b/_posts/2023-01-25-coding-test.md
new file mode 100644
index 0000000..7420b66
--- /dev/null
+++ b/_posts/2023-01-25-coding-test.md
@@ -0,0 +1,94 @@
+---
+layout: post
+title: 주저하는 개발자들을 위해 - 코딩 테스트
+author: 고병룡
+categories: 기술세미나
+banner:
+ image: https://docs.oracle.com/cd/E19340-01/820-6424/images/to_MOM.gif
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+ tags: [코딩테스트, 기술세미나]
+---
+
+## 코딩 테스트?
+코딩 테스트란 개발자의 기술적인 역량을 시험하기 위해 실시하는 알고리즘이나 구현을 요구하는 테스트입니다.
+
+회사 입장에서는 지원자를 평가하는 최소한의 기준이고 지원자에게는 ~~통곡의 벽~~ 처럼 느껴지는 코딩 테스트 대체 왜 해야할까?
+
+그리고 또 어떻게 준비해야만 할까..?
+
+## 코딩 테스트 그래서 왜 해야하나?
+무엇보다도, 많은 회사들이 코딩테스트를 1차적인 관문으로 두고 지원자를 거르고 있기 때문에 그런 회사들에 지원할 생각이 있다면 꾸준히 준비하는 게 좋다.
+
+> 아래 4가지 이유를 통해서 조금 더 자세히 알아보자면..
+
+* 여러분들이 가고 싶어하는 많은 회사에는 정말 많은 지원자가 몰린다. 이들 개개인의 모든 역량을 테스트하기에는 현실적으로 무리가 있고, 이 과정에서 코딩 테스트는 효율적으로 이들을 가려내는데 도움이 되기 때문에 많은 기업들이 도입한다.
+* 여러분들이 어떤 식으로 코드를 작성하는지 미리 확인하고 어떤 사고 방식과 결론, 평소 개발을 어떻게 하는지 엿볼 수 있는 창구와 비슷하다. 자신이 어떤 개발자인지 비교적 손 쉽게 다른 개발자들에게 보여줄 수 있다.
+* 개발에 필요한 지식들을 보여주고 나의 컴퓨터 과학 지식을 기반으로 한 나의 문제 해결력을 보여주기 쉽다. 결국 알고리즘 문제를 구현한다는 건 그 문제를 이해해야만 할 수 있는 거고, 그에 맞는 알고리즘을 찾고 시간 내에 테스트 케이스들을 통과시켜야 하기 때문에, 비교적 쉽게 내 문제 해결 능력을 보여줄 수 있다.
+* 개발자는 자주,, 생각보다 자주 이직이라는 카드를 꺼내든다.. 이직할 때 코테 준비를 하지말고,, 항상 이직이라는 카드를 꺼낼 수 있도록 언제든 코테를 준비를 할 필요가 있다.
+
+## [당신이 코딩테스트를 포기하는 7가지 이유](https://www.inflearn.com/course/%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%B7%A8%EC%97%85-%ED%86%B5%ED%95%A9%ED%8E%B8)
+아래의 7가지 이유는 [한정수님](https://github.com/Integerous)의 [비전공자를 위한 개발자 취업 가이드](https://www.inflearn.com/course/%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%B7%A8%EC%97%85-%ED%86%B5%ED%95%A9%ED%8E%B8)의 내용에서 가져온 개발자들이 코테를 포기하는 7가지 이유이다.
+
+가져온 이유들에는 각각 논리적인 허점이 존재하고 우리는 같이 그것을 깨부수고 코딩테스트를 준비하기 위한 마음가짐을 잡아 보도록 하자.
+
+>1. 코딩 테스트를 보는 회사에는 어차피 서류 합격도 못할 것이다.
+
+아니다. 서류만 내도 코테를 보게 해주는 회사가 많고 “서류”도 영향이 있지만 “테스트 결과” 도 영향이 있다.
+> 2. 코딩 테스트를 준비할 시간이 없다.
+
+분명히 당신의 하루에는 낭비되는 시간이 있다. 그 시간을 찾아서 하자. 코딩 테스트 준비 뿐만아니라 다른 공부도 마찬가지다..
+> 3. 지금부터 준비하더라도, 더 오래 준비한 전공자들에게 밀릴 것이다.
+
+체육 전공한 사람이 마라톤을 더 잘 뛸까? 아니면 일반인이 더 잘 뛸까? 확률은 전자가 높겠지만 거의 비슷하게 힘들다. 전공자들이라고 해서 코테가 쉽고 뚝딱 풀리는 일은 아니다.
+> 4. Java(언어), Spring(프레임워크)도 제대로 못하는데 무슨 코딩 테스트?
+
+코딩 테스트라도 제대로 해야지 면접은 볼 수 있지 않을까? 물론 둘 다 잘하면 정말 좋고 그것도 아니라면 면접에 들어갈 수 있는 실력이 된다는 것 자체로도 의미가 있다고 생각한다. 코테를 볼 기회는 항상 찾아오는게 아니니...
+> 5. 코딩 테스트 안봐도 개발로 취업은 하더라.
+
+당연히 할 수 있다. 하지 않는 기업을 찾아서 지원하면 된다. 하지만 차라리 코테를 준비하고 더 많은 기회를 얻는게 맞지 않나 라는 생각이 든다.
+>6. 조금 해봤는데, 너무 어렵다.
+
+착각하는 분들이 있는데 우리는 대회를 나가자고 하는 게 아니다. 코테를 쳐보는 것만으로도 소중한 자산이다. 이걸로 상을 타는 게 아니라 우리는 취업이 목적이기에....
+>7. 어떻게 준비해야 될지 모르겠다.
+
+그러면 이제부터 알아보자! 만약 필자가 뭐하는 사람인지 의심이 간다면.. 그래도 나름 [열심히(?)](https://solved.ac/profile/hodako97) 준비해오고 [알고리즘을 좋아하고](https://github.com/fingersdanny/PS_note), [알고리즘 스터디](https://github.com/Kernel360-cell1/algorithm-study)를 운영 중인 사람 중 하나로써 여러분들이 코테에서 더 행복해지길 바라는 마음에서 준비했다.
+
+## 코딩테스트 어떻게 준비해야 할까?
+
+### 1. 알고리즘 / 자료구조를 배우자
+
+코딩 테스트에 나오는 문제는 다양한 배경 지식을 요구하고 그 중 만나게 되는 대부분은 자료 구조와 다양한 알고리즘이다.
+
+따라서, 무턱대고 문제를 풀기위해 접근 하는 것보다는 미리 아래의 자료구조와 알고리즘과 친숙해진 이후로 풀어보길 시작하는 것을 권장한다..
+
+그 중에 보편적으로 활용되는 자료 구조와 알고리즘은 다음과 같다.
+
+#### 자료구조
+* 배열 (Array)
+* 리스트 (List)
+* 연결 리스트 (LinkedList)
+* 스택 (Stack)
+* 큐 (Queue)
+* 덱 (Deque)
+* 우선순위 큐 (Priority Queue), 힙 (Heap)
+* 트리 (Tree), 이진 트리(Binary Tree)
+* 그래프 (Graph)
+* 세트 (Set)
+* 맵 (Map)
+
+
+
+
+## 참고 자료
+[Kafka와 RabbitMQ의 차이점은 무엇인가요?](https://aws.amazon.com/ko/compare/the-difference-between-rabbitmq-and-kafka/)
+
+[Apache Kafka란 무엇입니까?](https://aws.amazon.com/ko/what-is/apache-kafka/)
+
+[Apache ActiveMQ](https://activemq.apache.org/)
+
+[메시지 큐란?](https://www.ibm.com/kr-ko/topics/message-queues)
+
+[Pub/Sub이란 무엇인가요?](https://cloud.google.com/pubsub/docs/overview?hl=ko)
From e0ca87f47d026a898adaabdb842d413179425492 Mon Sep 17 00:00:00 2001
From: Byungryong Ko
Date: Wed, 14 Feb 2024 13:12:07 +0900
Subject: [PATCH 07/50] =?UTF-8?q?chore=20:=20=EA=B8=80=20=EB=82=B4?=
=?UTF-8?q?=EC=9A=A9=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_posts/2023-01-25-coding-test.md | 67 +++++++++++++++++++++++++++++---
1 file changed, 61 insertions(+), 6 deletions(-)
diff --git a/_posts/2023-01-25-coding-test.md b/_posts/2023-01-25-coding-test.md
index 7420b66..dc5b74c 100644
--- a/_posts/2023-01-25-coding-test.md
+++ b/_posts/2023-01-25-coding-test.md
@@ -13,7 +13,7 @@ banner:
---
## 코딩 테스트?
-코딩 테스트란 개발자의 기술적인 역량을 시험하기 위해 실시하는 알고리즘이나 구현을 요구하는 테스트입니다.
+코딩 테스트란 개발자의 기술적인 역량을 시험하기 위해 실시하는 알고리즘이나 구현을 요구하는 테스트다.
회사 입장에서는 지원자를 평가하는 최소한의 기준이고 지원자에게는 ~~통곡의 벽~~ 처럼 느껴지는 코딩 테스트 대체 왜 해야할까?
@@ -78,17 +78,72 @@ banner:
* 그래프 (Graph)
* 세트 (Set)
* 맵 (Map)
+* 서로소 집합 (Disjoint Set / Union Find)
+> 위에 있는 자료 구조들을 모두 아는 편이 좋은가요?
+위 자료 구조들은 기술 면접 때도 자주 만날 수 있으니 말로 설명할 수 있을 만큼 알아 두는 편이 좋다. 당연히 문제를 만났을 때 위의 자료구조를 각 프로그래밍 언어별로 어떤 식으로 사용할 수 있는지도 알아두어야 문제에 적용할 수 있다.
+
+#### 알고리즘
+* 그리디 (Greedy)
+* 동적 계획법 (Dynamic Programming) : 메모이제이션...
+* 다양한 정렬 알고리즘 : 버블, 선택, 삽입, 병합, 힙, 퀵
+* 탐색 알고리즘
+ * 깊이 우선 탐색 (DFS)
+ * 너비 우선 탐색 (BFS)
+ * 이진 탐색
+ * 매개 변수 탐색
+ * 트리에서의 탐색 : 힙 트리, 트라이(Trie)
+* 크루스칼 알고리즘 (최소 신장 트리)
+* 백트래킹
+* 최단 경로 : 다익스트라, 벨만-포드, 플로이드-워셜
+* 완전 탐색 (Bruteforcing)
+
+> 알고리즘과 마찬가지로 위에 있는 내용들도 전부는 아니지만 말로 설명할 수 있어야 한다.
+
+> 알고리즘 공부를 시작하고 싶은데 어디서부터 보는게 좋을까요?
+
+개인적으로 방법은 중요하다고 생각하지 않고 꾸준히 보는게 더 낫다고 생각하지만 그래도 몇 가지 강의 및 책을 추천해보자면,
+
+[이것이 코딩 테스트다](https://product.kyobobook.co.kr/detail/S000001810273?utm_source=google&utm_medium=cpc&utm_campaign=googleSearch&gad_source=1&gclid=EAIaIQobChMIutbEu_OphAMVE1cPAh1V2A1hEAAYASAAEgLDevD_BwE)
+
+[BaaaaaaaarkingDog님의 실전 알고리즘 강좌](https://blog.encrypted.gg/919)
+
+
+### 2. 꾸준히 풀자
+
+너무나도 당연한 말이지만 생각보다 코딩 테스트는 언제든 볼 수 있게끔 준비를 해놓는 상태가 훨씬 좋다고 생각한다. 꾸준히 준비하지 않으면 실력이 떨어지는 속도는 가파르지만 실력을 올리는 속도는 생각보다 더 걸릴 수 있다.
+
+따라서 사람들이 자주 사용하고, 실제 코딩 테스트 환경에 가까운 곳에서 자주 문제를 풀어보기를 권장한다.
+
+* [프로그래머스](https://school.programmers.co.kr/learn/challenges?order=recent) : 많은 기업들의 코딩 테스트를 진행해주고 있고 문제도 꾸준히 올라온다. 카카오 등의 기업 공채에서의 기출 문제 또한 제공하고 있다.
+* [SW Expert Academy](https://swexpertacademy.com/main/main.do) : 삼성에서 운영하는 코딩테스트 및 알고리즘 학습 사이트이다. 삼성 관련 (반기 마다 열리는 알고리즘 특강, 입사 시 코딩 테스트)가 모두 여기에서 요구하는 문제 입출력 방식이나 라이브러리를 어떤 것을 사용할 수 있는지 까지 미리 알고 준비할 수 있다.
+* [Baekjoon Online Judge](https://www.acmicpc.net/) : 다양한 문제를 제공하고 삼성 SW 역랑 기출 문제를 제공하고 있다. 압도적인 문제 수와 유저 수로 인해 문제를 풀지 못했을 때 물어볼 곳이 더 많다는 이점이 있다.
+
+개인적으로는 백준을 제일 좋아하고 애용한다. 꾸준히 풀기를 지키기 위해서는 나름의 보상이 필요하다고 생각하는데.. 필자는 꾸준히 풀기 위해 코딩 테스트를 나름의 게임이라고 생각하여 위 백준 사이트와 연동되는 [solved.ac](https://solved.ac/)를 활용하여 꾸준히 잔디 심기(?) 및 랭크를 통해서 코딩 테스트를 준비중이다.
+
+### 3. 실제로 구현하기 전에 어떻게 구현할 지 손으로 적어보자
+
+아는 문제가 나와서 구현부터 할 생각할지 말고 무엇부터 어떻게 구현할지 생각해보고 문제 풀이를 작성해보자.
+
+ 1. 요즘 코딩 테스트에 나오는 문제들은 설명이 길다. 미리 순서를 정해두지 않고 구현만 하다가 보면 중간에 갈 길을 잃기 쉽고 문제 설명 중 어디까지 구현했는지 추적할 수가 없다. 결국 다시 되돌아가서 문제를 읽어야 할 수 도 있다. 처음부터 모든 상황을 본인의 언어로 정리해둔다면, 헷갈릴 이유도 없고 본인이 어디까지 구현했는 지 추적이 가능하다.
+ 2. 대부분의 코딩 테스트는 펜과 종이를 허용한다. 이걸 준비하라고 하는 이유는 써서 고민해봐도 좋다는 얘기고 이것을 활용하지 않을 이유가 없다!
+ 3. 많은 수의 기업이 코딩 테스트에 대한 기출문제를 제공하지 않는다. 따라서 직접 적어 놓은 문제 구현 계획을 보고 나서 나중에 복기할 수 있도록 한다.
+
+### 4. 시간 분배를 잘하자.
+
+1. 문제를 풀기 전에 시간 복잡도 계산을 해보고 올바른 알고리즘을 골랐는지 생각해보자. 보수적으로 생각했을 때 연산이 1억번을 1초라 가정하면 대부분의 문제에서 시간 초과를 받지 않을 수 있다. 어떤 알고리즘을 사용할지 입력의 최대 범위는 어디까지인지 시간은 얼마나 주어졌는지를 복합적으로 고려해보고 문제를 풀어야 한다.
+2. 실제 시험도 마찬가지지만 문제 당 시간 분배가 중요하다. 최악의 경우 2시간 내에 4문제를 풀어야할 수도 있고 그거 보다 길거나 짧을 수 있다. 평균적으로 실전에서는 40분 ~ 1시간이 주어진다고 생각하고 문제를 접근해야 테스트 중 시간이 모잘라서 문제를 포기하는 불상사를 겪지 않을 수 있다.
+3. 여느 시험을 볼 때와 마찬가지로 너무 오래 걸리는 문제만 붙잡고 있지 말아야 한다. 모든 답안을 다 들고 시험장에 갈 수 없듯이 코딩테스트도 못 푸는 문제가 있을 수 있다. 그럴 땐 넘기고 시간이 남을 때 돌아보는게 정신건강에 훨씬 더 좋다.
+4. 앞의 내용의 연장선에서 대부분의 코딩테스트는 순서대로 풀지 않아도 된다. 처음에 문제를 받는다면 쭉 훑어보고 해당 문제의 알고리즘이 바로 보이거나 구현이 오래 걸리지 않을 것 같은 문제들을 빨리 풀고 시간을 아끼는 게 좋다!
## 참고 자료
-[Kafka와 RabbitMQ의 차이점은 무엇인가요?](https://aws.amazon.com/ko/compare/the-difference-between-rabbitmq-and-kafka/)
+이것이 코딩 테스트다
-[Apache Kafka란 무엇입니까?](https://aws.amazon.com/ko/what-is/apache-kafka/)
+[개발자 취업을 위한 코딩 테스트 준비 방법](https://katfun.tistory.com/192)
-[Apache ActiveMQ](https://activemq.apache.org/)
+[알고리즘 분류 참고 - 백준 온라인 저지 알고리즘 별 문제 분류](https://www.acmicpc.net/problem/tags)
-[메시지 큐란?](https://www.ibm.com/kr-ko/topics/message-queues)
-[Pub/Sub이란 무엇인가요?](https://cloud.google.com/pubsub/docs/overview?hl=ko)
+헤더 이미지 붙이고 글 내용 읽고 수정해서 오늘 업로드 할 것
\ No newline at end of file
From 2bd1aaa41098e5b0feb25ffc39193c2ff678efb0 Mon Sep 17 00:00:00 2001
From: gunsight <103917282+gunsight1@users.noreply.github.com>
Date: Wed, 14 Feb 2024 14:21:26 +0900
Subject: [PATCH 08/50] Create 2023-12-01-RDBMS.md
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RDBMS의 조회과정, 쿼리실행계획 중요성
---
_posts/2023-12-01-RDBMS.md | 192 +++++++++++++++++++++++++++++++++++++
1 file changed, 192 insertions(+)
create mode 100644 _posts/2023-12-01-RDBMS.md
diff --git a/_posts/2023-12-01-RDBMS.md b/_posts/2023-12-01-RDBMS.md
new file mode 100644
index 0000000..d2ab64d
--- /dev/null
+++ b/_posts/2023-12-01-RDBMS.md
@@ -0,0 +1,192 @@
+# RDBMS의 조회과정, 쿼리실행계획 중요성
+
+반갑습니다.
+RDBMS와 쿼리실행계획의 중요성을 주제로 기술세미나 발표를 한 정지용 입니다.
+
+## [1. 개요]
+
+요즘 자바와 ORM을 기반으로 개발을 하게되어 직접적으로 쿼리를 보는 일이 예전보다 현저히 줄어들었다고는 하나 아직도 데이터가 저장되는 저장소는 대부분 데이터베이스입니다.
+
+결국 그 말은 즉슨 아무리 데이터베이스에 의존을 최소화 하더라도 어쩔 수 없이 데이터베이스에 대해 잘 알아야 한다는 이야기이기도 합니다.
+
+이번 시간에는 RDBMS에서 다양한 기능을 많이 지원하지만 가장 많이 쓰이는 조회과정과 이와 연관되어있는 쿼리실행계획의 중요성을 알아보는 시간을 가져보고자 합니다.
+
+
+
+## [2. RDBMS란?]
+
+진행하기 앞서, 데이터베이스(Database, 이하 DB)란 무엇일까요?
+
+짧고 명료하게 이야기 하자면 집합과 명제를 근간으로 하는 체계적인 데이터 모음입니다.
+
+RDBMS (관계형 데이터베이스 관리 시스템 :: Relational Database Management System)는 이름에서도 유추가 되듯 데이터베이스의 관리 시스템입니다.
+
+이 RDBMS에선 보통 일반적으로 4가지의 명령어를 지원합니다.
+
+![스크린샷 2024-02-14 134256](https://github.com/gunsight1/blog/assets/103917282/11ceddc9-60fb-4723-a7ca-551c4b1b8916)
+
+DDL(Data Definition Language)은 데이터 정의어로 DB 구조를 정의하거나 변경하는데 쓰입니다.
+
+DML(Data Manipolation Language)은 데이터 조작어로 등록(insert) 조회(select) 수정(update) 삭제(delete)를 수행합니다.
+
+DCL(Data Control Language)은 데이터 제어어로 DB에 접근하는 사용자의 권한관리를 담당합니다.
+
+TCL(Trangection Control Language)은 트랜잭션 제어어로 작업수행의 대한 승인(commit), 철회(rollback)을 담당합니다.
+
+이 중 우리가 알아볼 명령어는 DML에 속하는 SELECT이며 DBA가 아닌 이상 우리같은 개발자는 보통 DML과 TCL을 세트로 많이 사용합니다.
+
+DML의 가장 큰 특징은 DDL과 다르게 수행을 한 뒤 데이터가 즉시 DB에 반영되지 않으므로 TCL을 통해 최종 수행여부를 결정 해야합니다.
+
+
+
+## [3. SELECT의 조회 과정]
+
+DBMS의 명령어는 직관적인 편이며 SELECT의 문법도 이와 마찬가지입니다.
+
+SELECT, 선택한다. 무엇을? 컬럼을.
+
+FROM, 어디로부터? TABLE에서
+
+WHERE, 어떤 기준으로? 조건에 따라
+
+GROUP BY 어떻게 묶어? 컬럼에 맞춰서
+
+HAVING 어떤 기준으로? 조건에 따라
+
+ORDER BY 정렬은? 오름차순 / 내림차순
+
+![스크린샷 2024-02-14 140524](https://github.com/gunsight1/blog/assets/103917282/0f5afa37-bd98-4b8a-82be-bc114ded1634)
+
+위의 이미지에서 노란 박스안의 문법들은 옵션을 의미합니다.
+
+옆의 예제 SQL문법이 한눈에 읽히신다면 여러분들은 SELECT 쿼리를 쓸 줄 아시게 된겁니다.
+
+문법을 알아보았으니 이제 실행 과정을 살펴볼건데 이해하기 쉽게 뷔페에서 요리 담는 것으로 비유를 해봤습니다.
+
+
+![스크린샷 2024-02-14 135018](https://github.com/gunsight1/blog/assets/103917282/e1886f5e-e50f-40d4-bb41-ac05ec3092bd)
+
+FROM → 뷔페에 모든 요리들이 잔뜩 있는 상태입니다.
+
+WHERE → 내가 먹고 싶은 음식을 생각해봅시다.
+
+GROUP BY → 에피타이저, 메인, 디저트처럼 종류에 따라 나눠봅니다.
+
+HAVING → 나눈 음식중에 생각해보니 국수랑 튀김은 아니다 싶어 빼기로 했어요.
+
+SELECT → 이제 먹을 음식을 다 골랐고, 접시에 담았습니다.
+
+ORDER BY → 이 음식을 순서대로 먹습니다.
+
+결과로 보면 아래와 같은 이미지처럼 흐르게됩니다.
+
+
+![스크린샷 2024-02-14 135025](https://github.com/gunsight1/blog/assets/103917282/6c386616-902b-4bc5-98b6-f6b26c15b2e8)
+
+
+
+## [4. SELECT의 활용]
+
+SELECT는 활용도가 아주 높은 DML이고, 서브쿼리(sub-query)라는 특별한 기능을 제공합니다.
+
+서브쿼리란 쿼리 안에 또 쓰이는 다른 쿼리를 뜻합니다.
+
+DML에선 포괄적으로 쓰일 수 있고, DDL과의 혼용도 일부 지원을 합니다.
+
+대표적으로 자주 쓰이는 응용 3가지를 예시로 설명드리겠습니다.
+
+![스크린샷 2024-02-14 135158](https://github.com/gunsight1/blog/assets/103917282/b4ccc05d-aa38-43ce-8b59-ffce7fab0183)
+
+첫째로 백업, CREATE 명령어와 조합하면 테이블 백업으로도 쓸 수 있습니다.
+
+노란박스의 조건을 보면 1은1로 할 경우 데이터까지 복사
+
+1은0으로 하면 테이블 스키마만 복사합니다.
+
+![스크린샷 2024-02-14 140720](https://github.com/gunsight1/blog/assets/103917282/5f6c0366-7693-4b6c-945d-8207d31af973)
+
+둘째로 필터링입니다. 예를 들어 INSERT명령어와 조합하면 조건에 맞는 데이터만 뽑아 넣을 수 있습니다.
+
+![스크린샷 2024-02-14 140725](https://github.com/gunsight1/blog/assets/103917282/47927533-50e8-4a53-95c3-0aec17287883)
+
+셋째로 SELECT안에 SELECT를 써서 임시 테이블, 즉 버추얼 뷰처럼 쓸 수 있는데 이것을 인라인 뷰라고 합니다.
+
+![스크린샷 2024-02-14 135310](https://github.com/gunsight1/blog/assets/103917282/f69c7a35-432f-4940-87ca-9f0bc0ccddf1)
+
+위 이미지에 보이는 쿼리에서 첫번째는 조인을 이용한 쿼리 실행이고, 두번째는 인라인 뷰를 이용한 쿼리 실행 입니다.
+
+둘이 같은 결과를 보여주는 쿼리인데 어느 쪽이 더 빠르게 될까요? 쿼리를 다루게 된다면 항상 고민하게되는 포인트입니다.
+
+지금껏 이야기 한 SELECT 과정을 실제 RDBMS에서 수행되는 과정을 풀어보면 아래와 같은 이미지처럼 나오게 됩니다.
+
+DBMS에 관심이 있어 자세히 알아가고자 한다면 아래의 내용에 대해서도 공부해봄직합니다. 🫡
+
+![스크린샷 2024-02-14 135358](https://github.com/gunsight1/blog/assets/103917282/7fe177f8-3bdd-478f-a397-ec8437884cb3)
+
+
+
+## [5. 쿼리실행계획]
+
+우리의 입장에서 이것보다 더 먼저 알아야 할 것은 SELECT 쿼리가 실행 될 때 발생하는 실행계획(query-plan) 이란 것이 있습니다.
+
+이 실행계획은 말 그대로 쿼리가 실행 할 때 어떠한 계획을 가지고 수행하는가를 나타내는 계획서입니다. 이 실행계획의 각 단계를 COST, 즉 비용이라고 부르는데 말그대로 수행에 필요한 비용을 뜻합니다.
+
+우리같은 서민은 가성비를 좋아하듯, 쿼리의 성능도 가성비가 중요합니다. 🙃 보통 다른 환경이 동일하다는 가정하에 코스트가 낮을수록 결과를 빠르게 가져옵니다.
+
+같은 결과를 뽑더라도 이 실행 계획에 따라 성능이 좌지우지되므로 얼마나 중요한지 알려드리고자 아주 극단적이지만 심플한 예시를 통해 말씀드리겠습니다.
+
+## [6. 실행계획을 직접 확인해보자]
+
+![스크린샷 2024-02-14 135852](https://github.com/gunsight1/blog/assets/103917282/694cdd8e-cefc-42d7-956c-e53a1c8ec749)
+
+자 우리가 취업을 하게되서 회사에서 '통계 쿼리를 만들어라' 업무 지시를 받았다고 시나리오를 두고 위와 같은 구조를 가진 회원 정보 테이블이 있다 가정합시다.
+
+이 데이터를 토대로 전체 회원 수, 월 가입자 수, 6개월 이상 미접속자 수 3개를 가져오고자 합니다.
+
+![스크린샷 2024-02-14 135903](https://github.com/gunsight1/blog/assets/103917282/dcafd47d-9987-45cc-8719-cfe9f3828dd5)
+
+쿼리를 써본지 얼마 안된 초보자의 입장에선 방금전 문법을 알아가는 과정을 통해 SELECT를 가지고 세가지의 값을 가져와야 한다는 것은 인지 할 것입니다.
+
+그런데 각각 성격이 다른 값을 어떻게 하나로 묶어야할지 고민이 될겁니다.
+
+일단 각각의 결과를 뽑는 쿼리를 써보자면 보시는 그림과 같이 나올 것입니다.
+
+![스크린샷 2024-02-14 135935](https://github.com/gunsight1/blog/assets/103917282/21cb7b2d-1213-4b85-a59b-4d4725b67399)
+
+이제 이것을 하나의 결과로 보여주기위해 FROM절엔 테이블이 들어가야 한다는 문법을 생각해서 다음과 같이 작성했다고 가정해봅시다.
+
+FROM절에 아까 작성한 각각의 결과를 가져오는 쿼리를 넣어주고, SELECT절에서 값을 가져오게 했습니다. 문법상 아주 정확하고, 올바른 결과를 나타냅니다.
+
+앞으로 이와 같은 두번의 과정이 더 있는데 결과는 모두 동일함을 미리 말씀드립니다.
+
+![스크린샷 2024-02-14 140005](https://github.com/gunsight1/blog/assets/103917282/28dd9112-c97c-4b46-9c1d-0d4a8642fc64)
+
+작성한 쿼리 앞에 실행 계획을 확인하는 EXPLAIN을 넣고 다시 쿼리를 실행해보면 다음과 같이 실행 계획이 6개나 잡혀있는 것을 확인 할 수 있습니다.
+
+FROM절에 나온 서브쿼리 SELECT가 3번 사용되어 같은 테이블에 3번 요청을 하고, SELECT절에서도 3번의 결과를 가져온 꼴이 되어 결과적으로 3 더하기 3 = 6이 나왔습니다.
+
+회사에서 쿼리를 이렇게 짜고 보고를 하면 어떻게 될까요? 아이고 고생많았으니 얼른 퇴근하세요 ~ 라고 할까요? 안타깝게도 칼퇴는 커녕 야근으로 직행입니다.🫠
+
+![스크린샷 2024-02-14 140044](https://github.com/gunsight1/blog/assets/103917282/fbd9ccfd-bf1e-4add-af54-ae805f5dbfe6)
+
+자, 야근을 피하기 위해 이번엔 SELECT절 처음부터 각각의 값을 가져오도록 바꿔보았습니다.
+
+위의 코드에서 MYSQL은 문법상 보이진 않지만 FROM절이 있다고 가정을 해서 보는 것이 맞습니다.
+
+참고로 오라클에선 문법 가독성을 위해 FROM DUAL이라는 것을 지원합니다.
+
+FROM절을 가상의 테이블로 취급하여 1개, 서브쿼리로 뽑아오는 부분 3개로 아까보다 무려 2개나 줄었으니 이번엔 칼퇴각일 것 같죠??
+
+여러분들께서 이 쿼리를 보고 만족한다면 안타깝게도 또 하루 야근의 길로 당첨입니다.
+
+그럼 여기서 또 어떻게 줄여야할까요?
+
+![스크린샷 2024-02-14 140119](https://github.com/gunsight1/blog/assets/103917282/1fb16e96-fd5e-4b30-8501-40671fd75f4d)
+
+DBMS에서 지원하는 SUM 함수와 자바의 IF와 비슷한 CASE, WHEN, THEN 문법을 이용해서 단 한번으로 데이터를 가져오도록 바꿔보았습니다.
+
+와우, 코스트가 단 하나로 바뀌었네요. 이정도면 고생했단 칭찬과 함께 칼퇴 할 만 합니다.
+
+이렇게해서 같은 결과를 보여도 쿼리를 어떻게 짜느냐에 따라 효율이 올라가는지,
+
+그 효율을 보는 실행계획은 어떻게 보는지 아주 기초적인 내용으로 알려드렸습니다.
From a5876163e0f273cc71455ada5b8c810c6ac1eb73 Mon Sep 17 00:00:00 2001
From: gunsight <103917282+gunsight1@users.noreply.github.com>
Date: Wed, 14 Feb 2024 14:29:34 +0900
Subject: [PATCH 09/50] =?UTF-8?q?=ED=8F=AC=EC=8A=A4=ED=8C=85=20=EB=A0=88?=
=?UTF-8?q?=EC=9D=B4=EC=96=B4=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
코드 내 최상단 레이어 정보 추가하였음.
---
_posts/2023-12-01-RDBMS.md | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/_posts/2023-12-01-RDBMS.md b/_posts/2023-12-01-RDBMS.md
index d2ab64d..03ab6ad 100644
--- a/_posts/2023-12-01-RDBMS.md
+++ b/_posts/2023-12-01-RDBMS.md
@@ -1,3 +1,18 @@
+---
+layout: post
+title: RDBMS의 조회과정, 쿼리실행계획 중요성
+author: 정지용
+categories: 기술세미나
+banner:
+ image: https://github.com/gunsight1/blog/assets/103917282/6c386616-902b-4bc5-98b6-f6b26c15b2e8
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+ tags: [RDBMS, 오라클, MYSQL, DML, QUERYPLAN, 기술세미나]
+---
+
+
# RDBMS의 조회과정, 쿼리실행계획 중요성
반갑습니다.
From 5e42f9c076a579722903722541e0d9a6e906c670 Mon Sep 17 00:00:00 2001
From: gunsight <103917282+gunsight1@users.noreply.github.com>
Date: Wed, 14 Feb 2024 14:36:44 +0900
Subject: [PATCH 10/50] =?UTF-8?q?=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?=
=?UTF-8?q?=202023-12-01-RDBMS.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
오타 수정
---
_posts/2023-12-01-RDBMS.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/_posts/2023-12-01-RDBMS.md b/_posts/2023-12-01-RDBMS.md
index 03ab6ad..7e1376c 100644
--- a/_posts/2023-12-01-RDBMS.md
+++ b/_posts/2023-12-01-RDBMS.md
@@ -42,11 +42,11 @@ RDBMS (관계형 데이터베이스 관리 시스템 :: Relational Database Mana
DDL(Data Definition Language)은 데이터 정의어로 DB 구조를 정의하거나 변경하는데 쓰입니다.
-DML(Data Manipolation Language)은 데이터 조작어로 등록(insert) 조회(select) 수정(update) 삭제(delete)를 수행합니다.
+DML(Data Manipulation Language)은 데이터 조작어로 등록(insert) 조회(select) 수정(update) 삭제(delete)를 수행합니다.
DCL(Data Control Language)은 데이터 제어어로 DB에 접근하는 사용자의 권한관리를 담당합니다.
-TCL(Trangection Control Language)은 트랜잭션 제어어로 작업수행의 대한 승인(commit), 철회(rollback)을 담당합니다.
+TCL(Transaction Control Language)은 트랜잭션 제어어로 작업수행의 대한 승인(commit), 철회(rollback)을 담당합니다.
이 중 우리가 알아볼 명령어는 DML에 속하는 SELECT이며 DBA가 아닌 이상 우리같은 개발자는 보통 DML과 TCL을 세트로 많이 사용합니다.
@@ -200,8 +200,8 @@ FROM절을 가상의 테이블로 취급하여 1개, 서브쿼리로 뽑아오
DBMS에서 지원하는 SUM 함수와 자바의 IF와 비슷한 CASE, WHEN, THEN 문법을 이용해서 단 한번으로 데이터를 가져오도록 바꿔보았습니다.
-와우, 코스트가 단 하나로 바뀌었네요. 이정도면 고생했단 칭찬과 함께 칼퇴 할 만 합니다.
+와우 코스트가 단 하나로 바뀌었네요. 이정도면 고생했단 칭찬과 함께 칼퇴 할 만 합니다.
+
+이렇게해서 같은 결과를 보여도 쿼리를 어떻게 짜느냐에 따라 효율이 올라가는지, 그 효율을 보는 실행계획은 어떻게 보는지 아주 기초적인 내용으로 알려드렸습니다.
-이렇게해서 같은 결과를 보여도 쿼리를 어떻게 짜느냐에 따라 효율이 올라가는지,
-그 효율을 보는 실행계획은 어떻게 보는지 아주 기초적인 내용으로 알려드렸습니다.
From 0c00786c43be990b9c502a82814ba33d4bf3486d Mon Sep 17 00:00:00 2001
From: isevou__
Date: Wed, 14 Feb 2024 17:31:37 +0900
Subject: [PATCH 11/50] =?UTF-8?q?feat=20:=2020240125=5F=EC=BD=94=EB=94=A9?=
=?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=5F=EA=B3=A0=EB=B3=91=EB=A3=A1.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_posts/2023-01-25-coding-test.md | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/_posts/2023-01-25-coding-test.md b/_posts/2023-01-25-coding-test.md
index dc5b74c..fb9eab9 100644
--- a/_posts/2023-01-25-coding-test.md
+++ b/_posts/2023-01-25-coding-test.md
@@ -4,7 +4,7 @@ title: 주저하는 개발자들을 위해 - 코딩 테스트
author: 고병룡
categories: 기술세미나
banner:
- image: https://docs.oracle.com/cd/E19340-01/820-6424/images/to_MOM.gif
+ image: https://www.hanbit.co.kr/data/editor/20200918163925_xyypndmo.png
background: "#000"
height: "100vh"
min_height: "38vh"
@@ -139,11 +139,9 @@ banner:
## 참고 자료
-이것이 코딩 테스트다
+이것이 코딩 테스트다, 나동빈 저, pg 46 - 50
[개발자 취업을 위한 코딩 테스트 준비 방법](https://katfun.tistory.com/192)
[알고리즘 분류 참고 - 백준 온라인 저지 알고리즘 별 문제 분류](https://www.acmicpc.net/problem/tags)
-
-헤더 이미지 붙이고 글 내용 읽고 수정해서 오늘 업로드 할 것
\ No newline at end of file
From f0dd89d6af77191cc89673b08e0309dbc3ec0bfa Mon Sep 17 00:00:00 2001
From: mooncw <97713997+mooncw@users.noreply.github.com>
Date: Wed, 14 Feb 2024 20:20:41 +0900
Subject: [PATCH 12/50] =?UTF-8?q?fix=20:=2020240126=5Fstomp=20=EC=9B=B9?=
=?UTF-8?q?=EC=86=8C=EC=BC=93=20=ED=94=84=EB=A1=9C=EA=B7=B8=EB=9E=98?=
=?UTF-8?q?=EB=B0=8D=5F=EB=AC=B8=EC=B0=AC=EC=9A=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
썸네일 주소 오타 수정
---
_posts/2024-01-26-stomp-websocket-programing.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_posts/2024-01-26-stomp-websocket-programing.md b/_posts/2024-01-26-stomp-websocket-programing.md
index 16505bf..177798b 100644
--- a/_posts/2024-01-26-stomp-websocket-programing.md
+++ b/_posts/2024-01-26-stomp-websocket-programing.md
@@ -4,7 +4,7 @@ title: STOMP 웹소켓 프로그래밍
author: 문찬욱
categories: 기술세미나
banner:
- image: https://raw.githubusercontent.com/Kernel360/blog-image/main/2024/0126/thumb.jpg
+ image: https://raw.githubusercontent.com/Kernel360/blog-image/main/2024/0126/thumb.png
background: "#000"
height: "100vh"
min_height: "38vh"
From 5d342bc982ebaf307ebcb13a0bb9b27115e5dbee Mon Sep 17 00:00:00 2001
From: Wonsang Kim
Date: Thu, 15 Feb 2024 20:08:51 +0900
Subject: [PATCH 13/50] [docs] dynamic programming post
---
_posts/2024-02-08-dynamicprogramming.md | 42 +++++++++++++++++++++++++
1 file changed, 42 insertions(+)
create mode 100644 _posts/2024-02-08-dynamicprogramming.md
diff --git a/_posts/2024-02-08-dynamicprogramming.md b/_posts/2024-02-08-dynamicprogramming.md
new file mode 100644
index 0000000..86bde1c
--- /dev/null
+++ b/_posts/2024-02-08-dynamicprogramming.md
@@ -0,0 +1,42 @@
+---
+layout: post
+title: 다이나믹 프로그래밍
+author: 김원상
+categories: 기술세미나
+banner:
+ image: https://github.com/Kernel360/blog-image/blob/main/2024/0208/1.png?raw=true
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+ tags: [알고리즘, 다이나믹프로그래밍]
+---
+
+
+
+안녕하세요. 이번에 다이나믹프로그래밍에 관하여 기술세미나를 드릴 김원상입니다.
+
+
+
+## 1. 웹소켓
+
+
+
+
+## 2. HTTP vs 웹소켓
+
+
+![1](https://github.com/Kernel360/blog-image/blob/main/2024/0208/3.png?raw=true)
+![2](https://github.com/Kernel360/blog-image/blob/main/2024/0208/4.png?raw=true)
+![3](https://github.com/Kernel360/blog-image/blob/main/2024/0208/5.png?raw=true)
+![4](https://github.com/Kernel360/blog-image/blob/main/2024/0208/7.png?raw=true)
+![5](https://github.com/Kernel360/blog-image/blob/main/2024/0208/8.png?raw=true)
+![6](https://github.com/Kernel360/blog-image/blob/main/2024/0208/9.png?raw=true)
+
+
+
+## 4. STOMP
+
+
+## 5. 마무리
+
From 90959a2a88bf1290e88e9a7ee2c1b937d7d66e2e Mon Sep 17 00:00:00 2001
From: Wonsang Kim
Date: Thu, 15 Feb 2024 20:13:26 +0900
Subject: [PATCH 14/50] [docs] dynamic programming post
---
_posts/2024-02-08-dynamicprogramming.md | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/_posts/2024-02-08-dynamicprogramming.md b/_posts/2024-02-08-dynamicprogramming.md
index 86bde1c..b50b3f7 100644
--- a/_posts/2024-02-08-dynamicprogramming.md
+++ b/_posts/2024-02-08-dynamicprogramming.md
@@ -12,9 +12,11 @@ banner:
tags: [알고리즘, 다이나믹프로그래밍]
---
+안녕하세요. 이번에 다이나믹 프로그래밍에 관하여 기술세미나를 드릴 김원상입니다.
-
-안녕하세요. 이번에 다이나믹프로그래밍에 관하여 기술세미나를 드릴 김원상입니다.
+$$
+\int_{a}^{b} f(x) \, dx
+$$
From d0a55c4b8705be5ed23d5b90fb4aedc73dd44d34 Mon Sep 17 00:00:00 2001
From: Wonsang Kim
Date: Thu, 15 Feb 2024 20:41:56 +0900
Subject: [PATCH 15/50] [docs] dynamic programming post
---
_posts/2024-02-08-dynamicprogramming.md | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/_posts/2024-02-08-dynamicprogramming.md b/_posts/2024-02-08-dynamicprogramming.md
index b50b3f7..b33bf76 100644
--- a/_posts/2024-02-08-dynamicprogramming.md
+++ b/_posts/2024-02-08-dynamicprogramming.md
@@ -14,18 +14,17 @@ banner:
안녕하세요. 이번에 다이나믹 프로그래밍에 관하여 기술세미나를 드릴 김원상입니다.
-$$
-\int_{a}^{b} f(x) \, dx
-$$
+다이나믹 프로그래밍은 코딩테스트를 처음 접하시는 분들에게는 진입장벽, 조금 익숙하신 분들에게는 알다가도 모를것 같은 알고리즙인데요. 제 나름대로 다이나믹 프로그래밍 문제를 접근하는 방법과 어떤 식으로 공부하면 좋을지에 대한 생각을 나눌 수 있을 것 같아 선택한 주제입니다. 커널360 코딩테스트에도 나왔고, 다른 기업 코딩테스트 후기를 봐도 조금씩 나오기 때문에 연습을 많이 해두시면 분명 원하는 회사를 가시는데 도움이 될 거라 생각합니다.
-
+### 1. 리처드 E. 벨만
-## 1. 웹소켓
+다이나믹 프로그래밍은 리처드 E. 벨만이라는 수학자가 처음 고안한 알고리즘입니다. 어떤 과목이든지
+$$
+\int_{a}^{b} f(x) \, dx
+$$
-
-## 2. HTTP vs 웹소켓
![1](https://github.com/Kernel360/blog-image/blob/main/2024/0208/3.png?raw=true)
@@ -37,8 +36,3 @@ $$
-## 4. STOMP
-
-
-## 5. 마무리
-
From 170ae2e622d5bedeb54fb6e0081f612974bd4463 Mon Sep 17 00:00:00 2001
From: Byungryong Ko
Date: Thu, 15 Feb 2024 21:40:18 +0900
Subject: [PATCH 16/50] Update 2023-01-25-coding-test.md
---
_posts/2023-01-25-coding-test.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_posts/2023-01-25-coding-test.md b/_posts/2023-01-25-coding-test.md
index fb9eab9..41c7c80 100644
--- a/_posts/2023-01-25-coding-test.md
+++ b/_posts/2023-01-25-coding-test.md
@@ -54,7 +54,7 @@ banner:
착각하는 분들이 있는데 우리는 대회를 나가자고 하는 게 아니다. 코테를 쳐보는 것만으로도 소중한 자산이다. 이걸로 상을 타는 게 아니라 우리는 취업이 목적이기에....
>7. 어떻게 준비해야 될지 모르겠다.
-그러면 이제부터 알아보자! 만약 필자가 뭐하는 사람인지 의심이 간다면.. 그래도 나름 [열심히(?)](https://solved.ac/profile/hodako97) 준비해오고 [알고리즘을 좋아하고](https://github.com/fingersdanny/PS_note), [알고리즘 스터디](https://github.com/Kernel360-cell1/algorithm-study)를 운영 중인 사람 중 하나로써 여러분들이 코테에서 더 행복해지길 바라는 마음에서 준비했다.
+그러면 이제부터 알아보자! 만약 필자가 뭐하는 사람인지 의심이 간다면.. 그래도 나름 [열심히(?)](https://solved.ac/profile/hodako97) 준비해오고 [알고리즘을 좋아하고](https://github.com/fingersdanny/PS_note), [알고리즘 스터디](https://github.com/Kernel360-cell1/algorithm-study)를 운영 중인 사람 중 하나로서 여러분들이 코테에서 더 행복해지길 바라는 마음에서 준비했다.
## 코딩테스트 어떻게 준비해야 할까?
From 604c53e2f1ddc8aff09049be3b6faad7dce5aaca Mon Sep 17 00:00:00 2001
From: anso33
Date: Fri, 16 Feb 2024 14:30:29 +0900
Subject: [PATCH 17/50] chore: set codeowner
---
.github/CODEOWNERS | 1 +
1 file changed, 1 insertion(+)
create mode 100644 .github/CODEOWNERS
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..2b696f4
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @anso33
\ No newline at end of file
From b2d820c59f1c4d0723f0bed53f963d53e0d332b9 Mon Sep 17 00:00:00 2001
From: anso33
Date: Fri, 16 Feb 2024 20:31:48 +0900
Subject: [PATCH 18/50] chore: set codeowner
---
.github/CODEOWNERS | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 2b696f4..00e22c9 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1 +1,5 @@
-* @anso33
\ No newline at end of file
+* @anso33 @aacara
+
+*.md @anso33
+
+/_posts @anso33
\ No newline at end of file
From f000fa4bc8fbd551a9b496bd59f2859ee06fed5c Mon Sep 17 00:00:00 2001
From: AN-SOHYEON
Date: Fri, 16 Feb 2024 21:13:23 +0900
Subject: [PATCH 19/50] chore: Update CODEOWNERS
---
.github/CODEOWNERS | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 00e22c9..1d9e21e 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,5 +1,5 @@
-* @anso33 @aacara
+* @anso33
-*.md @anso33
+*.md @anso33 @Hju95
-/_posts @anso33
\ No newline at end of file
+/_posts @anso33
From bb65982f1dd4f4c434551f4dd48b3d3717c272d8 Mon Sep 17 00:00:00 2001
From: linglong67 <88479739+linglong67@users.noreply.github.com>
Date: Sun, 18 Feb 2024 15:11:00 +0900
Subject: [PATCH 20/50] feat: Web API (20231121) (#32)
---
_posts/2023-11-21-web-api.md | 212 +++++++++++++++++++++++++++++++++++
1 file changed, 212 insertions(+)
create mode 100644 _posts/2023-11-21-web-api.md
diff --git a/_posts/2023-11-21-web-api.md b/_posts/2023-11-21-web-api.md
new file mode 100644
index 0000000..0a58b83
--- /dev/null
+++ b/_posts/2023-11-21-web-api.md
@@ -0,0 +1,212 @@
+---
+layout: post
+title: 실시간 웹 애플리케이션을 위한 API 전략
+author: 김영롱
+categories: 기술세미나
+banner:
+ image: https://github.com/Kernel360/blog-image/blob/main/2023/1121/interface.png?raw=true
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+tags: [웹 API, REST, GraphQL, WebSocket, 기술세미나]
+---
+안녕하세요, *Lune* 입니다.
+
+저는 이번에 **실시간 웹 애플리케이션을 위한 API 전략**이라는 주제로 기술 세미나를 진행했습니다.
+
+이 주제를 통해 REST, GraphQL, WebSocket API에 대해 주로 설명하고 각각을 비교해보려고 합니다.
+
+## 1. API란
+먼저 API(Application Programming Interface)가 무엇인지 간단히 알아볼까요?
+
+우선 Application은 고유한 기능을 가진 모든 소프트웨어, Interface는 애플리케이션 간의 서비스 계약이라고 할 수 있습니다. 그리고 계약은 요청과 응답을 사용하여 애플리케이션이 서로 통신하는 방법이라고 할 수 있죠.
+
+좀 더 쉬운 설명을 위해 이미지를 가져와봤습니다. 식당을 예시로 들어볼게요.
+1) 손님은 점원이 가져다준 메뉴판으로 메뉴를 주문하고, 점원이 주문을 요리사에게 전달
+2) 요리사는 주문받은 요리를 만들어 점원에게 주고, 손님은 점원이 가져다준 요리로 맛있게 식사
+
+여기서 점원이 바로 API와 같은 역할을 한다고 볼 수 있습니다.
+
+![api](https://github.com/Kernel360/blog-image/blob/main/2023/1121/api.png?raw=true)
+
+식당 예시를 그대로 아래 이미지처럼 바꾼다고 하면 API는 좌측 프로그램이 요청할 수 있는 명령 목록을 제공하고, 명령을 받으면 우측 프로그램과 상호작용하여 명령에 대한 값을 받아 전달하게 되는 거죠. 쉽게 말해, API는 프로그램들이 서로 상호작용하는 것을 도와주는 매개체라고도 볼 수 있습니다.
+
+![api-2](https://github.com/Kernel360/blog-image/blob/main/2023/1121/api-2.png?raw=true)
+(일부 설명 및 이미지 출처 → [api란-쉽게-설명-그린클라이언트](https://blog.wishket.com/api란-쉽게-설명-그린클라이언트))
+
+### 웹 API
+웹 API는 웹 서버와 웹 브라우저 간의 애플리케이션 처리 인터페이스입니다.
+웹 API의 종류는 REST API, GraghQL API, WebSocket API, SOAP API, RPC API 등 다양한데요.
+그 중 앞의 3가지 API에 초점을 맞춰서 이야기해보겠습니다.
+
+## 2. REST API
+**REST API**는 REST 아키텍처 스타일을 따르는 API로 REST는 Representational State Transfer의 약어입니다. REST는 로이 필딩(Roy Fielding)이 HTTP의 장점을 최대한 활용할 수 있도록 고안한 아키텍처로 2000년에 처음올 소개되었고, 기본적으로 웹의 기존 기술과 HTTP 프로토콜을 그대로 활용하므로 ***웹의 장점을 최대한 활용할 수 있는 아키텍처 스타일*** 입니다.
+
+### 주요 특징
+REST API의 주요 특징은 다음과 같습니다.
+1) **Stateless** (무상태)
+ - 서버는 요청이 오가는 동안 클라이언트의 상태를 저장하지 않음
+2) **Cacheable** (캐시 가능성)
+ - 클라이언트가 응답을 캐시하여 네트워크 부하를 줄이고 성능을 향상시킬 수 있음
+3) **Uniform Interface** (통일된 인터페이스)
+ - API 디자인이 통일되어 있어 사용하기 쉬움
+ - 즉, 애플리케이션 요구사항별로 다른 형식이 아닌, 표준화된 형식으로 정보를 전송할 수 있도록 구성 요소 간 통합된 인터페이스를 가짐
+4) **Server-Client** (서버-클라이언트 구조)
+ - 클라이언트와 서버가 각각 독립적으로 발전할 수 있음
+ - 예를 들어, 웹 브라우저는 사용자에게 웹페이지를 보여주고, 서버는 데이터를 제공
+5) **Layered System** (계층화된 시스템)
+ - 시스템이 계층으로 나뉘어 있음
+ - 각 계층은 특정 역할을 수행하며, 상위 계층은 하위 계층의 구현을 알 필요가 없음
+ - 예를 들어, 클라이언트는 데이터를 요청하면 중간에 여러 계층을 거쳐 서버에 도달할 수 있지만 클라이언트는 중간 계층의 존재를 몰라도 됨
+
+## 3. GraphQL API
+**GraphQL API**는 2012년 Facebook(현 Meta)에서 개발한 API용 쿼리 언어로 2015년 오픈소스화되었는데요. 클라이언트가 서버로부터 원하는 데이터를 효율적으로 요청할 수 있게 하는 기술로 ***REST의 대안으로 설계*** 되었다고 합니다.
+
+그런데 REST API의 대안이라니.. 무슨 문제가 있다는 걸까요? GraphQL API을 더 잘 이해하기 위해 잠시 짚고 넘어가겠습니다.
+
+### REST API에 무슨 문제가 있나요?
+아래 JSON 응답을 참고해 설명해보겠습니다.
+(Fetch는 *웹 페이지를 구성하기 위해서 다양한 서버에 요청을 보내고 데이터를 받아오는 작업* 이라고 생각하시면 됩니다.)
+
+1) Over-Fetching
+ - 원하는 응답 데이터 → 도서 ID, 도서명, 저자명만 필요, 그러나 해당 API Response 값에 가격, 출판사, ISBN 등이 포함되어 있다면 다 받아야 함
+ - 즉, Over-Fetching은 필요한 데이터 이상으로 서버에서 데이터를 받아오게 되는 것을 의미하며, 필요없는 데이터까지 받아와 서버와 자원이 낭비됨
+2) Under-Fetching
+ - 도서 상세 페이지에서 도서 정보와 리뷰 목록을 보여주려고 함, 그러나 API가 도서 정보와 도서 리뷰에 대해 각각 다른 End-Point를 사용한다면 필연적으로 2번의 API 호출 발생
+ - 즉, 한 번의 요청으로 필요한 데이터를 모두 받아오지 못해 여러 번의 요청을 수행하는 것을 의미하며, 네트워크의 지연이 발생할 수 있고 사용자는 느린 로딩 속도로 인해 불편함을 겪을 수 있음
+3) 다양한 엔드포인트
+ - REST API는 여러 엔드포인트가 존재하며, 각자의 역할을 하고 있으므로 클라이언트는 다양한 엔드포인트를 요청해야 함
+```json
+{
+ "books": [
+ {
+ // 필요한 정보
+ "id": 1,
+ "title": "Do it! 자바 프로그래밍 입문",
+ "author": "박은종",
+ // 필요하지 않은 정보
+ "price": 25000,
+ "publisher": " 이지스퍼블리싱",
+ "isbn": "9791163030195"
+ },
+ {
+ // 필요한 정보
+ "id": 2,
+ "title": "모두의 한국어 텍스트 분석 with 파이썬",
+ "author": "박조은, 송영숙",
+ // 필요하지 않은 정보
+ "price": 27000,
+ "publisher": "길벗",
+ "isbn": "9791140704521"
+ }
+ ]
+}
+```
+위 문제들이 와닿으셨을까요? GraphQL API를 사용하면 REST API의 단점 중 하나인 Over-Fetching이나 Under-Fetching 문제를 효과적으로 해결할 수 있다고 합니다.
+
+### 주요 특징
+GraphQL API의 주요 특징은 다음과 같습니다.
+1) **유연하고 강력한 데이터 쿼리 언어**
+ - 클라이언트가 필요한 데이터의 구조와 양을 정확하게 명시할 수 있는 강력한 쿼리 언어를 제공하므로 과도한 데이터 전송이나 다수의 요청을 최소화할 수 있음
+ - 즉, REST API의 오버 페칭과 언더 페칭과 같은 이슈가 발생하지 않음
+2) **단일 엔드포인트**
+ - REST API에서는 각 엔드포인트마다 데이터를 요청해야 했지만, GraphQL은 단일 엔드포인트를 사용하여 클라이언트가 단일 요청으로 여러 데이터를 가져올 수 있음
+ - ex) @PostMapping("/graphql")
+3) **실시간 데이터 업데이트**
+ - 실시간 데이터 업데이트를 지원
+ - 일반적으로 Subscription이라 불리는 메커니즘을 통해 이루어짐
+```text
+query {
+ user(id: 123) {
+ id
+ name
+ email
+ posts {
+ title
+ content
+ }
+ }
+}
+```
+```json
+{
+ "data": {
+ "user": {
+ "id": 123,
+ "name": "John Doe",
+ "email": "john.doe@example.com",
+ "posts": [
+ {
+ "title": "GraphQL Basics",
+ "content": "Introduction to GraphQL"
+ },
+ {
+ "title": "Advanced GraphQL",
+ "content": "Deep dive into GraphQL concepts"
+ }
+ ]
+ }
+ }
+}
+```
+
+## 4. WebSocket API
+마지막으로 **WebSocket API**입니다. 일반적인 HTTP 통신은 클라이언트-서버간 요청-응답을 주고 받는 단방향 통신인데요. 채팅, 주식, 온라인 게임과 같은 실시간 애플리케이션에서는 ***빠른 속도로 정보를 전달하고 업데이트*** 하기 위해 양방향 통신이 필요합니다. WebSocket API는 이런 필요성이 요구될 때 사용되는 API랍니다.
+
+### 주요 특징
+WebSocket API의 주요 특징은 다음과 같습니다.
+1) **양방향 통신**
+ - 클라이언트-서버간 양방향 통신 가능
+ - 서버가 클라이언트에게 데이터를 푸시하고, 클라이언트가 서버에게 데이터를 전송할 수 있음
+2) **실시간성**
+ - 연결을 유지하면서 데이터를 실시간으로 전송
+ - 단방향 통신과는 달리, 데이터의 지연 시간을 최소화하여 실시간 응용 프로그램을 구축하는 데 적합
+3) **단일 연결 유지**
+ - WebSocket은 한 번의 연결을 설정하고 유지함으로써 여러 요청에 대한 새로운 연결을 맺지 않아도 됨
+4) **효율적인 데이터 전송**
+ - 연결을 유지하면서 계속 데이터를 주고받기 때문에, 새로운 연결을 설정할 필요가 없어 헤더의 오버헤드가 감소함
+5) **이벤트 기반 모델**
+ - 이벤트 기반의 모델을 사용하여 메시지를 수신하고 처리할 수 있음
+
+## 5. API 비교
+앞서 설명했던 내용에 덧붙여 간략하게 API별 비교를 위해 표로 정리해보겠습니다.
+
+ 특징 | REST API | GraphQL API | WebSocket API
+----------|--------------------------------|-------------------------------|-----------------------------------
+ 용도 | 주로 데이터 조회 및 간단한 상호 작용 (CRUD 작업) | 복잡한 데이터 요청 및 실시간 업데이트 | 실시간 데이터 전송 및 양방향 통신
+ 사용사례 | 소셜 미디어, 블로그 등 | 복잡한 데이터 요청이 필요한 애플리케이션 | 실시간 채팅, 주식 시세 업데이트, 실시간 협업 등
+ 통신방식 | 단방향 요청-응답 구조 | 클라이언트가 필요한 데이터를 정의하고 서버가 응답 | 양방향 통신으로 실시간 데이터 전송
+ 지연시간 | 새로운 연결마다 지연 시간이 발생 | 클라이언트가 필요한 데이터만을 요청하여 효율적인 전송 | 연결 유지로 낮은 지연 시간
+ 실시간 업데이트 | Polling 또는 Webhooks을 통한 업데이트 | 실시간 데이터 업데이트 | 실시간 데이터 업데이트
+ 유연성 | 여러 리소스에 대한 각각의 고유한 엔드포인트를 사용 | 클라이언트가 필요한 데이터만 요청 가능 | 단일 연결로 다양한 메시지 처리 |
+ 복잡한 쿼리 | 여러 엔드포인트에 각각의 요청을 보내 복잡한 쿼리 처리 | 복잡한 쿼리 및 중첩된 필드 지원 | 주로 간단한 메시지 전송에 사용되며, 덜 복잡한 데이터 구조
+ 상태 | 상태 저장이 필요하지 않음 | 상태 저장이 필요하지 않음 | 상태 저장이 필요한 경우 (예: 게임 상태)
+ 오버헤드 | HTTP 헤더, 상태 코드 등의 오버헤드 발생 | 필요한 데이터만 요청하므로 상대적으로 적음 | 일반적으로 상대적으로 낮은 오버헤드
+
+## 6. 정리
+지금까지 기술 세미나에서 나눴던 얘기를 마무리했습니다.
+아래에는 각각의 웹 API를 어떤 상황에서 사용하면 좋을지 간단히 작성해봤습니다. 하나의 프로젝트에서 여러 API를 함께 사용할 수도 있기 때문에 상황에 알맞은 API를 적용해 사용하면 되겠죠~?
+
+- 주로 상태를 저장하지 않고 단순한 데이터 전송에 사용되며, 서버의 부하가 크게 발생하지 않는 경우
+ - REST API
+- 클라이언트와 서버 간의 상태를 유지하고 실시간 양방향 통신이 필요한 경우
+ - WebSocket API
+- 복잡한 데이터 요청이 필요한 경우이거나 실시간 업데이트가 필요한 경우
+ - GraphQL API
+
+정말 정말 마지막으로 영상 하나를 추천하려고 해요!
+이번 세미나를 준비하며 보게 된 영상으로 흥미롭게 들었던 내용이라 공유드립니다. REST API와 관련된 내용인데 자주 사용하는 API인 만큼 시간되실 때 참고해보면 좋을 것 같습니다.
+
+[그런 REST API로 괜찮은가](https://youtu.be/RP_f5dMoHFc?si=9clhxJ_3Ucn5L4U3)
+
+## 7. 참고자료
+- [API란? 비개발자가 알기 쉽게 설명해드립니다!](https://blog.wishket.com/api란-쉽게-설명-그린클라이언트)
+- [RESTful](https://positiveko-til.vercel.app/til/cs/restful.html)
+- [REST란? REST API 와 RESTful API의 차이점](https://dev-coco.tistory.com/97)
+- [WebSocket API의 기본 구성요소 및 기능](https://appmaster.io/ko/blog/websocket-api-guseong-yoso-mic-gineung)
+- [GraphQL](https://graphql.org/learn/)
+- [REST API에서 GraphQL로의 패러다임 전환 - Facebook이 주목한 기술](https://enjoydev.life/blog/frontend/11-graphql)
+- [실시간으로 최신 데이터를 불러오는 Websocket API, REST API와 어떤 차이가 있을까?](https://youtu.be/LddPLO4bXmQ)
+- [[10분 테코톡] 정의 REST API](https://youtu.be/Nxi8Ur89Akw?si=koW8ZxGvhG1xAiRl)
+- [[10분 테코톡] ✨ 아론의 웹소켓&스프링](https://youtu.be/rvss-_t6gzg?si=sf4NiNiHzhwAl52D)
From 4c0a8506d8e010a43fcad7433107da2fccd03255 Mon Sep 17 00:00:00 2001
From: linglong67 <88479739+linglong67@users.noreply.github.com>
Date: Sun, 18 Feb 2024 20:48:04 +0900
Subject: [PATCH 21/50] feat: Spring REST Docs (20240124) (#33)
---
_posts/2023-11-21-web-api.md | 36 ++--
_posts/2024-01-24-spring-rest-docs.md | 272 ++++++++++++++++++++++++++
2 files changed, 290 insertions(+), 18 deletions(-)
create mode 100644 _posts/2024-01-24-spring-rest-docs.md
diff --git a/_posts/2023-11-21-web-api.md b/_posts/2023-11-21-web-api.md
index 0a58b83..ab4cbca 100644
--- a/_posts/2023-11-21-web-api.md
+++ b/_posts/2023-11-21-web-api.md
@@ -23,8 +23,8 @@ tags: [웹 API, REST, GraphQL, WebSocket, 기술세미나]
우선 Application은 고유한 기능을 가진 모든 소프트웨어, Interface는 애플리케이션 간의 서비스 계약이라고 할 수 있습니다. 그리고 계약은 요청과 응답을 사용하여 애플리케이션이 서로 통신하는 방법이라고 할 수 있죠.
좀 더 쉬운 설명을 위해 이미지를 가져와봤습니다. 식당을 예시로 들어볼게요.
-1) 손님은 점원이 가져다준 메뉴판으로 메뉴를 주문하고, 점원이 주문을 요리사에게 전달
-2) 요리사는 주문받은 요리를 만들어 점원에게 주고, 손님은 점원이 가져다준 요리로 맛있게 식사
+1. 손님은 점원이 가져다준 메뉴판으로 메뉴를 주문하고, 점원이 주문을 요리사에게 전달
+2. 요리사는 주문받은 요리를 만들어 점원에게 주고, 손님은 점원이 가져다준 요리로 맛있게 식사
여기서 점원이 바로 API와 같은 역할을 한다고 볼 수 있습니다.
@@ -45,17 +45,17 @@ tags: [웹 API, REST, GraphQL, WebSocket, 기술세미나]
### 주요 특징
REST API의 주요 특징은 다음과 같습니다.
-1) **Stateless** (무상태)
+1. **Stateless** (무상태)
- 서버는 요청이 오가는 동안 클라이언트의 상태를 저장하지 않음
-2) **Cacheable** (캐시 가능성)
+2. **Cacheable** (캐시 가능성)
- 클라이언트가 응답을 캐시하여 네트워크 부하를 줄이고 성능을 향상시킬 수 있음
-3) **Uniform Interface** (통일된 인터페이스)
+3. **Uniform Interface** (통일된 인터페이스)
- API 디자인이 통일되어 있어 사용하기 쉬움
- 즉, 애플리케이션 요구사항별로 다른 형식이 아닌, 표준화된 형식으로 정보를 전송할 수 있도록 구성 요소 간 통합된 인터페이스를 가짐
-4) **Server-Client** (서버-클라이언트 구조)
+4. **Server-Client** (서버-클라이언트 구조)
- 클라이언트와 서버가 각각 독립적으로 발전할 수 있음
- 예를 들어, 웹 브라우저는 사용자에게 웹페이지를 보여주고, 서버는 데이터를 제공
-5) **Layered System** (계층화된 시스템)
+5. **Layered System** (계층화된 시스템)
- 시스템이 계층으로 나뉘어 있음
- 각 계층은 특정 역할을 수행하며, 상위 계층은 하위 계층의 구현을 알 필요가 없음
- 예를 들어, 클라이언트는 데이터를 요청하면 중간에 여러 계층을 거쳐 서버에 도달할 수 있지만 클라이언트는 중간 계층의 존재를 몰라도 됨
@@ -69,13 +69,13 @@ REST API의 주요 특징은 다음과 같습니다.
아래 JSON 응답을 참고해 설명해보겠습니다.
(Fetch는 *웹 페이지를 구성하기 위해서 다양한 서버에 요청을 보내고 데이터를 받아오는 작업* 이라고 생각하시면 됩니다.)
-1) Over-Fetching
+1. Over-Fetching
- 원하는 응답 데이터 → 도서 ID, 도서명, 저자명만 필요, 그러나 해당 API Response 값에 가격, 출판사, ISBN 등이 포함되어 있다면 다 받아야 함
- 즉, Over-Fetching은 필요한 데이터 이상으로 서버에서 데이터를 받아오게 되는 것을 의미하며, 필요없는 데이터까지 받아와 서버와 자원이 낭비됨
-2) Under-Fetching
+2. Under-Fetching
- 도서 상세 페이지에서 도서 정보와 리뷰 목록을 보여주려고 함, 그러나 API가 도서 정보와 도서 리뷰에 대해 각각 다른 End-Point를 사용한다면 필연적으로 2번의 API 호출 발생
- 즉, 한 번의 요청으로 필요한 데이터를 모두 받아오지 못해 여러 번의 요청을 수행하는 것을 의미하며, 네트워크의 지연이 발생할 수 있고 사용자는 느린 로딩 속도로 인해 불편함을 겪을 수 있음
-3) 다양한 엔드포인트
+3. 다양한 엔드포인트
- REST API는 여러 엔드포인트가 존재하며, 각자의 역할을 하고 있으므로 클라이언트는 다양한 엔드포인트를 요청해야 함
```json
{
@@ -107,13 +107,13 @@ REST API의 주요 특징은 다음과 같습니다.
### 주요 특징
GraphQL API의 주요 특징은 다음과 같습니다.
-1) **유연하고 강력한 데이터 쿼리 언어**
+1. **유연하고 강력한 데이터 쿼리 언어**
- 클라이언트가 필요한 데이터의 구조와 양을 정확하게 명시할 수 있는 강력한 쿼리 언어를 제공하므로 과도한 데이터 전송이나 다수의 요청을 최소화할 수 있음
- 즉, REST API의 오버 페칭과 언더 페칭과 같은 이슈가 발생하지 않음
-2) **단일 엔드포인트**
+2. **단일 엔드포인트**
- REST API에서는 각 엔드포인트마다 데이터를 요청해야 했지만, GraphQL은 단일 엔드포인트를 사용하여 클라이언트가 단일 요청으로 여러 데이터를 가져올 수 있음
- ex) @PostMapping("/graphql")
-3) **실시간 데이터 업데이트**
+3. **실시간 데이터 업데이트**
- 실시간 데이터 업데이트를 지원
- 일반적으로 Subscription이라 불리는 메커니즘을 통해 이루어짐
```text
@@ -156,17 +156,17 @@ query {
### 주요 특징
WebSocket API의 주요 특징은 다음과 같습니다.
-1) **양방향 통신**
+1. **양방향 통신**
- 클라이언트-서버간 양방향 통신 가능
- 서버가 클라이언트에게 데이터를 푸시하고, 클라이언트가 서버에게 데이터를 전송할 수 있음
-2) **실시간성**
+2. **실시간성**
- 연결을 유지하면서 데이터를 실시간으로 전송
- 단방향 통신과는 달리, 데이터의 지연 시간을 최소화하여 실시간 응용 프로그램을 구축하는 데 적합
-3) **단일 연결 유지**
+3. **단일 연결 유지**
- WebSocket은 한 번의 연결을 설정하고 유지함으로써 여러 요청에 대한 새로운 연결을 맺지 않아도 됨
-4) **효율적인 데이터 전송**
+4. **효율적인 데이터 전송**
- 연결을 유지하면서 계속 데이터를 주고받기 때문에, 새로운 연결을 설정할 필요가 없어 헤더의 오버헤드가 감소함
-5) **이벤트 기반 모델**
+5. **이벤트 기반 모델**
- 이벤트 기반의 모델을 사용하여 메시지를 수신하고 처리할 수 있음
## 5. API 비교
diff --git a/_posts/2024-01-24-spring-rest-docs.md b/_posts/2024-01-24-spring-rest-docs.md
new file mode 100644
index 0000000..4dc3c08
--- /dev/null
+++ b/_posts/2024-01-24-spring-rest-docs.md
@@ -0,0 +1,272 @@
+---
+layout: post
+title: 이번엔 Spring REST Docs를 써볼까?
+author: 김영롱
+categories: 기술세미나
+banner:
+ image: https://github.com/Kernel360/blog-image/blob/main/2024/0124/spring-rest-docs.png?raw=true
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+tags: [API 문서, Spring REST Docs, 기술세미나]
+---
+안녕하세요, *Lune* 입니다.
+
+이번엔 **Spring REST Docs**를 기술 세미나 주제로 가져와봤는데요.
+
+Spring REST Docs를 프로젝트에서 사용하게 된 이유부터 적용기까지 공유해보려고 합니다.
+
+## 1. API 문서의 필요성
+조금 뻔한 얘기로 시작해볼까요?
+개발을 하면서 API 문서들이 필요한 이유는 무엇일까요? 제가 생각해봤을 때, 그리고 검색을 해봤을 때 아래와 같은 이유들이 있었습니다.
+
+1. API 사용법 이해
+2. 개발자 간의 효율적인 협업
+3. 빠른 문제 해결 및 버그 대응
+4. 개발 생산성 향상
+
+개인적으로는 일단 2번이 제일 와닿습니다. 협업할 때 같은 API 문서를 보며 얘기하면 소통이 더 잘된다고 느낀 적이 많았거든요.
+
+## 2. API 문서를 만드는 여러 방법들
+자, 그럼 이번에는 API 문서를 만들 수 있는 방법들에 대해 이야기해볼게요.
+
+1. 구글 공유 문서 (Docs / Sheets)
+2. Notion
+3. GitBook
+4. Swagger
+5. Spring REST Docs
+
+위에 리스트 말고도 더 많은 방법들이 있겠지만, 제가 사용해봤거나 사용사례를 본 적 있는 것 위주로 작성해봤습니다.
+
+### 구글 공유 문서 / Notion / GitBook
+코드베이스가 아니라 수동으로 직접 문서를 작성하는 방식입니다. 장단점을 알아보자면 다음과 같습니다.
+
+ 장점 | 단점
+-----------------|------------------
+ 쉬운 협업 및 공유 | API 문서 작성 기능 제한적
+ 커스텀 스타일 적용 쉬운 편 | 비용 문제 발생 가능
+ 사용자 친화적인 UI/UX | API 문서 자동화 어려움
+
+위 내용이 3가지 모두에 동일하게 적용된다고 할 수는 없지만, 보편적인 장단점 위주로 설명해보려고 했으니 조금 안 맞다고 생각이 들어도 이해해주세요 👐
+
+### Swagger / Spring REST Docs
+코드 내에 API 문서화를 위한 작업을 진행하는 방식입니다. 장단점을 알아보자면 다음과 같습니다.
+
+ 장점 | 단점
+----------------|-----------------
+ 자동 문서 생성 | 러닝커브 존재 및 설정 복잡
+ 일관된 형식과 스타일 유지 | 커스터마이제이션 한계
+ 실시간 업데이트 | 의존성 및 업그레이드 어려움
+
+여기서 *커스터마이제이션 한계* 란 문서의 외관이나 기능을 개발자가 원하는 대로 조정하는 데에 한계가 있다는 것을 의미합니다.
+
+## 3. Spring REST Docs를 선택한 이유
+현재 진행 중인 프로젝트에서는 왜 Spring REST Docs를 선택하게 되었을까요?
+
+우선 첫 시작은 GitBook 이었답니다. 기능 개발이 들어가지 않은 상태에서 프론트엔드 개발자와의 빠른 협업을 위해 GitBook으로 API 문서를 만들기 시작했었죠. 그런데 초반에 잘 알아보지 않은 탓에 얼마 지나지 않아 무료 버전의 한계를 맞닥뜨리게 되었습니다. 무료 버전에서는 여러 사람이 문서 편집을 할 수 없어 공동 작업이 더 이상 불가능하게 되어버렸거든요 🥲
+
+그 다음으로 생각한 건 API 문서 자동화가 가능한 Swagger와 Spring REST Docs였습니다. 그래서 그 둘을 비교해봤습니다.
+
+### Swagger
+
+ 장점 | 단점
+----------------|---------------------------
+ 어노테이션 기반 문서 생성 | 프로덕션 코드에 작업 필요
+ 화면에서 API 테스트 | 프로덕션 코드와 동기화 안 되어 있을 수 있음
+ 비교적 쉬운 적용 |
+
+### Spring REST Docs
+
+ 장점 | 단점
+-----------------|---------------
+ 프로덕션 코드에 영향 없음 | 적용이 어려운 편
+ 테스트 성공 시 문서 생성 | 테스트 코드 양이 늘어남
+ API 문서 최신 상태 유지 |
+
+(제목에 드러나있듯이) 결과적으로 Spring REST Docs를 사용하기로 결정을 했습니다. 이번 프로젝트에서는 테스트 코드를 작성하기로 했었고, 프로덕션 코드에 영향이 없고 늘 현행화가 가능하다는 점에 이끌렸거든요.
+
+## 4. Spring REST Docs 적용기
+이제부터는 Spring REST Docs를 적용했던 과정을 하나씩 설명해보겠습니다.
+참고로 저는 Asciidoctor & MockMvc 방식을 사용했는데요. 공식 문서에 따르면 문서 작성을 위해 Asciidoctor와 Markdown을 지원하고 있고 MockMvc, WebTestClient, REST Assured 방식의 테스트 예시를 보여주고 있습니다.
+
+### 1) build.gradle 설정
+build.gradle에 추가되어야 하는 내용 및 설명은 아래 코드로 대체합니다.
+```groovy
+plugins {
+ // Asciidoctor 플러그인 적용
+ id "org.asciidoctor.jvm.convert" version "3.3.2"
+}
+
+ext {
+ // 생성된 snippets 출력 위치를 정의하는 snippetsDir 속성을 구성
+ snippetsDir = file('build/generated-snippets')
+}
+
+configurations {
+ // asciidoctorExt 구성을 선언
+ asciidoctorExt
+}
+
+dependencies {
+ // asciidoctorExt 구성에서 spring-restdocs-asciidoctor에 대한 종속성을 추가
+ asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
+ // MockMvc 테스트 방식을 사용
+ testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
+}
+
+tasks.named('test') {
+ // 테스트 작업을 실행하면 출력이 snippetsDir에 기록된다는 것을 Gradle이 인식하도록 함
+ outputs.dir snippetsDir
+}
+
+asciidoctor {
+ // asciidoctor 작업을 구성
+ dependsOn test
+ configurations 'asciidoctorExt'
+ baseDirFollowsSourceFile()
+ inputs.dir snippetsDir
+}
+
+asciidoctor.doFirst {
+ // asciidoctor 작업이 수행될 때 가장 먼저 수행
+ delete file('src/main/resources/static/docs')
+}
+
+task copyDocument(type: Copy) {
+ // html 파일 복사
+ dependsOn asciidoctor
+ from file("build/docs/asciidoc")
+ into file("src/main/resources/static/docs")
+}
+
+bootJar {
+ dependsOn copyDocument
+}
+```
+
+### 2) 테스트 코드 작성
+첫 번째 *테스트 코드* 외에는 구현 방식에 따라 다를 수 있으므로 가볍게 봐주시면 됩니다.
+```java
+/** 테스트 코드 **/
+result.andExpect(status().isOk())
+ .andDo(document(
+ "commoncode/get-common-codes",
+ getDocumentRequest(),
+ getDocumentResponse(),
+ // pathParameters, queryParameters, requestFields, responseFields는 필요 시 각각 작성
+ pathParameters(
+ parameterWithName("codeName").description("코드명")
+ ),
+ responseFields(beneathPath("value").withSubsectionId("value"),
+ fieldWithPath("codeNo").type(JsonFieldType.NUMBER).description("코드번호"),
+ fieldWithPath("codeName").type(JsonFieldType.STRING).description("코드명"),
+ fieldWithPath("description").type(JsonFieldType.STRING).description("설명").optional()
+ )
+));
+```
+```java
+/** Utils 만들어 사용 **/
+public interface RestDocumentUtils {
+
+ static OperationRequestPreprocessor getDocumentRequest() {
+ return preprocessRequest(modifyUris().scheme("http")
+ .host("spring.restdocs.test") // 실제 host 아님
+ .removePort(), prettyPrint());
+ }
+
+ static OperationResponsePreprocessor getDocumentResponse() {
+ return preprocessResponse(prettyPrint());
+ }
+}
+```
+```java
+/** 추상 클래스 작성 **/
+@WebMvcTest({
+ CommonCodeController.class,
+})
+@AutoConfigureRestDocs // 통합 테스트에서 Spring REST Docs를 활성화하고 구성하는 데 사용
+public abstract class ControllerTest {
+
+ @Autowired
+ protected MockMvc mockMvc;
+
+ @Autowired
+ protected ObjectMapper objectMapper;
+
+ @MockBean
+ protected CommonCodeService commonCodeService;
+}
+
+// 아래와 같이 상속받아 사용
+// class CommonCodeControllerRestDocsTest extends ControllerTest {
+```
+
+### 3) 테스트 성공
+위와 같이 작성한 테스트 코드가 통과하게 된다면 build/generated-snippets 경로 하위에 adoc 확장자 파일들이 여러 개 생성된 것을 확인할 수 있습니다. 파일을 하나씩 선택해서 보면 Asciidoc 문법에 맞게 작성된 내용과 미리보기를 확인할 수 있답니다.
+
+![gradle-build](https://github.com/Kernel360/blog-image/blob/main/2024/0124/gradle-build.png?raw=true)
+
+### 4) API 문서 틀 작성
+위에서 본 문서 조각들(snippets)을 그대로 활용할 수 있다면 좋겠지만, HTML 형태의 API 문서로 만들어 주기 위해서는 아직 추가적인 작업이 남아있습니다. 한 데 모아주는 작업을 해줘야 하는데요. 우선 저는 *index.adoc* 이라는 파일을 만들어 API별 adoc 파일을 include 하는 구조를 사용했습니다. 참고로 index.adoc 파일은 *src/docs/asciidoc 하위* 에 만들어주었는데 이 경로가 gradle을 사용할 경우의 기본 경로랍니다.
+
+```asciidoc
+// index.adoc
+= API Document
+// Asciidoc 문서의 구조와 스타일 정의
+:doctype: book
+:icons: font
+:source-highlighter: highlightjs
+:toc: left
+:toclevels: 2
+:sectlinks:
+
+// adoc 파일 include
+include::overview.adoc[]
+include::sample-api.adoc[]
+```
+```asciidoc
+// sample-api.adoc
+== 샘플 API
+
+[[공통코드-조회]]
+=== 공통코드 조회
+
+==== Request
+include::{snippets}/commoncode/get-common-codes/path-parameters.adoc[]
+
+===== HTTP Request 예시
+include::{snippets}/commoncode/get-common-codes/http-request.adoc[]
+
+==== Response
+include::{snippets}/commoncode/get-common-codes/response-fields-value.adoc[]
+
+===== HTTP Response 예시
+include::{snippets}/commoncode/get-common-codes/http-response.adoc[]
+```
+
+### 5) API 문서 생성
+이제 거의 마무리 단계인데요. gradle의 bootJar 작업을 실행시키면 build.gradle에 작성한 copyDocument 작업을 거쳐서 미리 지정한 resources/static/docs 경로 하위에 build 내에 생성되어 있던 html 파일이 복사되어 들어오고, 서버를 띄웠을 때 도메인 하위 /docs/index.html 경로로 접속해 API 문서를 확인할 수 있게 된답니다.
+
+![api-doc](https://github.com/Kernel360/blog-image/blob/main/2024/0124/api-doc.png?raw=true)
+
+### 6) API 문서 살펴보기
+최종적으로 만들어진 문서의 형태는 다음과 같습니다. 좌측에 ToC가 있어 원하는 API로의 이동이 간편하고 화면도 깔끔하지 않나요?
+
+![index-html](https://github.com/Kernel360/blog-image/blob/main/2024/0124/index-html.png?raw=true)
+
+## 5. 정리
+지금까지 저와 함께 API 문서부터 Spring REST Docs 적용기까지 살펴봤는데요. 읽기에 어떠셨을지 궁금합니다 😄
+
+Spring REST Docs를 적용하면서 여러 차례 시행착오를 거치며 보낸 시간이 생각나네요. 처음 접하는 부분이 많아 공식 문서, 영상, 블로그 등을 참고했는데 그 과정에서 조금씩 이해하게 되고 원하는 결과를 만들어낼 수 있어서 개인적으로 뿌듯하고 좋았던 경험이었습니다.
+
+아 그리고 이번 세미나를 준비하면서 추가적인 정보를 찾다가 알게 된 건데 Swagger와 Spring REST Docs의 장점만 취해서 API 문서화를 할 수 있는 방법도 있다고 해요. 가능하다면 다음에는 이 방식을 사용하거나 시간이 될 때 변경해볼 수 있으면 좋을 것 같다는 생각이 드네요.
+
+## 6. 참고자료
+- [Spring REST Docs](https://docs.spring.io/spring-restdocs/docs/current/reference/htmlsingle/)
+- [Spring REST Docs에 날개를… (feat: Popup)](https://techblog.woowahan.com/2678)
+- [Spring REST Docs를 사용한 API 문서 자동화](https://hudi.blog/spring-rest-docs)
+- [RestDocs로 API 문서화하기](https://velog.io/@junho5336/RestDocs%EB%A1%9C-API-%EB%AC%B8%EC%84%9C%ED%99%94%ED%95%98%EA%B8%B0)
+- [[ 스프링 기반 REST API ] 스프링 REST Docs 소개](https://youtu.be/BFme2t9KSwA?si=ziyQ3jC1l-tQ57Md)
+- [[10분 테코톡] 승팡, 케이의 REST Docs](https://youtu.be/BoVpTSsTuVQ?si=VG3mhS5b32l1EY_s)
+- [[Spring] restdocs + swagger 같이 사용하기](https://velog.io/@hwsa1004/Spring-restdocs-swagger-%EA%B0%99%EC%9D%B4-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0)
From e50b1e5528670c843bbdf9d71d68b9374918758e Mon Sep 17 00:00:00 2001
From: Joon <44130863+kkkapuq@users.noreply.github.com>
Date: Mon, 19 Feb 2024 18:37:21 +0900
Subject: [PATCH 22/50] =?UTF-8?q?feat=20:=2020231205=5F=ED=81=B4=EB=A6=B0?=
=?UTF-8?q?=EC=BD=94=EB=93=9C,=20=EB=AD=90=EB=B6=80=ED=84=B0=20=EC=8B=9C?=
=?UTF-8?q?=EC=9E=91=ED=95=B4=EB=B3=BC=EA=B9=8C=3F=5F=EC=A1=B0=ED=98=95?=
=?UTF-8?q?=EC=A4=80=20(#36)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_posts/2023-12-05-how-to-start-clean-code.md | 114 +++++++++++++++++++
1 file changed, 114 insertions(+)
create mode 100644 _posts/2023-12-05-how-to-start-clean-code.md
diff --git a/_posts/2023-12-05-how-to-start-clean-code.md b/_posts/2023-12-05-how-to-start-clean-code.md
new file mode 100644
index 0000000..4b8177f
--- /dev/null
+++ b/_posts/2023-12-05-how-to-start-clean-code.md
@@ -0,0 +1,114 @@
+---
+layout: post
+title: 클린코드, 뭐부터 시작해볼까?
+author: 조형준
+categories: 기술세미나
+banner:
+ image: https://github.com/Kernel360/blog-image/blob/main/2023/1205/1.png?raw=true
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+ tags: [클린코드, 기술세미나]
+---
+## 개요
+안녕하세요, 커널360의 크루로 활동중인 조형준입니다.
+이번 기술세미나의 주제는 '클린 코드'를 선정해봤습니다.
+클린코드는 '읽기 쉬운 코드', '협업하기 좋은 코드' 등과 같은 특징을 가지고 있는데요.
+본 포스팅에서 어떤것부터 시작하면 좋을 지 찬찬히 따져보도록 하겠습니다.
+
+## 클린코드?
+![2.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/2.png?raw=true)
+개발자 필독도서라고 한번쯤은 들어보셨을 그 책입니다.
+책의 이름이기도 하지만, 결과적으로는 좋은코드, 읽기 좋은 코드 등의 의미와 일맥상통한다고 생각합니다.
+클린코드에서 말하는 규칙은 여러개가 있는데, 몇가지만 톺아보자면 다음과 같습니다.
+- 함수는 하나의 기능만
+- 나쁜 주석 배제
+- 좋은 함수 이름
+- 철저한 네이밍 컨벤션
+- 고치기 쉬운 코드
+- 그 외 등등..
+
+## 적용 사례
+![3.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/3.png?raw=true)
+간단하게 예제를 하나 들어보겠습니다.
+위 코드는 제가 E2E 프로젝트에서 진행했던 코드인데요, 게시글의 좋아요 여부값을 가져오는 코드입니다.
+로직상으로는 크게 문제는 없지만, 어떤 문제가 있을까요? 다음과 같습니다.
+- 좋아요 여부값을 가져오는 함수에서 사용자의 이메일을 가져오고있음.
+- 함수의 역할에 맞지 않게 유저 정보를 가져오는 작업을 추가로 진행중
+- 자연스럽게 코드의 길이는 늘어나고, 가독성이 안좋아짐.
+
+위와 같은 문제를 해결하기 위해서, 다음과 같이 코드를 수정해봤습니다.
+![4.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/4.png?raw=true)
+게시글 좋아요의 여부를 가져오는 메서드와, 로그인 유저의 id를 가져오는 메서드를 분리했습니다.
+이처럼, 클린코드는 거창한게 아닙니다. 책임을 최대한 분리해주고, 가독성 향상을 위한 노력이 클린코드를 만들어줍니다.
+하지만 이렇게 수정한 코드도 누군가에겐 dirty code가 될테죠... (주륵)
+![5.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/5.png?raw=true)
+
+## 그렇다면 우리는 뭘 해야할까?
+To-do 도 중요하지만, 더 중요한 것은 Not-To-Do 라고 생각합니다.
+하지말라는 것만 안해도, 코드가 저절로 보기 좋아집니다.
+따라서, 본 포스팅에서 소개해드리는 안티패턴을 먼저 지양하고, 주니어 레벨에서 할 수 있는 것부터 천천히 실행해봅시다.
+
+### Arrowhead
+![6.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/6.png?raw=true)
+화살촉 패턴이라는 이름의 이 안티패턴은, 사진이 모든걸 설명해줍니다.
+과도한 if문으로 if문의 depth가 늘어나는 것을 지양해야 합니다. 아래와 같이 수정할 수 있겠습니다.
+![7.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/7.png?raw=true)
+
+### Magic numbers
+![8.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/8.png?raw=true)
+이 코드만 보고 무슨 로직인지 이해가 가시나요?
+이 코드는 유저의 id가 100, 즉 사장이라면 견적서를 수정할 수 있게 하라는 의미입니다.
+특정 상수가 특별한 의미를 갖지 말게 해야합니다. 다음처럼 수정할 수 있겠습니다.
+![9.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/9.png?raw=true)
+
+### Cryptic names
+![10.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/10.png?raw=true)
+이 친구도 사진이 모든걸 설명해줍니다.
+`i`, `p`가 도대체 뭘까... 사람이 이해할 수 있는 변수나 메서드명을 사용하자는 것입니다. 즉, 암호를 쓰지맙시다.
+다음과 같이 수정해봅시다.
+![11.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/11.png?raw=true)
+
+### Single funtion, Multiple behaviors
+![12.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/12.png?raw=true)
+하나의 함수가 여러 역할, 즉 책임을 맡지 말자는 의미입니다.
+위 코드는 calculate라는 함수가 사칙연산을 수행하고 있는데요, 다음과 같이 역할을 분리해줍시다.
+![13.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/13.png?raw=true)
+
+### God class
+![14.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/14.png?raw=true)
+하나의 클래스가 너무 많은 역할을 하지 않도록 하는 것입니다.
+방금 전 언급한 안티패턴과 일맥상통합니다.
+
+### Silencing Error/Exceptions
+![15.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/15.png?raw=true)
+이 패턴은 실제 개발을 하면서 많이 겪게되는 문제일 것 같은데요.
+조용한 에러와 예외를 만들지 말자는 것입니다. 말로는 조금 감이 안잡히실텐데, 위 코드의 문제점이 무엇일까요?
+해당 코드는 유저가 작성한 파일을 모두 삭제하고, 유저를 비활성화 시키는 로직입니다.
+그러나 모종의 이유로 try문에서 실행이 되지 않더라도, 유저를 비활성화 시키는 로직이 실행되게 됩니다.
+한 두명인 경우 큰 문제는 안되겠지만, 대규모 시스템이라면 당연히 문제가 되겠죠? 이런 코드는 아래와 같이 바꿔볼 수 있겠습니다.
+try-catch문을 지워서 에러가 터지면 바로 종료되게 하거나, 파일 삭제를 삭제될때까지 계속 돌리는겁니다.
+![16.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/16.png?raw=true)
+
+### Bad Comment
+![17.png](https://github.com/Kernel360/blog-image/blob/main/2023/1205/17.png?raw=true)
+> Good code is self-documenting
+> 좋은 코드는 그 자체로 이미 훌륭한 주석이다
+
+불필요한 주석이나, 너무 긴 주석은 자제하는 것이 좋습니다.
+다만, 도메인 지식이나 구성원들이 알면 좋은 정보들은 주석으로 남겨주면 좋습니다.
+
+## 마치며
+이렇게 클린코드를 뭐부터 시작해야 할지, 안티패턴들을 학습해보는 시간을 가졌습니다.
+간단하게 정리를 해보겠습니다.
+- 클린코드 법칙을 실천하기 앞서, 안티 패턴 코드를 지양하자.
+- 클린코드를 만드는 방법보다 좀 더 쉬울 것.
+- 안티 패턴 코드를 지양하면서, 클린코드 법칙을 천천히 적용하자.
+- 뭐가 됐건, 스스로 가독성이 좋은 코드라고 느껴질 때까지 리팩토링해보자.
+
+여러분들도 코드를 작성하시다가, 해당 포스트의 내용을 떠올리면서 코드를 작성한다면, 클린코드에 한층 더 가까워질 수 있을 것이라 생각합니다!
+
+**참고영상**
+[코드에 이런 짓만 안 해도 욕먹지 않는 개발자가 될 수 있어요! 미국 개발자들을 열받게 하는 코드 패턴 공개.](https://youtu.be/ixOk13jC50w?si=fAOotcSJAd8jalAd)
+
From d05cdaa492f69460270ea2fa87dd1d8c29c55384 Mon Sep 17 00:00:00 2001
From: linglong67 <88479739+linglong67@users.noreply.github.com>
Date: Mon, 19 Feb 2024 19:03:13 +0900
Subject: [PATCH 23/50] fix: Web API (20231121) (#34)
---
_posts/2023-11-21-web-api.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/_posts/2023-11-21-web-api.md b/_posts/2023-11-21-web-api.md
index ab4cbca..5243821 100644
--- a/_posts/2023-11-21-web-api.md
+++ b/_posts/2023-11-21-web-api.md
@@ -77,6 +77,7 @@ REST API의 주요 특징은 다음과 같습니다.
- 즉, 한 번의 요청으로 필요한 데이터를 모두 받아오지 못해 여러 번의 요청을 수행하는 것을 의미하며, 네트워크의 지연이 발생할 수 있고 사용자는 느린 로딩 속도로 인해 불편함을 겪을 수 있음
3. 다양한 엔드포인트
- REST API는 여러 엔드포인트가 존재하며, 각자의 역할을 하고 있으므로 클라이언트는 다양한 엔드포인트를 요청해야 함
+
```json
{
"books": [
@@ -116,6 +117,7 @@ GraphQL API의 주요 특징은 다음과 같습니다.
3. **실시간 데이터 업데이트**
- 실시간 데이터 업데이트를 지원
- 일반적으로 Subscription이라 불리는 메커니즘을 통해 이루어짐
+
```text
query {
user(id: 123) {
From ab99421fbc06a74aff3401c899321bc62887ca51 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=8B=A0=EC=A2=85=EB=AF=BC?=
<124959156+ShineCorine@users.noreply.github.com>
Date: Mon, 19 Feb 2024 19:03:24 +0900
Subject: [PATCH 24/50] feat: database normalization (1127, shin) (#35)
---
_posts/2023-11-27-database-normalization.md | 220 ++++++++++++++++++++
1 file changed, 220 insertions(+)
create mode 100644 _posts/2023-11-27-database-normalization.md
diff --git a/_posts/2023-11-27-database-normalization.md b/_posts/2023-11-27-database-normalization.md
new file mode 100644
index 0000000..2653cba
--- /dev/null
+++ b/_posts/2023-11-27-database-normalization.md
@@ -0,0 +1,220 @@
+---
+layout: post
+title: 데이터베이스 정규화 초급
+author: 신종민
+categories: 기술세미나
+banner:
+ image: https://github.com/Kernel360/blog-image/blob/main/2023/1127/Cover.jpeg
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+tags: [데이터베이스, 정규화, database 정규화, database normalization]
+---
+
+
+# 10분 기술세미나
+
+주제: 데이터베이스 정규화
+
+안녕하세요. 커널360 백엔드 1기 4셀 신종민입니다.
+
+제가 이번에 준비한 발표 주제는 데이터베이스의 정규화에 관한 내용입니다.
+부트업과 해커톤, 그리고 End to End 프로젝트를 거치면서 데이터베이스에 대해서 모르는 점이 많다는 점을 깨달았습니다. 파이널 프로젝트 외에도 앞으로도 백엔드 개발자로서 반드시 알아야 한다는 점을 깨닫고 데이터베이스에 대해 잘 알고싶어 발표 주제를 정하게 되었습니다.
+
+---
+## 1. 정규화의 정의
+정규화란 무엇일까요? 위키피디아에서는 다음과 같이 나왔습니다.
+
+> 관게형 데이터베이스의 설계에서 중복을 최소화하게 데이터를 구조화하는 프로세스
+
+> 크고, 제대로 조직되지 않은 테이블들과 관계들을 작고 잘 조직된 테이블과 관계들로 나누는 것
+
+> Database normalization is a database schema design technique, by which an existing schema is modified to minimize redundancy and dependency of data.(데이터베이스 정규화를 통해 데이터의 중복과 의존성을 최소화할 수 있다.)
+
+이라고 합니다.
+
+정규화는 데이터베이스 설계에서 중요한 개념 중 하나로, 중복을 최소화하고 데이터를 구조화하는 프로세스입니다. 이를 통해 데이터베이스의 효율성을 높이고 무결성을 유지할 수 있습니다.
+
+---
+## 2. 정규화의 목적
+데이터베이스 정규화의 구체적인 목적은 다음과 같습니다.
+- 데이터베이스의 변경 시 `이상현상` 제거
+- 데이터베이스 구조 확장 시 재 디자인 최소화
+- 사용자에게 데이터 모델을 더욱 의미있게 만듦
+- 다양한 질의 지원
+- 주된 목적은 중복을 최소화하고 데이터의 무결성을 유지하는 것.
+
+여기서 주요한 개념을 짚고 넘어가야 할 것 같습니다.
+첫 번째로 이상현상입니다.
+### 이상현상이란?
+테이블의 수정시 발생하는 원치 않는 부작용을 이상현상이라고 한다.
+이상현상에는 갱신이상, 삽입 이상, 삭제 이상이 있다.
+
+1. 삽입이상: 자료를 삽입할 때 의도하지 않은 자료까지 삽입해야만 테이블에 추가가 가능한 현상을 말한다.
+2. 갱신이상: 중복된 데이터 중 일부만 수정되어 데이터 모순이 일어나는 현상
+3. 삭제이상: 어떤 정보를 삭제하면, 의도하지 않은 다른 정보까지 삭제되어버리는 현상
+
+---
+## 3. 정규화의 단계
+정규화의 단계는 제1정규화, 제2정규화, 제3정규화, BCNF정규화, 제4정규화, 제5정규화로 총 6단계가 있으며 실무에서는 보통 제3정규화나 BCNF 정규까지 진행한다고 합니다.
+
+정규화는 단계적으로 이루어지며 각 단계는 특정한 종속성을 해결하고 데이터의 일관성을 향상시킵니다.
+
+### 제1정규화
+제1정규화란 테이블의 컬럼이 원자값을 갖도록 하는 것입니다.
+우리가 일 대 다 연관관계를 설정할 때, 객체는 일 쪽이 다 쪽의 객체를 포함하는 반면에,
+관계 테이블은 다 대 일 관계에서 일의 키를 '다'쪽이 foreign 키로 가지고 있는 것과 관련이되어 있습니다.
+
+제1정규화를 달성하지 않으면 어떤 문제가 있을까요? 즉 하나의 컬럼이 원자화되지 않거나, 동일한 값을 가지는 컬럼이 여러 가지가 나타나게 된다면 어떤 문제가 생길까요?
+
+
+제1정규화를 지키지 않으면 데이터베이스에서 어떤 문제가 발생할 수 있는지를 예시를 통해 자세하게 설명하겠습니다.
+
+제1정규화의 주요 목표는 각 컬럼이 원자적인 값을 가져야 한다는 것입니다. 즉, 각 컬럼의 값은 더 이상 분해되거나 중첩되지 않아야 합니다. 제1정규화를 위반하면 다음과 같은 문제가 발생할 수 있습니다.
+
+### 예시
+
+고객 정보를 저장하는 테이블이 있다고 가정해봅시다.
+
+| 고객ID | 이름 | 전화번호 |
+|--------|----------|--------------------|
+| 1 | 홍길동 | 010-1234-5678 |
+| 2 | 김영희 | 02-9876-5432 |
+| 3 | 이철수 | 010-1111-2222 |
+
+이 테이블은 초기에는 제1정규화를 따르고 있습니다. 그러나 만약 전화번호 컬럼에 여러 전화번호를 저장하려고 한다면, 제1정규화를 위반하게 됩니다.
+
+| 고객ID | 이름 | 전화번호 |
+|--------|----------|--------------------|
+| 1 | 홍길동 | 010-1234-5678 |
+| 2 | 김영희 | 02-9876-5432 |
+| 3 | 이철수 | 010-1111-2222, 02-3333-4444 |
+
+위의 예시에서는 고객ID 3의 레코드에서 전화번호가 두 개 이상이면서 컬럼에 여러 전화번호가 중첩되어 저장되어 있습니다. 이는 제1정규화를 위반한 상태입니다.
+
+### 문제점
+
+1. **데이터 중복성**: 전화번호 정보가 중첩되어 저장되면서 데이터 중복이 발생합니다. 이로 인해 `데이터 일관성`이 깨질 수 있습니다.
+
+2. **검색 및 정렬 어려움**: 특정 전화번호를 검색하거나 정렬하는 것이 어려워집니다. 또한 이러한 중첩된 데이터를 처리하는 `쿼리 작성이 복잡`해집니다.
+
+3. **확장성 문제**: 새로운 전화번호를 추가하거나 기존 전화번호를 수정할 때 일관성을 유지하기 어려워집니다.
+
+이처럼 제1정규화를 위반하면 데이터의 일관성과 유지보수가 어려워지는 문제가 발생할 수 있습니다. 따라서 각 컬럼은 원자적인 값을 가져야 하며, 필요한 경우 별도의 테이블을 생성하여 관계를 맺어주는 것이 좋습니다.
+
+---
+### 제2정규화
+제2정규화를 쉽게 설명하자면, 현재 테이블의 주제와 관련이 없는 컬럼을 별도의 테이블로 분리하는 작업을 말합니다.
+제2정규화는 기본 키가 `복합키`로 되어있는 경우, 한 필드가 기본키를 이루는 일부 필드에 종속되는 현상이 있을 때 `부분 종속성`이 있다고 하는데, 이 부분 종속성을 제거하는 과정을 제2정규화라고 합니다.
+> 따라서 부분 함수 종속성은 기본키가 `복합키`로 되어 있을 경우 발생합니다.
+
+> 완전 함수 종속성: 모든 속성이 기본 키에 종속됐을 경우 완전 함수 종속성이 있다고 합니다.
+
+제2정규화를 이해하기 위해, 우선 제2정규화가 지켜지지 않은 상황에서 발생할 수 있는 문제를 예시를 통해 살펴보겠습니다.
+
+### 예시
+
+고객과 주문 정보를 저장하는 테이블이 있다고 가정해봅시다.
+
+**고객 테이블 (Customer Table):**
+
+| 고객ID | 이름 | 주소 |
+|--------|----------|---------------------|
+| 1 | 홍길동 | 서울 강남구 |
+| 2 | 김영희 | 부산 해운대구 |
+| 3 | 이철수 | 인천 남동구 |
+
+**주문 테이블 (Order Table):**
+
+| 고객ID | 주문일자 | 상품 | 가격 |
+|--------|------------|-------------|--------|
+| 1 | 2022-01-01 | 노트북 | 1,500,000|
+| 2 | 2022-01-02 | 스마트폰 | 800,000|
+| 1 | 2022-01-03 | 테블릿 | 600,000|
+| 3 | 2022-01-04 | 노트북 | 1,000,000|
+
+여기서 주문 테이블은 고객 테이블과 관련이 있습니다. 그러나 주문 테이블에서는 각 주문의 상품과 가격 정보가 함께 저장되어 있습니다.
+
+### 문제점
+
+1. **부분 종속성**: 위의 주문 테이블은 (고객ID, 주문일자, 상품)이 복합키를 이루는데요, 상품의 가격은 기본키가 아닌 일부 컬럼인 상품에만 종속되어 있습니다.
+
+2. **데이터 중복성**: 같은 상품을 여러 번 주문 했을 경우 같은 상품에 대한 가격이 곳곳에 흩어져 중복되어 저장되어 있습니다.
+
+### 제2정규화의 적용
+
+제2정규화는 부분 종속성을 해결하기 위한 것입니다. 주문 테이블을 정규화하여 두 개의 테이블로 나누어 보겠습니다.
+
+**고객 테이블 (Customer Table):**
+
+| 고객ID | 이름 | 주소 |
+|--------|----------|---------------------|
+| 1 | 홍길동 | 서울 강남구 |
+| 2 | 김영희 | 부산 해운대구 |
+| 3 | 이철수 | 인천 남동구 |
+
+**주문 테이블 (Order Table):**
+
+| 고객ID | 주문일자(년-월-일))| 상품 ID|
+|--------|------------|--------|
+| 1 | 2022-01-01 | 1001 |
+| 2 | 2022-01-02 | 1002 |
+| 1 | 2022-01-03 | 1003 |
+| 3 | 2022-01-04 | 1001 |
+
+**상품 테이블 (Product Table):**
+
+| 상품ID | 상품 | 가격(원) |
+|--------|-------------|--------|
+| 1001 | 노트북 | 1,500,000 |
+| 1002 | 스마트폰 | 800,000 |
+| 1003 | 테블릿 | 600,000 |
+| 1004 | 데스크탑 | 2,000,000 |
+
+이렇게 분리된 테이블은 각 테이블이 각자의 의미를 가지며, 부분 종속성 문제가 해결됩니다. 고객 테이블은 주문 테이블에 대해 부분 종속성이 없어지고, 데이터 중복성이 줄어들어 더 효율적인 데이터 관리가 가능해집니다.
+
+
+---
+### 제3정규화
+제3정규화는 `이행함수 종속성`을 제거하는 과정을 말합니다. 이행하수 종속성이란 어느 컬럼이 기본 키가 아닌 다른 컬럼에 정속되는 현상을 말합니다.
+
+
+자세한 예시를 통해 이행함수 종속성을 이해해보겠습니다.
+
+고려할 테이블은 학생과 학과에 대한 정보를 담고 있는 테이블입니다.
+
+**학생 테이블 (Students Table):**
+
+| 학번 | 이름 | 전공 |
+|--------|--------|--------|
+| 1001 | 홍길동 | 컴퓨터과학 |
+| 1002 | 김영희 | 경영학 |
+| 1003 | 이철수 | 전자공학 |
+
+여기서 학번은 이름을 결정하고, 이름은 전공을 결정합니다. 이 경우, 학번 → 이름, 이름 → 전공이 성립합니다.
+
+이제 이를 정규화하기 위해 학번과 이름을 가지는 테이블과 이름과 전공을 가지는 테이블로 나누어 보겠습니다.
+
+**학생 테이블 (Students Table):**
+
+| 학번 | 이름 |
+|--------|--------|
+| 1001 | 홍길동 |
+| 1002 | 김영희 |
+| 1003 | 이철수 |
+
+**전공 테이블 (Major Table):**
+
+| 이름 | 전공 |
+|--------|--------|
+| 홍길동 | 컴퓨터과학 |
+| 김영희 | 경영학 |
+| 이철수 | 전자공학 |
+
+이제 학번과 이름이 하나의 테이블에서 다른 테이블로 분리되었습니다. 이를 통해 학번이 이름에, 이름이 전공에 이행함수 종속되던 문제를 해결할 수 있습니다. 이렇게 데이터 중복성을 최소화하고 테이블 간의 의미 있는 관계를 유지하며 정규화가 이뤄진 것입니다.
+
+---
+## 마무리
+적절한 수준의 데이터베이스 정규화로 데이터를 중복되지 않고 이상현상이 발생하지 않도록 할 수 있습니다.
+하지만 정규화를 하면 join 연산의 필요성도 늘어나서 비정규화 과정을 거치는 사례도 있는만큼 상황에 맞는 적절한 전략이 필요합니다.
\ No newline at end of file
From 9f16a49c764f13e17dd1f42c29a6d56c24320a88 Mon Sep 17 00:00:00 2001
From: minson96 <118032886+minson96@users.noreply.github.com>
Date: Mon, 19 Feb 2024 19:19:19 +0900
Subject: [PATCH 25/50] =?UTF-8?q?0117=20=EA=B8=B0=EC=88=A0=EC=84=B8?=
=?UTF-8?q?=EB=AF=B8=EB=82=98=20=EB=B8=94=EB=A1=9C=EA=B7=B8=20=EA=B2=8C?=
=?UTF-8?q?=EC=8B=9C=EA=B8=80=20=EC=B6=94=EA=B0=80=20(#37)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_posts/2024-01-17-docker-replication.md | 176 ++++++++++++++++++++++++
1 file changed, 176 insertions(+)
create mode 100644 _posts/2024-01-17-docker-replication.md
diff --git a/_posts/2024-01-17-docker-replication.md b/_posts/2024-01-17-docker-replication.md
new file mode 100644
index 0000000..3f87f94
--- /dev/null
+++ b/_posts/2024-01-17-docker-replication.md
@@ -0,0 +1,176 @@
+---
+layout: post
+title: 배포있게 배포하기 -DB편-
+author: 손민우
+categories: 기술세미나
+banner:
+ image: https://github.com/Kernel360/blog-image/blob/main/2024/0117/1.png?raw=true
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+ tags: [Docker, AWS, DB]
+---
+
+다시 돌아온 Docker 세미나 시간입니다. 어쩌다보니 오픈세미나에 이어서 이번 주제도 Docker와 관련한 주제로 선택을 하게 되었는데요. (정말 파도 파도 공부해야 하는 부분이 계속 나오더라구요.)
+
+이전 오픈 세미나에서는 Docker의 기본적인 내용을 설명을 했다면 오늘 설명드릴 내용은 DB replication을 Docker를 통해서 적용해 보고 이를 쉽게 적용할 수 있도록 나온 서비스인 AWS RDS를
+
+통해서 이해하는 시간을 가져보려고 합니다. 그럼 시작해보겠습니다.
+
+## 1. Docker-Compose는 무엇인가?
+
+
+
+
+
+아마 Docker를 공부하다 보면 Docker-Compose에 대해서 이름은 들어보셨을 거라 생각됩니다. 제가 처음 Docker-Compose를 접하게 되었을 때 느꼈던 점은 사용만 할 줄 안다면 좋은 툴이 될 것
+같은데 그 과정이 쉽지 않을 것 같다는 생각이 정말 많이 들었습니다.
+
+그래서 이러한 생각을 좀 줄여 보고자 MySQL을 예로 들어 Docker-Compose를 작성해 보겠습니다.
+
+## 2. Docker-Compose로 MySQL 실행하기
+
+
+
+
+
+다음 사진은 MySQL을 실행시키기 위한 docker-compose.yml 파일의 내용입니다. 다음은 설명입니다.
+|옵션|설명|
+|------|---|
+|image|docker를 실행할 image:tag를 설정합니다. ex) ubuntu, linux, mysql, postgresql ...|
+|ports|port를 설정하는 옵션으로 [host port]:[container 내부 port]를 의미합니다.|
+|environment|container를 실행할 때 환경 변수를 추가한 상태로 실행할 수 있습니다. 각 이미지마다 환경 변수가 다를 수 있어 확인한 후 사용해야 합니다. ex) MYSQL_ROOT_PASSWORD: 1234 |
+|command|컨테이너를 실행 한 후 내부에서 명령어를 실행해 적용할 수 있습니다.|
+|volumes|마운트를 지정하게 되면 이후 컨테이너가 종료되거나 삭제되더라도 이후 연결되는 컨테이너가 같은 경로에 마운트 된다면 이전 데이터를 받을 수 있습니다.|
+
+어떤가요? 이렇게 보면 docker-compose라는 것은 단순하게 script의 형태를 띄기 때문에 각각의 의미만 안다면 어렵지 않습니다. 이제 간단하게 해봤으니 DB replication도 진행해보도록 하겠습니다.
+
+## 3. MySQL DB replication 구성해보기
+
+DB replication을 진행하기 전에 간단하게 replication에 대해 알아보겠습니다.
+
+DB replication은 데이터 저장과 백업하는 방법에 관련이 있는 데이터를 호스트 컴퓨터에서 다른 컴퓨터(컨테이너)로 복사하는 것을 의미합니다. 그렇다면 왜 필요할까요?
+
+서비스를 운영함에 있어서 읽기에 대한 요청은 읽기 이외의 요청 (생성, 수정, 삭제)에 비해 많은 비중을 가지게 됩니다. 그렇기 때문에 읽기에 대한 요청을 전담하여 맡아줄 DB를 생성해 DB로 하여금 부하를
+감소시킬 수 있도록 역할을 할 수 있습니다.
+
+
+
+
+
+다음 사진은 이제 진행할 db replication의 파일 구조입니다.
+위 파일 구조는 master-slave가 1 대 1로 되어 있지만 설정에 따라 N 대 N이 될 수도 있습니다.
+
+
+
+
+
+
+
+
+
+![image.jpg1](https://raw.githubusercontent.com/Kernel360/blog-image/main/2024/0117/5.png) |![image.jpg2](https://raw.githubusercontent.com/Kernel360/blog-image/main/2024/0117/6.png)--- |--- |
+
+위의 스크립트는 순서대로 master-db와 slave-db의 Docker-Compose의 내용이다. 위에서 설명하지 않는 옵션은 다음과 같습니다.
+
+|옵션|설명|
+|------|---|
+|build| context는 build를 실행한 경로를 dockerfile은 dockerfile이 위치한 경로를 입력해주면 됩니다.|
+|restart|재시작과 관련한 옵션으로 현재 항상 재시작한다는 옵션으로 지정되어 있습니다.|
+|networks|docker에는 network를 통해 컨테이너 간의 연결을 진행하고 데이터를 주고받을 수 있으며 기본값은 bridge network입니다.|
+
+docker-compose.yml파일 외에도 my.cnf와 Dockerfile이 있는데 이때 Master와 Slave의 차이는 파일 경로와 읽기 전용 옵션 외에는 동일하여 Master를 기준으로 보겠습니다.
+
+
+
+
+
+Dockerfile에서 내용은 다음과 같습니다.
+
+|옵션|설명|
+|------|---|
+|FROM|컨테이너의 환경을 지정하는 옵션으로 mysql이미지를 실행한다는 의미입니다.|
+|ADD|host에 위치한 파일을 컨테이너 내부 위치에 추가한다는 의미입니다. mysql의 configure 파일을 교체하여 내가 정한 규칙대로 실행되도록 합니다.|
+
+my.cnf 파일의 내용입니다.
+
+
+
+
+
+현재 있는 파일에서 초록색 표시가 되어있는 read_only 옵션은 Slave-db가 가지고 있는 옵션으로 읽기 전용으로 사용하기 위한 옵션입니다.
+
+이렇게 준비가 되었다면 docker-compose up -d 명령어를 통해 실행을 시키면 다음과 같은 log와 설정을 볼 수 있습니다.
+
+
+
+
+
+
+
+
+
+성공적으로 build가 되었다면 이제 db로 접속하여 설정을 진행해주어야 합니다.
+replication에 대한 유저를 생성하고 권한을 부여하는 과정입니다.
+
+
+
+
+
+권한 부여 이후에는 Slave DB에서 Master DB로 바라볼 수 있도록 설정을 수정합니다.
+
+
+
+
+
+설정을 진행한 이후 아래 명령어를 통해 동일한 내용이 나온다면 성공적으로 설정된 것을 볼 수 있습니다.
+
+
+
+
+
+Docker를 사용하여 replication을 진행하는 과정은 이렇게 마무리할 수 있습니다. 긴 과정일 수 있지만 실제로는 dockerfile과 docker-compose.yml, my.cnf만 여러 개 둔다면
+규모가 큰 DB replication도 가능하기 때문에 오히려 구성하기 어렵지 않았다고 생각됩니다.
+
+하지만 개발자 입장에서 개발에 더 몰입할 수 있도록 간단하게 구성할 수 있는 서비스가 AWS RDS입니다.
+
+## 4. AWS RDS란?
+
+AWS RDS(Amazon Relational Database Service)는 aws에서 제공되는 서비스로 MySQL 뿐만 아니라, PostgreSQL, Aurora, Oracle 등 여러 DB를 간단하게 구현할 수 있습니다.
+단일 구성 뿐 아니라 위에서 진행했던 DB replication도 보다 쉽게 구성할 수 있습니다. 그럼 AWS RDS로도 DB replication을 구성해 보도록 하겠습니다.
+
+## 5. AWS RDS replication 구성해보기
+
+처음 AWS에 접속하여 RDS로 이동하면 다음과 같은 화면을 볼 수 있고 데이터베이스 생성 버튼을 누릅니다.
+
+
+
+
+
+그 다음 여러 엔진 유형 중 제가 생성하고자 하는 MySQL을 선택하고 Database명, 비밀번호 등을 설정합니다.
+
+
+
+
+
+이때 외부에서 접속하고자 한다면 퍼블릭 엑세스를 예로 채크해야 합니다. 이렇게 설정을 마치고 생성을 진행하면 5 ~ 10분 정도를 기다리면 생성이 완료 됩니다.
+
+
+
+
+
+생성이 완료되면 생성된 DB를 선택하고 작업에서 읽기 전용 복제본 생성을 진행하고 위의 생성과정을 반복합니다.
+
+
+
+
+
+이렇게 하면 자동으로 RDS 내에서 master와 slave가 적용되며 db를 동일하게 백업하고 저장되는 것을 확인할 수 있습니다.
+Docker를 사용하는 것도 간단해 보였지만 AWS RDS를 사용하니 더욱 간단하게 구현을 마무리할 수 있었습니다.
+
+## 6. 마무리
+
+결론은 AWS RDS로 구현하는 것이 간단하다가 아닌 Docker를 통해서 구성하는 것을 토대로 AWS RDS를 이해하는 시간이 되었으면 좋겠습니다. (물론 개념적인 부분에 대한 설명이 부족하지만 ...)
+이러한 과정을 반복하는 것 만으로도 전체적인 흐름을 이해하는데 도움이 될 것이라고 생각합니다.
+끝까지 읽어주셔서 감사합니다.
From 28aa735d09f7423a29e632e2122e43c855c8248d Mon Sep 17 00:00:00 2001
From: minson96 <118032886+minson96@users.noreply.github.com>
Date: Mon, 19 Feb 2024 19:30:21 +0900
Subject: [PATCH 26/50] =?UTF-8?q?0117=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?=
=?UTF-8?q?=EC=88=98=EC=A0=95=20(#38)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_posts/2024-01-17-docker-replication.md | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/_posts/2024-01-17-docker-replication.md b/_posts/2024-01-17-docker-replication.md
index 3f87f94..5034096 100644
--- a/_posts/2024-01-17-docker-replication.md
+++ b/_posts/2024-01-17-docker-replication.md
@@ -62,15 +62,7 @@ DB replication은 데이터 저장과 백업하는 방법에 관련이 있는
다음 사진은 이제 진행할 db replication의 파일 구조입니다.
위 파일 구조는 master-slave가 1 대 1로 되어 있지만 설정에 따라 N 대 N이 될 수도 있습니다.
-
-
-
-
-
-
-
-
-![image.jpg1](https://raw.githubusercontent.com/Kernel360/blog-image/main/2024/0117/5.png) |![image.jpg2](https://raw.githubusercontent.com/Kernel360/blog-image/main/2024/0117/6.png)--- |--- |
+![image.jpg1](https://raw.githubusercontent.com/Kernel360/blog-image/main/2024/0117/5.png) ![image.jpg2](https://raw.githubusercontent.com/Kernel360/blog-image/main/2024/0117/6.png)
위의 스크립트는 순서대로 master-db와 slave-db의 Docker-Compose의 내용이다. 위에서 설명하지 않는 옵션은 다음과 같습니다.
@@ -107,11 +99,12 @@ my.cnf 파일의 내용입니다.
+성공적으로 build가 되었다면 이제 db로 접속하여 설정을 진행해주어야 합니다.
+
-성공적으로 build가 되었다면 이제 db로 접속하여 설정을 진행해주어야 합니다.
replication에 대한 유저를 생성하고 권한을 부여하는 과정입니다.
From d3c36e0a094dec3f78fa7a584c3f36d0fa4cfef5 Mon Sep 17 00:00:00 2001
From: AN-SOHYEON
Date: Mon, 19 Feb 2024 20:22:38 +0900
Subject: [PATCH 27/50] =?UTF-8?q?feat:=2020231120=5Fspring=5Fsecurity=5F?=
=?UTF-8?q?=EC=95=88=EC=86=8C=ED=98=84=20(#39)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/CODEOWNERS | 3 +-
_posts/2023-11-15-Https.md | 2 +-
_posts/2023-11-20-spring-security-6.md | 110 ++++++++++++++++++
_posts/2023-11-27-database-normalization.md | 2 +-
...ding-test.md => 2024-01-25-coding-test.md} | 0
5 files changed, 113 insertions(+), 4 deletions(-)
create mode 100644 _posts/2023-11-20-spring-security-6.md
rename _posts/{2023-01-25-coding-test.md => 2024-01-25-coding-test.md} (100%)
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 1d9e21e..eb8670f 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,5 +1,4 @@
-* @anso33
-*.md @anso33 @Hju95
+*.md @anso33
/_posts @anso33
diff --git a/_posts/2023-11-15-Https.md b/_posts/2023-11-15-Https.md
index 25d5adf..05bf702 100644
--- a/_posts/2023-11-15-Https.md
+++ b/_posts/2023-11-15-Https.md
@@ -4,7 +4,7 @@ title: Https 누구냐 넌?
author: 손현준
categories: 기술세미나
banner:
- image: https://raw.githubuserconten.com/Kernel360/blog-image/main/2023/1115/1.png
+ image: https://github.com/Kernel360/blog-image/blob/main/2023/1115/1.jpg?raw=true
background: "#000"
height: "100vh"
min_height: "38vh"
diff --git a/_posts/2023-11-20-spring-security-6.md b/_posts/2023-11-20-spring-security-6.md
new file mode 100644
index 0000000..197797f
--- /dev/null
+++ b/_posts/2023-11-20-spring-security-6.md
@@ -0,0 +1,110 @@
+---
+layout: post
+title: Spring Security Authentication 구조 훑어보기
+author: 안소현
+categories: 기술세미나
+banner:
+ image: https://github.com/Kernel360/blog-image/blob/main/2023/1120/11.png?raw=true
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+ tags: [spring, spring security]
+---
+
+안녕하세요. 스프링 시큐리티의 전체적인 인증 구조에 대해서 발표할 안소현입니다.
+
+스프링 시큐리티, 무엇일까요?
+
+스프링 시큐리티는 스프링 기반의 애플리케이션 보안을 담당하는 스프링 하위의 프레임워크입니다.
+
+우리가 시큐리티 로직을 짤 때 흔히 인증과 인가으로 나눌 수 있죠.
+
+인증(authentication)은 사용자의 신원을 입증하는 과정으로 사용자가 사이트에 로그인을 할 때 누구인지 확인하는 과정이고 인가는 사이트의 특정 부분에 접근할 수 있는지에 대한 권한을 확인하는 작업이죠!
+
+앞으로 발표할 내용은 spring docs에 나와있는 내용을 기반으로 작성되어 있습니다.
+
+스프링 시큐리티 독스에는 정말 많은 내용이 담겨있는데 우리는 오늘 이 중에서
+
+![1](https://github.com/Kernel360/blog-image/blob/main/2023/1120/1.png?raw=true)
+
+서블릿 애플리케이션에서의 스프링 시큐리티를 알아볼겁니다.
+
+
+## Delegating Filter Proxy
+
+클라이언트에서 요청이 오면 WAS의 필터체인을 타고 이 체인 안에서 Spring Security 관련 Filter Chain을 거치게 되는데요.
+
+![2](https://github.com/Kernel360/blog-image/blob/main/2023/1120/2.png?raw=true)
+
+그림을 보시면 SecurityFilterChain이 WASFilterChain에 등록되어 있다기보다는 DelegatingFilterProxy의 한 부분으로 들어간 것 같은 모습을 볼 수 있습니다.
+
+왜 그럴까요?
+
+
+Spring Security는 Spring 컨테이너에서 생성된 필터를 사용하여 스프링 컨테이너의 빈으로 등록됩니다.
+
+하지만 정작 클라이언트의 요청은 서블릿 필터를 기반으로 한 필터 체인을 타게 되죠.
+
+이때 서블릿 필터는 스프링에서 정의된 빈을 주입받아 사용할 수 없기 때문에 우리가 만든 security 필터를 사용할 수 없게 되죠!
+
+그래서 서블릿 컨테이너에서 관리되는 프록시용 필터인 DelegatingFilterProxy를 사용하여 WASFilterChain에 우리가 만든 security filterChain을 연결시켜주는 겁니다.
+
+조금 어렵죠…?ㅋㅋ
+
+![12](https://github.com/Kernel360/blog-image/blob/main/2023/1120/12.png?raw=true)
+
+즉, 정리하자면 간단히 말해서 스프링 빈과 서블릿 컨테이너의 생명주기를 연결하기 위해 DelegatingFilterProxy라는 Filter 구현체를 사용한다고 생각하시면 됩니다.
+
+
+
+## spring security authentication 구조
+
+그럼 이제 spring security authentication 구조로 들어가볼까요?
+
+![3](https://github.com/Kernel360/blog-image/blob/main/2023/1120/3.png?raw=true)
+
+spring security 구조 라고 검색하면 흔히 볼 수 있는 사진, 저도 가져왔습니다. ㅋㅋ
+
+이 구조는 가장 basic인 유저의 id, password를 받는 formLogin의 상황입니다.
+
+![13](https://github.com/Kernel360/blog-image/blob/main/2023/1120/13.png?raw=true)
+
+먼저 사용자가 http request로 로그인 정보와 함께 인증 요청을 합니다. 이때 Authentication Filter가 요청을 가로채고, 가로챈 정보를 기반으로 UsernamePasswordAuthentication Token을 생성합니다.
+
+UsernamePasswordAuthenticationToken, 이 아이가 결국 구현하고자 하는 것은 Authentication 인데요.
+
+![4](https://github.com/Kernel360/blog-image/blob/main/2023/1120/4.png?raw=true)
+![5](https://github.com/Kernel360/blog-image/blob/main/2023/1120/5.png?raw=true)
+
+![6](https://github.com/Kernel360/blog-image/blob/main/2023/1120/6.png?raw=true)
+
+이 Authentication은 추후 우리가 하나의 request 처리 흐름동안 들고다니면서 security 로직에 사용할 security context에 담기는 내용으로
+
+우리가 흔히 Userdetails에 두었던 principal, 주로 비밀번호를 가져오는 credentials, 권한 정보인 authorities 정보를 담고 있습니다.
+
+
+다음으로 AuthenticationManager의 구현체인 ProviderManager에게 생성한 UsernamePasswordToken 객체를 전달합니다.
+
+![14](https://github.com/Kernel360/blog-image/blob/main/2023/1120/14.png?raw=true)
+
+앞서 말했듯 **ProviderManager는 AuthenticationManager의 가장 일반적인 구현체이고 ProviderManager는 ‘AuthenticationProvider 목록’을 가지고 있습니다.**
+
+이 목록을 조회하면서 해당 Authentication의 인증을 지원하는 Authentication Provider를 찾아서 인증 역할을 위임합니다.
+
+![7](https://github.com/Kernel360/blog-image/blob/main/2023/1120/7.png?raw=true)
+
+다음으로 유저의 정보를 인증하는 과정인데요!
+
+**각 AuthenticationProvider는 인증 성공, 실패, 결정할 수 없음을 나타낼 수 있고, 나머지 AuthenticationProvider가 결정을 할 수 있도록 전달합니다. 인증을 결정할 수 있는 프로바이더는 자신의 authenticate메서드를 통해서** 입력으로 들어온 authentication을 자신만의 방식으로 검증하여 성공할 시 인증 성공된 토큰을 리턴하고 실패할 시에는 AuthenticationException을 던집니다.
+
+authentication을 검증할 수 있는 자신만의 방식에는 DB 비교도 있고, 시그니처 비교도 있고,, 여러 가지 방법들이 있겠죠??
+
+![10](https://github.com/Kernel360/blog-image/blob/main/2023/1120/10.png?raw=true)
+
+이제 마지막 코스입니다! 이렇게 생성된 Authentication 객체는 다시 최초의 AuthenticationFilter에 반환되고 이 Authenticaton 객체를 SecurityContext에 저장하면서 인증이 끝나게 됩니다.
+
+여기까지 spring security의 기본적인 구조였습니다.
+
+
+
diff --git a/_posts/2023-11-27-database-normalization.md b/_posts/2023-11-27-database-normalization.md
index 2653cba..c7952f1 100644
--- a/_posts/2023-11-27-database-normalization.md
+++ b/_posts/2023-11-27-database-normalization.md
@@ -4,7 +4,7 @@ title: 데이터베이스 정규화 초급
author: 신종민
categories: 기술세미나
banner:
- image: https://github.com/Kernel360/blog-image/blob/main/2023/1127/Cover.jpeg
+ image: https://github.com/Kernel360/blog-image/blob/main/2023/1127/Cover.jpeg?raw=true
background: "#000"
height: "100vh"
min_height: "38vh"
diff --git a/_posts/2023-01-25-coding-test.md b/_posts/2024-01-25-coding-test.md
similarity index 100%
rename from _posts/2023-01-25-coding-test.md
rename to _posts/2024-01-25-coding-test.md
From 2f6d6cc7d1b8226c116c8aa9671525cbf4d0c64f Mon Sep 17 00:00:00 2001
From: gunsight <103917282+gunsight1@users.noreply.github.com>
Date: Mon, 19 Feb 2024 20:37:14 +0900
Subject: [PATCH 28/50] =?UTF-8?q?JVM=20=EA=B8=B0=EC=88=A0=EC=84=B8?=
=?UTF-8?q?=EB=AF=B8=EB=82=98=20=EC=9E=91=EC=84=B1=20(#40)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_posts/2023-12-01-RDBMS.md | 3 +-
_posts/2024-02-02-JVM.md | 174 +++++++++++++++++++++++++++++++++++++
2 files changed, 176 insertions(+), 1 deletion(-)
create mode 100644 _posts/2024-02-02-JVM.md
diff --git a/_posts/2023-12-01-RDBMS.md b/_posts/2023-12-01-RDBMS.md
index 7e1376c..ec57a35 100644
--- a/_posts/2023-12-01-RDBMS.md
+++ b/_posts/2023-12-01-RDBMS.md
@@ -4,7 +4,8 @@ title: RDBMS의 조회과정, 쿼리실행계획 중요성
author: 정지용
categories: 기술세미나
banner:
- image: https://github.com/gunsight1/blog/assets/103917282/6c386616-902b-4bc5-98b6-f6b26c15b2e8
+ image: https://github.com/Kernel360/blog-image/blob/main/2023/1201/header.png?raw=true
+
background: "#000"
height: "100vh"
min_height: "38vh"
diff --git a/_posts/2024-02-02-JVM.md b/_posts/2024-02-02-JVM.md
new file mode 100644
index 0000000..9def99c
--- /dev/null
+++ b/_posts/2024-02-02-JVM.md
@@ -0,0 +1,174 @@
+---
+layout: post
+title: JVM
+author: 정지용
+categories: 기술세미나
+banner:
+ image: https://github.com/Kernel360/blog-image/blob/main/2024/0202/header.jpg?raw=true
+
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+ tags: [JVM, JAVA, Jit, Jrockit, WORA, 기술세미나]
+---
+
+
+# JVM
+
+반갑습니다.
+지난시간 RDBMS에 이어 이번에는 JVM을 주제로 기술세미나 발표를 한 정지용 입니다.
+
+## [1. 개요]
+
+우리가 자바를 공부하고, 스프링을 쓰고 있지만
+
+기업의 니즈 때문에 라는 이유를 빼고, 왜 자바를 쓰는지 생각해보신적 있으신가요?
+
+제가 생각하는 자바를 쓰는 이유는 객체지향이라는 개념적인 부분도 있겠지만
+
+우리가 도커를 사용하듯 OS에 종속이 최소인 기술적 장점도 있기 때문이라 생각합니다.
+
+이번 시간에는 JVM이란 무엇인지 일부 알아보는 시간을 가져보고자 합니다.
+
+
+
+## [2. JVM란?]
+
+![image](https://github.com/Kernel360/blog-image/blob/main/2024/0202/1.png?raw=true)
+
+JVM은 이름 그대로 자바를 가상의 환경에서 작동시켜주는 소프트웨어입니다.
+
+WORA 원칙을 가지고 있어 한번 작성하면 어디서든 동일하게 실행 할 수 있도록 설계되었습니다.
+
+JVM의 요소는 아래와 같은 항목들이 존재합니다.
+
+이 항목들을 10분이라는 짧은 시간동안 전부 알기엔 부족하므로, 초록색 글씨의 2가지만 살펴보고자 합니다.
+
+
+
+## [3. C vs JAVA]
+
+![image](https://github.com/Kernel360/blog-image/blob/main/2024/0202/2.png?raw=true)
+
+이 과정을 알기 위해선 불가피하게 C와 JAVA의 컴파일 과정 차이를 알아야 합니다.
+
+C언어는 이미지의 왼쪽처럼 다양한 과정을 통해 결국 기계어로 변환하여 CPU의 명령어 세트에 맞춰지고,
+
+이로 인해 다른 CPU에서 동일한 코드를 실행하려면 그에 맞는 재컴파일을 해야합니다.
+
+이번에 맥OS 환경에서 구축 된 도커 이미지를 vultr에 도커 컨테이너로 올려보셨다면
+
+아키텍쳐가 달라서 실행이 불가하다는 이슈를 접하셨을텐데, 매우 유사한 시나리오 입니다.
+
+자바는 그에 비해 우리가 작성한 소스 코드를 바이트 코드로 변환합니다.
+
+JVM은 이 바이트 코드를 OS에 맞는 네이티브 코드로 변환하고 실행합니다.
+
+이 역할을 해주는 담당자가 JVM의 요소중 누구냐면 바로 다음장에 나오는 Jit Compiler 입니다.
+
+
+
+## [4. Jit Compiler]
+
+![image](https://github.com/Kernel360/blog-image/blob/main/2024/0202/3.png?raw=true)
+
+오른쪽 이미지를 보시면 HotSpot VM 라는 아키텍처 이미지가 있는데,
+
+간단히 말하자면 Hotspot VM은 JVM을 실행하는 런처와 스레드 관리, JNI 관리 등을 하는 곳이고
+
+테트리스 맞추듯 GC와 컴파일러를 끼워맞춰 사용합니다.
+
+C 컴파일러는 한번 컴파일을 요구하면 바이트 코드까지 한번에 만들어 버리는데,
+
+자바는 실제 애플리케이션 실행에 필요한 네이티브 코드를 만드는 책임을 JVM에게 넘겼습니다.
+
+그렇기 때문에 JVM은 항상 바이트 코드로 시작하여 동적으로 네이티브 코드로 바뀝니다.
+
+모든 코드는 이미지에 보이는 인터프리터에 의해 어떤 코드들이 있는지 인지는 되지만
+
+실질적인 컴파일은 해당 코드가 많이 사용되는 우선순위에 따라 결정됩니다.
+
+그 결정을 담당하는건 옵티마이저가 하고,
+
+수행카운터와 백에지카운터라는 두개의 카운터에 의해 우선순위가 결정됩니다.
+
+쉽게 풀어서 말하자면 수행카운터는 메서드가 시작 할 때마다 증가하는 값이고
+
+백에지 카운터는 메서드가 얼마나 반복적으로 수행되는지를 체크하는 값입니다.
+
+그렇게 결정된 우선순위에 따라 큐에 컴파일요청을 쌓게되고, 컴파일러는 순서대로 컴파일을 합니다.
+
+JVM 옵션에서 백에지 카운터 수치를 조정 할 순 있지만
+
+VM튜닝을 하는 것이 아닌이상 보편적으로 손댈일은 잘 없지않을까 싶습니다.
+
+이 덕분에 자바의 JVM은 한번 작성한 코드를 어디서든 실행 할 수 있는 WORA를 준수하게 됩니다.
+
+
+
+
+## [5. JVM의 종류]
+
+![image](https://github.com/Kernel360/blog-image/blob/main/2024/0202/4.png?raw=true)
+
+이제 JIT 컴파일러의 최적화 과정을 말씀드릴까 하는데
+
+이 JVM이라는 것도 목적에 따라 종류가 매우 다양합니다.
+
+첫번째 이 Jrockit은 밑의 핫스팟이 쓰이기전에 나온 초기버전입니다.
+
+두번째 핫스팟 JVM은 요즘 자바에서 쓰이는 표준 JVM이라 이해하시면 되겠습니다.
+
+세번째는 IBM에서 개발한 것으로 경량화되어 임베디드나 클라우드 환경에서 쓰이고 이클립스 재단에서 관리하고 있습니다.
+
+그랄VM은 자바뿐만 아니라 자바스크립트, 파이썬, 루비처럼 다른 언어도 지원하는 것이 특징입니다.
+
+중국어처럼 보이는 아줄 징 JVM은 놀랍게도 미국회사이고, GC 성능이 강조된 고성능 JVM인 것이 특징입니다.
+
+네이버 클라우드 플랫폼도 이 아줄 JVm을 사용 및 서비스합니다.
+
+종류가 이만큼 많다는건? 내부 구조도 다 다르다는 이야기입니다.
+
+우리는 그중 첫번째 J락킷의 컴파일러로 알아보려고 합니다.
+
+## [6. Jrockit의 최적화 - 구조]
+
+![image](https://github.com/Kernel360/blog-image/blob/main/2024/0202/5.png?raw=true)
+
+첫 부팅때는 모든 메서드에 대해 최초 컴파일을 거친다면 오버헤드로 인해 느릴 수 있지만
+
+앞서 설명한 JIT 옵티마이저, 컴파일러로 인해 시작은 느려도 판단에 따라 최적화가 이뤄지므로
+
+지속적으로 수행 할 수록 더 빠른 처리가 이루어집니다.
+
+두번째 스레드 모니터는 샘플러스레드가 어떤 스레드들이 동작중인지, 수행내역을 관리합니다.
+
+이를 통해 어떤 메서드가 많이 쓰이는가 최적화 대상을 탐색합니다.
+
+마지막으로 샘플러 스레드가 식별한 대상을 최적화하며
+
+수행중인 어플리케이션에 영향을 주지 않습니다.
+
+## [6. Jrockit의 최적화 - 코드]
+
+![image](https://github.com/Kernel360/blog-image/blob/main/2024/0202/6.png?raw=true)
+
+첫번째와 같이 Class A에서 Class B를 사용하고 void foo()를 통해 y, z에 b.get()을 대입하여 sum을 하는 코드가 있다고 가정해봅시다.
+
+1. final method의 inline 처리를 합니다. b.get()을 b.value로 바꾸어 메서드콜로 인한 성능저하를 개선합니다.
+2. z,y 값이 동일하므로 z에 y를 할당하여 불필요한 호출 부하를 제거합니다.
+3. z와 y가 동일하므로 불필요 변수 z를 y로 변경합니다.
+4. 3의 과정으로 y=y가 되었으므로 데드코드를 삭제합니다.
+
+이러한 최적화 과정을 통해 우리가 코드를 작성하면서 가독성을 살리기위해
+
+같은 변수를 여러번 사용, 대입하여도 성능에 지장을 최소화 하도록 하게됩니다.
+
+마치 우리가 코드 리팩토링을 하는 과정과 비슷하죠?
+
+이렇게해서 JVM의 OWRA의 의미가 무엇인지, 바이트코드는 어떤 과정으로 컴파일 되는지
+
+컴파일에 쓰이는 많은 JVM중 가장 기초적인 Jrockit의 최적화 과정을 살펴보았습니다. 감사합니다.
+
+
From ed857b6b9da04852466a4873d0277a75033f6946 Mon Sep 17 00:00:00 2001
From: aqrms
Date: Mon, 19 Feb 2024 20:41:06 +0900
Subject: [PATCH 29/50] 240131-generics (#41)
---
.idea/misc.xml | 1 -
_posts/2024-01-31-generics.md | 284 ++++++++++++++++++++++++++++++++++
2 files changed, 284 insertions(+), 1 deletion(-)
create mode 100644 _posts/2024-01-31-generics.md
diff --git a/.idea/misc.xml b/.idea/misc.xml
index d79bd4e..f45063f 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-
diff --git a/_posts/2024-01-31-generics.md b/_posts/2024-01-31-generics.md
new file mode 100644
index 0000000..6a07480
--- /dev/null
+++ b/_posts/2024-01-31-generics.md
@@ -0,0 +1,284 @@
+---
+layout: post
+title: 자바 제네릭(Generic) - 제네릭 메서드와 타입 범위 한정
+author: 우무룡
+categories: 기술세미나
+banner:
+ image: https://github.com/Kernel360/blog-image/blob/main/2024/0131/GENERICS_THUMBNAIL.png?raw=true
+ background: "#000"
+ height: "100vh"
+ min_height: "38vh"
+ heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline"
+ tags: [제네릭, 기술세미나]
+---
+
+안녕하세요 커널360 1기 크루 우무룡입니다.
+
+기술세미나 발표주제로 익숙하면서도 헷갈릴 수 있는 제네릭을 선정했습니다.
+기본적인 개념에 대해 간단히 알아보고 개인적으로 헷갈렸던 제네릭 메서드와 타입 범위 한정에 대해 주로 알아보겠습니다!
+
+
+# 제네릭이란
+자바에서 제네릭은 타입 안정성을 위해 jdk 1.5부터 도입된 문법이다.
+클래스 내부에서 사용할 데이터 타입을 클래스 내부에서 선언하는 것이 아닌 외부에서 사용자에 의해 지정하는 기법이다.
+
+```java
+ArrayList list = new ArrayList<>();
+```
+저 꺾쇠 괄호가 바로 제네릭이다. 괄호 안에는 타입명을 기재한다. 그러면 저 리스트 클래스 자료형의 타입은 String 타입으로 지정되어 문자열 데이터만 리스트에 적재할 수 있게 된다.
+
+이처럼 제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입(type)을 파라미터(parameter) 주듯이 외부에서 지정하는 이른바 타입을 변수화 한 기능이라고 이해하면 된다.
+
+# 제네릭 클래스
+클래스 선언문 옆에 제네릭 타입 파라미터가 쓰이면, 이를 제네릭 클래스라고 한다.
+
+```java
+class Sample {
+ private T value; // 멤버 변수 val의 타입은 T 이다.
+
+ // T 타입의 값 val을 반환한다.
+ public T getValue() {
+ return value;
+ }
+
+ // T 타입의 값을 멤버 변수 val에 대입한다.
+ public void setValue(T value) {
+ this.value = value;
+ }
+}
+
+public class Main {
+ public static void main(String[] args) {
+ Sample sample = new Sample();
+ //Sample sample = new Sample<>(); 생성자 부분 타입 생략가능
+}
+
+```
+제네릭 클래스의 타입 파라미터는 해당 클래스를 **인스턴스화 하는 시점**에 입력한 값을 받아와서 해당 파라미터가 지정된 곳으로 전파된다. jdk 1.7 이후부터는 생성자 부분의 제네릭 타입은 생략 가능하다.
+
+# 제네릭의 장점
+## 재사용성
+```java
+ArrayList list1 = new ArrayList();
+ArrayList list2 = new ArrayList();
+
+LinkedList list3 = new LinkedList():
+LinkedList list4 = new LinkedList();
+```
+흔히쓰는 ArrayList와 LinkedList를 예로 들었다. 위와 같이 ArrayList와 LinkedList에 다양한 타입을 사용할 때에도 IntegerArrayList나 StringArrayList 같은 클래스를 사용할 필요없이 ArrayList에 제네릭에 <원하는 타입>을 지정해 줌으로써 같은 클래스를 재사용할 수 있었다.
+
+제네릭을 사용하면 우리가 나중에 어떤 클래스를 작성할 때에도 지원하고자 하는 타입에 따라 모든 별도의 클래스를 만들필요 없이 사용할때 지정해주도록 해서 재사용성을 높일 수 있다.
+
+## 컴파일 타임 타입검사
+
+제네릭이 없던 jdk 1.5 이전에는 하나의 클래스가 여러 타입을 다루기 위해서 모든 클래스의 조상인 Object 클래스를 인자와 반환값으로 사용했다. 반환된 Object를 원하는 타입으로 사용하기 위해서는 일일이 타입 변환을 해야했고, 그로 인해 런타임 에러가 발생할 가능성이 존재했다.
+```java
+List list = new ArrayList();
+list.add(new Apple());
+list.add(new Banana());
+
+Apple apple = (Apple)list.get(0);
+Apple apple1 = (Apple)list.get(1); // 런타임 에러! (ClassCastException)
+```
+위 예시에는 ArrayList를 제네릭 없이 선언했고 그러면 인자와 반환값을 모두 Object로 사용한다. list에는 Apple만 들어있어야 했으나 개발자가 착각해서 Banana를 추가했다. 다시 객체를 가져올 때 Apple로 형변환 해 가져오려고 했기 때문에 런타임 에러인 ClassCastException이 발생한다.
+
+
+```java
+List list = new ArrayList();
+list.add(new Apple());
+list.add(new Banana()); // 컴파일 에러
+
+Apple apple = list.get(0); // 불필요한 캐스팅 제거
+```
+제네릭을 사용하면 이런 실수를 사전에 방지할 수 있다. 코드를 실행하기 전 컴파일 타임에 에러를 찾아 알려주기 때문이다. 게다가 타입이 이미 정해져 있기 때문에 불필요하게 형변환을 해줄 필요가 없다.
+
+
+# 제네릭 메소드
+제네릭 메서드란 클래스에 선언한 제네릭과 관계없이(혹은 클래스에서 선언하지 않더라도) 독립적인 제네릭을 메서드의 타입파라미터로 지정하는 메서드를 의미한다.
+보통 아래 예시의 get, set 메서드처럼 클래스의 제네릭을 매개변수로 받거나 반환값으로 사용하는 메서드를 제네릭 메서드로 오해하기 쉽다.
+
+genericMethod처럼 메서드의 선언부에 별도의 타입파라미터를 선언한 메서드가 제네릭 메서드임을 주의하자.
+```java
+class ClassName {
+
+ private E element;
+
+ void set(E element) {
+ this.element = element;
+ }
+
+ E get() {
+ return element;
+ }
+
+ // 제네릭 메소드
+ T genericMethod(T o) {
+ return o;
+ }
+
+}
+
+public class Main {
+ public static void main(String[] args) {
+
+ ClassName a = new ClassName<>();
+ a.set("10");
+
+ System.out.println("a data : " + a.get());
+ System.out.println("a E Type : " + a.get().getClass().getName());
+
+ // 제네릭 메소드 Integer
+ System.out.println(" returnType : " + a.genericMethod(3).getClass().getName());
+ // 제네릭 메소드 String
+ System.out.println(" returnType : " + a.genericMethod("ABCD").getClass().getName());
+ }
+}
+```
+위 예시의 메인메서드와 아래의 실행결과를 보면 클래스의 제네릭과 독립적이라는 것이 어떤 의미인지 알 수 있다.
+위 코드를 실행시키면 아래와 같이 출력된다.
+
+![](https://github.com/Kernel360/blog-image/blob/main/2024/0131/GENERICS_CLASSTYPE_CONSOLE.png?raw=true)
+
+'a' 인스턴스를 생성하면서 String으로 타입파라미터를 전달했다. E로 선언된 제네릭은 **인스턴스 생성시점**에 String으로 결정되어 E타입을 String으로 반환한다.
+
+그러나 genericMethod에 인자를 3이라는 정수로 전달하였더니 'a' 클래스를 생성할때 전달했던 타입과 관계없이 Integer를 반환한다. 제네릭 메서드의 타입은 제네릭 클래스와 달리 **메서드를 호출하는 시점에 결정**된다.
+따라서, 클래스에 선언된 제네릭과 독립적으로 타입을 지정할 수 있다.
+
+그럼 제네릭 클래스의 타입을 가져다 사용하면 되는데 제네릭 클래스와 독립적인 타입을 선언해야 하는 이유는 뭘까? 바로 정적 메서드를 선언할 때는 꼭 필요하기 때문이다.
+
+
+이전에 제네릭 클래스의 타입은 인스턴스화 할때 결정된다고 했다. 하지만 static 메서드는 인스턴스를 생성하기도 전에 프로그램 실행시 모두 스태틱 메모리 영역에 올라가게 된다. 그래서 인스턴스를 생성하지 않고 바로 사용할 수 있는데, 인스턴스가 생성되기 이전 시점에 제네릭 클래스로 부터 타입을 받아올 수 없다. 따라서, 제네릭이 사용되는 메소드를 정적메소드로 두고 싶은 경우 제네릭 클래스와 별도로 독립적인 제네릭이 사용되어야 한다.
+
+> 하지만 제네릭 메서드가 꼭 정적 메서드로만 선언되어야 하는 건 아니다. 인스턴스 메서드로 선언한다면 메서드 호출을 위해 클래스의 인스턴스를 생성해서 접근해야겠지만,
+> 여전히 클래스에 선언된 제네릭(또는 선언되지 않았더라도)과 관계없이 독립적인 타입파라미터를 선언해 활용할 수 있다.
+# 제네릭 타입 범위 한정
+
+제네릭을 사용하면 타입을 원하는 대로 자유롭게 지정할 수 있다는 것이 장점이지만 또, 너무 자유롭다는 것이 단점이 될 수도 있다.
+
+예를 들어, 개발자가 아래와 같은 계산기 클래스를 만들었다고 하자. 다양한 숫자타입의 계산을 지원하기 위해 제네릭 클래스로 선언했다. 하지만, 단순히 로 지정하게 되면 숫자에 관련된 래퍼 클래스 뿐만 아니라 String이나 다른 클래스들도 대입이 가능하다는 점이 문제다.
+
+```java
+// 숫자만 받아 계산하는 계산기 클래스 모듈
+class Calculator {
+ void add(T a, T b) {}
+ void min(T a, T b) {}
+ void mul(T a, T b) {}
+ void div(T a, T b) {}
+}
+
+public class Main {
+ public static void main(String[] args) {
+ // 제네릭에 아무 타입이나 모두 할당이 가능
+ Calculator cal1 = new Calculator<>();
+ Calculator