-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
213 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
--- | ||
layout: single | ||
title: "Monad" | ||
date: 2020-11-22 11:10:03 +0900 | ||
categories: [woowa] | ||
--- | ||
|
||
|
||
|
||
## python monad | ||
|
||
monad 는 이해하기 어려운 개념이라고 악명이 높죠. | ||
|
||
https://www.youtube.com/watch?v=26jVysJHB-s | ||
프레젠테이션은 별로인데 예제가 좋아서 가져왔습니다. | ||
|
||
|
||
## 예시: TimedValue | ||
|
||
일련의 함수를 실행하고, 총 실행시간을 측정하고 싶다고 합시다. | ||
먼저 함수의 실행 시간을 리턴하도록 만드는 decorator 를 선언합니다. | ||
|
||
```python | ||
from functools import wraps | ||
from time import sleep, time | ||
def time_it(f): | ||
@wraps(f) | ||
def wrapper(*args, **kwargs): | ||
start = time() | ||
result = f(*args, **kwargs) | ||
end = time() | ||
return result, end - start | ||
return wrapper | ||
``` | ||
|
||
이제 이 decorator 를 함수에 씌우고 실행하면? 실행 결과와 실행시간이 리턴되겠죠? | ||
|
||
```python | ||
@time_it | ||
def fast(x): | ||
return x + 1 | ||
@time_it | ||
def slow(x): | ||
sleep(0.1) | ||
return x + 1 | ||
@time_it | ||
def slow2(x): | ||
sleep(0.1) | ||
return x + 2 | ||
``` | ||
|
||
함수를 실행하고 걸린 시간을 저장해 봅시다. | ||
|
||
```python | ||
x0, time0 = fast(1) | ||
x1, time1 = slow(x0) | ||
x2, time2 = slow2(x1) | ||
total_time = sum(time0, time1, time2) | ||
``` | ||
|
||
깔끔한 코드입니다만! 아쉬운 점이 조금 있습니다. | ||
|
||
* unpacking (x0, time0) 을 반복합니다. | ||
* 실행 종료 후 각 time 을 따로 sum() 해야 합니다. (물론 각 함수의 개별 실행 시간이 필요하다면 이 방법을 써야 합니다.) | ||
|
||
이를 메소드 chaining 을 사용해서 개선해보겠습니다. 시간과 값을 갖는 클래스 | ||
`TimedValue` 를 만듭니다. | ||
|
||
|
||
```python | ||
from functools import wraps | ||
from time import sleep, time | ||
class TimedValue: | ||
def __init__(self, value, time=time()): | ||
self.value = value | ||
self.time = time | ||
def bind(self, f): | ||
''' | ||
f() 는 TimedValue 객체를 반환하는 함수. | ||
bind 를 사용해서 method 를 묶습니다(chain). | ||
''' | ||
timed_value = f(self.value) | ||
new_value = timed_value.value | ||
new_time = self.time + timed_value.time | ||
return TimedValue(new_value, new_time) | ||
def time_it(f): | ||
@wraps(f) | ||
def wrapper(*args, **kwargs): | ||
start = time() | ||
result = f(*args, **kwargs) | ||
end = time() | ||
return TimedValue(result, end - start) | ||
return wrapper | ||
timed_value = fast(1).bind(slow).bind(slow2) | ||
print(timed_value.value, timed_value.time) | ||
``` | ||
|
||
어때요? 더 간결하게 느껴지시나요? | ||
그건 그런데 이게 monad 와 무슨 상관이냐구요? 방금 우리가 | ||
monad 를 만들었잖아요! 바로 TimedValue 클래스입니다! | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
--- | ||
layout: single | ||
title: "좋아요에 관한 간단한 고찰" | ||
date: 2021-06-20 11:10:03 +0900 | ||
categories: [Python, Aws] | ||
--- | ||
|
||
## 게시글에 '좋아요' | ||
좋아요, 이게 간단해 보이지만 생각보다 엄청 복잡한 기능입니다. | ||
퀄리티 있는 좋아요 기능을 구현하기 위해서는 다음과 같은 문제를 해결해야 합니다. | ||
|
||
* 새로운 '좋아요' 값은 기존 '좋아요' 값에 영향을 받습니다. (new_like = old_like + 1) | ||
그렇다면 동시성 문제를 해결하기 위해 Lock 을 걸어야 할까? 같은 고민을 하게 되죠. | ||
|
||
* 다양한 종류의 테이블에 좋아요를 할 수 있어야 합니다. 요즘 SNS 보면 댓글에도 좋아요, 게시글에도 좋아요 | ||
별의별 종류의 테이블에 좋아요를 할 수 있죠. 이건 RDBMS 에서 어떻게 모델링을 해야 하는 걸까요? | ||
|
||
* 좋아요는 쓰기보다 읽기가 훨씬 많은 데이터 입니다. 따라서 좋아요 수를 계산하기 위해 record 를 매 번 세는 것은 | ||
효율적이지 않습니다. 총 좋아요 값을 저장할 필요가 있습니다. | ||
|
||
* 운영 측면에서 좋아요 수를 가지고 통계를 내기에 편리해야 합니다. | ||
|
||
|
||
## 좋아요를 구현하는 다양한 방법들 | ||
|
||
|
||
### 좋아요 테이블이 수많은 테이블과 직접 foreign key 를 맺는 방법 | ||
* likes 가 수많은 foreign key 중 하나만 값을 갖고 나머지는 NULL 일 것을 보장해야 합니다. mysql 만으로는 할 수 없고, | ||
코드 상에서 제한을 두어야겠죠? | ||
|
||
|
||
|
||
### Document 에 좋아요를 하는 방법 | ||
|
||
* 공통된 부모를 두고, 부모에 좋아요를 연결 | ||
* NULL 인 foreign key 가 없습니다. | ||
* 좋아요 수를 구하기 위해서 바로 likes 를 join 할 수 없고, documents 를 중간에 join 해야 합니다. | ||
* documents 에 like_cnt 를 둘 수 있습니다. | ||
|
||
|
||
|
||
|
||
## 운영 측면에서 통계 내기 | ||
|
||
|
||
### 좋아요가 가장 많은 게시글은 무엇인가? | ||
|
||
간단한 쿼리로 알아낼 수 있습니다. | ||
```sql | ||
SELECT MAX(id) FROM likes group by article_id; | ||
``` | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
### 좋아요 수를 읽어들이지 않고, 바로 UPDATE 를 치는 방법 | ||
Lock 을 걸지 않고 문제를 해결하는 아주 깔끔한 방법입니다. | ||
|
||
|
||
|
||
|
||
|
||
|
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters