main 26c959a31f27 cached
28 files
200.1 KB
84.9k tokens
1 requests
Download .txt
Showing preview only (210K chars total). Download the full file or copy to clipboard to get everything.
Repository: jbee37142/Interview_Question_for_Beginner
Branch: main
Commit: 26c959a31f27
Files: 28
Total size: 200.1 KB

Directory structure:
gitextract_jfqhlcxv/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── Bug_report.md
│   │   ├── Comments.md
│   │   ├── Enhancement.md
│   │   ├── New_resources.md
│   │   ├── Questions.md
│   │   └── Suggestions.md
│   ├── ISSUE_TEMPLATE.md
│   └── PULL_REQUEST_TEMPLATE.md
├── .prettierrc
├── Algorithm/
│   └── README.md
├── CONTRIBUTING.md
├── DataStructure/
│   └── README.md
├── Database/
│   └── README.md
├── DesignPattern/
│   └── README.md
├── Development_common_sense/
│   └── README.md
├── FrontEnd/
│   └── README.md
├── Java/
│   └── README.md
├── JavaScript/
│   └── README.md
├── LICENSE
├── MachineLearning/
│   └── README.md
├── Network/
│   └── README.md
├── OS/
│   ├── README.en.md
│   └── README.md
├── Python/
│   └── README.md
├── README.md
├── Reverse_Interview/
│   └── README.md
├── Tip/
│   └── README.md
└── iOS/
    └── README.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/Bug_report.md
================================================
---
name: 🐛 Bug report
about: 오타 또는 잘못된 링크를 수정 🛠️
---

## Description


================================================
FILE: .github/ISSUE_TEMPLATE/Comments.md
================================================
---
name: 💬 Comments
about: 기타 다른 comment, 아무말 대잔치 😃
---

## Description


================================================
FILE: .github/ISSUE_TEMPLATE/Enhancement.md
================================================
---
name: 🌈 Enhancement
about: 해당 저장소의 개선 사항 등록 🎉
---

## Description


================================================
FILE: .github/ISSUE_TEMPLATE/New_resources.md
================================================
---
name: 🎁 New Resources
about: 새로운 자료 추가 🚀
---

## Description


================================================
FILE: .github/ISSUE_TEMPLATE/Questions.md
================================================
---
name: ❓ Questions
about: 해당 저장소에서 다루고 있는 내용에 대한 질문 또는 메인테이너에게 질문 ❔
---

## Description


================================================
FILE: .github/ISSUE_TEMPLATE/Suggestions.md
================================================
---
name: 📝 Suggestions
about: 해당 저장소에 건의하고 싶은 사항 👍
---

## Description


================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================



================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
### This Pull Request is...
* [ ] Edit typos or links
* [ ] Inaccurate information
* [ ] New Resources

#### Description
(say something...)


================================================
FILE: .prettierrc
================================================


================================================
FILE: Algorithm/README.md
================================================
# Algorithm

* [코딩 테스트를 위한 Tip](#코딩-테스트를-위한-tip)
* [문제 해결을 위한 전략적 접근](#문제-해결을-위한-전략적-접근)
* [Sorting Algorithm](#sorting-algorithm)
* [Prime Number Algorithm](#prime-number-algorithm)

[뒤로](https://github.com/JaeYeopHan/for_beginner)

## 코딩 테스트를 위한 Tip

> Translate this article: [How to Rock an Algorithms Interview](https://web.archive.org/web/20110929132042/http://blog.palantir.com/2011/09/26/how-to-rock-an-algorithms-interview/)

### 1. 칠판에 글쓰기를 시작하십시오.

이것은 당연하게 들릴지 모르지만, 빈 벽을 쳐다 보면서 수십 명의 후보자가 붙어 있습니다. 나는 아무것도 보지 않는 것보다 문제의 예를 응시하는 것이 더 생산적이라고 생각합니다. 관련성이있는 그림을 생각할 수 있다면 그 그림을 그립니다. 중간 크기의 예제가 있으면 작업 할 수 있습니다. (중간 크기는 작은 것보다 낫습니다.) 때로는 작은 예제에 대한 솔루션이 일반화되지 않기 때문입니다. 또는 알고있는 몇 가지 명제를 적어 두십시오. 뭐라도 하는 것이 아무것도 안 하는 것보다 낫습니다.

### 2. 그것을 통해 이야기하십시오.

자신이 한 말이 어리석은 소리일까 걱정하지 마십시오. 많은 사람들이 문제를 조용히 생각하는 것을 선호하지만, 문제를 풀다가 막혔다면 말하는 것이 한 가지 방법이 될 수 있습니다. 가끔은 면접관에게 진행 상황에 대해서 명확하게 말하는 것이 지금 문제에서 무슨 일이 일어나고 있는지 이해할 수 있는 계기가 될 수 있습니다. 당신의 면접관은 당신이 그 생각을 추구하도록 당신을 방해 할 수도 있습니다. 무엇을 하든지 힌트를 위해 면접관을 속이려 하지 마십시오. 힌트가 필요하면 정직하게 질문하십시오.

### 3. 알고리즘을 생각하세요.

때로는 문제의 세부 사항을 검토하고 해결책이 당신에게 나올 것을 기대하는 것이 유용합니다 (이것이 상향식 접근법 일 것입니다). 그러나 다른 알고리즘에 대해서도 생각해 볼 수 있으며 각각의 알고리즘이 당신 앞의 문제에 적용되는지를 질문 할 수 있습니다 (하향식 접근법). 이러한 방식으로 참조 프레임을 변경하면 종종 즉각적인 통찰력을 얻을 수 있습니다. 다음은 면접에서 요구하는 문제의 절반 이상을 해결하는 데 도움이되는 알고리즘 기법입니다.

* Sorting (plus searching / binary search)
* Divide and Conquer
* Dynamic Programming / Memoization
* Greediness
* Recursion
* Algorithms associated with a specific data structure (which brings us to our fourth suggestion...)

### 4. 데이터 구조를 생각하십시오.

상위 10 개 데이터 구조가 실제 세계에서 사용되는 모든 데이터 구조의 99 %를 차지한다는 것을 알고 계셨습니까? 때로는 최적의 솔루션이 블룸 필터 또는 접미어 트리를 필요로하는 문제를 묻습니다. 하지만 이러한 문제조차도 훨씬 더 일상적인 데이터 구조를 사용하는 최적의 솔루션을 사용하는 경향이 있습니다. 가장 자주 표시 될 데이터 구조는 다음과 같습니다.

* Array
* Stack / Queue
* HashSet / HashMap / HashTable / Dictionary
* Tree / Binary tree
* Heap
* Graph

### 5. 이전에 보았던 관련 문제와 해결 방법에 대해 생각해보십시오.

여러분에게 제시한 문제는 이전에 보았던 문제이거나 적어도 조금은 유사합니다. 이러한 솔루션에 대해 생각해보고 문제의 세부 사항에 어떻게 적응할 수 있는지 생각하십시오. 문제가 제기되는 형태로 넘어지지는 마십시오. 핵심 과제로 넘어 가서 과거에 해결 한 것과 일치하는지 확인하십시오.

### 6. 문제를 작은 문제로 분해하여 수정하십시오.

특별한 경우 또는 문제의 단순화 된 버전을 해결하십시오. 코너 케이스를 보는 것은 문제의 복잡성과 범위를 제한하는 좋은 방법입니다. 문제를 큰 문제의 하위 집합으로 축소하면 작은 부분부터 시작하여 전체 범위까지 작업을 진행할 수 있습니다. 작은 문제의 구성으로 문제를 보는 것도 도움이 될 수 있습니다.

### 7. 되돌아 오는 것을 두려워하지 마십시오.

특정 접근법이 효과적이지 않다고 느끼면 다른 접근 방식을 시도 할 때가 있습니다. 물론 너무 쉽게 포기해서는 안됩니다. 그러나 열매를 맺지 않고도 유망한 생각이 들지 않는 접근법에 몇 분을 소비했다면, 백업하고 다른 것을 시도해보십시오. 저는 덜 접근한 지원자보다 한참 더 많이 나아간 지원자를 많이 보았습니다. 즉, (모두 평등 한) 다른 사람들이 좀 더 기민한 접근 방식을 포기해야 한다는 것을 의미합니다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#algorithm)

</br>

## 문제 해결을 위한 전략적 접근

### 코딩 테스트의 목적

1.  문제 해결 여부
2.  예외 상황과 경계값 처리
3.  코드 가독성과 중복 제거 여부 등 코드 품질
4.  언어 이해도
5.  효율성

궁극적으로는 문제 해결 능력을 측정하기 위함이며 이는 '어떻게 이 문제를 창의적으로 해결할 것인가'를 측정하기 위함이라고 볼 수 있다.

### 접근하기

1.  문제를 공격적으로 받아들이고 필요한 정보를 추가적으로 요구하여, 해당 문제에 대해 완벽하게 이해하는게 우선이다.
2.  해당 문제를 익숙한 용어로 재정의하거나 문제를 해결하기 위한 정보를 추출한다. 이 과정을 추상화라고 한다.
3.  추상화된 데이터를 기반으로 이 문제를 어떻게 해결할 지 계획을 세운다. 이 때 사용할 알고리즘과 자료구조를 고민한다.
4.  세운 계획에 대해 검증을 해본다. 수도 코드 작성도 해당될 수 있고 문제 출제자에게 의견을 물어볼 수도 있다.
5.  세운 계획으로 문제를 해결해본다. 해결이 안 된다면 앞선 과정을 되짚어본다.

### 생각할 때

* 비슷한 문제를 생각해본다.
* 단순한 방법으로 시작하여 점진적으로 개선해나간다.
* 작은 값을 생각해본다.
* 그림으로 그려본다.
* 수식으로 표현해본다.
* 순서를 강제해본다.
* 뒤에서부터 생각해본다.

</br>

### 해결 방법 분류

#### DP(동적 계획법)

복잡한 문제를 간단한 여러 개의 하위 문제(sub-problem)로 나누어 푸는 방법을 말한다.

DP 에는 두 가지 구현 방식이 존재한다.

* top-down : 여러 개의 하위 문제(sub-problem) 나눴을시에 하위 문제를 결합하여 최종적으로 최적해를 구한다.
  * 같은 하위 문제를 가지고 있는 경우가 존재한다.
    그 최적해를 저장해서 사용하는 경우 하위 문제수가 기하급수적으로 증가할 때 유용하다.
    위 방법을 memoization 이라고 한다.
* bottom-up : top-down 방식과는 하위 문제들로 상위 문제의 최적해를 구한다.

Fibonacci 수열을 예로 들어보면,

```
top-down
f (int n) {
  if n == 0 : return 0
  elif n == 1: return 1
  if dp[n] has value : return dp[n]
  else : dp[n] = f(n-2) + f(n-1)
         return dp[n]
}
```

```
bottom-up
f (int n){
  f[0] = 0
  f[1] = 1
  for (i = 2; i <= n; i++) {
   f[i] = f[i-2] + f[i-1]
  }
  return f[n]
}
```

#### 접근방법

1.  모든 답을 만들어보고 그 중 최적해의 점수를 반환하는 완전 탐색 알고리즘을 설계한다.
2.  전체 답의 점수를 반환하는 것이 아니라, 앞으로 남은 선택들에 해당하는 저수만을 반환하도록 부분 문제 정의를 변경한다.
3.  재귀 호출의 입력 이전의 선택에 관련된 정보가 있다면 꼭 필요한 것만 남기고 줄인다.
4.  입력이 배열이거나 문자열인 경우 가능하다면 적절한 변환을 통해 메모이제이션할 수 있도록 조정한다.
5.  메모이제이션을 적용한다.

#### Greedy (탐욕법)

모든 선택지를 고려해보고 그 중 가장 좋은 것을 찾는 방법이 Divide conquer or dp 였다면
greedy 는 각 단계마다 지금 당장 가장 좋은 방법만을 선택하는 해결 방법이다.
탐욕법은 동적 계획법보다 수행 시간이 훨씬 빠르기 때문에 유용하다.
많은 경우 최적해를 찾지 못하고 적용될 수 있는 경우가 두 가지로 제한된다.

1.  탐욕법을 사용해도 항상 최적해를 구할 수 있는 경우
2.  시간이나 공간적 제약으로 최적해 대신 근사해를 찾아서 해결하는 경우

#### 접근 방법

1.  문제의 답을 만드는 과정을 여러 조각으로 나눈다.
2.  각 조각마다 어떤 우선순위로 선택을 내려야 할지 결정한다. 작은 입력을 손으로 풀어본다.
3.  다음 두 속성이 적용되는지 확인해본다.

1)  탐욕적 성택 속성 : 항상 각 단계에서 우리가 선택한 답을 포함하는 최적해가 존재하는가
2)  최적 부분 구조 : 각 단계에서 항상 최적의 선택만을 했을 때, 전체 최적해를 구할 수 있는가

#### Divide and Conquer (분할 정복)

분할 정복은 큰 문제를 작은 문제로 쪼개어 답을 찾아가는 방식이다.
하부구조(non-overlapping subproblem)가 반복되지 않는 문제를 해결할 때 사용할 수 있다.
최적화 문제(가능한 해답의 범위 중 최소, 최대를 구하는 문제), 최적화가 아닌 문제 모두에 적용할 수 있다.
top-down 접근 방식을 사용한다.
재귀적 호출 구조를 사용한다. 이때 call stack을 사용한다. (call stack에서의 stack overflow에 유의해야 한다.)

#### 접근 방법

1.  Divide, 즉 큰 문제를 여러 작은 문제로 쪼갠다. Conquer 가능할 때까지 쪼갠다.
2.  Conquer, 작은 문제들을 정복한다.
3.  Merge, 정복한 작은 문제들의 해답을 합친다. 이 단계가 필요하지 않은 경우도 있다(이분 탐색).

### DP vs DIVIDE&CONQUER vs GREEDY

 |Divide and Conquer|Dynamic Programming|Greedy|
 |:---:|:---:|:---:|
 |non-overlapping한 문제를 작은 문제로 쪼개어 해결하는데 non-overlapping|overlapping substructure를 갖는 문제를 해결한다.|각 단계에서의 최적의 선택을 통해 해결한다.|
 |top-down 접근|top-down, bottom-up 접근||
 |재귀 함수를 사용한다.|재귀적 관계(점화식)를 이용한다.(점화식)|반복문을 사용한다.|
 |call stack을 통해 답을 구한다.|look-up-table, 즉 행렬에 반복적인 구조의 solution을 저장해 놓는 방식으로 답을 구한다.|solution set에 단계별 답을 추가하는 방식으로 답을 구한다.|
 |분할 - 정복 - 병합|점화식 도출 - look-up-table에 결과 저장 - 나중에 다시 꺼내씀|단계별 최적의 답을 선택 - 조건에 부합하는지 확인 - 마지막에 전체조건에 부합하는지 확인|
 |이분탐색, 퀵소트, 머지소트|최적화 이분탐색, 이항계수 구하디, 플로이드-와샬|크루스칼, 프림, 다익스트라, 벨만-포드|

#### Reference

[프로그래밍 대회에서 배우는 알고리즘 문제 해결 전략](http://www.yes24.com/24/Goods/8006522?Acode=101)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#algorithm)

</br>

## Sorting Algorithm

Sorting 알고리즘은 크게 Comparisons 방식과 Non-Comparisons 방식으로 나눌 수 있다.

### Comparisons Sorting Algorithm (비교 방식 알고리즘)

`Bubble Sort`, `Selection Sort`, `Insertion Sort`, `Merge Sort`, `Heap Sort`, `Quick Sort` 를 소개한다.

### Bubble Sort

n 개의 원소를 가진 배열을 정렬할 때, In-place sort 로 인접한 두 개의 데이터를 비교해가면서 정렬을 진행하는 방식이다. 가장 큰 값을 배열의 맨 끝에다 이동시키면서 정렬하고자 하는 원소의 개수 만큼을 두 번 반복하게 된다.

| Space Complexity | Time Complexity |
| :--------------: | :-------------: |
|       O(1)       |     O(n^2)      |

#### [code](https://github.com/JaeYeopHan/algorithm_basic_java/blob/master/src/test/java/sort/BubbleSort.java)

</br>

### Selection Sort

n 개의 원소를 가진 배열을 정렬할 때, 계속해서 바꾸는 것이 아니라 비교하고 있는 값의 index 를 저장해둔다. 그리고 최종적으로 한 번만 바꿔준다. 하지만 여러 번 비교를 하는 것은 마찬가지이다.

| Space Complexity | Time Complexity |
| :--------------: | :-------------: |
|       O(1)       |     O(n^2)      |

#### [code](https://github.com/JaeYeopHan/algorithm_basic_java/blob/master/src/test/java/sort/SelectionSort.java)

</br>

### Insertion Sort

n 개의 원소를 가진 배열을 정렬할 때, i 번째를 정렬할 순서라고 가정하면, 0 부터 i-1 까지의 원소들은 정렬되어있다는 가정하에, i 번째 원소와 i-1 번째 원소부터 0 번째 원소까지 비교하면서 i 번째 원소가 비교하는 원소보다 클 경우 서로의 위치를 바꾸고, 작을 경우 위치를 바꾸지 않고 다음 순서의 원소와 비교하면서 정렬해준다. 이 과정을 정렬하려는 배열의 마지막 원소까지 반복해준다.

| Space Complexity | Time Complexity |
| :--------------: | :-------------: |
|       O(1)       |     O(n^2)      |

#### [code](https://github.com/JaeYeopHan/algorithm_basic_java/blob/master/src/test/java/sort/InsertionSort.java)

</br>

### Merge Sort

기본적인 개념으로는 n 개의 원소를 가진 배열을 정렬할 때, 정렬하고자 하는 배열의 크기를 작은 단위로 나누어 정렬하고자 하는 배열의 크기를 줄이는 원리를 사용한다. `Divide and conquer`라는, "분할하여 정복한다"의 원리인 것이다. 말 그대로 복잡한 문제를 복잡하지 않은 문제로 분할하여 정복하는 방법이다. 단 분할(divide)해서 정복했으니 정복(conquer)한 후에는 **결합(combine)** 의 과정을 거쳐야 한다.

`Merge Sort`는 더이상 나누어지지 않을 때 까지 **반 씩(1/2)** 분할하다가 더 이상 나누어지지 않은 경우(원소가 하나인 배열일 때)에는 자기 자신, 즉 원소 하나를 반환한다. 원소가 하나인 경우에는 정렬할 필요가 없기 때문이다. 이 때 반환한 값끼리 **`combine`될 때, 비교가 이뤄지며,** 비교 결과를 기반으로 정렬되어 **임시 배열에 저장된다.** 그리고 이 임시 배열에 저장된 순서를 합쳐진 값으로 반환한다. 실제 정렬은 나눈 것을 병합하는 과정에서 이뤄지는 것이다.

결국 하나씩 남을 때까지 분할하는 것이면, 바로 하나씩 분할해버리면 되지 않을까? 재귀적으로 정렬하는 원리인 것이다. 재귀적 구현을 위해 1/2 씩 분할한다.

| Space Complexity | Time Complexity |
| :--------------: | :-------------: |
|       O(n)       |    O(nlogn)     |

</br>

### Heap Sort

`binary heap` 자료구조를 활용할 Sorting 방법에는 두 가지 방법이 존재한다. 하나는 정렬의 대상인 데이터들을 힙에 넣었다가 꺼내는 원리로 Sorting 을 하게 되는 방법이고, 나머지 하나는 기존의 배열을 `heapify`(heap 으로 만들어주는 과정)을 거쳐 꺼내는 원리로 정렬하는 방법이다. `heap`에 데이터를 저장하는 시간 복잡도는 `O(log n)`이고, 삭제 시간 복잡도 또한 `O(log n)`이 된다. 때문에 힙 자료구조를 사용하여 Sorting 을 하는데 time complexity 는 `O(log n)`이 된다. 이 정렬을 하려는 대상이 n 개라면 time complexity 는 `O(nlogn)`이 된다.

`Heap`자료구조에 대한 설명은 [DataStructure - Binary Heap](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/DataStructure#binary-heap)부분을 참고하면 된다.

| Space Complexity | Time Complexity |
| :--------------: | :-------------: |
|       O(1)       |    O(nlogn)     |

</br>

### Quick Sort

Sorting 기법 중 가장 빠르다고 해서 quick 이라는 이름이 붙여졌다. **하지만 Worst Case 에서는 시간복잡도가 O(n^2)가 나올 수도 있다.** 하지만 `constant factor`가 작아서 속도가 빠르다.

`Quick Sort` 역시 `Divide and Conquer` 전략을 사용하여 Sorting 이 이루어진다. Divide 과정에서 `pivot`이라는 개념이 사용된다. 입력된 배열에 대해 오름차순으로 정렬한다고 하면 이 pivot 을 기준으로 좌측은 pivot 으로 설정된 값보다 작은 값이 위치하고, 우측은 큰 값이 위치하도록 `partition`된다. 이렇게 나뉜 좌, 우측 각각의 배열을 다시 재귀적으로 Quick Sort 를 시키면 또 partition 과정이 적용된다.이 때 한 가지 주의할 점은 partition 과정에서 pivot 으로 설정된 값은 다음 재귀과정에 포함시키지 않아야 한다. 이미 partition 과정에서 정렬된 자신의 위치를 찾았기 때문이다.

#### Quick Sort's worst case

그렇다면 어떤 경우가 Worst Case 일까? Quick Sort 로 오름차순 정렬을 한다고 하자. 그렇다면 Worst Case 는 partition 과정에서 pivot value 가 항상 배열 내에서 가장 작은 값 또는 가장 큰 값으로 설정되었을 때이다. 매 partition 마다 `unbalanced partition`이 이뤄지고 이렇게 partition 이 되면 비교 횟수는 원소 n 개에 대해서 n 번, (n-1)번, (n-2)번 … 이 되므로 시간 복잡도는 **O(n^2)** 이 된다.

#### Balanced-partitioning

자연스럽게 Best-Case 는 두 개의 sub-problems 의 크기가 동일한 경우가 된다. 즉 partition 과정에서 반반씩 나뉘게 되는 경우인 것이다. 그렇다면 Partition 과정에서 pivot 을 어떻게 정할 것인가가 중요해진다. 어떻게 정하면 정확히 반반의 partition 이 아니더라도 balanced-partitioning 즉, 균형 잡힌 분할을 할 수 있을까? 배열의 맨 뒤 또는 맨 앞에 있는 원소로 설정하는가? Random 으로 설정하는 것은 어떨까? 특정 위치의 원소를 pivot 으로 설정하지 않고 배열 내의 원소 중 임의의 원소를 pivot 으로 설정하면 입력에 관계없이 일정한 수준의 성능을 얻을 수 있다. 또 악의적인 입력에 대해 성능 저하를 막을 수 있다.

#### Partitioning

정작 중요한 Partition 은 어떻게 이루어지는가에 대한 이야기를 하지 않았다. 가장 마지막 원소를 pivot 으로 설정했다고 가정하자. 이 pivot 의 값을 기준으로 좌측에는 작은 값 우측에는 큰 값이 오도록 해야 하는데, 일단 pivot 은 움직이지 말자. 첫번째 원소부터 비교하는데 만약 그 값이 pivot 보다 작다면 그대로 두고 크다면 맨 마지막에서 그 앞의 원소와 자리를 바꿔준다. 즉 pivot value 의 index 가 k 라면 k-1 번째와 바꿔주는 것이다. 이 모든 원소에 대해 실행하고 마지막 과정에서 작은 값들이 채워지는 인덱스를 가리키고 있는 값에 1 을 더한 index 값과 pivot 값을 바꿔준다. 즉, 최종적으로 결정될 pivot 의 인덱스를 i 라고 했을 때, 0 부터 i-1 까지는 pivot 보다 작은 값이 될 것이고 i+1 부터 k 까지는 pivot 값보다 큰 값이 될 것이다.

| Space Complexity | Time Complexity |
| :--------------: | :-------------: |
|       O(log(n))       |    O(nlogn)     |

#### [code](https://github.com/JaeYeopHan/algorithm_basic_java/blob/master/src/test/java/sort/QuickSort.java)

</br>

### non-Comparisons Sorting Algorithm

`Counting Sort`, `Radix Sort` 를 소개한다.

### Counting Sort

Count Sort 는 말 그대로 몇 개인지 개수를 세어 정렬하는 방식이다. 정렬하고자 하는 값 중 **최대값에 해당하는 값을 size 로 하는 임시 배열** 을 만든다. 만들어진 배열의 index 중 일부는 정렬하고자 하는 값들이 되므로 그 값에는 그 값들의 **개수** 를 나타낸다. 정렬하고자 하는 값들이 몇 개씩인지 파악하는 임시 배열이 만들어졌다면 이 임시 배열을 기준으로 정렬을 한다. 그 전에 임시 배열에서 한 가지 작업을 추가적으로 수행해주어야 하는데 큰 값부터 즉 큰 index 부터 시작하여 누적된 값으로 변경해주는 것이다. 이 누적된 값은 정렬하고자 하는 값들이 정렬될 index 값을 나타내게 된다. 작업을 마친 임시 배열의 index 는 정렬하고자 하는 값을 나타내고 value 는 정렬하고자 하는 값들이 정렬되었을 때의 index 를 나타내게 된다. 이를 기준으로 정렬을 해준다. 점수와 같이 0~100 으로 구성되는 좁은 범위에 존재하는 데이터들을 정렬할 때 유용하게 사용할 수 있다.

| Space Complexity | Time Complexity |
| :--------------: | :-------------: |
|       O(n)       |      O(n)       |

</br>

### Radix Sort

정렬 알고리즘의 한계는 O(n log n)이지만, 기수 정렬은 이 한계를 넘어설 수 있는 알고리즘이다. 단, 한 가지 단점이 존재하는데 적용할 수 있는 범위가 제한적이라는 것이다. 이 범위는 **데이터 길이** 에 의존하게 된다. 정렬하고자 하는 데이터의 길이가 동일하지 않은 데이터에 대해서는 정렬이 불가능하다. 숫자말고 문자열의 경우도 마찬가지이다. (불가능하다는 것은 기존의 정렬 알고리즘에 비해 기수 정렬 알고리즘으로는 좋은 성능을 내는데 불가능하다는 것이다.)

기수(radix)란 주어진 데이터를 구성하는 기본요소를 의미한다. 이 기수를 이용해서 정렬을 진행한다. 하나의 기수마다 하나의 버킷을 생성하여, 분류를 한 뒤에, 버킷 안에서 또 정렬을 하는 방식이다.

기수 정렬은 `LSD(Least Significant Digit)` 방식과 `MSD(Most Significant Digit)` 방식 두 가지로 나뉜다. LSD 는 덜 중요한 숫자부터 정렬하는 방식으로 예를 들어 숫자를 정렬한다고 했을 때, 일의 자리부터 정렬하는 방식이다. MSD 는 중요한 숫자부터 정렬하는 방식으로 세 자리 숫자면 백의 자리부터 정렬하는 방식이다.

두 가지 방식의 Big-O 는 동일하다. 하지만 주로 기수정렬을 이야기할 때는 LSD 를 이야기한다. LSD 는 중간에 정렬 결과를 볼 수 없다. 무조건 일의 자리부터 시작해서 백의 자리까지 모두 정렬이 끝나야 결과를 확인할 수 있고, 그 때서야 결과가 나온다. 하지만 MSD 는 정렬 중간에 정렬이 될 수 있다. 그러므로 정렬하는데 걸리는 시간을 줄일 수 있다. 하지만 정렬이 완료됬는지 확인하는 과정이 필요하고 이 때문에 메모리를 더 사용하게 된다. 또 상황마다 일관적인 정렬 알고리즘을 사용하여 정렬하는데 적용할 수 없으므로 불편하다. 이러한 이유들로 기수 정렬을 논할 때는 주로 LSD 에 대해서 논한다.

| Space Complexity | Time Complexity |
| :--------------: | :-------------: |
|       O(n)       |      O(n)       |

</br>

#### Sorting Algorithm's Complexity 정리

|   Algorithm    | Space Complexity | (average) Time Complexity | (worst) Time Complexity |
| :------------: | :--------------: | :-----------------------: | :---------------------: |
|  Bubble sort   |       O(1)       |          O(n^2)           |         O(n^2)          |
| Selection sort |       O(1)       |          O(n^2)           |         O(n^2)          |
| Insertion sort |       O(1)       |          O(n^2)           |         O(n^2)          |
|   Merge sort   |       O(n)       |         O(nlogn)          |        O(nlogn)         |
|   Heap sort    |       O(1)       |         O(nlogn)          |        O(nlogn)         |
|   Quick sort   |       O(1)       |         O(nlogn)          |         O(n^2)          |
|   Count sort   |       O(n)       |           O(n)            |          O(n)           |
|   Radix sort   |       O(n)       |           O(n)            |          O(n)           |

#### 더 읽을거리

* [Sorting Algorithm 을 비판적으로 바라보자](http://asfirstalways.tistory.com/338)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#algorithm)

</br>

## Prime Number Algorithm

소수란 양의 약수를 딱 두 개만 갖는 자연수를 소수라 부른다. 2, 3, 5, 7, 11, …이 그런 수들인데, 소수를 판별하는 방법으로 첫 번째로 3보다 크거나 같은 임의의 양의 정수 N이 소수인지 판별하기 위해서는 N 을 2 부터 N 보다 1 작은 수까지 나누어서 나머지가 0 인 경우가 있는지 검사하는 방법과 두 번째로 `에라토스테네스의 체`를 사용할 수 있다.  

아래 코드는 2부터 N - 1까지를 순회하며 소수인지 판별하는 코드와 2부터 √N까지 순회하며 소수인지 판별하는 코드이다.
```cpp
// Time complexity: O(N)
bool is_prime(int N) {
    if(N == 1) return false;
    for(int i = 2; i < N - 1; ++i) {
        if(N % i == 0) {
            return false;
        }
    }
    return true;
}
```

```cpp
// Time complexity: O(√N)
bool is_prime(int N) {
    if(N == 1) return false;
    for(long long i = 2; i * i <= N; ++i) { // 주의) i를 int로 선언하면 i*i를 계산할 때 overflow가 발생할 수 있다.
        if(N % i == 0) {
            return false;
        }
    }
    return true;
}
```



### 에라토스테네스의 체 [Eratosthenes’ sieve]

`에라토스테네스의 체(Eratosthenes’ sieve)`는, 임의의 자연수에 대하여, 그 자연수 이하의 `소수(prime number)`를 모두 찾아 주는 방법이다. 입자의 크기가 서로 다른 가루들을 섞어 체에 거르면 특정 크기 이하의 가루들은 다 아래로 떨어지고, 그 이상의 것들만 체 위에 남는 것처럼, 에라토스테네스의 체를 사용하면 특정 자연수 이하의 합성수는 다 지워지고 소수들만 남는 것이다. 방법은 간단하다. 만일 `100` 이하의 소수를 모두 찾고 싶다면, `1` 부터 `100` 까지의 자연수를 모두 나열한 후, 먼저 소수도 합성수도 아닌 `1`을 지우고, `2`외의 `2`의 배수들을 다 지우고, `3`외의 `3`의 배수들을 다 지우고, `5`외의 `5`의 배수들을 지우는 등의 이 과정을 의 `100`제곱근인 `10`이하의 소수들에 대해서만 반복하면, 이때 남은 수들이 구하고자 하는 소수들이다.</br>

에라토스테네스의 체를 이용하여 50 까지의 소수를 구하는 순서를 그림으로 표현하면 다음과 같다.</br>

1.  초기 상태

|  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  | 10  |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| 11  | 12  | 13  | 14  | 15  | 16  | 17  | 18  | 19  | 20  |
| 21  | 22  | 23  | 24  | 25  | 26  | 27  | 28  | 29  | 30  |
| 31  | 32  | 33  | 34  | 35  | 36  | 37  | 38  | 39  | 40  |
| 41  | 42  | 43  | 44  | 45  | 46  | 47  | 48  | 49  | 50  |

2.  소수도 합성수도 아닌 1 제거

|  x  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  | 10  |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| 11  | 12  | 13  | 14  | 15  | 16  | 17  | 18  | 19  | 20  |
| 21  | 22  | 23  | 24  | 25  | 26  | 27  | 28  | 29  | 30  |
| 31  | 32  | 33  | 34  | 35  | 36  | 37  | 38  | 39  | 40  |
| 41  | 42  | 43  | 44  | 45  | 46  | 47  | 48  | 49  | 50  |

3.  2 외의 2 의 배수들을 제거

|  x  |  2  |  3  |  x  |  5  |  x  |  7  |  x  |  9  |  x  |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| 11  |  x  | 13  |  x  | 15  |  x  | 17  |  x  | 19  |  x  |
| 21  |  x  | 23  |  x  | 25  |  x  | 27  |  x  | 29  |  x  |
| 31  |  x  | 33  |  x  | 35  |  x  | 37  |  x  | 39  |  x  |
| 41  |  x  | 43  |  x  | 45  |  x  | 47  |  x  | 49  |  x  |

4.  3 외의 3 의 배수들을 제거

|  x  |  2  |  3  |  x  |  5  |  x  |  7  |  x  |  x  |  x  |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| 11  |  x  | 13  |  x  |  x  |  x  | 17  |  x  | 19  |  x  |
|  x  |  x  | 23  |  x  | 25  |  x  |  x  |  x  | 29  |  x  |
| 31  |  x  |  x  |  x  | 35  |  x  | 37  |  x  |  x  |  x  |
| 41  |  x  | 43  |  x  |  x  |  x  | 47  |  x  | 49  |  x  |

5.  5 외의 5 의 배수들을 제거

|  x  |  2  |  3  |  x  |  5  |  x  |  7  |  x  |  x  |  x  |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| 11  |  x  | 13  |  x  |  x  |  x  | 17  |  x  | 19  |  x  |
|  x  |  x  | 23  |  x  |  x  |  x  |  x  |  x  | 29  |  x  |
| 31  |  x  |  x  |  x  |  x  |  x  | 37  |  x  |  x  |  x  |
| 41  |  x  | 43  |  x  |  x  |  x  | 47  |  x  | 49  |  x  |

6.  7 외의 7 의 배수들을 제거(50 이하의 소수 판별 완료)

|  x  |  2  |  3  |  x  |  5  |  x  |  7  |  x  |  x  |  x  |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| 11  |  x  | 13  |  x  |  x  |  x  | 17  |  x  | 19  |  x  |
|  x  |  x  | 23  |  x  |  x  |  x  |  x  |  x  | 29  |  x  |
| 31  |  x  |  x  |  x  |  x  |  x  | 37  |  x  |  x  |  x  |
| 41  |  x  | 43  |  x  |  x  |  x  | 47  |  x  |  x  |  x  |

| Space Complexity | Time Complexity |
| :--------------: | :-------------: |
|       O(n)       |   O(nloglogn)   |

#### [code](http://boj.kr/90930351636e46f7842b1f017eec831b)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#algorithm)

</br>

#### Time Complexity

O(1) < O(log N) < O(N) < O(N log N) < O(N^2) < O(N^3)

O(2^N) : 크기가 N 인 집합의 부분 집합

O(N!) : 크기가 N 인 순열

#### 알고리즘 문제 연습 사이트

* https://algospot.com/
* https://codeforces.com
* http://topcoder.com
* https://www.acmicpc.net/
* https://leetcode.com/problemset/algorithms/
* https://programmers.co.kr/learn/challenges
* https://www.hackerrank.com
* http://codingdojang.com/
* http://codeup.kr/JudgeOnline/index.php
* http://euler.synap.co.kr/
* http://koistudy.net
* https://www.codewars.com
* https://app.codility.com/programmers/
* http://euler.synap.co.kr/
* https://swexpertacademy.com/
* https://www.codeground.org/
* https://onlinejudge.org/

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#algorithm)

</br>

</br>

_Algorithm.end_


================================================
FILE: CONTRIBUTING.md
================================================
# HOW TO CONTRIBUTE

여러 가지 방법으로 해당 Repository 에 참여하실 수 있습니다 :)
PR 을 올려주실 때, labels 를 참고하셔서 알맞은 제목을 함께 올려주세요!
Commit Message 는 `Update`라고만 해주셔도 되고, 원하시는 메세지를 적어주시면 됩니다.

## Process

해당 Repository 에 contribute 하는 방법을 소개드립니다.

### Pull Request 를 통한 Contribute

#### 1. Fork this respository

이 repository 를 fork 해주세요!

#### 2. Clone forked repository

fork 해간 repository 를 local directory 에 clone 해주세요!

```bash
# in your workspace
$ git clone https://github.com/JaeYeopHan/Interview_Question_for_Beginner interview
$ cd interview
```

#### 3. Commit your

```bash
$ git add .
$ git commit -m "[your description]"
$ git push origin master
```

### 4. Register pull request for your commit

`Pull Request`를 등록해주세요.

### 5. Apply prettier

```
$ prettier --write **/*.md
# or
$ npx prettier --write **/*.md
```

### Optional. Resolve Conflict

Pull Request 를 등록했는데, conflict 가 있어서 auto merge 가 안된다고 하는 경우 해당 conflict 를 해결해주세요.

```bash
# in Interview_Question_for_Beginner
$ git remote add --track master upstream https://github.com/JaeYeopHan/Interview_Question_for_Beginner
$ git fetch upstream
$ git rebase upstream/master
# (resolve conflict in your editor)
$ git add .
$ git rebase --continue
$ git push -f origin master
```

- 참고자료 : [많은 Git 커맨드 중 정말 필요한 것만 정리한 내용](https://github.com/JaeYeopHan/Minimal_Git_command)

### Issue 를 통한 Contribute

Pull Request 방식이 익숙하시지 않은 분들은 issue 로 내용을 등록하실 수도 있습니다. 추가하고 싶은 내용을 issue 로 등록해주시면 저 또는 다른 분들이 적절한 위치에 올려주신 내용을 추가할 수 있습니다 :)

</br>

---

</br>

## Labels for PR

- Edit typos or links
  - 오타 또는 잘못된 링크를 수정.
- Inaccurate information
  - 잘못된 정보에 대한 Fix.
- New Resources
  - 새로운 자료 추가

### 그 외 Labels

- Suggestions
  - 해당 `Repository`에 건의하고 싶은 사항에 대해서 `Issue`로 등록해주세요.
- Questions
  - 질문이 있으시면 해당 Label 과 함께 `Issue`를 등록해주세요.

</br>

_Pull Request example>_

## Edit typo or link path

DataStructure Link 수정

</br>

---

### ISSUE_TEMPLATE

```
### This issue is...
* [ ] Edit typos or links
* [ ] Inaccurate information
* [ ] New Resources
* [ ] Suggestions
* [ ] Questions

#### Description
(say something...)
```

</br>

### PULL_REQUEST_TEMPLATE

```
### This Pull Request is...
* [ ] Edit typos or links
* [ ] Inaccurate information
* [ ] New Resources

#### Description
(say something...)
```


================================================
FILE: DataStructure/README.md
================================================
# Part 1-2 DataStructure

* [Array vs Linked List](#array-vs-linked-list)
* [Stack and Queue](#stack-and-queue)
* [Tree](#tree)
  * Binary Tree
  * Full Binary Tree
  * Complete Binary Tree
  * BST (Binary Search Tree)
* [Binary Heap](#binary-heap)
* [Red Black Tree](#red-black-tree)
  * 정의
  * 특징
  * 삽입
  * 삭제
* [Hash Table](#hash-table)
  * Hash Function
  * Resolve Collision
    * Open Addressing
    * Separate Chaining
  * Resize
* [Graph](#graph)
  * Graph 용어정리
  * Graph 구현
  * Graph 탐색
  * Minimum Spanning Tree
    * Kruskal algorithm
    * Prim algorithm

[뒤로](https://github.com/JaeYeopHan/for_beginner)

</br>

## Array vs Linked List

### Array

가장 기본적인 자료구조인 `Array` 자료구조는, 논리적 저장 순서와 물리적 저장 순서가 일치한다. 따라서 `인덱스`(index)로 해당 원소(element)에 접근할 수 있다. 그렇기 때문에 찾고자 하는 원소의 인덱스 값을 알고 있으면 `Big-O(1)`에 해당 원소로 접근할 수 있다. 즉 **random access** 가 가능하다는 장점이 있는 것이다.

하지만 삭제 또는 삽입의 과정에서는 해당 원소에 접근하여 작업을 완료한 뒤(O(1)), 또 한 가지의 작업을 추가적으로 해줘야 하기 때문에, 시간이 더 걸린다. 만약 배열의 원소 중 어느 원소를 삭제했다고 했을 때, 배열의 연속적인 특징이 깨지게 된다. 즉 빈 공간이 생기는 것이다. 따라서 삭제한 원소보다 큰 인덱스를 갖는 원소들을 `shift`해줘야 하는 비용(cost)이 발생하고 이 경우의 시간 복잡도는 O(n)가 된다. 그렇기 때문에 Array 자료구조에서 삭제 기능에 대한 time complexity 의 worst case 는 O(n)이 된다.

삽입의 경우도 마찬가지이다. 만약 첫번째 자리에 새로운 원소를 추가하고자 한다면 모든 원소들의 인덱스를 1 씩 shift 해줘야 하므로 이 경우도 O(n)의 시간을 요구하게 된다.

### Linked List

이 부분에 대한 문제점을 해결하기 위한 자료구조가 linked list 이다. 각각의 원소들은 자기 자신 다음에 어떤 원소인지만을 기억하고 있다. 따라서 이 부분만 다른 값으로 바꿔주면 삭제와 삽입을 O(1) 만에 해결할 수 있는 것이다.

하지만 Linked List 역시 한 가지 문제가 있다. 원하는 위치에 삽입을 하고자 하면 원하는 위치를 Search 과정에 있어서 첫번째 원소부터 다 확인해봐야 한다는 것이다. Array 와는 달리 논리적 저장 순서와 물리적 저장 순서가 일치하지 않기 때문이다. 이것은 일단 삽입하고 정렬하는 것과 마찬가지이다. 이 과정 때문에, 어떠한 원소를 삭제 또는 추가하고자 했을 때, 그 원소를 찾기 위해서 O(n)의 시간이 추가적으로 발생하게 된다.

결국 linked list 자료구조는 search 에도 O(n)의 time complexity 를 갖고, 삽입, 삭제에 대해서도 O(n)의 time complexity 를 갖는다. 그렇다고 해서 아주 쓸모없는 자료구조는 아니기에, 우리가 학습하는 것이다. 이 Linked List 는 Tree 구조의 근간이 되는 자료구조이며, Tree 에서 사용되었을 때 그 유용성이 드러난다.

#### Personal Recommendation

* Array 를 기반으로한 Linked List 구현
* ArrayList 를 기반으로한 Linked List 구현

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-2-datastructure)

---

</br>

## Stack and Queue

### Stack

선형 자료구조의 일종으로 `Last In First Out (LIFO)` - 나중에 들어간 원소가 먼저 나온다. 또는 `First In Last Out (FILO)` - 먼저 들어간 원소가 나중에 나온다. 이것은 Stack 의 가장 큰 특징이다. 차곡차곡 쌓이는 구조로 먼저 Stack 에 들어가게 된 원소는 맨 바닥에 깔리게 된다. 그렇기 때문에 늦게 들어간 녀석들은 그 위에 쌓이게 되고 호출 시 가장 위에 있는 녀석이 호출되는 구조이다.

### Queue

선형 자료구조의 일종으로 `First In First Out (FIFO)`. 즉, 먼저 들어간 놈이 먼저 나온다. Stack 과는 반대로 먼저 들어간 놈이 맨 앞에서 대기하고 있다가 먼저 나오게 되는 구조이다. 참고로 Java Collection 에서 Queue 는 인터페이스이다. 이를 구현하고 있는 `Priority queue`등을 사용할 수 있다.

#### Personal Recommendation

* Stack 을 사용하여 미로찾기 구현하기
* Queue 를 사용하여 Heap 자료구조 구현하기
* Stack 두 개로 Queue 자료구조 구현하기
* Stack 으로 괄호 유효성 체크 코드 구현하기

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-2-datastructure)

---

</br>

## Tree

트리는 스택이나 큐와 같은 선형 구조가 아닌 비선형 자료구조이다. 트리는 계층적 관계(Hierarchical Relationship)을 표현하는 자료구조이다. 이 `트리`라는 자료구조는 표현에 집중한다. 무엇인가를 저장하고 꺼내야 한다는 사고에서 벗어나 트리라는 자료구조를 바라보자.

#### 트리를 구성하고 있는 구성요소들(용어)

* Node (노드) : 트리를 구성하고 있는 각각의 요소를 의미한다.
* Edge (간선) : 트리를 구성하기 위해 노드와 노드를 연결하는 선을 의미한다.
* Root Node (루트 노드) : 트리 구조에서 최상위에 있는 노드를 의미한다.
* Terminal Node ( = leaf Node, 단말 노드) : 하위에 다른 노드가 연결되어 있지 않은 노드를 의미한다.
* Internal Node (내부노드, 비단말 노드) : 단말 노드를 제외한 모든 노드로 루트 노드를 포함한다.

</br>

### Binary Tree (이진 트리)

루트 노드를 중심으로 두 개의 서브 트리(큰 트리에 속하는 작은 트리)로 나뉘어 진다. 또한 나뉘어진 두 서브 트리도 모두 이진 트리어야 한다. 재귀적인 정의라 맞는듯 하면서도 이해가 쉽지 않을 듯하다. 한 가지 덧붙이자면 공집합도 이진 트리로 포함시켜야 한다. 그래야 재귀적으로 조건을 확인해갔을 때, leaf node 에 다다랐을 때, 정의가 만족되기 때문이다. 자연스럽게 노드가 하나 뿐인 것도 이진 트리 정의에 만족하게 된다.

트리에서는 각 `층별로` 숫자를 매겨서 이를 트리의 `Level(레벨)`이라고 한다. 레벨의 값은 0 부터 시작하고 따라서 루트 노드의 레벨은 0 이다. 그리고 트리의 최고 레벨을 가리켜 해당 트리의 `height(높이)`라고 한다.

#### Perfect Binary Tree (포화 이진 트리), Complete Binary Tree (완전 이진 트리), Full Binary Tree (정 이진 트리)

모든 레벨이 꽉 찬 이진 트리를 가리켜 포화 이진 트리라고 한다. 위에서 아래로, 왼쪽에서 오른쪽으로 순서대로 차곡차곡 채워진 이진 트리를 가리켜 완전 이진 트리라고 한다. 모든 노드가 0개 혹은 2개의 자식 노드만을 갖는 이진 트리를 가리켜 정 이진 트리라고 한다. 배열로 구성된 `Binary Tree`는 노드의 개수가 n 개이고 root가 0이 아닌 1에서 시작할 때, i 번째 노드에 대해서 parent(i) = i/2 , left_child(i) = 2i , right_child(i) = 2i + 1 의 index 값을 갖는다.

</br>

### BST (Binary Search Tree)

효율적인 탐색을 위해서는 어떻게 찾을까만 고민해서는 안된다. 그보다는 효율적인 탐색을 위한 저장방법이 무엇일까를 고민해야 한다. 이진 탐색 트리는 이진 트리의 일종이다. 단 이진 탐색 트리에는 데이터를 저장하는 규칙이 있다. 그리고 그 규칙은 특정 데이터의 위치를 찾는데 사용할 수 있다.

* 규칙 1. 이진 탐색 트리의 노드에 저장된 키는 유일하다.
* 규칙 2. 부모의 키가 왼쪽 자식 노드의 키보다 크다.
* 규칙 3. 부모의 키가 오른쪽 자식 노드의 키보다 작다.
* 규칙 4. 왼쪽과 오른쪽 서브트리도 이진 탐색 트리이다.

이진 탐색 트리의 탐색 연산은 O(log n)의 시간 복잡도를 갖는다. 사실 정확히 말하면 O(h)라고 표현하는 것이 맞다. 트리의 높이를 하나씩 더해갈수록 추가할 수 있는 노드의 수가 두 배씩 증가하기 때문이다. 하지만 이러한 이진 탐색 트리는 Skewed Tree(편향 트리)가 될 수 있다. 저장 순서에 따라 계속 한 쪽으로만 노드가 추가되는 경우가 발생하기 때문이다. 이럴 경우 성능에 영향을 미치게 되며, 탐색의 Worst Case 가 되고 시간 복잡도는 O(n)이 된다.

배열보다 많은 메모리를 사용하며 데이터를 저장했지만 탐색에 필요한 시간 복잡도가 같게 되는 비효율적인 상황이 발생한다. 이를 해결하기 위해 `Rebalancing` 기법이 등장하였다. 균형을 잡기 위한 트리 구조의 재조정을 `Rebalancing`이라 한다. 이 기법을 구현한 트리에는 여러 종류가 존재하는데 그 중에서 하나가 뒤에서 살펴볼 `Red-Black Tree`이다.

#### Personal Recommendation

* Binary Search Tree 구현하기
* 주어진 트리가 Binary 트리인지 확인하는 알고리즘 구현하기

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-2-datastructure)

</br>

## Binary Heap

자료구조의 일종으로 Tree 의 형식을 하고 있으며, Tree 중에서도 배열에 기반한 `Complete Binary Tree`이다. 배열에 트리의 값들을 넣어줄 때, 0 번째는 건너뛰고 1 번 index 부터 루트노드가 시작된다. 이는 노드의 고유번호 값과 배열의 index 를 일치시켜 혼동을 줄이기 위함이다. `힙(Heap)`에는 `최대힙(max heap)`, `최소힙(min heap)` 두 종류가 있다.

`Max Heap`이란, 각 노드의 값이 해당 children 의 값보다 **크거나 같은** `complete binary tree`를 말한다. ( Min Heap 은 그 반대이다.)

`Max Heap`에서는 Root node 에 있는 값이 제일 크므로, 최대값을 찾는데 소요되는 연산의 time complexity 이 O(1)이다. 그리고 `complete binary tree`이기 때문에 배열을 사용하여 효율적으로 관리할 수 있다. (즉, random access 가 가능하다. Min heap 에서는 최소값을 찾는데 소요되는 연산의 time complexity 가 O(1)이다.) 하지만 heap 의 구조를 계속 유지하기 위해서는 제거된 루트 노드를 대체할 다른 노드가 필요하다. 여기서 heap 은 맨 마지막 노드를 루트 노드로 대체시킨 후, 다시 heapify 과정을 거쳐 heap 구조를 유지한다. 이런 경우에는 결국 O(log n)의 시간복잡도로 최대값 또는 최소값에 접근할 수 있게 된다.

#### Personal Recommendation

* Heapify 구현하기

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-2-datastructure)

</br>

## Red Black Tree

RBT(Red-Black Tree)는 BST 를 기반으로하는 트리 형식의 자료구조이다. 결론부터 말하자면 Red-Black Tree 에 데이터를 저장하게되면 Search, Insert, Delete 에 O(log n)의 시간 복잡도가 소요된다. 동일한 노드의 개수일 때, depth 를 최소화하여 시간 복잡도를 줄이는 것이 핵심 아이디어이다. 동일한 노드의 개수일 때, depth 가 최소가 되는 경우는 tree 가 complete binary tree 인 경우이다.

### Red-Black Tree 의 정의

Red-Black Tree 는 다음의 성질들을 만족하는 BST 이다.

1.  각 노드는 `Red` or `Black`이라는 색깔을 갖는다.
2.  Root node 의 색깔은 `Black`이다.
3.  각 leaf node 는 `black`이다.
4.  어떤 노드의 색깔이 `red`라면 두 개의 children 의 색깔은 모두 black 이다.
5.  각 노드에 대해서 노드로부터 descendant leaves 까지의 단순 경로는 모두 같은 수의 black nodes 들을 포함하고 있다. 이를 해당 노드의 `Black-Height`라고 한다.
    _cf) Black-Height: 노드 x 로부터 노드 x 를 포함하지 않은 leaf node 까지의 simple path 상에 있는 black nodes 들의 개수_

### Red-Black Tree 의 특징

1.  Binary Search Tree 이므로 BST 의 특징을 모두 갖는다.
2.  Root node 부터 leaf node 까지의 모든 경로 중 최소 경로와 최대 경로의 크기 비율은 2 보다 크지 않다. 이러한 상태를 `balanced` 상태라고 한다.
3.  노드의 child 가 없을 경우 child 를 가리키는 포인터는 NIL 값을 저장한다. 이러한 NIL 들을 leaf node 로 간주한다.

_RBT 는 BST 의 삽입, 삭제 연산 과정에서 발생할 수 있는 문제점을 해결하기 위해 만들어진 자료구조이다. 이를 어떻게 해결한 것인가?_

</br>

### 삽입

우선 BST 의 특성을 유지하면서 노드를 삽입을 한다. 그리고 삽입된 노드의 색깔을 **RED 로** 지정한다. Red 로 지정하는 이유는 Black-Height 변경을 최소화하기 위함이다. 삽입 결과 RBT 의 특성 위배(violation)시 노드의 색깔을 조정하고, Black-Height 가 위배되었다면 rotation 을 통해 height 를 조정한다. 이러한 과정을 통해 RBT 의 동일한 height 에 존재하는 internal node 들의 Black-height 가 같아지게 되고 최소 경로와 최대 경로의 크기 비율이 2 미만으로 유지된다.

### 삭제

삭제도 삽입과 마찬가지로 BST 의 특성을 유지하면서 해당 노드를 삭제한다. 삭제될 노드의 child 의 개수에 따라 rotation 방법이 달라지게 된다. 그리고 만약 지워진 노드의 색깔이 Black 이라면 Black-Height 가 1 감소한 경로에 black node 가 1 개 추가되도록 rotation 하고 노드의 색깔을 조정한다. 지워진 노드의 색깔이 red 라면 Violation 이 발생하지 않으므로 RBT 가 그대로 유지된다.

Java Collection 에서 TreeMap 도 내부적으로 RBT 로 이루어져 있고, HashMap 에서의 `Separate Chaining`에서도 사용된다. 그만큼 효율이 좋고 중요한 자료구조이다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-2-datastructure)

---

</br>

## Hash Table

`hash`는 내부적으로 `배열`을 사용하여 데이터를 저장하기 때문에 빠른 검색 속도를 갖는다. 특정한 값을 Search 하는데 데이터 고유의 `인덱스`로 접근하게 되므로 average case 에 대하여 Time Complexity 가 O(1)이 되는 것이다.(항상 O(1)이 아니고 average case 에 대해서 O(1)인 것은 collision 때문이다.) 하지만 문제는 이 인덱스로 저장되는 `key`값이 불규칙하다는 것이다.

그래서 **특별한 알고리즘을 이용하여** 저장할 데이터와 연관된 **고유한 숫자를 만들어 낸 뒤** 이를 인덱스로 사용한다. 특정 데이터가 저장되는 인덱스는 그 데이터만의 고유한 위치이기 때문에, 삽입 연산 시 다른 데이터의 사이에 끼어들거나, 삭제 시 다른 데이터로 채울 필요가 없으므로 연산에서 추가적인 비용이 없도록 만들어진 구조이다.

</br>

### Hash Function

'특별한 알고리즘'이란 것을 통해 고유한 인덱스 값을 설정하는 것이 중요해보인다. 위에서 언급한 '특별한 알고리즘'을 `hash method` 또는 `해시 함수(hash function)`라고 하고 이 메소드에 의해 반환된 데이터의 고유 숫자 값을 `hashcode`라고 한다. 저장되는 값들의 key 값을 `hash function`을 통해서 **작은 범위의 값들로** 바꿔준다.

하지만 어설픈 `hash function`을 통해서 key 값들을 결정한다면 동일한 값이 도출될 수가 있다. 이렇게 되면 동일한 key 값에 복수 개의 데이터가 하나의 테이블에 존재할 수 있게 되는 것인데 이를 `Collision` 이라고 한다.
_Collision : 서로 다른 두 개의 키가 같은 인덱스로 hashing(hash 함수를 통해 계산됨을 의미)되면 같은 곳에 저장할 수 없게 된다._

#### 그렇다면 좋은 `hash function`는 어떠한 조건들을 갖추고 있어야 하는가?

일반적으로 좋은 `hash function`는 키의 일부분을 참조하여 해쉬 값을 만들지 않고 키 전체를 참조하여 해쉬 값을 만들어 낸다. 하지만 좋은 해쉬 함수는 키가 어떤 특성을 가지고 있느냐에 따라 달라지게 된다.

`hash function`를 무조건 1:1 로 만드는 것보다 Collision 을 최소화하는 방향으로 설계하고 발생하는 Collision 에 대비해 어떻게 대응할 것인가가 더 중요하다. 1:1 대응이 되도록 만드는 것이 거의 불가능하기도 하지만 그런 `hash function`를 만들어봤자 그건 array 와 다를바 없고 메모리를 너무 차지하게 된다.

Collision 이 많아질 수록 Search 에 필요한 Time Complexity 가 O(1)에서 O(n)에 가까워진다. 어설픈 `hash function`는 hash 를 hash 답게 사용하지 못하도록 한다. 좋은 `hash function`를 선택하는 것은 hash table 의 성능 향상에 필수적인 것이다.

따라서 hashing 된 인덱스에 이미 다른 값이 들어 있다면 새 데이터를 저장할 다른 위치를 찾은 뒤에야 저장할 수 있는 것이다. 따라서 충돌 해결은 필수이며 그 방법들에 대해 알아보자.

</br>

### Resolve Conflict

기본적인 두 가지 방법부터 알아보자. 해시 충돌을 해결하기 위한 다양한 자료가 있지만, 다음 두 가지 방법을 응용한 방법들이기 때문이다.

#### 1. Open Address 방식 (개방주소법)

해시 충돌이 발생하면, (즉 삽입하려는 해시 버킷이 이미 사용 중인 경우) **다른 해시 버킷에 해당 자료를 삽입하는 방식** 이다. 버킷이란 바구니와 같은 개념으로 데이터를 저장하기 위한 공간이라고 생각하면 된다. 다른 해시 버킷이란 어떤 해시 버킷을 말하는 것인가?

공개 주소 방식이라고도 불리는 이 알고리즘은 Collision 이 발생하면 데이터를 저장할 장소를 찾아 헤맨다. Worst Case 의 경우 비어있는 버킷을 찾지 못하고 탐색을 시작한 위치까지 되돌아 올 수 있다. 이 과정에서도 여러 방법들이 존재하는데, 다음 세 가지에 대해 알아보자.

1.  Linear Probing
    순차적으로 탐색하며 비어있는 버킷을 찾을 때까지 계속 진행된다.
2.  Quadratic probing
    2 차 함수를 이용해 탐색할 위치를 찾는다.
3.  Double hashing probing
    하나의 해쉬 함수에서 충돌이 발생하면 2 차 해쉬 함수를 이용해 새로운 주소를 할당한다. 위 두 가지 방법에 비해 많은 연산량을 요구하게 된다.

</br>

#### 2. Separate Chaining 방식 (분리 연결법)

일반적으로 Open Addressing 은 Separate Chaining 보다 느리다. Open Addressing 의 경우 해시 버킷을 채운 밀도가 높아질수록 Worst Case 발생 빈도가 더 높아지기 때문이다. 반면 Separate Chaining 방식의 경우 해시 충돌이 잘 발생하지 않도록 보조 해시 함수를 통해 조정할 수 있다면 Worst Case 에 가까워 지는 빈도를 줄일 수 있다. Java 7 에서는 Separate Chaining 방식을 사용하여 HashMap 을 구현하고 있다. Separate Chaining 방식으로는 두 가지 구현 방식이 존재한다.

* **연결 리스트를 사용하는 방식(Linked List)**
  각각의 버킷(bucket)들을 연결리스트(Linked List)로 만들어 Collision 이 발생하면 해당 bucket 의 list 에 추가하는 방식이다. 연결 리스트의 특징을 그대로 이어받아 삭제 또는 삽입이 간단하다. 하지만 단점도 그대로 물려받아 작은 데이터들을 저장할 때 연결 리스트 자체의 오버헤드가 부담이 된다. 또 다른 특징으로는, 버킷을 계속해서 사용하는 Open Address 방식에 비해 테이블의 확장을 늦출 수 있다.

* **Tree 를 사용하는 방식 (Red-Black Tree)**
  기본적인 알고리즘은 Separate Chaining 방식과 동일하며 연결 리스트 대신 트리를 사용하는 방식이다. 연결 리스트를 사용할 것인가와 트리를 사용할 것인가에 대한 기준은 하나의 해시 버킷에 할당된 key-value 쌍의 개수이다. 데이터의 개수가 적다면 링크드 리스트를 사용하는 것이 맞다. 트리는 기본적으로 메모리 사용량이 많기 때문이다. 데이터 개수가 적을 때 Worst Case 를 살펴보면 트리와 링크드 리스트의 성능 상 차이가 거의 없다. 따라서 메모리 측면을 봤을 때 데이터 개수가 적을 때는 링크드 리스트를 사용한다.

**_데이터가 적다는 것은 얼마나 적다는 것을 의미하는가?_**
앞에서 말했듯이 기준은 하나의 해시 버킷에 할당된 key-value 쌍의 개수이다. 이 키-값 쌍의 개수가 6 개, 8 개를 기준으로 결정한다. 기준이 두 개 인것이 이상하게 느껴질 수 있다. 7 은 어디로 갔는가? 링크드 리스트의 기준과 트리의 기준을 6 과 8 로 잡은 것은 변경하는데 소요되는 비용을 줄이기 위함이다.

**_한 가지 상황을 가정해보자._**
해시 버킷에 **6 개** 의 key-value 쌍이 들어있었다. 그리고 하나의 값이 추가되었다. 만약 기준이 6 과 7 이라면 자료구조를 링크드 리스트에서 트리로 변경해야 한다. 그러다 바로 하나의 값이 삭제된다면 다시 트리에서 링크드 리스트로 자료구조를 변경해야 한다. 각각 자료구조로 넘어가는 기준이 1 이라면 Switching 비용이 너무 많이 필요하게 되는 것이다. 그래서 2 라는 여유를 남겨두고 기준을 잡아준 것이다. 따라서 데이터의 개수가 6 개에서 7 개로 증가했을 때는 링크드 리스트의 자료구조를 취하고 있을 것이고 8 개에서 7 개로 감소했을 때는 트리의 자료구조를 취하고 있을 것이다.

#### `Open Address` vs `Separate Chaining`

일단 두 방식 모두 Worst Case 에서 O(M)이다. 하지만 `Open Address`방식은 연속된 공간에 데이터를 저장하기 때문에 `Separate Chaining`에 비해 캐시 효율이 높다. 따라서 데이터의 개수가 충분히 적다면 `Open Address`방식이 `Separate Chaining`보다 더 성능이 좋다. 한 가지 차이점이 더 존재한다. `Separate Chaining`방식에 비해 `Open Address`방식은 버킷을 계속해서 사용한다. 따라서 `Separate Chaining` 방식은 테이블의 확장을 보다 늦출 수 있다.

#### 보조 해시 함수

보조 해시 함수(supplement hash function)의 목적은 `key`의 해시 값을 변형하여 해시 충돌 가능성을 줄이는 것이다. `Separate Chaining` 방식을 사용할 때 함께 사용되며 보조 해시 함수로 Worst Case 에 가까워지는 경우를 줄일 수 있다.

</br>

### 해시 버킷 동적 확장(Resize)

해시 버킷의 개수가 적다면 메모리 사용을 아낄 수 있지만 해시 충돌로 인해 성능 상 손실이 발생한다. 그래서 HashMap 은 key-value 쌍 데이터 개수가 일정 개수 이상이 되면 해시 버킷의 개수를 두 배로 늘린다. 이렇게 늘리면 해시 충돌로 인한 성능 손실 문제를 어느 정도 해결할 수 있다. 또 애매모호한 '일정 개수 이상'이라는 표현이 등장했다. 해시 버킷 크기를 두 배로 확장하는 임계점은 현재 데이터 개수가 해시 버킷의 개수의 75%가 될 때이다. `0.75`라는 숫자는 load factor 라고 불린다.

##### Reference

* http://d2.naver.com/helloworld/831311

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-2-datastructure)

---

</br>

## Graph

### 정점과 간선의 집합, Graph

_cf) 트리 또한 그래프이며, 그 중 사이클이 허용되지 않는 그래프를 말한다._

### 그래프 관련 용어 정리

#### Undirected Graph 와 Directed Graph (Digraph)

말 그대로 정점과 간선의 연결관계에 있어서 방향성이 없는 그래프를 Undirected Graph 라 하고,
간선에 방향성이 포함되어 있는 그래프를 Directed Graph 라고 한다.

* Directed Graph (Digraph)

```
V = {1, 2, 3, 4, 5, 6}
E = {(1, 4), (2,1), (3, 4), (3, 4), (5, 6)}
(u, v) = vertex u에서 vertex v로 가는 edge
```

* Undirected Graph

```
V = {1, 2, 3, 4, 5, 6}
E = {(1, 4), (2,1), (3, 4), (3, 4), (5, 6)}
(u, v) = vertex u와 vertex v를 연결하는 edge
```

#### Degree

Undirected Graph 에서 각 정점(Vertex)에 연결된 Edge 의 개수를 Degree 라 한다.
Directed Graph 에서는 간선에 방향성이 존재하기 때문에 Degree 가 두 개로 나뉘게 된다.
각 정점으로부터 나가는 간선의 개수를 Outdegree 라 하고, 들어오는 간선의 개수를 Indegree 라 한다.

#### 가중치 그래프(Weight Graph)와 부분 그래프(Sub Graph)

가중치 그래프란 간선에 가중치 정보를 두어서 구성한 그래프를 말한다. 반대의 개념인 비가중치 그래프 즉, 모든 간선의 가중치가 동일한 그래프도 물론 존재한다. 부분 집합과 유사한 개념으로 부분 그래프라는 것이 있다. 부분 그래프는 본래의 그래프의 일부 정점 및 간선으로 이루어진 그래프를 말한다.

</br>

### 그래프를 구현하는 두 방법

#### 인접 행렬 (adjacent matrix) : 정방 행렬을 사용하는 방법

해당하는 위치의 value 값을 통해서 vertex 간의 연결 관계를 O(1) 으로 파악할 수 있다. Edge 개수와는 무관하게 V^2 의 Space Complexity 를 갖는다. Dense graph 를 표현할 때 적절할 방법이다.

#### 인접 리스트 (adjacent list) : 연결 리스트를 사용하는 방법

vertex 의 adjacent list 를 확인해봐야 하므로 vertex 간 연결되어있는지 확인하는데 오래 걸린다. Space Complexity 는 O(E + V)이다. Sparse graph 를 표현하는데 적당한 방법이다.

</br>

### 그래프 탐색

그래프는 정점의 구성 뿐만 아니라 간선의 연결에도 규칙이 존재하지 않기 때문에 탐색이 복잡하다. 따라서 그래프의 모든 정점을 탐색하기 위한 방법은 다음의 두 가지 알고리즘을 기반으로 한다.

#### 깊이 우선 탐색 (Depth First Search: DFS)

그래프 상에 존재하는 임의의 한 정점으로부터 연결되어 있는 한 정점으로만 나아간다라는 방법을 우선으로 탐색한다. 일단 연결된 정점으로 탐색하는 것이다. 연결할 수 있는 정점이 있을 때까지 계속 연결하다가 더 이상 연결될 수 있는 정점이 없으면 바로 그 전 단계의 정점으로 돌아가서 연결할 수 있는 정점이 있는지 살펴봐야 할 것이다. 갔던 길을 되돌아 오는 상황이 존재하는 미로찾기처럼 구성하면 되는 것이다. 어떤 자료구조를 사용해야할까? 바로 Stack 이다.
**Time Complexity : O(V+E) … vertex 개수 + edge 개수**

#### 너비 우선 탐색 (Breadth First Search: BFS)

그래프 상에 존재하는 임의의 한 정점으로부터 연결되어 있는 모든 정점으로 나아간다. Tree 에서의 Level Order Traversal 형식으로 진행되는 것이다. BFS 에서는 자료구조로 Queue 를 사용한다. 연락을 취할 정점의 순서를 기록하기 위한 것이다.
우선, 탐색을 시작하는 정점을 Queue 에 넣는다.(enqueue) 그리고 dequeue 를 하면서 dequeue 하는 정점과 간선으로 연결되어 있는 정점들을 enqueue 한다.
즉 vertex 들을 방문한 순서대로 queue 에 저장하는 방법을 사용하는 것이다.

**Time Complexity : O(V+E) … vertex 개수 + edge 개수**

_**! 모든 간선에 가중치가 존재하지않거나 모든 간선의 가중치가 같은 경우, BFS 로 구한 경로는 최단 경로이다.**_

</br>

### Minimum Spanning Tree

그래프 G 의 spanning tree 중 edge weight 의 합이 최소인 `spanning tree`를 말한다. 여기서 말하는 `spanning tree`란 그래프 G 의 모든 vertex 가 cycle 이 없이 연결된 형태를 말한다.

### Kruskal Algorithm

초기화 작업으로 **edge 없이** vertex 들만으로 그래프를 구성한다. 그리고 weight 가 제일 작은 edge 부터 검토한다. 그러기 위해선 Edge Set 을 non-decreasing 으로 sorting 해야 한다. 그리고 가장 작은 weight 에 해당하는 edge 를 추가하는데 추가할 때 그래프에 cycle 이 생기지 않는 경우에만 추가한다. spanning tree 가 완성되면 모든 vertex 들이 연결된 상태로 종료가 되고 완성될 수 없는 그래프에 대해서는 모든 edge 에 대해 판단이 이루어지면 종료된다.
[Kruskal Algorithm의 세부 동작과정](https://gmlwjd9405.github.io/2018/08/29/algorithm-kruskal-mst.html)
[Kruskal Algorithm 관련 Code](https://github.com/morecreativa/Algorithm_Practice/blob/master/Kruskal%20Algorithm.cpp)

#### 어떻게 cycle 생성 여부를 판단하는가?

Graph 의 각 vertex 에 `set-id`라는 것을 추가적으로 부여한다. 그리고 초기화 과정에서 모두 1~n 까지의 값으로 각각의 vertex 들을 초기화 한다. 여기서 0 은 어떠한 edge 와도 연결되지 않았음을 의미하게 된다. 그리고 연결할 때마다 `set-id`를 하나로 통일시키는데, 값이 동일한 `set-id` 개수가 많은 `set-id` 값으로 통일시킨다.

#### Time Complexity

1.  Edge 의 weight 를 기준으로 sorting - O(E log E)
2.  cycle 생성 여부를 검사하고 set-id 를 통일 - O(E + V log V)
    => 전체 시간 복잡도 : O(E log E)

### Prim Algorithm

초기화 과정에서 한 개의 vertex 로 이루어진 초기 그래프 A 를 구성한다. 그리고나서 그래프 A 내부에 있는 vertex 로부터 외부에 있는 vertex 사이의 edge 를 연결하는데 그 중 가장 작은 weight 의 edge 를 통해 연결되는 vertex 를 추가한다. 어떤 vertex 건 간에 상관없이 edge 의 weight 를 기준으로 연결하는 것이다. 이렇게 연결된 vertex 는 그래프 A 에 포함된다. 위 과정을 반복하고 모든 vertex 들이 연결되면 종료한다.

#### Time Complexity

=> 전체 시간 복잡도 : O(E log V)

</br>

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-2-datastructure)

_DataStructure.end_


================================================
FILE: Database/README.md
================================================
# Part 1-5 Database

* [데이터베이스](#데이터베이스)
  * 데이터베이스를 사용하는 이유
  * 데이터베이스 성능
* [Index](#index)
  * Index 란 무엇인가
  * Index 의 자료구조
  * Primary index vs Secondary index
  * Composite index
  * Index 의 성능과 고려해야할 사항
* [정규화에 대해서](#정규화에-대해서)
  * 정규화 탄생 배경
  * 정규화란 무엇인가
  * 정규화의 종류
  * 정규화의 장단점
* [Transaction](#transaction)
  * 트랜잭션(Transaction)이란 무엇인가?
  * 트랜잭션과 Lock
  * 트랜잭션의 특성
  * 트랜잭션을 사용할 때 주의할 점
* [교착상태](#교착상태)
  * 교착상태란 무엇인가
  * 교착상태의 예(MySQL)
  * 교착 상태의 빈도를 낮추는 방법
* [Statement vs PreparedStatement](#statement-vs-preparedstatement)
* [NoSQL](#nosql)
  * 정의
  * CAP 이론
    * 일관성
    * 가용성
    * 네트워크 분할 허용성
  * 저장방식에 따른 분류
    * Key-Value Model
    * Document Model
    * Column Model

[뒤로](https://github.com/JaeYeopHan/for_beginner)

</br>

## 데이터베이스

### 데이터베이스를 사용하는 이유

데이터베이스가 존재하기 이전에는 파일 시스템을 이용하여 데이터를 관리하였다. (현재도 부분적으로 사용되고 있다.) 데이터를 각각의 파일 단위로 저장하며 이러한 일들을 처리하기 위한 독립적인 애플리케이션과 상호 연동이 되어야 한다. 이 때의 문제점은 데이터 종속성 문제와 중복성, 데이터 무결성이다.

#### 데이터베이스의 특징

1.  데이터의 독립성
    * 물리적 독립성 : 데이터베이스 사이즈를 늘리거나 성능 향상을 위해 데이터 파일을 늘리거나 새롭게 추가하더라도 관련된 응용 프로그램을 수정할 필요가 없다.
    * 논리적 독립성 : 데이터베이스는 논리적인 구조로 다양한 응용 프로그램의 논리적 요구를 만족시켜줄 수 있다.
2.  데이터의 무결성   
    여러 경로를 통해 잘못된 데이터가 발생하는 경우의 수를 방지하는 기능으로 데이터의 유효성 검사를 통해 데이터의 무결성을 구현하게 된다.
3.  데이터의 보안성   
    인가된 사용자들만 데이터베이스나 데이터베이스 내의 자원에 접근할 수 있도록 계정 관리 또는 접근 권한을 설정함으로써 모든 데이터에 보안을 구현할 수 있다.
4.  데이터의 일관성   
    연관된 정보를 논리적인 구조로 관리함으로써 어떤 하나의 데이터만 변경했을 경우 발생할 수 있는 데이터의 불일치성을 배제할 수 있다. 또한 작업 중 일부 데이터만 변경되어 나머지 데이터와 일치하지 않는 경우의 수를 배제할 수 있다.
5.  데이터 중복 최소화   
    데이터베이스는 데이터를 통합해서 관리함으로써 파일 시스템의 단점 중 하나인 자료의 중복과 데이터의 중복성 문제를 해결할 수 있다.

</br>

### 데이터베이스의 성능?

데이터베이스의 성능 이슈는 디스크 I/O 를 어떻게 줄이느냐에서 시작된다. 디스크 I/O 란 디스크 드라이브의 플래터(원판)을 돌려서 읽어야 할 데이터가 저장된 위치로 디스크 헤더를 이동시킨 다음 데이터를 읽는 것을 의미한다. 이 때 데이터를 읽는데 걸리는 시간은 디스크 헤더를 움직여서 읽고 쓸 위치로 옮기는 단계에서 결정된다. 즉 디스크의 성능은 디스크 헤더의 위치 이동 없이 얼마나 많은 데이터를 한 번에 기록하느냐에 따라 결정된다고 볼 수 있다.

그렇기 때문에 순차 I/O 가 랜덤 I/O 보다 빠를 수 밖에 없다. 하지만 현실에서는 대부분의 I/O 작업이 랜덤 I/O 이다. 랜덤 I/O 를 순차 I/O 로 바꿔서 실행할 수는 없을까? 이러한 생각에서부터 시작되는 데이터베이스 쿼리 튜닝은 랜덤 I/O 자체를 줄여주는 것이 목적이라고 할 수 있다.

</br>

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-5-database)

</br>

## Index

### 인덱스(Index)란 무엇인가?

인덱스는 말 그대로 책의 맨 처음 또는 맨 마지막에 있는 색인이라고 할 수 있다. 이 비유를 그대로 가져와서 인덱스를 살펴본다면 데이터는 책의 내용이고 데이터가 저장된 레코드의 주소는 인덱스 목록에 있는 페이지 번호가 될 것이다. DBMS 도 데이터베이스 테이블의 모든 데이터를 검색해서 원하는 결과를 가져 오려면 시간이 오래 걸린다. 그래서 칼럼의 값과 해당 레코드가 저장된 주소를 키와 값의 쌍으로 인덱스를 만들어 두는 것이다.

DBMS 의 인덱스는 항상 정렬된 상태를 유지하기 때문에 원하는 값을 탐색하는데는 빠르지만 새로운 값을 추가하거나 삭제, 수정하는 경우에는 쿼리문 실행 속도가 느려진다. 결론적으로 DBMS 에서 인덱스는 데이터의 저장 성능을 희생하고 그 대신 데이터의 읽기 속도를 높이는 기능이다. SELECT 쿼리 문장의 WHERE 조건절에 사용되는 칼럼이라고 전부 인덱스로 생성하면 데이터 저장 성능이 떨어지고 인덱스의 크기가 비대해져서 오히려 역효과만 불러올 수 있다.

</br>

### Index 자료구조

그렇다면 DBMS 는 인덱스를 어떻게 관리하고 있는가

#### B+-Tree 인덱스 알고리즘

일반적으로 사용되는 인덱스 알고리즘은 B+-Tree 알고리즘이다. B+-Tree 인덱스는 칼럼의 값을 변형하지 않고(사실 값의 앞부분만 잘라서 관리한다.), 원래의 값을 이용해 인덱싱하는 알고리즘이다.

#### Hash 인덱스 알고리즘

칼럼의 값으로 해시 값을 계산해서 인덱싱하는 알고리즘으로 매우 빠른 검색을 지원한다. 하지만 값을 변형해서 인덱싱하므로, 특정 문자로 시작하는 값으로 검색을 하는 전방 일치와 같이 값의 일부만으로 검색하고자 할 때는 해시 인덱스를 사용할 수 없다. 주로 메모리 기반의 데이터베이스에서 많이 사용한다.

#### 왜 index 를 생성하는데 b-tree 를 사용하는가?

데이터에 접근하는 시간복잡도가 O(1)인 hash table 이 더 효율적일 것 같은데? SELECT 질의의 조건에는 부등호(<>) 연산도 포함이 된다. hash table 을 사용하게 된다면 등호(=) 연산이 아닌 부등호 연산의 경우에 문제가 발생한다. 동등 연산(=)에 특화된 `hashtable`은 데이터베이스의 자료구조로 적합하지 않다.

</br>

### Primary Index vs Secondary Index

- Primary Index는 *Primary Key에 대해서 생성된 Index* 를 의미한다
  - 테이블 당 하나의 Primary Index만 존재할 수 있다
- Secondary Index는 *Primary Key가 아닌 다른 칼럼에 대해서 생성된 Index* 를 의미한다
  - 테이블 당 여러 개의 Secondary Index를 생성할 수 있다

### Clustered Index vs Non-clustered Index

클러스터(Cluster)란 여러 개를 하나로 묶는다는 의미로 주로 사용되는데, 클러스터드 인덱스도 크게 다르지 않다. 인덱스에서 클러스터드는 비슷한 것들을 묶어서 저장하는 형태로 구현되는데, 이는 주로 비슷한 값들을 동시에 조회하는 경우가 많다는 점에서 착안된 것이다. 여기서 비슷한 값들은 물리적으로 *인접한 장소에 저장* 되어 있는 데이터들을 말한다.

- 클러스터드 인덱스(Clustered Index)는 인덱스가 적용된 속성 값에 의해 레코드의 물리적 저장 위치가 결정되는 인덱스이다.
- 일반적으로 데이터베이스 시스템은 Primary Key에 대해서 기본적으로 클러스터드 인덱스를 생성한다.
  - Primary Key는 행마다 고유하며 Null 값을 가질 수 없기 때문에 물리적 정렬 기준으로 적합하기 때문이다.
  - 이러한 경우에는 Primary Key 값이 비슷한 레코드끼리 묶어서 저장하게 된다.
- 물론 Primary Key가 아닌 다른 칼럼에 대해서도 클러스터드 인덱스를 생성할 수 있다.
- 클러스터드 인덱스에서는 인덱스가 적용된 속성 값(주로 Primary Key)에 의해 *레코드의 저장 위치가 결정* 되며 속성 값이 변경되면 그 레코드의 물리적인 저장 위치 또한 변경되어야 한다.
  - 그렇기 때문에 어떤 속성에 클러스터드 인덱스를 적용할지 신중하게 결정하고 사용해야 한다.
- 클러스터드 인덱스는 테이블 당 한 개만 생성할 수 있다.
- 논클러스터드 인덱스(Non-clustered Index)는 데이터를 물리적으로 정렬하지 않는다.
  - 논클러스터드 인덱스는 별도의 인덱스 테이블을 만들어 실제 데이터 테이블의 행을 참조한다.
  - 테이블 당 여러 개의 논클러스터드 인덱스를 생성할 수 있다.

</br>

### Composite Index

인덱스로 설정하는 필드의 속성이 중요하다. title, author 이 순서로 인덱스를 설정한다면 title 을 search 하는 경우, index 를 생성한 효과를 볼 수 있지만, author 만으로 search 하는 경우, index 를 생성한 것이 소용이 없어진다. 따라서 SELECT 질의를 어떻게 할 것인가가 인덱스를 어떻게 생성할 것인가에 대해 많은 영향을 끼치게 된다.

</br>

### Index 의 성능과 고려해야할 사항

SELECT 쿼리의 성능을 월등히 향상시키는 INDEX 항상 좋은 것일까? 쿼리문의 성능을 향상시킨다는데, 모든 컬럼에 INDEX 를 생성해두면 빨라지지 않을까?
_결론부터 말하자면 그렇지 않다._
우선, 첫번째 이유는 INDEX 를 생성하게 되면 INSERT, DELETE, UPDATE 쿼리문을 실행할 때 별도의 과정이 추가적으로 발생한다. INSERT 의 경우 INDEX 에 대한 데이터도 추가해야 하므로 그만큼 성능에 손실이 따른다. DELETE 의 경우 INDEX 에 존재하는 값은 삭제하지 않고 사용 안한다는 표시로 남게 된다. 즉 row 의 수는 그대로인 것이다. 이 작업이 반복되면 어떻게 될까?

실제 데이터는 10 만건인데 데이터가 100 만건 있는 결과를 낳을 수도 있는 것이다. 이렇게 되면 인덱스는 더 이상 제 역할을 못하게 되는 것이다. UPDATE 의 경우는 INSERT 의 경우, DELETE 의 경우의 문제점을 동시에 수반한다. 이전 데이터가 삭제되고 그 자리에 새 데이터가 들어오는 개념이기 때문이다. 즉 변경 전 데이터는 삭제되지 않고 insert 로 인한 split 도 발생하게 된다.

하지만 더 중요한 것은 컬럼을 이루고 있는 데이터의 형식에 따라서 인덱스의 성능이 악영향을 미칠 수 있다는 것이다. 즉, 데이터의 형식에 따라 인덱스를 만들면 효율적이고 만들면 비효율적은 데이터의 형식이 존재한다는 것이다. 어떤 경우에 그럴까?

`이름`, `나이`, `성별` 세 가지의 필드를 갖고 있는 테이블을 생각해보자.
이름은 온갖 경우의 수가 존재할 것이며 나이는 INT 타입을 갖을 것이고, 성별은 남, 녀 두 가지 경우에 대해서만 데이터가 존재할 것임을 쉽게 예측할 수 있다. 이 경우 어떤 컬럼에 대해서 인덱스를 생성하는 것이 효율적일까? 결론부터 말하자면 이름에 대해서만 인덱스를 생성하면 효율적이다.

왜 성별이나 나이는 인덱스를 생성하면 비효율적일까?
10000 레코드에 해당하는 테이블에 대해서 2000 단위로 성별에 인덱스를 생성했다고 가정하자. 값의 range 가 적은 성별은 인덱스를 읽고 다시 한 번 디스크 I/O 가 발생하기 때문에 그 만큼 비효율적인 것이다.

</br>

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-5-database)

</br>

## 정규화에 대해서

### 1. 정규화는 어떤 배경에서 생겨났는가?

한 릴레이션에 여러 엔티티의 애트리뷰트들을 혼합하게 되면 정보가 중복 저장되며, 저장 공간을 낭비하게 된다. 또 중복된 정보로 인해 `갱신 이상`이 발생하게 된다. 동일한 정보를 한 릴레이션에는 변경하고, 나머지 릴레이션에서는 변경하지 않은 경우 어느 것이 정확한지 알 수 없게 되는 것이다. 이러한 문제를 해결하기 위해 정규화 과정을 거치는 것이다.

#### 1-1. 갱신 이상에는 어떠한 것들이 있는가?

* 삽입 이상(insertion anomalies)
  원하지 않는 자료가 삽입된다든지, 삽입하는데 자료가 부족해 삽입이 되지 않아 발생하는 문제점을 말한다.

* 삭제 이상(deletion anomalies)
  하나의 자료만 삭제하고 싶지만, 그 자료가 포함된 튜플 전체가 삭제됨으로 원하지 않는 정보 손실이 발생하는 문제점을 말한다.

* 수정(갱신)이상(modification anomalies)
  정확하지 않거나 일부의 튜플만 갱신되어 정보가 모호해지거나 일관성이 없어져 정확한 정보 파악이 되지 않는 문제점을 말한다.

</br>

### 2. 그래서 정규화란 무엇인가?

관계형 데이터베이스에서 중복을 최소화하기 위해 데이터를 구조화하는 작업이다. 좀 더 구체적으로는 불만족스러운 **나쁜** 릴레이션의 애트리뷰트들을 나누어서 **좋은** 작은 릴레이션으로 분해하는 작업을 말한다. 정규화 과정을 거치게 되면 정규형을 만족하게 된다. 정규형이란 특정 조건을 만족하는 릴레이션의 스키마의 형태를 말하며 제 1 정규형, 제 2 정규형, 제 3 정규형, … 등이 존재한다.

#### 2-1. ‘나쁜' 릴레이션은 어떻게 파악하는가?

엔티티를 구성하고 있는 애트리뷰트 간에 함수적 종속성(Functional Dependency)을 판단한다. 판단된 함수적 종속성은 좋은 릴레이션 설계의 정형적 기준으로 사용된다. 즉, 각각의 정규형마다 어떠한 함수적 종속성을 만족하는지에 따라 정규형이 정의되고, 그 정규형을 만족하지 못하는 정규형을 나쁜 릴레이션으로 파악한다.

#### 2-2. 함수적 종속성이란 무엇인가?

함수적 종속성이란 애트리뷰트 데이터들의 의미와 애트리뷰트들 간의 상호 관계로부터 유도되는 제약조건의 일종이다. X 와 Y 를 임의의 애트리뷰트 집합이라고 할 때, X 의 값이 Y 의 값을 유일하게(unique) 결정한다면 "X 는 Y 를 함수적으로 결정한다"라고 한다. 함수적 종속성은 실세계에서 존재하는 애트리뷰트들 사이의 제약조건으로부터 유도된다. 또한 각종 추론 규칙에 따라서 애트리뷰트들간의 함수적 종속성을 판단할 수 있다.
_cf> 애트리뷰트들의 관계로부터 추론된 함수적 종속성들을 기반으로 추론 가능한 모든 함수적 종속성들의 집합을 폐포라고 한다._

#### 2-3. 각각의 정규형은 어떠한 조건을 만족해야 하는가?

1.  분해의 대상인 분해 집합 D 는 **무손실 조인** 을 보장해야 한다.
2.  분해 집합 D 는 함수적 종속성을 보존해야 한다.

</br>

### 제 1 정규형

애트리뷰트의 도메인이 오직 `원자값`만을 포함하고, 튜플의 모든 애트리뷰트가 도메인에 속하는 하나의 값을 가져야 한다. 즉, 복합 애트리뷰트, 다중값 애트리뷰트, 중첩 릴레이션 등 비 원자적인 애트리뷰트들을 허용하지 않는 릴레이션 형태를 말한다.

### 제 2 정규형

모든 비주요 애트리뷰트들이 주요 애트리뷰트에 대해서 **완전 함수적 종속이면** 제 2 정규형을 만족한다고 볼 수 있다. 완전 함수적 종속이란 `X -> Y` 라고 가정했을 때, X 의 어떠한 애트리뷰트라도 제거하면 더 이상 함수적 종속성이 성립하지 않는 경우를 말한다. 즉, 키가 아닌 열들이 각각 후보키에 대해 결정되는 릴레이션 형태를 말한다.

### 제 3 정규형

어떠한 비주요 애트리뷰트도 기본키에 대해서 **이행적으로 종속되지 않으면** 제 3 정규형을 만족한다고 볼 수 있다. 이행 함수적 종속이란 `X - >Y`, `Y -> Z`의 경우에 의해서 추론될 수 있는 `X -> Z`의 종속관계를 말한다. 즉, 비주요 애트리뷰트가 비주요 애트리뷰트에 의해 종속되는 경우가 없는 릴레이션 형태를 말한다.

### BCNF(Boyce-Codd) 정규형

여러 후보 키가 존재하는 릴레이션에 해당하는 정규화 내용이다. 복잡한 식별자 관계에 의해 발생하는 문제를 해결하기 위해 제 3 정규형을 보완하는데 의미가 있다. 비주요 애트리뷰트가 후보키의 일부를 결정하는 분해하는 과정을 말한다.

_각 정규형은 그의 선행 정규형보다 더 엄격한 조건을 갖는다._

* 모든 제 2 정규형 릴레이션은 제 1 정규형을 갖는다.
* 모든 제 3 정규형 릴레이션은 제 2 정규형을 갖는다.
* 모든 BCNF 정규형 릴레이션은 제 3 정규형을 갖는다.

수많은 정규형이 있지만 관계 데이터베이스 설계의 목표는 각 릴레이션이 3NF(or BCNF)를 갖게 하는 것이다.

</br>

### 3. 정규화에는 어떠한 장점이 있는가?

1.  데이터베이스 변경 시 이상 현상(Anomaly) 제거
    위에서 언급했던 각종 이상 현상들이 발생하는 문제점을 해결할 수 있다.

2.  데이터베이스 구조 확장 시 재 디자인 최소화
    정규화된 데이터베이스 구조에서는 새로운 데이터 형의 추가로 인한 확장 시, 그 구조를 변경하지 않아도 되거나 일부만 변경해도 된다. 이는 데이터베이스와 연동된 응용 프로그램에 최소한의 영향만을 미치게 되며 응용프로그램의 생명을 연장시킨다.

3.  사용자에게 데이터 모델을 더욱 의미있게 제공
    정규화된 테이블들과 정규화된 테이블들간의 관계들은 현실 세계에서의 개념들과 그들간의 관계들을 반영한다.

</br>

### 4. 단점은 없는가?

릴레이션의 분해로 인해 릴레이션 간의 연산(JOIN 연산)이 많아진다. 이로 인해 질의에 대한 응답 시간이 느려질 수 있다.
조금 덧붙이자면, 정규화를 수행한다는 것은 데이터를 결정하는 결정자에 의해 함수적 종속을 가지고 있는 일반 속성을 의존자로 하여 입력/수정/삭제 이상을 제거하는 것이다. 데이터의 중복 속성을 제거하고 결정자에 의해 동일한 의미의 일반 속성이 하나의 테이블로 집약되므로 한 테이블의 데이터 용량이 최소화되는 효과가 있다. 따라서 정규화된 테이블은 데이터를 처리할 때 속도가 빨라질 수도 있고 느려질 수도 있는 특성이 있다.

</br>

### 5. 단점에서 미루어보았을 때 어떠한 상황에서 정규화를 진행해야 하는가? 단점에 대한 대응책은?

조회를 하는 SQL 문장에서 조인이 많이 발생하여 이로 인한 성능저하가 나타나는 경우에 반정규화를 적용하는 전략이 필요하다.

#### 반정규화(De-normalization, 비정규화)

`반정규화`는 정규화된 엔티티, 속성, 관계를 시스템의 성능 향상 및 개발과 운영의 단순화를 위해 중복 통합, 분리 등을 수행하는 데이터 모델링 기법 중 하나이다. 디스크 I/O 량이 많아서 조회 시 성능이 저하되거나, 테이블끼리의 경로가 너무 멀어 조인으로 인한 성능 저하가 예상되거나, 칼럼을 계산하여 조회할 때 성능이 저하될 것이 예상되는 경우 반정규화를 수행하게 된다. 일반적으로 조회에 대한 처리 성능이 중요하다고 판단될 때 부분적으로 반정규화를 고려하게 된다.

#### 5-1. 무엇이 반정규화의 대상이 되는가?

1.  자주 사용되는 테이블에 액세스하는 프로세스의 수가 가장 많고, 항상 일정한 범위만을 조회하는 경우
2.  테이블에 대량 데이터가 있고 대량의 범위를 자주 처리하는 경우, 성능 상 이슈가 있을 경우
3.  테이블에 지나치게 조인을 많이 사용하게 되어 데이터를 조회하는 것이 기술적으로 어려울 경우

#### 5-2. 반정규화 과정에서 주의할 점은?

반정규화를 과도하게 적용하다 보면 데이터의 무결성이 깨질 수 있다. 또한 입력, 수정, 삭제의 질의문에 대한 응답 시간이 늦어질 수 있다.

</br>

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-5-database)

</br>

## Transaction

### 트랜잭션(Transaction)이란 무엇인가?

트랜잭션은 작업의 **완전성** 을 보장해주는 것이다. 즉, 논리적인 작업 셋을 모두 완벽하게 처리하거나 또는 처리하지 못할 경우에는 원 상태로 복구해서 작업의 일부만 적용되는 현상이 발생하지 않게 만들어주는 기능이다. 사용자의 입장에서는 작업의 논리적 단위로 이해를 할 수 있고 시스템의 입장에서는 데이터들을 접근 또는 변경하는 프로그램의 단위가 된다.

</br>

### 트랜잭션과 Lock

잠금(Lock)과 트랜잭션은 서로 비슷한 개념 같지만 사실 잠금은 동시성을 제어하기 위한 기능이고 트랜잭션은 데이터의 정합성을 보장하기 위한 기능이다. 잠금은 여러 커넥션에서 동시에 동일한 자원을 요청할 경우 순서대로 한 시점에는 하나의 커넥션만 변경할 수 있게 해주는 역할을 한다. 여기서 자원은 레코드나 테이블을 말한다. 이와는 조금 다르게 트랜잭션은 꼭 여러 개의 변경 작업을 수행하는 쿼리가 조합되었을 때만 의미있는 개념은 아니다. 트랜잭션은 하나의 논리적인 작업 셋 중 하나의 쿼리가 있든 두 개 이상의 쿼리가 있든 관계없이 논리적인 작업 셋 자체가 100% 적용되거나 아무것도 적용되지 않아야 함을 보장하는 것이다. 예를 들면 HW 에러 또는 SW 에러와 같은 문제로 인해 작업에 실패가 있을 경우, 특별한 대책이 필요하게 되는데 이러한 문제를 해결하는 것이다.

</br>

### 트랜잭션의 특성

_트랜잭션은 어떠한 특성을 만족해야할까?_
Transaction 은 다음의 ACID 라는 4 가지 특성을 만족해야 한다.

#### 원자성(Atomicity)

만약 트랜잭션 중간에 어떠한 문제가 발생한다면 트랜잭션에 해당하는 어떠한 작업 내용도 수행되어서는 안되며 아무런 문제가 발생되지 않았을 경우에만 모든 작업이 수행되어야 한다.

#### 일관성(Consistency)

트랜잭션이 완료된 다음의 상태에서도 트랜잭션이 일어나기 전의 상황과 동일하게 데이터의 일관성을 보장해야 한다.

#### 고립성(Isolation)

각각의 트랜잭션은 서로 간섭없이 독립적으로 수행되어야 한다.

#### 지속성(Durability)

트랜잭션이 정상적으로 종료된 다음에는 영구적으로 데이터베이스에 작업의 결과가 저장되어야 한다.

</br>

### 트랜잭션의 상태

![트랜잭션 상태 다이어그램](/Database/images/transaction-status.png)

#### Active

트랜잭션의 활동 상태. 트랜잭션이 실행중이며 동작중인 상태를 말한다.

#### Failed

트랜잭션 실패 상태. 트랜잭션이 더이상 정상적으로 진행 할 수 없는 상태를 말한다.

#### Partially Committed

트랜잭션의 `Commit` 명령이 도착한 상태. 트랜잭션의 `commit`이전 `sql`문이 수행되고 `commit`만 남은 상태를 말한다.

#### Committed

트랜잭션 완료 상태. 트랜잭션이 정상적으로 완료된 상태를 말한다.

#### Aborted

트랜잭션이 취소 상태. 트랜잭션이 취소되고 트랜잭션 실행 이전 데이터로 돌아간 상태를 말한다.

#### Partially Committed 와 Committed 의 차이점

`Commit` 요청이 들어오면 상태는 `Partial Commited` 상태가 된다. 이후 `Commit`을 문제없이 수행할 수 있으면 `Committed` 상태로 전이되고, 만약 오류가 발생하면 `Failed` 상태가 된다. 즉, `Partial Commited`는 `Commit` 요청이 들어왔을때를 말하며, `Commited`는 `Commit`을 정상적으로 완료한 상태를 말한다.

### 트랜잭션을 사용할 때 주의할 점

트랜잭션은 꼭 필요한 최소의 코드에만 적용하는 것이 좋다. 즉 트랜잭션의 범위를 최소화하라는 의미다. 일반적으로 데이터베이스 커넥션은 개수가 제한적이다. 그런데 각 단위 프로그램이 커넥션을 소유하는 시간이 길어진다면 사용 가능한 여유 커넥션의 개수는 줄어들게 된다. 그러다 어느 순간에는 각 단위 프로그램에서 커넥션을 가져가기 위해 기다려야 하는 상황이 발생할 수도 있는 것이다.


### 교착상태

#### 교착상태란 무엇인가

복수의 트랜잭션을 사용하다보면 교착상태가 일어날수 있다. 교착상태란 두 개 이상의 트랜잭션이 특정 자원(테이블 또는 행)의 잠금(Lock)을 획득한 채 다른 트랜잭션이 소유하고 있는 잠금을 요구하면 아무리 기다려도 상황이 바뀌지 않는 상태가 되는데, 이를 `교착상태`라고 한다.

#### 교착상태의 예(MySQL)

MySQL [MVCC](https://en.wikipedia.org/wiki/Multiversion_concurrency_control)에 따른 특성 때문에 트랜잭션에서 갱신 연산(Insert, Update, Delete)를 실행하면 잠금을 획득한다. (기본은 행에 대한 잠금)

![classic deadlock 출처: https://darkiri.wordpress.com/tag/sql-server/](/Database/images/deadlock.png)

트랜잭션 1이 테이블 B의 첫번째 행의 잠금을 얻고 트랜잭션 2도 테이블 A의 첫번째 행의 잠금을 얻었다고 하자.
```SQL
Transaction 1> create table B (i1 int not null primary key) engine = innodb;
Transaction 2> create table A (i1 int not null primary key) engine = innodb;

Transaction 1> start transaction; insert into B values(1);
Transaction 2> start transaction; insert into A values(1);
```

트랜잭션을 commit 하지 않은채 서로의 첫번째 행에 대한 잠금을 요청하면


```SQL
Transaction 1> insert into A values(1);
Transaction 2> insert into B values(1);
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
```

Deadlock 이 발생한다. 일반적인 DBMS는 교착상태를 독자적으로 검출해 보고한다.

#### 교착 상태의 빈도를 낮추는 방법
* 트랜잭션을 자주 커밋한다.
* 정해진 순서로 테이블에 접근한다. 위에서 트랜잭션 1 이 테이블 B -> A 의 순으로 접근했고,
트랜잭션 2 는 테이블 A -> B의 순으로 접근했다. 트랜잭션들이 동일한 테이블 순으로 접근하게 한다.
* 읽기 잠금 획득 (SELECT ~ FOR UPDATE)의 사용을 피한다.
* 한 테이블의 복수 행을 복수의 연결에서 순서 없이 갱신하면 교착상태가 발생하기 쉽다, 이 경우에는 테이블 단위의 잠금을 획득해 갱신을 직렬화 하면 동시성은 떨어지지만 교착상태를 회피할 수 있다.
</br>

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-5-database)

</br>

## Statement vs PreparedStatement

우선 속도 면에서 `PreparedStatement`가 빠르다고 알려져 있다. 이유는 쿼리를 수행하기 전에 이미 쿼리가 컴파일 되어 있으며, 반복 수행의 경우 프리 컴파일된 쿼리를 통해 수행이 이루어지기 때문이다.

`Statement`에는 보통 변수를 설정하고 바인딩하는 `static sql`이 사용되고 `Prepared Statement`에서는 쿼리 자체에 조건이 들어가는 `dynamic sql`이 사용된다. `PreparedStatement`가 파싱 타임을 줄여주는 것은 분명하지만 `dynamic sql`을 사용하는데 따르는 퍼포먼스 저하를 고려하지 않을 수 없다.

하지만 성능을 고려할 때 시간 부분에서 가장 큰 비중을 차지하는 것은 테이블에서 레코드(row)를 가져오는 과정이고 SQL 문을 파싱하는 시간은 이 시간의 10 분의 1 에 불과하다. 그렇기 때문에 `SQL Injection` 등의 문제를 보완해주는 `PreparedStatement`를 사용하는 것이 옳다.

#### 참고 자료

* http://java.ihoney.pe.kr/76

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-5-database)

</br>

## NoSQL

### 정의

관계형 데이터 모델을 **지양** 하며 대량의 분산된 데이터를 저장하고 조회하는 데 특화되었으며 스키마 없이 사용 가능하거나 느슨한 스키마를 제공하는 저장소를 말한다.

종류마다 쓰기/읽기 성능 특화, 2 차 인덱스 지원, 오토 샤딩 지원 같은 고유한 특징을 가진다. 대량의 데이터를 빠르게 처리하기 위해 메모리에 임시 저장하고 응답하는 등의 방법을 사용한다. 동적인 스케일 아웃을 지원하기도 하며, 가용성을 위하여 데이터 복제 등의 방법으로 관계형 데이터베이스가 제공하지 못하는 성능과 특징을 제공한다.

</br>

### CAP 이론

### 1. 일관성(Consistency)

일관성은 동시성 또는 동일성이라고도 하며 다중 클라이언트에서 같은 시간에 조회하는 데이터는 항상 동일한 데이터임을 보증하는 것을 의미한다. 이것은 관계형 데이터베이스가 지원하는 가장 기본적인 기능이지만 일관성을 지원하지 않는 NoSQL 을 사용한다면 데이터의 일관성이 느슨하게 처리되어 동일한 데이터가 나타나지 않을 수 있다. 느슨하게 처리된다는 것은 데이터의 변경을 시간의 흐름에 따라 여러 노드에 전파하는 것을 말한다. 이러한 방법을 최종적으로 일관성이 유지된다고 하여 최종 일관성 또는 궁극적 일관성을 지원한다고 한다.

각 NoSQL 들은 분산 노드 간의 데이터 동기화를 위해서 두 가지 방법을 사용한다.
첫번째로 데이터의 저장 결과를 클라이언트로 응답하기 전에 모든 노드에 데이터를 저장하는 동기식 방법이 있다. 그만큼 느린 응답시간을 보이지만 데이터의 정합성을 보장한다.
두번째로 메모리나 임시 파일에 기록하고 클라이언트에 먼저 응답한 다음, 특정 이벤트 또는 프로세스를 사용하여 노드로 데이터를 동기화하는 비동기식 방법이 있다. 빠른 응답시간을 보인다는 장점이 있지만, 쓰기 노드에 장애가 발생하였을 경우 데이터가 손실될 수 있다.

</br>

### 2. 가용성(Availability)

가용성이란 모든 클라이언트의 읽기와 쓰기 요청에 대하여 항상 응답이 가능해야 함을 보증하는 것이며 내고장성이라고도 한다. 내고장성을 가진 NoSQL 은 클러스터 내에서 몇 개의 노드가 망가지더라도 정상적인 서비스가 가능하다.

몇몇 NoSQL 은 가용성을 보장하기 위해 데이터 복제(Replication)을 사용한다. 동일한 데이터를 다중 노드에 중복 저장하여 그 중 몇 대의 노드가 고장나도 데이터가 유실되지 않도록 하는 방법이다. 데이터 중복 저장 방법에는 동일한 데이터를 가진 저장소를 하나 더 생성하는 Master-Slave 복제 방법과 데이터 단위로 중복 저장하는 Peer-to-Peer 복제 방법이 있다.

</br>

### 3. 네트워크 분할 허용성(Partition tolerance)

분할 허용성이란 지역적으로 분할된 네트워크 환경에서 동작하는 시스템에서 두 지역 간의 네트워크가 단절되거나 네트워크 데이터의 유실이 일어나더라도 각 지역 내의 시스템은 정상적으로 동작해야 함을 의미한다.

</br>

### 저장 방식에 따른 NoSQL 분류

`Key-Value Model`, `Document Model`, `Column Model`, `Graph Model`로 분류할 수 있다.

### 1. Key-Value Model

가장 기본적인 형태의 NoSQL 이며 키 하나로 데이터 하나를 저장하고 조회할 수 있는 단일 키-값 구조를 갖는다. 단순한 저장구조로 인하여 복잡한 조회 연산을 지원하지 않는다. 또한 고속 읽기와 쓰기에 최적화된 경우가 많다. 사용자의 프로필 정보, 웹 서버 클러스터를 위한 세션 정보, 장바구니 정보, URL 단축 정보 저장 등에 사용한다. 하나의 서비스 요청에 다수의 데이터 조회 및 수정 연산이 발생하면 트랜잭션 처리가 불가능하여 데이터 정합성을 보장할 수 없다.
_ex) Redis_

### 2. Document Model

키-값 모델을 개념적으로 확장한 구조로 하나의 키에 하나의 구조화된 문서를 저장하고 조회한다. 논리적인 데이터 저장과 조회 방법이 관계형 데이터베이스와 유사하다. 키는 문서에 대한 ID 로 표현된다. 또한 저장된 문서를 컬렉션으로 관리하며 문서 저장과 동시에 문서 ID 에 대한 인덱스를 생성한다. 문서 ID 에 대한 인덱스를 사용하여 O(1) 시간 안에 문서를 조회할 수 있다.

대부분의 문서 모델 NoSQL 은 B 트리 인덱스를 사용하여 2 차 인덱스를 생성한다. B 트리는 크기가 커지면 커질수록 새로운 데이터를 입력하거나 삭제할 때 성능이 떨어지게 된다. 그렇기 때문에 읽기와 쓰기의 비율이 7:3 정도일 때 가장 좋은 성능을 보인다. 중앙 집중식 로그 저장, 타임라인 저장, 통계 정보 저장 등에 사용된다.
_ex) MongoDB_

### 3. Column Model

하나의 키에 여러 개의 컬럼 이름과 컬럼 값의 쌍으로 이루어진 데이터를 저장하고 조회한다. 모든 컬럼은 항상 타임 스탬프 값과 함께 저장된다.

구글의 빅테이블이 대표적인 예로 차후 컬럼형 NoSQL 은 빅테이블의 영향을 받았다. 이러한 이유로 Row key, Column Key, Column Family 같은 빅테이블 개념이 공통적으로 사용된다. 저장의 기본 단위는 컬럼으로 컬럼은 컬럼 이름과 컬럼 값, 타임스탬프로 구성된다. 이러한 컬럼들의 집합이 로우(Row)이며, 로우키(Row key)는 각 로우를 유일하게 식별하는 값이다. 이러한 로우들의 집합은 키 스페이스(Key Space)가 된다.

대부분의 컬럼 모델 NoSQL 은 쓰기와 읽기 중에 쓰기에 더 특화되어 있다. 데이터를 먼저 커밋로그와 메모리에 저장한 후 응답하기 때문에 빠른 응답속도를 제공한다. 그렇기 때문에 읽기 연산 대비 쓰기 연산이 많은 서비스나 빠른 시간 안에 대량의 데이터를 입력하고 조회하는 서비스를 구현할 때 가장 좋은 성능을 보인다. 채팅 내용 저장, 실시간 분석을 위한 데이터 저장소 등의 서비스 구현에 적합하다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-5-database)

</br>

</br>

_Database.end_


================================================
FILE: DesignPattern/README.md
================================================
# Part 1-6 Design Pattern

* [Singleton](#singleton)

[뒤로](https://github.com/JaeYeopHan/for_beginner)

</br>

## Singleton

### 필요성

`Singleton pattern(싱글턴 패턴)`이란 애플리케이션에서 인스턴스를 하나만 만들어 사용하기 위한 패턴이다. 커넥션 풀, 스레드 풀, 디바이스 설정 객체 등의 경우, 인스턴스를 여러 개 만들게 되면 자원을 낭비하게 되거나 버그를 발생시킬 수 있으므로 오직 하나만 생성하고 그 인스턴스를 사용하도록 하는 것이 이 패턴의 목적이다.

### 구현

하나의 인스턴스만을 유지하기 위해 인스턴스 생성에 특별한 제약을 걸어둬야 한다. new 를 실행할 수 없도록 생성자에 private 접근 제어자를 지정하고, 유일한 단일 객체를 반환할 수 있도록 정적 메소드를 지원해야 한다. 또한 유일한 단일 객체를 참조할 정적 참조변수가 필요하다.

```java
public class Singleton {
    private static Singleton singletonObject;

    private Singleton() {}

    public static Singleton getInstance() {
        if (singletonObject == null) {
            singletonObject = new Singleton();
        }
        return singletonObject;
    }
}
```

이 코드는 정말 위험하다. 멀티스레딩 환경에서 싱글턴 패턴을 적용하다보면 문제가 발생할 수 있다. 동시에 접근하다가 하나만 생성되어야 하는 인스턴스가 두 개 생성될 수 있는 것이다. 그렇게 때문에 `getInstance()` 메소드를 동기화시켜야 멀티스레드 환경에서의 문제가 해결된다.

```java
public class Singleton {
    private static Singleton singletonObject;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (singletonObject == null) {
            singletonObject = new Singleton();
        }
        return singletonObject;
    }
}
```

`synchronized` 키워드를 사용하게 되면 성능상에 문제점이 존재한다. 좀 더 효율적으로 제어할 수는 없을까?

```java
public class Singleton {
    private static volatile Singleton singletonObject;

    private Singleton() {}

    public static Singleton getInstance() {
        if (singletonObject == null) {
            synchronized (Singleton.class) {
                if(singletonObject == null) {
                    singletonObject = new Singleton();
                }
            }
        }
        return singletonObject;
    }
}
```

`DCL(Double Checking Locking)`을 써서 `getInstance()`에서 **동기화 되는 영역을 줄일 수 있다.** 초기에 객체를 생성하지 않으면서도 동기화하는 부분을 작게 만들었다. 그러나 이 코드는 **멀티코어 환경에서 동작할 때,** 하나의 CPU 를 제외하고는 다른 CPU 가 lock 이 걸리게 된다. 그렇기 때문에 다른 방법이 필요하다.

```java
public class Singleton {
    private static volatile Singleton singletonObject = new Singleton();

    private Singleton() {}

    public static Singleton getSingletonObject() {
        return singletonObject;
    }
}
```

클래스가 로딩되는 시점에 미리 객체를 생성해두고 그 객체를 반환한다.

_cf) `volatile` : 컴파일러가 특정 변수에 대해 옵티마이져가 캐싱을 적용하지 못하도록 하는 키워드이다._

#### Reference

* http://asfirstalways.tistory.com/335

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-6-design-pattern)

</br>

</br>

_Design pattern.end_


================================================
FILE: Development_common_sense/README.md
================================================
# Part 1-1 Development common sense

* [좋은 코드란 무엇인가](#좋은-코드란-무엇인가)
* [객체 지향 프로그래밍이란 무엇인가](#object-oriented-programming)
  * 객체 지향 개발 원칙은 무엇인가?
* [RESTful API 란](#restful-api)
* [TDD 란 무엇이며 어떠한 장점이 있는가](#tdd)
* [함수형 프로그래밍](#함수형-프로그래밍)
* [MVC 패턴이란 무엇인가?](http://asfirstalways.tistory.com/180)
* [Git 과 GitHub 에 대해서](#git-과-github-에-대해서)

[뒤로](https://github.com/JaeYeopHan/for_beginner)

</br>

## 좋은 코드란 무엇인가

‘좋은 코드란?‘이라고 구글링해보면 많은 검색 결과가 나온다. 나도 그렇고 다들 궁금했던듯하다. ‘좋은 코드’란 녀석은 정체도, 실체도 없이 이 세상에 떠돌고 있다. 모두가 ‘좋은 코드’의 기준이 조금씩 다르고 각각의 경험을 기반으로 좋은 코드를 정의하고 있다. 세간에 좋은 코드의 정의는 정말 많다.

- 읽기 쉬운 코드
- 중복이 없는 코드
- 테스트가 용이한 코드

등등… 더 읽어보기 > https://jbee.io/etc/what-is-good-code/

## Object Oriented Programming

_객체 지향 프로그래밍. 저도 잘 모르고 너무 거대한 부분이라서 넣을지 말지 많은 고민을 했습니다만, 면접에서 이 정도 이야기하면 되지 않을까?하는 생각에 조심스레 적어봤습니다._

객체 지향 프로그래밍 이전의 프로그래밍 패러다임을 살펴보면, 중심이 컴퓨터에 있었다. 컴퓨터가 사고하는대로 프로그래밍을 하는 것이다. 하지만 객체지향 프로그래밍이란 인간 중심적 프로그래밍 패러다임이라고 할 수 있다. 즉, 현실 세계를 프로그래밍으로 옮겨와 프로그래밍하는 것을 말한다. 현실 세계의 사물들을 객체라고 보고 그 객체로부터 개발하고자 하는 애플리케이션에 필요한 특징들을 뽑아와 프로그래밍 하는 것이다. 이것을 추상화라한다.

OOP 로 코드를 작성하면 이미 작성한 코드에 대한 재사용성이 높다. 자주 사용되는 로직을 라이브러리로 만들어두면 계속해서 사용할 수 있으며 그 신뢰성을 확보 할 수 있다. 또한 라이브러리를 각종 예외상황에 맞게 잘 만들어두면 개발자가 사소한 실수를 하더라도 그 에러를 컴파일 단계에서 잡아낼 수 있으므로 버그 발생이 줄어든다. 또한 내부적으로 어떻게 동작하는지 몰라도 개발자는 라이브러리가 제공하는 기능들을 사용할 수 있기 때문에 생산성이 높아지게 된다. 객체 단위로 코드가 나눠져 작성되기 때문에 디버깅이 쉽고 유지보수에 용이하다. 또한 데이터 모델링을 할 때 객체와 매핑하는 것이 수월하기 때문에 요구사항을 보다 명확하게 파악하여 프로그래밍 할 수 있다.

객체 간의 정보 교환이 모두 메시지 교환을 통해 일어나므로 실행 시스템에 많은 overhead 가 발생하게 된다. 하지만 이것은 하드웨어의 발전으로 많은 부분 보완되었다. 객체 지향 프로그래밍의 치명적인 단점은 함수형 프로그래밍 패러다임의 등장 배경을 통해서 알 수 있다. 바로 객체가 상태를 갖는다는 것이다. 변수가 존재하고 이 변수를 통해 객체가 예측할 수 없는 상태를 갖게 되어 애플리케이션 내부에서 버그를 발생시킨다는 것이다. 이러한 이유로 함수형 패러다임이 주목받고 있다.

### 객체 지향적 설계 원칙

1.  SRP(Single Responsibility Principle) : 단일 책임 원칙  
    클래스는 단 하나의 책임을 가져야 하며 클래스를 변경하는 이유는 단 하나의 이유이어야 한다.
2.  OCP(Open-Closed Principle) : 개방-폐쇄 원칙  
    확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다.
3.  LSP(Liskov Substitution Principle) : 리스코프 치환 원칙  
    상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다.
4.  ISP(Interface Segregation Principle) : 인터페이스 분리 원칙  
    인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다.
5.  DIP(Dependency Inversion Principle) : 의존 역전 원칙  
    고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다.

#### Reference

* [객체 지향에 대한 얕은 이해](http://asfirstalways.tistory.com/177)

#### Personal Recommendation

* (도서) [객체 지향의 사실과 오해](http://www.yes24.com/24/Goods/18249021)
* (도서) [객체 지향과 디자인 패턴](http://www.yes24.com/24/Goods/9179120?Acode=101)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-1-development-common-sense)

</br>

## RESTful API

우선, 위키백과의 정의를 요약해보자면 다음과 같다.

> 월드 와이드 웹(World Wide Web a.k.a WWW)과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식으로 자원을 정의하고 자원에 대한 주소를 지정하는 방법 전반에 대한 패턴

`REST`란, REpresentational State Transfer 의 약자이다. 여기에 ~ful 이라는 형용사형 어미를 붙여 ~한 API 라는 표현으로 사용된다. 즉, REST 의 기본 원칙을 성실히 지킨 서비스 디자인은 'RESTful'하다라고 표현할 수 있다.

`REST`가 디자인 패턴이다, 아키텍처다 많은 이야기가 존재하는데, 하나의 아키텍처로 볼 수 있다. 좀 더 정확한 표현으로 말하자면, REST 는 `Resource Oriented Architecture` 이다. API 설계의 중심에 자원(Resource)이 있고 HTTP Method 를 통해 자원을 처리하도록 설계하는 것이다.

### REST 6 가지 원칙

* Uniform Interface
* Stateless
* Caching
* Client-Server
* Hierarchical system
* Code on demand  
  _cf) 보다 자세한 내용에 대해서는 Reference 를 참고해주세요._

### RESTful 하게 API 를 디자인 한다는 것은 무엇을 의미하는가.(요약)

1.  **리소스** 와 **행위** 를 명시적이고 직관적으로 분리한다.

* 리소스는 `URI`로 표현되는데 리소스가 가리키는 것은 `명사`로 표현되어야 한다.
* 행위는 `HTTP Method`로 표현하고, `GET(조회)`, `POST(생성)`, `PUT(기존 entity 전체 수정)`, `PATCH(기존 entity 일부 수정)`, `DELETE(삭제)`을 분명한 목적으로 사용한다.

2.  Message 는 Header 와 Body 를 명확하게 분리해서 사용한다.

* Entity 에 대한 내용은 body 에 담는다.
* 애플리케이션 서버가 행동할 판단의 근거가 되는 컨트롤 정보인 API 버전 정보, 응답받고자 하는 MIME 타입 등은 header 에 담는다.
* header 와 body 는 http header 와 http body 로 나눌 수도 있고, http body 에 들어가는 json 구조로 분리할 수도 있다.

3.  API 버전을 관리한다.

* 환경은 항상 변하기 때문에 API 의 signature 가 변경될 수도 있음에 유의하자.
* 특정 API 를 변경할 때는 반드시 하위호환성을 보장해야 한다.

4.  서버와 클라이언트가 같은 방식을 사용해서 요청하도록 한다.

* 브라우저는 form-data 형식의 submit 으로 보내고 서버에서는 json 형태로 보내는 식의 분리보다는 json 으로 보내든, 둘 다 form-data 형식으로 보내든 하나로 통일한다.
* 다른 말로 표현하자면 URI 가 플랫폼 중립적이어야 한다.

### 어떠한 장점이 존재하는가?

1.  Open API 를 제공하기 쉽다
2.  멀티플랫폼 지원 및 연동이 용이하다.
3.  원하는 타입으로 데이터를 주고 받을 수 있다.
4.  기존 웹 인프라(HTTP)를 그대로 사용할 수 있다.

### 단점은 뭐가 있을까?

1.  사용할 수 있는 메소드가 한정적이다.
2.  분산환경에는 부적합하다.
3.  HTTP 통신 모델에 대해서만 지원한다.

위 내용은 간단히 요약된 내용이므로 보다 자세한 내용은 다음 Reference 를 참고하시면 됩니다 :)

##### Reference

* [우아한 테크톡 - REST-API](https://www.youtube.com/watch?v=Nxi8Ur89Akw)
* [REST API 제대로 알고 사용하기 - TOAST](http://meetup.toast.com/posts/92)
* [바쁜 개발자들을 위한 RESTFul api 논문 요약](https://blog.npcode.com/2017/03/02/%EB%B0%94%EC%81%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%93%A4%EC%9D%84-%EC%9C%84%ED%95%9C-rest-%EB%85%BC%EB%AC%B8-%EC%9A%94%EC%95%BD/)
* [REST 아키텍처를 훌륭하게 적용하기 위한 몇 가지 디자인 팁 - spoqa](https://spoqa.github.io/2012/02/27/rest-introduction.html)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-1-development-common-sense)

</br>

## TDD

### TDD 란 무엇인가

Test-Driven Development(TDD)는 매우 짧은 개발 사이클의 반복에 의존하는 소프트웨어 개발 프로세스이다. 우선 개발자는 요구되는 새로운 기능에 대한 자동화된 테스트케이스를 작성하고 해당 테스트를 통과하는 가장 간단한 코드를 작성한다. 일단 테스트 통과하는 코드를 작성하고 상황에 맞게 리팩토링하는 과정을 거치는 것이다. 말 그대로 테스트가 코드 작성을 주도하는 개발방식인 것이다.

### Add a test

테스트 주도형 개발에선, 새로운 기능을 추가하기 전 테스트를 먼저 작성한다. 테스트를 작성하기 위해서, 개발자는 해당 기능의 요구사항과 명세를 분명히 이해하고 있어야 한다. 이는 사용자 케이스와 사용자 스토리 등으로 이해할 수 있으며, 이는 개발자가 코드를 작성하기 전에 보다 요구사항에 집중할 수 있도록 도와준다. 이는 정말 중요한 부분이자 테스트 주도 개발이 주는 이점이라고 볼 수 있다.

### Run all tests and see if new one fails

어떤 새로운 기능을 추가하면 잘 작동하던 기능이 제대로 작동하지 않는 경우가 발생할 수 있다. 더 위험한 경우는 개발자가 이를 미처 인지하지 못하는 경우이다. 이러한 경우를 방지하기 위해 테스트 코드를 작성하는 것이다. 새로운 기능을 추가할 때 테스트 코드를 작성함으로써, 새로운 기능이 제대로 작동함과 동시에 기존의 기능들이 잘 작동하는지 테스트를 통해 확인할 수 있는 것이다.

### Refactor code

'좋은 코드'를 작성하기란 정말 쉽지가 않다. 코드를 작성할 때 고려해야 할 요소가 한 두 가지가 아니기 때문이다. 가독성이 좋게 coding convention 을 맞춰야 하며, 네이밍 규칙을 적용하여 메소드명, 변수명, 클래스명에 일관성을 줘야하며, 앞으로의 확장성 또한 고려해야 한다. 이와 동시에 비즈니스 로직에 대한 고려도 반드시 필요하며, 예외처리 부분 역시 빠뜨릴 수 없다. 물론 코드량이 적을 때는 이런 저런 것들을 모두 신경쓰면서 코드를 작성할 수 있지만 끊임없이 발견되는 버그들을 디버깅하는 과정에서 코드가 더럽혀지기 마련이다.

이러한 이유로 코드량이 방대해지면서 리팩토링을 하게 된다. 이 때 테스트 주도 개발을 통해 개발을 해왔다면, 테스트 코드가 그 중심을 잡아줄 수 있다. 뚱뚱해진 함수를 여러 함수로 나누는 과정에서 해당 기능이 오작동을 일으킬 수 있지만 간단히 테스트를 돌려봄으로써 이에 대한 안심을 하고 계속해서 리팩토링을 진행할 수 있다. 결과적으로 리팩토링 속도도 빨라지고 코드의 퀄리티도 그만큼 향상하게 되는 것이다. 코드 퀄리티 부분을 조금 상세히 들어가보면, 보다 객체지향적이고 확장 가능이 용이한 코드, 재설계의 시간을 단축시킬 수 있는 코드, 디버깅 시간이 단축되는 코드가 TDD 와 함께 탄생하는 것이다.

어차피 코드를 작성하고나서 제대로 작동하는지 판단해야하는 시점이 온다. 물론 중간 중간 수동으로 확인도 할 것이다. 또 테스트에 대한 부분에 대한 문서도 만들어야 한다. 그 부분을 자동으로 해주면서, 코드 작성에 도움을 주는 것이 TDD 인 것이다. 끊임없이 TDD 찬양에 대한 말만 했다. TDD 를 처음 들어보는 사람은 이 좋은 것을 왜 안하는가에 대한 의문이 들 수도 있다.

### 의문점들

#### Q. 코드 생산성에 문제가 있지는 않나?

두 배는 아니더라도 분명 코드량이 늘어난다. 비즈니스 로직, 각종 코드 디자인에도 시간이 많이 소요되는데, 거기에다가 테스트 코드까지 작성하기란 여간 벅찬 일이 아닐 것이다. 코드 퀄리티보다는 빠른 생산성이 요구되는 시점에서 TDD 는 큰 걸림돌이 될 수 있다.

#### Q. 테스트 코드를 작성하기가 쉬운가?

이 또한 TDD 라는 개발 방식을 적용하기에 큰 걸림돌이 된다. 진입 장벽이 존재한다는 것이다. 어떠한 부분을 테스트해야할 지, 어떻게 테스트해야할 지, 여러 테스트 프레임워크 중 어떤 것이 우리의 서비스와 맞는지 등 여러 부분들에 대한 학습이 필요하고 익숙해지는데에도 시간이 걸린다. 팀에서 한 명만 익숙해진다고 해결될 일이 아니다. 개발은 팀 단위로 수행되기 때문에 팀원 전체의 동의가 필요하고 팀원 전체가 익숙해져야 비로소 테스트 코드가 빛을 발하게 되는 것이다.

#### Q. 모든 상황에 대해서 테스트 코드를 작성할 수 있는가? 작성해야 하는가?

세상에는 다양한 사용자가 존재하며, 생각지도 못한 예외 케이스가 존재할 수 있다. 만약 테스트를 반드시 해봐야 하는 부분에 있어서 테스트 코드를 작성하는데 어려움이 발생한다면? 이러한 상황에서 주객이 전도하는 상황이 발생할 수 있다. 분명 실제 코드가 더 중심이 되어야 하는데 테스트를 위해서 코드의 구조를 바꿔야 하나하는 고민이 생긴다. 또한 발생할 수 있는 상황에 대한 테스트 코드를 작성하기 위해 배보다 배꼽이 더 커지는 경우가 허다하다. 실제 구현 코드보다 방대해진 코드를 관리하는 것도 쉽지만은 않은 일이 된 것이다.

모든 코드에 대해서 테스트 코드를 작성할 수 없으며 작성할 필요도 없다. 또한 테스트 코드를 작성한다고 해서 버그가 발생하지 않는 것도 아니다. 애초에 TDD 는 100% coverage 와 100% 무결성을 주장하지 않았다.

#### Personal Recommendation

* (도서) [켄트 벡 - 테스트 주도 개발](http://www.yes24.com/24/Goods/12246033)

##### Reference

* [TDD 에 대한 토론 - slipp](https://slipp.net/questions/16)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-1-development-common-sense)

</br>

## 함수형 프로그래밍

_아직 저도 잘 모르는 부분이라서 정말 간단한 내용만 정리하고 관련 링크를 첨부합니다._
함수형 프로그래밍의 가장 큰 특징 두 가지는 `immutable data`와 `first class citizen으로서의 function`이다.

### immutable vs mutable

우선 `immutable`과 `mutable`의 차이에 대해서 이해를 하고 있어야 한다. `immutable`이란 말 그대로 변경 불가능함을 의미한다. `immutable` 객체는 객체가 가지고 있는 값을 변경할 수 없는 객체를 의미하여 값이 변경될 경우, 새로운 객체를 생성하고 변경된 값을 주입하여 반환해야 한다. 이와는 달리, `mutable` 객체는 해당 객체의 값이 변경될 경우 값을 변경한다.

### first-class citizen

함수형 프로그래밍 패러다임을 따르고 있는 언어에서의 `함수(function)`는 `일급 객체(first class citizen)`로 간주된다. 일급 객체라 함은 다음과 같다.

* 변수나 데이터 구조안에 함수를 담을 수 있어서 함수의 파라미터로 전달할 수 있고, 함수의 반환값으로 사용할 수 있다.
* 할당에 사용된 이름과 관계없이 고유한 구별이 가능하다.
* 함수를 리터럴로 바로 정의할 수 있다.

### Reactive Programming

반응형 프로그래밍(Reactive Programming)은 선언형 프로그래밍(declarative programming)이라고도 불리며, 명령형 프로그래밍(imperative programming)의 반대말이다. 또 함수형 프로그래밍 패러다임을 활용하는 것을 말한다. 반응형 프로그래밍은 기본적으로 모든 것을 스트림(stream)으로 본다. 스트림이란 값들의 집합으로 볼 수 있으며 제공되는 함수형 메소드를 통해 데이터를 immutable 하게 관리할 수 있다.

#### Reference

* [함수형 프로그래밍 소개](https://medium.com/@jooyunghan/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%86%8C%EA%B0%9C-5998a3d66377)
* [반응형 프로그래밍이란 무엇인가](https://brunch.co.kr/@yudong/33)
* [What-I-Learned-About-RP](https://github.com/CoderK/What-I-Learned-About-RP)
* [Reactive Programming](http://sculove.github.io/blog/2016/06/22/Reactive-Programming)
* [MS 는 ReactiveX 를 왜 만들었을까?](http://huns.me/development/2051)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-1-development-common-sense)

</br>

## MVC 패턴이란 무엇인가?

그림과 함께 설명하는 것이 더 좋다고 판단하여 [포스팅](http://asfirstalways.tistory.com/180)으로 대체한다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-1-development-common-sense)

</br>

## Git 과 GitHub 에 대해서

Git 이란 VCS(Version Control System)에 대해서 기본적인 이해를 요구하고 있다.

* [Git 을 조금 더 알아보자 slide share](https://www.slideshare.net/ky200223/git-89251791)

Git 을 사용하기 위한 각종 전략(strategy)들이 존재한다. 해당 전략들에 대한 이해를 기반으로 Git 을 사용해야 하기 때문에 면접에서 자주 물어본다. 주로 사용되는 strategy 중심으로 질문이 들어오며 유명한 세 가지를 비교한 글을 첨부한다.

* [Gitflow vs GitHub flow vs GitLab flow](https://ujuc.github.io/2015/12/16/git-flow-github-flow-gitlab-flow/)

많은 회사들이 GitHub 을 기반으로 협업을 하게 되는데, (BitBucket 이라는 훌륭한 도구도 존재합니다.) GitHub 에서 어떤 일을 할 수 있는지, 어떻게 GitHub Repository 에 기여를 하는지 정리한 글을 첨부한다.

* [오픈소스 프로젝트에 컨트리뷰트 하기](http://guruble.com/%EC%98%A4%ED%94%88%EC%86%8C%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%9D%98-%EC%BB%A8%ED%8A%B8%EB%A6%AC%EB%B7%B0%ED%84%B0%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%90%98%EB%8A%94-%EA%B2%83/)
* [GitHub Cheetsheet](https://github.com/tiimgreen/github-cheat-sheet)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-1-development-common-sense)

</br>

</br>

_Development_common_sense.end_


================================================
FILE: FrontEnd/README.md
================================================
# Part 3-1 Front-End

* [브라우저의 동작 원리](#브라우저의-동작-원리)
* [Document Object Model](#Document-Object-Model)
* [CORS](#cors)
* [크로스 브라우징](#크로스-브라우징)
* [웹 성능과 관련된 Issues](#웹-성능과-관련된-issue-정리)
* [서버 사이드 렌더링 vs 클라이언트 사이드 렌더링](#서버-사이드-렌더링-vs-클라이언트-사이드-렌더링)
* [CSS Methodology](#css-methodology)
* [normalize.css vs reset.css](#normalize-vs-reset)
* [그 외 프론트엔드 개발 환경 관련](#그-외-프론트엔드-개발-환경-관련)

[뒤로](https://github.com/JaeYeopHan/for_beginner)

## 브라우저의 동작 원리

브라우저의 동작 원리는 Critical Rendering Path(CRP)라고도 불립니다.
아래는 브라우저가 서버로부터 HTML 응답을 받아 화면을 그리기 위해 실행하는 과정입니다.
1.  HTML 마크업을 처리하고 DOM 트리를 빌드한다. (**"무엇을"** 그릴지 결정한다.)
2.  CSS 마크업을 처리하고 CSSOM 트리를 빌드한다. (**"어떻게"** 그릴지 결정한다.)
3.  DOM 및 CSSOM 을 결합하여 렌더링 트리를 형성한다. (**"화면에 그려질 것만"** 결정)
4.  렌더링 트리에서 레이아웃을 실행하여 각 노드의 기하학적 형태를 계산한다. (**"Box-Model"** 을 생성한다.)
5.  개별 노드를 화면에 페인트한다.(or 래스터화)

#### Reference

* [Naver D2 - 브라우저의 작동 원리](http://d2.naver.com/helloworld/59361)
* [Web fundamentals - Critical-rendering-path](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/?hl=ko)
* [브라우저의 Critical path (한글)](http://m.post.naver.com/viewer/postView.nhn?volumeNo=8431285&memberNo=34176766)
* [What is critical rendering path?](https://www.frontendinterviewquestions.com/interview-questions/what-is-critical-rendering-path)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-3-1-front-end)

</br>

## Document Object Model

웹에서는 수많은 이벤트(Event)가 발생하고 흐른다.

- 브라우저(user agent)로부터 발생하는 이벤트
- 사용자의 행동(interaction)에 의해 발생하는 이벤트
- DOM의 ‘변화’로 인해 발생하는 이벤트

발생하는 이벤트는 그저 자바스크립트 객체일 뿐이다. 브라우저의 Event interface에 맞춰 구현된 객체인 것이다.

여러 DOM Element로 구성된 하나의 웹 페이지는 Window를 최상위로 하는 트리를 생성하게 된다. 결론부터 말하자면 이벤트는 이벤트 각각이 갖게 되는 전파 경로(propagation path)를 따라 전파된다. 그리고 이 전파 경로는 DOM Tree 구조에서 Element의 위상(hierarchy)에 의해 결정이 된다.

### Reference

- [스펙 살펴보기: Document Object Model Event](https://www.jbee.io/articles/web/%EC%8A%A4%ED%8E%99%20%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0:%20Document%20Object%20Model%20Event)

## CORS

다른 도메인으로부터 리소스가 요청될 경우 해당 리소스는 **cross-origin HTTP 요청** 에 의해 요청된다. 하지만 대부분의 브라우저들은 보안 상의 이유로 스크립트에서의 cross-origin HTTP 요청을 제한한다. 이것을 `Same-Origin-Policy(동일 근원 정책)`이라고 한다. 요청을 보내기 위해서는 요청을 보내고자 하는 대상과 프로토콜도 같아야 하고, 포트도 같아야 함을 의미한다.

이러한 문제를 해결하기 위해 과거에는 flash 를 proxy 로 두고 타 도메인간 통신을 했다. 하지만 모바일 운영체제의 등장으로 flash 로는 힘들어졌다. (iOS 는 전혀 플래시를 지원하지 않는다.) 대체제로 나온 기술이 `JSONP(JSON-padding)`이다. jQuery v.1.2 이상부터 `jsonp`형태가 지원되 ajax 를 호출할 때 타 도메인간 호출이 가능해졌다. `JSONP`에는 타 도메인간 자원을 공유할 수 있는 몇 가지 태그가 존재한다. 예를들어 `img`, `iframe`, `anchor`, `script`, `link` 등이 존재한다.

여기서 `CORS`는 타 도메인 간에 자원을 공유할 수 있게 해주는 것이다. `Cross-Origin Resource Sharing` 표준은 웹 브라우저가 사용하는 정보를 읽을 수 있도록 허가된 **출처 집합**을 서버에게 알려주도록 허용하는 특정 HTTP 헤더를 추가함으로써 동작한다.

|           HTTP Header            |          Description           |
| :------------------------------: | :----------------------------: |
|   Access-Control-Allow-Origin    |     접근 가능한 `url` 설정     |
| Access-Control-Allow-Credentials |    접근 가능한 `쿠키` 설정     |
|   Access-Control-Allow-Headers   |    접근 가능한 `헤더` 설정     |
|   Access-Control-Allow-Methods   | 접근 가능한 `http method` 설정 |

### Preflight Request

실제 요청을 보내도 안전한지 판단하기 위해 preflight 요청을 먼저 보내는 방법을 말한다. 즉, `Preflight Request`는 실제 요청 전에 인증 헤더를 전송하여 서버의 허용 여부를 미리 체크하는 테스트 요청이다. 이 요청으로 트래픽이 증가할 수 있는데 서버의 헤더 설정으로 캐쉬가 가능하다. 서버 측에서는 브라우저가 해당 도메인에서 CORS 를 허용하는지 알아보기 위해 preflight 요청을 보내는데 이에 대한 처리가 필요하다. preflight 요청은 HTTP 의 `OPTIONS` 메서드를 사용하며 `Access-Control-Request-*` 형태의 헤더로 전송한다.

이는 브라우저가 강제하며 HTTP `OPTION` 요청 메서드를 이용해 서버로부터 지원 중인 메서드들을 내려 받은 뒤, 서버에서 `approval(승인)` 시에 실제 HTTP 요청 메서드를 이용해 실제 요청을 전송하는 것이다.

#### Reference

* [MDN - HTTP 접근 제어 CORS](https://developer.mozilla.org/ko/docs/Web/HTTP/Access_control_CORS)
* [Cross-Origin-Resource-Sharing 에 대해서](http://homoefficio.github.io/2015/07/21/Cross-Origin-Resource-Sharing/)
* [구루비 - CORS 에 대해서](http://wiki.gurubee.net/display/SWDEV/CORS+%28Cross-Origin+Resource+Sharing%29)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-3-1-front-end)

</br>

## 크로스 브라우징

웹 표준에 따라 개발을 하여 서로 다른 OS 또는 플랫폼에 대응하는 것을 말한다. 즉, 브라우저의 렌더링 엔진이 다른 경우에 인터넷이 이상없이 구현되도록 하는 기술이다. 웹 사이트를 서로 비슷하게 만들어 어떤 **환경** 에서도 이상없이 작동되게 하는데 그 목적이 있다. 즉, 어느 한쪽에 최적화되어 치우치지 않도록 공통요소를 사용하여 웹 페이지를 제작하는 방법을 말한다.

### 참고자료

* [크로스 브라우징 이슈에 대응하는 프론트엔드 개발자들의 전략](http://asfirstalways.tistory.com/237)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-3-1-front-end)

</br>

## 웹 성능과 관련된 Issue 정리

### 1. 네트워크 요청에 빠르게 응답하자

* `3.xx` 리다이렉트를 피할 것
* `meta-refresh` 사용금지
* `CDN(content delivery network)`을 사용할 것
* 동시 커넥션 수를 최소화 할 것
* 커넥션을 재활용할 것

### 2. 자원을 최소한의 크기로 내려받자

* 777K
* `gzip` 압축을 사용할 것
* `HTML5 App cache`를 활용할 것
* 자원을 캐시 가능하게 할 것
* 조건 요청을 보낼 것

### 3. 효율적인 마크업 구조를 구축하자

* 레거시 IE 모드는 http 헤더를 사용할 것
* @import 의 사용을 피할 것
* inline 스타일과 embedded 스타일은 피할 것
* 사용하는 스타일만 CSS 에 포함할 것
* 중복되는 코드를 최소화 할 것
* 단일 프레임워크를 사용할 것
* Third Party 스크립트를 삽입하지 말 것

### 4. 미디어 사용을 개선하자

* 이미지 스프라이트를 사용할 것 ( 하나의 이미지로 편집해서 요청을 한번만 보낸다의 의미인가? )
* 실제 이미지 해상도를 사용할 것
* CSS3 를 활용할 것
* 하나의 작은 크기의 이미지는 DataURL 을 사용할 것
* 비디오의 미리보기 이미지를 만들 것

### 5. 빠른 자바스크립트 코드를 작성하자

* 코드를 최소화할 것
* 필요할 때만 스크립트를 가져올 것 : flag 사용
* DOM 에 대한 접근을 최소화 할 것 : Dom manipulate 는 느리다.
* 다수의 엘리먼트를 찾을 때는 selector api 를 사용할 것.
* 마크업의 변경은 한번에 할 것 : temp 변수를 활용
* DOM 의 크기를 작게 유지할 것.
* 내장 JSON 메서드를 사용할 것.

### 6. 애플리케이션의 작동원리를 알고 있자.

* Timer 사용에 유의할 것.
* `requestAnimationFrame` 을 사용할 것
* 활성화될 때를 알고 있을 것

#### Reference

* [HTML5 앱과 웹사이트를 보다 빠르게 하는 50 가지 - yongwoo Jeon](https://www.slideshare.net/mixed/html5-50)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-3-1-front-end)

</br>

## 서버 사이드 렌더링 vs 클라이언트 사이드 렌더링

* 그림과 함께 설명하기 위해 일단 블로그 링크를 추가한다.
* http://asfirstalways.tistory.com/244

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-3-1-front-end)

</br>

## CSS Methodology

`SMACSS`, `OOCSS`, `BEM`에 대해서 소개한다.

### SMACSS(Scalable and Modular Architecture for CSS)

`SMACSS`의 핵심은 범주화이며(`categorization`) 스타일을 다섯 가지 유형으로 분류하고, 각 유형에 맞는 선택자(selector)와 작명법(naming convention)을 제시한다.

* 기초(Base)
  * element 스타일의 default 값을 지정해주는 것이다. 선택자로는 요소 선택자를 사용한다.
* 레이아웃(Layout)
  * 구성하고자 하는 페이지를 컴포넌트를 나누고 어떻게 위치해야하는지를 결정한다. `id`는 CSS 에서 클래스와 성능 차이가 없는데, CSS 에서 사용하게 되면 재사용성이 떨어지기 때문에 클래스를 주로 사용한다.
* 모듈(Module)
  * 레이아웃 요소 안에 들어가는 더 작은 부분들에 대한 스타일을 정의한다. 클래스 선택자를 사용하며 요소 선택자는 가급적 피한다. 클래스 이름은 적용되는 스타일의 내용을 담는다.
* 상태(States)
  * 다른 스타일에 덧붙이거나 덮어씌워서 상태를 나타낸다. 그렇기 때문에 자바스크립트에 의존하는 스타일이 된다. `is-` prefix 를 붙여 상태를 제어하는 스타일임을 나타낸다. 특정 모듈에 한정된 상태는 모듈 이름도 이름에 포함시킨다.
* 테마(Theme)
  * 테마는 프로젝트에서 잘 사용되지 않는 카테고리이다. 사용자의 설정에 따라서 css 를 변경할 수 있는 css 를 설정할 때 사용하게 되며 접두어로는 `theme-`를 붙여 표시한다.

</br>

### OOCSS(Object Oriented CSS)

객체지향 CSS 방법론으로 2 가지 기본원칙을 갖고 있다.

* 원칙 1. 구조와 모양을 분리한다.
  * 반복적인 시각적 기능을 별도의 스킨으로 정의하여 다양한 객체와 혼합해 중복코드를 없앤다.
* 원칙 2. 컨테이너와 컨텐츠를 분리한다.
  * 스타일을 정의할 때 위치에 의존적인 스타일을 사용하지 않는다. 사물의 모양은 어디에 위치하든지 동일하게 보여야 한다.

</br>

### BEM(Block Element Modifier)

웹 페이지를 각각의 컴포넌트의 조합으로 바라보고 접근한 방법론이자 규칙(Rule)이다. SMACSS 가 가이드라인이라는 것에 비해서 좀 더 범위가 좁은 반면 강제성 측면에서 다소 강하다고 볼 수 있다. BEM 은 CSS 로 스타일을 입힐 때 id 를 사용하는 것을 막는다. 또한 요소 셀렉터를 통해서 직접 스타일을 적용하는 것도 불허한다. 하나를 더 불허하는데 그것은 바로 자손 선택자 사용이다. 이러한 규칙들은 재사용성을 높이기 위함이다.

* Naming Convention
  * 소문자와 숫자만을 이용해 작명하고 여러 단어의 조합은 하이픈(`-`)과 언더바(`_`)를 사용하여 연결한다.
* BEM 의 B 는 “Block”이다.
  * 블록(block)이란 재사용 할 수 있는 독립적인 페이지 구성 요소를 말하며, HTML 에서 블록은 class 로 표시된다. 블록은 주변 환경에 영향을 받지 않아야 하며, 여백이나 위치를 설정하면 안된다.
* BEM 의 E 는 “Element”이다.
  * 블록 안에서 특정 기능을 담당하는 부분으로 block_element 형태로 사용한다. 요소는 중첩해서 작성될 수 있다.
* BEM 의 M 는 “Modifier”이다.
  * 블록이나 요소의 모양, 상태를 정의한다. `block_element-modifier`, `block—modifier` 형태로 사용한다. 수식어에는 불리언 타입과 키-값 타입이 있다.

</br>

#### Reference

* [CSS 방법론에 대해서](http://wit.nts-corp.com/2015/04/16/3538)
* [CSS 방법론 SMACSS 에 대해 알아보자](https://brunch.co.kr/@larklark/1)
* [BEM 에 대해서](https://en.bem.info/)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-3-1-front-end)

</br>

## normalize vs reset

브라우저마다 기본적으로 제공하는 element 의 style 을 통일시키기 위해 사용하는 두 `css`에 대해 알아본다.

### reset.css

`reset.css`는 기본적으로 제공되는 브라우저 스타일 전부를 **제거** 하기 위해 사용된다. `reset.css`가 적용되면 `<H1>~<H6>`, `<p>`, `<strong>`, `<em>` 등 과 같은 표준 요소는 완전히 똑같이 보이며 브라우저가 제공하는 기본적인 styling 이 전혀 없다.

### normalize.css

`normalize.css`는 브라우저 간 일관된 스타일링을 목표로 한다. `<H1>~<H6>`과 같은 요소는 브라우저간에 일관된 방식으로 굵게 표시됩니다. 추가적인 디자인에 필요한 style 만 CSS 로 작성해주면 된다.

즉, `normalize.css`는 모든 것을 "해제"하기보다는 유용한 기본값을 보존하는 것이다. 예를 들어, sup 또는 sub 와 같은 요소는 `normalize.css`가 적용된 후 바로 기대하는 스타일을 보여준다. 반면 `reset.css`를 포함하면 시각적으로 일반 텍스트와 구별 할 수 없다. 또한 normalize.css 는 reset.css 보다 넓은 범위를 가지고 있으며 HTML5 요소의 표시 설정, 양식 요소의 글꼴 상속 부족, pre-font 크기 렌더링 수정, IE9 의 SVG 오버플로 및 iOS 의 버튼 스타일링 버그 등에 대한 이슈를 해결해준다.

### 그 외 프론트엔드 개발 환경 관련

- 웹팩(webpack)이란?
  - 웹팩은 자바스크립트 애플리케이션을 위한 모듈 번들러입니다. 웹팩은 의존성을 관리하고, 여러 파일을 하나의 번들로 묶어주며, 코드를 최적화하고 압축하는 기능을 제공합니다.
  - https://joshua1988.github.io/webpack-guide/webpack/what-is-webpack.html#%EC%9B%B9%ED%8C%A9%EC%9D%B4%EB%9E%80
- 바벨과 폴리필이란?

  - 바벨(Babel)은 자바스크립트 코드를 변환해주는 트랜스 컴파일러입니다. 최신 자바스크립트 문법으로 작성된 코드를 예전 버전의 자바스크립트 문법으로 변환하여 호환성을 높이는 역할을 합니다.

    이 변환과정에서 브라우저별로 지원하는 기능을 체크하고 해당 기능을 대체하는 폴리필을 제공하여 이를 통해 크로스 브라우징 이슈도 어느정도 해결할 수 있습니다.

  - 폴리필(polyfill)은 현재 브라우저에서 지원하지 않는 최신기능이나 API를 구현하여, 오래된 브라우저에서도 해당 기능을 사용할 수 있도록 해주는 코드조각입니다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-3-1-front-end)

</br>

</br>

_Front-End.end_


================================================
FILE: Java/README.md
================================================
# Part 2-1 Java

- [Part 2-1 Java](#part-2-1-java)
  - [JVM 에 대해서, GC 의 원리](#jvm-%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-gc-%EC%9D%98-%EC%9B%90%EB%A6%AC)
  - [Collection](#collection)
  - [Annotation](#annotation)
      - [Reference](#reference)
  - [Generic](#generic)
  - [final keyword](#final-keyword)
  - [Overriding vs Overloading](#overriding-vs-overloading)
  - [Access Modifier](#access-modifier)
  - [Wrapper class](#wrapper-class)
    - [AutoBoxing](#autoboxing)
  - [Multi-Thread 환경에서의 개발](#multi-thread-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C%EC%9D%98-%EA%B0%9C%EB%B0%9C)
    - [Field member](#field-member)
    - [동기화(Synchronized)](#%EB%8F%99%EA%B8%B0%ED%99%94synchronized)
    - [ThreadLocal](#threadlocal)
      - [Personal Recommendation](#personal-recommendation)

[뒤로](https://github.com/JaeYeopHan/for_beginner)

</br>

## JVM 에 대해서, GC 의 원리

그림과 함께 설명해야 하는 부분이 많아 링크를 첨부합니다.

* [Java Virtual Machine 에 대해서](http://asfirstalways.tistory.com/158)
* [Garbage Collection 에 대해서](http://asfirstalways.tistory.com/159)
* [Java Garbage Collection - 네이버 D2](https://d2.naver.com/helloworld/1329)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-1-java)

</br>

## Collection

Java Collection 에는 `List`, `Map`, `Set` 인터페이스를 기준으로 여러 구현체가 존재한다. 이에 더해 `Stack`과 `Queue` 인터페이스도 존재한다. 왜 이러한 Collection 을 사용하는 것일까? 그 이유는 다수의 Data 를 다루는데 표준화된 클래스들을 제공해주기 때문에 DataStructure 를 직접 구현하지 않고 편하게 사용할 수 있기 때문이다. 또한 배열과 다르게 객체를 보관하기 위한 공간을 미리 정하지 않아도 되므로, 상황에 따라 객체의 수를 동적으로 정할 수 있다. 이는 프로그램의 공간적인 효율성 또한 높여준다.

* List  
  `List` 인터페이스를 직접 `@Override`를 통해 사용자가 정의하여 사용할 수도 있으며, 대표적인 구현체로는 `ArrayList`가 존재한다. 이는 기존에 있었던 `Vector`를 개선한 것이다. 이외에도 `LinkedList` 등의 구현체가 있다.
* Map  
  대표적인 구현체로 `HashMap`이 존재한다. (밑에서 살펴볼 멀티스레드 환경에서의 개발 부분에서 HashTable 과의 차이점에 대해 살펴본다.) key-value 의 구조로 이루어져 있으며 Map 에 대한 구체적인 내용은 DataStructure 부분의 hashtable 과 일치한다. key 를 기준으로 중복된 값을 저장하지 않으며 순서를 보장하지 않는다. key 에 대해서 순서를 보장하기 위해서는 `LinkedHashMap`을 사용한다.
* Set  
  대표적인 구현체로 `HashSet`이 존재한다. `value`에 대해서 중복된 값을 저장하지 않는다. 사실 Set 자료구조는 Map 의 key-value 구조에서 key 대신에 value 가 들어가 value 를 key 로 하는 자료구조일 뿐이다. 마찬가지로 순서를 보장하지 않으며 순서를 보장해주기 위해서는 `LinkedHashSet`을 사용한다.
* Stack 과 Queue  
  `Stack` 객체는 직접 `new` 키워드로 사용할 수 있으며, `Queue` 인터페이스는 JDK 1.5 부터 `LinkedList`에 `new` 키워드를 적용하여 사용할 수 있다. 자세한 부분은 DataStructure 부분의 설명을 참고하면 된다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-1-java)

</br>

## Annotation

어노테이션이란 본래 주석이란 뜻으로, 인터페이스를 기반으로 한 문법이다. 주석과는 그 역할이 다르지만 주석처럼 코드에 달아 클래스에 특별한 의미를 부여하거나 기능을 주입할 수 있다. 또 해석되는 시점을 정할 수도 있다.(Retention Policy) 어노테이션에는 크게 세 가지 종류가 존재한다. JDK 에 내장되어 있는 `built-in annotation`과 어노테이션에 대한 정보를 나타내기 위한 어노테이션인 `Meta annotation` 그리고 개발자가 직접 만들어 내는 `Custom Annotation`이 있다. built-in annotation 은 상속받아서 메소드를 오버라이드 할 때 나타나는 @Override 어노테이션이 그 대표적인 예이다. 어노테이션의 동작 대상을 결정하는 Meta-Annotation 에도 여러 가지가 존재한다.

#### Reference

* http://asfirstalways.tistory.com/309

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-1-java)

</br>

## Generic

제네릭은 자바에서 안정성을 맡고 있다고 할 수 있다. 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에서 사용하는 것으로, 컴파일 과정에서 타입체크를 해주는 기능이다. 객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안전성을 높이고 형변환의 번거로움을 줄여준다. 자연스럽게 코드도 더 간결해진다. 예를 들면, Collection 에 특정 객체만 추가될 수 있도록, 또는 특정한 클래스의 특징을 갖고 있는 경우에만 추가될 수 있도록 하는 것이 제네릭이다. 이로 인한 장점은 collection 내부에서 들어온 값이 내가 원하는 값인지 별도의 로직처리를 구현할 필요가 없어진다. 또한 api 를 설계하는데 있어서 보다 명확한 의사전달이 가능해진다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-1-java)

</br>

## final keyword

* final class  
  다른 클래스에서 상속하지 못한다.

* final method  
  다른 메소드에서 오버라이딩하지 못한다.

* final variable  
  변하지 않는 상수값이 되어 새로 할당할 수 없는 변수가 된다.

추가적으로 혼동할 수 있는 두 가지를 추가해봤다.

* finally  
  `try-catch` or `try-catch-resource` 구문을 사용할 때, 정상적으로 작업을 한 경우와 에러가 발생했을 경우를 포함하여 마무리 해줘야하는 작업이 존재하는 경우에 해당하는 코드를 작성해주는 코드 블록이다.

* finalize()  
  keyword 도 아니고 code block 도 아닌 메소드이다. `GC`에 의해 호출되는 함수로 절대 호출해서는 안 되는 함수이다. `Object` 클래스에 정의되어 있으며 GC 가 발생하는 시점이 불분명하기 때문에 해당 메소드가 실행된다는 보장이 없다. 또한 `finalize()` 메소드가 오버라이딩 되어 있으면 GC 가 이루어질 때 바로 Garbage Collecting 되지 않는다. GC 가 지연되면서 OOME(Out of Memory Exception)이 발생할 수 있다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-1-java)

</br>

## Overriding vs Overloading

둘 다 다형성을 높여주는 개념이고 비슷한 이름이지만, 전혀 다른 개념이라고 봐도 무방할 만큼 차이가 있다(오버로딩은 다른 시그니쳐를 만든다는 관점에서 다형성으로 보지 않는 의견도 있다). 공통점으로는 같은 이름의 다른 함수를 호출한다는 것이다. 

* 오버라이딩(Overriding)  
  상위 클래스 혹은 인터페이스에 존재하는 메소드를 하위 클래스에서 필요에 맞게 재정의하는 것을 의미한다. 자바의 경우는 오버라이딩 시 동적바인딩된다.

  예)<br>
  아래와 같은 경우, SuperClass의 fun이라는 인터페이스를 통해 SubClass의 fun이 실행된다.
  ```java
  SuperClass object = new SubClass();
  object.fun();
  ```

* 오버로딩(Overloading)
  메소드의 이름은 같다. return 타입은 동일하거나 다를 수 있지만, return 타입만 다를 수는 없다. 매개변수의 타입이나 갯수가 다른 메소드를 만드는 것을 의미한다. 다양한 상황에서 메소드가 호출될 수 있도록 한다. 언어마다 다르지만, 자바의경우 오버로딩은 다른 시그니쳐를 만드는 것으로, 아예 다른함수를 만든것과 비슷하다고 생각하면 된다. 시그니쳐가 다르므로 정적바인딩으로 처리 가능하며, 자바의 경우 정적으로 바인딩된다.

  예)<br>
  아래와 같은 경우,fun(SuperClass super)이 실행된다.
  ```java
  main(blabla) {
    SuperClass object = new SubClass();
    fun(object);
  }
  
  fun(SuperClass super) {
    blabla....
  }

  fun(SubClass sub) {
    blabla....
  }
  ```

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-1-java)

</br>

## Access Modifier

변수 또는 메소드의 접근 범위를 설정해주기 위해서 사용하는 Java 의 예약어를 의미하며 총 네 가지 종류가 존재한다.

* public  
  어떤 클래스에서라도 접근이 가능하다.

* protected  
  클래스가 정의되어 있는 해당 패키지 내 그리고 해당 클래스를 상속받은 외부 패키지의 클래스에서 접근이 가능하다.

* (default)  
  클래스가 정의되어 있는 해당 패키지 내에서만 접근이 가능하도록 접근 범위를 제한한다.

* private  
  정의된 해당 클래스에서만 접근이 가능하도록 접근 범위를 제한한다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-1-java)

</br>

## Wrapper class

기본 자료형(Primitive data type)에 대한 클래스 표현을 Wrapper class 라고 한다. `Integer`, `Float`, `Boolean` 등이 Wrapper class 의 예이다. int 를 Integer 라는 객체로 감싸서 저장해야 하는 이유가 있을까? 일단 컬렉션에서 제네릭을 사용하기 위해서는 Wrapper class 를 사용해줘야 한다. 또한 `null` 값을 반환해야만 하는 경우에는 return type 을 Wrapper class 로 지정하여 `null`을 반환하도록 할 수 있다. 하지만 이러한 상황을 제외하고 일반적인 상황에서 Wrapper class 를 사용해야 하는 이유는 객체지향적인 프로그래밍을 위한 프로그래밍이 아니고서야 없다. 일단 해당 값을 비교할 때, Primitive data type 인 경우에는 `==`로 바로 비교해줄 수 있다. 하지만 Wrapper class 인 경우에는 `.intValue()` 메소드를 통해 해당 Wrapper class 의 값을 가져와 비교해줘야 한다.

### AutoBoxing

JDK 1.5 부터는 `AutoBoxing`과 `AutoUnBoxing`을 제공한다. 이 기능은 각 Wrapper class 에 상응하는 Primitive data type 일 경우에만 가능하다.

```java
List<Integer> lists = new ArrayList<>();
lists.add(1);
```

우린 `Integer`라는 Wrapper class 로 설정한 collection 에 데이터를 add 할 때 Integer 객체로 감싸서 넣지 않는다. 자바 내부에서 `AutoBoxing`해주기 때문이다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-1-java)

</br>

## Multi-Thread 환경에서의 개발

개발을 시작하는 입장에서 멀티 스레드를 고려한 프로그램을 작성할 일이 별로 없고 실제로 부딪히기 힘든 문제이기 때문에 많은 입문자들이 잘 모르고 있는 부분 중 하나라고 생각한다. 하지만 이 부분은 정말 중요하며 고려하지 않았을 경우 엄청난 버그를 양산할 수 있기 때문에 정말 중요하다.

### Field member

`필드(field)`란 클래스에 변수를 정의하는 공간을 의미한다. 이곳에 변수를 만들어두면 메소드 끼리 변수를 주고 받는 데 있어서 참조하기 쉬우므로 정말 편리한 공간 중 하나이다. 하지만 객체가 여러 스레드가 접근하는 싱글톤 객체라면 field 에서 상태값을 갖고 있으면 안된다. 모든 변수를 parameter 로 넘겨받고 return 하는 방식으로 코드를 구성해야 한다.

</br>

### 동기화(Synchronized)

`synchronized` 키워드를 직접 사용해서 특정 메소드나 구간에 Lock을 걸어 스레드 간 상호 배제를 구현할 수 있는 이 때 메서드에 직접 걸 수 도 있으며 블록으로 구간을 직접 지정해줄 수 있다.
메서드에 직접 걸어줄 경우에는 해당 class 인스턴스에 대해 Lock을 걸고 synchronized 블록을 이용할 경우에는 블록으로 감싸진 구간만 Lock이 걸린다. 때문에 Lock을 걸 때에는
이 개념에 대해 충분히 고민해보고 적절하게 사용해야만 한다.

그렇다면 필드에 Collection 이 불가피하게 필요할 때는 어떠한 방법을 사용할까? `synchronized` 키워드를 기반으로 구현된 Collection 들도 많이 존재한다. `List`를 대신하여 `Vector`를 사용할 수 있고, `Map`을 대신하여 `HashTable`을 사용할 수 있다. 하지만 이 Collection 들은 제공하는 API 가 적고 성능도 좋지 않다.

기본적으로는 `Collections`라는 util 클래스에서 제공되는 static 메소드를 통해 이를 해결할 수 있다. `Collections.synchronizedList()`, `Collections.synchronizedSet()`, `Collections.synchronizedMap()` 등이 존재한다.
JDK 1.7 부터는 `concurrent package`를 통해 `ConcurrentHashMap`이라는 구현체를 제공한다. Collections util 을 사용하는 것보다 `synchronized` 키워드가 적용된 범위가 좁아서 보다 좋은 성능을 낼 수 있는 자료구조이다.

</br>

### ThreadLocal

스레드 사이에 간섭이 없어야 하는 데이터에 사용한다. 멀티스레드 환경에서는 클래스의 필드에 멤버를 추가할 수 없고 매개변수로 넘겨받아야 하기 때문이다. 즉, 스레드 내부의 싱글톤을 사용하기 위해 사용한다. 주로 사용자 인증, 세션 정보, 트랜잭션 컨텍스트에 사용한다.

스레드 풀 환경에서 ThreadLocal 을 사용하는 경우 ThreadLocal 변수에 보관된 데이터의 사용이 끝나면 반드시 해당 데이터를 삭제해 주어야 한다. 그렇지 않을 경우 재사용되는 쓰레드가 올바르지 않은 데이터를 참조할 수 있다.

_ThreadLocal 을 사용하는 방법은 간단하다._

1.  ThreadLocal 객체를 생성한다.
2.  ThreadLocal.set() 메서드를 이용해서 현재 스레드의 로컬 변수에 값을 저장한다.
3.  ThreadLocal.get() 메서드를 이용해서 현재 스레드의 로컬 변수 값을 읽어온다.
4.  ThreadLocal.remove() 메서드를 이용해서 현재 스레드의 로컬 변수 값을 삭제한다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-1-java)

</br>

#### Personal Recommendation

* (도서) [Effective Java 2nd Edition](http://www.yes24.com/24/goods/14283616?scode=032&OzSrank=9)
* (도서) [스프링 입문을 위한 자바 객체 지향의 원리와 이해](http://www.yes24.com/24/Goods/17350624?Acode=101)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-1-java)

</br>

</br>

_Java.end_


================================================
FILE: JavaScript/README.md
================================================
# Part 2-2 JavaScript

* [JavaScript Event Loop](#javascript-event-loop)
* [Hoisting](#hoisting)
* [Closure](#closure)
* [this 에 대해서](#this-에-대해서)
* [Promise](#promise)
* [Arrow Function](#arrow-function)

[뒤로](https://github.com/JaeYeopHan/for_beginner)

## JavaScript Event Loop

그림과 함께 설명을 하면 좀 더 이해가 쉬울 것 같아 따로 정리한 포스팅으로 대체합니다.

* [JavaScript 이벤트 루프에 대해서](http://asfirstalways.tistory.com/362)
* [자바스크립트의 비동기 처리 과정](http://sculove.github.io/blog/2018/01/18/javascriptflow/)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-2-javascript)

</br>

## Hoisting

_ES6 문법이 표준화가 되면서 크게 신경쓰지 않아도 되는 부분이 되었지만, JavaScript 라는 언어의 특성을 가장 잘 보여주는 특성 중 하나이기에 정리했습니다._

### 정의

`hoist` 라는 단어의 사전적 정의는 끌어올리기 라는 뜻이다. 자바스크립트에서 끌어올려지는 것은 변수이다. `var` keyword 로 선언된 모든 변수 선언은 **호이스트** 된다. 호이스트란 변수의 정의가 그 범위에 따라 `선언`과 `할당`으로 분리되는 것을 의미한다. 즉, 변수가 함수 내에서 정의되었을 경우, 선언이 함수의 최상위로, 함수 바깥에서 정의되었을 경우, 전역 컨텍스트의 최상위로 변경이 된다.

우선, 선언(Declaration)과 할당(Assignment)을 이해해야 한다. 끌어올려지는 것은 선언이다.

```js
function getX() {
  console.log(x); // undefined
  var x = 100;
  console.log(x); // 100
}
getX();
```

다른 언어의 경우엔, 변수 x 를 선언하지 않고 출력하려 한다면 오류를 발생할 것이다. 하지만 자바스크립트에서는 `undefined`라고 하고 넘어간다. `var x = 100;` 이 구문에서 `var x;`를 호이스트하기 때문이다. 즉, 작동 순서에 맞게 코드를 재구성하면 다음과 같다.

```js
function getX() {
  var x;
  console.log(x);
  x = 100;
  console.log(x);
}
getX();
```

선언문은 항시 자바스크립트 엔진 구동시 가장 최우선으로 해석하므로 호이스팅 되고, **할당 구문은 런타임 과정에서 이루어지기 때문에** 호이스팅 되지 않는다.

함수가 자신이 위치한 코드에 상관없이 함수 선언문 형태로 정의한 함수의 유효범위는 전체 코드의 맨 처음부터 시작한다. 함수 선언이 함수 실행 부분보다 뒤에 있더라도 자바스크립트 엔진이 함수 선언을 끌어올리는 것을 의미한다. 함수 호이스팅은 함수를 끌어올리지만 변수의 값은 끌어올리지 않는다.

```js
foo( );
function foo( ){
  console.log(‘hello’);
};
// console> hello
```

foo 함수에 대한 선언을 호이스팅하여 global 객체에 등록시키기 때문에 `hello`가 제대로 출력된다.

```js
foo( );
var foo = function( ) {
  console.log(‘hello’);
};
// console> Uncaught TypeError: foo is not a function
```

이 두번째 예제의 함수 표현은 함수 리터럴을 할당하는 구조이기 때문에 호이스팅 되지 않으며 그렇기 때문에 런타임 환경에서 `Type Error`를 발생시킨다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-2-javascript)

</br>

## Closure

Closure(클로저)는 **두 개의 함수로 만들어진 환경** 으로 이루어진 특별한 객체의 한 종류이다. 여기서 **환경** 이라 함은 클로저가 생성될 때 그 **범위** 에 있던 여러 지역 변수들이 포함된 `context`를 말한다. 이 클로저를 통해서 자바스크립트에는 없는 비공개(private) 속성/메소드, 공개 속성/메소드를 구현할 수 있는 방안을 마련할 수 있다.

### 클로저 생성하기

다음은 클로저가 생성되는 조건이다.

1.  내부 함수가 익명 함수로 되어 외부 함수의 반환값으로 사용된다.
2.  내부 함수는 외부 함수의 실행 환경(execution environment)에서 실행된다.
3.  내부 함수에서 사용되는 변수 x 는 외부 함수의 변수 스코프에 있다.

```js
function outer() {
  var name = `closure`;
  function inner() {
    console.log(name);
  }
  inner();
}
outer();
// console> closure
```

`outer`함수를 실행시키는 `context`에는 `name`이라는 변수가 존재하지 않는다는 것을 확인할 수 있다. 비슷한 맥락에서 코드를 조금 변경해볼 수 있다.

```js
var name = `Warning`;
function outer() {
  var name = `closure`;
  return function inner() {
    console.log(name);
  };
}

var callFunc = outer();
callFunc();
// console> closure
```

위 코드에서 `callFunc`를 클로저라고 한다. `callFunc` 호출에 의해 `name`이라는 값이 console 에 찍히는데, 찍히는 값은 `Warning`이 아니라 `closure`라는 값이다. 즉, `outer` 함수의 context 에 속해있는 변수를 참조하는 것이다. 여기서 `outer`함수의 지역변수로 존재하는 `name`변수를 `free variable(자유변수)`라고 한다.

이처럼 외부 함수 호출이 종료되더라도 외부 함수의 지역 변수 및 변수 스코프 객체의 체인 관계를 유지할 수 있는 구조를 클로저라고 한다. 보다 정확히는 외부 함수에 의해 반환되는 내부 함수를 가리키는 말이다.

#### Reference

* [TOAST meetup - 자바스크립트의 스코프와 클로저](http://meetup.toast.com/posts/86)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-2-javascript)

</br>

## this 에 대해서

자바스크립트에서 모든 함수는 실행될 때마다 함수 내부에 `this`라는 객체가 추가된다. `arguments`라는 유사 배열 객체와 함께 함수 내부로 암묵적으로 전달되는 것이다. 그렇기 때문에 자바스크립트에서의 `this`는 함수가 호출된 상황에 따라 그 모습을 달리한다.

### 상황 1. 객체의 메서드를 호출할 때

객체의 프로퍼티가 함수일 경우 메서드라고 부른다. `this`는 함수를 실행할 때 함수를 소유하고 있는 객체(메소드를 포함하고 있는 인스턴스)를 참조한다. 즉 해당 메서드를 호출한 객체로 바인딩된다. `A.B`일 때 `B`함수 내부에서의 `this`는 `A`를 가리키는 것이다.

```js
var myObject = {
  name: "foo",
  sayName: function() {
    console.log(this);
  }
};
myObject.sayName();
// console> Object {name: "foo", sayName: sayName()}
```

</br>

### 상황 2. 함수를 호출할 때

특정 객체의 메서드가 아니라 함수를 호출하면, 해당 함수 내부 코드에서 사용된 this 는 전역객체에 바인딩 된다. `A.B`일 때 `A`가 전역 객체가 되므로 `B`함수 내부에서의 `this`는 당연히 전역 객체에 바인딩 되는 것이다.

```js
var value = 100;
var myObj = {
  value: 1,
  func1: function() {
    console.log(`func1's this.value: ${this.value}`);

    var func2 = function() {
      console.log(`func2's this.value ${this.value}`);
    };
    func2();
  }
};

myObj.func1();
// console> func1's this.value: 1
// console> func2's this.value: 100
```

`func1`에서의 `this`는 **상황 1** 과 같다. 그렇기 때문에 `myObj`가 `this`로 바인딩되고 `myObj`의 `value`인 1 이 console 에 찍히게 된다. 하지만 `func2`는 **상황 2** 로 해석해야 한다. `A.B`구조에서 `A`가 없기 때문에 함수 내부에서 `this`가 전역 객체를 참조하게 되고 `value`는 100 이 되는 것이다.

</br>

### 상황 3. 생성자 함수를 통해 객체를 생성할 때

그냥 함수를 호출하는 것이 아니라 `new`키워드를 통해 생성자 함수를 호출할 때는 또 `this`가 다르게 바인딩 된다. `new` 키워드를 통해서 호출된 함수 내부에서의 `this`는 객체 자신이 된다. 생성자 함수를 호출할 때의 `this` 바인딩은 생성자 함수가 동작하는 방식을 통해 이해할 수 있다.

`new` 연산자를 통해 함수를 생성자로 호출하게 되면, 일단 빈 객체가 생성되고 this 가 바인딩 된다. 이 객체는 함수를 통해 생성된 객체이며, 자신의 부모인 프로토타입 객체와 연결되어 있다. 그리고 return 문이 명시되어 있지 않은 경우에는 `this`로 바인딩 된 새로 생성한 객체가 리턴된다.

```js
var Person = function(name) {
  console.log(this);
  this.name = name;
};

var foo = new Person("foo"); // Person
console.log(foo.name); // foo
```

</br>

### 상황 4. apply, call, bind 를 통한 호출

상황 1, 상황 2, 상황 3 에 의존하지 않고 `this`를 자바스크립트 코드로 주입 또는 설정할 수 있는 방법이다. 상황 2 에서 사용했던 예제 코드를 다시 한 번 보고 오자. `func2`를 호출할 때, `func1`에서의 this 를 주입하기 위해서 위 세가지 메소드를 사용할 수 있다. 그리고 세 메소드의 차이점을 파악하기 위해 `func2`에 파라미터를 받을 수 있도록 수정한다.

* `bind` 메소드 사용

```js
var value = 100;
var myObj = {
  value: 1,
  func1: function() {
    console.log(`func1's this.value: ${this.value}`);

    var func2 = function(val1, val2) {
      console.log(`func2's this.value ${this.value} and ${val1} and ${val2}`);
    }.bind(this, `param1`, `param2`);
    func2();
  }
};

myObj.func1();
// console> func1's this.value: 1
// console> func2's this.value: 1 and param1 and param2
```

* `call` 메소드 사용

```js
var value = 100;
var myObj = {
  value: 1,
  func1: function() {
    console.log(`func1's this.value: ${this.value}`);

    var func2 = function(val1, val2) {
      console.log(`func2's this.value ${this.value} and ${val1} and ${val2}`);
    };
    func2.call(this, `param1`, `param2`);
  }
};

myObj.func1();
// console> func1's this.value: 1
// console> func2's this.value: 1 and param1 and param2
```

* `apply` 메소드 사용

```js
var value = 100;
var myObj = {
  value: 1,
  func1: function() {
    console.log(`func1's this.value: ${this.value}`);

    var func2 = function(val1, val2) {
      console.log(`func2's this.value ${this.value} and ${val1} and ${val2}`);
    };
    func2.apply(this, [`param1`, `param2`]);
  }
};

myObj.func1();
// console> func1's this.value: 1
// console> func2's this.value: 1 and param1 and param2
```

* `bind` vs `apply`, `call`
  우선 `bind`는 함수를 선언할 때, `this`와 파라미터를 지정해줄 수 있으며, `call`과 `apply`는 함수를 호출할 때, `this`와 파라미터를 지정해준다.

* `apply` vs `bind`, `call`
  `apply` 메소드에는 첫번째 인자로 `this`를 넘겨주고 두번째 인자로 넘겨줘야 하는 파라미터를 배열의 형태로 전달한다. `bind`메소드와 `call`메소드는 각각의 파라미터를 하나씩 넘겨주는 형태이다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-2-javascript)

</br>

## Promise

Javascript 에서는 대부분의 작업들이 비동기로 이루어진다. 콜백 함수로 처리하면 되는 문제였지만 요즘에는 프론트엔드의 규모가 커지면서 코드의 복잡도가 높아지는 상황이 발생하였다. 이러면서 콜백이 중첩되는 경우가 따라서 발생하였고, 이를 해결할 방안으로 등장한 것이 Promise 패턴이다. Promise 패턴을 사용하면 비동기 작업들을 순차적으로 진행하거나, 병렬로 진행하는 등의 컨트롤이 보다 수월해진다. 또한 예외처리에 대한 구조가 존재하기 때문에 오류 처리 등에 대해 보다 가시적으로 관리할 수 있다. 이 Promise 패턴은 ECMAScript6 스펙에 정식으로 포함되었다.

#### Reference

* http://programmingsummaries.tistory.com/325
* https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise
* https://developers.google.com/web/fundamentals/getting-started/primers/promises?hl=ko

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-2-javascript)

</br>

### Personal Recommendation

* [ECMAScript6 학습하기](https://jaeyeophan.github.io/categories/ECMAScript6)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-2-javascript)

</br>

## Async/Await
비동기 코드를 작성하는 새로운 방법이다. Javascript 개발자들이 훌륭한 비동기 처리 방안이 Promise로 만족하지 못하고 더 훌륭한 방법을 고안 해낸 것이다(사실 async/await는 promise기반). 절차적 언어에서 작성하는 코드와 같이 사용법도 간단하고 이해하기도 쉽다. function 키워드 앞에 async를 붙여주면 되고 function 내부의 promise를 반환하는 비동기 처리 함수 앞에 await를 붙여주기만 하면 된다. async/await의 가장 큰 장점은 Promise보다 비동기 코드의 겉모습을 더 깔끔하게 한다는 것이다. 이 것은 es8의 공식 스펙이며 node8LTS에서 지원된다(바벨이 async/await를 지원해서 곧바로 쓸수 있다고 한다!). 

* `promise`로 구현

```js
function makeRequest() {
    return getData()
        .then(data => {
            if(data && data.needMoreRequest) {
                return makeMoreRequest(data)
                  .then(moreData => {
                      console.log(moreData);
                      return moreData;
                  }).catch((error) => {
                      console.log('Error while makeMoreRequest', error);
                  });
            } else {
                console.log(data);
                return data;
            }
        }).catch((error) => {
          console.log('Error while getData', error);
        });
}
```

* `async/await` 구현

```js
async function makeRequest() { 
    try {
      const data = await getData();
      if(data && data.needMoreRequest) {
          const moreData = await makeMoreRequest(data);
          console.log(moreData);
          return moreData;
      } else {
          console.log(data);
          return data;
      }
    } catch (error) {
        console.log('Error while getData', error);
    }
}
```


#### Reference
* https://medium.com/@kiwanjung/%EB%B2%88%EC%97%AD-async-await-%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-%EC%A0%84%EC%97%90-promise%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-955dbac2c4a4
* https://medium.com/@constell99/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-async-await-%EA%B0%80-promises%EB%A5%BC-%EC%82%AC%EB%9D%BC%EC%A7%80%EA%B2%8C-%EB%A7%8C%EB%93%A4-%EC%88%98-%EC%9E%88%EB%8A%94-6%EA%B0%80%EC%A7%80-%EC%9D%B4%EC%9C%A0-c5fe0add656c
</br>

</br>

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-2-javascript)

</br>

## Arrow Function
화살표 함수 표현식은 기존의 function 표현방식보다 간결하게 함수를 표현할 수 있다. 화살표 함수는 항상 익명이며, 자신의 this, arguments, super 그리고 new.target을 바인딩하지 않는다. 그래서 생성자로는 사용할 수 없다.
- 화살표 함수 도입 영향: 짧은 함수, 상위 스코프 this

### 짧은 함수
```js
var materials = [
  'Hydrogen',
  'Helium',
  'Lithium',
  'Beryllium'
];

materials.map(function(material) { 
  return material.length; 
}); // [8, 6, 7, 9]

materials.map((material) => {
  return material.length;
}); // [8, 6, 7, 9]

materials.map(({length}) => length); // [8, 6, 7, 9]
```
기존의 function을 생략 후 => 로 대체 표현

### 상위 스코프 this
```js
function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this|는 person 객체를 참조
  }, 1000);
}

var p = new Person();
```
일반 함수에서 this는 자기 자신을 this로 정의한다. 하지만 화살표 함수 this는 Person의 this와 동일한 값을 갖는다. setInterval로 전달된 this는 Person의 this를 가리키며, Person 객체의 age에 접근한다.

#### Reference

* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

</br>

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-2-javascript)

</br>

=====
_JavaScript.end_


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2017 Jbee

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: MachineLearning/README.md
================================================
# Part 3-3 Machine Learning

> 면접에서 나왔던 질문들을 정리했으며 디테일한 모든 내용을 다루기보단 전체적인 틀을 다뤘으며, 틀린 내용이 있을 수도 있으니 비판적으로 찾아보면서 공부하는 것을 추천드립니다. Machine Learning 면접을 준비하시는 분들에게 조금이나마 도움이 되길 바라겠습니다.

+ Cost Function

</br>

## Cost Function
### [ 비용 함수 (Cost Function) ]
**Cost Function**이란 **데이터 셋**과 어떤 **가설 함수**와의 오차를 계산하는 함수이다. Cost Function의 결과가 작을수록 데이터셋에 더 **적합한 Hypothesis**(가설 함수)라는 의미다. **Cost Function**의 궁극적인 목표는 **Global Minimum**을 찾는 것이다.

### [ 선형회귀 (linear regression)에서의 Cost Function ]

| X   | Y   |
| --- | --- |
| 1   | 5   |
| 2   | 8   |
| 3   | 11  |
| 4   | 14  | 

위의 데이터를 가지고 우리는 우리가 찾아야할 그래프가 일차방정식이라는 것을 확인할 수 있고 `y=Wx + b`라는 식을 세울수 있고 `W(weight)`의 값과 `b(bias)`의 값을 학습을 통해 우리가 찾고자한다. 이때 **Cost Function**을 사용하는데 `W`와 `b`의 값을 바꾸어 가면서 그린 그래프와 테스트 데이터의 그래프들 간의 값의 차이의 가장 작은 값 즉 **Global Minimum**을 **경사하강법(Gradient descent algorithm)**을 사용해 찾는다.


================================================
FILE: Network/README.md
================================================
# Part 1-3 Network

- [HTTP 의 GET 과 POST 비교](#http의-get과-post-비교)
- [TCP 3-way-handshake](#tcp-3-way-handshake)
- [TCP와 UDP의 비교](#tcp와-udp의-비교)
- [HTTP 와 HTTPS](#http와-https)
  - HTTP 의 문제점들
- [DNS Round Robin 방식](#dns-round-robin-방식)
- [웹 통신의 큰 흐름](#웹-통신의-큰-흐름)

[뒤로](https://github.com/JaeYeopHan/for_beginner)

</br>

## HTTP의 GET과 POST 비교

둘 다 HTTP 프로토콜을 이용해서 서버에 무엇인가를 요청할 때 사용하는 방식이다. 하지만 둘의 특징을 제대로 이해하여 기술의 목적에 맞게 알맞은 용도에 사용해야한다.

### GET

우선 GET 방식은 요청하는 데이터가 `HTTP Request Message`의 Header 부분에 url 이 담겨서 전송된다. 때문에 url 상에 `?` 뒤에 데이터가 붙어 request 를 보내게 되는 것이다. 이러한 방식은 url 이라는 공간에 담겨가기 때문에 전송할 수 있는 데이터의 크기가 제한적이다. 또 보안이 필요한 데이터에 대해서는 데이터가 그대로 url 에 노출되므로 `GET`방식은 적절하지 않다. (ex. password)

### POST

POST 방식의 request 는 `HTTP Request Message`의 Body 부분에 데이터가 담겨서 전송된다. 때문에 바이너리 데이터를 요청하는 경우 POST 방식으로 보내야 하는 것처럼 데이터 크기가 GET 방식보다 크고 보안면에서 낫다.(하지만 보안적인 측면에서는 암호화를 하지 않는 이상 고만고만하다.)

_그렇다면 이러한 특성을 이해한 뒤에는 어디에 적용되는지를 알아봐야 그 차이를 극명하게 이해할 수 있다._
우선 GET 은 가져오는 것이다. 서버에서 어떤 데이터를 가져와서 보여준다거나 하는 용도이지 서버의 값이나 상태 등을 변경하지 않는다. SELECT 적인 성향을 갖고 있다고 볼 수 있는 것이다. 반면에 POST 는 서버의 값이나 상태를 변경하기 위해서 또는 추가하기 위해서 사용된다.

부수적인 차이점을 좀 더 살펴보자면 GET 방식의 요청은 브라우저에서 Caching 할 수 있다. 때문에 POST 방식으로 요청해야 할 것을 보내는 데이터의 크기가 작고 보안적인 문제가 없다는 이유로 GET 방식으로 요청한다면 기존에 caching 되었던 데이터가 응답될 가능성이 존재한다. 때문에 목적에 맞는 기술을 사용해야 하는 것이다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-3-network)

</br>

## TCP 3-way Handshake

일부 그림이 포함되어야 하는 설명이므로 링크를 대신 첨부합니다.

#### Reference

- http://asfirstalways.tistory.com/356

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-3-network)

</br>

## TCP와 UDP의 비교

### UDP

`UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜)`는 **비연결형 프로토콜** 이다. IP 데이터그램을 캡슐화하여 보내는 방법과 연결 설정을 하지 않고 보내는 방법을 제공한다. `UDP`는 흐름제어, 오류제어 또는 손상된 세그먼트의 수신에 대한 재전송을 **하지 않는다.** 이 모두가 사용자 프로세스의 몫이다. `UDP`가 행하는 것은 포트들을 사용하여 IP 프로토콜에 인터페이스를 제공하는 것이다.

종종 클라이언트는 서버로 짧은 요청을 보내고, 짧은 응답을 기대한다. 만약 요청 또는 응답이 손실된다면, 클라이언트는 time out 되고 다시 시도할 수 있으면 된다. 코드가 간단할 뿐만 아니라 TCP 처럼 초기설정(initial setup)에서 요구되는 프로토콜보다 적은 메시지가 요구된다.

`UDP`를 사용한 것들에는 `DNS`가 있다. 어떤 호스트 네임의 IP 주소를 찾을 필요가 있는 프로그램은, DNS 서버로 호스트 네임을 포함한 UDP 패킷을 보낸다. 이 서버는 호스트의 IP 주소를 포함한 UDP 패킷으로 응답한다. 사전에 설정이 필요하지 않으며 그 후에 해제가 필요하지 않다.

</br>

### TCP

대부분의 인터넷 응용 분야들은 **신뢰성** 과 **순차적인 전달** 을 필요로 한다. UDP 로는 이를 만족시킬 수 없으므로 다른 프로토콜이 필요하여 탄생한 것이 `TCP`이다. `TCP(Transmission Control Protocol, 전송제어 프로토콜)`는 신뢰성이 없는 인터넷을 통해 종단간에 신뢰성 있는 **바이트 스트림을 전송** 하도록 특별히 설계되었다. TCP 서비스는 송신자와 수신자 모두가 소켓이라고 부르는 종단점을 생성함으로써 이루어진다. TCP 에서 연결 설정(connection establishment)는 `3-way handshake`를 통해 행해진다.

모든 TCP 연결은 전이중(full-duplex), 점대점(point to point)방식이다. 전이중이란 전송이 양방향으로 동시에 일어날 수 있음을 의미하며 점대점이란 각 연결이 정확히 2 개의 종단점을 가지고 있음을 의미한다. TCP 는 멀티캐스팅이나 브로드캐스팅을 지원하지 않는다.

#### Reference

- http://d2.naver.com/helloworld/47667
- http://asfirstalways.tistory.com/327

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-3-network)

</br>

## HTTP와 HTTPS

### HTTP 의 문제점

- HTTP 는 평문 통신이기 때문에 도청이 가능하다.
- 통신 상대를 확인하지 않기 때문에 위장이 가능하다.
- 완전성을 증명할 수 없기 때문에 변조가 가능하다.

_위 세 가지는 다른 암호화하지 않은 프로토콜에도 공통되는 문제점들이다._

### TCP/IP 는 도청 가능한 네트워크이다.

TCP/IP 구조의 통신은 전부 통신 경로 상에서 엿볼 수 있다. 패킷을 수집하는 것만으로 도청할 수 있다. 평문으로 통신을 할 경우 메시지의 의미를 파악할 수 있기 때문에 암호화하여 통신해야 한다.

#### 보완 방법

1.  통신 자체를 암호화
    `SSL(Secure Socket Layer)` or `TLS(Transport Layer Security)`라는 다른 프로토콜을 조합함으로써 HTTP 의 통신 내용을 암호화할 수 있다. SSL 을 조합한 HTTP 를 `HTTPS(HTTP Secure)` or `HTTP over SSL`이라고 부른다.

2.  콘텐츠를 암호화
    말 그대로 HTTP 를 사용해서 운반하는 내용인, HTTP 메시지에 포함되는 콘텐츠만 암호화하는 것이다. 암호화해서 전송하면 받은 측에서는 그 암호를 해독하여 출력하는 처리가 필요하다.

</br>

### 통신 상대를 확인하지 않기 때문에 위장이 가능하다.

HTTP 에 의한 통신에는 상대가 누구인지 확인하는 처리는 없기 때문에 누구든지 리퀘스트를 보낼 수 있다. IP 주소나 포트 등에서 그 웹 서버에 액세스 제한이 없는 경우 리퀘스트가 오면 상대가 누구든지 무언가의 리스폰스를 반환한다. 이러한 특징은 여러 문제점을 유발한다.

1.  리퀘스트를 보낸 곳의 웹 서버가 원래 의도한 리스폰스를 보내야 하는 웹 서버인지를 확인할 수 없다.
2.  리스폰스를 반환한 곳의 클라이언트가 원래 의도한 리퀘스트를 보낸 클라이언트인지를 확인할 수 없다.
3.  통신하고 있는 상대가 접근이 허가된 상대인지를 확인할 수 없다.
4.  어디에서 누가 리퀘스트 했는지 확인할 수 없다.
5.  의미없는 리퀘스트도 수신한다. —> DoS 공격을 방지할 수 없다.

#### 보완 방법

위 암호화 방법으로 언급된 `SSL`로 상대를 확인할 수 있다. SSL 은 상대를 확인하는 수단으로 **증명서** 를 제공하고 있다. 증명서는 신뢰할 수 있는 **제 3 자 기관에 의해** 발행되는 것이기 때문에 서버나 클라이언트가 실재하는 사실을 증명한다. 이 증명서를 이용함으로써 통신 상대가 내가 통신하고자 하는 서버임을 나타내고 이용자는 개인 정보 누설 등의 위험성이 줄어들게 된다. 한 가지 이점을 더 꼽자면 클라이언트는 이 증명서로 본인 확인을 하고 웹 사이트 인증에서도 이용할 수 있다.

</br>

### 완전성을 증명할 수 없기 때문에 변조가 가능하다

여기서 완전성이란 **정보의 정확성** 을 의미한다. 서버 또는 클라이언트에서 수신한 내용이 송신측에서 보낸 내용과 일치한다라는 것을 보장할 수 없는 것이다. 리퀘스트나 리스폰스가 발신된 후에 상대가 수신하는 사이에 누군가에 의해 변조되더라도 이 사실을 알 수 없다. 이와 같이 공격자가 도중에 리퀘스트나 리스폰스를 빼앗아 변조하는 공격을 중간자 공격(Man-in-the-Middle)이라고 부른다.

#### 보완 방법

`MD5`, `SHA-1` 등의 해시 값을 확인하는 방법과 파일의 디지털 서명을 확인하는 방법이 존재하지만 확실히 확인할 수 있는 것은 아니다. 확실히 방지하기에는 `HTTPS`를 사용해야 한다. SSL 에는 인증이나 암호화, 그리고 다이제스트 기능을 제공하고 있다.

</br>

### HTTPS

> HTTP 에 암호화와 인증, 그리고 완전성 보호를 더한 HTTPS

`HTTPS`는 SSL 의 껍질을 덮어쓴 HTTP 라고 할 수 있다. 즉, HTTPS 는 새로운 애플리케이션 계층의 프로토콜이 아니라는 것이다. HTTP 통신하는 소켓 부분을 `SSL(Secure Socket Layer)` or `TLS(Transport Layer Security)`라는 프로토콜로 대체하는 것 뿐이다. HTTP 는 원래 TCP 와 직접 통신했지만, HTTPS 에서 HTTP 는 SSL 과 통신하고 **SSL 이 TCP 와 통신** 하게 된다. SSL 을 사용한 HTTPS 는 암호화와 증명서, 안전성 보호를 이용할 수 있게 된다.

HTTPS 의 SSL 에서는 공통키 암호화 방식과 공개키 암호화 방식을 혼합한 하이브리드 암호 시스템을 사용한다. 공통키를 공개키 암호화 방식으로 교환한 다음에 다음부터의 통신은 공통키 암호를 사용하는 방식이다.

#### 모든 웹 페이지에서 HTTPS를 사용해도 될까?

평문 통신에 비해서 암호화 통신은 CPU나 메모리 등 리소스를 더 많이 요구한다. 통신할 때마다 암호화를 하면 추가적인 리소스를 소비하기 때문에 서버 한 대당 처리할 수 있는 리퀘스트의 수가 상대적으로 줄어들게 된다.

하지만 최근에는 하드웨어의 발달로 인해 HTTPS를 사용하더라도 속도 저하가 거의 일어나지 않으며, 새로운 표준인 HTTP 2.0을 함께 이용한다면 오히려 HTTPS가 HTTP보다 더 빠르게 동작한다. 따라서 웹은 과거의 민감한 정보를 다룰 때만 HTTPS에 의한 암호화 통신을 사용하는 방식에서 현재 모든 웹 페이지에서 HTTPS를 적용하는 방향으로 바뀌어가고 있다.

#### Reference

- https://tech.ssut.me/https-is-faster-than-http/

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-3-network)

</br>

## DNS round robin 방식

### DNS Round Robin 방식의 문제점

1.  서버의 수 만큼 공인 IP 주소가 필요함. <br/>
    부하 분산을 위해 서버의 대수를 늘리기 위해서는 그 만큼의 공인 IP 가 필요하다.

2.  균등하게 분산되지 않음. <br/>
    모바일 사이트 등에서 문제가 될 수 있는데, 스마트폰의 접속은 캐리어 게이트웨이 라고 하는 프록시 서버를 경유 한다. 프록시 서버에서는 이름변환 결과가 일정 시간 동안 캐싱되므로 같은 프록시 서버를 경유 하는 접속은 항상 같은 서버로 접속된다. 또한 PC 용 웹 브라우저도 DNS 질의 결과를 캐싱하기 때문에 균등하게 부하분산 되지 않는다. DNS 레코드의 TTL 값을 짧게 설정함으로써 어느 정도 해소가 되지만, TTL 에 따라 캐시를 해제하는 것은 아니므로 반드시 주의가 필요하다.

3.  서버가 다운되도 확인 불가. <br/>
    DNS 서버는 웹 서버의 부하나 접속 수 등의 상황에 따라 질의결과를 제어할 수 없다. 웹 서버의 부하가 높아서 응답이 느려지거나 접속수가 꽉 차서 접속을 처리할 수 없는 상황인 지를 전혀 감지할 수가 없기 때문에 어떤 원인으로 다운되더라도 이를 검출하지 못하고 유저들에게 제공한다. 이때문에 유저들은 간혹 다운된 서버로 연결이 되기도 한다. DNS 라운드 로빈은 어디까지나 부하분산 을 위한 방법이지 다중화 방법은 아니므로 다른 S/W 와 조합해서 관리할 필요가 있다.

_Round Robin 방식을 기반으로 단점을 해소하는 DNS 스케줄링 알고리즘이 존재한다. (일부만 소개)_

#### Weighted round robin (WRR)

각각의 웹 서버에 가중치를 가미해서 분산 비율을 변경한다. 물론 가중치가 큰 서버일수록 빈번하게 선택되므로 처리능력이 높은 서버는 가중치를 높게 설정하는 것이 좋다.

#### Least connection

접속 클라이언트 수가 가장 적은 서버를 선택한다. 로드밸런서에서 실시간으로 connection 수를 관리하거나 각 서버에서 주기적으로 알려주는 것이 필요하다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-3-network)

</br>

## 웹 통신의 큰 흐름

_우리가 Chrome 을 실행시켜 주소창에 특정 URL 값을 입력시키면 어떤 일이 일어나는가?_

### in 브라우저

1.  url 에 입력된 값을 브라우저 내부에서 결정된 규칙에 따라 그 의미를 조사한다.
2.  조사된 의미에 따라 HTTP Request 메시지를 만든다.
3.  만들어진 메시지를 웹 서버로 전송한다.

이 때 만들어진 메시지 전송은 브라우저가 직접하는 것이 아니다. 브라우저는 메시지를 네트워크에 송출하는 기능이 없으므로 OS에 의뢰하여 메시지를 전달한다. 우리가 택배를 보낼 때 직접 보내는게 아니라, 이미 서비스가 이루어지고 있는 택배 시스템(택배 회사)을 이용하여 보내는 것과 같은 이치이다. 단, OS에 송신을 의뢰할 때는 도메인명이 아니라 ip주소로 메시지를 받을 상대를 지정해야 하는데, 이 과정에서 DNS서버를 조회해야 한다.

</br>

### in 프로토콜 스택, LAN 어댑터

1.  프로토콜 스택(운영체제에 내장된 네트워크 제어용 소프트웨어)이 브라우저로부터 메시지를 받는다.
2.  브라우저로부터 받은 메시지를 패킷 속에 저장한다.
3.  그리고 수신처 주소 등의 제어정보를 덧붙인다.
4.  그런 다음, 패킷을 LAN 어댑터에 넘긴다.
5.  LAN 어댑터는 다음 Hop의 MAC주소를 붙인 프레임을 전기신호로 변환시킨다.
6.  신호를 LAN 케이블에 송출시킨다.

프로토콜 스택은 통신 중 오류가 발생했을 때, 이 제어 정보를 사용하여 고쳐 보내거나, 각종 상황을 조절하는 등 다양한 역할을 하게 된다. 네트워크 세계에서는 비서가 있어서 우리가 비서에게 물건만 건네주면, 받는 사람의 주소와 각종 유의사항을 써준다! 여기서는 프로토콜 스택이 비서의 역할을 한다고 볼 수 있다.

</br>

### in 허브, 스위치, 라우터

1.  LAN 어댑터가 송신한 프레임은 스위칭 허브를 경유하여 인터넷 접속용 라우터에 도착한다.
2.  라우터는 패킷을 프로바이더(통신사)에게 전달한다.
3.  인터넷으로 들어가게 된다.

</br>

### in 액세스 회선, 프로바이더

1.  패킷은 인터넷의 입구에 있는 액세스 회선(통신 회선)에 의해 POP(Point Of Presence, 통신사용 라우터)까지 운반된다.
2.  POP 를 거쳐 인터넷의 핵심부로 들어가게 된다.
3.  수 많은 고속 라우터들 사이로 패킷이 목적지를 향해 흘러가게 된다.

</br>

### in 방화벽, 캐시서버

1.  패킷은 인터넷 핵심부를 통과하여 웹 서버측의 LAN 에 도착한다.
2.  기다리고 있던 방화벽이 도착한 패킷을 검사한다.
3.  패킷이 웹 서버까지 가야하는지 가지 않아도 되는지를 판단하는 캐시서버가 존재한다.

굳이 서버까지 가지 않아도 되는 경우를 골라낸다. 액세스한 페이지의 데이터가 캐시서버에 있으면 웹 서버에 의뢰하지 않고 바로 그 값을 읽을 수 있다. 페이지의 데이터 중에 다시 이용할 수 있는 것이 있으면 캐시 서버에 저장된다.

</br>

### in 웹 서버

1.  패킷이 물리적인 웹 서버에 도착하면 웹 서버의 프로토콜 스택은 패킷을 추출하여 메시지를 복원하고 웹 서버 애플리케이션에 넘긴다.
2.  메시지를 받은 웹 서버 애플리케이션은 요청 메시지에 따른 데이터를 응답 메시지에 넣어 클라이언트로 회송한다.
3.  왔던 방식대로 응답 메시지가 클라이언트에게 전달된다.

</br>

#### Personal Recommendation

- (도서) [성공과 실패를 결정하는 1% 네트워크 원리](http://www.yes24.com/24/Goods/17286237?Acode=101)
- (도서) [그림으로 배우는 Http&Network basic](http://www.yes24.com/24/Goods/15894097?Acode=101)
- (도서) [HTTP 완벽 가이드](http://www.yes24.com/24/Goods/15381085?Acode=101)
- Socket programming (Multi-chatting program)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-3-network)

</br>

</br>

_Network.end_


================================================
FILE: OS/README.en.md
================================================
# Part 1-4 Operating System

* [Process vs Thread](#process-vs-thread)
* [Multi-thread](#multi-thread)
  * Pros and cons
  * Multi-thread vs Multi-process
* [Scheduler](#scheduler)
  * Long-term scheduler
  * Short-term scheduler
  * Medium-term scheduler
* [CPU scheduler](#cpu-scheduler)
  * FCFS
  * SJF
  * SRTF
  * Priority scheduling
  * RR
* [Synchronous vs Asynchronous](#synchronous-vs-ayschrnous)
* [Process synchronization](#process-synchronization)
  * Critical Section
  * Solution
    * Lock
    * Semaphores
    * Monitoring
* [Memory management strategy](#memory-management-strategy)
  * Background of memory management
  * Paging
  * Segmentation
* [Virtual memory](#virtual-memory)
  * Background
  * Virtual memory usahge
  * Demand Paging (요구 페이징)
  * Page replacement algorithm
* [Locality of Cache](#locality-of-cache)
  * Locality
  * Caching line

[Back](https://github.com/JaeYeopHan/for_beginner)

</br>

---

## Process vs Thread

### Process

The process is an instance of a program in excecution, which can be loaded into memory from a disk and receive CPU allocation. Address space, files, memory, etc. are allocated by the operating system, and collectively referred to as a process. A process includes a stack with temporary data such as function parameters, return addresses, and local variables, and a data section containing global variables. A process also includes heap, dynamically allocated memory during its execution.

#### Process Control Block (PCB)

The PCB is a data structure of the operating system that **stores important information about a particular process**. When a process is created, the operating system **simultaneously creates a unique PCB** to manage the process. While a process is handling its operations on the CPU, if a process switching occurs, the process must save the ongoing work and yields the CPU. The progress status is saved in the PCB. Then, when the process regain CPU allocation, it can recall the stored status in the PCB and continue where it left off.

_Information store by PCB_

* Process ID (PID): process identification number
* Process status: the status of the process such as new, ready, running, waiting, terminated.
* Program counter: Address of the next instruction to be executed by the process.
* CPU scheduling information: priority of process, pointer to schedule queue, etc.
* Memory management information: page table, segment table, etc.
* IO status information : IO devices assigned to the process, list of open files, ...
* Bookkeeping information: consumed CPU time, time limit, account number, etc.

</br>

### Thread

The thread is an execution unit of the process. Within a process, several execution flows could share address spaces or resources.
The thread consists of a thread ID, a program counter, a register set, and a stack. Each thread shares operating system resources such as code section, data section, and open files or signals with other threads belonging to the same process.
Multi-threading is the division of one process into multiple execution units, which share resources and minimize redundancy in resource creation and management to improve performance. In this case, each thread has its own stack and PC register values because it has to perform independent tasks.

#### Why each thread has its own independent thread 

Stack is a memory space storing the function parameters, return addresses and locally declared variables. If the stack memory space is independent, function can be called independently, which adds an independent execution flow. Therefore, according to the definition of the thread, to add an independent execution flow, an independent stack is allocated for each thread as a minimum condition.

#### Why each thread has its own PC register

The PC value indicates the next instruction to be executed by the thread. The thread can receive CPU allocation and yield the CPU once premempted by the scheduler. Therefore, the instructions might not be performed continuously and it is necessary to save the part where the thread left off. Therefore, the PC register is assigned independently.

[Back](https://github.com/JaeYeopHan/for_beginner)/[Up](#part-1-4-operating-system)

</br>

---

## Multi-thread

### Pros of multi-threading

If we use process and simultaneously execute many tasks in different threads, memory space and system resource consumption are reduced. Even when communication between threads is required, data may be exchanged using the Heap area, which is a space of global variables or dynamically allocated variables, rather than using separate resources. Therefore, the inter-thread communication method is much simpler than the inter-process communication method. Context switch is also faster between threads because it does not have to empty the cache memory, unlike the context switch between process. Therefore, the system's throughput is improved and resource consumption is reduced, and the response time of the program is naturally shortened. Thanks to these advantages, tasks that can be done through multiple processes are divided into threads in only one process.
</br>

### Cons of multi-threading

Multi-process programming has no shared resource between the process, disabling simultaneous access to the same resource. However, we should be careful when programming based on multithreading. Because different threads share data and heap areas, some threads can access variables or data structures currently in use in other threads, consequently read or modify the wrong value.

Therefore, in the multi-threading setting, synchronization is required. Synchronization controls the order of operations and access to shared resources. However, some bottlenecks might arise due to excessive locks and degrade the performance. Therefore, we need to reduce bottlenecks.

</br>

### Multi-thread vs Multi-process

Compared to multi-process, multi-thread occupies less memory space and has faster context switch, but if one thread terminates, all other threads might be terminated and synchonization problem might occur. On the other hand, multi-process has an advantage that even when a process is terminated, other processed are unaffected and operates normally. However, it occupies more memory space and CPU times than multi-thread. 

These two are similar in that they perform several tasks at the same time, but they could be (dis)advantageous depending on the system in use. Depending on the characteristics of the targeted system, we should select the appropriate scheme.

[Back](https://github.com/JaeYeopHan/for_beginner)/[Up](#part-1-4-operating-system)

</br>

---

## Scheduler

_There are three types of queue for process scheduling_
* Job Queue: The set of all processes in the current system
* Ready Queue: The set of processes currently in the memory wiaitng to gain control of CPU
* Device Queue : The set of processes currently waiting for device IO's operations

There are also **three types** of schedulers that insert and pop processes into each queue

### Long-term scheduler or job scheduler

The memory is limited, and when many processes are loaded into memory at a time, they are temporarily stored in a large storage (typically disk). The job scheduler determines which process in this pool to allocate memory and send to the Ready Queue.

* In charge of scheduling between memory and disk
* Allocate process's memory and resource
* Control the degree of multiprogramming (the number of 
processes in excecution)
* Process status transition: new -> ready(in memory)

_cf) It hurts the performance when too much or too few program is loaded into the memory. For reference, there is no long-term scheduler in the time sharing system. It is just loaded to the memory immediately and becomes ready_

</br>

### Short-term scheduler or CPU scheduler

* In charge of scheduling between CPU and memory
* Determine which process in the ready queue to run
* Allocate CPU to process (schedular dispatch)
* Process status transition: ready -> rubnning -> waiting -> ready

</br>

### Medium-term scheduler or Swapper

* Migrate the entire process from memory to disk to make space (swapping).
* Deallocate memory from the process
* Control the degree of multiprogramming 
* Regulate when excessively many program is loaded to the memory of the current system. 
* Process status transition:
  ready -> suspended

#### Process state - suspended

Suspended(stopped): The memory state in which the process execution is stopped due to external factors. All the process is swapped out from disk. Blocked state could go back to the ready state on its own, since the process is waiting for other I/O operations. Suspended state cannot go back to ready state by itself, since it is caused by external factors.

[Back](https://github.com/JaeYeopHan/for_beginner)/[Up](#part-1-4-operating-system)

</br>

---

## CPU scheduler

_It schedule the process in the Ready Queue._

### FCFS(First Come First Served)

#### Characteristic

* The method that serving the customer that comes first (i.e, in the order of first-come)
* Non-Preemptive (비선점형) scheduling  
  Once a process gain the control of CPU, it completes the CPU burst nonstop without yielding control. Scheduling is performed only when the allocated CPU is yielded (returned).

#### Issue

* Convoy effect  
  When a process with long processing time is allocated, it can slow down the whole operating system.

</br>

### SJF (Shortest Job First)

#### Characteristics

* The short process with short CPU burst time is allocated first even if it comes later than other processes.
* Non-preemtive scheduling

#### Issue

* Starvation  
  Even though efficency is important, every process should be served. This scheduling might prefer the job with short CPU time so extremely that the process with long procesing time might never be allocated.  

</br>

### SRTF(Shortest Remaining Time First)

#### Characteristic
* When a new process comes, scheduling is done
* Preemptive (선전) scheduling
  If the newly arrived process has shorter CPU burst time than the remaining burst time of ongoing process, the CPU is yielded to allocate to the new process.

#### Issue

* Starvation
* Scheduling is performed for every newly arrived process, so CPU burst time (CPU used time) cannot be measured.

</br>

### Priority Scheduling

#### Characteristic

* CPU is allocated to the process with highest priority.  
The priority is expressed as an integer, where smaller number indicates higher priority.
* Preemptive (선전) scheduling method
  If a process with higher priority arrives, ongoing process will stops and yields CPU.
* Non-preemptive (비선전) scheduling
  If a process with higher priority arrives, it is put to the head of the Ready Queue.

#### Issue

* Starvation
* Indefinite blocking (무기한 봉쇄)
  The state that waits for the CPU indefinitely, because the current process is ready to run but cannot use the CPU due to low priority.

#### Solution

* Aging  
  Increase the priority of a process if it waits for a long time, regardless of how low priority it has.

</br>

### Round Robin

#### Characteristic
* Modern CPU scheduling
* Each process has the same amount of time quantime (할당 시간).
* After spending the time quantum, a process is preempted and put to the back of the Ready Queue (to be continued later)
* `RR` is efficient when the CPU burst time of each process is random.
* `RR` is possible because the process context can be saved.

#### Pros

* `Response time` is shortened.  
  If there are n processes in the ready queue and the time quantum (할당 시간) is q, no process waits more than (n-1)q time unit.
* The waiting time of the process increases with the CPU
  burst time. It is said to be fair scheduling.

#### Note
The time quantum is set too high, it behaves like `FCFS`. If it is set too low, scheduling algorithm will be ideal, but overhead might occur due to frequent context switch.

설정한 `time quantum`이 너무 커지면 `FCFS`와 같아진다.
또 너무 작아지면 스케줄링 알고리즘의 목적에는 이상적이지만 잦은 context switch 로 overhead 가 발생한다.
그렇기 때문에 적당한 `time quantum`을 설정하는 것이 중요하다.

[Back](https://github.com/JaeYeopHan/for_beginner)/[Up](#part-1-4-operation system)

</br>

---

## Synchronous and Asynchronous

### Examplified explanation

Suppose that there are 3 tasks to do: laundry, dishes, and cleaning. If these tasks are processed synchronously, we do laundry, then wash dishes, then clean the house.
If these tasks are processed asynchrously, we assign the the laundry agent to wash clothes, the dishwashing agent to wash dish, and the cleaning agent to clean. We do not know which one completes first. After finish its work, the agent will notify us, so we can do other work in the mean time.
CS-wise, it is said to be asynchronous when the operation is processed in the background thread. 

### Sync vs Async
Generally, a method is called **synchronous** when the return values is expected to come `together` with the program execution. Else, it is called **asynchronous**.
If we run a job synchronously, there is `blocking` until the program returns. If we run asynchronouly, there is no `blocking` and the job is put in the jobs queue or delegate to the background thread and we immediately execute the next code. Hence, and the job does not immediately return.

_Since it is hard to explain with word, the link to a supplementary figure is attached._

#### Reference

* http://asfirstalways.tistory.com/348

[Back](https://github.com/JaeYeopHan/for_beginner)/[Up](#part-1-4-operating-system)

</br>

---

## Process synchronization

### Critical Section (임계영역)

As mentioned in multi-threading, the section of the code that simultaneously access the same resources is referred as Critial Section

### Critical Section Problem (임계영역 문제)

Design a protocol that enable multiple processes to use Critical Section together

#### Requirements (해결을 위한 기본조건)

* Mutual Exclusion (상호 배제)  
  While process P1 is executing the Critical Section, other process can never enter their Critical Section
* Progress (진행)  
  If no process is executing in its critical section,
  only those processes that are not executing in their remainder section (i.e, has not entered its critical section) are candidate to be the next process to enter its critical section. This selection **cannot be postponed indefinitely**.

* Bounded Waiting(한정된 대기)  
  After P1 made a request to enter the Critical Section and before it receives admission, there is a bound on the number of times other processes can enter their Critical Section. (**no starvation**)

### Solutions

### Lock

As a basic hardware-based solution, to prevent simultaneous access to shared resources, the process will acquire a Lock when entering its Critical Section and release the Lock when it leaves the Critical Section.

#### Limitation
Time efficiency in multi-processor machine cannot be utilized.

### Semaphores (세마포)
* Synchroniozation tool to resolve Critical Section issues in software

#### Types

OS distinguishes between Counting and Binary semaphores

* Counting semaphore  
  Semaphore controls access to the resources by **a number indicating availability**. The semaphore is initilized to be the **number of available resources**. When a resource is used, semaphore decreases, and when a resource is released, semaphore increases.

* Binary (이진) semaphore 
  It is alaso called MUTEX (abbv. for Mutual Exclusion)
  As the name suggested, there are only to possible value: 0 and 1. This is used to solve the Critical Section Problem among processes.

#### Cons

* Busy Waiting (바쁜 대기)  

In the initial version of Semaphore (called Spin lock), the process entering Critical Section has to keep executing the code repeatedly, wasting a lot of CPU time. This is called Busy Waiting, which is inefficient except for some special situation. Generally, Semaphore will block a process attempted but failed enter its Critical Section, and wake them up when there is space in the Critical Section. This solves the time inefficiency problem of Busy Waiting.

#### Deadlock (교착상태)
* Semaphore has a Ready Queue. Deadlock is the situation in which two or more processes is waiting indefinitely to enter their Criticial Section, or the process running in its Critical Section can only exit when an awaiting process start executing.

### Monitoring
* The design structure of high-level programming language, where an abstract data form is made for developers to code in a mutually exclusive way.
* Access to shared resources requires both key acquisition and resources release after use (Semaphore requires direct key release and access to shared resources.)

[Back](https://github.com/JaeYeopHan/for_beginner)/[Up](#part-1-4-operating-system)

---

## Memory management strategy

### Background of memory management

  Each **process** has its independent memory space, so the OS need to limit process from accessing the memory space of other processes. However, only **operating system** can access the kernel memory and user (application)
  memory. 

**Swapping**: The technique to manage memory. In scheduling scheme such as round-robin, after the process uses up its CPU allocation, the process's memory is exported to the auxiliary storage device (e.g. hard disk) to make room to retrieve the other process's memory.

> This process is called **swap**. The process of bringing in the main memory (RAM) is called **swap-in**, and export to the auxiliary storage device is called **swap-out**. Swap only starts when memory space is inadequate, since disk transfer takes a long time.

**Fragmentation** (**단편화**): 
If a process is repeatedly loaded and removed from the memory, many free space in the gap between memory occupied by the process becomes too small to be usable. This is called **fragmentation**. There are 2 types of fragmentation:

| `Process A` | free | `Process B` | free | `Process C` | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; free &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | `Process D` |
| ----------- | ---- | ----------- | ---- | ----------- | :--------------------------------------------------------------------------------------: | ----------- |


* External fragmentation (외부 단편화): Refer to the unusable part in the memory space. Although the remaining spaces in the physical memory (RAM) are enough to be used (if combined), they are dispersed across the whole memory space. 

* Internal fragmentation (내부 단편화): Refer to the remaining part included in the memory space used by the process. For example, if the memory is splitted into free spaces of 10,000B and process A use 9,998B, and 2B remains. This is referred to as internal fragmentation.

Compression: To solve the external fragmentation, we can put the space used by the process to one side to secure the free space, but it is not efficient. (This memory status is shown in the figure below)

| `Process A` | `Process B` | `Process C` | `Process D` | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; free &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; |
| ----------- | ----------- | ----------- | :---------: | ------------------------------------------------------------------------------------------------------------------ |


### Paging (페이징)

The method by which the memory space used by a process is not necessarily contingous. 

The method is made to handle internal fragmentation and compression.  Physical memory (물리 메모리) is separated into fixed size of Frame. Logical memory (논리 메모리 - occupied by the process) is divided into fixed size blocks, called page. (subjected to page replacement algorithm)

Paging technique brings a major advantage in resolving external fragmentation. Logical memory does not need to be store contingously in the physical memory, and can be arranged properly in the remaining frames in the physical memory.

Space used by each process is divided into and managed by several pages (in the logical memory), where individual page, **regardless of order**, is mapped and saved into the frames in the physical memory.

* Cons: Internal fragmentation might increase. For example, if page size is 1,024B and **process A** request 3,172B of memory, 4 pages is required, since if we use 3 page frames (1024 \* 3 = 3,072), there are still 100B remaining. 924B remains unused in the 4th page, leading to internal fragmentation.

### Segmentation (세그멘테이션)
The physical memory and physical memory is divided into segments of different size, instead of the same block size as in paging. 
Users designate two addresses a saved (segment number + offset).
The segment table store the reference to each segment (segment starting physical address) and a bound (segment length).

* Cons: When a segments with different length is loaded and removed reapatedly, fee space would be splitted up into many small unusable pieces (external fragmentation).

[Back](https://github.com/JaeYeopHan/for_beginner)/[Up](#part-1-4-operating-system)

---

## Virtual memory (가상 메모리)
To realize multi-programming, we need to load many process into the memory at the same time. Virtual memory is the **technique that allows a process to be executed without loading entirely into the memory**. The main advantage is that, the program can be even bigger than the physical memory.

### Background of virtual memory development

Without virtual memory, **the entirety of the code in execution must pe present in the physical memory**, so **the code bigger than the memory capacity cannot be executed**. Also, when many programs are loaded simoustaneously into the memory, there would be capacity limit and page replacement will suffer from performance issue.

In addition, since the memory occupied by occasionally used codes can be checked, the entire program does not need to be loaded to the memory.

#### If only part of the program is loaded into the memory...

* There is no restriction due to the capacity of the physical memory.
* More program can be executed simultanoeusly. Therefore, `response time` is maintained while `CPU utilization` and `process rate` is improved.
* [swap](#memory-managment-background) requires less I/O, expediting the execution.

### Virtual memory usage

Virtual memory separate the concept of physical memory in reality and the concept of user's logical memory. Thereby, even with small memory, programmers can have unlimitedly large `virtual memory space`.

#### Virtual address space (가상 주소 공간)

* Virtual memory is the a space that implements the logical location in which a process is stored in memory.
  The memory space requested by the process is provided in the virtual memory. Thereby, the memory space not immediately required does not need to be loaded to the actual physical memory, saving the physical memory.
* For example, assume a process is executing and requires 100KB in the virtual memory.
  However, if the sum of the memory space `(Heap section, Stack sec, code, data)` required to run is 40KB, it can be understood that only 40KB is listed in the actual physical memory, and the remaining 60KB is required for physical memory if necessary.

However, if the total of the memory space required `(HEAP segment, stack segment, code, data)` is 40 KB, only 40 KB is loaded to the actual physical memory, and the remaining 60KB is only requested from the physical memory when necessary.
| `Stack` | &nbsp;&nbsp;&nbsp; free (60KB) &nbsp;&nbsp;&nbsp;&nbsp; | `Heap` | `Data` | `Code` |
| ------- | ------------------------------------------------------- | :----: | ------ | ------ |


#### Sharing pages among process (프로세스간의 페이지 공유)

With virtual memory, ...

* `system libraries` can be shared among several process.
  Each process can recognize and use the `shared libraries` as if they are in its own virtual addess space, but the `physical memory page` locating those libraries can be shared among all processes. 
* The processes can share memory, and communicate via shared memory.  
  Each process also has the illusion of its own address space, but the actual physical memory is shared.
* Page sharing is enable in process creation by `fork()`.

### Demand Paging (요구 페이징)

At the start of program execution, instead of loading the entire program into physical memory of the disk at the start of program execution, demand paging is the strategy that only loads the initially required part. It is widely ussed in virtual memory system. The virtual memory is mainly managed by [Paging](#paging-페이징) method.

In the virtual memory with demand paging, the pages are loaded when necessary during execution. **The pages that are not accessed are never loaded into the physical memory**.

Individual page in the process is manage by `pager (페이저)`. During execution, pager only reads and transfers necessary pages into the memory, thereby **the time and memory consumption for the the unused pages is reduced**.

#### Page fault trap (페이지 부재 트랩)

### Page replacement

In `demand paging`, as mentioned, not all parts of a program in execution is loaded into the physical memory. When the process requests a necessary page for its operation, `page fault (페이지 부제)` might happen and the desired pages are brought from the auxiliary storage devices. However, in case all physical memory is used, page replacement must take place. (Or, the OS must force the process termination).

#### Basic methods

If all physical memory is in use, the replacement flows as follow:
1. Locate the required page in disk.
2. Find an empty page frame.
    1. Using `Page replacement algorithm`, choose a victim page.
    1. Record the victim page on disk and update the related page table.
1. Read a new page to the empty frame and update the page table.
2. Restart the user process.
  

#### Page replacement algorithm

##### FIFO page replacement

The simpliest page replacement algorithm has a FIFO (first-in-first-out) flow. That is, the page is replaced in the order of entering the physical memory.

* Pros:
  
  * Easy to understand and implement

* Cons:
  * The old pages might include necessary information (initial variables, ...).
  * The pages actively used fromt he beginning might get replaced, increasing page fault rate.
  * `Belady anomaly`: increasing the number of page frames might result in an increase in the number of page faults.

##### Optimal Page Replacement (최적 페이지 교체)
After `Belady's anomaly` is confirmed, people started exploring the optimal replacement algorithm, which has lower page fault rate than all other algorithms, and eliminates `Belady's anomaly`. The core of this algorithm is to find and replace pages that will not be used for the longest time in the future.
This is mainly used in research for comparison purpose.

* Pros
  * Guaranteed to have the least page fault among all algorithms

* Cons
  * It is hard to implement, because there is no way to know in advance how each process reference the memory.

##### LRU Page Replacement (LRU 페이지 교체)

`LRU: Least-Recently-Used` 
The least recently used page is selected for replacement. This algoritms approximates the optimal algorithm 

* Characteristic
  * Generally, `FIFO algorithm` is better then FIFO algorithm, but nto as good as `optimal algorithm`.

##### LFU Page Replacement (LFU 페이지 교체)

`LFU: Least Frequently Used`  
The page that is referenced the leats time is replaced. The algoritm is made under the assumption that the actively used pages is referenced more.
* Characteristic
  * After a particular process use a specific page intensively, the page might remain in the memory even if it is no longer used. This goes against the intial assumption.
  * Since it does not properly approximate the optimal page replacement, it is not widely applied.

##### MFU 페이지 교체(MFU Page Replacement)

`MFU: Most Frequently Used`  
  The page is based on the assumption that the infrequently-referenced page was recently loaded to memory and will continue to be used in the future.

* Characteristic
  * Since it does not properly approximate the optimal page replacement, it is not widely applied.

</br>

[Back](https://github.com/JaeYeopHan/for_beginner)/[Up](#part-1-4-operating-system)

---

## Locality of Cache

### Locality principle of cache

Cache memory is a widely used memory to reduce the bottlenecks due to speed difference between fast and slow device. To fulfill this role, it must be able to predict to some extent what data the CPU will want. This is because the performance of the cache depends on how much useful information (referenced later by the CPU) in a small capacity cache memory

This use the locality (지역성) principle of the data to maximize the `hit rate (적종율)`. As the prerequisites of locality, the program does not access all code or data equally. In other words, locality is a characterisitc of intensively referencing only a specfific part of the program at a specific time, instead of accessing all the information in the storage device equally.

Data locality is typically divided into Temporal Locality ̣̣(시간 지역성) and Spacial Locality (공간 지역성).

* Temporal locality: the content of recently referenced address is likely to be referenced again soon.
* Spacial Locality: In most real program, the content at the address adjacent to the previously referenced addresses is likely to be referenced.

</br>

### Caching line
As mentioned, the cache, located near the processor, is the place to put frequently used data. However, the target data is stored anywhere in the cache. No matter how close the cache is, traversing through the cache to find the target data will take a long time. If the target data is stored in the cache, the cache becomes meaningful only if the data can be accessed and read immediately.

Therefore, when storing data into the cache, we use a special data structure that stores data as bundle, called **cache line**. Since the process use data stored at many different addresses, the frequently used data is also scattered. Thus, it is necessary to attach a tag that records the corresponding memory addresses along with the data. This bundle is called caching line, and the cache line is brought to the cache.
Typically, there are three methods:

1.  Full Associative
2.  Set Associative
3.  Direct Map

[Back](https://github.com/JaeYeopHan/for_beginner)/[Up](#part-1-4-operating-system)

</br>

---

</br>

_OS.end_


================================================
FILE: OS/README.md
================================================
# Part 1-4 운영체제

* [프로세스와 스레드의 차이](#프로세스와-스레드의-차이)
* [멀티스레드](#멀티스레드)
  * 장점과 단점
  * 멀티스레드 vs 멀티프로세스
* [스케줄러](#스케줄러)
  * 장기 스케줄러
  * 단기 스케줄러
  * 중기 스케줄러
* [CPU 스케줄러](#cpu-스케줄러)
  * FCFS
  * SJF
  * SRTF
  * Priority scheduling
  * RR
* [동기와 비동기의 차이](#동기와-비동기의-차이)
* [프로세스 동기화](#프로세스-동기화)
  * Critical Section
  * 해결책
    * Lock
    * Semaphores
    * 모니터
* [메모리 관리 전략](#메모리-관리-전략)
  * 메모리 관리 배경
  * Paging
  * Segmentation
* [가상 메모리](#가상-메모리)
  * 배경
  * 가상 메모리가 하는 일
  * Demand Paging(요구 페이징)
  * 페이지 교체 알고리즘
* [캐시의 지역성](#캐시의-지역성)
  * Locality
  * Caching line

[뒤로](https://github.com/JaeYeopHan/for_beginner)

</br>

---

## 프로세스와 스레드의 차이

### 프로세스(Process)

프로세스는 실행 중인 프로그램으로, 디스크로부터 메모리에 적재되어 CPU 의 할당을 받을 수 있는 것을 말한다. 운영체제로부터 주소 공간, 파일, 메모리 등을 할당받으며 이것들을 총칭하여 프로세스라고 한다. 구체적으로 살펴보면 프로세스는 함수의 매개 변수, 복귀 주소, 로컬 변수와 같은 임시 자료를 갖는 프로세스 스택과 전역 변수들을 수록하는 데이터 섹션을 포함한다. 또한 프로세스는 프로세스 실행 중에 동적으로 할당되는 메모리인 힙을 포함한다.

#### 프로세스 제어 블록(Process Control Block, PCB)

PCB 는 특정 **프로세스에 대한 중요한 정보를 저장** 하고 있는 운영체제의 자료 구조이다. 운영체제는 프로세스를 관리하기 위해 **프로세스의 생성과 동시에 고유한 PCB 를 생성** 한다. 프로세스는 CPU 를 할당받아 작업을 처리하다가도 프로세스 전환이 발생하면 진행하던 작업을 저장하고 CPU 를 반환해야 하는데, 이때 작업의 진행 상황을 모두 PCB 에 저장하게 된다. 그리고 다시 CPU 를 할당받게 되면 PCB 에 저장되어 있던 내용을 불러와 이전에 종료됐던 시점부터 다시 작업을 수행한다.

_PCB 에 저장되는 정보_

* 프로세스 식별자(Process ID, PID) : 프로세스 식별 번호
* 프로세스 상태 : new, ready, running, waiting, terminated 등의 상태를 저장
* 프로그램 카운터 : 프로세스가 다음에 실행할 명령어의 주소
* CPU 레지스터
* CPU 스케줄링 정보 : 프로세스의 우선순위, 스케줄 큐에 대한 포인터 등
* 메모리 관리 정보 : 페이지 테이블 또는 세그먼트 테이블 등과 같은 정보를 포함
* 입출력 상태 정보 : 프로세스에 할당된 입출력 장치들과 열린 파일 목록
* 어카운팅 정보 : 사용된 CPU 시간, 시간제한, 계정 번호 등

</br>

### 스레드(Thread)

스레드는 프로세스의 실행 단위라고 할 수 있다. 한 프로세스 내에서 동작하는 여러 실행 흐름으로, 프로세스 내의 주소 공간이나 자원을 공유할 수 있다. 스레드는 스레드 ID, 프로그램 카운터, 레지스터 집합, 그리고 스택으로 구성된다. 같은 프로세스에 속한 다른 스레드와 코드, 데이터 섹션, 그리고 열린 파일이나 신호와 같은 운영체제 자원들을 공유한다. 하나의 프로세스를 다수의 실행 단위로 구분하여 자원을 공유하고 자원의 생성과 관리의 중복성을 최소화하여 수행 능력을 향상하는 것을 멀티스레딩이라고 한다. 이 경우 각각의 스레드는 독립적인 작업을 수행해야 하기 때문에 각자의 스택과 PC 레지스터 값을 갖고 있다.

#### 스택을 스레드마다 독립적으로 할당하는 이유

스택은 함수 호출 시 전달되는 인자, 되돌아갈 주소값 및 함수 내에서 선언하는 변수 등을 저장하기 위해 사용되는 메모리 공간이므로 스택 메모리 공간이 독립적이라는 것은 독립적인 함수 호출이 가능하다는 것이고 이는 독립적인 실행 흐름이 추가되는 것이다. 따라서 스레드의 정의에 따라 독립적인 실행 흐름을 추가하기 위한 최소 조건으로 독립된 스택을 할당한다.

#### PC Register 를 스레드마다 독립적으로 할당하는 이유

PC 값은 스레드가 명령어의 어디까지 수행하였는지를 나타낸다. 스레드는 CPU 를 할당받았다가 스케줄러에 의해 다시 선점당한다. 그렇기 때문에 명령어가 연속적으로 수행되지 못하고, 어느 부분까지 수행했는지 기억할 필요가 있다. 따라서 PC 레지스터를 독립적으로 할당한다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-4-운영체제)

</br>

---

## 멀티스레드

### 멀티스레딩의 장점

프로세스를 이용하여 동시에 처리하던 일을 스레드로 구현할 경우 메모리 공간과 시스템 자원 소모가 줄어들게 된다. 스레드 간의 통신이 필요한 경우에도 별도의 자원을 이용하는 것이 아니라 전역 변수의 공간 또는 동적으로 할당된 공간인 힙 영역을 이용하여 데이터를 주고받을 수 있다. 그렇기 때문에 프로세스 간 통신 방법에 비해 스레드 간 통신 방법이 훨씬 간단하다. 심지어 스레드의 context switch 는 프로세스 context switch 와는 달리 캐시 메모리를 비울 필요가 없기 때문에 더 빠르다. 따라서 시스템의 throughput 이 향상되고 자원 소모가 줄어들며 자연스럽게 프로그램의 응답 시간이 단축된다. 이러한 장점 때문에 여러 프로세스로 할 수 있는 작업들을 하나의 프로세스에서 스레드로 나눠 수행하는 것이다.

</br>

### 멀티스레딩의 문제점

멀티프로세스 기반으로 프로그래밍할 때는 프로세스 간 공유하는 자원이 없기 때문에 동일한 자원에 동시에 접근하는 일이 없었지만, 멀티스레딩을 기반으로 프로그래밍할 때는 이 부분을 신경 써야 한다. 서로 다른 스레드가 데이터와 힙 영역을 공유하기 때문에 어떤 스레드가 다른 스레드에서 사용 중인 변수나 자료 구조에 접근하여 엉뚱한 값을 읽어오거나 수정할 수 있다.

그렇기 때문에 멀티스레딩 환경에서는 동기화 작업이 필요하다. 동기화를 통해 작업 처리 순서를 컨트롤하고 공유 자원에 대한 접근을 컨트롤하는 것이다. 하지만 이로 인해 병목 현상이 발생하여 성능이 저하될 가능성이 높다. 그러므로 과도한 록(lock)으로 인한 병목 현상을 줄여야 한다.

</br>

### 멀티스레드 vs 멀티프로세스

멀티스레드는 멀티프로세스보다 적은 메모리 공간을 차지하고 문맥 전환이 빠르다는 장점이 있지만, 오류로 인해 하나의 스레드가 종료되면 전체 스레드가 종료될 수 있다는 점과 동기화 문제를 안고 있다. 반면 멀티프로세스 방식은 하나의 프로세스가 죽더라도 다른 프로세스에는 영향을 끼치지 않고 정상적으로 수행된다는 장점이 있지만, 멀티스레드보다 많은 메모리 공간과 CPU 시간을 차지한다는 단점이 존재한다. 이 두 가지는 동시에 여러 작업을 수행한다는 점에서 같지만 적용해야 하는 시스템에 따라 적합/부적합이 구분된다. 따라서 대상 시스템의 특징에 따라 적합한 동작 방식을 선택하고 적용해야 한다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-4-운영체제)

</br>

---

## 스케줄러

_프로세스를 스케줄링하기 위한 Queue 에는 세 가지 종류가 존재한다._

* Job Queue : 현재 시스템 내에 있는 모든 프로세스의 집합
* Ready Queue : 현재 메모리 내에 있으면서 CPU 를 잡아서 실행되기를 기다리는 프로세스의 집합
* Device Queue : Device I/O 작업을 대기하고 있는 프로세스의 집합

각각의 Queue 에 프로세스들을 넣고 빼주는 스케줄러에도 크게 **세 가지 종류가** 존재한다.

### 장기스케줄러(Long-term scheduler or job scheduler)

메모리는 한정되어 있는데 많은 프로세스들이 한꺼번에 메모리에 올라올 경우, 대용량 메모리(일반적으로 디스크)에 임시로 저장된다. 이 pool 에 저장되어 있는 프로세스 중 어떤 프로세스에 메모리를 할당하여 ready queue 로 보낼지 결정하는 역할을 한다.

* 메모리와 디스크 사이의 스케줄링을 담당.
* 프로세스에 memory(및 각종 리소스)를 할당(admit)
* degree of Multiprogramming 제어  
  (실행중인 프로세스의 수 제어)
* 프로세스의 상태  
  new -> ready(in memory)

_cf) 메모리에 프로그램이 너무 많이 올라가도, 너무 적게 올라가도 성능이 좋지 않은 것이다. 참고로 time sharing system 에서는 장기 스케줄러가 없다. 그냥 곧바로 메모리에 올라가 ready 상태가 된다._

</br>

### 단기스케줄러(Short-term scheduler or CPU scheduler)

* CPU 와 메모리 사이의 스케줄링을 담당.
* Ready Queue 에 존재하는 프로세스 중 어떤 프로세스를 running 시킬지 결정.
* 프로세스에 CPU 를 할당(scheduler dispatch)
* 프로세스의 상태  
  ready -> running -> waiting -> ready

</br>

### 중기스케줄러(Medium-term scheduler or Swapper)

* 여유 공간 마련을 위해 프로세스를 통째로 메모리에서 디스크로 쫓아냄 (swapping)
* 프로세스에게서 memory 를 deallocate
* degree of Multiprogramming 제어
* 현 시스템에서 메모리에 너무 많은 프로그램이 동시에 올라가는 것을 조절하는 스케줄러.
* 프로세스의 상태  
  ready -> suspended

#### Process state - suspended

Suspended(stopped) : 외부적인 이유로 프로세스의 수행이 정지된 상태로 메모리에서 내려간 상태를 의미한다. 프로세스 전부 디스크로 swap out 된다. blocked 상태는 다른 I/O 작업을 기다리는 상태이기 때문에 스스로 ready state 로 돌아갈 수 있지만 이 상태는 외부적인 이유로 suspending 되었기 때문에 스스로 돌아갈 수 없다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-4-운영체제)

</br>

---

## CPU 스케줄러

_스케줄링 대상은 Ready Queue 에 있는 프로세스들이다._

### FCFS(First Come First Served)

#### 특징

* 먼저 온 고객을 먼저 서비스해주는 방식, 즉 먼저 온 순서대로 처리.
* 비선점형(Non-Preemptive) 스케줄링  
  일단 CPU 를 잡으면 CPU burst 가 완료될 때까지 CPU 를 반환하지 않는다. 할당되었던 CPU 가 반환될 때만 스케줄링이 이루어진다.

#### 문제점

* convoy effect  
  소요시간이 긴 프로세스가 먼저 도달하여 효율성을 낮추는 현상이 발생한다.

</br>

### SJF(Shortest - Job - First)

#### 특징

* 다른 프로세스가 먼저 도착했어도 CPU burst time 이 짧은 프로세스에게 선 할당
* 비선점형(Non-Preemptive) 스케줄링

#### 문제점

* starvation  
  효율성을 추구하는게 가장 중요하지만 특정 프로세스가 지나치게 차별받으면 안되는 것이다. 이 스케줄링은 극단적으로 CPU 사용이 짧은 job 을 선호한다. 그래서 사용 시간이 긴 프로세스는 거의 영원히 CPU 를 할당받을 수 없다.

</br>

### SRTF(Shortest Remaining Time First)

#### 특징

* 새로운 프로세스가 도착할 때마다 새로운 스케줄링이 이루어진다.
* 선점형 (Preemptive) 스케줄링  
  현재 수행중인 프로세스의 남은 burst time 보다 더 짧은 CPU burst time 을 가지는 새로운 프로세스가 도착하면 CPU 를 뺏긴다.

#### 문제점

* starvation
* 새로운 프로세스가 도달할 때마다 스케줄링을 다시하기 때문에 CPU burst time(CPU 사용시간)을 측정할 수가 없다.

</br>

### Priority Scheduling

#### 특징

* 우선순위가 가장 높은 프로세스에게 CPU 를 할당하는 스케줄링이다. 우선순위란 정수로 표현하게 되고 작은 숫자가 우선순위가 높다.
* 선점형 스케줄링(Preemptive) 방식  
  더 높은 우선순위의 프로세스가 도착하면 실행중인 프로세스를 멈추고 CPU 를 선점한다.
* 비선점형 스케줄링(Non-Preemptive) 방식  
  더 높은 우선순위의 프로세스가 도착하면 Ready Queue 의 Head 에 넣는다.

#### 문제점

* starvation
* 무기한 봉쇄(Indefinite blocking)  
  실행 준비는 되어있으나 CPU 를 사용못하는 프로세스를 CPU 가 무기한 대기하는 상태

#### 해결책

* aging  
  아무리 우선순위가 낮은 프로세스라도 오래 기다리면 우선순위를 높여주자.

</br>

### Round Robin

#### 특징

* 현대적인 CPU 스케줄링
* 각 프로세스는 동일한 크기의 할당 시간(time quantum)을 갖게 된다.
* 할당 시간이 지나면 프로세스는 선점당하고 ready queue 의 제일 뒤에 가서 다시 줄을 선다.
* `RR`은 CPU 사용시간이 랜덤한 프로세스들이 섞여있을 경우에 효율적
* `RR`이 가능한 이유는 프로세스의 context 를 save 할 수 있기 때문이다.

#### 장점

* `Response time`이 빨라진다.  
  n 개의 프로세스가 ready queue 에 있고 할당시간이 q(time quantum)인 경우 각 프로세스는 q 단위로 CPU 시간의 1/n 을 얻는다. 즉, 어떤 프로세스도 (n-1)q time unit 이상 기다리지 않는다.
* 프로세스가 기다리는 시간이 CPU 를 사용할 만큼 증가한다.  
  공정한 스케줄링이라고 할 수 있다.

#### 주의할 점

설정한 `time quantum`이 너무 커지면 `FCFS`와 같아진다.
또 너무 작아지면 스케줄링 알고리즘의 목적에는 이상적이지만 잦은 context switch 로 overhead 가 발생한다.
그렇기 때문에 적당한 `time quantum`을 설정하는 것이 중요하다.

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-4-운영체제)

</br>

---

## 동기와 비동기의 차이

### 비유를 통한 쉬운 설명

해야할 일(task)가 빨래, 설거지, 청소 세 가지가 있다고 가정한다. 이 일들을 동기적으로 처리한다면 빨래를 하고 설거지를 하고 청소를 한다.
비동기적으로 일을 처리한다면 빨래하는 업체에게 빨래를 시킨다. 설거지 대행 업체에 설거지를 시킨다. 청소 대행 업체에 청소를 시킨다. 셋 중 어떤 것이 먼저 완료될지는 알 수 없다. 일을 모두 마친 업체는 나에게 알려주기로 했으니 나는 다른 작업을 할 수 있다. 이 때는 백그라운드 스레드에서 해당 작업을 처리하는 경우의 비동기를 의미한다.

### Sync vs Async

일반적으로 동기와 비동기의 차이는 메소드를 실행시킴과 `동시에` 반환 값이 기대되는 경우를 **동기** 라고 표현하고 그렇지 않은 경우에 대해서 **비동기** 라고 표현한다. 동시에라는 말은 실행되었을 때 값이 반환되기 전까지는 `blocking`되어 있다는 것을 의미한다. 비동기의 경우, `blocking`되지 않고 이벤트 큐에 넣거나 백그라운드 스레드에게 해당 task 를 위임하고 바로 다음 코드를 실행하기 때문에 기대되는 값이 바로 반환되지 않는다.

_글로만 설명하기가 어려운 것 같아 그림과 함께 설명된 링크를 첨부합니다._

#### Reference

* http://asfirstalways.tistory.com/348

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-4-운영체제)

</br>

---

## 프로세스 동기화

### Critical Section(임계영역)

멀티스레딩의 문제점에서 나오듯, 동일한 자원을 동시에 접근하는 작업(e.g. 공유하는 변수 사용, 동일 파일을 사용하는 등)을 실행하는 코드 영역을 Critical Section 이라 칭한다.

### Critical Section Problem(임계영역 문제)

프로세스들이 Critical Section 을 함께 사용할 수 있는 프로토콜을 설계하는 것이다.

#### Requirements(해결을 위한 기본조건)

* Mutual Exclusion(상호 배제)  
  프로세스 P1 이 Critical Section 에서 실행중이라면, 다른 프로세스들은 그들이 가진 Critical Section 에서 실행될 수 없다.
* Progress(진행)  
  Critical Section 에서 실행중인 프로세스가 없고, 별도의 동작이 없는 프로세스들만 Critical Section 진입 후보로서 참여될 수 있다.
* Bounded Waiting(한정된 대기)  
  P1 가 Critical Section 에 진입 신청 후 부터 받아들여질 때가지, 다른 프로세스들이 Critical Section 에 진입하는 횟수는 제한이 있어야 한다.

### 해결책

### Mutex Lock

* 동시에 공유 자원에 접근하는 것을 막기 위해 Critical Section 에 진입하는 프로세스는 Lock 을 획득하고 Critical Section 을 빠져나올 때, Lock 을 방출함으로써 동시에 접근이 되지 않도록 한다.

#### 한계

* 다중처리기 환경에서는 시간적인 효율성 측면에서 적용할 수 없다.

### Semaphores(세마포)

* 소프트웨어상에서 Critical Section 문제를 해결하기 위한 동기화 도구

#### 종류

OS 는 Counting/Binary 세마포를 구분한다

* 카운팅 세마포  
  **가용한 개수를 가진 자원** 에 대한 접근 제어용으로 사용되며, 세마포는 그 가용한 **자원의 개수** 로 초기화 된다.
  자원을 사용하면 세마포가 감소, 방출하면 세마포가 증가 한다.

* 이진 세마포  
  MUTEX 라고도 부르며, 상호배제의 (Mutual Exclusion)의 머릿글자를 따서 만들어졌다.
  이름 그대로 0 과 1 사이의 값만 가능하며, 다중 프로세스들 사이의 Critical Section 문제를 해결하기 위해 사용한다.

#### 단점

* Busy Waiting(바쁜 대기)  
Spin lock이라고 불리는 Semaphore 초기 버전에서 Critical Section 에 진입해야하는 프로세스는 진입 코드를 계속 반복 실행해야 하며, CPU 시간을 낭비했었다. 이를 Busy Waiting이라고 부르며 특수한 상황이 아니면 비효율적이다.
일반적으로는 Semaphore에서 Critical Section에 진입을 시도했지만 실패한 프로세스에 대해 Block시킨 뒤, Critical Section에 자리가 날 때 다시 깨우는 방식을 사용한다. 이 경우 Busy waiting으로 인한 시간낭비 문제가 해결된다.

#### Deadlock(교착상태)

* 세마포가 Ready Queue 를 가지고 있고, 둘 이상의 프로세스가 Critical Section 진입을 무한정 기다리고 있고, Critical Section 에서 실행되는 프로세스는 진입 대기 중인 프로세스가 실행되야만 빠져나올 수 있는 상황을 지칭한다.

### 모니터

* 고급 언어의 설계 구조물로서, 개발자의 코드를 상호배제 하게끔 만든 추상화된 데이터 형태이다.
* 공유자원에 접근하기 위한 키 획득과 자원 사용 후 해제를 모두 처리한다. (세마포어는 직접 키 해제와 공유자원 접근 처리가 필요하다. )

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-4-운영체제)

---

## 메모리 관리 전략

### 메모리 관리 배경

각각의 **프로세스** 는 독립된 메모리 공간을 갖고, 운영체제 혹은 다른 프로세스의 메모리 공간에 접근할 수 없는 제한이 걸려있다. 단지, **운영체제** 만이 운영체제 메모리 영역과 사용자 메모리 영역의 접근에 제약을 받지 않는다.

**Swapping** : 메모리의 관리를 위해 사용되는 기법. 표준 Swapping 방식으로는 round-robin 과 같은 스케줄링의 다중 프로그래밍 환경에서 CPU 할당 시간이 끝난 프로세스의 메모리를 보조 기억장치(e.g. 하드디스크)로 내보내고 다른 프로세스의 메모리를 불러 들일 수 있다.

> 이 과정을 **swap** (**스왑시킨다**) 이라 한다. 주 기억장치(RAM)으로 불러오는 과정을 **swap-in**, 보조 기억장치로 내보내는 과정을 **swap-out** 이라 한다. swap 에는 큰 디스크 전송시간이 필요하기 때문에 현재에는 메모리 공간이 부족할때 Swapping 이 시작된다.

**단편화** (**Fragmentation**) : 프로세스들이 메모리에 적재되고 제거되는 일이 반복되다보면, 프로세스들이 차지하는 메모리 틈 사이에 사용 하지 못할 만큼의 작은 자유공간들이 늘어나게 되는데, 이것이 **단편화** 이다. 단편화는 2 가지 종류로 나뉜다.

| `Process A` | free | `Process B` | free | `Process C` | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; free &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | `Process D` |
| ----------- | ---- | ----------- | ---- | ----------- | :--------------------------------------------------------------------------------------: | ----------- |


* 외부 단편화: 메모리 공간 중 사용하지 못하게 되는 일부분. 물리 메모리(RAM)에서 사이사이 남는 공간들을 모두 합치면 충분한 공간이 되는 부분들이 **분산되어 있을때 발생한다고 볼 수 있다.**
* 내부 단편화: 프로세스가 사용하는 메모리 공간 에 포함된 남는 부분. 예를들어 **메모리 분할 자유 공간이 10,000B 있고 Process A 가 9,998B 사용하게되면 2B 라는 차이** 가 존재하고, 이 현상을 내부 단편화라 칭한다.

압축 : 외부 단편화를 해소하기 위해 프로세스가 사용하는 공간들을 한쪽으로 몰아, 자유공간을 확보하는 방법론 이지만, 작업효율이 좋지 않다. (위의 메모리 현황이 압축을 통해 아래의 그림 처럼 바뀌는 효과를 가질 수 있다)

| `Process A` | `Process B` | `Process C` | `Process D` | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; free &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; |
| ----------- | ----------- | ----------- | :---------: | ------------------------------------------------------------------------------------------------------------------ |


### Paging(페이징)

하나의 프로세스가 사용하는 메모리 공간이 연속적이어야 한다는 제약을 없애는 메모리 관리 방법이다.
외부 단편화와 압축 작업을 해소 하기 위해 생긴 방법론으로, 물리 메모리는 Frame 이라는 고정 크기로 분리되어 있고, 논리 메모리(프로세스가 점유하는)는 페이지라 불리는 고정 크기의 블록으로 분리된다.(페이지 교체 알고리즘에 들어가는 페이지)

페이징 기법을 사용함으로써 논리 메모리는 물리 메모리에 저장될 때, 연속되어 저장될 필요가 없고 물리 메모리의 남는 프레임에 적절히 배치됨으로 외부 단편화를 해결할 수 있는 큰 장점이 있다.

하나의 프로세스가 사용하는 공간은 여러개의 페이지로 나뉘어서 관리되고(논리 메모리에서), 개별 페이지는 **순서에 상관없이** 물리 메모리에 있는 프레임에 mapping 되어 저장된다고 볼 수 있다.

* 단점 : 내부 단편화 문제의 비중이 늘어나게 된다. 예를들어 페이지 크기가 1,024B 이고 **프로세스 A** 가 3,172B 의 메모리를 요구한다면 3 개의 페이지 프레임(1,024 \* 3 = 3,072) 하고도 100B 가 남기때문에 총 4 개의 페이지 프레임이 필요한 것이다. 결론적으로 4 번째 페이지 프레임에는 924B(1,024 - 100)의 여유 공간이 남게 되는 내부 단편화 문제가 발생하는 것이다.

### Segmentation(세그멘테이션)

페이징에서처럼 논리 메모리와 물리 메모리를 같은 크기의 블록이 아닌, 서로 다른 크기의 논리적 단위인 세그먼트(Segment)로 분할
사용자가 두 개의 주소로 지정(세그먼트 번호 + 변위)
세그먼트 테이블에는 각 세그먼트의 기준(세그먼트의 시작 물리 주소)과 한계(세그먼트의 길이)를 저장

* 단점 : 서로 다른 크기의 세그먼트들이 메모리에 적재되고 제거되는 일이 반복되다 보면, 자유 공간들이 많은 수의 작은 조각들로 나누어져 못 쓰게 될 수도 있다.(외부 단편화)


[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-4-운영체제)

---

## 가상 메모리

다중 프로그래밍을 실현하기 위해서는 많은 프로세스들을 동시에 메모리에 올려두어야 한다. 가상메모리는 **프로세스 전체가 메모리 내에 올라오지 않더라도 실행이 가능하도록 하는 기법** 이며, 프로그램이 물리 메모리보다 커도 된다는 주요 장점이 있다.

### 가상 메모리 개발 배경

실행되는 **코드의 전부를 물리 메모리에 존재시켜야** 했고, **메모리 용량보다 큰 프로그램은 실행시킬 수 없었다.** 또한, 여러 프로그램을 동시에 메모리에 올리기에는 용량의 한계와, 페이지 교체등의 성능 이슈가 발생하게 된다.
또한, 가끔만 사용되는 코드가 차지하는 메모리들을 확인할 수 있다는 점에서, 불필요하게 전체의 프로그램이 메모리에 올라와 있어야 하는게 아니라는 것을 알 수 있다.

#### 프로그램의 일부분만 메모리에 올릴 수 있다면...

* 물리 메모리 크기에 제약받지 않게 된다.
* 더 많은 프로그램을 동시에 실행할 수 있게 된다. 이에 따라 `응답시간`은 유지되고, `CPU 이용률`과 `처리율`은 높아진다.
* [swap](#메모리-관리-배경)에 필요한 입출력이 줄어들기 때문에 프로그램들이 빠르게 실행된다.

### 가상 메모리가 하는 일

가상 메모리는 실제의 물리 메모리 개념과 사용자의 논리 메모리 개념을 분리한 것으로 정리할 수 있다. 이로써 작은 메모리를 가지고도 얼마든지 큰 `가상 주소 공간`을 프로그래머에게 제공할 수 있다.

#### 가상 주소 공간

* 한 프로세스가 메모리에 저장되는 논리적인 모습을 가상메모리에 구현한 공간이다.
  프로세스가 요구하는 메모리 공간을 가상메모리에서 제공함으로써 현재 직접적으로 필요치 않은 메모리 공간은 실제 물리 메모리에 올리지 않는 것으로 물리 메모리를 절약할 수 있다.
* 예를 들어, 한 프로그램이 실행되며 논리 메모리로 100KB 가 요구되었다고 하자.
  하지만 실행까지에 필요한 메모리 공간`(Heap영역, Stack 영역, 코드, 데이터)`의 합이 40KB 라면, 실제 물리 메모리에는 40KB 만 올라가 있고, 나머지 60KB 만큼은 필요시에 물리메모리에 요구한다고 이해할 수 있겠다.

| `Stack` | &nbsp;&nbsp;&nbsp; free (60KB) &nbsp;&nbsp;&nbsp;&nbsp; | `Heap` | `Data` | `Code` |
| ------- | ------------------------------------------------------- | :----: | ------ | ------ |


#### 프로세스간의 페이지 공유

가상 메모리는...

* `시스템 라이브러리`가 여러 프로세스들 사이에 공유될 수 있도록 한다.
  각 프로세스들은 `공유 라이브러리`를 자신의 가상 주소 공간에 두고 사용하는 것처럼 인식하지만, 라이브러리가 올라가있는 `물리 메모리 페이지`들은 모든 프로세스에 공유되고 있다.
* 프로세스들이 메모리를 공유하는 것을 가능하게 하고, 프로세스들은 공유 메모리를 통해 통신할 수 있다.
  이 또한, 각 프로세스들은 각자 자신의 주소 공간처럼 인식하지만, 실제 물리 메모리는 공유되고 있다.
* `fork()`를 통한 프로세스 생성 과정에서 페이지들이 공유되는 것을 가능하게 한다.

### Demand Paging(요구 페이징)

프로그램 실행 시작 시에 프로그램 전체를 디스크에서 물리 메모리에 적재하는 대신, 초기에 필요한 것들만 적재하는 전략을 `요구 페이징`이라 하며, 가상 메모리 시스템에서 많이 사용된다. 그리고 가상 메모리는 대개 [페이지](#paging페이징)로 관리된다.
요구 페이징을 사용하는 가상 메모리에서는 실행과정에서 필요해질 때 페이지들이 적재된다. **한 번도 접근되지 않은 페이지는 물리 메모리에 적재되지 않는다.**

프로세스 내의 개별 페이지들은 `페이저(pager)`에 의해 관리된다. 페이저는 프로세스 실행에 실제 필요한 페이지들만 메모리로 읽어 옮으로써, **사용되지 않을 페이지를 가져오는 시간낭비와 메모리 낭비를 줄일 수 있다.**

#### Page fault trap(페이지 부재 트랩)

### 페이지 교체

`요구 페이징` 에서 언급된대로 프로그램 실행시에 모든 항목이 물리 메모리에 올라오지 않기 때문에, 프로세스의 동작에 필요한 페이지를 요청하는 과정에서 `page fault(페이지 부재)`가 발생하게 되면, 원하는 페이지를 보조저장장치에서 가져오게 된다. 하지만, 만약 물리 메모리가 모두 사용 중인 상황이라면, 페이지 교체가 이뤄져야 한다.(또는, 운영체제가 프로세스를 강제 종료하는 방법이 있다.)

#### 기본적인 방법

물리 메모리가 모두 사용 중인 상황에서의 메모리 교체 흐름이다.

1.  디스크에서 필요한 페이지의 위치를 찾는다
1.  빈 페이지 프레임을 찾는다.
    1.  `페이지 교체 알고리즘`을 통해 희생될(victim) 페이지를 고른다.
    1.  희생될 페이지를 디스크에 기록하고, 관련 페이지 테이블을 수정한다.
1.  새롭게 비워진 페이지 테이블 내 프레임에 새 페이지를 읽어오고, 프레임 테이블을 수정한다.
1.  사용자 프로세스 재시작

#### 페이지 교체 알고리즘

##### FIFO 페이지 교체

가장 간단한 페이지 교체 알고리즘으로 FIFO(first-in first-out)의 흐름을 가진다. 즉, 먼저 물리 메모리에 들어온 페이지 순서대로 페이지 교체 시점에 먼저 나가게 된다는 것이다.

* 장점

  * 이해하기도 쉽고, 프로그램하기도 쉽다.

* 단점
  * 오래된 페이지가 항상 불필요하지 않은 정보를 포함하지 않을 수 있다(초기 변수 등)
  * 처음부터 활발하게 사용되는 페이지를 교체해서 페이지 부재율을 높이는 부작용을 초래할 수 있다.
  * `Belady의 모순`: 페이지를 저장할 수 있는 페이지 프레임의 갯수를 늘려도 되려 페이지 부재가 더 많이 발생하는 모순이 존재한다.

##### 최적 페이지 교체(Optimal Page Replacement)

`Belady의 모순`을 확인한 이후 최적 교체 알고리즘에 대한 탐구가 진행되었고, 모든 알고리즘보다 낮은 페이지 부재율을 보이며 `Belady의 모순`이 발생하지 않는다. 이 알고리즘의 핵심은 `앞으로 가장 오랫동안 사용되지 않을 페이지를 찾아 교체`하는 것이다.
주로 비교 연구 목적을 위해 사용한다.

* 장점

  * 알고리즘 중 가장 낮은 페이지 부재율을 보장한다.

* 단점
  * 구현의 어려움이 있다. 모든 프로세스의 메모리 참조의 계획을 미리 파악할 방법이 없기 때문이다.

##### LRU 페이지 교체(LRU Page Replacement)

`LRU: Least-Recently-Used`  
최적 알고리즘의 근사 알고리즘으로, 가장 오랫동안 사용되지 않은 페이지를 선택하여 교체한다.

* 특징
  * 대체적으로 `FIFO 알고리즘`보다 우수하고, `OPT알고리즘`보다는 그렇지 못한 모습을 보인다.

##### LFU 페이지 교체(LFU Page Replacement)

`LFU: Least Frequently Used`  
참조 횟수가 가장 적은 페이지를 교체하는 방법이다. 활발하게 사용되는 페이지는 참조 횟수가 많아질 거라는 가정에서 만들어진 알고리즘이다.

* 특징
  * 어떤 프로세스가 특정 페이지를 집중적으로 사용하다, 다른 기능을 사용하게되면 더 이상 사용하지 않아도 계속 메모리에 머물게 되어 초기 가정에 어긋나는 시점이 발생할 수 있다
  * 최적(OPT) 페이지 교체를 제대로 근사하지 못하기 때문에, 잘 쓰이지 않는다.

##### MFU 페이지 교체(MFU Page Replacement)

`MFU: Most Frequently Used`  
참조 회수가 가장 작은 페이지가 최근에 메모리에 올라왔고, 앞으로 계속 사용될 것이라는 가정에 기반한다.

* 특징
  * 최적(OPT) 페이지 교체를 제대로 근사하지 못하기 때문에, 잘 쓰이지 않는다.

</br>

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-4-운영체제)

---

## 캐시의 지역성

### 캐시의 지역성 원리

캐시 메모리는 속도가 빠른 장치와 느린 장치 간의 속도 차에 따른 병목 현상을 줄이기 위한 범용 메모리이다. 이러한 역할을 수행하기 위해서는 CPU 가 어떤 데이터를 원할 것인가를 어느 정도 예측할 수 있어야 한다. 캐시의 성능은 작은 용량의 캐시 메모리에 CPU 가 이후에 참조할, 쓸모 있는 정보가 어느 정도 들어있느냐에 따라 좌우되기 때문이다.

이때 `적중율(hit rate)`을 극대화하기 위해 데이터 `지역성(locality)의 원리`를 사용한다. 지역성의 전제 조건으로 프로그램은 모든 코드나 데이터를 균등하게 access 하지 않는다는 특성을 기본으로 한다. 즉, `locality`란 기억 장치 내의 정보를 균일하게 access 하는 것이 아닌 어느 한순간에 특정 부분을 집중적으로 참조하는 특성이다.

데이터 지역성은 대표적으로 시간 지역성(temporal locality)과 공간 지역성(spatial locality)으로 나뉜다.

* 시간 지역성 : 최근에 참조된 주소의 내용은 곧 다음에 다시 참조되는 특성
* 공간 지역성 : 대부분의 실제 프로그램이 참조된 주소와 인접한 주소의 내용이 다시 참조되는 특성

</br>

### Caching Line

언급했듯이 캐시(cache)는 프로세서 가까이에 위치하면서 빈번하게 사용되는 데이터를 놔두는 장소이다. 하지만 캐시가 아무리 가까이 있더라도 찾고자 하는 데이터가 어느 곳에 저장되어 있는지 몰라 모든 데이터를 순회해야 한다면 시간이 오래 걸리게 된다. 즉, 캐시에 목적 데이터가 저장되어 있다면 바로 접근하여 출력할 수 있어야 캐시가 의미 있게 된다는 것이다.

그렇기 때문에 캐시에 데이터를 저장할 때 특정 자료 구조를 사용하여 `묶음`으로 저장하게 되는데 이를 **캐싱 라인** 이라고 한다. 프로세스는 다양한 주소에 있는 데이터를 사용하므로 빈번하게 사용하는 데이터의 주소 또한 흩어져 있다. 따라서 캐시에 저장하는 데이터에는 데이터의 메모리 주소 등을 기록해 둔 태그를 달아 놓을 필요가 있다. 이러한 태그들의 묶음을 캐싱 라인이라고 하고 메모리로부터 가져올 때도 캐싱 라인을 기준으로 가져온다.

종류로는 대표적으로 세 가지 방식이 존재한다.

1.  Full Associative
2.  Set Associative
3.  Direct Map

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-1-4-운영체제)

</br>

---

</br>

_OS.end_


================================================
FILE: Python/README.md
================================================
# Part 2-3 Python

* [Generator](#generator)
* [클래스를 상속했을 때 메서드 실행 방식](#클래스를-상속했을-때-메서드-실행-방식)
* [GIL 과 그로 인한 성능 문제](#gil-과-그로-인한-성능-문제)
* [GC 작동 방식](#gc-작동-방식)
* [Celery](#celery)
* [PyPy 가 CPython 보다 빠른 이유](#pypy-가-cpython-보다-빠른-이유)
* [메모리 누수가 발생할 수 있는 경우](#메모리-누수가-발생할-수-있는-경우)
* [Duck Typing](#Duck-Typing)
* [Timsort : Python의 내부 sort](#timsort--python의-내부-sort)

[뒤로](https://github.com/JaeYeopHan/for_beginner)

## Generator

[Generator(제네레이터)](https://docs.python.org/3/tutorial/classes.html#generators)는 제네레이터 함수가 호출될 때 반환되는 [iterator(이터레이터)](https://docs.python.org/3/tutorial/classes.html#iterators)의 일종이다. 제네레이터 함수는 일반적인 함수와 비슷하게 생겼지만 `yield 구문`을 사용해 데이터를 원하는 시점에 반환하고 처리를 다시 시작할 수 있다. 일반적인 함수는 진입점이 하나라면 제네레이터는 진입점이 여러개라고 생각할 수 있다. 이러한 특성때문에 제네레이터를 사용하면 원하는 시점에 원하는 데이터를 받을 수 있게된다.

### 예제

```python
>>> def generator():
...     yield 1
...     yield 'string'
...     yield True

>>> gen = generator()
>>> gen
<generator object generator at 0x10a47c678>
>>> next(gen)
1
>>> next(gen)
'string'
>>> next(gen)
True
>>> next(gen)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
```

### 동작

1.  yield 문이 포함된 제네레이터 함수를 실행하면 제네레이터 객체가 반환되는데 이 때는 함수의 내용이 실행되지 않는다.
2.  `next()`라는 빌트인 메서드를 통해 제네레이터를 실행시킬 수 있으며 `next()` 메서드 내부적으로 iterator 를 인자로 받아 이터레이터의 `__next__()` 메서드를 실행시킨다.
3.  처음 `__next__()` 메서드를 호출하면 함수의 내용을 실행하다 yield 문을 만났을 때 처리를 중단한다.
4.  이 때 모든 local state 는 유지되는데 변수의 상태, 명령어 포인터, 내부 스택, 예외 처리 상태를 포함한다.
5.  그 후 제어권을 상위 컨텍스트로 양보(yield)하고 또 `__next__()`가 호출되면 제네레이터는 중단된 시점부터 다시 시작한다.

> yield 문의 값은 어떤 메서드를 통해 제네레이터가 다시 동작했는지에 따라 다른데, `__next__()`를 사용하면 None 이고 `send()`를 사용하면 메서드로 전달 된 값을 갖게되어 외부에서 데이터를 입력받을 수 있게 된다.

### 이점

List, Set, Dict 표현식은 iterable(이터러블)하기에 for 표현식 등에서 유용하게 쓰일 수 있다. 이터러블 객체는 유용한 한편 모든 값을 메모리에 담고 있어야 하기 때문에 큰 값을 다룰 때는 별로 좋지 않다. 제네레이터를 사용하면 yield 를 통해 그때그때 필요한 값만을 받아 쓰기때문에 모든 값을 메모리에 들고 있을 필요가 없게된다.

> `range()`함수는 Python 2.x 에서 리스트를 반환하고 Python 3.x 에선 range 객체를 반환한다. 이 range 객체는 제네레이터, 이터레이터가 아니다. 실제로 `next(range(1))`를 호출해보면 `TypeError: 'range' object is not an iterator` 오류가 발생한다. 그렇지만 내부 구현상 제네레이터를 사용한 것 처럼 메모리 사용에 있어 이점이 있다.

```python
>>> import sys
>>> a = [i for i in range(100000)]
>>> sys.getsizeof(a)
824464
>>> b = (i for i in range(100000))
>>> sys.getsizeof(b)
88
```

다만 제네레이터는 그때그때 필요한 값을 던져주고 기억하지는 않기 때문에 `a 리스트`가 여러번 사용될 수 있는 반면 `b 제네레이터`는 한번 사용된 후 소진된다. 이는 모든 이터레이터가 마찬가지인데 List, Set 은 이터러블하지만 이터레이터는 아니기에 소진되지 않는다.

```python
>>> len(list(b))
100000
>>> len(list(b))
0
```

또한 `while True` 구문으로 제공받을 데이터가 무한하거나, 모든 값을 한번에 계산하기엔 시간이 많이 소요되어 그때 그때 필요한 만큼만 받아 계산하고 싶을 때 제네레이터를 활용할 수 있다.

### Generator, Iterator, Iterable 간 관계

![](http://nvie.com/img/relationships.png)

#### Reference

* [제네레이터 `__next__()` 메서드](https://docs.python.org/3/reference/expressions.html#generator.__next__)
* [제네레이터 `send()` 메서드](https://docs.python.org/3/reference/expressions.html#generator.send)
* [yield 키워드 알아보기](https://tech.ssut.me/2017/03/24/what-does-the-yield-keyword-do-in-python/)
* [Generator 와 yield 키워드](https://item4.github.io/2016-05-09/Generator-and-Yield-Keyword-in-Python/)
* [Iterator 와 Generator](http://pythonstudy.xyz/python/article/23-Iterator%EC%99%80-Generator)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-3-python)

</br>

## 클래스를 상속했을 때 메서드 실행 방식

인스턴스의 메서드를 실행한다고 가정할 때 `__getattribute__()`로 bound 된 method 를 가져온 후 메서드를 실행한다. 메서드를 가져오는 순서는 `__mro__`에 따른다. MRO(method resolution order)는 메소드를 확인하는 순서로 파이썬 2.3 이후 C3 알고리즘이 도입되어 지금까지 사용되고있다. 단일상속 혹은 다중상속일 때 어떤 순서로 메서드에 접근할지는 해당 클래스의 `__mro__`에 저장되는데 왼쪽에 있을수록 우선순위가 높다. B, C 를 다중상속받은 D 클래스가 있고, B 와 C 는 각각 A 를 상속받았을 때(다이아몬드 상속) D 의 mro 를 조회하면 볼 수 있듯이 부모클래스는 반드시 자식클래스 이후에 위치해있다. 최상위 object 클래스까지 확인했는데도 적절한 메서드가 없으면 `AttributeError`를 발생시킨다.

```python
class A:
    pass

class B(A):
    pass

class C(A):
    pass

class D(B, C):
    pass

>>> D.__mro__
(__main__.D, __main__.B, __main__.C, __main__.A, object)
```

![](https://makina-corpus.com/blog/metier/2014/python-mro-conflict)

Python 2.3 이후 위 이미지와 같은 상속을 시도하려하면 `TypeError: Cannot create a consistent method resolution` 오류가 발생한다.

#### Reference

* [INHERITANCE(상속), MRO](https://kimdoky.github.io/python/2017/11/28/python-inheritance.html)
* [What does mro do](https://stackoverflow.com/questions/2010692/what-does-mro-do)
* [Python 2.3 이후의 MRO 알고리즘에 대한 파이썬 공식 문서](https://www.python.org/download/releases/2.3/mro/)
* [What is a method in python](https://stackoverflow.com/questions/3786881/what-is-a-method-in-python/3787670#3787670)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-3-python)

</br>

## GIL 과 그로 인한 성능 문제

GIL 때문에 성능 문제가 대두되는 경우는 압축, 정렬, 인코딩 등 수행시간에 CPU 의 영향이 큰 작업(CPU bound)을 멀티 스레드로 수행하도록 한 경우다. 이 땐 GIL 때문에 멀티 스레드로 작업을 수행해도 싱글 스레드일 때와 별반 차이가 나지 않는다. 이를 해결하기 위해선 멀티 스레드는 파일, 네트워크 IO 같은 IO bound 프로그램에 사용하고 멀티 프로세스를 활용해야한다.

### GIL(Global Interpreter Lock)

GIL 은 스레드에서 사용되는 Lock 을 인터프리터 레벨로 확장한 개념인데 여러 스레드가 동시에 실행되는걸 방지한다. 더 정확히 말하자면 어느 시점이든 하나의 Bytecode 만이 실행되도록 강제한다. 각 스레드는 다른 스레드에 의해 GIL 이 해제되길 기다린 후에야 실행될 수 있다. 즉 멀티 스레드로 만들었어도 본질적으로 싱글 스레드로 동작한다.

![](https://cdn-images-1.medium.com/max/1600/1*hqWXEQmyMZCGzAAxrd0N0g.png)

<sup> _출처 [mjhans83 님의 python GIL](https://medium.com/@mjhans83/python-gil-f940eac0bef9)_ </sup>

### GIL 의 장점

코어 개수는 점점 늘어만 가는데 이 GIL 때문에 그 장점을 제대로 살리지 못하기만 하는 것 같으나 이 GIL 로 인한 장점도 존재한다. GIL 을 활용한 멀티 스레드가 그렇지 않은 멀티 스레드보다 구현이 쉬우며, 레퍼런스 카운팅을 사용하는 메모리 관리 방식에서 GIL 덕분에 오버헤드가 적어 싱글 스레드일 때 [fine grained lock 방식](https://fileadmin.cs.lth.se/cs/Education/EDA015F/2013/Herlihy4-5-presentation.pdf)보다 성능이 우월하다. 또한 C extension 을 활용할 때 GIL 은 해제되므로 C library 를 사용하는 CPU bound 프로그램을 멀티 스레드로 실행하는 경우 더 빠를 수 있다.

#### Reference

* [동시성과 병렬성](https://www.slideshare.net/deview/2d4python)
* [Understanding the Python GIL](http://www.dabeaz.com/python/UnderstandingGIL.pdf)
* [Threads and the GIL](http://jessenoller.com/blog/2009/02/01/python-threads-and-the-global-interpreter-lock)
* [Python GIL](https://medium.com/@mjhans83/python-gil-f940eac0bef9)
* [Old GIL 과 New GIL](https://blog.naver.com/parkjy76/30167429369)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-3-python)

</br>

## GC 작동 방식

파이썬에선 기본적으로 [garbage collection](https://docs.python.org/3/glossary.html#term-garbage-collection)(가비지 컬렉션)과 [reference counting](https://docs.python.org/3/glossary.html#term-reference-count)(레퍼런스 카운팅)을 통해 할당 된 메모리를 관리한다. 기본적으로 참조 횟수가 0 이된 객체를 메모리에서 해제하는 레퍼런스 카운팅 방식을 사용하지만, 참조 횟수가 0 은 아니지만 도달할 수 없는 상태인 reference cycles(순환 참조)가 발생했을 때는 가비지 컬렉션으로 그 상황을 해결한다.

> 엄밀히 말하면 레퍼런스 카운팅 방식을 통해 객체를 메모리에서 해제하는 행위가 가비지 컬렉션의 한 형태지만 여기서는 순환 참조가 발생했을 때 cyclic garbage collector 를 통한 **가비지 컬렉션**과 **레퍼런스 카운팅**을 통한 가비지 컬렉션을 구분했다.

여기서 '순환 참조가 발생한건 어떻게 탐지하지?', '주기적으로 감시한다면 그 주기의 기준은 뭘까?', '가비지 컬렉션은 언제 발생하지?' 같은 의문이 들 수 있는데 이 의문을 해결하기 전에 잠시 레퍼런스 카운팅, 순환 참조, 파이썬의 가비지 컬렉터에 대한 간단한 개념을 짚고 넘어가자. 이 개념을 알고 있다면 바로 [가비지 컬렉션의 작동 방식 단락](#가비지-컬렉션의-작동-방식)을 읽으면 된다.

#### 레퍼런스 카운팅

모든 객체는 참조당할 때 레퍼런스 카운터를 증가시키고 참조가 없어질 때 카운터를 감소시킨다. 이 카운터가 0 이 되면 객체가 메모리에서 해제한다. 어떤 객체의 레퍼런스 카운트를 보고싶다면 `sys.getrefcount()`로 확인할 수 있다.

<details>
    <summary>
        <code>Py_INCREF()</code>와 <code>Py_DECREF()</code>를 통한 카운터 증감
    </summary>
<br>

카운터를 증감시키는 명령은 아래와 같이 [object.h](https://github.com/python/cpython/blob/master/Include/object.h)에 선언되어있는데 카운터를 증가시킬 때는 단순히 `ob_refcnt`를 1 증가시키고 감소시킬때는 1 감소시킴과 동시에 카운터가 0 이되면 메모리에서 객체를 해제하는 것을 확인할 수 있다.

```c
#define Py_INCREF(op) (                         \
    _Py_INC_REFTOTAL  _Py_REF_DEBUG_COMMA       \
    ((PyObject *)(op))->ob_refcnt++)

#define Py_DECREF(op)                                   \
    do {                                                \
        PyObject *_py_decref_tmp = (PyObject *)(op);    \
        if (_Py_DEC_REFTOTAL  _Py_REF_DEBUG_COMMA       \
        --(_py_decref_tmp)->ob_refcnt != 0)             \
            _Py_CHECK_REFCNT(_py_decref_tmp)            \
        else                                            \
            _Py_Dealloc(_py_decref_tmp);                \
    } while (0)
```

더 정확한 정보는 [파이썬 공식 문서](https://docs.python.org/3/extending/extending.html#reference-counting-in-python)를 참고하면 자세하게 설명되어있다.

</details>

#### 순환 참조

순환 참조의 간단한 예제는 자기 자신을 참조하는 객체다.

```python
>>> l = []
>>> l.append(l)
>>> del l
```

`l`의 참조 횟수는 1 이지만 이 객체는 더이상 접근할 수 없으며 레퍼런스 카운팅 방식으로는 메모리에서 해제될 수 없다.

또 다른 예로는 서로를 참조하는 객체다.

```python
>>> a = Foo()  # 0x60
>>> b = Foo()  # 0xa8
>>> a.x = b  # 0x60의 x는 0xa8를 가리킨다.
>>> b.x = a  # 0xa8의 x는 0x60를 가리킨다.
# 이 시점에서 0x60의 레퍼런스 카운터는 a와 b.x로 2
# 0xa8의 레퍼런스 카운터는 b와 a.x로 2다.
>>> del a  # 0x60은 1로 감소한다. 0xa8은 b와 0x60.x로 2다.
>>> del b  # 0xa8도 1로 감소한다.
```

이 상태에서 `0x60.x`와 `0xa8.x`가 서로를 참조하고 있기 때문에 레퍼런스 카운트는 둘 다 1 이지만 도달할 수 없는 가비지가 된다.

#### 가비지 컬렉터

파이썬의 `gc` 모듈을 통해 가비지 컬렉터를 직접 제어할 수 있다. `gc` 모듈은 [cyclic garbage collection 을 지원](https://docs.python.org/3/c-api/gcsupport.html)하는데 이를 통해 reference cycles(순환 참조)를 해결할 수 있다. gc 모듈은 오로지 순환 참조를 탐지하고 해결하기위해 존재한다. [`gc` 파이썬 공식문서](https://docs.python.org/3/library/gc.html)에서도 순환 참조를 만들지 않는다고 확신할 수 있으면 `gc.disable()`을 통해 garbage collector 를 비활성화 시켜도 된다고 언급하고 있다.

> Since the collector supplements the reference counting already used in Python, you can disable the collector if you are sure your program does not create reference cycles.

### 가비지 컬렉션의 작동 방식

순환 참조 상태도 해결할 수 있는 cyclic garbage collection 이 어떤 방식으로 동작하는지는 결국 **어떤 기준으로 가비지 컬렉션이 발생**하고 **어떻게 순환 참조를 감지**하는지에 관한 내용이다. 이에 대해 차근차근 알아보자.

#### 어떤 기준으로 가비지 컬렉션이 일어나는가

앞에서 제기했던 의문은 결국 발생 기준에 관한 의문이다. 가비지 컬렉터는 내부적으로 `generation`(세대)과 `threshold`(임계값)로 가비지 컬렉션 주기와 객체를 관리한다. 세대는 0 세대, 1 세대, 2 세대로 구분되는데 최근에 생성된 객체는 0 세대(young)에 들어가고 오래된 객체일수록 2 세대(old)에 존재한다. 더불어 한 객체는 단 하나의 세대에만 속한다. 가비지 컬렉터는 0 세대일수록 더 자주 가비지 컬렉션을 하도록 설계되었는데 이는 [generational hypothesis](http://www.memorymanagement.org/glossary/g.html#term-generational-hypothesis)에 근거한다.

<details>
    <summary>generational hypothesis의 두 가지 가설</summary>
<br>

* 대부분의 객체는 금방 도달할 수 없는 상태(unreachable)가 된다.
* 오래된 객체(old)에서 젊은 객체(young)로의 참조는 아주 적게 존재한다.

![](https://plumbr.io/wp-content/uploads/2015/05/object-age-based-on-GC-generation-generational-hypothesis.png)
<sup> _출처 [plumbr.io](https://plumbr.io/handbook/garbage-collection-in-java/generational-hypothesis)_ </sup>

* [Reference: Naver D2 - Java Garbage Collection](http://d2.naver.com/helloworld/1329)

<hr>
</details>

주기는 threshold 와 관련있는데 `gc.get_threshold()`로 확인해 볼 수 있다.

```python
>>> gc.get_threshold()
(700, 10, 10)
```

각각 `threshold 0`, `threshold 1`, `threshold 2`을 의미하는데 n 세대에 객체를 할당한 횟수가 `threshold n`을 초과하면 가비지 컬렉션이 수행되며 이 값은 변경될 수 있다.

0 세대의 경우 메모리에 객체가 할당된 횟수에서 해제된 횟수를 뺀 값, 즉 객체 수가 `threshold 0`을 초과하면 실행된다. 다만 그 이후 세대부터는 조금 다른데 0 세대 가비지 컬렉션이 일어난 후 0 세대 객체를 1 세대로 이동시킨 후 카운터를 1 증가시킨다. 이 1 세대 카운터가 `threshold 1`을 초과하면 그 때 1 세대 가비지 컬렉션이 일어난다. 러프하게 말하자면 0 세대 가비지 컬렉션이 객체 생성 700 번만에 일어난다면 1 세대는 7000 번만에, 2 세대는 7 만번만에 일어난다는 뜻이다.

이를 말로 풀어서 설명하려니 조금 복잡해졌지만 간단하게 말하면 메모리 할당시 `generation[0].count++`, 해제시 `generation[0].count--`가 발생하고, `generation[0].count > threshold[0]`이면 `genreation[0].count = 0`, `generation[1].count++`이 발생하고 `generation[1].count > 10`일 때 0 세대, 1 세대 count 를 0 으로 만들고 `generation[2].count++`을 한다는 뜻이다.

[gcmodule.c 코드로 보기](https://github.com/python/cpython/blob/master/Modules/gcmodule.c#L832-L836)

#### 라이프 사이클

이렇듯 가비지 컬렉터는 세대와 임계값을 통해 가비지 컬렉션의 주기를 관리한다. 이제 가비지 컬렉터가 어떻게 순환 참조를 발견하는지 알아보기에 앞서 가비지 컬렉션의 실행 과정(라이프 사이클)을 간단하게 알아보자.

새로운 객체가 만들어 질 때 파이썬은 객체를 메모리와 0 세대에 할당한다. 만약 0 세대의 객체 수가 `threshold 0`보다 크면 `collect_generations()`를 실행한다.

<details>
    <summary>코드와 함께하는 더 자세한 설명</summary>
<br>

새로운 객체가 만들어 질 때 파이썬은 `_PyObject_GC_Alloc()`을 호출한다. 이 메서드는 객체를 메모리에 할당하고, 가비지 컬렉터의 0 세대의 카운터를 증가시킨다. 그 다음 0 세대의 객체 수가 `threshold 0`보다 큰지, `gc.enabled`가 true 인지, `threshold 0`이 0 이 아닌지, 가비지 컬렉션 중이 아닌지 확인하고, 모든 조건을 만족하면 `collect_generations()`를 실행한다.

다음은 `_PyObject_GC_Alloc()`을 간략화 한 소스며 메서드 전체 내용은 [여기](https://github.com/python/cpython/blob/master/Modules/gcmodule.c#L1681-L1710)에서 확인할 수 있다.

```c
_PyObject_GC_Alloc() {
    // ...

    gc.generations[0].count++; /* 0세대 카운터 증가 */
    if (gc.generations[0].count > gc.generations[0].threshold && /* 임계값을 초과하며 */
        gc.enabled &&  /* 사용가능하며 */
        gc.generations[0].threshold &&  /* 임계값이 0이 아니고 */
        !gc.collecting)  /* 컬렉션 중이 아니면 */
    {
        gc.collecting = 1;
        collect_generations();
        gc.collecting = 0;
    }
    // ...
}
```

참고로 `gc`를 끄고싶으면 `gc.disable()`보단 `gc.set_threshold(0)`이 더 확실하다. `disable()`의 경우 서드 파티 라이브러리에서 `enable()`하는 경우가 있다고 한다.

<hr>
</details>

`collect_generations()`이 호출되면 모든 세대(기본적으로 3 개의 세대)를 검사하는데 가장 오래된 세대(2 세대)부터 역으로 확인한다. 해당 세대에 객체가 할당된 횟수가 각 세대에 대응되는 `threshold n`보다 크면 `collect()`를 호출해 가비지 컬렉션을 수행한다.

<details>
    <summary>코드</summary>
<br>

`collect()`가 호출될 때 해당 세대보다 어린 세대들은 모두 통합되어 가비지 컬렉션이 수행되기 때문에 `break`를 통해 검사를 중단한다.

다음은 `collect_generations()`을 간략화 한 소스며 메서드 전체 내용은 [여기](https://github.com/python/cpython/blob/master/Modules/gcmodule.c#L1020-L1056)에서 확인할 수 있다.

```c
static Py_ssize_t
collect_generations(void)
{
    int i;
    for (i = NUM_GENERATIONS-1; i >= 0; i--) {
        if (gc.generations[i].count > gc.generations[i].threshold) {
            collect_with_callback(i);
            break;
        }
    }
}

static Py_ssize_t
collect_with_callback(int generation)
{
    // ...
    result = collect(generation, &collected, &uncollectable, 0);
    // ...
}
```

<hr>
</details>

`collect()` 메서드는 **순환 참조 탐지 알고리즘**을 수행하고 특정 세대에서 도달할 수 있는 객체(reachable)와 도달할 수 없는 객체(unreachable)를 구분하고 도달할 수 없는 객체 집합을 찾는다. 도달할 수 있는 객체 집합은 다음 상위 세대로 합쳐지고(0 세대에서 수행되었으면 1 세대로 이동), 도달할 수 없는 객체 집합은 콜백을 수행 한 후 메모리에서 해제된다.

이제 정말 **순환 참조 탐지 알고리즘**을 알아볼 때가 됐다.

#### 어떻게 순환 참조를 감지하는가

먼저 순환 참조는 컨테이너 객체(e.g. `tuple`, `list`, `set`, `dict`, `class`)에 의해서만 발생할 수 있음을 알아야한다. 컨테이너 객체는 다른 객체에 대한 참조를 보유할 수 있다. 그러므로 정수, 문자열은 무시한채 관심사를 컨테이너 객체에만 집중할 수 있다.

순환 참조를 해결하기 위한 아이디어로 모든 컨테이너 객체를 추적한다. 여러 방법이 있겠지만 객체 내부의 링크 필드에 더블 링크드 리스트를 사용하는 방법이 가장 좋다. 이렇게 하면 추가적인 메모리 할당 없이도 **컨테이너 객체 집합**에서 객체를 빠르게 추가하고 제거할 수 있다. 컨테이너 객체가 생성될 때 이 집합에 추가되고 제거될 때 집합에서 삭제된다.

<details>
    <summary>
        <code>PyGC_Head</code>에 선언된 더블 링크드 리스트
    </summary>
<br>

더블 링크드 리스트는 다음과 같이 선언되어 있으며 [objimpl.h 코드](https://github.com/python/cpython/blob/master/Include/objimpl.h#L250-L259)에서 확인해볼 수 있다.

```c
#ifndef Py_LIMITED_API
typedef union _gc_head {
    struct {
        union _gc_head *gc_next;
        union _gc_head *gc_prev;
        Py_ssize_t gc_refs;
    } gc;
    double dummy;  /* force worst-case alignment */
} PyGC_Head;
```

<hr>
</details>

이제 모든 컨테이터 객체에 접근할 수 있으니 순환 참조를 찾을 수 있어야 한다. 순환 참조를 찾는 과정은 다음과 같다.

1.  객체에 `gc_refs` 필드를 레퍼런스 카운트와 같게 설정한다.
2.  각 객체에서 참조하고 있는 다른 컨테이너 객체를 찾고, 참조되는 컨테이너의 `gc_refs`를 감소시킨다.
3.  `gc_refs`가 0 이면 그 객체는 컨테이너 집합 내부에서 자기들끼리 참조하고 있다는 뜻이다.
4.  그 객체를 unreachable 하다고 표시한 뒤 메모리에서 해제한다.

이제 우리는 가비지 콜렉터가 어떻게 순환 참조 객체를 탐지하고 메모리에서 해제하는지 알았다.

#### 예제

> 아래 예제는 보기 쉽게 가공한 예제이며 실제 `collect()`의 동작과는 차이가 있다. 정확한 작동 방식은 아래에서 다시 서술한다. 혹은 [`collect()` 코드](https://github.com/python/cpython/blob/master/Modules/gcmodule.c#L797-L981)를 참고하자.

아래의 예제를 통해 가비지 컬렉터가 어떤 방법으로 순환 참조 객체인 `Foo(0)`과 `Foo(1)`을 해제하는지 알아보겠다.

```python
a = [1]
# Set: a:[1]
b = ['a']
# Set: a:[1] <-> b:['a']
c = [a, b]
# Set: a:[1] <-> b:['a'] <-> c:[a, b]
d = c
# Set: a:[1] <-> b:['a'] <-> c,d:[a, b]
# 컨테이너 객체가 생성되지 않았기에 레퍼런스 카운트만 늘어난다.
e = Foo(0)
# Set: a:[1] <-> b:['a'] <-> c,d:[a, b] <-> e:Foo(0)
f = Foo(1)
# Set: a:[1] <-> b:['a'] <-> c,d:[a, b] <-> e:Foo(0) <-> f:Foo(1)
e.x = f
# Set: a:[1] <-> b:['a'] <-> c,d:[a, b] <-> e:Foo(0) <-> f,Foo(0).x:Foo(1)
f.x = e
# Set: a:[1] <-> b:['a'] <-> c,d:[a, b] <-> e,Foo(1).x:Foo(0) <-> f,Foo(0).x:Foo(1)
del e
# Set: a:[1] <-> b:['a'] <-> c,d:[a, b] <-> Foo(1).x:Foo(0) <-> f,Foo(0).x:Foo(1)
del f
# Set: a:[1] <-> b:['a'] <-> c,d:[a, b] <-> Foo(1).x:Foo(0) <-> Foo(0).x:Foo(1)
```

위 상황에서 각 컨테이너 객체의 레퍼런스 카운트는 다음과 같다.

```py
# ref count
[1]     <- a,c      = 2
['a']   <- b,c      = 2
[a, b]  <- c,d      = 2
Foo(0)  <- Foo(1).x = 1
Foo(1)  <- Foo(0).x = 1
```

1 번 과정에서 각 컨테이너 객체의 `gc_refs`가 설정된다.

```py
# gc_refs
[1]    = 2
['a']  = 2
[a, b] = 2
Foo(0) = 1
Foo(1) = 1
```

2 번 과정에서 컨테이너 집합을 순회하며 `gc_refs`을 감소시킨다.

```py
[1]     = 1  # [a, b]에 의해 참조당하므로 1 감소
['a']   = 1  # [a, b]에 의해 참조당하므로 1 감소
[a, b]  = 2  # 참조당하지 않으므로 그대로
Foo(0)  = 0  # Foo(1)에 의해 참조당하므로 1 감소
Foo(1)  = 0  # Foo(0)에 의해 참조당하므로 1 감소
```

3 번 과정을 통해 `gc_refs`가 0 인 순환 참조 객체를 발견했다. 이제 이 객체를 unreachable 집합에 옮겨주자.

```py
 unreachable |  reachable
             |    [1] = 1
 Foo(0) = 0  |  ['a'] = 1
 Foo(1) = 0  | [a, b] = 2
```

이제 `Foo(0)`와 `Foo(1)`을 메모리에서 해제하면 가비지 컬렉션 과정이 끝난다.

### 더 정확하고 자세한 설명

`collect()` 메서드는 현재 세대와 어린 세대를 합쳐 순환 참조를 검사한다. 이 합쳐진 세대를 `young`으로 이름 붙이고 다음의 과정을 거치며 최종적으로 도달 할 수 없는 객체가 모인 unreachable 리스트를 메모리에서 해제하고 young 에 남아있는 객체를 다음 세대에 할당한다.

```c
update_refs(young)
subtract_refs(young)
gc_init_list(&unreachable)
move_unreachable(young, &unreachable)
```

`update_refs()`는 모든 객체의 레퍼런스 카운트 사본을 만든다. 이는 가비지 컬렉터가 실제 레퍼런스 카운트를 건드리지 않게 하기 위함이다.

`subtract_refs()`는 각 객체 i 에 대해 i 에 의해 참조되는 객체 j 의 `gc_refs`를 감소시킨다. 이 과정이 끝나면 (young 세대에 남아있는 객체의 레퍼런스 카운트) - (남아있는 `gc_refs`) 값이 old 세대에서 young 세대를 참조하는 수와 같다.

`move_unreachable()` 메서드는 young 세대를 스캔하며 `gc_refs`가 0 인 객체를 `unreachable` 리스트로 이동시키고 `GC_TENTATIVELY_UNREACHABLE`로 설정한다. 왜 완전히 `unreachable`이 아닌 임시로(Tentatively) 설정하냐면 나중에 스캔될 객체로부터 도달할 수도 있기 때문이다.

<details>
    <summary>예제 보기</summary>
<br>

```py
a, b = Foo(0), Foo(1)
a.x = b
b.x = a
c = b
del a
del b

# 위 상황을 요약하면 다음과 같다.
Foo(0).x = Foo(1)
Foo(1).x = Foo(0)
c = Foo(1)
```

이 때 상황은 다음과 같은데 `Foo(0)`의 `gc_refs`가 0 이어도 뒤에 나올 `Foo(1)`을 통해 도달 할 수 있다.

|  young   | ref count | gc_refs | reachable |
| :------: | :-------: | :-----: | :-------: |
| `Foo(0)` |     1     |    0    |   `c.x`   |
| `Foo(1)` |     2     |    1    |    `c`    |

<hr>
</details>

0 이 아닌 객체는 `GC_REACHABLE`로 설정하고 그 객체가 참조하고 있는 객체 또한 찾아가(traverse) `GC_REACHABLE`로 설정한다. 만약 그 객체가 `unreachable` 리스트에 있던 객체라면 `young` 리스트의 끝으로 보낸다. 굳이 `young`의 끝으로 보내는 이유는 그 객체 또한 다른 `gc_refs`가 0 인 객체를 참조하고 있을 수 있기 때문이다.

<details>
    <summary>예제 보기</summary>
<br>

```py
a, b = Foo(0), Foo(1)
a.x = b
b.x = a
c = b
d = Foo(2)
d.x = d
a.y = d
del d
del a
del b

# 위 상황을 요약하면 다음과 같다.
Foo(0).x = Foo(1)
Foo(1).x = Foo(0)
c = Foo(1)
Foo(0).y = Foo(2)
```

|  young   | ref count | gc_refs | reachable |
| :------: | :-------: | :-----: | :-------: |
| `Foo(0)` |     1     |    0    |   `c.x`   |
| `Foo(1)` |     2     |    1    |    `c`    |
| `Foo(2)` |     1     |    0    |  `c.x.y`  |

이 상황에서 `Foo(0)`은 `unreachable` 리스트에 있다가 `Foo(1)`을 조사하며 다시 `young` 리스트의 맨 뒤로 돌아왔고, `Foo(2)`도 `unreachable` 리스트에 갔지만 곧 `Foo(0)`에 의해 참조될 수 있음을 알고 다시 `young` 리스트로 돌아온다.

<hr>
</details>

`young` 리스트의 전체 스캔이 끝나면 이제 `unreachable` 리스트에 있는 객체는 **정말 도달할 수 없다**. 이제 이 객체들을 메모리에서 해제되고 `young` 리스트의 객체들은 상위 세대로 합쳐진다.

#### Reference

* [Instagram 이 gc 를 없앤 이유](https://b.luavis.kr/python/dismissing-python-garbage-collection-at-instagram)
* [파이썬 Garbage Collection](http://weicomes.tistory.com/277)
* [Finding reference cycle](https://www.kylev.com/2009/11/03/finding-my-first-python-reference-cycle/)
* [Naver D2 - Java Garbage Collection](http://d2.naver.com/helloworld/1329)
* [gc 의 threshold](https://docs.python.org/3/library/gc.html#gc.set_threshold)
* [Garbage Collection for Python](http://www.arctrix.com/nas/python/gc/)
* [How does garbage collection in Python work](https://www.quora.com/How-does-garbage-collection-in-Python-work-What-are-the-pros-and-cons)
* [gcmodule.c](https://github.com/python/cpython/blob/master/Modules/gcmodule.c)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-3-python)

</br>

## Celery

[Celery](http://www.celeryproject.org/)는 메시지 패싱 방식의 분산 비동기 작업 큐다. 작업(Task)은 브로커(Broker)를 통해 메시지(Message)로 워커(Worker)에 전달되어 처리된다. 작업은 멀티프로세싱, eventlet, gevent 를 사용해 하나 혹은 그 이상의 워커에서 동시적으로 실행되며 백그라운드에서 비동기적으로 실행될 수 있다.

#### Reference

* [Spoqa - Celery 를 이용한 긴 작업 처리](https://spoqa.github.io/2012/05/29/distribute-task-with-celery.html)
* [[번역]셀러리 입문하기](https://beomi.github.io/2017/03/19/Introduction-to-Celery/)
* [Python Celery with Redis](http://dgkim5360.tistory.com/entry/python-celery-asynchronous-system-with-redis)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-3-python)

</br>

## PyPy 가 CPython 보다 빠른 이유

간단히 말하면 CPython 은 일반적인 인터프리터인데 반해 PyPy 는 [실행 추적 JIT(Just In Time) 컴파일](https://en.wikipedia.org/wiki/Tracing_just-in-time_compilation)을 제공하는 인터프리터기 때문이다. PyPy 는 RPython 으로 컴파일된 인터프리터인데, C 로 작성된 RPython 툴체인으로 인터프리터 소스에 JIT 컴파일을 위한 힌트를 추가해 CPython 보다 빠른 실행 속도를 가질 수 있게 되었다.

### PyPy

PyPy 는 파이썬으로 만들어진 파이썬 인터프리터다. 일반적으로 파이썬 인터프리터를 다시 한번 파이썬으로 구현한 것이기에 속도가 매우 느릴거라 생각하지만 실제 PyPy 는 [스피드 센터](http://speed.pypy.org/)에서 볼 수 있듯 CPython 보다 빠르다.

### 실행 추적 JIT 컴파일

메소드 단위로 최적화 하는 전통적인 JIT 과 다르게 런타임에서 자주 실행되는 루프를 최적화한다.

### RPython(Restricted Python)

[RPython](https://rpython.readthedocs.io/en/latest/index.html)은 이런 실행 추적 JIT 컴파일을 C 로 구현해 툴체인을 포함한다. 그래서 RPython 으로 인터프리터를 작성하고 툴체인으로 힌트를 추가하면 인터프리터에 실행추적 JIT 컴파일러를 빌드한다. 참고로 RPython 은 PyPy 프로젝트 팀이 만든 일종의 인터프리터 제작 프레임워크(언어)다. 동적 언어인 Python 에서 표준 라이브러리와 문법에 제약을 가해 변수의 정적 컴파일이 가능하도록 RPython 을 만들었으며, 동적 언어 인터프리터를 구현하는데 사용된다.

이렇게 언어 사양(파이썬 언어 규칙, BF 언어 규칙 등)과 구현(실제 인터프리터 제작)을 분리함으로써 어떤 동적 언어에 대해서라도 자동으로 JIT(Just-in-Time) 컴파일러를 생성할 수 있게 되었다.

#### Reference

* [RPython 공식 레퍼런스](https://rpython.readthedocs.io/en/latest/)
* [PyPy - wikipedia](https://en.wikipedia.org/wiki/PyPy)
* [PyPy 가 CPython 보다 빠를 수 있는 이유 - memorable](https://memorable.link/link/188)
* [PyPy 와 함께 인터프리터 작성하기](https://www.haruair.com/blog/1882)
* [알파희 - PyPy/RPython 으로 20 배 빨라지는 아희 JIT 인터프리터](https://www.slideshare.net/YunWonJeong/pypyrpython-20-jit)
* [PyPy 가 CPython 보다 빠를 수 있는 이유 - 홍민희](https://blog.hongminhee.org/2011/05/02/5124874464/)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-3-python)

</br>

## 메모리 누수가 발생할 수 있는 경우

> 메모리 누수를 어떻게 정의하냐에 따라 조금 다르다. `a = 1`을 선언한 후에 프로그램에서 더 이상 `a`를 사용하지 않아도 이것을 메모리 누수라고 볼 수 있다. 다만 여기서는 사용자의 부주의로 인해 발생하는 메모리 누수만 언급한다.

대표적으로 mutable 객체를 기본 인자값으로 사용하는 경우에 메모리 누수가 일어난다.

```python
def foo(a=[]):
    a.append(time.time())
    return a
```

위의 경우 `foo()`를 호출할 때마다 기본 인자값인 `a`에 타임스탬프 값이 추가된다. 이는 의도하지 않은 결과를 초래하므로 보통의 경우 `a=None`으로 두고 함수 내부에서 `if a is None` 구문으로 빈 리스트를 할당해준다.

다른 경우로 웹 애플리케이션에서 timeout 이 없는 캐시 데이터를 생각해 볼 수 있다. 요청이 들어올수록 캐시 데이터는 쌓여만 가는데 이를 해제할 루틴을 따로 만들어두지 않는다면 이도 메모리 누수를 초래한다.

클래스 내 `__del__` 메서드를 재정의하는 행위도 메모리 누수를 일으킬 수 있다. 순환 참조 중인 클래스가 `__del__` 메서드를 재정의하고 있다면 가비지 컬렉터로 해제되지 않는다.

#### Reference

* [Is it possible to have an actual memory leak?](https://stackoverflow.com/questions/2017381/is-it-possible-to-have-an-actual-memory-leak-in-python-because-of-your-code)
* [파이썬에서 메모리 누수가 발생할 수 있는 경우 - memorable](https://memorable.link/link/189)
* [약한 참조 사용하기](https://soooprmx.com/archives/5074)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-3-python)

</br>

## Duck Typing

Duck typing이란 특히 동적 타입을 가지는 프로그래밍 언어에서 많이 사용되는 개념으로, 객체의 실제 타입보다는 객체의 변수와 메소드가 그 객체의 적합성을 결정하는 것을 의미한다. Duck typing이라는 용어는 흔히 [duck test](https://en.wikipedia.org/wiki/Duck_test)라고 불리는 한 구절에서 유래됐다.

> If it walks like a duck and it quacks like a duck, then it must be a duck.
>
> 만일 그 새가 오리처럼 걷고, 오리처럼 꽥꽥거린다면 그 새는 오리일 것이다.

동적 타입 언어인 파이썬은 메소드 호출이나 변수 접근시 타입 검사를 하지 않으므로 duck typing을 넒은 범위에서 활용할 수 있다. 
다음은 간단한 duck typing의 예시다.

```py
class Duck:
    def walk(self):
        print('뒤뚱뒤뚱')

    def quack(self):
        print('Quack!')

class Mallard:  # 청둥오리
    def walk(self):
        print('뒤뚱뒤뒤뚱뒤뚱')

    def quack(self):
        print('Quaaack!')

class Dog:
    def run(self):
        print('타다다다')

    def bark(self):
        print('왈왈')


def walk_and_quack(animal):
    animal.walk()
    animal.quack()


walk_and_quack(Duck())  # prints '뒤뚱뒤뚱', prints 'Quack!'
walk_and_quack(Mallard())  # prints '뒤뚱뒤뒤뚱뒤뚱', prints 'Quaaack!'
walk_and_quack(Dog())  # AttributeError : 'Dog' object has no attribute 'walk'
```

위 예시에서 `Duck` 과 `Mallard` 는 둘 다 `walk()` 와 `quack()` 을 구현하고 있기 때문에 `walk_and_quack()` 이라는 함수의 인자로서 **적합하다**.
그러나 `Dog` 는 두 메소드 모두 구현되어 있지 않으므로 해당 함수의 인자로서 부적합하다. 즉, `Dog` 는 적절한 duck typing에 실패한 것이다.

Python에서는 다양한 곳에서 duck typing을 활용한다. `__len__()`을 구현하여 _길이가 있는 무언가_ 를 표현한다던지 (흔히 [listy](https://cs.gmu.edu/~kauffman/cs310/w04-2.pdf)하다고 표현한다), 또는 `__iter__()` 와 `__getitem__()` 을 구현하여 [iterable](https://docs.python.org/3/glossary.html#term-iterable)을 duck-typing한다.
굳이 `Iterable` (가명) 이라는 interface를 상속받지 않고 `__iter__()`와 `__getitem__()`을 구현하기만 하면 `for ... in` 에서 바로 사용할 수 있다.

이와 같은 방식은 일반적으로 `interface`를 구현하거나 클래스를 상속하는 방식으로 
인자나 변수의 적합성을 runtime 이전에 판단하는 정적 타입 언어들과 비교된다.
자바나 스칼라에서는 `interface`, c++는 `template` 을 활용하여 타입의 적합성을 보장한다. 
(c++의 경우 `template`으로 duck typing과 같은 효과를 낼 수 있다 [참고](http://www.drdobbs.com/templates-and-duck-typing/184401971))


#### Reference

* [Templates and Duck Typing](http://www.drdobbs.com/templates-and-duck-typing/184401971)
* [Strong and Weak Typing](https://en.wikipedia.org/wiki/Strong_and_weak_typing)
* [Python Duck Typing - or, what is an interface?](https://infohost.nmt.edu/tcc/help/pubs/python/web/interface.html)
* [Quora : What is duck typing in python?](https://www.quora.com/What-is-Duck-typing-in-Python)
* [Duck Test](https://en.wikipedia.org/wiki/Duck_test)


[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-3-python)

</br>

## Timsort : Python의 내부 sort

python의 내부 sort는 timsort 알고리즘으로 구현되어있다.
2.3 버전부터 적용되었으며, merge sort와 insert sort가 병합된 형태의 안정정렬이다. 

timsort는 merge sort의 최악 시간 복잡도와 insert sort의 최고 시간 복잡도를 보장한다. 따라서 O(n) ~ O(n log n)의 시간복잡도를 보장받을 수 있고, 공간복잡도의 경우에도 최악의 경우 O(n)의 공간복잡도를 가진다. 또한 안정정렬으로 동일한 키를 가진 요소들의 순서가 섞이지 않고 보장된다.

timsort를 좀 더 자세하게 이해하고 싶다면 [python listsort](https://github.com/python/cpython/blob/24e5ad4689de9adc8e4a7d8c08fe400dcea668e6/Objects/listsort.txt) 참고.

#### Reference

* [python listsort](https://github.com/python/cpython/blob/24e5ad4689de9adc8e4a7d8c08fe400dcea668e6/Objects/listsort.txt)
* [Timsort wikipedia](https://en.wikipedia.org/wiki/Timsort)

[뒤로](https://github.com/JaeYeopHan/for_beginner)/[위로](#part-2-3-python)

_Python.end_


================================================
FILE: README.md
================================================
<div align=center>

![](/assets/images/tech_interview_main.png)

</div>

# Technical Interview Guidelines for Beginners

<div align=center>

<a href="https://twitter.com/JbeeLjyhanll">
<img alt="Twitter: JbeeLjyhanll" src="https://img.shields.io/twitter/follow/JbeeLjyhanll.svg?style=social" target="_blank" />
</a>

[![author](https://img.shields.io/badge/author-jbee-ff69b4.svg?style=flat-square)](https://jbee.io/about)
[![CONTRIBUTORS](https://img.shields.io/badge/contributors-75-green.svg?style=flat-square)](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/blob/master/CONTRIBUTING.md)
[![LICENSE](https://img.shields.io/dub/l/vibe-d.svg?style=flat-square)](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/blob/master/LICENSE)

<a href="https://github.com/JaeYeopHan/Interview_Question_for_Beginner/graphs/contributors"><img src="https://opencollective.com/interview_question_for_beginner/contributors.svg?width=720"></a>

</div>

> 해당 Repository 에 기여를 해주신 분들입니다. 감사합니다. :pray:

</br>

## :memo: Table of Contents

- [What is this?](#what-is-this)
- [면접에서 받았던 질문들](#면접에서-받았던-질문들)
- [Part 1. CS](#part-1-전산-기초)
  - [개발상식](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/Development_common_sense)
  - [자료구조](https://github.com/JaeYeopHan/for_beginner/tree/master/DataStructure)
  - [네트워크](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/Network)
  - [운영체제](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/OS)
  - [데이터베이스](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/Database)
  - [디자인패턴](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/DesignPattern)
  - [알고리즘](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/Algorithm)
- [Part 2. Language](#part-2-language)
  - [Java](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/Java)
  - [JavaScript](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/JavaScript)
  - [Python](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/Python)
- [Part 3. 분야별 정리](#part-3-분야별)
  - [FrontEnd](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/FrontEnd)
  - [iOS](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/iOS)
  - [Machine Learning](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/MachineLearning)
- [그 외 좋은 자료 추천](#그-외-좋은-자료)

</br>

</br>

# What is this?

예비 개발자들 또는 개발자들의 기술 면접 준비를 위한 자료를 정리해놓은 저장소입니다. 개발이라는 분야를 모두 담지는 못했습니다. 그저 가이드라인으로 참고해주시면 감사하겠습니다. 또한 제가 개인적으로 면접을 준비하면서 정리한 내용이라 잘못된 부분이 있을 수 있습니다. 이런 부분들에 대해서는 `Pull Request` or `Issue`로 참여해주시면 정말 감사하겠습니다. 주제와 관련된 좋은 참고 자료를 추가하는 것도 가능합니다. 해당 Repository 에서 학습을 하시다가 생기는 질문은 `Issue`에 올려주세요!

> 취준생 여러분의 건승을 기원합니다 :thumbsup:

### :sparkles: HELP

##### :pray: [HOW TO CONTRIBUTE](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/blob/master/CONTRIBUTING.md)

##### :star: 이 저장소는 PR 과 star 를 먹고 자랍니다.

</br>

</br>

---

### [면접에서 받았던 질문들](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/issues/59)

해당 Issue 에서 실제로 받았던 면접 질문들을 공유할 수 있습니다.

---


### [회사에 궁금한 점이 있으신가요?](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/Reverse_Interview)

인터뷰를 마치고 한번씩은 반드시 들어봤을 질문입니다. 이 때 어떠한 질문을 하면 좋을까요? 적절한 질문들을 정리해둔 Reverse Interview 목록입니다.

---

# Part 1. 전산 기초

## :bulb: 개발상식 [Link](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/Development_common_sense)

- 좋은 코드란 무엇인가?
- 객체 지향 프로그래밍이란 무엇인가?
- RESTFul API 란?
- TDD 란 무엇이며 어떠한 장점이 있는가?
- 함수형 프로그래밍이란?
- MVC 패턴이란 무엇인가?
- Git 과 GitHub 에 대해서

</br>

## :bulb: 자료구조 [Link](https://github.com/JaeYeopHan/for_beginner/tree/master/DataStructure)

- Array vs Linked List
- Stack and Queue
- Tree
  - Binary Tree
  - Full Binary Tree
  - Complete Binary Tree
  - BST (Binary Search Tree)
- Binary Heap
- Red-Black Tree
  - 정의
  - 특징
  - 삽입
  - 삭제
- Hash Table
  - Hash Function
  - Resolve Collision
    - Open Addressing
    - Separate Chaining
  - Resize
- Graph
  - Graph 용어 정리
  - Graph 구현
  - Graph 탐색
  - Minimum Spanning Tree
    - Kruskal algorithm
    - Prim algorithm

</br>

## :bulb: 네트워크 [Link](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/Network)

- GET, POST 방식의 차이점
- TCP 3-way-handshake
- TCP 와 UDP 의 차이점
- HTTP 와 HTTPS 의 차이점
  - HTTP 의 문제점들
- DNS round robin 방식
- 웹 통신의 큰 흐름

</br>

## :bulb: 운영체제 [Link](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/OS)

- 프로세스와 스레드의 차이
- 스케줄러의 종류
  - 장기 스케줄러
  - 단기 스케줄러
  - 중기 스케줄러
- CPU 스케줄러
  - FCFS
  - SJF
  - SRT
  - Priority scheduling
  - RR
- 동기와 비동기의 차이
- 멀티스레드
  - 장점과 단점
- 프로세스 동기화
  - Critical Section
  - 해결책
- 메모리 관리 전략
  - 메모리 관리 배경
  - Paging
  - Segmentation
- 가상 메모리
  - 배경
  - 가상 메모리가 하는 일
  - Demand Paging (요구 페이징)
  - 페이지 교체 알고리즘
- 캐시의 지역성
  - Locality
  - Caching line

</br>

## :bulb: 데이터베이스 [Link](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/Database)

- 데이터베이스
  - 데이터베이스를 사용하는 이유
  - 데이터베이스 성능
- Index
  - Index 란 무엇인가
  - Index 의 자료구조
  - Primary index vs Secondary index
  - Composite index
  - Index 의 성능과 고려해야할 사항
- 정규화에 대해서
  - 정규화 탄생 배경
  - 정규화란 무엇인가
  - 정규화의 종류
  - 정규화의 장단점
- Transaction
  - 트랜잭션(Transaction)이란 무엇인가?
  - 트랜잭션과 Lock
  - 트랜잭션의 특성
  - 트랜잭션의 상태
  - 트랜잭션을 사용할 때 주의할 점
- Statement vs PreparedStatement
- NoSQL
  - 정의
  - CAP 이론
    - 일관성
    - 가용성
    - 네트워크 분할 허용성
  - 저장방식에 따른 분류
    - Key-Value Model
    - Document Model
    - Column Model

#### 추가자료

- [DBMS 는 어떻게 트랜잭션을 관리할까?](https://d2.naver.com/helloworld/407507)

</br>

## :bulb: Design Pattern [Link](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/DesignPattern)

- Singleton

</br>

## :bulb: Algorithm (알고리즘) [Link](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/Algorithm)

- 손코딩 및 코딩 테스트 대비
  => 대부분의 내용이 코드이기 때문에 별도의 [Java Algorithm Training Repository](https://github.com/JaeYeopHan/algorithm_basic_java)에 저장합니다.
- 코딩 테스트를 위한 Tip
- 문제 해결을 위한 전략적 접근
- Sorting Algorithm
- Prime Number Algorithm

</br>

<sup>[(목차로 돌아가기)](#technical-interview-guidelines-for-beginners)</sup>

</br>

---

</br>

# Part 2. Language

## :gem: Java [Link](https://github.com/JaeYeopHan/Beginner_for_interview/tree/master/Java)

- JVM 에 대해서 / GC 의 원리
- Collection
- Annotation
- Generic
- final
- Overriding vs Overloading
- Access Modifier
- Wrapper class
- Multi-Thread 환경에서의 개발

#### 추가 자료

- [Java 기본서 비교](http://asfirstalways.tistory.com/146)

</br>

## :gem: JavaScript [Link](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/JavaScript)

- JavaScript Event Loop
- Hoisting
- Closure
- this 에 대해서
- Promise

#### 추가 자료

- [JavaScript 기본서 비교](http://asfirstalways.tistory.com/246)
- [ECMAScript6 정리](https://jaeyeophan.github.io/categories/ECMAScript6)
- [Interview Algorithm Questions in JavaScript (영어)](https://github.com/kennymkchan/interview-questions-in-javascript)
  - JavaScript 와 관련된 인터뷰 관련 내용들을 정리해놓은 자료입니다.
    </br>

## :gem: Python [Link](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/Python)

- Generator
- 클래스를 상속했을 때 메서드 실행 방식
- GIL 과 그로인한 성능 문제
- GC 작동 방식
- Celery
- PyPy 가 CPython 보다 빠른 이유
- 메모리 누수가 발생할 수 있는 경우
- Duck Typing
- Timsort : Python의 내부 sort

#### 추가 자료

- [asyncio 와 놀아보기](https://tech.ssut.me/python-3-play-with-asyncio/)
- [metaclasses 이해하기](https://tech.ssut.me/understanding-python-metaclasses/)

</br>

<sup>[(목차로 돌아가기)](#technical-interview-guidelines-for-beginners)</sup>

</br>

---

</br>

# Part 3. 분야별

## :large_orange_diamond: Front-End [Link](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/FrontEnd)

- 브라우저의 작동 원리
- Document Object Model
  - Event Bubbling and Capturing
  - Event delegation
- CORS
- 크로스 브라우징
- 웹 성능과 관련된 Issues
- 서버 사이드 렌더링 vs 클라이언트 사이드 렌더링
- CSS Methodology
- normalize.css vs reset.css
- 그 외 프론트엔드 개발 환경 관련

#### 추가 자료

- [신입 프론트엔드 개발자가 되려면 무엇을 학습해야 하나요?](https://jbee.io/essay/for_junior_frontend_developer/)
- [Front-end Developer Interview Questions (한국어)](https://h5bp.org/Front-end-Developer-Interview-Questions/translations/korean/)
- [Front-end Interview (영어)](http://thatjsdude.com/interview/index.html)
- [Front-end Checklist](https://github.com/kesuskim/Front-End-Checklist)
  - 면접 시 물어보기 가장 좋은 것들이 '기본'에 대한 내용이라고 생각되는데요, 그 '기본'에 대해 체크리스트 형식으로 잘 정리되어 있는 문서를 공유합니다.
- [Front End Interview Handbook (한국어)](https://www.frontendinterviewhandbook.com/)
- [React 구조에 대한 고민 시리즈](https://jbee.io/react/react-0-intro/)

</br>

## :large_orange_diamond: iOS [Link](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/iOS)

- App Life Cycle
- View Life Cycle
- Delegate vs Block vs Notification
- Memory Management
- assign vs weak
- Frame vs Bounds
- 기타 질문

#### 추가 자료

- [iOS 면접 질문 정리 사이트 1](https://github.com/MaximAbramchuck/awesome-interview-questions#objective-c)
- [iOS 면접 질문 정리 사이트 2](https://github.com/MaximAbramchuck/awesome-interview-questions#ios)
- [Swift 를 공부하기 위한 정보 링크 모음 레포](https://github.com/ClintJang/awesome-swift-korean-lecture)

</br>

## :large_orange_diamond: Machine Learning [Link](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/MachineLearning)

- Cost Function

#### 추가 자료

- [모두를 위한 머신러닝/딥러닝 강의](http://hunkim.github.io/ml/)

</br>

<sup>[(목차로 돌아가기)](#technical-interview-guidelines-for-beginners)</sup>

</br>

---

</br>

## 그 외 좋은 자료

- [소프트웨어 엔지니어의 이력서](https://jbee.io/essay/swe-resume/)
- [미세먼지 같은 면접 팁](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/Tip)
- [주니어 개발자를 위한 취업 정보](https://github.com/jojoldu/junior-recruit-scheduler)
- [mission-peace/interview](https://github.com/mission-peace/interview)
  - 각종 알고리즘에 대한 코드와 동영상 강의 링크를 제공합니다. (영어)
- [awesome-interview-questions](https://github.com/MaximAbramchuck/awesome-interview-questions)
  - 각종 언어, CS 기초에 대한 interview 질문들이 정리되어 있습니다. (영어)
- [coding-interview-university](https://github.com/jwasham/coding-interview-university/blob/master/translations/README-ko.md)
  - 구글 인터뷰를 준비하면서 정리한 자료가 한국어로 번역되어 있는 자료입니다. (한국어 version)
- [코딩 인터뷰 완전분석](http://www.yes24.com/24/Goods/44305533?Acode=101)
  - (도서) 코딩 인터뷰에 관련된 도서 중 가장 유명한 책이라고 생각되는데요, 최근 개정판이 발간되었습니다.
- [tech-interview-handbook](https://github.com/yangshun/tech-interview-handbook)
  - 코딩 인터뷰에 관련되어 정리되어있는 respository 입니다. (영어)
- [A perfect guide for cracking a JavaScript interview (A developer's perspective)](https://medium.com/dev-bits/a-perfect-guide-for-cracking-a-javascript-interview-a-developers-perspective-23a5c0fa4d0d)
  - [@JayJin](https://github.com/milooy)님이 추천하신 자바스크립트 인터뷰 아티클입니다.

</br>

---

</br>

</br>

### License

[MIT](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/blob/master/LICENSE)


================================================
FILE: Reverse_Interview/README.md
================================================
# Reverse Interview

> [@JaeYeopHan](https://github.com/JaeYeopHan): 한국어로 번역을 진행하다보니 현재 한국 상황에 맞게 끔 약간씩 수정을 했습니다. 또 낯선 용어가 있을 수 있어 해당 내용을 보충했습니다. 그만큼 의역도 많으니 본문도 함께 보시길 추천드립니다. (_원문: https://github.com/viraptor/reverse-interview_)

## 👨‍💻 회사에 궁금한 점은 없으신가요?

인터뷰를 마치고 한번씩은 들어봤을 질문이다. 이 때 어떠한 질문을 하면 좋을까? 적절한 질문들을 항목별로 정리해둔 Reverse Interview Question 목록이다.

## 💡이 목록을 이렇게 사용하길 기대합니다.

### 1. 우선 검색으로 스스로 찾을 수 있는 질문인지 확인해보세요.

- 요즘 회사는 많은 정보를 공개하고 있다. 인터넷에서 검색만으로 쉽게 접할 수 있는 것을 질문한다면 안 좋은 인상을 줄 수 있다. 지원하는 회사에 대해 충분히 알아본 후, 어떠한 질문을 할 지 생각해보자.

### 2. 당신 상황에서 어떤 질문이 흥미로운지 생각해보세요.

- 여기에서 '상황'이란 지원한 회사, 팀일 수 있고 자신이 지원한 포지션과 관련된 것을 말한다.

### 3. 그런 다음 질문하면 좋을 것 같아요.

- 확실한 건, 아래 리스트를 **전부 물어보려고 하면 좋지 않으니** 그러지 말자.

<br />

<br />

# 💁‍♂️ 역할 (The Role)

- on-call에 대한 계획 또는 시스템이 있나요? 있다면 어떻게 될까요? (그에 대한 대가는 무엇이 있나요?)
  - `on-call`이란 팀에서 업무 시간 외에 문제를 해결할 사람을 로테이션으로 지정하는 문화를 말한다.
- 평상 시 업무에는 어떠한 것들이 있나요? 제가 맡게 될 업무에는 어떠한 것들이 있을까요?
- 팀의 주니어 / 시니어 구성 밸런스는 어떻게 되나요? (그것을 바꿀 계획이 있나요?)
- 온보딩(onboarding)은 어떻게 이루어지나요?
  - `onboarding` 이란 조직 내 새로 합류한 사람이 빠르게 조직의 문화를 익히고 적응하도록 돕는 과정을 말한다.
- 제공된 목록에서 작업하는 것과 비교하여 얼마나 독립적 인 행동이 예상됩니까?
- 기대하는 근무시간, 핵심 근무 시간(core work hours)은 몇 시간인가요? 몇시부터 몇시까지 인가요?
  - `core work hours` 란 자율 출퇴근 시 출퇴근 시간이 사람마다 다를 수 있는데 이 때, 오피스에 상주하거나 회의에 참석할 수 있는 시간을 말한다.
- (제가 지원한) 이 포지션의 '성공'에 대한 정의는 무엇인가요? 개발 조직 (또는 팀)에서 목표로 하고 있는 KPI가 있나요?
  - KPI란 Key Performance Indicator의 줄임말로 핵심 성과 지표라고 할 수 있다. 개인이나 조직의 전략 달성에 대한 기여도를 측정하는 지표를 말한다.
- 제 지원에 대해 혹시 우려 사항이 있을까요? 
- 제가 가장 가까이 일할 사람에 대해서 이야기해 주실 수 있을까요?
- 제 직속 상사와 그 위 상사의 관리 스타일은 어떤가요? (마이크로 매니징 혹은 매크로 매니징) 

# 🚀 기술 (Tech)

- 회사 또는 팀 내에서 주로 사용되는 기술 스택은 무엇인가요? 현재 제품은 어떤 기술 스택으로 만들어져 있나요?
- 소스 컨트롤(버전 관리)은 어떻게 이루어지고 있나요?
- 작성한 코드는 보통 어떻게 테스트가 이루어지나요?
  - 표준화된 테스트 환경이 있는지 테스트 코드는 어느 정도 작성되고 있는지를 포함할 수 있는 질문이라고 생각한다.
  - 지원한 회사의 주요 프로덕트와 팀, 포지션과 관련하여 좀 더 질문을 구체화 할 수 있다. 앱 내 웹뷰를 만드는 팀이라면 작성한 웹뷰 코드를 테스트할 수 있는 프로세스를 질문할 수 있다.
- 버그는 어떻게 보고되고 어떻게 관리되고 있나요?
  - 어떤 BTS(Bug Tracking System)을 사용하고 있는지 질문을 구체화 할 수 있다.
  - 좀 더 구체적으로는 QA 팀이 있는지, 협업은 어떻게 이루어지는지도 물어볼 수 있다.
- 변경 사항을 어떻게 통합하고 배포하나요? CI / CD는 어떻게 이루어지고 있나요?
- 버전 관리에 기반한 인프라 설정이 있나요? / 관리는 어떻게 이루어지나요?
- 일반적으로 기획(planning)부터 배포까지 진행되는 워크 플로우(Work Flow)에 대해 설명해주실 수 있나요?
- 장애에 대한 대응은 어떻게 이루어지나요?
- 팀 내에서 표준화 된 개발 환경이 있나요?
- 제품에 대한 로컬 테스트 환경을 설정할 수 있는 프로세스가 있나요?
- 코드나 의존성(dependencies) 보안 이슈에 대해서 얼마나 빠르게 검토하고 있나요? 
- 모든 개발자들에게 자신 컴퓨터 로컬 어드민에 접근하는 걸 허용하고 있나요?
- 당신의 기술적 생각 혹은 비전에 대해 말씀해 주실 수 있을까요? 
- 코드에 대한 개발자 문서가 있나요? 고객을 위한 별도의 문서가 또 있을까요?
- 정적 코드 분석기를 사용하고 있나요?
- 내부/외부 산출물 관리는 어떻게 하고 있나요? 
- 의존성 관리는 어떻게 하고 있나요?
- 개발문서의 작성은 어떻게 하고 있나요?
- 테스트 환경과 실제 운영 환경의 차이점이 어떻게 되나요?
- 장애 발생시 대응 메뉴얼이나 문서가 존재하나요?
- 사용하고 있는 클라우드 서비스가 있나요?

# 👨‍👩‍👧‍👧 팀 (The Team)

- 현재 팀에서 이루어지고 있는 작업(Task)은 어떻게 구성되어 있나요?
- 팀 내 / 팀 간 커뮤니케이션은 보통 어떻게 이루어지나요? 어떤 도구를 사용하나요?
- 구성원간의 의견 차이가 발생할 경우 어떻게 의사 결정이 이루어지나요?
- 주어진 작업에 대해서 누가 우선 순위와 일정을 정하나요?
- 해당 내용에 대해 다른 의견을 제시한다면(pushback) 그 다음 의사 결정이 어떻게 이루어지나요?
- 매주 어떤 종류의 회의가 있나요?
- 제품 또는 서비스 배포 주기는 어떻게 이루어지나요? (주간 릴리스 / 연속 배포 / 다중 릴리스 스트림 / ...)
- 제품에서 장애가 발생할 경우 추가 대응은 어떻게 이루어지나요? 책임자를 찾고 탓하지 않는(blameless) 문화가 팀 내에 있나요?
- 팀이 아직 해결하지 못한 문제는 무엇이 있나요?
  - 불필요한 반복 작업을 자동화하지 못한 부분이 있나요?
  - 채용 시 필요한 인재에 대한 기준이 명확하게 자리 잡았나요?
- 프로젝트 진행 상황은 어떻게 관리하고 있나요?
- 기대치와 목표 설정은 어떻게 하고 있으며, 누가 정하나요?
- 코드 리뷰는 어떠한 방식으로 하나요?
- 기술적 목표와 비지니스 목표의 균형은 어떠한가요? 
- 역자 추가) 팀 내 기술 공유 어떻게 이루어지고 있나요?
- 팀원들의 서로에 대한 호칭은 무엇인가요?
 
# 👩‍💻 미래의 동료들 (Your Potential Coworkers)
- 그들이 여기서 일함으로써 가장 좋은 점은 뭔가요?
- 그럼, 가장 싫어하는 점은 뭔가요? 
- 만약 가능하다면, 바꾸고 싶은 것은 무엇인가요? 
- 이 팀에서 가장 오래 일한 사람은 얼마나 다니셨나요? 

# 🏬 회사 (The Company)

- 회의 또는 출장에 대한 예산이 있나요? 이를 사용하는 규칙은 무엇인가요?
- 승진을 위한 별도의 과정이 있나요? 일반적인 요구 사항이나 기대치는 어떻게 전달받나요?
- 기술직과 경영직은 분리되어 있나요?
- 연간 / 개인 / 병가 / 부모 / 무급 휴가는 얼마입니까?
- 현재 회사에서 진행중인 채용 상태는 어떤가요?
- 전자 책 구독 또는 온라인 강좌와 같이 학습에 사용할 수있는 전사적 리소스가 있나요?
- 이를 지원 받기 위한 예산이 있나요?
- FOSS 프로젝트에 기여할 수 있나요? 별도 승인이 필요한가요?
  - FOSS란 Free and Open Source Software, 즉 오픈소스 프로젝트를 말한다.
- 경업 금지 약정(Non-compete agreement)나 기밀 유지 협약서(non-disclosure agreement)에 사인해야하나요?
- 앞으로 5/10년 후의 이 회사가 위치에 있을 거라 생각하나요?
- 회사 문화의 격차가 무엇이라고 생각하나요? 
- 이 회사의 개발자들에게 클린 코드는 어떤 의미인가요? 
- 최근, 이 회사에서 성장하고 있다라고 생각이 든 사람이 있었나요? 어떻게 성장하고 있었나요? 
- 이 회사에서의 성공이란 무엇인가요? 그리고 그걸 어떻게 측정하나요? 
- 이 회사에서 워라밸(work-life balance)은 어떤 의미 인가요? 

# 💥 충돌 (Conflict) 

- 구성원간의 의견 차이가 발생할 경우 어떻게 의사 결정이 이루어지나요?
- 해당 내용에 대해 다른 의견을 제시한다면(pushback) 그 다음 의사 결정이 어떻게 이루어지나요? (예를 들어, "이건 기간 안에 못 할 것 같습니다.") 
- 불가능한 일의 
Download .txt
gitextract_jfqhlcxv/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── Bug_report.md
│   │   ├── Comments.md
│   │   ├── Enhancement.md
│   │   ├── New_resources.md
│   │   ├── Questions.md
│   │   └── Suggestions.md
│   ├── ISSUE_TEMPLATE.md
│   └── PULL_REQUEST_TEMPLATE.md
├── .prettierrc
├── Algorithm/
│   └── README.md
├── CONTRIBUTING.md
├── DataStructure/
│   └── README.md
├── Database/
│   └── README.md
├── DesignPattern/
│   └── README.md
├── Development_common_sense/
│   └── README.md
├── FrontEnd/
│   └── README.md
├── Java/
│   └── README.md
├── JavaScript/
│   └── README.md
├── LICENSE
├── MachineLearning/
│   └── README.md
├── Network/
│   └── README.md
├── OS/
│   ├── README.en.md
│   └── README.md
├── Python/
│   └── README.md
├── README.md
├── Reverse_Interview/
│   └── README.md
├── Tip/
│   └── README.md
└── iOS/
    └── README.md
Condensed preview — 28 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (212K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/Bug_report.md",
    "chars": 70,
    "preview": "---\nname: 🐛 Bug report\nabout: 오타 또는 잘못된 링크를 수정 🛠️\n---\n\n## Description\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Comments.md",
    "chars": 73,
    "preview": "---\nname: 💬 Comments\nabout: 기타 다른 comment, 아무말 대잔치 😃\n---\n\n## Description\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Enhancement.md",
    "chars": 70,
    "preview": "---\nname: 🌈 Enhancement\nabout: 해당 저장소의 개선 사항 등록 🎉\n---\n\n## Description\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/New_resources.md",
    "chars": 65,
    "preview": "---\nname: 🎁 New Resources\nabout: 새로운 자료 추가 🚀\n---\n\n## Description\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Questions.md",
    "chars": 91,
    "preview": "---\nname: ❓ Questions\nabout: 해당 저장소에서 다루고 있는 내용에 대한 질문 또는 메인테이너에게 질문 ❔\n---\n\n## Description\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Suggestions.md",
    "chars": 72,
    "preview": "---\nname: 📝 Suggestions\nabout: 해당 저장소에 건의하고 싶은 사항 👍\n---\n\n## Description\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 140,
    "preview": "### This Pull Request is...\n* [ ] Edit typos or links\n* [ ] Inaccurate information\n* [ ] New Resources\n\n#### Description"
  },
  {
    "path": ".prettierrc",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "Algorithm/README.md",
    "chars": 18518,
    "preview": "# Algorithm\n\n* [코딩 테스트를 위한 Tip](#코딩-테스트를-위한-tip)\n* [문제 해결을 위한 전략적 접근](#문제-해결을-위한-전략적-접근)\n* [Sorting Algorithm](#sorting-"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2243,
    "preview": "# HOW TO CONTRIBUTE\n\n여러 가지 방법으로 해당 Repository 에 참여하실 수 있습니다 :)\nPR 을 올려주실 때, labels 를 참고하셔서 알맞은 제목을 함께 올려주세요!\nCommit Mess"
  },
  {
    "path": "DataStructure/README.md",
    "chars": 16478,
    "preview": "# Part 1-2 DataStructure\n\n* [Array vs Linked List](#array-vs-linked-list)\n* [Stack and Queue](#stack-and-queue)\n* [Tree]"
  },
  {
    "path": "Database/README.md",
    "chars": 17030,
    "preview": "# Part 1-5 Database\n\n* [데이터베이스](#데이터베이스)\n  * 데이터베이스를 사용하는 이유\n  * 데이터베이스 성능\n* [Index](#index)\n  * Index 란 무엇인가\n  * Index"
  },
  {
    "path": "DesignPattern/README.md",
    "chars": 2471,
    "preview": "# Part 1-6 Design Pattern\n\n* [Singleton](#singleton)\n\n[뒤로](https://github.com/JaeYeopHan/for_beginner)\n\n</br>\n\n## Single"
  },
  {
    "path": "Development_common_sense/README.md",
    "chars": 10396,
    "preview": "# Part 1-1 Development common sense\n\n* [좋은 코드란 무엇인가](#좋은-코드란-무엇인가)\n* [객체 지향 프로그래밍이란 무엇인가](#object-oriented-programming)\n"
  },
  {
    "path": "FrontEnd/README.md",
    "chars": 9216,
    "preview": "# Part 3-1 Front-End\n\n* [브라우저의 동작 원리](#브라우저의-동작-원리)\n* [Document Object Model](#Document-Object-Model)\n* [CORS](#cors)\n* "
  },
  {
    "path": "Java/README.md",
    "chars": 8618,
    "preview": "# Part 2-1 Java\n\n- [Part 2-1 Java](#part-2-1-java)\n  - [JVM 에 대해서, GC 의 원리](#jvm-%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-g"
  },
  {
    "path": "JavaScript/README.md",
    "chars": 11035,
    "preview": "# Part 2-2 JavaScript\n\n* [JavaScript Event Loop](#javascript-event-loop)\n* [Hoisting](#hoisting)\n* [Closure](#closure)\n*"
  },
  {
    "path": "LICENSE",
    "chars": 1061,
    "preview": "MIT License\n\nCopyright (c) 2017 Jbee\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof th"
  },
  {
    "path": "MachineLearning/README.md",
    "chars": 854,
    "preview": "# Part 3-3 Machine Learning\n\n> 면접에서 나왔던 질문들을 정리했으며 디테일한 모든 내용을 다루기보단 전체적인 틀을 다뤘으며, 틀린 내용이 있을 수도 있으니 비판적으로 찾아보면서 공부하는 것을 "
  },
  {
    "path": "Network/README.md",
    "chars": 8853,
    "preview": "# Part 1-3 Network\n\n- [HTTP 의 GET 과 POST 비교](#http의-get과-post-비교)\n- [TCP 3-way-handshake](#tcp-3-way-handshake)\n- [TCP와 "
  },
  {
    "path": "OS/README.en.md",
    "chars": 30278,
    "preview": "# Part 1-4 Operating System\n\n* [Process vs Thread](#process-vs-thread)\n* [Multi-thread](#multi-thread)\n  * Pros and cons"
  },
  {
    "path": "OS/README.md",
    "chars": 18035,
    "preview": "# Part 1-4 운영체제\n\n* [프로세스와 스레드의 차이](#프로세스와-스레드의-차이)\n* [멀티스레드](#멀티스레드)\n  * 장점과 단점\n  * 멀티스레드 vs 멀티프로세스\n* [스케줄러](#스케줄러)\n  * "
  },
  {
    "path": "Python/README.md",
    "chars": 25860,
    "preview": "# Part 2-3 Python\n\n* [Generator](#generator)\n* [클래스를 상속했을 때 메서드 실행 방식](#클래스를-상속했을-때-메서드-실행-방식)\n* [GIL 과 그로 인한 성능 문제](#gi"
  },
  {
    "path": "README.md",
    "chars": 10736,
    "preview": "<div align=center>\n\n![](/assets/images/tech_interview_main.png)\n\n</div>\n\n# Technical Interview Guidelines for Beginners\n"
  },
  {
    "path": "Reverse_Interview/README.md",
    "chars": 5925,
    "preview": "# Reverse Interview\n\n> [@JaeYeopHan](https://github.com/JaeYeopHan): 한국어로 번역을 진행하다보니 현재 한국 상황에 맞게 끔 약간씩 수정을 했습니다. 또 낯선 용"
  },
  {
    "path": "Tip/README.md",
    "chars": 835,
    "preview": "# 미세먼지 같은 면접 Tip\n\n## 면접 단골 질문들\n\n* 1 분(or 30 초) 자기소개\n* (비전공자 대상) 개발 공부를 시작하게 된 계기\n* 5 년 후 나의 모습은 어떠한 모습인가?\n* 본인의 장단점\n* 본인"
  },
  {
    "path": "iOS/README.md",
    "chars": 5912,
    "preview": "# Part 3-2 iOS\n\n> 면접에서 나왔던 질문들을 정리했으며 디테일한 모든 내용을 다루기보단 전체적인 틀을 다뤘으며, 틀린 내용이 있을 수도 있으니 비판적으로 찾아보면서 공부하는 것을 추천드립니다. iOS 면"
  }
]

About this extraction

This page contains the full source code of the jbee37142/Interview_Question_for_Beginner GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 28 files (200.1 KB), approximately 84.9k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!