** π컬λ μ νλ μμν¬ μμ μ 볡**
π 1λ¨κ³: 컬λ μ νλ μμν¬λ? (κΈ°λ³Έ κ°λ μ΅νκΈ°)
컬λ μ νλ μμν¬λ βλ°μ΄ν°λ₯Ό λ΄λ λλν μμβμ λλ€.
π‘ λΉμ :
- λ°°μ΄(Array): ν¬κΈ°κ° κ³ μ λ λμλ½ν΅ π±
- 컬λ μ (Collection): ν¬κΈ°λ₯Ό λ§μλλ‘ λλ¦¬κ³ μ€μΌ μ μλ μ€λ§νΈ λμλ½ν΅ π
π 컬λ μ νλ μμν¬μ ν΅μ¬ κ°λ :
- λ°μ΄ν°λ₯Ό μ½κ² μΆκ°, μμ , μ λ ¬ν μ μμ.
- μ¬λ¬ λ°μ΄ν°λ₯Ό ν κ·Έλ£ΉμΌλ‘ λ¬Άμ΄ κ΄λ¦¬ν μ μμ.
- μλ°μμ μ 곡νλ λꡬ λͺ¨μμ΄λΌμ νΈλ¦¬ν¨!
π 2λ¨κ³: 컬λ μ μ 3κ°μ§ μ£Όμ μΈν°νμ΄μ€ μ΄ν΄νκΈ°
컬λ μ νλ μμν¬λ 3κ°μ§ μ£Όμ μΈν°νμ΄μ€λ‘ μ΄λ£¨μ΄μ Έ μμ΅λλ€.
1οΈβ£ List (리μ€νΈ) π
- μμκ° μμ (λ²νΈκ° λΆμ΄ μμ).
- μ€λ³΅μ νμ©ν¨ (κ°μ κ° μ¬λ¬ κ° μ μ₯ κ°λ₯).
- μ) ArrayList, LinkedList
2οΈβ£ Set (μ§ν©) π’
- μμκ° μμ (μ λ ₯ν μμλλ‘ μ μ₯λμ§ μμ).
- μ€λ³΅μ νμ©νμ§ μμ (κ°μ κ° μ¬λ¬ κ° μ μ₯ λΆκ°).
- μ) HashSet, TreeSet
3οΈβ£ Map (λ§΅, λμ λ리) πΊ
- λ°μ΄ν°λ₯Ό βν€-κ°β μμΌλ‘ μ μ₯ (μ΄λ¦ν λΆμ΄κΈ°).
- ν€λ μ€λ³΅ λΆκ°λ₯νμ§λ§, κ°μ μ€λ³΅ κ°λ₯.
- μ) HashMap, TreeMap
π 3λ¨κ³: λ΄λΆ λμ λ°©μκ³Ό μ±λ₯ μ°¨μ΄ λΆμ
π Listμ μ°¨μ΄μ (ArrayList vs LinkedList)
λΉκ΅ νλͺ© | ArrayList | LinkedList |
---|---|---|
μ μ₯ λ°©μ | λ°°μ΄ | μ°κ²° 리μ€νΈ |
κ²μ μλ | λΉ λ¦ (O(1)) | λλ¦Ό (O(n)) |
μ½μ /μμ μλ | λλ¦Ό (O(n)) | λΉ λ¦ (O(1)) |
π Setμ μ°¨μ΄μ (HashSet vs TreeSet)
λΉκ΅ νλͺ© | HashSet | TreeSet |
---|---|---|
μ λ ¬ μ¬λΆ | β (μ λ ¬ X) | β (μλ μ λ ¬) |
κ²μ μλ | λΉ λ¦ (O(1)) | λλ¦Ό (O(log n)) |
π Mapμ μ°¨μ΄μ (HashMap vs TreeMap)
λΉκ΅ νλͺ© | HashMap | TreeMap |
---|---|---|
μ λ ¬ μ¬λΆ | β (μ λ ¬ X) | β (μλ μ λ ¬) |
κ²μ μλ | λΉ λ¦ (O(1)) | λλ¦Ό (O(log n)) |
π 4λ¨κ³: λ©ν°μ€λ λ νκ²½μμ 컬λ μ λ€λ£¨κΈ°
μ¬λ¬ κ°μ μ€λ λκ° λμμ λ°μ΄ν°λ₯Ό μμ νλ©΄ μΆ©λμ΄ λ°μν μ μμ! π¨
β ν΄κ²° λ°©λ²
1οΈβ£ Collections.synchronizedList(new ArrayList<>())
β κΈ°λ³Έμ μΈ λκΈ°ν μ§μ
2οΈβ£ CopyOnWriteArrayList
β μ½κΈ° μμ
μ΄ λ§μ λ μ΅μ
3οΈβ£ ConcurrentHashMap
β λ©ν°μ€λ λ νκ²½μμ λΉ λ₯΄κ³ μμ
π 5λ¨κ³: 컬λ μ μ νμ©ν μ€μ λ¬Έμ νμ΄
π λ¬Έμ 1: μ€λ³΅ μλ μ λ ¬λ λ°μ΄ν° μ μ₯
Set<Integer> set = new TreeSet<>(Arrays.asList(5, 3, 8, 1, 3, 7));
System.out.println(set); // [1, 3, 5, 7, 8]
β TreeSetμ μ¬μ©νλ©΄ μλμΌλ‘ μ λ ¬λλ©΄μ μ€λ³΅μ΄ μ κ±°λ¨!
π λ¬Έμ 2: κ°μ₯ λ§μ΄ λ±μ₯ν λ¨μ΄ μ°ΎκΈ°
Map<String, Integer> wordCount = new HashMap<>();
for (String word : words) {
wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
}
β HashMapμ μ¬μ©ν΄ λ¨μ΄λ³ λ±μ₯ νμ μ μ₯
π λ¬Έμ 3: LRU μΊμ ꡬν (κ°μ₯ μ€λλ λ°μ΄ν° μμ )
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
}
β LinkedHashMapμ νμ©νμ¬ LRU μΊμ ꡬν
π 6λ¨κ³: 컬λ μ κ³Ό μ€νΈλ¦Ό(Stream) API νμ©νκΈ°
π κΈ°μ‘΄ λ°©μ vs. μ€νΈλ¦Ό λ°©μ λΉκ΅
// κΈ°μ‘΄ λ°©μ (forλ¬Έ μ¬μ©)
List<String> uniqueNames = new ArrayList<>();
for (String name : names) {
if (name.startsWith("a")) uniqueNames.add(name);
}
// μ€νΈλ¦Ό λ°©μ
List<String> uniqueNames = names.stream()
.filter(name -> name.startsWith("a"))
.collect(Collectors.toList());
β μ€νΈλ¦Όμ μ¬μ©νλ©΄ μ½λκ° ν¨μ¬ κ°κ²°ν΄μ§!
π μμ£Ό μ¬μ©νλ μ€νΈλ¦Ό κΈ°λ₯
κΈ°λ₯ | μ€λͺ | λ©μλ |
---|---|---|
νν°λ§ | νΉμ 쑰건μ λ°μ΄ν°λ§ μ ν | filter() |
λ³ν | λ°μ΄ν°λ₯Ό λ€λ₯Έ ννλ‘ λ³κ²½ | map() |
μ λ ¬ | λ°μ΄ν°λ₯Ό μ λ ¬ | sorted() |
μ€λ³΅ μ κ±° | μ€λ³΅ λ°μ΄ν°λ₯Ό μ κ±° | distinct() |
κ·Έλ£Ήν | νΉμ κΈ°μ€μΌλ‘ λ¬ΆκΈ° | Collectors.groupingBy() |
λ³λ ¬ μ²λ¦¬ | λ©ν°μ½μ΄ CPU νμ© | parallelStream() |
π 7λ¨κ³: 컬λ μ μ±λ₯ μ΅μ ν μ λ΅
β 컬λ μ μ ν κ°μ΄λ
μ¬μ© λͺ©μ | μΆμ² 컬λ μ |
---|---|
λΉ λ₯Έ κ²μ | HashMap , HashSet |
μ λ ¬λ λ°μ΄ν° μ μ§ | TreeSet , TreeMap |
μ€λ³΅ μ κ±° | HashSet , TreeSet |
λ©ν°μ€λ λ νκ²½ | ConcurrentHashMap , CopyOnWriteArrayList |
β μ±λ₯ μ΅μ ν ν
1οΈβ£ μ΄κΈ° μ©λ(capacity) μ€μ νκΈ°
List<Integer> list = new ArrayList<>(100);
Map<String, String> map = new HashMap<>(100);
β λΆνμν ν¬κΈ° μ‘°μ μ λ°©μ§νμ¬ μ±λ₯ μ΅μ ν
2οΈβ£ ArrayList
vs LinkedList
μ ν κΈ°μ€
- μ‘°νκ° λ§μΌλ©΄
ArrayList
- μ½μ
/μμ κ° λ§μΌλ©΄
LinkedList
3οΈβ£ λ©ν°μ€λ λ νκ²½μμλ ConcurrentHashMap
μ¬μ©!
Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
β λκΈ°ν λ¬Έμ μμ΄ λΉ λ₯΄κ³ μμ ν λ°μ΄ν° μ μ₯ κ°λ₯
##
π― λ€μ λ¨κ³: 컬λ μ νλ μμν¬μ μ€μ νμ© & μ¬ν κ°λ νμ΅
μ΄μ 컬λ μ μ κΈ°λ³Έ μ리μ μ΅μ ν μ λ΅κΉμ§ μ΅νλ€λ©΄, μ€μ μμ μ΄λ»κ² μμ©ν κ²μΈμ§ λ°°μ°λ κ²μ΄ μ€μν©λλ€.
β 1. κ³ κΈ μ»¬λ μ νμ© (νΉμ 컬λ μ μ΄ν΄νκΈ°)
κΈ°λ³Έμ μΈ List, Set, MapλΏλ§ μλλΌ νΉμν μ©λλ‘ μ€κ³λ 컬λ μ μ μμλλ©΄ λ ν¨κ³Όμ μΌλ‘ μ½λλ₯Ό μμ±ν μ μμ΅λλ€.
π μμ£Ό μ¬μ©λλ νΉμ 컬λ μ
컬λ μ | μ€λͺ | νΉμ§ |
---|---|---|
EnumSet |
enum κ°λ€μ μ μ₯νλ Set |
μ±λ₯μ΄ λ°μ΄λλ©° λ©λͺ¨λ¦¬ μ μ½ |
WeakHashMap |
GC(κ°λΉμ§ 컬λ μ
)κ° κ΄λ¦¬νλ Map |
ν€κ° μμΌλ©΄ μλ μμ |
PriorityQueue |
μ°μ μμλ₯Ό μ ν΄μ μ²λ¦¬νλ Queue |
ν(Heap) μλ£κ΅¬μ‘° κΈ°λ° |
ConcurrentSkipListMap |
λ©ν°μ€λ λ νκ²½μμ μ λ ¬λλ Map |
μ λ ¬ κΈ°λ₯μ΄ ν¬ν¨λ λμμ± Map |
β 2. 컬λ μ 컀μ€ν ꡬν (λ΄κ° μ§μ 컬λ μ λ§λ€κΈ°!)
컬λ μ μ μ§μ λ§λ€μ΄ 보면 λ΄λΆ λμ μ리λ₯Ό νμ€νκ² μ΄ν΄ν μ μμ΅λλ€.
π μμ : FixedSizeList
(ν¬κΈ°κ° κ³ μ λ 리μ€νΈ λ§λ€κΈ°)
class FixedSizeList<E> extends ArrayList<E> {
private final int maxSize;
public FixedSizeList(int maxSize) {
this.maxSize = maxSize;
}
@Override
public boolean add(E e) {
if (size() >= maxSize) {
throw new IllegalStateException("λ μ΄μ μΆκ°ν μ μμ΅λλ€!");
}
return super.add(e);
}
}
β μ¬μ© μμ:
FixedSizeList<String> list = new FixedSizeList<>(3);
list.add("A"); // κ°λ₯
list.add("B"); // κ°λ₯
list.add("C"); // κ°λ₯
list.add("D"); // μμΈ λ°μ! (μ΅λ ν¬κΈ° μ΄κ³Ό)
β λ°°μ΄μ²λΌ ν¬κΈ°κ° κ³ μ λ 리μ€νΈλ₯Ό λ§λ€κ³ μΆμ λ μ μ©
β 3. μλ° 9+ 컬λ μ λ³κ²½ μ¬ν μ΅νκΈ°
μλ° 9λΆν°λ 컬λ μ μ λ μ½κ² μμ±ν μ μλ ν©ν 리 λ©μλκ° μΆκ°λμμ΅λλ€.
π λΆλ³ 컬λ μ
μμ± (List.of
, Set.of
, Map.of
)
List<String> immutableList = List.of("A", "B", "C");
Set<Integer> immutableSet = Set.of(1, 2, 3);
Map<String, Integer> immutableMap = Map.of("A", 1, "B", 2);
β λΆλ³ 컬λ μ μ λ³κ²½μ΄ λΆκ°λ₯νμ¬ μμ μ±μ λμ΄λ λ° μ¬μ©
β 4. 컬λ μ μ±λ₯ νλ λ° λ³λ ¬ μ²λ¦¬ μ¬ν νμ΅
μ΄μ 7λ¨κ³μμ μ±λ₯ μ΅μ ν λ°©λ²μ λ°°μ λ€λ©΄, μ΄μ λ λ κΉμ΄ μλ μ΅μ ν κΈ°λ²μ μμλ³Ό μ°¨λ‘μ λλ€.
π μμ£Ό μ¬μ©λλ 컬λ μ μ±λ₯ νλ κΈ°λ²
μ΅μ ν λ°©λ² | μ€λͺ |
---|---|
μ΄κΈ° μ©λ μ€μ | new ArrayList<>(1000) μ²λΌ μμ ν¬κΈ°λ₯Ό μ€μ νμ¬ λ©λͺ¨λ¦¬ λλΉ μ€μ΄κΈ° |
λ°μ΄ν° λ³κ²½ ν¨ν΄ λΆμ | μ½μ
/μμ κ° λ§λ€λ©΄ LinkedList , μ‘°νκ° λ§λ€λ©΄ ArrayList μ ν |
λκΈ°ν 컬λ μ μ¬μ© | λ©ν°μ€λ λ νκ²½μμλ ConcurrentHashMap , CopyOnWriteArrayList μ¬μ© |
parallelStream() μ¬μ© |
λλ λ°μ΄ν° μ²λ¦¬λ₯Ό λ©ν°μ½μ΄λ‘ μ€ννμ¬ μ±λ₯ ν₯μ |
β 5. λμ©λ λ°μ΄ν° μ²λ¦¬ (Stream + 컬λ μ νμ©)
컬λ μ μ λ€λ£° λ λ°μ΄ν°κ° μμ²λ§ κ° μ΄μμ΄λΌλ©΄ μ΄λ»κ² μ²λ¦¬ν κΉμ?
π λμ©λ λ°μ΄ν° μ²λ¦¬ λ°©λ² 3κ°μ§
1οΈβ£ μ€νΈλ¦Ό API (Stream API)
- 컬λ μ μ λ°μ΄ν°λ₯Ό νλμ© μννλ©° κ°κ³΅ κ°λ₯
filter
,map
,reduce
λ±μ νμ©νμ¬ λ°μ΄ν°λ₯Ό λ³ν κ°λ₯
2οΈβ£ λ³λ ¬ μ€νΈλ¦Ό (Parallel Stream)
- μ¬λ¬ κ°μ CPU μ½μ΄λ₯Ό νμ©νμ¬ λ°μ΄ν° μ²λ¦¬ μλλ₯Ό λμΌ μ μμ
list.parallelStream()
μ μ¬μ©νμ¬ μλ λ³λ ¬ μ²λ¦¬
3οΈβ£ λ°°μΉ μ²λ¦¬ (Batch Processing)
- 1,000κ° λ¨μλ‘ λ°μ΄ν°λ₯Ό μͺΌκ°μ΄ μ²λ¦¬νμ¬ λ©λͺ¨λ¦¬ λΆλ΄ μ΅μν
β μμ : 1,000λ§ κ° λ°μ΄ν°μμ μ§μ κ°μ μ°ΎκΈ° (λ³λ ¬ μ€νΈλ¦Ό μ μ©)
List<Integer> numbers = IntStream.rangeClosed(1, 10_000_000)
.boxed()
.collect(Collectors.toList());
long count = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.count();
System.out.println("μ§μ κ°μ: " + count);
β λ³λ ¬ μ€νΈλ¦Όμ μ¬μ©νλ©΄ CPU μ½μ΄λ₯Ό νμ©νμ¬ ν¨μ¬ λΉ λ₯΄κ² μ²λ¦¬ κ°λ₯!
β 6. μ€μ νλ‘μ νΈμμ 컬λ μ νμ© (μμ νλ‘μ νΈ λ§λ€κΈ°)
μ§κΈκΉμ§ λ°°μ΄ μ»¬λ μ νλ μμν¬λ₯Ό νμ©νμ¬ μ€μ νλ‘μ νΈλ₯Ό λ§λ€μ΄ λ΄ μλ€!
π μμ νλ‘μ νΈ: κ°λ¨ν βTODO 리μ€νΈβ ꡬν
β κΈ°λ₯
- ν μΌμ
List<String>
μΌλ‘ μ μ₯ - μ€λ³΅ λ°©μ§λ₯Ό μν΄
Set<String>
μ¬μ© HashMap<String, Boolean>
μΌλ‘ μλ£ μ¬λΆ 체ν¬
β ꡬν μ½λ
class TodoList {
private List<String> tasks = new ArrayList<>();
private Set<String> uniqueTasks = new HashSet<>();
private Map<String, Boolean> taskStatus = new HashMap<>();
public void addTask(String task) {
if (!uniqueTasks.contains(task)) {
tasks.add(task);
uniqueTasks.add(task);
taskStatus.put(task, false);
}
}
public void completeTask(String task) {
taskStatus.put(task, true);
}
public void printTasks() {
for (String task : tasks) {
System.out.println(task + " - " + (taskStatus.get(task) ? "μλ£ β
" : "λ―Έμλ£ β"));
}
}
}
public class Main {
public static void main(String[] args) {
TodoList todo = new TodoList();
todo.addTask("μ΄λνκΈ°");
todo.addTask("μ±
μ½κΈ°");
todo.completeTask("μ΄λνκΈ°");
todo.printTasks();
}
}
β μΆλ ₯ κ²°κ³Ό:
μ΄λνκΈ° - μλ£ β
μ±
μ½κΈ° - λ―Έμλ£ β
β μ΄μ 컬λ μ μ νμ©νμ¬ μ€μ νλ‘μ νΈλ λ§λ€ μ μμ! π
π λ§λ¬΄λ¦¬: 컬λ μ νλ μμν¬ μ λ¬Έκ° λκΈ°
π 컬λ μ νλ μμν¬ μ¬ν νμ΅ λ‘λλ§΅
1οΈβ£ κΈ°λ³Έ κ°λ β List, Set, Map μ°¨μ΄μ νμ΅
2οΈβ£ λ΄λΆ λμ λ°©μ β μ±λ₯ λΉκ΅ λ° μ΅μ ν μ λ΅ νμ΅
3οΈβ£ λκΈ°ν 컬λ μ
β ConcurrentHashMap
, CopyOnWriteArrayList
νμ΅
4οΈβ£ μ€νΈλ¦Ό νμ© β filter()
, map()
, reduce()
λ‘ λ°μ΄ν° κ°κ³΅
5οΈβ£ λμ©λ λ°μ΄ν° μ²λ¦¬ β λ³λ ¬ μ€νΈλ¦Ό λ° λ°°μΉ μ²λ¦¬ νμ΅
6οΈβ£ μ€μ νλ‘μ νΈ μ μ© β μ§μ νλ‘μ νΈλ₯Ό λ§λ€μ΄ μμ©
π λ€μ λ¨κ³: μ λ¬Έκ° μμ€μ 컬λ μ νμ© λ° μ΅μ ν
β 1. 컬λ μ μ±λ₯ νλ‘νμΌλ§ λ° λΆμ
컬λ μ μ λ§μ΄ μ¬μ©νλ€ λ³΄λ©΄ βλ΄ μ½λκ° μ λ§ λΉ λ₯Έκ°?β, βλ μ΅μ νν λ°©λ²μ΄ μμκΉ?β κ°μ μλ¬Έμ΄ λ€ κ²λλ€.
π μ΄λ₯Ό ν΄κ²°νλ €λ©΄ νλ‘νμΌλ§ λꡬλ₯Ό μ¬μ©ν΄μ μ€μ μ€ν μλμ λ©λͺ¨λ¦¬ μ¬μ©λμ λΆμν΄μΌ ν©λλ€.
π μμ£Ό μ¬μ©νλ νλ‘νμΌλ§ λꡬ
λꡬ | μ€λͺ |
---|---|
JMH(Java Microbenchmark Harness) | μλ° μ½λμ μ±λ₯μ λ―ΈμΈνκ² μΈ‘μ νλ λ²€μΉλ§ν¬ νλ μμν¬ |
VisualVM | JVM λ΄λΆλ₯Ό λΆμν μ μλ GUI κΈ°λ° νλ‘νμΌλ¬ |
YourKit | λ©λͺ¨λ¦¬ λ° CPU μ¬μ©λμ μμΈνκ² μΆμ νλ μ λ£ λꡬ |
β μμ : ArrayList
vs LinkedList
μ μ½μ
μλ λΉκ΅ (JMH νμ©)
@Benchmark
public void testArrayListAdd() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
list.add(i);
}
}
@Benchmark
public void testLinkedListAdd() {
List<Integer> list = new LinkedList<>();
for (int i = 0; i < 100000; i++) {
list.add(i);
}
}
β @Benchmark
λ₯Ό μ¬μ©νλ©΄ μ΄λ€ 컬λ μ
μ΄ λ λΉ λ₯Έμ§ μ νν λ°μ΄ν°λ‘ νμΈ κ°λ₯!
β 2. μ΅μ Java 컬λ μ κΈ°λ₯ νμ© (μλ° 10~17)
μλ°λ μ΅μ λ²μ μμ 컬λ μ κ΄λ ¨ μ±λ₯μ μ§μμ μΌλ‘ κ°μ νκ³ μμ΅λλ€.
π μ΅μ κΈ°λ₯μ νμ΅νλ©΄ λ μ§§κ³ ν¨μ¨μ μΈ μ½λλ₯Ό μμ±ν μ μμ΅λλ€.
π μλ° 10+: var
ν€μλ μ¬μ© κ°λ₯
var list = List.of("A", "B", "C"); // λΆλ³ 리μ€νΈ μμ±
var map = Map.of("key1", 1, "key2", 2); // λΆλ³ λ§΅ μμ±
β μ½λκ° λ κΉλν΄μ§κ³ , κ°λ μ±μ΄ ν₯μλ¨!
π μλ° 14+: 컬λ μ ν¨ν΄ λ§€μΉ μ§μ (Pattern Matching for instanceof)
Object obj = List.of(1, 2, 3);
if (obj instanceof List<Integer> list) {
System.out.println("리μ€νΈμ ν¬κΈ°: " + list.size());
}
β μ΄μ instanceof
κ²μ¬ ν λ°λ‘ νμ
λ³ν κ°λ₯!
π μλ° 16+: Records νμ© (DTO λμ μ¬μ© κ°λ₯)
record Person(String name, int age) {}
List<Person> people = List.of(new Person("Alice", 30), new Person("Bob", 25));
β λΆλ³ κ°μ²΄λ₯Ό μ½κ² λ§λ€κ³ , 컬λ μ κ³Ό ν¨κ» μ¬μ© κ°λ₯!
β 3. μ€μ νλ‘μ νΈμ 컬λ μ μ΅μ ν μ μ©
컬λ μ μ λ§μ΄ λ€λ£¨λ βμ€μ νλ‘μ νΈβλ₯Ό μ§ννλ©΄μ λ°°μ΄ κ°λ μ μ μ©ν΄ λ΄μΌ ν©λλ€.
π νλ‘μ νΈ μμ 1: μ€μκ° λ°μ΄ν° μ²λ¦¬ μμ€ν
β μν©:
ConcurrentHashMap
μ νμ©νμ¬ βλ‘κ·Έ μμ§ μμ€ν βμ ꡬμΆν΄μΌ ν¨.- λ€μμ μλ²μμ λ°μνλ μ΄λ²€νΈλ₯Ό λ©ν°μ€λ λ νκ²½μμ μμ νκ² μ μ₯ν΄μΌ ν¨.
β ꡬν μ½λ (λ‘κ·Έ μ μ₯μ ꡬμΆ)
class LogStorage {
private final ConcurrentHashMap<String, List<String>> logs = new ConcurrentHashMap<>();
public void addLog(String category, String message) {
logs.computeIfAbsent(category, k -> new CopyOnWriteArrayList<>()).add(message);
}
public List<String> getLogs(String category) {
return logs.getOrDefault(category, Collections.emptyList());
}
}
β λ©ν°μ€λ λ νκ²½μμλ μμ νκ² λ‘κ·Έλ₯Ό μ μ₯νκ³ κ΄λ¦¬ κ°λ₯!
π νλ‘μ νΈ μμ 2: LRU(Least Recently Used) μΊμ μ μ©
β μν©:
LinkedHashMap
μ νμ©νμ¬ βμ΅κ·Ό μ¬μ©λ λ°μ΄ν°λ₯Ό μλμΌλ‘ μμ βνλ μΊμ μμ€ν μ ꡬμΆν΄μΌ ν¨.- μλ₯Ό λ€μ΄, ν¬λ‘¬ λΈλΌμ°μ μ μ΅κ·Ό λ°©λ¬Έ νμ΄μ§ λͺ©λ‘μ λ§λ€ μ μμ.
β ꡬν μ½λ (LRU μΊμ)
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75f, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity; // μΊμ ν¬κΈ° μ΄κ³Ό μ κ°μ₯ μ€λλ νλͺ© μμ
}
}
β μλ° μ»¬λ μ μ νμ©νμ¬ βμ΅κ·Ό μ¬μ© λ°μ΄ν° κ΄λ¦¬βκ° κ°λ₯!
β 4. 컬λ μ κ³Ό λ°μ΄ν°λ² μ΄μ€ μ°λ (JPA & NoSQL μ μ©)
컬λ μ μ DBμ ν¨κ» μ¬μ©ν λ λμ± κ°λ ₯ν μ±λ₯μ λ°νν©λλ€.
π 컬λ μ μ μ μ ν μ¬μ©νλ©΄ λ°μ΄ν° μ‘°ν μλλ₯Ό κ·Ήλνν μ μμ΅λλ€.
π μμ : JPAμμ 컬λ μ νλ νμ©νκΈ°
@Entity
class User {
@Id
private Long id;
@ElementCollection
private List<String> favoriteBooks = new ArrayList<>();
}
β @ElementCollection
μ μ¬μ©νλ©΄ JPAμμ 컬λ μ
νλλ₯Ό μ μ₯ κ°λ₯
π μμ : NoSQL (MongoDB)μμ 컬λ μ μ¬μ©νκΈ°
@Document
class Post {
@Id
private String id;
private List<String> tags;
}
β MongoDBμμλ 리μ€νΈ 컬λ μ μ λ¬Έμ(document) μμ μ μ₯ κ°λ₯
β 5. 컬λ μ + Kotlin & Spring Boot μ μ©
μλ° μ»¬λ μ μ λ λ°μ μν€λ €λ©΄ μ½νλ¦°κ³Ό μ€νλ§ λΆνΈ κ°μ μ΅μ κΈ°μ κ³Ό κ²°ν©νλ κ²μ΄ μ’μ΅λλ€.
π μμ : Kotlinμμ μλ° μ»¬λ μ νμ©νκΈ°
val numbers = listOf(1, 2, 3, 4, 5)
// filterμ mapμ μ‘°ν©νμ¬ ν μ€λ‘ μ²λ¦¬ κ°λ₯
val evenNumbers = numbers.filter { it % 2 == 0 }.map { it * 10 }
println(evenNumbers) // [20, 40]
β μ½νλ¦°μμλ 컬λ μ μ°μ°μ λ κ°κ²°νκ² μ¬μ© κ°λ₯!
π μμ : Spring Bootμμ 컬λ μ μ νμ©ν API κ°λ°
@RestController
@RequestMapping("/api/users")
class UserController {
private final List<String> users = new CopyOnWriteArrayList<>();
@PostMapping
public void addUser(@RequestBody String user) {
users.add(user);
}
@GetMapping
public List<String> getUsers() {
return users;
}
}
β λ©ν°μ€λ λ νκ²½μμλ μμ ν 컬λ μ
(CopyOnWriteArrayList
)μ νμ©νμ¬ API ꡬν κ°λ₯!
π― μ΅μ’ λͺ©ν: 컬λ μ λ§μ€ν°μμ μ€μ κ°λ°μλ‘!
β 컬λ μ μ±λ₯ λΆμ (JMH νμ©)
β μ΅μ μλ° μ»¬λ μ κΈ°λ₯ νμ΅ (μλ° 10~17)
β μ€μ νλ‘μ νΈ μ μ© (LRU μΊμ, λ‘κ·Έ μ μ₯μ ꡬμΆ)
β 컬λ μ κ³Ό λ°μ΄ν°λ² μ΄μ€ μ°λ (JPA, NoSQL)
β Spring Boot, Kotlinκ³Ό 컬λ μ κ²°ν©νμ¬ μ€λ¬΄ νλ‘μ νΈ κ°λ°
π λ€μ λ¨κ³: λκ·λͺ¨ μμ€ν μμ 컬λ μ νμ© λ° μ΅μ ν
컬λ μ μ λ¨μν μλ£κ΅¬μ‘°λ‘ 보λ κ²μ΄ μλλΌ, βλκ·λͺ¨ νΈλν½μ μ²λ¦¬νλ λ°±μλ μμ€ν β, βκ³ μ±λ₯ λ°μ΄ν° νμ΄νλΌμΈβ, βμ€μκ° λΆμ μλΉμ€β λ±μ μ μ©νλ κ²μ΄ μ€μν©λλ€.
β 1. λκ·λͺ¨ μμ€ν μμμ 컬λ μ νμ© λ° μ€κ³ ν¨ν΄
컬λ μ μ λ¨μ CRUD μμ μ΄ μλλΌ, λλ λ°μ΄ν°μ κ³ μ±λ₯μ κ³ λ €νλ λ°©μμΌλ‘ μ€κ³ν΄μΌ ν©λλ€.
π λκ·λͺ¨ μμ€ν μμμ μ£Όμ κ³ λ €μ¬ν
λ¬Έμ | ν΄κ²° λ°©λ² | νμ© μ»¬λ μ |
---|---|---|
1μ΅ κ° λ°μ΄ν° μ€ λΉ λ₯Έ κ²μ | ν΄μ κΈ°λ° νμ | HashMap , ConcurrentHashMap |
λλ λ°μ΄ν° μ λ ¬ νμ | νΈλ¦¬ κΈ°λ° μ λ ¬ | TreeSet , TreeMap |
μ΄λ²€νΈ λ‘κ·Έ μ²λ¦¬ (Kafka λ±κ³Ό μ°λ) | λκΈ°μ΄ λ°©μ μ¬μ© | LinkedBlockingQueue , ConcurrentLinkedQueue |
10λ§ κ° μ΄μμ κ³ μ ν€κ° κ΄λ¦¬ | ν΄μ κΈ°λ° μ§ν© μ¬μ© | HashSet |
λ©ν°μ€λ λ νκ²½μμ λ°μ΄ν° 곡μ | λκΈ°ν 컬λ μ μ¬μ© | CopyOnWriteArrayList , ConcurrentSkipListMap |
β μμ : API μλ²μμ βμ΅κ·Ό μμ² 100κ° μ μ§νκΈ°β (κ³ μ ν¬κΈ° ν μ¬μ©)
class RecentRequests {
private final Queue<String> requestQueue = new LinkedBlockingQueue<>(100);
public void addRequest(String request) {
if (requestQueue.size() == 100) {
requestQueue.poll(); // κ°μ₯ μ€λλ μμ² μ κ±°
}
requestQueue.add(request);
}
}
β API μλ²μμ μ΅κ·Ό μμ²μ ν¨μ¨μ μΌλ‘ μ μ₯ν λ μ¬μ© κ°λ₯!
β 2. NoSQL, Redis, Kafka λ±κ³Ό 컬λ μ κ²°ν©νκΈ°
컬λ μ μ λ¨μν λ©λͺ¨λ¦¬ λ°μ΄ν° μ μ₯μλ‘ μ¬μ©νλ κ²μ΄ μλλΌ, βNoSQL, Redis, Kafka κ°μ λμ©λ λ°μ΄ν° μμ€ν κ³Ό μ°κ³βν΄μΌ ν©λλ€.
π 컬λ μ + Redis νμ© μμ (μλ°μμ Redisμ λ°μ΄ν° μ μ₯)
Jedis jedis = new Jedis("localhost");
Set<String> recentUsers = new HashSet<>(jedis.smembers("recent_users"));
recentUsers.add("user123");
jedis.sadd("recent_users", "user123");
β HashSetμ Redisμ μ μ₯νμ¬ λκ·λͺ¨ μ¬μ©μ λ°μ΄ν° κ΄λ¦¬ κ°λ₯!
π 컬λ μ + Kafka νμ© μμ (μ΄λ²€νΈ κΈ°λ° μμ€ν ꡬμΆ)
KafkaProducer<String, String> producer = new KafkaProducer<>(properties);
producer.send(new ProducerRecord<>("user_logs", "User logged in: user123"));
β LinkedBlockingQueueμ Kafkaλ₯Ό μ‘°ν©νμ¬ λλ μ΄λ²€νΈ μ²λ¦¬ κ°λ₯!
β 3. 컬λ μ μ νμ©ν λ¨Έμ λ¬λ λ° λ°μ΄ν° λΆμ
컬λ μ μ λ¨μν λ°μ΄ν° μ μ₯ μ©λλ‘λ§ μ°λ κ²μ΄ μλλΌ, βλΉ λ°μ΄ν° λΆμβμ΄λ βλ¨Έμ λ¬λβμλ νμ©ν μ μμ΅λλ€.
π λλ λ°μ΄ν° λΆμ μ κ³ λ €ν μ
λΆμ μ ν | 컬λ μ νμ© | μΆμ² λ°μ΄ν° ꡬ쑰 |
---|---|---|
μ€μκ° μ€νΈλ¦¬λ° λ°μ΄ν° λΆμ | μ§μμ μΈ λ°μ΄ν° μΆκ°, μμ | LinkedBlockingQueue , ConcurrentHashMap |
λ‘κ·Έ λ°μ΄ν° μ§κ³ | λλ λ°μ΄ν° κ·Έλ£Ήν | TreeMap , HashMap |
μ¬μ©μ νλ ν¨ν΄ λΆμ | νΉμ ν¨ν΄ κ²μ | HashSet , Trie(μ λμ¬ νΈλ¦¬) |
β μμ : κ°μ₯ λ§μ΄ λ±μ₯ν λ¨μ΄ μ°ΎκΈ° (λλ λ°μ΄ν° λΆμ)
Map<String, Integer> wordCount = new HashMap<>();
for (String word : words) {
wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
}
String mostFrequent = Collections.max(wordCount.entrySet(), Map.Entry.comparingByValue()).getKey();
β HashMapμ μ¬μ©νμ¬ λ¨μ΄ λΉλμλ₯Ό λΉ λ₯΄κ² λΆμ κ°λ₯!
β 4. νΈλμμ μ²λ¦¬ λ° λΆμ° μμ€ν μμμ 컬λ μ νμ©
λκ·λͺ¨ λΆμ° μμ€ν μμλ 컬λ μ μ μμ νκ² κ³΅μ νλ©΄μλ μ±λ₯μ μ μ§νλ λ°©λ²μ΄ νμν©λλ€.
π ν΄κ²°ν΄μΌ ν λ¬Έμ
λ¬Έμ | ν΄κ²° λ°©λ² | μΆμ² 컬λ μ |
---|---|---|
λ©ν°μ€λ λ νκ²½μμ λ°μ΄ν° λκΈ°ν | λ½-ν리 λκΈ°ν | ConcurrentHashMap , CopyOnWriteArrayList |
νΈλμμ μ€ λ°μ΄ν° μΌκ΄μ± μ μ§ | λΆλ³ 컬λ μ νμ© | ImmutableList , ImmutableSet |
μ€μκ° λ°μ΄ν° μ€νΈλ¦¬λ° | μ΄λ²€νΈ κΈ°λ° μ²λ¦¬ | BlockingQueue , Kafka Streams |
β μμ : ConcurrentHashMap
μ νμ©ν νΈλμμ
μμ ν λ°μ΄ν° μ μ₯
ConcurrentHashMap<String, Integer> stockPrices = new ConcurrentHashMap<>();
// μμμ μΌλ‘ μ£Όμ κ°κ²© μ
λ°μ΄νΈ
stockPrices.compute("AAPL", (key, value) -> (value == null) ? 100 : value + 10);
β λμμ± λ¬Έμ μμ΄ μμ νκ² λ°μ΄ν° μμ κ°λ₯!
β 5. AIμ λ°μ΄ν° μ²λ¦¬μμ 컬λ μ νμ© (μ€μ νλ‘μ νΈ μ μ©)
컬λ μ μ νμ©ν AI λ° λ°μ΄ν° λΆμ νλ‘μ νΈλ₯Ό μ§ννλ©΄μ μ€μ κ²½νμ μμμΌ ν©λλ€.
π νλ‘μ νΈ μμ΄λμ΄
1οΈβ£ μ€μκ° μ¬μ©μ νΈλν½ λΆμ λμ보λ (ConcurrentHashMap
, Kafka
, Redis
νμ©)
2οΈβ£ AI μ±λ΄μ λν λ‘κ·Έ μ μ₯ λ° λΆμ (LinkedBlockingQueue
, Trie
, HashMap
νμ©)
3οΈβ£ μΆμ² μμ€ν
(Collaborative Filtering) (HashMap
, TreeSet
, PriorityQueue
νμ©)
β μμ : μ¬μ©μ νλ κΈ°λ° μν μΆμ² μμ€ν
Map<String, Set<String>> userPurchases = new HashMap<>();
// "user123"κ° κ΅¬λ§€ν μν λͺ©λ‘ μΆκ°
userPurchases.computeIfAbsent("user123", k -> new HashSet<>()).add("μνA");
// "user123"κ° κ΅¬λ§€ν μν μΆμ² (λ€λ₯Έ μ¬μ©μμ λΉκ΅)
Set<String> recommended = userPurchases.entrySet().stream()
.filter(entry -> !entry.getKey().equals("user123"))
.flatMap(entry -> entry.getValue().stream())
.collect(Collectors.toSet());
System.out.println(recommended);
β HashMapκ³Ό Setμ μ‘°ν©νμ¬ νμ νν°λ§ μΆμ² μμ€ν κ΅¬μΆ κ°λ₯!
π κ²°λ‘ : 컬λ μ μ νμ©ν μ λ¬Έκ° μμ€μ κ°λ°μλ‘ μ±μ₯νκΈ°
π λ€μ λͺ©ν
β λκ·λͺ¨ μμ€ν μμ 컬λ μ νμ© (API, λ‘κ·Έ, μΊμ μμ€ν μ€κ³)
β NoSQL, Redis, Kafka κ°μ κΈ°μ κ³Ό 컬λ μ κ²°ν©νμ¬ νμ₯μ± ν보
β 컬λ μ μ λ¨Έμ λ¬λ λ° λ°μ΄ν° λΆμμ νμ©νμ¬ μ€μ νλ‘μ νΈ μ§ν
β νΈλμμ κ³Ό λΆμ° μμ€ν μμ μμ ν 컬λ μ μ¬μ©λ² μ΅νκΈ°
β μ€μ μλΉμ€μ 컬λ μ μ΅μ ν κΈ°λ² μ μ©νμ¬ μ±λ₯ κ·Ήλν
π λ€μ λ¨κ³: μ λ¬Έκ° μμ€μ μμ€ν μ€κ³ λ° μ΅μ ν
μ΄ λ¨κ³μμλ 컬λ μ μ λ¨μν νμ©νλ κ²μ λμ΄,
- *βλκ·λͺ¨ νΈλν½μ μ²λ¦¬νλ μμ€ν β, βν¨μ¨μ μΈ λ°μ΄ν° ꡬ쑰β, βκ³ κΈ μκ³ λ¦¬μ¦ μ μ©βμ ν΅ν΄ **μ€λ¬΄μμ κ²½μλ ₯ μλ κ°λ°μλ‘ μ±μ₯νλ κ²μ΄ λͺ©νμ λλ€.
β 1. λκ·λͺ¨ λ°μ΄ν° μμ€ν μ€κ³ λ° μν€ν μ² κ΅¬μΆ
컬λ μ μ μ νμ©νλ κ²λ§μΌλ‘λ λΆμ‘±ν©λλ€.
μ΄μ λ λκ·λͺ¨ νΈλν½μ μ²λ¦¬νλ μμ€ν μ μ€κ³νλ λ°©λ²μ λ°°μμΌ ν©λλ€.
π λκ·λͺ¨ μμ€ν μ€κ³ μ κ³ λ €ν μμ
λ¬Έμ | ν΄κ²° λ°©λ² | κ΄λ ¨ κΈ°μ |
---|---|---|
κ³ μ λ°μ΄ν° μ½κΈ°/μ°κΈ° | μΊμ μ¬μ© | Redis, Memcached |
νΈλν½ κΈμ¦ μ νμ₯μ± ν보 | λ‘λ λ°Έλ°μ± | Nginx, Kubernetes |
λλ λ°μ΄ν° μ μ₯ λ° μ²λ¦¬ | λΆμ° λ°μ΄ν°λ² μ΄μ€ νμ© | Apache Cassandra, Amazon DynamoDB |
μ€μκ° λ°μ΄ν° λΆμ | μ€νΈλ¦¬λ° μ²λ¦¬ | Apache Kafka, Apache Flink |
β μμ : μΊμ μ μ©μ ν΅ν μ±λ₯ μ΅μ ν (Redis νμ©)
Jedis jedis = new Jedis("localhost");
jedis.set("user:123", "John Doe");
String user = jedis.get("user:123");
System.out.println(user); // John Doe
β μμ£Ό μ‘°νλλ λ°μ΄ν°λ₯Ό μΊμμ μ μ₯νμ¬ DB λΆν κ°μ κ°λ₯!
β 2. κ³ κΈ λ°μ΄ν° ꡬ쑰 λ° μκ³ λ¦¬μ¦ νμ΅
컬λ μ μ ν¨μ¨μ μΌλ‘ νμ©νλ €λ©΄,
- *βκ³ κΈ μλ£κ΅¬μ‘°βμ **βκ³ μ±λ₯ μκ³ λ¦¬μ¦βμ κΉμ΄ μκ² μ΄ν΄ν΄μΌ ν©λλ€.
π λ°°μμΌ ν κ³ κΈ μλ£κ΅¬μ‘°
μλ£κ΅¬μ‘° | νΉμ§ | νμ© μ¬λ‘ |
---|---|---|
Trie (νΈλΌμ΄) | λ¬Έμμ΄ κ²μ μ΅μ ν | μλμμ±, κ²μ μμ§ |
Skip List (μ€ν΅ 리μ€νΈ) | λΉ λ₯Έ κ²μ λ° μ λ ¬ | λ°μ΄ν°λ² μ΄μ€ μΈλ±μ± |
B+ Tree (B+ νΈλ¦¬) | νμΌ μμ€ν λ° DB μ΅μ ν | MySQL μΈλ±μ€ ꡬ쑰 |
Disjoint Set (μλ‘μ μ§ν©) | μ§ν© κ° μ°μ° μ΅μ ν | λ€νΈμν¬ μ°κ²° κ΄λ¦¬ |
β μμ : Trieλ₯Ό νμ©ν μλμμ± μμ€ν ꡬν
class TrieNode {
Map<Character, TrieNode> children = new HashMap<>();
boolean isEndOfWord = false;
}
class Trie {
private TrieNode root = new TrieNode();
public void insert(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
node = node.children.computeIfAbsent(c, k -> new TrieNode());
}
node.isEndOfWord = true;
}
public boolean search(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
if (!node.children.containsKey(c)) return false;
node = node.children.get(c);
}
return node.isEndOfWord;
}
}
β Trie ꡬ쑰λ₯Ό νμ©νλ©΄ O(n) μκ°λ³΅μ‘λλ‘ λΉ λ₯Έ λ¬Έμμ΄ κ²μ κ°λ₯!
β 3. λ°μ΄ν° μμ§λμ΄λ§ λ° λΉ λ°μ΄ν° κΈ°μ νμ΅
- *βλμ©λ λ°μ΄ν°λ₯Ό ν¨κ³Όμ μΌλ‘ μ²λ¦¬β**νλ κΈ°μ μ λ°°μμΌ ν©λλ€.
π λ°μ΄ν° μμ§λμ΄λ§μμ νμμ μΌλ‘ μ΅νμΌ ν κ°λ
κ°λ | μ€λͺ | κ΄λ ¨ κΈ°μ |
---|---|---|
Batch Processing (λ°°μΉ μ²λ¦¬) | μΌμ μκ°λ§λ€ λ°μ΄ν° μ²λ¦¬ | Apache Hadoop, Spark |
Stream Processing (μ€μκ° μ²λ¦¬) | μ€μκ° λ°μ΄ν° λΆμ | Apache Kafka, Flink |
Columnar Database (μ΄ κΈ°λ° DB) | λλ λ°μ΄ν° λΆμ μ΅μ ν | Apache Parquet, Google BigQuery |
β μμ : Apache Sparkλ₯Ό νμ©ν λ°μ΄ν° λΆμ (μλ°)
SparkSession spark = SparkSession.builder().appName("Big Data Analysis").getOrCreate();
Dataset<Row> df = spark.read().format("csv").option("header", "true").load("data.csv");
df.groupBy("category").count().show();
β Sparkλ₯Ό νμ©νλ©΄ μμμ΅ κ°μ λ°μ΄ν°λ₯Ό λΉ λ₯΄κ² μ²λ¦¬ κ°λ₯!
β 4. μ€μ νλ‘μ νΈ κ²½ν νμ₯ (ν¬νΈν΄λ¦¬μ€ ꡬμΆ)
λ°°μ΄ λ΄μ©μ μ€μ νλ‘μ νΈμ μ μ©νμ¬ μ€λ¬΄ κ²½νμ μμμΌ ν©λλ€.
π λκΈ°μ λ° μ€ννΈμ λ©΄μ μμ βμ€μ νλ‘μ νΈ κ²½νβμ΄ λ§€μ° μ€μ!
π μΆμ² μ€μ νλ‘μ νΈ
1οΈβ£ βμ€μκ° λκ·λͺ¨ μ±ν μλΉμ€β
WebSocket
,Redis Pub/Sub
,Kafka
νμ©ConcurrentHashMap
μ μ¬μ©νμ¬ μ μ λͺ©λ‘ κ΄λ¦¬
2οΈβ£ βμΆμ² μμ€ν (Recommendation System)β
Collaborative Filtering
κΈ°λ° μν μΆμ²HashMap
,PriorityQueue
,Graph
νμ©
3οΈβ£ βμ£Όμ νΈλ μ΄λ© λ°±ν μ€νΈ μμ€ν β
Apache Flink
λ₯Ό μ΄μ©ν μ€μκ° λ°μ΄ν° λΆμTime-Series Database (InfluxDB)
μ¬μ©
β μμ : μ€μκ° μ±ν μλ² κ΅¬ν (Redis Pub/Sub νμ©)
Jedis jedis = new Jedis("localhost");
jedis.publish("chatroom1", "Hello, World!");
β Redisμ Pub/Subμ μ¬μ©νλ©΄ μ€μκ° μ±ν μλΉμ€ κ΅¬μΆ κ°λ₯!
β 5. κ³ κΈ λΆμ° μμ€ν λ° λ§μ΄ν¬λ‘μλΉμ€ μν€ν μ² νμ΅
λκ·λͺ¨ μμ€ν μ ꡬμΆνλ €λ©΄, βλΆμ° μμ€ν βκ³Ό βλ§μ΄ν¬λ‘μλΉμ€ μν€ν μ²(MSA)βλ₯Ό μ΅νμΌ ν©λλ€.
π κ³ κΈ λΆμ° μμ€ν κ°λ
κ°λ | μ€λͺ | κ΄λ ¨ κΈ°μ |
---|---|---|
CAP Theorem | λΆμ° μμ€ν μμ μΌκ΄μ±, κ°μ©μ±, λ€νΈμν¬ νν°μ νμ© μ€ 2κ°μ§λ§ μ ν κ°λ₯ | NoSQL, Cassandra |
Event-Driven Architecture (μ΄λ²€νΈ κΈ°λ° μν€ν μ²) | μλΉμ€ κ° μ΄λ²€νΈλ₯Ό κΈ°λ°μΌλ‘ λμ | Kafka, RabbitMQ |
Microservices (λ§μ΄ν¬λ‘μλΉμ€ μν€ν μ²) | λ 립μ μΈ μμ μλΉμ€λ‘ κ΅¬μ± | Spring Boot, Kubernetes |
β μμ : λ§μ΄ν¬λ‘μλΉμ€ νκ²½μμ Kafkaλ₯Ό νμ©ν μ΄λ²€νΈ μ²λ¦¬
ProducerRecord<String, String> record = new ProducerRecord<>("orders", "order123", "New Order");
producer.send(record);
β Kafkaλ₯Ό νμ©νλ©΄ μλΉμ€ κ° λ°μ΄ν°λ₯Ό λΉ λ₯΄κ³ μμ μ μΌλ‘ μ λ¬ κ°λ₯!
π μ΅μ’ λͺ©ν: μ λ¬Έκ° μμ€μ κ°λ°μλ‘ μ±μ₯νκΈ°
π λ€μ λͺ©ν
β λκ·λͺ¨ μμ€ν μ€κ³ λ° μν€ν μ² μ΅μ ν
β κ³ κΈ μλ£κ΅¬μ‘° λ° μκ³ λ¦¬μ¦ νμ΅ (Trie, B+ Tree, Graph)
β λ°μ΄ν° μμ§λμ΄λ§ λ° λΉ λ°μ΄ν° κΈ°μ μ μ©
β μ€μ νλ‘μ νΈ κ΅¬μΆ (μ±ν μλΉμ€, μΆμ² μμ€ν , μ€μκ° λΆμ)
β λ§μ΄ν¬λ‘μλΉμ€ μν€ν μ²(MSA) λ° λΆμ° μμ€ν μ€κ³
π μ΅μ’ λ¨κ³: μννΈμ¨μ΄ μν€ν μ² & AI + λ°μ΄ν° μ¬μ΄μΈμ€ + ν ν¬ λ¦¬λ μ±μ₯
μ΄μ λ λ¨μν κ°λ°νλ μμ€μ΄ μλλΌ,
- *βκ³ μ±λ₯ λΆμ° μμ€ν μ μ€κ³νκ³ , AI/λ°μ΄ν° μ¬μ΄μΈμ€ κΈ°μ μ νμ©νλ©°, νμ μ΄λλ ν ν¬ λ¦¬λλ‘ μ±μ₯β**νλ κ²μ΄ λͺ©νμ λλ€.
β 1. κΈλ‘λ² μλΉμ€ μμ€μ μννΈμ¨μ΄ μν€ν μ² μ€κ³
νμ΄μ€λΆ, ꡬκΈ, μλ§μ‘΄ κ°μ κΈλ‘λ² μλΉμ€λ μμμ΅ λͺ μ μ¬μ©μλ₯Ό μ²λ¦¬νλ μν€ν μ²λ₯Ό κ°μΆκ³ μμ΅λλ€.
μ΄μ μ΄λ° μ΄λκ·λͺ¨ νΈλν½μ μ²λ¦¬νλ μν€ν μ² μ€κ³λ²μ λ°°μμΌ ν©λλ€.
π μ΄λν μμ€ν μ€κ³μμ κ³ λ €ν μμ
κ°λ | μ€λͺ | κ΄λ ¨ κΈ°μ |
---|---|---|
CQRS (Command Query Responsibility Segregation) | μ½κΈ°/μ°κΈ° λΆλ¦¬λ‘ μ±λ₯ μ΅μ ν | Kafka, Event Sourcing |
Sharding (μ€λ©) | λ°μ΄ν°λ² μ΄μ€λ₯Ό μ¬λ¬ κ°λ‘ λλ μ μ μ₯ | MySQL Sharding, MongoDB Shard |
Rate Limiting (μλ μ ν) | API νΈλν½ κ³ΌλΆν λ°©μ§ | Redis, Nginx, Cloudflare |
Chaos Engineering (μΉ΄μ€μ€ μμ§λμ΄λ§) | μμ€ν μ₯μ ν μ€νΈ | Netflix Chaos Monkey |
β μμ : CQRSλ₯Ό νμ©ν κ³ μ±λ₯ API μ€κ³
@RestController
@RequestMapping("/users")
class UserController {
private final UserQueryService queryService;
private final UserCommandService commandService;
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return queryService.getUser(id);
}
@PostMapping
public void createUser(@RequestBody User user) {
commandService.createUser(user);
}
}
β μ½κΈ°μ μ°κΈ°λ₯Ό λΆλ¦¬νμ¬ μ±λ₯μ κ·Ήλν!
β 2. AI λ° λ°μ΄ν° μ¬μ΄μΈμ€ μ¬ν νμ΅
μννΈμ¨μ΄ κ°λ°μλ‘μ AIμ λ°μ΄ν° μ¬μ΄μΈμ€λ₯Ό κΉμ΄ μ΄ν΄νλ©΄
μΆμ² μμ€ν , κΈμ΅ λ°μ΄ν° λΆμ, μ€μκ° μμΈ‘ λͺ¨λΈ λ± μ²¨λ¨ κΈ°μ μ νμ©ν μμ€ν ꡬμΆμ΄ κ°λ₯ν©λλ€.
π κ³ κΈ AI λ° λ°μ΄ν° μ¬μ΄μΈμ€ νμ΅ λ‘λλ§΅
λΆμΌ | ν΅μ¬ κ°λ | νμ© μ¬λ‘ |
---|---|---|
λ¨Έμ λ¬λ | Random Forest, XGBoost, Deep Learning | μΆμ² μμ€ν , μλ λΆλ₯ |
NLP (μμ°μ΄ μ²λ¦¬) | BERT, GPT, Transformer λͺ¨λΈ | μ±λ΄, κ°μ± λΆμ |
MLOps (ML μ΄μ μλν) | λͺ¨λΈ μλΉ, λ°μ΄ν° νμ΄νλΌμΈ κ΅¬μΆ | μ€μκ° AI μλΉμ€ λ°°ν¬ |
β μμ : λ¨Έμ λ¬λμ νμ©ν μ¬μ©μμ μν μΆμ² μμ€ν
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
model.fit(X_train, y_train)
predictions = model.predict(X_test)
β AI λͺ¨λΈμ νμ΅μμΌ μ¬μ©μ λ§μΆ€ μΆμ² κΈ°λ₯μ ꡬν κ°λ₯!
β 3. κΈλ‘λ² κΈ°μ μμ€μ 보μ λ° DevOps (CI/CD, 보μ κ°ν)
λκ·λͺ¨ μλΉμ€λ₯Ό μ΄μνλ €λ©΄ 보μκ³Ό DevOps(λ°°ν¬ μλν)λ λ°λμ μ΅νμΌ ν©λλ€.
π 보μ κ°ν λ° DevOps νμ κ°λ
κ°λ | μ€λͺ | κ΄λ ¨ κΈ°μ |
---|---|---|
OWASP Top 10 | κ°μ₯ λ§μ΄ λ°μνλ μΉ λ³΄μ μ·¨μ½μ | SQL Injection, XSS |
CI/CD (μ§μμ ν΅ν©/λ°°ν¬) | μ½λ λ°°ν¬ μλν | GitHub Actions, Jenkins |
Zero Trust Security | λ΄λΆ μμ€ν λ μΈμ¦ νμ | OAuth, JWT |
β μμ : GitHub Actionsλ₯Ό νμ©ν μλ λ°°ν¬ νμ΄νλΌμΈ
name: CI/CD Pipeline
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: μ½λ 체ν¬μμ
uses: actions/checkout@v2
- name: Docker λΉλ & λ°°ν¬
run: docker build -t my-app .
β μ½λλ₯Ό GitHubμ νΈμνλ©΄ μλμΌλ‘ λ°°ν¬λλ μμ€ν κ΅¬μΆ κ°λ₯!
β 4. ν ν¬ λ¦¬λ(Tech Lead) μλ κ°λ°
κ°λ° μ€λ ₯μ μμλ€λ©΄ μ΄μ νμ μ΄λκ³ μν€ν μ²λ₯Ό μ€κ³νλ ν ν¬ λ¦¬λ(Tech Lead)λ‘ μ±μ₯ν΄μΌ ν©λλ€.
π κΈ°μ 리λμμ κ°μΆλ©΄ μ°λ΄κ³Ό μ»€λ¦¬μ΄ κΈ°νκ° κΈμμΉ!
π ν ν¬ λ¦¬λκ° λκΈ° μν΄ νμν ν΅μ¬ μλ
μλ | μ€λͺ | κ΄λ ¨ μ€ν¬ |
---|---|---|
μμ€ν μ€κ³ λ₯λ ₯ | μ΅μ μ μν€ν μ²λ₯Ό μ€κ³νλ λ₯λ ₯ | λ§μ΄ν¬λ‘μλΉμ€, λΆμ° μμ€ν |
μ½λ 리뷰 λ° κ°μ΄λ | νμλ€μ μ½λ νμ§μ ν₯μ | Clean Code, SOLID μμΉ |
λΉμ¦λμ€ μ΄ν΄λ ₯ | κ°λ°μ λμ΄ λΉμ¦λμ€ μ λ΅μ κ³ λ € | μ ν κΈ°ν, λ°μ΄ν° λΆμ |
β ν ν¬ λ¦¬λλ‘μ μ½λ 리뷰λ₯Ό μ§ννλ μμ
// [κ°μ μ ] null 체ν¬κ° λΆμ‘±νμ¬ NPE λ°μ κ°λ₯
public String getUserEmail(User user) {
return user.getEmail();
}
// [κ°μ ν] Optionalμ νμ©νμ¬ μμ νκ² μ²λ¦¬
public String getUserEmail(User user) {
return Optional.ofNullable(user).map(User::getEmail).orElse("unknown@example.com");
}
β μ½λ νμ§μ λμ΄κ³ , νμλ€μκ² μ’μ κ°λ° μ΅κ΄μ κ°λ₯΄μΉ μ μμ!
β 5. κΈλ‘λ² κΈ°μ λ©΄μ μ€λΉ (FAANG & μ€ννΈμ CTO λμ )
μ΄μ μ΅κ³ μ κ°λ°μλ‘ μ±μ₯νκΈ° μν΄
ꡬκΈ, νμ΄μ€λΆ, μλ§μ‘΄(FAANG) λ° μ€ννΈμ CTOμ λμ ν μ€λΉλ₯Ό ν΄μΌ ν©λλ€.
π FAANG & μ€ννΈμ CTO λμ μ μν μ€λΉ λ°©λ²
λ¨κ³ | λͺ©ν | νμ΅ λ°©λ² |
---|---|---|
1λ¨κ³ | μκ³ λ¦¬μ¦ & μλ£κ΅¬μ‘° μ¬ν | LeetCode, Codeforces |
2λ¨κ³ | μμ€ν μ€κ³ λ§μ€ν° | βSystem Design Interviewβ μ± μ½κΈ° |
3λ¨κ³ | μ€νμμ€ κΈ°μ¬ κ²½ν | GitHubμμ νλ‘μ νΈ κΈ°μ¬ |
4λ¨κ³ | λͺ¨μ λ©΄μ μ€λΉ | Pramp, Interviewing.io |
β μμ : μμ€ν μ€κ³ λ©΄μ μμ μμ£Ό λμ€λ μ§λ¬Έ
- βνμ΄μ€λΆ λ΄μ€νΌλλ μ΄λ»κ² λμν κΉμ?β
- βνΈμν°μμ μ€μκ° νΈλ λλ₯Ό λΆμνλ λ°©λ²μ?β
- βλκ·λͺ¨ λμμ μ€νΈλ¦¬λ° μλΉμ€(μ: μ νλΈ)μ μ€κ³λ μ΄λ»κ² ν κΉμ?β
π λ§λ¬΄λ¦¬: μννΈμ¨μ΄ μν€ν μ² & AI & ν ν¬ λ¦¬λ μμ±!
β λκ·λͺ¨ μν€ν μ² μ€κ³ (CQRS, Sharding, Rate Limiting)
β AI & λ°μ΄ν° μ¬μ΄μΈμ€ νμ΅ (λ¨Έμ λ¬λ, NLP, λΉ λ°μ΄ν° λΆμ)
β DevOps & 보μ κ°ν (CI/CD, OWASP Top 10, Docker λ°°ν¬)
β ν ν¬ λ¦¬λλ‘ μ±μ₯ (μ½λ 리뷰, μμ€ν μ΅μ ν, ν 리λ©)
β FAANG & μ€ννΈμ CTO λμ (μκ³ λ¦¬μ¦, μμ€ν μ€κ³, λ©΄μ μ€λΉ)
π λΆλ‘: κΈλ‘λ² CTO & κΈ°μ μ°½μ & λ―Έλ κΈ°μ μ°κ΅¬
μ΄μ λ λ¨μν κ°λ°μκ° μλλΌ,
- *βμΈκ³μ μΈ κΈ°μ 리λκ° λκ³ , μ§μ νμ¬λ₯Ό μ°½μ νλ©°, λ―Έλ κΈ°μ μ μ°κ΅¬νλ λ¨κ³β**λ‘ λμ ν μ°¨λ‘μ λλ€.
β 1. κΈλ‘λ² CTO λλ κΈ°μ μ°½μ μ€λΉ
π‘ μ΄μ CTO(Chief Technology Officer, μ΅κ³ κΈ°μ μ± μμ)λ‘ μ±μ₯νκ±°λ,
μ€ννΈμ μ μ°½μ νμ¬ μλ‘μ΄ κΈ°μ νμ μ μ΄λ£¨λ κ²μ΄ λͺ©νκ° λ©λλ€.
π CTO λ° κΈ°μ μ°½μ μκ° μμμΌ ν ν΅μ¬ κ°λ
μλ | μ€λͺ | κ΄λ ¨ μ€ν¬ |
---|---|---|
λΉμ¦λμ€ μ λ΅ | κΈ°μ μ μ΄μ©ν΄ νμ¬λ₯Ό μ±μ₯μν€λ μ λ΅ | μ€ννΈμ κ²½μ, ν¬μ μ μΉ |
κΈ°μ 리λμ | λκ·λͺ¨ κ°λ° μ‘°μ§μ μ΄λλ λ₯λ ₯ | ν λΉλ©, μν€ν μ² μ€κ³ |
μ ν κ°λ° | μμ₯μμ μ±κ³΅ν μ μλ μ ν μ€κ³ | Lean Startup, Agile |
μκΈ μ‘°λ¬ & ν¬μ μ μΉ | VC λ° μμ € ν¬μμλ‘λΆν° μκΈ μ‘°λ¬ | μ€ννΈμ νΌμΉ, μ¬λ¬΄ λͺ¨λΈλ§ |
β μμ : μ€ννΈμ μ ν΅μ¬ MVP(Minimum Viable Product) κ°λ° μμΉ
1οΈβ£ κ°μ₯ μ€μν κΈ°λ₯λ§ ν¬ν¨ν μ΅μ μ ν(MVP)μ λ§λ λ€.
2οΈβ£ λΉ λ₯΄κ² μ¬μ©μ λ°μμ νμΈνκ³ , κ°μ νλ€.
3οΈβ£ κΈ°μ 보λ€λ μμ₯κ³Ό κ³ κ° μ€μ¬μΌλ‘ μ νμ μ€κ³νλ€.
β CTOκ° λ°λμ κ³ λ €ν΄μΌ ν 3κ°μ§ μ§λ¬Έ
- βμ΄ κΈ°μ μ΄ μ§μ§ λ¬Έμ λ₯Ό ν΄κ²°νλκ°?β
- βμ΄ κΈ°μ μ μ€μΌμΌ(νμ₯μ±)μ΄ κ°λ₯νκ°?β
- βκ²½μμ¬κ° λ°λΌμ¬ μ μμ λ§νΌ μ°¨λ³νλ κΈ°μ μΈκ°?β
β 2. μννΈμ¨μ΄ + νλμ¨μ΄ κ²°ν© κΈ°μ νμ΅ (IoT, λ‘보ν±μ€, Web3)
π‘ μ΄μ μννΈμ¨μ΄λΏλ§ μλλΌ νλμ¨μ΄μμ κ²°ν© κΈ°μ μ λ°°μμΌ ν©λλ€.
π IoT, λ‘보ν±μ€, Web3, λΈλ‘μ²΄μΈ λ±μ κΈ°μ μ νμ©νλ©΄ μλ‘μ΄ λΉμ¦λμ€ κΈ°νλ₯Ό λ§λ€ μ μμ΅λλ€.
π μννΈμ¨μ΄ + νλμ¨μ΄ κ²°ν© κΈ°μ
κΈ°μ | μ€λͺ | νμ© μ¬λ‘ |
---|---|---|
IoT (μ¬λ¬Ό μΈν°λ·) | μΈν°λ·κ³Ό μ°κ²°λ μ€λ§νΈ κΈ°κΈ° | μ€λ§νΈ ν, ν¬μ€μΌμ΄ κΈ°κΈ° |
λ‘보ν±μ€ & AIoT | λ‘λ΄κ³Ό AIλ₯Ό κ²°ν© | μμ¨μ£Όν, μ€λ§νΈ ν©ν 리 |
Web3 & λΈλ‘μ²΄μΈ | νμ€μν μ ν리μΌμ΄μ | NFT, DAO, μ€λ§νΈ κ³μ½ |
AR/VR & λ©νλ²μ€ | νμ€κ³Ό κ°μ μΈκ³μ κ²°ν© | λ©νλ²μ€, κ°μ νμ |
β μμ : IoT κΈ°λ° μ€λ§νΈ ν μμ€ν μ€κ³
import paho.mqtt.client as mqtt
def on_message(client, userdata, message):
print(f"Received: {message.payload.decode()}")
client = mqtt.Client()
client.on_message = on_message
client.connect("iot-broker.example.com")
client.subscribe("home/livingroom/light")
client.loop_forever()
β IoT κΈ°κΈ°μμ MQTT νλ‘ν μ½μ νμ©νμ¬ μ€μκ° λ°μ΄ν° μμ§ κ°λ₯!
β 3. μμ μ»΄ν¨ν , μλͺ 곡ν, λ-μ»΄ν¨ν° μΈν°νμ΄μ€ μ°κ΅¬
π‘ μ΄μ λ λ―Έλ κΈ°μ (Quantum Computing, Biotech, BCI)μ μ°κ΅¬νκ³ μ μ©νλ λ¨κ³μ λλ€.
π μμΌλ‘ 10~20λ μ μ£Όλν κΈ°μ μ νμ΅νμ¬ λ―Έλλ₯Ό μ€λΉν΄μΌ ν©λλ€.
π λ―Έλ κΈ°μ μ°κ΅¬ μ£Όμ
κΈ°μ | μ€λͺ | νμ© μ¬λ‘ |
---|---|---|
μμ μ»΄ν¨ν (Quantum Computing) | κΈ°μ‘΄ μ»΄ν¨ν°λ³΄λ€ μμ² λ°° λΉ λ₯Έ μ°μ° κ°λ₯ | μνΈ ν΄λ , AI μ΅μ ν |
μλͺ 곡ν (Biotech & Bioinformatics) | μ μ μ λΆμ λ° λ§μΆ€ν μλ£ | μ μ μ μΉλ£, μ μ½ κ°λ° |
λ-μ»΄ν¨ν° μΈν°νμ΄μ€ (BCI) | μΈκ° λμ μ»΄ν¨ν° μ°κ²° | μ κ²½ μΈν°νμ΄μ€, AI λ³΄μ² |
β μμ : μμ μ»΄ν¨ν μ νμ©ν μ΅μ ν λ¬Έμ ν΄κ²°
from qiskit import QuantumCircuit, Aer, transpile, assemble
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
sim = Aer.get_backend('aer_simulator')
job = sim.run(transpile(qc, sim))
result = job.result()
print(result.get_counts())
β μμ νλ‘λ₯Ό μ¬μ©νμ¬ κΈ°μ‘΄ μ»΄ν¨ν°λ‘ ν΄κ²°ν μ μλ λ¬Έμ λ₯Ό ν μ μμ!
β 4. κΈ°μ μ² ν & μ€λ¦¬ μ°κ΅¬ (AI μ€λ¦¬, λ°μ΄ν° νλΌμ΄λ²μ, λμ§νΈ μΈκΆ)
π‘ μ΄μ λ κΈ°μ μ λμ΄ βκΈ°μ μ΄ μΈλ₯μ λ―ΈμΉλ μν₯βκΉμ§ κ³ λ―Όν΄μΌ ν©λλ€.
π AI μ€λ¦¬, λ°μ΄ν° νλΌμ΄λ²μ, λμ§νΈ μΈκΆ λ±μ μ°κ΅¬νκ³ μ¬νμ κ°μΉλ₯Ό λ§λ€μ΄μΌ ν©λλ€.
π κΈ°μ μ² ν & μ€λ¦¬μμ κ³ λ €ν μ£Όμ
μ£Όμ | μ€λͺ | κ΄λ ¨ κΈ°μ |
---|---|---|
AI μ€λ¦¬ | AIκ° μ°¨λ³ μμ΄ κ³΅μ νκ² λμνλλ‘ μ€κ³ | Fair AI, Explainable AI |
λ°μ΄ν° νλΌμ΄λ²μ | κ°μΈμ 보 λ³΄νΈ λ° λ³΄μ κ°ν | GDPR, Differential Privacy |
λμ§νΈ μΈκΆ | μ¨λΌμΈ μμ ννμ μμ μ κ²μ΄ λ¬Έμ | μΈν°λ· κ²μ΄ λ°©μ§ κΈ°μ |
β μμ : AI λͺ¨λΈμ νΈν₯(Bias) νμ§ μ½λ
from sklearn.metrics import classification_report
y_true = [0, 1, 0, 1, 0, 1]
y_pred = [0, 0, 0, 1, 0, 1]
print(classification_report(y_true, y_pred))
β AIκ° νΉμ κ·Έλ£Ήμ λν΄ λΆκ³΅μ ν κ²°μ μ λ΄λ¦¬λμ§ λΆμν μ μμ!
β 5. κΈ°μ κ³Ό μΈλ₯μ λ―Έλλ₯Ό κ³ λ―Όνλ λ¨κ³ (Singularity & Post-Human Society)
π‘ λ§μ§λ§ λ¨κ³μμλ βκΈ°μ μ΄ μΈκ°μ μ΄λ»κ² λ³νμν€λκ°?βλ₯Ό κ³ λ―Όν΄μΌ ν©λλ€.
π μΈκ³΅μ§λ₯, μ μ μ νΈμ§, λ-μ»΄ν¨ν° μΈν°νμ΄μ€ λ±μΌλ‘ μΈκ°μ νκ³λ₯Ό λλ μλ(Post-Human Society)κ° λλνκ³ μμ΅λλ€.
π κΈ°μ λ°μ μ μ² νμ μ§λ¬Έ
- βμΈκ³΅μ§λ₯μ΄ μΈκ°λ³΄λ€ λλν΄μ§λ©΄, μΈκ°μ 무μμ ν΄μΌ ν κΉ?β
- βμμμ΄ κ°λ₯ν΄μ§λ€λ©΄, μΈκ°μ μΆμ μλ―Έλ?β
- βλμ§νΈ μΈκ³μ νμ€ μΈκ³μ κ²½κ³λ μ΄λ»κ² λ κΉ?β
β μ΄ λ¨κ³μμλ μ² ν, μ¬νν, μ€λ¦¬νκΉμ§ 곡λΆν΄μΌ ν©λλ€.
π λ§λ¬΄λ¦¬: μΈκ³μ μΈ κΈ°μ 리λ & λ―Έλ κ°μ²μλ‘ μ±μ₯!
π μ΅μ’ λͺ©ν
β CTO λλ κΈ°μ μ°½μ (λΉμ¦λμ€ + κΈ°μ 리λμ)
β μννΈμ¨μ΄ + νλμ¨μ΄ κ²°ν© (IoT, Web3, λ‘보ν±μ€)
β λ―Έλ κΈ°μ μ°κ΅¬ (μμ μ»΄ν¨ν , BCI, Biotech)
β κΈ°μ μ€λ¦¬ λ° μ¬νμ μ± μ κ³ λ―Ό (AI μ€λ¦¬, λ°μ΄ν° νλΌμ΄λ²μ)
β κΈ°μ κ³Ό μΈλ₯μ λ―Έλλ₯Ό κ³ λ―Όνλ μ² νμ μ¬κ³
μ΄μ λΉμ μ λ¨μν κ°λ°μκ° μλλΌ, μΈμμ λ°κΏ κΈ°μ 리λλ‘ μ±μ₯ν μ€λΉκ° λμμ΅λλ€! ππ₯
μΆκ°λ‘ κΆκΈν μ μ΄ μλ€λ©΄ μΈμ λ μ§λ¬Έν΄ μ£ΌμΈμ! π